mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
server/cli: support add/delete EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG route
Signed-off-by: ISHIDA Wataru <[email protected]>
This commit is contained in:
committed by
FUJITA Tomonori
parent
8a3724c7fd
commit
ccfded2fee
+21
-1
@@ -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"`
|
||||
|
||||
+8
-1
@@ -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;
|
||||
|
||||
+71
-12
@@ -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)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -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
|
||||
|
||||
+85
-55
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user