diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-04-25 05:52:14 +0000 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-04-25 18:26:28 +0900 |
commit | 27d0d45b6319658bc0a43511d1909a411df40b08 (patch) | |
tree | 51cd5c2ffb60fd077f8a425796d8112325172961 /packet | |
parent | 99133709be6c555b814347f7deb34f45129be5dd (diff) |
bgp: add RFC5512 related message serializer/decoder
RFC5512 is for tunnel information exchange between peers.
This is used in EVPN/VXLAN usecase(draft-ietf-bess-evpn-overlay-01).
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'packet')
-rw-r--r-- | packet/bgp.go | 531 | ||||
-rw-r--r-- | packet/bgp_test.go | 91 |
2 files changed, 571 insertions, 51 deletions
diff --git a/packet/bgp.go b/packet/bgp.go index 8e468ec4..c181f4b8 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -38,6 +38,7 @@ const ( SAFI_UNICAST = 1 SAFI_MULTICAST = 2 SAFI_MPLS_LABEL = 4 + SAFI_ENCAPSULATION = 7 SAFI_VPLS = 65 SAFI_EVPN = 70 SAFI_MPLS_VPN = 128 @@ -56,6 +57,82 @@ const ( BGP_ASPATH_ATTR_TYPE_SEQ = 2 ) +// RFC7153 5.1. Registries for the "Type" Field +// RANGE REGISTRACTION PROCEDURES +// 0x00-0x3F Transitive First Come First Served +// 0x40-0x7F Non-Transitive First Come First Served +// 0x80-0x8F Transitive Experimental Use +// 0x90-0xBF Transitive Standards Action +// 0xC0-0xCF Non-Transitive Experimental Use +// 0xD0-0xFF Non-Transitive Standards Action +type ExtendedCommunityAttrType uint8 + +const ( + EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x00 + EC_TYPE_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x01 + EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x02 + EC_TYPE_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x03 + EC_TYPE_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x04 + EC_TYPE_COS_CAPABILITY ExtendedCommunityAttrType = 0x05 + EC_TYPE_EVPN ExtendedCommunityAttrType = 0x06 + EC_TYPE_FLOWSPEC_REDIRECT_MIRROR ExtendedCommunityAttrType = 0x08 + EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x40 + EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x41 + EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x42 + EC_TYPE_NON_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x43 + EC_TYPE_NON_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x44 + EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL ExtendedCommunityAttrType = 0x80 +) + +// RFC7153 5.2. Registraction for the "Sub-Type" Field +// RANGE REGISTRACTION PROCEDURES +// 0x00-0xBF First Come First Served +// 0xC0-0xFF IETF Review +type ExtendedCommunityAttrSubType uint8 + +const ( + EC_SUBTYPE_ORIGIN_VALIDATION ExtendedCommunityAttrSubType = 0x00 + EC_SUBTYPE_ROUTE_TARGET ExtendedCommunityAttrSubType = 0x02 + EC_SUBTYPE_ROUTE_ORIGIN ExtendedCommunityAttrSubType = 0x03 + EC_SUBTYPE_LINK_BANDWIDTH ExtendedCommunityAttrSubType = 0x04 + EC_SUBTYPE_GENERIC ExtendedCommunityAttrSubType = 0x04 + EC_SUBTYPE_OSPF_DOMAIN_ID ExtendedCommunityAttrSubType = 0x05 + EC_SUBTYPE_OSPF_ROUTE_TYPE ExtendedCommunityAttrSubType = 0x06 + EC_SUBTYPE_OSPF_ROUTE_ID ExtendedCommunityAttrSubType = 0x07 + EC_SUBTYPE_BGP_DATA_COLLECTION ExtendedCommunityAttrSubType = 0x08 + EC_SUBTYPE_SOURCE_AS ExtendedCommunityAttrSubType = 0x09 + EC_SUBTYPE_L2VPN_ID ExtendedCommunityAttrSubType = 0x0A + EC_SUBTYPE_L2_INFO ExtendedCommunityAttrSubType = 0x0A + EC_SUBTYPE_VRF_ROUTE_IMPORT ExtendedCommunityAttrSubType = 0x0B + EC_SUBTYPE_COLOR ExtendedCommunityAttrSubType = 0x0B + EC_SUBTYPE_ENCAPSULATION ExtendedCommunityAttrSubType = 0x0C + EC_SUBTYPE_DEFAULT_GATEWAY ExtendedCommunityAttrSubType = 0x0D + EC_SUBTYPE_CISCO_VPN_DISTINGUISHER ExtendedCommunityAttrSubType = 0x10 + EC_SUBTYPE_UUID_BASED_RT ExtendedCommunityAttrSubType = 0x11 + + EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE ExtendedCommunityAttrSubType = 0x06 + EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION ExtendedCommunityAttrSubType = 0x07 + EC_SUBTYPE_FLOWSPEC_REDIRECT ExtendedCommunityAttrSubType = 0x08 + EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK ExtendedCommunityAttrSubType = 0x09 + + EC_SUBTYPE_MAC_MOBILITY ExtendedCommunityAttrSubType = 0x00 + EC_SUBTYPE_ESI_MPLS_LABEL ExtendedCommunityAttrSubType = 0x01 + EC_SUBTYPE_ES_IMPORT ExtendedCommunityAttrSubType = 0x02 +) + +type TunnelType uint16 + +const ( + TUNNEL_TYPE_L2TP3 TunnelType = 1 + TUNNEL_TYPE_GRE TunnelType = 2 + TUNNEL_TYPE_IP_IN_IP TunnelType = 7 + TUNNEL_TYPE_VXLAN TunnelType = 8 + TUNNEL_TYPE_NVGRE TunnelType = 9 + TUNNEL_TYPE_MPLS TunnelType = 10 + TUNNEL_TYPE_MPLS_IN_GRE TunnelType = 11 + TUNNEL_TYPE_VXLAN_GRE TunnelType = 12 +) + const ( _ = iota BGP_MSG_OPEN @@ -540,10 +617,6 @@ func (r *IPAddrPrefix) ToApiStruct() *api.Nlri { } } -type IPv6AddrPrefix struct { - IPAddrPrefix -} - func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix { return &IPAddrPrefix{ IPAddrPrefixDefault{length, net.ParseIP(prefix).To4()}, @@ -551,6 +624,10 @@ func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix { } } +type IPv6AddrPrefix struct { + IPAddrPrefix +} + func (r *IPv6AddrPrefix) AFI() uint16 { return AFI_IP6 } @@ -967,7 +1044,11 @@ type RouteTargetMembershipNLRI struct { func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte) error { n.AS = binary.BigEndian.Uint32(data[0:4]) - n.RouteTarget = parseExtended(data[4:]) + rt, err := parseExtended(data[4:]) + n.RouteTarget = rt + if err != nil { + return err + } return nil } @@ -1394,6 +1475,64 @@ func NewEVPNNLRI(routetype uint8, length uint8, routetypedata EVPNRouteTypeInter routetypedata, } } + +type EncapNLRI struct { + IPAddrPrefixDefault +} + +func (n *EncapNLRI) DecodeFromBytes(data []byte) error { + if len(data) < 4 { + eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) + eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) + return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") + } + n.Length = data[0] + return n.decodePrefix(data[1:], n.Length, n.Length/8) +} + +func (n *EncapNLRI) Serialize() ([]byte, error) { + buf := make([]byte, 1) + buf[0] = net.IPv6len * 8 + if n.Prefix.To4() != nil { + buf[0] = net.IPv4len * 8 + n.Prefix = n.Prefix.To4() + } + n.Length = buf[0] + pbuf, err := n.serializePrefix(n.Length) + if err != nil { + return nil, err + } + return append(buf, pbuf...), nil +} + +func (n *EncapNLRI) String() string { + return n.Prefix.String() +} + +func (n *EncapNLRI) AFI() uint16 { + if n.Prefix.To4() != nil { + return AFI_IP + } + return AFI_IP6 +} + +func (n *EncapNLRI) SAFI() uint8 { + return SAFI_ENCAPSULATION +} + +func (n *EncapNLRI) ToApiStruct() *api.Nlri { + return &api.Nlri{ + Af: &api.AddressFamily{api.AFI(n.AFI()), api.SAFI(n.SAFI())}, + Prefix: n.String(), + } +} + +func NewEncapNLRI(endpoint string) *EncapNLRI { + return &EncapNLRI{ + IPAddrPrefixDefault{0, net.ParseIP(endpoint)}, + } +} + func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily { return RouteFamily(int(afi)<<16 | int(safi)) } @@ -1418,6 +1557,7 @@ const ( RF_VPLS RouteFamily = AFI_L2VPN<<16 | SAFI_VPLS RF_EVPN RouteFamily = AFI_L2VPN<<16 | SAFI_EVPN RF_RTC_UC RouteFamily = AFI_IP<<16 | SAFI_ROUTE_TARGET_CONSTRTAINS + RF_ENCAP RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION ) func GetRouteFamily(name string) (RouteFamily, error) { @@ -1446,6 +1586,8 @@ func GetRouteFamily(name string) (RouteFamily, error) { return RF_VPLS, nil case "l2vpn-evpn": return RF_EVPN, nil + case "encap": + return RF_ENCAP, nil } return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name) } @@ -1468,6 +1610,8 @@ func routeFamilyPrefix(afi uint16, safi uint8) (prefix AddrPrefixInterface, err prefix = NewEVPNNLRI(0, 0, nil) case RF_RTC_UC: prefix = &RouteTargetMembershipNLRI{} + case RF_ENCAP: + prefix = NewEncapNLRI("") default: return nil, errors.New("unknown route family") } @@ -1498,11 +1642,16 @@ const ( _ _ _ - BGP_ATTR_TYPE_MP_REACH_NLRI + BGP_ATTR_TYPE_MP_REACH_NLRI // = 14 BGP_ATTR_TYPE_MP_UNREACH_NLRI BGP_ATTR_TYPE_EXTENDED_COMMUNITIES BGP_ATTR_TYPE_AS4_PATH BGP_ATTR_TYPE_AS4_AGGREGATOR + _ + _ + _ + _ + BGP_ATTR_TYPE_TUNNEL_ENCAP // = 23 ) // NOTIFICATION Error Code RFC 4271 4.5. @@ -1592,6 +1741,7 @@ var pathAttrFlags map[BGPAttrType]uint8 = map[BGPAttrType]uint8{ BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_TYPE_AS4_PATH: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_TYPE_AS4_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, + BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, } type PathAttributeInterface interface { @@ -2605,14 +2755,19 @@ type ExtendedCommunityInterface interface { } type TwoOctetAsSpecificExtended struct { - SubType uint8 - AS uint16 - LocalAdmin uint32 + SubType uint8 + AS uint16 + LocalAdmin uint32 + IsTransitive bool } func (e *TwoOctetAsSpecificExtended) Serialize() ([]byte, error) { buf := make([]byte, 8) - buf[0] = 0x00 + if e.IsTransitive { + buf[0] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) + } else { + buf[0] = byte(EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) + } buf[1] = e.SubType binary.BigEndian.PutUint16(buf[2:], e.AS) binary.BigEndian.PutUint32(buf[4:], e.LocalAdmin) @@ -2624,14 +2779,19 @@ func (e *TwoOctetAsSpecificExtended) String() string { } type IPv4AddressSpecificExtended struct { - SubType uint8 - IPv4 net.IP - LocalAdmin uint16 + SubType uint8 + IPv4 net.IP + LocalAdmin uint16 + IsTransitive bool } func (e *IPv4AddressSpecificExtended) Serialize() ([]byte, error) { buf := make([]byte, 8) - buf[0] = 0x01 + if e.IsTransitive { + buf[0] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) + } else { + buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC) + } buf[1] = e.SubType copy(buf[2:6], e.IPv4) binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) @@ -2643,14 +2803,19 @@ func (e *IPv4AddressSpecificExtended) String() string { } type FourOctetAsSpecificExtended struct { - SubType uint8 - AS uint32 - LocalAdmin uint16 + SubType uint8 + AS uint32 + LocalAdmin uint16 + IsTransitive bool } func (e *FourOctetAsSpecificExtended) Serialize() ([]byte, error) { buf := make([]byte, 8) - buf[0] = 0x02 + if e.IsTransitive { + buf[0] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) + } else { + buf[0] = byte(EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) + } buf[1] = e.SubType binary.BigEndian.PutUint32(buf[2:], e.AS) binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) @@ -2665,22 +2830,128 @@ func (e *FourOctetAsSpecificExtended) String() string { return fmt.Sprintf("%d.%d:%d", asUpper, asLower, e.LocalAdmin) } -type OpaqueExtended struct { +type OpaqueExtendedValueInterface interface { + Serialize() ([]byte, error) + String() string +} + +type DefaultOpaqueExtendedValue struct { Value []byte } -func (e *OpaqueExtended) Serialize() ([]byte, error) { +func (v *DefaultOpaqueExtendedValue) Serialize() ([]byte, error) { + return v.Value[:7], nil +} + +func (v *DefaultOpaqueExtendedValue) String() string { buf := make([]byte, 8) - buf[0] = 0x03 - copy(buf[1:], e.Value) + copy(buf[1:], v.Value) + d := binary.BigEndian.Uint64(buf) + return fmt.Sprintf("%d", d) +} + +type ColorExtended struct { + Value uint32 +} + +func (e *ColorExtended) Serialize() ([]byte, error) { + buf := make([]byte, 7) + buf[0] = byte(EC_SUBTYPE_COLOR) + binary.BigEndian.PutUint32(buf[3:], uint32(e.Value)) + return buf, nil +} + +func (e *ColorExtended) String() string { + return fmt.Sprintf("%d", e.Value) +} + +type EncapExtended struct { + TunnelType TunnelType +} + +func (e *EncapExtended) Serialize() ([]byte, error) { + buf := make([]byte, 7) + buf[0] = byte(EC_SUBTYPE_ENCAPSULATION) + binary.BigEndian.PutUint16(buf[5:], uint16(e.TunnelType)) + return buf, nil +} + +func (e *EncapExtended) String() string { + switch e.TunnelType { + case TUNNEL_TYPE_L2TP3: + return "L2TPv3 over IP" + case TUNNEL_TYPE_GRE: + return "GRE" + case TUNNEL_TYPE_IP_IN_IP: + return "IP in IP" + case TUNNEL_TYPE_VXLAN: + return "VXLAN" + case TUNNEL_TYPE_NVGRE: + return "NVGRE" + case TUNNEL_TYPE_MPLS: + return "MPLS" + case TUNNEL_TYPE_MPLS_IN_GRE: + return "MPLS in GRE" + case TUNNEL_TYPE_VXLAN_GRE: + return "VXLAN GRE" + default: + return fmt.Sprintf("TUNNEL TYPE: %d", e.TunnelType) + } +} + +type OpaqueExtended struct { + IsTransitive bool + Value OpaqueExtendedValueInterface +} + +func (e *OpaqueExtended) DecodeFromBytes(data []byte) error { + if len(data) != 7 { + return fmt.Errorf("Invalid OpaqueExtended bytes len: %d", len(data)) + } + subType := ExtendedCommunityAttrSubType(data[0]) + + switch subType { + case EC_SUBTYPE_COLOR: + v := binary.BigEndian.Uint32(data[3:7]) + e.Value = &ColorExtended{ + Value: v, + } + case EC_SUBTYPE_ENCAPSULATION: + t := TunnelType(binary.BigEndian.Uint16(data[5:7])) + e.Value = &EncapExtended{ + TunnelType: t, + } + default: + e.Value = &DefaultOpaqueExtendedValue{ + Value: data, //7byte + } + } + return nil +} + +func (e *OpaqueExtended) Serialize() ([]byte, error) { + buf := make([]byte, 1, 7) + if e.IsTransitive { + buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) + } else { + buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE) + } + bbuf, err := e.Value.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, bbuf...) return buf, nil } func (e *OpaqueExtended) String() string { - buf := make([]byte, 8) - copy(buf[1:], e.Value) - v := binary.BigEndian.Uint64(buf) - return fmt.Sprintf("%d", v) + return e.Value.String() +} + +func NewOpaqueExtended(isTransitive bool) *OpaqueExtended { + return &OpaqueExtended{ + IsTransitive: isTransitive, + } } type UnknownExtended struct { @@ -2707,36 +2978,53 @@ type PathAttributeExtendedCommunities struct { Value []ExtendedCommunityInterface } -func parseExtended(data []byte) ExtendedCommunityInterface { - typehigh := data[0] & ^uint8(0x40) - switch typehigh { - case 0: +func parseExtended(data []byte) (ExtendedCommunityInterface, error) { + attrType := ExtendedCommunityAttrType(data[0]) + transitive := false + switch attrType { + case EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: + transitive = true + fallthrough + case EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: e := &TwoOctetAsSpecificExtended{} + e.IsTransitive = transitive e.SubType = data[1] e.AS = binary.BigEndian.Uint16(data[2:4]) e.LocalAdmin = binary.BigEndian.Uint32(data[4:8]) - return e - case 1: + return e, nil + case EC_TYPE_TRANSITIVE_IP4_SPECIFIC: + transitive = true + fallthrough + case EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC: e := &IPv4AddressSpecificExtended{} + e.IsTransitive = transitive e.SubType = data[1] e.IPv4 = data[2:6] e.LocalAdmin = binary.BigEndian.Uint16(data[6:8]) - return e - case 2: + return e, nil + case EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: + transitive = true + fallthrough + case EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: e := &FourOctetAsSpecificExtended{} + e.IsTransitive = transitive e.SubType = data[1] e.AS = binary.BigEndian.Uint32(data[2:6]) e.LocalAdmin = binary.BigEndian.Uint16(data[6:8]) - return e - case 3: - e := &OpaqueExtended{} + return e, nil + case EC_TYPE_TRANSITIVE_OPAQUE: + transitive = true + fallthrough + case EC_TYPE_NON_TRANSITIVE_OPAQUE: + e := NewOpaqueExtended(transitive) + err := e.DecodeFromBytes(data[1:8]) + return e, err + default: + e := &UnknownExtended{} + e.Type = BGPAttrType(data[0]) e.Value = data[1:8] - return e + return e, nil } - e := &UnknownExtended{} - e.Type = BGPAttrType(data[0]) - e.Value = data[1:8] - return e } func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte) error { @@ -2751,7 +3039,10 @@ func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte) error { } value := p.PathAttribute.Value for len(value) >= 8 { - e := parseExtended(value) + e, err := parseExtended(value) + if err != nil { + return err + } p.Value = append(p.Value, e) value = value[8:] } @@ -2928,6 +3219,158 @@ func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4A } } +type TunnelEncapSubTLV struct { + Type uint8 + Len int + Value []byte +} + +func (p *TunnelEncapSubTLV) Serialize() ([]byte, error) { + buf := make([]byte, 2, 2+len(p.Value)) + buf = append(buf, p.Value...) + buf[0] = p.Type + p.Len = len(buf) - 2 + buf[1] = byte(p.Len) + return buf, nil +} + +func (p *TunnelEncapSubTLV) ToApiStruct() *api.TunnelEncapSubTLV { + return &api.TunnelEncapSubTLV{ + Type: uint32(p.Type), + Value: string(p.Value), + } +} + +type TunnelEncapTLV struct { + Type TunnelType + Len int + Value []*TunnelEncapSubTLV +} + +func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error { + curr := 0 + for { + if len(data) < curr+2 { + break + } + subType := data[curr] + l := int(data[curr+1]) + if len(data) < curr+2+l { + return fmt.Errorf("Not all TunnelEncapSubTLV bytes available") + } + v := data[curr+2 : curr+2+l] + subTlv := &TunnelEncapSubTLV{ + Type: subType, + Len: l, + Value: v, + } + t.Value = append(t.Value, subTlv) + curr += 2 + l + } + return nil +} + +func (p *TunnelEncapTLV) Serialize() ([]byte, error) { + buf := make([]byte, 4) + for _, s := range p.Value { + bbuf, err := s.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, bbuf...) + } + binary.BigEndian.PutUint16(buf, uint16(p.Type)) + p.Len = len(buf) - 4 + binary.BigEndian.PutUint16(buf[2:], uint16(p.Len)) + return buf, nil +} + +func (p *TunnelEncapTLV) ToApiStruct() *api.TunnelEncapTLV { + subTlvs := make([]*api.TunnelEncapSubTLV, 0, len(p.Value)) + for _, v := range p.Value { + subTlvs = append(subTlvs, v.ToApiStruct()) + } + return &api.TunnelEncapTLV{ + Type: api.TUNNEL_TYPE(p.Type), + SubTlv: subTlvs, + } +} + +type PathAttributeTunnelEncap struct { + PathAttribute + Value []*TunnelEncapTLV +} + +func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte) error { + err := p.PathAttribute.DecodeFromBytes(data) + if err != nil { + return err + } + curr := 0 + for { + if len(p.PathAttribute.Value) < curr+4 { + break + } + t := binary.BigEndian.Uint16(p.PathAttribute.Value[curr : curr+2]) + tunnelType := TunnelType(t) + l := int(binary.BigEndian.Uint16(p.PathAttribute.Value[curr+2 : curr+4])) + if len(p.PathAttribute.Value) < curr+4+l { + return fmt.Errorf("Not all TunnelEncapTLV bytes available. %d < %d", len(p.PathAttribute.Value), curr+4+l) + } + v := p.PathAttribute.Value[curr+4 : curr+4+l] + tlv := &TunnelEncapTLV{ + Type: tunnelType, + Len: l, + } + err = tlv.DecodeFromBytes(v) + if err != nil { + return err + } + p.Value = append(p.Value, tlv) + curr += 4 + l + } + return nil +} + +func (p *PathAttributeTunnelEncap) Serialize() ([]byte, error) { + buf := make([]byte, 0) + for _, t := range p.Value { + bbuf, err := t.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, bbuf...) + } + p.PathAttribute.Value = buf + return p.PathAttribute.Serialize() +} + +func (p *PathAttributeTunnelEncap) ToApiStruct() *api.PathAttr { + tlvs := make([]*api.TunnelEncapTLV, 0, len(p.Value)) + for _, v := range p.Value { + tlvs = append(tlvs, v.ToApiStruct()) + } + return &api.PathAttr{ + Type: api.BGP_ATTR_TYPE_TUNNEL_ENCAP, + TunnelEncap: tlvs, + } +} + +func (p *PathAttributeTunnelEncap) MarshalJSON() ([]byte, error) { + return json.Marshal(p.ToApiStruct()) +} + +func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap { + t := BGP_ATTR_TYPE_TUNNEL_ENCAP + return &PathAttributeTunnelEncap{ + PathAttribute: PathAttribute{ + Flags: pathAttrFlags[t], + Type: t, + }, + Value: value, + } +} + type PathAttributeUnknown struct { PathAttribute } @@ -2981,6 +3424,8 @@ func getPathAttribute(data []byte) (PathAttributeInterface, error) { return &PathAttributeAs4Path{}, nil case BGP_ATTR_TYPE_AS4_AGGREGATOR: return &PathAttributeAs4Aggregator{}, nil + case BGP_ATTR_TYPE_TUNNEL_ENCAP: + return &PathAttributeTunnelEncap{}, nil } return &PathAttributeUnknown{}, nil } diff --git a/packet/bgp_test.go b/packet/bgp_test.go index 64228a36..6f078e5e 100644 --- a/packet/bgp_test.go +++ b/packet/bgp_test.go @@ -62,7 +62,9 @@ func update() *BGPMessage { &TwoOctetAsSpecificExtended{SubType: 1, AS: 10003, LocalAdmin: 3 << 20}, &FourOctetAsSpecificExtended{SubType: 2, AS: 1 << 20, LocalAdmin: 300}, &IPv4AddressSpecificExtended{SubType: 3, IPv4: net.ParseIP("192.2.1.2").To4(), LocalAdmin: 3000}, - &OpaqueExtended{Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}}, + &OpaqueExtended{ + Value: &DefaultOpaqueExtendedValue{[]byte{0, 1, 2, 3, 4, 5, 6, 7}}, + }, &UnknownExtended{Type: 99, Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}}, } @@ -175,15 +177,16 @@ func Test_RouteTargetMembershipNLRIString(t *testing.T) { // TwoOctetAsSpecificExtended buf := make([]byte, 12) binary.BigEndian.PutUint32(buf[:4], 65546) - buf[4] = 0x00 // typehigh + buf[4] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) // typehigh binary.BigEndian.PutUint16(buf[6:8], 65000) binary.BigEndian.PutUint32(buf[8:], 65546) r.DecodeFromBytes(buf) assert.Equal("65546:65000:65546/96", r.String()) // IPv4AddressSpecificExtended + buf = make([]byte, 12) binary.BigEndian.PutUint32(buf[:4], 65546) - buf[4] = 0x01 // typehigh + buf[4] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) // typehigh ip := net.ParseIP("10.0.0.1").To4() copy(buf[6:10], []byte(ip)) binary.BigEndian.PutUint16(buf[10:], 65000) @@ -191,26 +194,98 @@ func Test_RouteTargetMembershipNLRIString(t *testing.T) { assert.Equal("65546:10.0.0.1:65000/96", r.String()) // FourOctetAsSpecificExtended + buf = make([]byte, 12) binary.BigEndian.PutUint32(buf[:4], 65546) - buf[4] = 0x02 // typehigh - buf[5] = 0x01 // subtype + buf[4] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) // typehigh + buf[5] = byte(EC_SUBTYPE_ROUTE_TARGET) // subtype binary.BigEndian.PutUint32(buf[6:], 65546) binary.BigEndian.PutUint16(buf[10:], 65000) r.DecodeFromBytes(buf) assert.Equal("65546:1.10:65000/96", r.String()) // OpaqueExtended + buf = make([]byte, 12) binary.BigEndian.PutUint32(buf[:4], 65546) - buf[4] = 0x03 // typehigh + buf[4] = byte(EC_TYPE_TRANSITIVE_OPAQUE) // typehigh binary.BigEndian.PutUint32(buf[8:], 1000000) r.DecodeFromBytes(buf) - assert.Equal("65546:281479272677952/96", r.String()) + assert.Equal("65546:1000000/96", r.String()) // Unknown + buf = make([]byte, 12) binary.BigEndian.PutUint32(buf[:4], 65546) buf[4] = 0x04 // typehigh binary.BigEndian.PutUint32(buf[8:], 1000000) r.DecodeFromBytes(buf) - assert.Equal("65546:281479272677952/96", r.String()) + assert.Equal("65546:1000000/96", r.String()) + +} + +func Test_RFC5512(t *testing.T) { + assert := assert.New(t) + + buf := make([]byte, 8) + buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) + buf[1] = byte(EC_SUBTYPE_COLOR) + binary.BigEndian.PutUint32(buf[4:], 1000000) + ec, err := parseExtended(buf) + assert.Equal(nil, err) + assert.Equal("1000000", ec.String()) + buf, err = ec.Serialize() + assert.Equal(nil, err) + assert.Equal([]byte{0x3, 0xb, 0x0, 0x0, 0x0, 0xf, 0x42, 0x40}, buf) + + buf = make([]byte, 8) + buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) + buf[1] = byte(EC_SUBTYPE_ENCAPSULATION) + binary.BigEndian.PutUint16(buf[6:], uint16(TUNNEL_TYPE_VXLAN)) + ec, err = parseExtended(buf) + assert.Equal(nil, err) + assert.Equal("VXLAN", ec.String()) + buf, err = ec.Serialize() + assert.Equal(nil, err) + assert.Equal([]byte{0x3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, buf) + + subTlv := &TunnelEncapSubTLV{ + Type: 1, + Value: []byte{0, 1, 2, 3}, + } + + tlv := &TunnelEncapTLV{ + Type: 1, + Value: []*TunnelEncapSubTLV{subTlv}, + } + + attr := NewPathAttributeTunnelEncap([]*TunnelEncapTLV{tlv}) + + buf1, err := attr.Serialize() + assert.Equal(nil, err) + + p, err := getPathAttribute(buf1) + assert.Equal(nil, err) + + err = p.DecodeFromBytes(buf1) + assert.Equal(nil, err) + + buf2, err := p.Serialize() + assert.Equal(nil, err) + assert.Equal(buf1, buf2) + + n1 := NewEncapNLRI("10.0.0.1") + buf1, err = n1.Serialize() + assert.Equal(nil, err) + + n2 := NewEncapNLRI("") + err = n2.DecodeFromBytes(buf1) + assert.Equal(nil, err) + assert.Equal("10.0.0.1", n2.String()) + + n1 = NewEncapNLRI("2001::1") + buf1, err = n1.Serialize() + assert.Equal(nil, err) + n2 = NewEncapNLRI("") + err = n2.DecodeFromBytes(buf1) + assert.Equal(nil, err) + assert.Equal("2001::1", n2.String()) } |