diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-08-03 14:04:34 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-08-03 21:59:39 +0900 |
commit | 84dd9d6983564b37b7e146264c44da6874a08cf4 (patch) | |
tree | 1dcda7f9b8164aec87c0fc6c889f8499c6fd8492 | |
parent | d895c87c741084b4469bb260e3ef94f7793a8f92 (diff) |
api: use serialized buffer rather than protobuf struct to add paths
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r-- | api/gobgp.pb.go | 13 | ||||
-rw-r--r-- | api/gobgp.proto | 4 | ||||
-rw-r--r-- | gobgp/global.go | 254 | ||||
-rw-r--r-- | packet/bgp.go | 36 | ||||
-rw-r--r-- | server/grpc_server.go | 8 | ||||
-rw-r--r-- | server/server.go | 228 |
6 files changed, 195 insertions, 348 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 901abcad..2f5a50fa 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -590,21 +590,16 @@ func (m *Arguments) GetAf() *AddressFamily { } type ModPathArguments struct { - Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"` - Path *Path `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"` + Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"` + IsWithdraw bool `protobuf:"varint,2,opt,name=is_withdraw" json:"is_withdraw,omitempty"` + RawNlri []byte `protobuf:"bytes,3,opt,name=raw_nlri,proto3" json:"raw_nlri,omitempty"` + RawPattrs [][]byte `protobuf:"bytes,4,rep,name=raw_pattrs,proto3" json:"raw_pattrs,omitempty"` } func (m *ModPathArguments) Reset() { *m = ModPathArguments{} } func (m *ModPathArguments) String() string { return proto.CompactTextString(m) } func (*ModPathArguments) ProtoMessage() {} -func (m *ModPathArguments) GetPath() *Path { - if m != nil { - return m.Path - } - return nil -} - type PolicyArguments struct { Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"` Operation Operation `protobuf:"varint,2,opt,name=operation,enum=api.Operation" json:"operation,omitempty"` diff --git a/api/gobgp.proto b/api/gobgp.proto index e50e3c71..cb85db27 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -60,7 +60,9 @@ message Arguments { message ModPathArguments { Resource resource = 1; - Path path = 2; + bool is_withdraw = 2; + bytes raw_nlri = 3; + repeated bytes raw_pattrs = 4; } message PolicyArguments { diff --git a/gobgp/global.go b/gobgp/global.go index 79d91a65..9c272691 100644 --- a/gobgp/global.go +++ b/gobgp/global.go @@ -18,12 +18,12 @@ package main import ( "fmt" "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/packet" "github.com/spf13/cobra" "golang.org/x/net/context" "net" "os" "strconv" - "strings" ) func showGlobalRib(args []string) error { @@ -55,186 +55,178 @@ func modPath(modtype string, args []string) error { return err } - path := &api.Path{} + var nlri bgp.AddrPrefixInterface + var nexthop string + switch rf { case api.AF_IPV4_UC, api.AF_IPV6_UC: if len(args) != 1 { return fmt.Errorf("usage: global rib %s <prefix> -a { ipv4 | ipv6 }", modtype) } - prefix := args[0] - path.Nlri = &api.Nlri{ - Af: rf, - Prefix: prefix, + ip, net, _ := net.ParseCIDR(args[0]) + if rf == api.AF_IPV4_UC { + if ip.To4() == nil { + return fmt.Errorf("invalid ipv4 prefix") + } + nexthop = "0.0.0.0" + ones, _ := net.Mask.Size() + nlri = bgp.NewNLRInfo(uint8(ones), ip.String()) + } else { + if ip.To16() == nil { + return fmt.Errorf("invalid ipv6 prefix") + } + nexthop = "::" + ones, _ := net.Mask.Size() + nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) } case api.AF_IPV4_VPN, api.AF_IPV6_VPN: - if len(args) < 1 { - return fmt.Errorf("usage: global rib %s <rd>:<prefix> [<rt>...] -a { vpn-ipv4 | vpn-ipv6 }", modtype) + if len(args) < 3 || args[1] != "rd" { + return fmt.Errorf("usage: global rib %s <prefix> rd <rd> -a { vpn-ipv4 | vpn-ipv6 }", modtype) } - elems := strings.SplitN(args[0], ":", 4) - if len(elems) != 4 { - return fmt.Errorf("invalid <rd>:<prefix>: %s. hint. <rd> := <type>:<admin>:<assigned>", args[0]) - } - rd, err := parseRD(elems[:3]) + ip, net, _ := net.ParseCIDR(args[0]) + ones, _ := net.Mask.Size() + + rd, err := bgp.ParseRouteDistinguisher(args[2]) if err != nil { return err } - prefix := elems[3] - elems = strings.Split(prefix, "/") - if len(elems) != 2 { - return fmt.Errorf("invalid prefix: %s", prefix) - } - masklen, err := strconv.Atoi(elems[1]) - if err != nil { - return fmt.Errorf("invalid prefix: %s", prefix) - } + mpls := bgp.NewMPLSLabelStack() - nlri := &api.VPNNlri{ - Rd: rd, - IpAddr: elems[0], - IpAddrLen: uint32(masklen), - } - path.Nlri = &api.Nlri{ - Af: rf, - VpnNlri: nlri, + if rf == api.AF_IPV4_VPN { + if ip.To4() == nil { + return fmt.Errorf("invalid ipv4 prefix") + } + nexthop = "0.0.0.0" + nlri = bgp.NewLabeledVPNIPAddrPrefix(uint8(ones), ip.String(), *mpls, rd) + } else { + if ip.To16() == nil { + return fmt.Errorf("invalid ipv6 prefix") + } + nexthop = "::" + nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(ones), ip.String(), *mpls, rd) } - case api.AF_EVPN: - var nlri *api.EVPNNlri + case api.AF_EVPN: if len(args) < 1 { return fmt.Errorf("usage: global rib %s { macadv | multicast } ... -a evpn", modtype) } subtype := args[0] + args = args[1:] switch subtype { case "macadv": - if len(args) < 5 { - return fmt.Errorf("usage: global rib %s macadv <mac address> <ip address> <etag> <label> -a evpn", modtype) + if len(args) < 6 || args[4] != "rd" { + return fmt.Errorf("usage: global rib %s macadv <mac address> <ip address> <etag> <label> rd <rd> -a evpn", modtype) } - macAddr := args[1] - ipAddr := args[2] - eTag, err := strconv.Atoi(args[3]) + mac, err := net.ParseMAC(args[0]) if err != nil { - return fmt.Errorf("invalid eTag: %s. err: %s", args[3], err) + return fmt.Errorf("invalid mac: %s", args[0]) } - label, err := strconv.Atoi(args[4]) - if err != nil { - return fmt.Errorf("invalid label: %s. err: %s", args[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)}, - }, + var ip net.IP + iplen := 0 + if args[1] != "0.0.0.0" || args[1] != "::" { + ip = net.ParseIP(args[1]) + if ip == nil { + return fmt.Errorf("invalid ip prefix: %s", args[1]) + } + iplen = net.IPv4len * 8 + if ip.To4() == nil { + iplen = net.IPv6len * 8 + } } - case "multicast": - if len(args) < 3 { - return fmt.Errorf("usage : global rib %s multicast <etag> <label> -a evpn", modtype) + eTag, err := strconv.Atoi(args[2]) + if err != nil { + return fmt.Errorf("invalid eTag: %s. err: %s", args[2], err) } - eTag, err := strconv.Atoi(args[1]) + label, err := strconv.Atoi(args[3]) if err != nil { - return fmt.Errorf("invalid eTag: %s. err: %s", args[1], err) + return fmt.Errorf("invalid label: %s. err: %s", args[3], err) } - label, err := strconv.Atoi(args[2]) + rd, err := bgp.ParseRouteDistinguisher(args[5]) if err != nil { - return fmt.Errorf("invalid label: %s. err: %s", args[2], err) + return err } - nlri = &api.EVPNNlri{ - Type: api.EVPN_TYPE_INCLUSIVE_MULTICAST_ETHERNET_TAG, - MulticastEtag: &api.EvpnInclusiveMulticastEthernetTag{ - Etag: uint32(eTag), + macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{ + RD: rd, + ESI: bgp.EthernetSegmentIdentifier{ + Type: bgp.ESI_ARBITRARY, }, + MacAddressLength: 48, + MacAddress: mac, + IPAddressLength: uint8(iplen), + IPAddress: ip, + Labels: []uint32{uint32(label)}, + 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), - }, + nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv) + case "multicast": + if len(args) < 5 || args[2] != "rd" { + return fmt.Errorf("usage : global rib %s multicast <ip address> <etag> rd <rd> -a evpn", modtype) } - 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(args) < 1 { - return fmt.Errorf("usage: global rib %s <end point ip address> [<vni>] -a encap", modtype) - } - prefix := args[0] - - path.Nlri = &api.Nlri{ - Af: rf, - Prefix: prefix, - } + var ip net.IP + iplen := 0 + if args[0] != "0.0.0.0" || args[0] != "::" { + ip = net.ParseIP(args[0]) + if ip == nil { + return fmt.Errorf("invalid ip prefix: %s", args[0]) + } + iplen = net.IPv4len * 8 + if ip.To4() == nil { + iplen = net.IPv6len * 8 + } + } - if len(args) > 1 { - vni, err := strconv.Atoi(args[1]) + eTag, err := strconv.Atoi(args[1]) if err != nil { - return fmt.Errorf("invalid vni: %s", args[1]) - } - subTlv := &api.TunnelEncapSubTLV{ - Type: api.ENCAP_SUBTLV_TYPE_COLOR, - Color: uint32(vni), - } - tlv := &api.TunnelEncapTLV{ - Type: api.TUNNEL_TYPE_VXLAN, - SubTlv: []*api.TunnelEncapSubTLV{subTlv}, - } - attr := &api.PathAttr{ - Type: api.BGP_ATTR_TYPE_TUNNEL_ENCAP, - TunnelEncap: []*api.TunnelEncapTLV{tlv}, + return fmt.Errorf("invalid eTag: %s. err: %s", args[1], err) } - path.Attrs = append(path.Attrs, attr) - } - case api.AF_RTC: - if !(len(args) == 3 && args[0] == "default") && len(args) < 4 { - return fmt.Errorf("usage: global rib add <asn> <local admin> -a rtc") - } - var asn, admin int - - if args[0] != "default" { - asn, err = strconv.Atoi(args[0]) + rd, err := bgp.ParseRouteDistinguisher(args[3]) if err != nil { - return fmt.Errorf("invalid asn: %s", args[0]) + return err } - admin, err = strconv.Atoi(args[1]) - if err != nil { - return fmt.Errorf("invalid local admin: %s", args[1]) + + multicastEtag := &bgp.EVPNMulticastEthernetTagRoute{ + RD: rd, + IPAddressLength: uint8(iplen), + IPAddress: ip, + ETag: uint32(eTag), } + nlri = bgp.NewEVPNNLRI(bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 0, multicastEtag) + default: + return fmt.Errorf("usage: global rib add { macadv | multicast | ... -a evpn") } - path.Nlri = &api.Nlri{ - Af: rf, - RtNlri: &api.RTNlri{ - Target: &api.ExtendedCommunity{ - Type: api.EXTENDED_COMMUNITIE_TYPE_TWO_OCTET_AS_SPECIFIC, - Subtype: api.EXTENDED_COMMUNITIE_SUBTYPE_ROUTE_TARGET, - Asn: uint32(asn), - LocalAdmin: uint32(admin), - }, - }, - } + nexthop = "0.0.0.0" + default: + return fmt.Errorf("Unsupported route family: %s", rf) } + + arg := &api.ModPathArguments{ + Resource: api.Resource_GLOBAL, + RawPattrs: make([][]byte, 0), + } + switch modtype { case CMD_ADD: - path.IsWithdraw = false + arg.IsWithdraw = false case CMD_DEL: - path.IsWithdraw = true + arg.IsWithdraw = true } - arg := &api.ModPathArguments{ - Resource: api.Resource_GLOBAL, - Path: path, + if rf == api.AF_IPV4_UC { + arg.RawNlri, _ = nlri.Serialize() + n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize() + arg.RawPattrs = append(arg.RawPattrs, n) + } else { + mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize() + arg.RawPattrs = append(arg.RawPattrs, mpreach) } + + origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP).Serialize() + arg.RawPattrs = append(arg.RawPattrs, origin) + stream, err := client.ModPath(context.Background()) if err != nil { return err diff --git a/packet/bgp.go b/packet/bgp.go index b5bf7924..7fd4f9e6 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -24,6 +24,8 @@ import ( "math" "net" "reflect" + "regexp" + "strconv" "strings" ) @@ -856,6 +858,40 @@ func getRouteDistinguisher(data []byte) RouteDistinguisherInterface { return rd } +func parseRd(input string) ([]string, error) { + exp := regexp.MustCompile("^((\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)|((\\d+)\\.)?(\\d+)):(\\d+)$") + group := exp.FindSubmatch([]byte(input)) + if len(group) != 10 { + return nil, fmt.Errorf("failed to parse") + } + elems := make([]string, 0, len(group)) + for _, elem := range group { + elems = append(elems, string(elem)) + } + return elems, nil +} + +func ParseRouteDistinguisher(rd string) (RouteDistinguisherInterface, error) { + elems, err := parseRd(rd) + if err != nil { + return nil, err + } + assigned, _ := strconv.Atoi(elems[9]) + ip := net.ParseIP(elems[1]) + switch { + case ip.To4() != nil: + return NewRouteDistinguisherIPAddressAS(elems[1], uint16(assigned)), nil + case elems[6] == "" && elems[7] == "": + asn, _ := strconv.Atoi(elems[8]) + return NewRouteDistinguisherTwoOctetAS(uint16(asn), uint32(assigned)), nil + default: + fst, _ := strconv.Atoi(elems[7]) + snd, _ := strconv.Atoi(elems[8]) + asn := fst<<16 | snd + return NewRouteDistinguisherFourOctetAS(uint32(asn), uint16(assigned)), nil + } +} + // // RFC3107 Carrying Label Information in BGP-4 // diff --git a/server/grpc_server.go b/server/grpc_server.go index 55dd4381..e72b42aa 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -334,15 +334,11 @@ func (s *Server) ModPath(stream api.Grpc_ModPathServer) error { } reqType := REQ_GLOBAL_ADD - if arg.Path.IsWithdraw { + if arg.IsWithdraw { reqType = REQ_GLOBAL_DELETE } - rf, err := convertAf2Rf(arg.Path.Nlri.Af) - if err != nil { - return err - } - req := NewGrpcRequest(reqType, "", rf, arg.Path) + req := NewGrpcRequest(reqType, "", bgp.RouteFamily(0), arg) s.bgpServerCh <- req res := <-req.ResponseCh diff --git a/server/server.go b/server/server.go index b2ad3764..8eca9d75 100644 --- a/server/server.go +++ b/server/server.go @@ -737,15 +737,12 @@ func (server *BgpServer) checkNeighborRequest(grpcReq *GrpcRequest) (*Peer, erro func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*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)) - rf := grpcReq.RouteFamily - path, ok := grpcReq.Data.(*api.Path) + args, ok := grpcReq.Data.(*api.ModPathArguments) if !ok { result.ResponseErr = fmt.Errorf("type assertion failed") goto ERR @@ -754,219 +751,48 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t isWithdraw = true } - 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) + if len(args.RawNlri) > 0 { + nlri = &bgp.NLRInfo{} + err := nlri.DecodeFromBytes(args.RawNlri) + if err != nil { + result.ResponseErr = err goto ERR } - ones, _ := net.Mask.Size() - nlri = &bgp.NLRInfo{ - IPAddrPrefix: *bgp.NewIPAddrPrefix(uint8(ones), ip.String()), - } - - pattr = append(pattr, bgp.NewPathAttributeNextHop("0.0.0.0")) - - case bgp.RF_IPv6_UC: + } - ip, net, _ := net.ParseCIDR(path.Nlri.Prefix) - if ip.To16() == nil { - result.ResponseErr = fmt.Errorf("Invalid ipv6 prefix: %s", path.Nlri.Prefix) + for _, attr := range args.RawPattrs { + p, err := bgp.GetPathAttribute(attr) + if err != nil { + result.ResponseErr = err goto ERR } - ones, _ := net.Mask.Size() - nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) - - pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})) - - case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN: - var rd bgp.RouteDistinguisherInterface - switch path.Nlri.VpnNlri.Rd.Type { - case api.ROUTE_DISTINGUISHER_TYPE_TWO_OCTET_AS: - a, err := strconv.Atoi(path.Nlri.VpnNlri.Rd.Admin) - if err != nil { - result.ResponseErr = fmt.Errorf("Invalid admin value: %s", path.Nlri.VpnNlri.Rd.Admin) - goto ERR - } - rd = bgp.NewRouteDistinguisherTwoOctetAS(uint16(a), path.Nlri.VpnNlri.Rd.Assigned) - case api.ROUTE_DISTINGUISHER_TYPE_IP4: - ip := net.ParseIP(path.Nlri.VpnNlri.Rd.Admin) - if ip.To4() == nil { - result.ResponseErr = fmt.Errorf("Invalid ipv4 prefix: %s", path.Nlri.VpnNlri.Rd.Admin) - goto ERR - } - assigned := uint16(path.Nlri.VpnNlri.Rd.Assigned) - rd = bgp.NewRouteDistinguisherIPAddressAS(path.Nlri.VpnNlri.Rd.Admin, assigned) - case api.ROUTE_DISTINGUISHER_TYPE_FOUR_OCTET_AS: - a, err := strconv.Atoi(path.Nlri.VpnNlri.Rd.Admin) - if err != nil { - result.ResponseErr = fmt.Errorf("Invalid admin value: %s", path.Nlri.VpnNlri.Rd.Admin) - goto ERR - } - admin := uint32(a) - assigned := uint16(path.Nlri.VpnNlri.Rd.Assigned) - rd = bgp.NewRouteDistinguisherFourOctetAS(admin, assigned) - } - - mpls := bgp.NewMPLSLabelStack(0) - if rf == bgp.RF_IPv4_VPN { - nlri = bgp.NewLabeledVPNIPAddrPrefix(uint8(path.Nlri.VpnNlri.IpAddrLen), path.Nlri.VpnNlri.IpAddr, *mpls, rd) - pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri})) - } else { - nlri = bgp.NewLabeledVPNIPv6AddrPrefix(uint8(path.Nlri.VpnNlri.IpAddrLen), path.Nlri.VpnNlri.IpAddr, *mpls, rd) - pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})) - } - - case bgp.RF_EVPN: - 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 - - 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) - } - 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) + err = p.DecodeFromBytes(attr) + if err != nil { + result.ResponseErr = err goto ERR - } - nlri = bgp.NewEncapNLRI(endpoint.String()) - pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri})) - iterSubTlvs := func(subTlvs []*api.TunnelEncapSubTLV) { - for _, subTlv := range subTlvs { - if subTlv.Type == api.ENCAP_SUBTLV_TYPE_COLOR { - color := subTlv.Color - subTlv := &bgp.TunnelEncapSubTLV{ - Type: bgp.ENCAP_SUBTLV_TYPE_COLOR, - Value: &bgp.TunnelEncapSubTLVColor{color}, - } - tlv := &bgp.TunnelEncapTLV{ - Type: bgp.TUNNEL_TYPE_VXLAN, - Value: []*bgp.TunnelEncapSubTLV{subTlv}, - } - attr := bgp.NewPathAttributeTunnelEncap([]*bgp.TunnelEncapTLV{tlv}) - pattr = append(pattr, attr) - break - } - } - } - - iterTlvs := func(tlvs []*api.TunnelEncapTLV) { - for _, tlv := range tlvs { - if tlv.Type == api.TUNNEL_TYPE_VXLAN { - iterSubTlvs(tlv.SubTlv) - break - } - } - } - - func(attrs []*api.PathAttr) { - for _, attr := range attrs { - if attr.Type == api.BGP_ATTR_TYPE_TUNNEL_ENCAP { - iterTlvs(attr.TunnelEncap) - break - } - } - }(path.Attrs) - - case bgp.RF_RTC_UC: - var ec bgp.ExtendedCommunityInterface - target := path.Nlri.RtNlri.Target - ec_type := target.Type - ec_subtype := target.Subtype - switch ec_type { - case api.EXTENDED_COMMUNITIE_TYPE_TWO_OCTET_AS_SPECIFIC: - if target.Asn == 0 && target.LocalAdmin == 0 { - break - } - ec = &bgp.TwoOctetAsSpecificExtended{ - SubType: bgp.ExtendedCommunityAttrSubType(ec_subtype), - AS: uint16(target.Asn), - LocalAdmin: target.LocalAdmin, - IsTransitive: true, + switch p.GetType() { + case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: + value := p.(*bgp.PathAttributeMpReachNLRI).Value + if len(value) != 1 { + result.ResponseErr = fmt.Errorf("include only one route in mp_reach_nlri") + goto ERR } + nlri = p.(*bgp.PathAttributeMpReachNLRI).Value[0] + fallthrough default: - result.ResponseErr = fmt.Errorf("Invalid endpoint ip address: %s", path.Nlri.Prefix) - goto ERR + pattr = append(pattr, p) } + } - nlri = bgp.NewRouteTargetMembershipNLRI(peerInfo.AS, ec) - - pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("0.0.0.0", []bgp.AddrPrefixInterface{nlri})) - - default: - result.ResponseErr = fmt.Errorf("Unsupported address family: %s", rf) + if nlri == nil { + result.ResponseErr = fmt.Errorf("no nlri included") goto ERR } - p = table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now()) - return []*table.Path{p} + return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now())} ERR: grpcReq.ResponseCh <- result close(grpcReq.ResponseCh) |