diff options
-rw-r--r-- | docs/sources/evpn.md | 7 | ||||
-rw-r--r-- | gobgp/cmd/global.go | 35 | ||||
-rw-r--r-- | packet/bgp/bgp.go | 47 |
3 files changed, 76 insertions, 13 deletions
diff --git a/docs/sources/evpn.md b/docs/sources/evpn.md index 176dca3c..ddf80376 100644 --- a/docs/sources/evpn.md +++ b/docs/sources/evpn.md @@ -149,7 +149,7 @@ $ gobgp global rib -a evpn del macadv aa:bb:cc:dd:ee:ff 10.0.0.1 esi AS 65000 10 ```bash # Add a route -$ gobgp global rib -a evpn add multicast <ip address> etag <etag> rd <rd> [rt <rt>...] [encap <encap type>] +$ gobgp global rib -a evpn add multicast <ip address> etag <etag> rd <rd> [rt <rt>...] [encap <encap type>] [pmsi <type> [leaf-info-required] <label> <tunnel-id>] # Show routes $ gobgp global rib -a evpn [multicast] @@ -169,11 +169,10 @@ $ gobgp global rib -a evpn $ gobgp global rib -a evpn del multicast 10.0.0.1 etag 100 rd 1.1.1.1:65000 # With optionals -$ gobgp global rib -a evpn add multicast 10.0.0.1 etag 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan +$ gobgp global rib -a evpn add multicast 10.0.0.1 etag 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan pmsi ingress-repl 100 1.1.1.1 $ gobgp global rib -a evpn multicast Network Labels Next Hop AS_PATH Age Attrs -*> [type:multicast][rd:1.1.1.1:65000][etag:100][ip:10.0.0.1] 0.0.0.0 00:00:00 [{Origin: ?} {Extcomms: [65000:200], [VXLAN]}] -$ gobgp global rib -a evpn del multicast 10.0.0.1 etag 100 rd 1.1.1.1:65000 +*> [type:multicast][rd:1.1.1.1:65000][etag:100][ip:10.0.0.1] 0.0.0.0 00:00:00 [{Origin: ?} {Pmsi: type: ingress-repl, label: 100, tunnel-id: 1.1.1.1} {Extcomms: [65000:200], [VXLAN]}] ``` ### Ethernet Segment Route diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go index 2c7a71d6..81506802 100644 --- a/gobgp/cmd/global.go +++ b/gobgp/cmd/global.go @@ -961,6 +961,22 @@ func extractLargeCommunity(args []string) ([]string, bgp.PathAttributeInterface, return args, nil, nil } +func extractPmsiTunnel(args []string) ([]string, bgp.PathAttributeInterface, error) { + for idx, arg := range args { + if arg == "pmsi" { + pmsi, err := bgp.ParsePmsiTunnel(args[idx+1:]) + if err != nil { + return nil, nil, err + } + if pmsi.IsLeafInfoRequired { + return append(args[:idx], args[idx+5:]...), pmsi, nil + } + return append(args[:idx], args[idx+4:]...), pmsi, nil + } + } + return args, nil, nil +} + func extractAigp(args []string) ([]string, bgp.PathAttributeInterface, error) { for idx, arg := range args { if arg == "aigp" { @@ -1028,14 +1044,15 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*table.Path, error) { attrs := table.PathAttrs(make([]bgp.PathAttributeInterface, 0, 1)) fns := []func([]string) ([]string, bgp.PathAttributeInterface, error){ - extractAsPath, - extractOrigin, - extractMed, - extractLocalPref, - extractCommunity, - extractAigp, - extractAggregator, - extractLargeCommunity, + extractOrigin, // 1 ORIGIN + extractAsPath, // 2 AS_PATH + extractMed, // 4 MULTI_EXIT_DISC + extractLocalPref, // 5 LOCAL_PREF + extractAggregator, // 7 AGGREGATOR + extractCommunity, // 8 COMMUNITY + extractPmsiTunnel, // 22 PMSI_TUNNEL + extractAigp, // 26 AIGP + extractLargeCommunity, // 32 LARGE_COMMUNITY } for _, fn := range fns { @@ -1351,7 +1368,7 @@ usage: %s rib -a %%s %s%%s match <MATCH> then <THEN>%%s%%s%%s usage: %s rib %s { a-d <A-D> | macadv <MACADV> | multicast <MULTICAST> | esi <ESI> | prefix <PREFIX> } -a evpn <A-D> : esi <esi> etag <etag> label <label> rd <rd> [rt <rt>...] [encap <encap type>] [esi-label <esi-label> [single-active | all-active]] <MACADV> : <mac address> <ip address> [esi <esi>] etag <etag> label <label> rd <rd> [rt <rt>...] [encap <encap type>] [default-gateway] - <MULTICAST> : <ip address> etag <etag> rd <rd> [rt <rt>...] [encap <encap type>] + <MULTICAST> : <ip address> etag <etag> rd <rd> [rt <rt>...] [encap <encap type>] [pmsi <type> [leaf-info-required] <label> <tunnel-id>] <ESI> : <ip address> esi <esi> rd <rd> [rt <rt>...] [encap <encap type>] <PREFIX> : <ip prefix> [gw <gateway>] [esi <esi>] etag <etag> [label <label>] rd <rd> [rt <rt>...] [encap <encap type>] [router-mac <mac address>]`, err, diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index df2e1571..8e9288e0 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -7927,6 +7927,53 @@ func NewPathAttributePmsiTunnel(typ PmsiTunnelType, isLeafInfoRequired bool, lab } } +func ParsePmsiTunnel(args []string) (*PathAttributePmsiTunnel, error) { + // Format: + // "<type>" ["leaf-info-required"] "<label>" "<tunnel-id>" + if len(args) < 3 { + return nil, fmt.Errorf("invalid pmsi tunnel arguments: %s", args) + } + + pmsi := NewPathAttributePmsiTunnel(0, false, 0, nil) + + switch args[0] { + case "ingress-repl": + pmsi.TunnelType = PMSI_TUNNEL_TYPE_INGRESS_REPL + default: + typ, err := strconv.ParseUint(args[0], 10, 8) + if err != nil { + return nil, fmt.Errorf("invalid pmsi tunnel type: %s", args[0]) + } + pmsi.TunnelType = PmsiTunnelType(typ) + } + + indx := 1 + if args[indx] == "leaf-info-required" { + pmsi.IsLeafInfoRequired = true + indx++ + } + + label, err := strconv.ParseUint(args[indx], 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid pmsi tunnel label: %s", args[indx]) + } + pmsi.Label = uint32(label) + indx++ + + switch pmsi.TunnelType { + case PMSI_TUNNEL_TYPE_INGRESS_REPL: + ip := net.ParseIP(args[indx]) + if ip == nil { + return nil, fmt.Errorf("invalid pmsi tunnel identifier: %s", args[indx]) + } + pmsi.TunnelID = &IngressReplTunnelID{Value: ip} + default: + pmsi.TunnelID = &DefaultPmsiTunnelID{Value: []byte(args[indx])} + } + + return pmsi, nil +} + type AigpTLVType uint8 const ( |