diff options
-rw-r--r-- | packet/bgp.go | 176 | ||||
-rw-r--r-- | packet/bgp_test.go | 20 |
2 files changed, 196 insertions, 0 deletions
diff --git a/packet/bgp.go b/packet/bgp.go index 022dcbd5..201a4cc9 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -3040,6 +3040,9 @@ const ( _ BGP_ATTR_TYPE_PMSI_TUNNEL // = 22 BGP_ATTR_TYPE_TUNNEL_ENCAP + _ + _ + BGP_ATTR_TYPE_AIGP // = 26 ) // NOTIFICATION Error Code RFC 4271 4.5. @@ -3131,6 +3134,7 @@ var pathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{ BGP_ATTR_TYPE_AS4_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_TYPE_PMSI_TUNNEL: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, + BGP_ATTR_TYPE_AIGP: BGP_ATTR_FLAG_OPTIONAL, } type PathAttributeInterface interface { @@ -5635,6 +5639,176 @@ func NewPathAttributePmsiTunnel(typ PmsiTunnelType, isLeafInfoRequired bool, lab } } +type AigpTLVType uint8 + +const ( + AIGP_TLV_UNKNOWN AigpTLVType = iota + AIGP_TLV_IGP_METRIC +) + +type AigpTLV interface { + Serialize() ([]byte, error) + String() string + MarshalJSON() ([]byte, error) + Type() AigpTLVType +} + +type AigpTLVDefault struct { + typ AigpTLVType + Value []byte +} + +func (t *AigpTLVDefault) Serialize() ([]byte, error) { + buf := make([]byte, 3+len(t.Value)) + buf[0] = uint8(t.Type()) + binary.BigEndian.PutUint16(buf[1:], uint16(3+len(t.Value))) + copy(buf[3:], t.Value) + return buf, nil +} + +func (t *AigpTLVDefault) String() string { + return fmt.Sprintf("{Type: %d, Value: %v}", t.Type(), t.Value) +} + +func (t *AigpTLVDefault) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type AigpTLVType `json:"type"` + Value []byte `json:"value"` + }{ + Type: t.Type(), + Value: t.Value, + }) +} + +func (t *AigpTLVDefault) Type() AigpTLVType { + return t.typ +} + +type AigpTLVIgpMetric struct { + Metric uint64 +} + +func (t *AigpTLVIgpMetric) Serialize() ([]byte, error) { + buf := make([]byte, 11) + buf[0] = uint8(AIGP_TLV_IGP_METRIC) + binary.BigEndian.PutUint16(buf[1:], uint16(11)) + binary.BigEndian.PutUint64(buf[3:], t.Metric) + return buf, nil +} + +func (t *AigpTLVIgpMetric) String() string { + return fmt.Sprintf("{Metric: %d}", t.Metric) +} + +func (t *AigpTLVIgpMetric) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type AigpTLVType `json:"type"` + Metric uint64 `json:"metric"` + }{ + Type: AIGP_TLV_IGP_METRIC, + Metric: t.Metric, + }) +} + +func NewAigpTLVIgpMetric(metric uint64) *AigpTLVIgpMetric { + return &AigpTLVIgpMetric{ + Metric: metric, + } +} + +func (t *AigpTLVIgpMetric) Type() AigpTLVType { + return AIGP_TLV_IGP_METRIC +} + +type PathAttributeAigp struct { + PathAttribute + Values []AigpTLV +} + +func (p *PathAttributeAigp) DecodeFromBytes(data []byte) error { + err := p.PathAttribute.DecodeFromBytes(data) + if err != nil { + return err + } + + rest := p.PathAttribute.Value + values := make([]AigpTLV, 0) + + for { + if len(rest) < 3 { + break + } + typ := rest[0] + length := binary.BigEndian.Uint16(rest[1:3]) + if len(rest) < int(length) { + break + } + v := rest[3:length] + switch AigpTLVType(typ) { + case AIGP_TLV_IGP_METRIC: + if len(v) < 8 { + break + } + metric := binary.BigEndian.Uint64(v) + values = append(values, NewAigpTLVIgpMetric(metric)) + default: + values = append(values, &AigpTLVDefault{AigpTLVType(typ), v}) + } + rest = rest[length:] + if len(rest) == 0 { + p.Values = values + return nil + } + } + eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) + eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) + return NewMessageError(eCode, eSubCode, nil, "Aigp length is incorrect") +} + +func (p *PathAttributeAigp) Serialize() ([]byte, error) { + buf := make([]byte, 0) + for _, t := range p.Values { + bbuf, err := t.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, bbuf...) + } + p.PathAttribute.Value = buf + return p.PathAttribute.Serialize() +} + +func (p *PathAttributeAigp) String() string { + buf := bytes.NewBuffer(make([]byte, 0, 32)) + buf.WriteString("{Aigp: [") + for _, v := range p.Values { + buf.WriteString(v.String()) + } + buf.WriteString("]}") + return buf.String() +} + +func (p *PathAttributeAigp) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type BGPAttrType `json:"type"` + Value []AigpTLV `json:"value"` + }{ + Type: p.GetType(), + Value: p.Values, + }) +} + +func NewPathAttributeAigp(values []AigpTLV) *PathAttributeAigp { + t := BGP_ATTR_TYPE_AIGP + return &PathAttributeAigp{ + PathAttribute: PathAttribute{ + Flags: pathAttrFlags[t], + Type: t, + }, + Values: values, + } +} + type PathAttributeUnknown struct { PathAttribute } @@ -5680,6 +5854,8 @@ func GetPathAttribute(data []byte) (PathAttributeInterface, error) { return &PathAttributeTunnelEncap{}, nil case BGP_ATTR_TYPE_PMSI_TUNNEL: return &PathAttributePmsiTunnel{}, nil + case BGP_ATTR_TYPE_AIGP: + return &PathAttributeAigp{}, nil } return &PathAttributeUnknown{}, nil } diff --git a/packet/bgp_test.go b/packet/bgp_test.go index 55931ef7..b7b26d38 100644 --- a/packet/bgp_test.go +++ b/packet/bgp_test.go @@ -511,3 +511,23 @@ func Test_FlowSpecNlriv6(t *testing.T) { t.Log(bytes.Equal(buf1, buf2)) } } + +func Test_Aigp(t *testing.T) { + assert := assert.New(t) + m := NewAigpTLVIgpMetric(1000) + a1 := NewPathAttributeAigp([]AigpTLV{m}) + buf1, err := a1.Serialize() + assert.Nil(err) + a2 := NewPathAttributeAigp(nil) + err = a2.DecodeFromBytes(buf1) + assert.Nil(err) + buf2, _ := a2.Serialize() + if reflect.DeepEqual(a1, a2) == true { + t.Log("OK") + } else { + t.Error("Something wrong") + t.Error(len(buf1), a1, buf1) + t.Error(len(buf2), a2, buf2) + t.Log(bytes.Equal(buf1, buf2)) + } +} |