server/cli: support add/delete EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG route

Signed-off-by: ISHIDA Wataru <[email protected]>
This commit is contained in:
ISHIDA Wataru
2015-07-01 21:24:40 +09:00
committed by FUJITA Tomonori
parent 8a3724c7fd
commit ccfded2fee
5 changed files with 195 additions and 70 deletions
+21 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {