diff options
-rw-r--r-- | api/gobgp.pb.go | 22 | ||||
-rw-r--r-- | api/gobgp.proto | 9 | ||||
-rw-r--r-- | gobgp/global.go | 83 | ||||
-rw-r--r-- | packet/bgp.go | 11 | ||||
-rw-r--r-- | server/server.go | 140 |
5 files changed, 195 insertions, 70 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index e0cde493..bc1cad51 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -21,6 +21,7 @@ It has these top-level messages: ExtendedCommunity EVPNNlri EvpnMacIpAdvertisement + EvpnInclusiveMulticastEthernetTag RTNlri Nlri TunnelEncapSubTLV @@ -690,7 +691,8 @@ func (*ExtendedCommunity) ProtoMessage() {} type EVPNNlri struct { Type EVPN_TYPE `protobuf:"varint,1,opt,name=type,enum=api.EVPN_TYPE" json:"type,omitempty"` // EvpnAutoDiscoveryRoute = 2; - MacIpAdv *EvpnMacIpAdvertisement `protobuf:"bytes,3,opt,name=mac_ip_adv" json:"mac_ip_adv,omitempty"` + MacIpAdv *EvpnMacIpAdvertisement `protobuf:"bytes,3,opt,name=mac_ip_adv" json:"mac_ip_adv,omitempty"` + MulticastEtag *EvpnInclusiveMulticastEthernetTag `protobuf:"bytes,4,opt,name=multicast_etag" json:"multicast_etag,omitempty"` } func (m *EVPNNlri) Reset() { *m = EVPNNlri{} } @@ -704,6 +706,13 @@ func (m *EVPNNlri) GetMacIpAdv() *EvpnMacIpAdvertisement { return nil } +func (m *EVPNNlri) GetMulticastEtag() *EvpnInclusiveMulticastEthernetTag { + if m != nil { + return m.MulticastEtag + } + return nil +} + type EvpnMacIpAdvertisement struct { MacAddr string `protobuf:"bytes,1,opt,name=mac_addr" json:"mac_addr,omitempty"` MacAddrLen uint32 `protobuf:"varint,2,opt,name=mac_addr_len" json:"mac_addr_len,omitempty"` @@ -719,6 +728,17 @@ func (m *EvpnMacIpAdvertisement) Reset() { *m = EvpnMacIpAdvertisement{} func (m *EvpnMacIpAdvertisement) String() string { return proto.CompactTextString(m) } func (*EvpnMacIpAdvertisement) ProtoMessage() {} +type EvpnInclusiveMulticastEthernetTag struct { + Rd string `protobuf:"bytes,1,opt,name=rd" json:"rd,omitempty"` + Etag uint32 `protobuf:"varint,2,opt,name=etag" json:"etag,omitempty"` + IpAddr string `protobuf:"bytes,3,opt,name=ip_addr" json:"ip_addr,omitempty"` + IpAddrLen uint32 `protobuf:"varint,4,opt,name=ip_addr_len" json:"ip_addr_len,omitempty"` +} + +func (m *EvpnInclusiveMulticastEthernetTag) Reset() { *m = EvpnInclusiveMulticastEthernetTag{} } +func (m *EvpnInclusiveMulticastEthernetTag) String() string { return proto.CompactTextString(m) } +func (*EvpnInclusiveMulticastEthernetTag) ProtoMessage() {} + type RTNlri struct { Asn uint32 `protobuf:"varint,1,opt,name=asn" json:"asn,omitempty"` Target *ExtendedCommunity `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"` diff --git a/api/gobgp.proto b/api/gobgp.proto index 1467ab51..1e789502 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -210,7 +210,7 @@ message EVPNNlri { EVPN_TYPE type = 1; // EvpnAutoDiscoveryRoute = 2; EvpnMacIpAdvertisement mac_ip_adv = 3; -// EvpnInclusiveMulticastEthernetTag = 4; + EvpnInclusiveMulticastEthernetTag multicast_etag = 4; // EvpnEthernetSegmentRoute = 5; } @@ -225,6 +225,13 @@ message EvpnMacIpAdvertisement { repeated uint32 labels = 8; } +message EvpnInclusiveMulticastEthernetTag { + string rd = 1; + uint32 etag = 2; + string ip_addr = 3; + uint32 ip_addr_len = 4; +} + message RTNlri { uint32 asn = 1; ExtendedCommunity target = 2; diff --git a/gobgp/global.go b/gobgp/global.go index 00b0da6c..8744449f 100644 --- a/gobgp/global.go +++ b/gobgp/global.go @@ -21,6 +21,7 @@ import ( "github.com/spf13/cobra" "golang.org/x/net/context" "net" + "os" "strconv" ) @@ -36,7 +37,7 @@ func modPath(modtype string, eArgs []string) error { } path := &api.Path{} - var prefix, macAddr, ipAddr string + var prefix string switch rf { case api.AF_IPV4_UC, api.AF_IPV6_UC: if len(eArgs) == 1 || len(eArgs) == 3 { @@ -49,21 +50,71 @@ func modPath(modtype string, eArgs []string) error { Prefix: prefix, } case api.AF_EVPN: - if len(eArgs) == 4 { - macAddr = eArgs[0] - ipAddr = eArgs[1] - } else { - return fmt.Errorf("usage: global rib %s <mac address> <ip address> -a evpn", modtype) + var nlri *api.EVPNNlri + + if len(eArgs) < 1 { + return fmt.Errorf("usage: global rib %s { macadv | multicast } ... -a evpn", modtype) } - path.Nlri = &api.Nlri{ - Af: rf, - EvpnNlri: &api.EVPNNlri{ + subtype := eArgs[0] + + switch subtype { + case "macadv": + if len(eArgs) < 5 { + return fmt.Errorf("usage: global rib %s macadv <mac address> <ip address> <etag> <label> -a evpn", modtype) + } + macAddr := eArgs[1] + ipAddr := eArgs[2] + eTag, err := strconv.Atoi(eArgs[3]) + if err != nil { + return fmt.Errorf("invalid eTag: %s. err: %s", eArgs[3], err) + } + label, err := strconv.Atoi(eArgs[4]) + if err != nil { + return fmt.Errorf("invalid label: %s. err: %s", eArgs[4], err) + } + nlri = &api.EVPNNlri{ Type: api.EVPN_TYPE_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, MacIpAdv: &api.EvpnMacIpAdvertisement{ MacAddr: macAddr, IpAddr: ipAddr, + Etag: uint32(eTag), + Labels: []uint32{uint32(label)}, }, - }, + } + case "multicast": + if len(eArgs) < 3 { + return fmt.Errorf("usage : global rib %s multicast <etag> <label> -a evpn", modtype) + } + eTag, err := strconv.Atoi(eArgs[1]) + if err != nil { + return fmt.Errorf("invalid eTag: %s. err: %s", eArgs[1], err) + } + label, err := strconv.Atoi(eArgs[2]) + if err != nil { + return fmt.Errorf("invalid label: %s. err: %s", eArgs[2], err) + } + nlri = &api.EVPNNlri{ + Type: api.EVPN_TYPE_INCLUSIVE_MULTICAST_ETHERNET_TAG, + MulticastEtag: &api.EvpnInclusiveMulticastEthernetTag{ + Etag: uint32(eTag), + }, + } + + attr := &api.PathAttr{ + Type: api.BGP_ATTR_TYPE_PMSI_TUNNEL, + PmsiTunnel: &api.PmsiTunnel{ + Type: api.PMSI_TUNNEL_TYPE_INGRESS_REPL, + Label: uint32(label), + }, + } + + path.Attrs = append(path.Attrs, attr) + default: + return fmt.Errorf("usage: global rib add { macadv | multicast | ... -a evpn") + } + path.Nlri = &api.Nlri{ + Af: rf, + EvpnNlri: nlri, } case api.AF_ENCAP: if len(eArgs) < 3 { @@ -172,14 +223,22 @@ func NewGlobalCmd() *cobra.Command { addCmd := &cobra.Command{ Use: CMD_ADD, Run: func(cmd *cobra.Command, args []string) { - modPath(CMD_ADD, args) + err := modPath(CMD_ADD, args) + if err != nil { + fmt.Println(err) + os.Exit(1) + } }, } delCmd := &cobra.Command{ Use: CMD_DEL, Run: func(cmd *cobra.Command, args []string) { - modPath(CMD_DEL, args) + err := modPath(CMD_DEL, args) + if err != nil { + fmt.Println(err) + os.Exit(1) + } }, } diff --git a/packet/bgp.go b/packet/bgp.go index 4301d7c1..bdd07911 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -797,7 +797,7 @@ func NewRouteDistinguisherIPAddressAS(admin string, assigned uint16) *RouteDisti DefaultRouteDistinguisher: DefaultRouteDistinguisher{ Type: BGP_RD_IPV4_ADDRESS, }, - Admin: net.ParseIP(admin), + Admin: net.ParseIP(admin).To4(), Assigned: assigned, } } @@ -3037,6 +3037,15 @@ func (e *TwoOctetAsSpecificExtended) ToApiStruct() *api.ExtendedCommunity { } } +func NewTwoOctetAsSpecificExtended(as uint16, rt uint32, isTransitive bool) *TwoOctetAsSpecificExtended { + return &TwoOctetAsSpecificExtended{ + SubType: ExtendedCommunityAttrSubType(EC_SUBTYPE_ROUTE_TARGET), + AS: as, + LocalAdmin: rt, + IsTransitive: isTransitive, + } +} + type IPv4AddressSpecificExtended struct { SubType ExtendedCommunityAttrSubType IPv4 net.IP diff --git a/server/server.go b/server/server.go index 29f3a1fd..437e90da 100644 --- a/server/server.go +++ b/server/server.go @@ -668,36 +668,32 @@ func (server *BgpServer) checkNeighborRequest(grpcReq *GrpcRequest) (*Peer, erro } func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path { - pathList := []*table.Path{} + var isWithdraw bool + var p *table.Path + var nlri bgp.AddrPrefixInterface result := &GrpcResponse{} + pattr := make([]bgp.PathAttributeInterface, 0) + pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)) + asparam := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{peerInfo.AS}) + pattr = append(pattr, bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{asparam})) + rf := grpcReq.RouteFamily path, ok := grpcReq.Data.(*api.Path) if !ok { result.ResponseErr = fmt.Errorf("type assertion failed") - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } - var isWithdraw bool if grpcReq.RequestType == REQ_GLOBAL_DELETE { isWithdraw = true } - var nlri bgp.AddrPrefixInterface - pattr := make([]bgp.PathAttributeInterface, 0) - pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)) - asparam := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{peerInfo.AS}) - pattr = append(pattr, bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{asparam})) - switch rf { case bgp.RF_IPv4_UC: ip, net, _ := net.ParseCIDR(path.Nlri.Prefix) if ip.To4() == nil { result.ResponseErr = fmt.Errorf("Invalid ipv4 prefix: %s", path.Nlri.Prefix) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } ones, _ := net.Mask.Size() nlri = &bgp.NLRInfo{ @@ -711,9 +707,7 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t ip, net, _ := net.ParseCIDR(path.Nlri.Prefix) if ip.To16() == nil { result.ResponseErr = fmt.Errorf("Invalid ipv6 prefix: %s", path.Nlri.Prefix) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } ones, _ := net.Mask.Size() nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) @@ -721,45 +715,80 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})) case bgp.RF_EVPN: - mac, err := net.ParseMAC(path.Nlri.EvpnNlri.MacIpAdv.MacAddr) - if err != nil { - result.ResponseErr = fmt.Errorf("Invalid mac: %s", path.Nlri.EvpnNlri.MacIpAdv.MacAddr) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList - } - ip := net.ParseIP(path.Nlri.EvpnNlri.MacIpAdv.IpAddr) - if ip == nil { - result.ResponseErr = fmt.Errorf("Invalid ip prefix: %s", path.Nlri.EvpnNlri.MacIpAdv.IpAddr) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList - } - iplen := net.IPv4len * 8 - if ip.To4() == nil { - iplen = net.IPv6len * 8 + if peerInfo.AS > (1<<16 - 1) { + result.ResponseErr = fmt.Errorf("evpn path can't be created in 4byte-AS env") } + asn := uint16(peerInfo.AS) + routerId := peerInfo.LocalID + var eTag uint32 - macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{ - RD: bgp.NewRouteDistinguisherTwoOctetAS(0, 0), - ESI: bgp.EthernetSegmentIdentifier{ - Type: bgp.ESI_ARBITRARY, - }, - MacAddressLength: 48, - MacAddress: mac, - IPAddressLength: uint8(iplen), - IPAddress: ip, - Labels: []uint32{0}, + switch path.Nlri.EvpnNlri.Type { + case bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT: + mac, err := net.ParseMAC(path.Nlri.EvpnNlri.MacIpAdv.MacAddr) + if err != nil { + result.ResponseErr = fmt.Errorf("Invalid mac: %s", path.Nlri.EvpnNlri.MacIpAdv.MacAddr) + goto ERR + } + var ip net.IP + iplen := 0 + if path.Nlri.EvpnNlri.MacIpAdv.IpAddr != "0.0.0.0" { + ip = net.ParseIP(path.Nlri.EvpnNlri.MacIpAdv.IpAddr) + if ip == nil { + result.ResponseErr = fmt.Errorf("Invalid ip prefix: %s", path.Nlri.EvpnNlri.MacIpAdv.IpAddr) + goto ERR + } + iplen = net.IPv4len * 8 + if ip.To4() == nil { + iplen = net.IPv6len * 8 + } + } + + var labels []uint32 + if len(path.Nlri.EvpnNlri.MacIpAdv.Labels) == 0 { + labels = []uint32{0} + } else { + labels = path.Nlri.EvpnNlri.MacIpAdv.Labels + } + + eTag = path.Nlri.EvpnNlri.MacIpAdv.Etag + macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{ + RD: bgp.NewRouteDistinguisherIPAddressAS(routerId.String(), 0), + ESI: bgp.EthernetSegmentIdentifier{ + Type: bgp.ESI_ARBITRARY, + }, + MacAddressLength: 48, + MacAddress: mac, + IPAddressLength: uint8(iplen), + IPAddress: ip, + Labels: labels, + ETag: eTag, + } + nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv) + case bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG: + eTag = path.Nlri.EvpnNlri.MulticastEtag.Etag + ip := peerInfo.LocalID + iplen := net.IPv4len * 8 + if ip.To4() == nil { + iplen = net.IPv6len * 8 + } + multicastEtag := &bgp.EVPNMulticastEthernetTagRoute{ + RD: bgp.NewRouteDistinguisherIPAddressAS(routerId.String(), 0), + IPAddressLength: uint8(iplen), + IPAddress: ip, + ETag: eTag, + } + nlri = bgp.NewEVPNNLRI(bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 0, multicastEtag) } - nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv) pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri})) + isTransitive := true + rt := bgp.NewTwoOctetAsSpecificExtended(asn, eTag, isTransitive) + encap := &bgp.OpaqueExtended{isTransitive, &bgp.EncapExtended{bgp.TUNNEL_TYPE_VXLAN}} + pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities([]bgp.ExtendedCommunityInterface{rt, encap})) case bgp.RF_ENCAP: endpoint := net.ParseIP(path.Nlri.Prefix) if endpoint == nil { result.ResponseErr = fmt.Errorf("Invalid endpoint ip address: %s", path.Nlri.Prefix) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } nlri = bgp.NewEncapNLRI(endpoint.String()) @@ -820,9 +849,7 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t } default: result.ResponseErr = fmt.Errorf("Invalid endpoint ip address: %s", path.Nlri.Prefix) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } nlri = bgp.NewRouteTargetMembershipNLRI(peerInfo.AS, ec) @@ -831,13 +858,16 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t default: result.ResponseErr = fmt.Errorf("Unsupported address family: %s", rf) - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) - return pathList + goto ERR } - p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now()) + p = table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now()) return []*table.Path{p} +ERR: + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + return []*table.Path{} + } func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { |