summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packet/bgp.go176
-rw-r--r--packet/bgp_test.go20
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))
+ }
+}