From 2fc9b887fc63da94e173f75dd15330254e35647c Mon Sep 17 00:00:00 2001 From: ISHIDA Wataru Date: Thu, 2 Jul 2015 23:39:20 +0900 Subject: server/cli: support add/delete vpnv4/vpnv6 routes $ gobgp global rib add 1:10.0.0.1:1000:10.0.0.0/24 -a vpnv4 Signed-off-by: ISHIDA Wataru --- api/gobgp.pb.go | 62 ++++++++++++++++++++++++++++ api/gobgp.proto | 20 +++++++++ api/util.go | 2 + config/default.go | 2 + gobgp/common.go | 4 ++ gobgp/global.go | 109 ++++++++++++++++++++++++++++++++++++-------------- packet/bgp.go | 71 +++++++++++++++++--------------- packet/bgp_test.go | 8 ++-- server/grpc_server.go | 4 ++ server/server.go | 38 ++++++++++++++++++ 10 files changed, 253 insertions(+), 67 deletions(-) diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index e4214a66..b0897927 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -14,6 +14,7 @@ It has these top-level messages: ModPathArguments PolicyArguments AddressFamily + RouteDistinguisher GracefulRestartTuple GracefulRestart Capability @@ -23,6 +24,7 @@ It has these top-level messages: EvpnMacIpAdvertisement EvpnInclusiveMulticastEthernetTag RTNlri + VPNNlri Nlri TunnelEncapSubTLV TunnelEncapTLV @@ -198,6 +200,29 @@ func (x SAFI) String() string { return proto.EnumName(SAFI_name, int32(x)) } +type ROUTE_DISTINGUISHER_TYPE int32 + +const ( + ROUTE_DISTINGUISHER_TYPE_TWO_OCTET_AS ROUTE_DISTINGUISHER_TYPE = 0 + ROUTE_DISTINGUISHER_TYPE_IP4 ROUTE_DISTINGUISHER_TYPE = 1 + ROUTE_DISTINGUISHER_TYPE_FOUR_OCTET_AS ROUTE_DISTINGUISHER_TYPE = 2 +) + +var ROUTE_DISTINGUISHER_TYPE_name = map[int32]string{ + 0: "TWO_OCTET_AS", + 1: "IP4", + 2: "FOUR_OCTET_AS", +} +var ROUTE_DISTINGUISHER_TYPE_value = map[string]int32{ + "TWO_OCTET_AS": 0, + "IP4": 1, + "FOUR_OCTET_AS": 2, +} + +func (x ROUTE_DISTINGUISHER_TYPE) String() string { + return proto.EnumName(ROUTE_DISTINGUISHER_TYPE_name, int32(x)) +} + type BGP_CAPABILITY int32 const ( @@ -608,6 +633,16 @@ func (m *AddressFamily) Reset() { *m = AddressFamily{} } func (m *AddressFamily) String() string { return proto.CompactTextString(m) } func (*AddressFamily) ProtoMessage() {} +type RouteDistinguisher struct { + Type ROUTE_DISTINGUISHER_TYPE `protobuf:"varint,1,opt,name=type,enum=api.ROUTE_DISTINGUISHER_TYPE" json:"type,omitempty"` + Admin string `protobuf:"bytes,2,opt,name=admin" json:"admin,omitempty"` + Assigned uint32 `protobuf:"varint,3,opt,name=assigned" json:"assigned,omitempty"` +} + +func (m *RouteDistinguisher) Reset() { *m = RouteDistinguisher{} } +func (m *RouteDistinguisher) String() string { return proto.CompactTextString(m) } +func (*RouteDistinguisher) ProtoMessage() {} + type GracefulRestartTuple struct { Af *AddressFamily `protobuf:"bytes,1,opt,name=af" json:"af,omitempty"` Flags uint32 `protobuf:"varint,2,opt,name=flags" json:"flags,omitempty"` @@ -756,12 +791,31 @@ func (m *RTNlri) GetTarget() *ExtendedCommunity { return nil } +type VPNNlri struct { + Rd *RouteDistinguisher `protobuf:"bytes,1,opt,name=rd" json:"rd,omitempty"` + Labels []uint32 `protobuf:"varint,2,rep,name=labels" json:"labels,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 *VPNNlri) Reset() { *m = VPNNlri{} } +func (m *VPNNlri) String() string { return proto.CompactTextString(m) } +func (*VPNNlri) ProtoMessage() {} + +func (m *VPNNlri) GetRd() *RouteDistinguisher { + if m != nil { + return m.Rd + } + return nil +} + type Nlri struct { Af *AddressFamily `protobuf:"bytes,1,opt,name=af" json:"af,omitempty"` Prefix string `protobuf:"bytes,2,opt,name=prefix" json:"prefix,omitempty"` Nexthop string `protobuf:"bytes,3,opt,name=nexthop" json:"nexthop,omitempty"` EvpnNlri *EVPNNlri `protobuf:"bytes,4,opt,name=evpn_nlri" json:"evpn_nlri,omitempty"` RtNlri *RTNlri `protobuf:"bytes,5,opt,name=rt_nlri" json:"rt_nlri,omitempty"` + VpnNlri *VPNNlri `protobuf:"bytes,6,opt,name=vpn_nlri" json:"vpn_nlri,omitempty"` } func (m *Nlri) Reset() { *m = Nlri{} } @@ -789,6 +843,13 @@ func (m *Nlri) GetRtNlri() *RTNlri { return nil } +func (m *Nlri) GetVpnNlri() *VPNNlri { + if m != nil { + return m.VpnNlri + } + return nil +} + type TunnelEncapSubTLV struct { Type ENCAP_SUBTLV_TYPE `protobuf:"varint,1,opt,name=type,enum=api.ENCAP_SUBTLV_TYPE" json:"type,omitempty"` Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` @@ -1255,6 +1316,7 @@ func init() { proto.RegisterEnum("api.Operation", Operation_name, Operation_value) proto.RegisterEnum("api.AFI", AFI_name, AFI_value) proto.RegisterEnum("api.SAFI", SAFI_name, SAFI_value) + proto.RegisterEnum("api.ROUTE_DISTINGUISHER_TYPE", ROUTE_DISTINGUISHER_TYPE_name, ROUTE_DISTINGUISHER_TYPE_value) proto.RegisterEnum("api.BGP_CAPABILITY", BGP_CAPABILITY_name, BGP_CAPABILITY_value) proto.RegisterEnum("api.Origin", Origin_name, Origin_value) proto.RegisterEnum("api.EXTENDED_COMMUNITIE_TYPE", EXTENDED_COMMUNITIE_TYPE_name, EXTENDED_COMMUNITIE_TYPE_value) diff --git a/api/gobgp.proto b/api/gobgp.proto index d52f96dc..677ee963 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -113,6 +113,18 @@ message AddressFamily { SAFI Safi = 2; } +enum ROUTE_DISTINGUISHER_TYPE { + TWO_OCTET_AS = 0; + IP4 = 1; + FOUR_OCTET_AS = 2; +} + +message RouteDistinguisher { + ROUTE_DISTINGUISHER_TYPE type = 1; + string admin = 2; + uint32 assigned = 3; +} + enum BGP_CAPABILITY { UNKNOWN_CAP = 0; MULTIPROTOCOL = 1; @@ -238,12 +250,20 @@ message RTNlri { uint32 length = 3; } +message VPNNlri { + RouteDistinguisher rd = 1; + repeated uint32 labels = 2; + string ip_addr = 3; + uint32 ip_addr_len = 4; +} + message Nlri { AddressFamily af = 1; string prefix = 2; string nexthop = 3; EVPNNlri evpn_nlri = 4; RTNlri rt_nlri = 5; + VPNNlri vpn_nlri = 6; } enum ENCAP_SUBTLV_TYPE { diff --git a/api/util.go b/api/util.go index 591c1c59..677d4f6a 100644 --- a/api/util.go +++ b/api/util.go @@ -17,6 +17,8 @@ package api var AF_IPV4_UC *AddressFamily = &AddressFamily{AFI_IP, SAFI_UNICAST} var AF_IPV6_UC *AddressFamily = &AddressFamily{AFI_IP6, SAFI_UNICAST} +var AF_IPV4_VPN *AddressFamily = &AddressFamily{AFI_IP, SAFI_MPLS_VPN} +var AF_IPV6_VPN *AddressFamily = &AddressFamily{AFI_IP6, SAFI_MPLS_VPN} var AF_EVPN *AddressFamily = &AddressFamily{AFI_L2VPN, SAFI_EVPN} var AF_ENCAP *AddressFamily = &AddressFamily{AFI_IP, SAFI_ENCAP} var AF_RTC *AddressFamily = &AddressFamily{AFI_IP, SAFI_ROUTE_TARGET_CONSTRAINTS} diff --git a/config/default.go b/config/default.go index 6e08a70e..f0c37f66 100644 --- a/config/default.go +++ b/config/default.go @@ -33,6 +33,8 @@ func SetDefaultConfigValues(md toml.MetaData, bt *Bgp) error { bt.Global.AfiSafiList = []AfiSafi{ AfiSafi{AfiSafiName: "ipv4-unicast"}, AfiSafi{AfiSafiName: "ipv6-unicast"}, + AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"}, + AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"}, AfiSafi{AfiSafiName: "l2vpn-evpn"}, AfiSafi{AfiSafiName: "encap"}, AfiSafi{AfiSafiName: "rtc"}, diff --git a/gobgp/common.go b/gobgp/common.go index b58eb4aa..f2533c37 100644 --- a/gobgp/common.go +++ b/gobgp/common.go @@ -273,6 +273,10 @@ func checkAddressFamily(ip net.IP) (*api.AddressFamily, error) { rf = api.AF_IPV4_UC case "ipv6", "v6", "6": rf = api.AF_IPV6_UC + case "vpnv4", "vpn-ipv4": + rf = api.AF_IPV4_VPN + case "vpnv6", "vpn-ipv6": + rf = api.AF_IPV6_VPN case "evpn": rf = api.AF_EVPN case "encap": diff --git a/gobgp/global.go b/gobgp/global.go index 8744449f..79d91a65 100644 --- a/gobgp/global.go +++ b/gobgp/global.go @@ -23,6 +23,7 @@ import ( "net" "os" "strconv" + "strings" ) func showGlobalRib(args []string) error { @@ -30,47 +31,95 @@ func showGlobalRib(args []string) error { return showNeighborRib(CMD_GLOBAL, bogusIp, args) } -func modPath(modtype string, eArgs []string) error { +func parseRD(args []string) (*api.RouteDistinguisher, error) { + t, err := strconv.Atoi(args[0]) + if err != nil { + return nil, err + } + typ := api.ROUTE_DISTINGUISHER_TYPE(t) + admin := args[1] + assigned, err := strconv.Atoi(args[2]) + if err != nil { + return nil, err + } + return &api.RouteDistinguisher{ + Type: typ, + Admin: admin, + Assigned: uint32(assigned), + }, nil +} + +func modPath(modtype string, args []string) error { rf, err := checkAddressFamily(net.IP{}) if err != nil { return err } path := &api.Path{} - var prefix string switch rf { case api.AF_IPV4_UC, api.AF_IPV6_UC: - if len(eArgs) == 1 || len(eArgs) == 3 { - prefix = eArgs[0] - } else { + if len(args) != 1 { return fmt.Errorf("usage: global rib %s -a { ipv4 | ipv6 }", modtype) } + prefix := args[0] path.Nlri = &api.Nlri{ Af: rf, Prefix: prefix, } + case api.AF_IPV4_VPN, api.AF_IPV6_VPN: + if len(args) < 1 { + return fmt.Errorf("usage: global rib %s : [...] -a { vpn-ipv4 | vpn-ipv6 }", modtype) + } + elems := strings.SplitN(args[0], ":", 4) + if len(elems) != 4 { + return fmt.Errorf("invalid :: %s. hint. := ::", args[0]) + } + rd, err := parseRD(elems[:3]) + 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) + } + + nlri := &api.VPNNlri{ + Rd: rd, + IpAddr: elems[0], + IpAddrLen: uint32(masklen), + } + path.Nlri = &api.Nlri{ + Af: rf, + VpnNlri: nlri, + } case api.AF_EVPN: var nlri *api.EVPNNlri - if len(eArgs) < 1 { + if len(args) < 1 { return fmt.Errorf("usage: global rib %s { macadv | multicast } ... -a evpn", modtype) } - subtype := eArgs[0] + subtype := args[0] switch subtype { case "macadv": - if len(eArgs) < 5 { + if len(args) < 5 { return fmt.Errorf("usage: global rib %s macadv