diff options
author | Wataru Ishida <ishida.wataru@lab.ntt.co.jp> | 2016-09-15 08:17:22 +0000 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-09-15 14:32:34 -0700 |
commit | 0db1cd4af26a2c5025517ae30c9c16b11d5bb8d6 (patch) | |
tree | b06750b6047064a598fad3eef1997a7423c97daa /packet | |
parent | 035b129966b5e91e50a96027e375df577e09194a (diff) |
bgp/cli: support evpn route type 5 (ip prefix advertisement)
see draft-ietf-bess-evpn-prefix-advertisement-03
$ gobgp g ri -a evpn add prefix 10.0.0.0/24 etag 20 rd 100:100 rt 100:100 gw 10.10.10.10 label 100
$ gobgp g ri -a evpn add prefix 200::/64 etag 20 rd 100:100 rt 100:100 gw 200::1 label 10000
close #1082
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'packet')
-rw-r--r-- | packet/bgp/bgp.go | 134 | ||||
-rw-r--r-- | packet/bgp/bgp_test.go | 36 |
2 files changed, 162 insertions, 8 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index ce594128..a3f137c4 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -1893,14 +1893,6 @@ func (er *EVPNEthernetSegmentRoute) Serialize() ([]byte, error) { return buf, nil } -type EVPNRouteTypeInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - rd() RouteDistinguisherInterface - MarshalJSON() ([]byte, error) -} - func (er *EVPNEthernetSegmentRoute) String() string { return fmt.Sprintf("[type:esi][rd:%s][esi:%d][ip:%s]", er.RD, er.ESI, er.IPAddress) } @@ -1921,6 +1913,129 @@ func (er *EVPNEthernetSegmentRoute) rd() RouteDistinguisherInterface { return er.RD } +type EVPNIPPrefixRoute struct { + RD RouteDistinguisherInterface + ESI EthernetSegmentIdentifier + ETag uint32 + IPPrefixLength uint8 + IPPrefix net.IP + GWIPAddress net.IP + Label uint32 +} + +func (er *EVPNIPPrefixRoute) DecodeFromBytes(data []byte) error { + if len(data) < 30 { // rd + esi + etag + prefix-len + ipv4 addr + label + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPN IP Prefix Route bytes available") + } + er.RD = GetRouteDistinguisher(data) + data = data[er.RD.Len():] + err := er.ESI.DecodeFromBytes(data) + if err != nil { + return err + } + data = data[10:] + er.ETag = binary.BigEndian.Uint32(data[0:4]) + data = data[4:] + er.IPPrefixLength = data[0] + addrLen := 4 + data = data[1:] + if len(data) > 19 { // ipv6 addr + label + addrLen = 16 + } + er.IPPrefix = net.IP(data[:addrLen]) + data = data[addrLen:] + switch { + case len(data) == 3: + er.Label = labelDecode(data) + case len(data) == addrLen+3: + er.GWIPAddress = net.IP(data[:addrLen]) + er.Label = labelDecode(data[addrLen:]) + default: + return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPN IP Prefix Route bytes available") + } + return nil +} + +func (er *EVPNIPPrefixRoute) Serialize() ([]byte, error) { + var buf []byte + var err error + if er.RD != nil { + buf, err = er.RD.Serialize() + if err != nil { + return nil, err + } + } else { + buf = make([]byte, 8) + } + tbuf, err := er.ESI.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, tbuf...) + + tbuf = make([]byte, 4) + binary.BigEndian.PutUint32(tbuf, er.ETag) + buf = append(buf, tbuf...) + + buf = append(buf, er.IPPrefixLength) + + if er.IPPrefix == nil { + return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("IP Prefix is nil")) + } else if er.IPPrefix.To4() != nil { + buf = append(buf, []byte(er.IPPrefix.To4())...) + } else { + buf = append(buf, []byte(er.IPPrefix)...) + } + + if er.GWIPAddress != nil { + if er.GWIPAddress.To4() != nil { + buf = append(buf, []byte(er.GWIPAddress.To4())...) + } else { + buf = append(buf, []byte(er.GWIPAddress.To16())...) + } + } + + tbuf = make([]byte, 3) + labelSerialize(er.Label, tbuf) + buf = append(buf, tbuf...) + + return buf, nil +} + +func (er *EVPNIPPrefixRoute) String() string { + return fmt.Sprintf("[type:Prefix][rd:%s][esi:%s][etag:%d][prefix:%s/%d][gw:%s][label:%d]", er.RD, er.ESI.String(), er.ETag, er.IPPrefix, er.IPPrefixLength, er.GWIPAddress, er.Label) +} + +func (er *EVPNIPPrefixRoute) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + RD RouteDistinguisherInterface `json:"rd"` + ESI string `json:"esi"` + Etag uint32 `json:"etag"` + Prefix string `json:"prefix"` + Gateway string `json:"gateway"` + Label uint32 `json:"label"` + }{ + RD: er.RD, + ESI: er.ESI.String(), + Etag: er.ETag, + Prefix: fmt.Sprintf("%s/%d", er.IPPrefix, er.IPPrefixLength), + Gateway: er.GWIPAddress.String(), + Label: er.Label, + }) +} + +func (er *EVPNIPPrefixRoute) rd() RouteDistinguisherInterface { + return er.RD +} + +type EVPNRouteTypeInterface interface { + DecodeFromBytes([]byte) error + Serialize() ([]byte, error) + String() string + rd() RouteDistinguisherInterface + MarshalJSON() ([]byte, error) +} + func getEVPNRouteType(t uint8) (EVPNRouteTypeInterface, error) { switch t { case EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY: @@ -1931,6 +2046,8 @@ func getEVPNRouteType(t uint8) (EVPNRouteTypeInterface, error) { return &EVPNMulticastEthernetTagRoute{}, nil case EVPN_ETHERNET_SEGMENT_ROUTE: return &EVPNEthernetSegmentRoute{}, nil + case EVPN_IP_PREFIX: + return &EVPNIPPrefixRoute{}, nil } return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Unknown EVPN Route type: %d", t)) } @@ -1940,6 +2057,7 @@ const ( EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT = 2 EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG = 3 EVPN_ETHERNET_SEGMENT_ROUTE = 4 + EVPN_IP_PREFIX = 5 ) type EVPNNLRI struct { diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go index 80dcc5af..0fcef12d 100644 --- a/packet/bgp/bgp_test.go +++ b/packet/bgp/bgp_test.go @@ -480,3 +480,39 @@ func Test_FlowSpecNlriVPN(t *testing.T) { t.Log(bytes.Equal(buf1, buf2)) } } + +func Test_EVPNIPPrefixRoute(t *testing.T) { + assert := assert.New(t) + rd, _ := ParseRouteDistinguisher("100:100") + r := &EVPNIPPrefixRoute{ + RD: rd, + ESI: EthernetSegmentIdentifier{ + Type: ESI_ARBITRARY, + Value: make([]byte, 9), + }, + ETag: 10, + IPPrefixLength: 24, + IPPrefix: net.IP{10, 10, 10, 0}, + GWIPAddress: net.IP{10, 10, 10, 10}, + Label: 1000, + } + n1 := NewEVPNNLRI(EVPN_IP_PREFIX, 0, r) + buf1, err := n1.Serialize() + assert.Nil(err) + n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_EVPN)) + assert.Nil(err) + err = n2.DecodeFromBytes(buf1) + assert.Nil(err) + buf2, _ := n2.Serialize() + t.Log(n1.RouteTypeData.(*EVPNIPPrefixRoute).ESI.Value, n2.(*EVPNNLRI).RouteTypeData.(*EVPNIPPrefixRoute).ESI.Value) + t.Log(reflect.DeepEqual(n1.RouteTypeData.(*EVPNIPPrefixRoute).ESI.Value, n2.(*EVPNNLRI).RouteTypeData.(*EVPNIPPrefixRoute).ESI.Value)) + if reflect.DeepEqual(n1, n2) { + t.Log("OK") + } else { + t.Error("Something wrong") + t.Error(len(buf1), n1, buf1) + t.Error(len(buf2), n2, buf2) + t.Log(bytes.Equal(buf1, buf2)) + } + +} |