summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--config/bgp_configs.go7
-rw-r--r--docs/sources/cli-command-syntax.md6
-rw-r--r--docs/sources/flowspec.md20
-rw-r--r--gobgp/cmd/common.go2
-rw-r--r--gobgp/cmd/global.go60
-rw-r--r--packet/bgp.go327
-rw-r--r--packet/bgp_test.go29
-rw-r--r--packet/constant.go61
-rw-r--r--tools/pyang_plugins/gobgp.yang9
9 files changed, 438 insertions, 83 deletions
diff --git a/config/bgp_configs.go b/config/bgp_configs.go
index b5e18c5b..4fa29bd4 100644
--- a/config/bgp_configs.go
+++ b/config/bgp_configs.go
@@ -234,6 +234,7 @@ const (
AFI_SAFI_TYPE_L3VPN_IPV4_FLOWSPEC AfiSafiType = "l3vpn-ipv4-flowspec"
AFI_SAFI_TYPE_IPV6_FLOWSPEC AfiSafiType = "ipv6-flowspec"
AFI_SAFI_TYPE_L3VPN_IPV6_FLOWSPEC AfiSafiType = "l3vpn-ipv6-flowspec"
+ AFI_SAFI_TYPE_L2VPN_FLOWSPEC AfiSafiType = "l2vpn-flowspec"
AFI_SAFI_TYPE_OPAQUE AfiSafiType = "opaque"
)
@@ -256,7 +257,8 @@ var AfiSafiTypeToIntMap = map[AfiSafiType]int{
AFI_SAFI_TYPE_L3VPN_IPV4_FLOWSPEC: 15,
AFI_SAFI_TYPE_IPV6_FLOWSPEC: 16,
AFI_SAFI_TYPE_L3VPN_IPV6_FLOWSPEC: 17,
- AFI_SAFI_TYPE_OPAQUE: 18,
+ AFI_SAFI_TYPE_L2VPN_FLOWSPEC: 18,
+ AFI_SAFI_TYPE_OPAQUE: 19,
}
func (v AfiSafiType) ToInt() int {
@@ -286,7 +288,8 @@ var IntToAfiSafiTypeMap = map[int]AfiSafiType{
15: AFI_SAFI_TYPE_L3VPN_IPV4_FLOWSPEC,
16: AFI_SAFI_TYPE_IPV6_FLOWSPEC,
17: AFI_SAFI_TYPE_L3VPN_IPV6_FLOWSPEC,
- 18: AFI_SAFI_TYPE_OPAQUE,
+ 18: AFI_SAFI_TYPE_L2VPN_FLOWSPEC,
+ 19: AFI_SAFI_TYPE_OPAQUE,
}
func (v AfiSafiType) Validate() error {
diff --git a/docs/sources/cli-command-syntax.md b/docs/sources/cli-command-syntax.md
index 7034bfc8..011209e3 100644
--- a/docs/sources/cli-command-syntax.md
+++ b/docs/sources/cli-command-syntax.md
@@ -80,7 +80,7 @@ The following options can be specified in the global subcommand:
| short |long | description | default |
|--------|---------------|--------------------------------------------|---------|
-|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeled`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `opaque` | `ipv4` |
+|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeled`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `l2vpn-flowspec`, `opaque` | `ipv4` |
<br>
@@ -110,7 +110,7 @@ The following options can be specified in the global subcommand:
| short |long | description | default |
|--------|---------------|--------------------------------------------|---------|
-|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeld`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `opaque` | `ipv4` |
+|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeld`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `l2vpn-flowspec`, `opaque` | `ipv4` |
### 2.3. Show Rib - local-rib/adj-rib-in/adj-rib-out -
#### - syntax
@@ -132,7 +132,7 @@ The following options can be specified in the neighbor subcommand:
| short |long | description | default |
|--------|---------------|--------------------------------------------|---------|
-|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeld`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `opaque` | `ipv4` |
+|a |address-family |specify any one from among `ipv4`, `ipv6`, `vpnv4`, `vpnv6`, `ipv4-labeled`, `ipv6-labeld`, `evpn`, `encap`, `rtc`, `ipv4-flowspec`, `ipv6-flowspec`, `l2vpn-flowspec`, `opaque` | `ipv4` |
### 2.4. Operations for Policy - add/del/show -
diff --git a/docs/sources/flowspec.md b/docs/sources/flowspec.md
index 97ab2a85..34c20608 100644
--- a/docs/sources/flowspec.md
+++ b/docs/sources/flowspec.md
@@ -2,7 +2,8 @@
GoBGP supports [RFC5575](https://tools.ietf.org/html/rfc5575),
[draft-ietf-idr-flowspec-redirect-rt-bis-05](http://tools.ietf.org/html/draft-ietf-idr-flowspec-redirect-rt-bis-05)
-and [draft-ietf-idr-flow-spec-v6-06](https://tools.ietf.org/html/draft-ietf-idr-flow-spec-v6-06).
+, [draft-ietf-idr-flow-spec-v6-06](https://tools.ietf.org/html/draft-ietf-idr-flow-spec-v6-06)
+and [draft-ietf-idr-flowspec-l2vpn-03](https://tools.ietf.org/html/draft-ietf-idr-flowspec-l2vpn-03).
## Prerequisites
@@ -28,11 +29,15 @@ afi-safis like below.
peer-as = 64512
[[neighbors.afi-safis]]
afi-safi-name = "ipv4-flowspec"
+[[neighbors.afi-safis]]
+ afi-safi-name = "ipv6-flowspec"
+[[neighbors.afi-safis]]
+ afi-safi-name = "l2vpn-flowspec"
```
## <a name="section1"> Add Flowspec routes through CLI
-CLI syntax to add flowspec is
+CLI syntax to add ipv4/ipv6 flowspec rule is
```shell
% global rib add match <MATCH_EXPR> then <THEN_EXPR> -a [ipv4-flowspec|ipv6-flowspec]
@@ -47,6 +52,17 @@ CLI syntax to add flowspec is
<RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy
```
+that for l2vpn flowspec rule is
+
+``` shell
+% global rib add match <MATCH_EXPR> then <THEN_EXPR> -a [l2vpn-flowspec]
+ <MATCH_EXPR> : { { destination-mac | source-mac } <MAC> | ether-type <ETHER_TYPE> | { llc-dsap | llc-ssap | llc-control | snap | vid | cos | inner-vid | inner-cos } <ITEM>... }...
+ <ETHER_TYPE> : arp, vmtp, ipx, snmp, net-bios, xtp, pppoe-discovery, ipv4, rarp, ipv6, pppoe-session, loopback, apple-talk, aarp
+ <ITEM> : &?{<|>|=}<value>
+ <THEN_EXPR> : { accept | discard | rate-limit <value> | redirect <RT> | mark <value> | action { sample | terminal | sample-terminal } | rt <RT>... }...
+ <RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy
+```
+
### Examples
```shell
diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go
index 8a53df48..5694a572 100644
--- a/gobgp/cmd/common.go
+++ b/gobgp/cmd/common.go
@@ -456,6 +456,8 @@ func checkAddressFamily(def bgp.RouteFamily) (bgp.RouteFamily, error) {
rf = bgp.RF_FS_IPv4_UC
case "ipv6-flowspec", "ipv6-flow", "flow6":
rf = bgp.RF_FS_IPv6_UC
+ case "l2vpn-flowspec":
+ rf = bgp.RF_FS_L2_VPN
case "opaque":
rf = bgp.RF_OPAQUE
case "":
diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go
index 6b328ab1..abddc526 100644
--- a/gobgp/cmd/global.go
+++ b/gobgp/cmd/global.go
@@ -301,6 +301,9 @@ func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string) (bgp.AddrPrefixInterfa
case bgp.RF_FS_IPv6_UC:
nlri = bgp.NewFlowSpecIPv6Unicast(cmp)
fnlri = &nlri.(*bgp.FlowSpecIPv6Unicast).FlowSpecNLRI
+ case bgp.RF_FS_L2_VPN:
+ nlri = bgp.NewFlowSpecL2VPN(cmp)
+ fnlri = &nlri.(*bgp.FlowSpecL2VPN).FlowSpecNLRI
default:
return nil, nil, fmt.Errorf("invalid route family")
}
@@ -646,7 +649,7 @@ func ParsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) {
}
case bgp.RF_EVPN:
nlri, extcomms, err = ParseEvpnArgs(args)
- case bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC:
+ case bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC, bgp.RF_FS_L2_VPN:
nlri, extcomms, err = ParseFlowSpecArgs(rf, args)
case bgp.RF_OPAQUE:
m := extractReserved(args, []string{"key", "value"})
@@ -719,20 +722,29 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
ss = append(ss, v)
}
flags := strings.Join(ss, ", ")
+ ss = make([]string, 0, len(bgp.EthernetTypeNameMap))
+ for _, v := range bgp.EthernetTypeNameMap {
+ ss = append(ss, v)
+ }
+ etherTypes := strings.Join(ss, ", ")
helpErrMap := map[bgp.RouteFamily]error{}
helpErrMap[bgp.RF_IPv4_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] -a ipv4", cmdstr, modtype)
helpErrMap[bgp.RF_IPv6_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [origin { igp | egp | incomplete }] [nexthop <ADDRESS>] [med <VALUE>] [local-pref <VALUE>] [community <VALUE>] [aigp metric <METRIC>] -a ipv6", cmdstr, modtype)
fsHelpMsgFmt := fmt.Sprintf(`err: %s
usage: %s rib %s match <MATCH_EXPR> then <THEN_EXPR> -a %%s
- <MATCH_EXPR> : { %s <PREFIX> [<OFFSET>] | %s <PREFIX> [<OFFSET>] |
- %s <PROTO>... | %s <FRAGMENT_TYPE> | %s [not] [match] <TCPFLAG>... |
- { %s | %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
- <PROTO> : %s
- <FRAGMENT_TYPE> : dont-fragment, is-fragment, first-fragment, last-fragment, not-a-fragment
- <TCPFLAG> : %s
- <ITEM> : &?{<|>|=}<value>
- <THEN_EXPR> : { %s | %s | %s <value> | %s <RT> | %s <value> | %s { sample | terminal | sample-terminal } | %s <RT>... }...
- <RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy`, err, cmdstr, modtype,
+%%s
+ <THEN_EXPR> : { %s | %s | %s <value> | %s <RT> | %s <value> | %s { sample | terminal | sample-terminal } | %s <RT>... }...
+ <RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy`, err, cmdstr, modtype,
+ ExtCommNameMap[ACCEPT], ExtCommNameMap[DISCARD],
+ ExtCommNameMap[RATE], ExtCommNameMap[REDIRECT],
+ ExtCommNameMap[MARK], ExtCommNameMap[ACTION], ExtCommNameMap[RT])
+ ipFsMatchExpr := fmt.Sprintf(` <MATCH_EXPR> : { %s <PREFIX> [<OFFSET>] | %s <PREFIX> [<OFFSET>] |
+ %s <PROTO>... | %s <FRAGMENT_TYPE> | %s [not] [match] <TCPFLAG>... |
+ { %s | %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
+ <PROTO> : %s
+ <FRAGMENT_TYPE> : dont-fragment, is-fragment, first-fragment, last-fragment, not-a-fragment
+ <TCPFLAG> : %s
+ <ITEM> : &?{<|>|=}<value>`,
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PREFIX],
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PREFIX],
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_IP_PROTO],
@@ -746,12 +758,28 @@ usage: %s rib %s match <MATCH_EXPR> then <THEN_EXPR> -a %%s
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_PKT_LEN],
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DSCP],
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_LABEL],
- protos, flags,
- ExtCommNameMap[ACCEPT], ExtCommNameMap[DISCARD],
- ExtCommNameMap[RATE], ExtCommNameMap[REDIRECT],
- ExtCommNameMap[MARK], ExtCommNameMap[ACTION], ExtCommNameMap[RT])
- helpErrMap[bgp.RF_FS_IPv4_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv4-flowspec")
- helpErrMap[bgp.RF_FS_IPv6_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv6-flowspec")
+ protos,
+ flags,
+ )
+ helpErrMap[bgp.RF_FS_IPv4_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv4-flowspec", ipFsMatchExpr)
+ helpErrMap[bgp.RF_FS_IPv6_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv6-flowspec", ipFsMatchExpr)
+ macFsMatchExpr := fmt.Sprintf(` <MATCH_EXPR> : { { %s | %s } <MAC> | %s <ETHER_TYPE> | { %s | %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
+ <ETHER_TYPE> : %s
+ <ITEM> : &?{<|>|=}<value>`,
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_MAC],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_MAC],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ETHERNET_TYPE],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_LLC_DSAP],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_LLC_SSAP],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_LLC_CONTROL],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SNAP],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_VID],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_COS],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_INNER_VID],
+ bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_INNER_COS],
+ etherTypes,
+ )
+ helpErrMap[bgp.RF_FS_L2_VPN] = fmt.Errorf(fsHelpMsgFmt, "l2vpn-flowspec", macFsMatchExpr)
helpErrMap[bgp.RF_EVPN] = fmt.Errorf(`usage: %s rib %s { macadv <MACADV> | multicast <MULTICAST> } -a evpn
<MACADV> : <mac address> <ip address> <etag> <label> rd <rd> rt <rt>... [encap <encap type>]
<MULTICAST> : <ip address> <etag> rd <rd> rt <rt>... [encap <encap type>]`, cmdstr, modtype)
diff --git a/packet/bgp.go b/packet/bgp.go
index b899e8f2..34b812a0 100644
--- a/packet/bgp.go
+++ b/packet/bgp.go
@@ -2070,39 +2070,72 @@ const (
FLOW_SPEC_TYPE_DSCP
FLOW_SPEC_TYPE_FRAGMENT
FLOW_SPEC_TYPE_LABEL
+ FLOW_SPEC_TYPE_ETHERNET_TYPE // 14
+ FLOW_SPEC_TYPE_SRC_MAC
+ FLOW_SPEC_TYPE_DST_MAC
+ FLOW_SPEC_TYPE_LLC_DSAP
+ FLOW_SPEC_TYPE_LLC_SSAP
+ FLOW_SPEC_TYPE_LLC_CONTROL
+ FLOW_SPEC_TYPE_SNAP
+ FLOW_SPEC_TYPE_VID
+ FLOW_SPEC_TYPE_COS
+ FLOW_SPEC_TYPE_INNER_VID
+ FLOW_SPEC_TYPE_INNER_COS
)
var FlowSpecNameMap = map[BGPFlowSpecType]string{
- FLOW_SPEC_TYPE_UNKNOWN: "unknown",
- FLOW_SPEC_TYPE_DST_PREFIX: "destination",
- FLOW_SPEC_TYPE_SRC_PREFIX: "source",
- FLOW_SPEC_TYPE_IP_PROTO: "protocol",
- FLOW_SPEC_TYPE_PORT: "port",
- FLOW_SPEC_TYPE_DST_PORT: "destination-port",
- FLOW_SPEC_TYPE_SRC_PORT: "source-port",
- FLOW_SPEC_TYPE_ICMP_TYPE: "icmp-type",
- FLOW_SPEC_TYPE_ICMP_CODE: "icmp-code",
- FLOW_SPEC_TYPE_TCP_FLAG: "tcp-flags",
- FLOW_SPEC_TYPE_PKT_LEN: "packet-length",
- FLOW_SPEC_TYPE_DSCP: "dscp",
- FLOW_SPEC_TYPE_FRAGMENT: "fragment",
- FLOW_SPEC_TYPE_LABEL: "label",
+ FLOW_SPEC_TYPE_UNKNOWN: "unknown",
+ FLOW_SPEC_TYPE_DST_PREFIX: "destination",
+ FLOW_SPEC_TYPE_SRC_PREFIX: "source",
+ FLOW_SPEC_TYPE_IP_PROTO: "protocol",
+ FLOW_SPEC_TYPE_PORT: "port",
+ FLOW_SPEC_TYPE_DST_PORT: "destination-port",
+ FLOW_SPEC_TYPE_SRC_PORT: "source-port",
+ FLOW_SPEC_TYPE_ICMP_TYPE: "icmp-type",
+ FLOW_SPEC_TYPE_ICMP_CODE: "icmp-code",
+ FLOW_SPEC_TYPE_TCP_FLAG: "tcp-flags",
+ FLOW_SPEC_TYPE_PKT_LEN: "packet-length",
+ FLOW_SPEC_TYPE_DSCP: "dscp",
+ FLOW_SPEC_TYPE_FRAGMENT: "fragment",
+ FLOW_SPEC_TYPE_LABEL: "label",
+ FLOW_SPEC_TYPE_ETHERNET_TYPE: "ether-type",
+ FLOW_SPEC_TYPE_SRC_MAC: "source-mac",
+ FLOW_SPEC_TYPE_DST_MAC: "destination-mac",
+ FLOW_SPEC_TYPE_LLC_DSAP: "llc-dsap",
+ FLOW_SPEC_TYPE_LLC_SSAP: "llc-ssap",
+ FLOW_SPEC_TYPE_LLC_CONTROL: "llc-control",
+ FLOW_SPEC_TYPE_SNAP: "snap",
+ FLOW_SPEC_TYPE_VID: "vid",
+ FLOW_SPEC_TYPE_COS: "cos",
+ FLOW_SPEC_TYPE_INNER_VID: "inner-vid",
+ FLOW_SPEC_TYPE_INNER_COS: "inner-cos",
}
var FlowSpecValueMap = map[string]BGPFlowSpecType{
- FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]: FLOW_SPEC_TYPE_DST_PREFIX,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]: FLOW_SPEC_TYPE_SRC_PREFIX,
- FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]: FLOW_SPEC_TYPE_IP_PROTO,
- FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]: FLOW_SPEC_TYPE_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]: FLOW_SPEC_TYPE_DST_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]: FLOW_SPEC_TYPE_SRC_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]: FLOW_SPEC_TYPE_ICMP_TYPE,
- FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]: FLOW_SPEC_TYPE_ICMP_CODE,
- FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]: FLOW_SPEC_TYPE_TCP_FLAG,
- FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]: FLOW_SPEC_TYPE_PKT_LEN,
- FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]: FLOW_SPEC_TYPE_DSCP,
- FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]: FLOW_SPEC_TYPE_FRAGMENT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]: FLOW_SPEC_TYPE_LABEL,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]: FLOW_SPEC_TYPE_DST_PREFIX,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]: FLOW_SPEC_TYPE_SRC_PREFIX,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]: FLOW_SPEC_TYPE_IP_PROTO,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]: FLOW_SPEC_TYPE_PORT,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]: FLOW_SPEC_TYPE_DST_PORT,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]: FLOW_SPEC_TYPE_SRC_PORT,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]: FLOW_SPEC_TYPE_ICMP_TYPE,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]: FLOW_SPEC_TYPE_ICMP_CODE,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]: FLOW_SPEC_TYPE_TCP_FLAG,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]: FLOW_SPEC_TYPE_PKT_LEN,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]: FLOW_SPEC_TYPE_DSCP,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]: FLOW_SPEC_TYPE_FRAGMENT,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]: FLOW_SPEC_TYPE_LABEL,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE]: FLOW_SPEC_TYPE_ETHERNET_TYPE,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]: FLOW_SPEC_TYPE_SRC_MAC,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]: FLOW_SPEC_TYPE_DST_MAC,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_DSAP]: FLOW_SPEC_TYPE_LLC_DSAP,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_SSAP]: FLOW_SPEC_TYPE_LLC_SSAP,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_CONTROL]: FLOW_SPEC_TYPE_LLC_CONTROL,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_SNAP]: FLOW_SPEC_TYPE_SNAP,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_VID]: FLOW_SPEC_TYPE_VID,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_COS]: FLOW_SPEC_TYPE_COS,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_VID]: FLOW_SPEC_TYPE_INNER_VID,
+ FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_COS]: FLOW_SPEC_TYPE_INNER_COS,
}
func flowSpecPrefixParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
@@ -2205,6 +2238,29 @@ func flowSpecTcpFlagParser(rf RouteFamily, args []string) (FlowSpecComponentInte
return NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, items), nil
}
+func flowSpecEtherTypeParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
+ ss := make([]string, 0, len(EthernetTypeNameMap))
+ for _, v := range EthernetTypeNameMap {
+ ss = append(ss, v)
+ }
+ protos := strings.Join(ss, "|")
+ exp := regexp.MustCompile(fmt.Sprintf("^%s (((%s) )*)(%s)$", FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE], protos, protos))
+ elems := exp.FindStringSubmatch(strings.Join(args, " "))
+ items := make([]*FlowSpecComponentItem, 0)
+ eq := 0x1
+ if elems[1] != "" {
+ for _, v := range strings.Split(elems[1], " ") {
+ p, ok := EthernetTypeValueMap[v]
+ if !ok {
+ continue
+ }
+ items = append(items, NewFlowSpecComponentItem(eq, int(p)))
+ }
+ }
+ items = append(items, NewFlowSpecComponentItem(eq, int(EthernetTypeValueMap[elems[4]])))
+ return NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, items), nil
+}
+
func doFlowSpecNumericParser(rf RouteFamily, args []string, validationFunc func(int) error) (FlowSpecComponentInterface, error) {
if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP && FlowSpecValueMap[args[0]] == FLOW_SPEC_TYPE_LABEL {
return nil, fmt.Errorf("flow label spec is only allowed for ipv6")
@@ -2321,20 +2377,52 @@ func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInt
return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
}
+func flowSpecMacParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
+ if len(args) < 2 {
+ return nil, fmt.Errorf("invalid flowspec dst/src mac")
+ }
+ if rf != RF_FS_L2_VPN {
+ return nil, fmt.Errorf("invalid family")
+ }
+ typ := args[0]
+ mac, err := net.ParseMAC(args[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid mac")
+ }
+ switch typ {
+ case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]:
+ return NewFlowSpecDestinationMac(mac), nil
+ case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]:
+ return NewFlowSpecSourceMac(mac), nil
+ }
+ return nil, fmt.Errorf("invalid type. only %s or %s allowed", FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC], FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC])
+}
+
var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, []string) (FlowSpecComponentInterface, error){
- FLOW_SPEC_TYPE_DST_PREFIX: flowSpecPrefixParser,
- FLOW_SPEC_TYPE_SRC_PREFIX: flowSpecPrefixParser,
- FLOW_SPEC_TYPE_IP_PROTO: flowSpecIpProtoParser,
- FLOW_SPEC_TYPE_PORT: flowSpecPortParser,
- FLOW_SPEC_TYPE_DST_PORT: flowSpecPortParser,
- FLOW_SPEC_TYPE_SRC_PORT: flowSpecPortParser,
- FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumericParser,
- FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumericParser,
- FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser,
- FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumericParser,
- FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser,
- FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser,
- FLOW_SPEC_TYPE_LABEL: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_DST_PREFIX: flowSpecPrefixParser,
+ FLOW_SPEC_TYPE_SRC_PREFIX: flowSpecPrefixParser,
+ FLOW_SPEC_TYPE_IP_PROTO: flowSpecIpProtoParser,
+ FLOW_SPEC_TYPE_PORT: flowSpecPortParser,
+ FLOW_SPEC_TYPE_DST_PORT: flowSpecPortParser,
+ FLOW_SPEC_TYPE_SRC_PORT: flowSpecPortParser,
+ FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser,
+ FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser,
+ FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser,
+ FLOW_SPEC_TYPE_LABEL: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser,
+ FLOW_SPEC_TYPE_DST_MAC: flowSpecMacParser,
+ FLOW_SPEC_TYPE_SRC_MAC: flowSpecMacParser,
+ FLOW_SPEC_TYPE_LLC_DSAP: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_LLC_SSAP: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_LLC_CONTROL: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_SNAP: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_VID: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_COS: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_INNER_VID: flowSpecNumericParser,
+ FLOW_SPEC_TYPE_INNER_COS: flowSpecNumericParser,
}
func ParseFlowSpecComponents(rf RouteFamily, input string) ([]FlowSpecComponentInterface, error) {
@@ -2513,6 +2601,66 @@ func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpe
return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}}
}
+type flowSpecMac struct {
+ Mac net.HardwareAddr
+ type_ BGPFlowSpecType
+}
+
+func (p *flowSpecMac) DecodeFromBytes(data []byte) error {
+ if len(data) < 2 || len(data) < 2+int(data[1]) {
+ return fmt.Errorf("not all mac bits available")
+ }
+ p.type_ = BGPFlowSpecType(data[0])
+ p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])])
+ return nil
+}
+
+func (p *flowSpecMac) Serialize() ([]byte, error) {
+ if len(p.Mac) == 0 {
+ return nil, fmt.Errorf("mac unset")
+ }
+ buf := []byte{byte(p.Type()), byte(len(p.Mac))}
+ return append(buf, []byte(p.Mac)...), nil
+}
+
+func (p *flowSpecMac) Len() int {
+ return 2 + len(p.Mac)
+}
+
+func (p *flowSpecMac) Type() BGPFlowSpecType {
+ return p.type_
+}
+
+func (p *flowSpecMac) String() string {
+ return fmt.Sprintf("[%s:%s]", p.Type(), p.Mac.String())
+}
+
+func (p *flowSpecMac) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type BGPFlowSpecType `json:"type"`
+ Value string `json:"value"`
+ }{
+ Type: p.Type(),
+ Value: p.Mac.String(),
+ })
+}
+
+type FlowSpecSourceMac struct {
+ flowSpecMac
+}
+
+func NewFlowSpecSourceMac(mac net.HardwareAddr) *FlowSpecSourceMac {
+ return &FlowSpecSourceMac{flowSpecMac{Mac: mac, type_: FLOW_SPEC_TYPE_SRC_MAC}}
+}
+
+type FlowSpecDestinationMac struct {
+ flowSpecMac
+}
+
+func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac {
+ return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, type_: FLOW_SPEC_TYPE_DST_MAC}}
+}
+
type FlowSpecComponentItem struct {
Op int `json:"op"`
Value int `json:"value"`
@@ -2702,27 +2850,39 @@ func formatFragment(op int, value int) string {
return fmt.Sprintf("%s%s", formatNumericOp(op), ss[0])
}
+func formatEtherType(op int, value int) string {
+ return fmt.Sprintf(" %s", EthernetType(value).String())
+}
+
var flowSpecFormatMap = map[BGPFlowSpecType]func(op int, value int) string{
- FLOW_SPEC_TYPE_UNKNOWN: formatRaw,
- FLOW_SPEC_TYPE_IP_PROTO: formatProto,
- FLOW_SPEC_TYPE_PORT: formatNumeric,
- FLOW_SPEC_TYPE_DST_PORT: formatNumeric,
- FLOW_SPEC_TYPE_SRC_PORT: formatNumeric,
- FLOW_SPEC_TYPE_ICMP_TYPE: formatNumeric,
- FLOW_SPEC_TYPE_ICMP_CODE: formatNumeric,
- FLOW_SPEC_TYPE_TCP_FLAG: formatFlag,
- FLOW_SPEC_TYPE_PKT_LEN: formatNumeric,
- FLOW_SPEC_TYPE_DSCP: formatNumeric,
- FLOW_SPEC_TYPE_FRAGMENT: formatFragment,
- FLOW_SPEC_TYPE_LABEL: formatNumeric,
+ FLOW_SPEC_TYPE_UNKNOWN: formatRaw,
+ FLOW_SPEC_TYPE_IP_PROTO: formatProto,
+ FLOW_SPEC_TYPE_PORT: formatNumeric,
+ FLOW_SPEC_TYPE_DST_PORT: formatNumeric,
+ FLOW_SPEC_TYPE_SRC_PORT: formatNumeric,
+ FLOW_SPEC_TYPE_ICMP_TYPE: formatNumeric,
+ FLOW_SPEC_TYPE_ICMP_CODE: formatNumeric,
+ FLOW_SPEC_TYPE_TCP_FLAG: formatFlag,
+ FLOW_SPEC_TYPE_PKT_LEN: formatNumeric,
+ FLOW_SPEC_TYPE_DSCP: formatNumeric,
+ FLOW_SPEC_TYPE_FRAGMENT: formatFragment,
+ FLOW_SPEC_TYPE_LABEL: formatNumeric,
+ FLOW_SPEC_TYPE_ETHERNET_TYPE: formatEtherType,
+ FLOW_SPEC_TYPE_LLC_DSAP: formatNumeric,
+ FLOW_SPEC_TYPE_LLC_SSAP: formatNumeric,
+ FLOW_SPEC_TYPE_LLC_CONTROL: formatNumeric,
+ FLOW_SPEC_TYPE_SNAP: formatNumeric,
+ FLOW_SPEC_TYPE_VID: formatNumeric,
+ FLOW_SPEC_TYPE_COS: formatNumeric,
+ FLOW_SPEC_TYPE_INNER_VID: formatNumeric,
+ FLOW_SPEC_TYPE_INNER_COS: formatNumeric,
}
func (p *FlowSpecComponent) String() string {
- var f func(op int, value int) string
- if _, ok := flowSpecFormatMap[p.Type()]; !ok {
- f = flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN]
+ f := flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN]
+ if _, ok := flowSpecFormatMap[p.Type()]; ok {
+ f = flowSpecFormatMap[p.Type()]
}
- f = flowSpecFormatMap[p.Type()]
buf := bytes.NewBuffer(make([]byte, 0, 32))
for _, i := range p.Items {
buf.WriteString(f(i.Op, i.Value))
@@ -2782,17 +2942,22 @@ type FlowSpecNLRI struct {
func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error {
var length int
- if (data[0] >> 4) == 0xf {
+ if (data[0]>>4) == 0xf && len(data) > 2 {
length = int(binary.BigEndian.Uint16(data[0:2]))
data = data[2:]
- } else {
+ } else if len(data) > 1 {
length = int(data[0])
data = data[1:]
+ } else {
+ return fmt.Errorf("not all flowspec component bytes available")
}
n.rf = rf
for l := length; l > 0; {
+ if len(data) == 0 {
+ return fmt.Errorf("not all flowspec component bytes available")
+ }
t := BGPFlowSpecType(data[0])
var i FlowSpecComponentInterface
switch t {
@@ -2822,9 +2987,25 @@ func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error {
default:
return fmt.Errorf("Invalid RF: %v", rf)
}
+ case FLOW_SPEC_TYPE_SRC_MAC:
+ switch rf {
+ case RF_FS_L2_VPN:
+ i = NewFlowSpecSourceMac(nil)
+ default:
+ return fmt.Errorf("invalid family: %v", rf)
+ }
+ case FLOW_SPEC_TYPE_DST_MAC:
+ switch rf {
+ case RF_FS_L2_VPN:
+ i = NewFlowSpecDestinationMac(nil)
+ default:
+ return fmt.Errorf("invalid family: %v", rf)
+ }
case FLOW_SPEC_TYPE_IP_PROTO, FLOW_SPEC_TYPE_PORT, FLOW_SPEC_TYPE_DST_PORT, FLOW_SPEC_TYPE_SRC_PORT,
FLOW_SPEC_TYPE_ICMP_TYPE, FLOW_SPEC_TYPE_ICMP_CODE, FLOW_SPEC_TYPE_TCP_FLAG, FLOW_SPEC_TYPE_PKT_LEN,
- FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL:
+ FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL, FLOW_SPEC_TYPE_ETHERNET_TYPE,
+ FLOW_SPEC_TYPE_LLC_DSAP, FLOW_SPEC_TYPE_LLC_SSAP, FLOW_SPEC_TYPE_LLC_CONTROL, FLOW_SPEC_TYPE_SNAP,
+ FLOW_SPEC_TYPE_VID, FLOW_SPEC_TYPE_COS, FLOW_SPEC_TYPE_INNER_VID, FLOW_SPEC_TYPE_INNER_COS:
i = NewFlowSpecComponent(t, nil)
default:
i = &FlowSpecUnknown{}
@@ -2981,6 +3162,29 @@ func NewFlowSpecIPv6VPN(value []FlowSpecComponentInterface) *FlowSpecIPv6VPN {
}}
}
+type FlowSpecL2VPN struct {
+ FlowSpecNLRI
+}
+
+func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte) error {
+ return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
+}
+
+func (n *FlowSpecL2VPN) AFI() uint16 {
+ return AFI_L2VPN
+}
+
+func (n *FlowSpecL2VPN) SAFI() uint8 {
+ return SAFI_FLOW_SPEC_VPN
+}
+
+func NewFlowSpecL2VPN(value []FlowSpecComponentInterface) *FlowSpecL2VPN {
+ return &FlowSpecL2VPN{FlowSpecNLRI{
+ Value: value,
+ rf: RF_FS_L2_VPN,
+ }}
+}
+
type OpaqueNLRI struct {
Length uint8
Key []byte
@@ -3068,6 +3272,7 @@ const (
RF_FS_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_VPN
RF_FS_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_UNICAST
RF_FS_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_VPN
+ RF_FS_L2_VPN RouteFamily = AFI_L2VPN<<16 | SAFI_FLOW_SPEC_VPN
RF_OPAQUE RouteFamily = AFI_OPAQUE<<16 | SAFI_KEY_VALUE
)
@@ -3090,6 +3295,7 @@ var AddressFamilyNameMap = map[RouteFamily]string{
RF_FS_IPv4_VPN: "l3vpn-ipv4-flowspec",
RF_FS_IPv6_UC: "ipv6-flowspec",
RF_FS_IPv6_VPN: "l3vpn-ipv6-flowspec",
+ RF_FS_L2_VPN: "l2vpn-flowspec",
RF_OPAQUE: "opaque",
}
@@ -3112,6 +3318,7 @@ var AddressFamilyValueMap = map[string]RouteFamily{
AddressFamilyNameMap[RF_FS_IPv4_VPN]: RF_FS_IPv4_VPN,
AddressFamilyNameMap[RF_FS_IPv6_UC]: RF_FS_IPv6_UC,
AddressFamilyNameMap[RF_FS_IPv6_VPN]: RF_FS_IPv6_VPN,
+ AddressFamilyNameMap[RF_FS_L2_VPN]: RF_FS_L2_VPN,
AddressFamilyNameMap[RF_OPAQUE]: RF_OPAQUE,
}
@@ -3150,6 +3357,8 @@ func NewPrefixFromRouteFamily(afi uint16, safi uint8) (prefix AddrPrefixInterfac
prefix = &FlowSpecIPv6Unicast{}
case RF_FS_IPv6_VPN:
prefix = &FlowSpecIPv6VPN{}
+ case RF_FS_L2_VPN:
+ prefix = &FlowSpecL2VPN{}
case RF_OPAQUE:
prefix = &OpaqueNLRI{}
default:
diff --git a/packet/bgp_test.go b/packet/bgp_test.go
index f243a785..29aa4e69 100644
--- a/packet/bgp_test.go
+++ b/packet/bgp_test.go
@@ -3,6 +3,7 @@ package bgp
import (
"bytes"
"encoding/binary"
+ "fmt"
"github.com/stretchr/testify/assert"
"net"
"reflect"
@@ -534,3 +535,31 @@ func Test_Aigp(t *testing.T) {
t.Log(bytes.Equal(buf1, buf2))
}
}
+
+func Test_FlowSpecNlriL2(t *testing.T) {
+ assert := assert.New(t)
+ mac, _ := net.ParseMAC("01:23:45:67:89:ab")
+ cmp := make([]FlowSpecComponentInterface, 0)
+ cmp = append(cmp, NewFlowSpecDestinationMac(mac))
+ cmp = append(cmp, NewFlowSpecSourceMac(mac))
+ eq := 0x1
+ item1 := NewFlowSpecComponentItem(eq, int(IPv4))
+ cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, []*FlowSpecComponentItem{item1}))
+ n1 := NewFlowSpecL2VPN(cmp)
+ buf1, err := n1.Serialize()
+ assert.Nil(err)
+ n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_L2_VPN))
+ assert.Nil(err)
+ err = n2.DecodeFromBytes(buf1)
+ assert.Nil(err)
+ buf2, _ := n2.Serialize()
+ if reflect.DeepEqual(n1, n2) == true {
+ t.Log("OK")
+ } else {
+ t.Error("Something wrong")
+ t.Error(len(buf1), n1, buf1)
+ t.Error(len(buf2), n2, buf2)
+ t.Log(bytes.Equal(buf1, buf2))
+ }
+ fmt.Println(n1, n2)
+}
diff --git a/packet/constant.go b/packet/constant.go
index ac270cad..aa9b17b9 100644
--- a/packet/constant.go
+++ b/packet/constant.go
@@ -131,3 +131,64 @@ func (f TCPFlag) String() string {
}
return strings.Join(ss, "|")
}
+
+type EthernetType int
+
+const (
+ IPv4 EthernetType = 0x0800
+ ARP EthernetType = 0x0806
+ RARP EthernetType = 0x8035
+ VMTP EthernetType = 0x805B
+ APPLE_TALK EthernetType = 0x809B
+ AARP EthernetType = 0x80F3
+ IPX EthernetType = 0x8137
+ SNMP EthernetType = 0x814C
+ NET_BIOS EthernetType = 0x8191
+ XTP EthernetType = 0x817D
+ IPv6 EthernetType = 0x86DD
+ PPPoE_DISCOVERY EthernetType = 0x8863
+ PPPoE_SESSION EthernetType = 0x8864
+ LOOPBACK EthernetType = 0x9000
+)
+
+var EthernetTypeNameMap = map[EthernetType]string{
+ IPv4: "ipv4",
+ ARP: "arp",
+ RARP: "rarp",
+ VMTP: "vmtp",
+ APPLE_TALK: "apple-talk",
+ AARP: "aarp",
+ IPX: "ipx",
+ SNMP: "snmp",
+ NET_BIOS: "net-bios",
+ XTP: "xtp",
+ IPv6: "ipv6",
+ PPPoE_DISCOVERY: "pppoe-discovery",
+ PPPoE_SESSION: "pppoe-session",
+ LOOPBACK: "loopback",
+}
+
+var EthernetTypeValueMap = map[string]EthernetType{
+ EthernetTypeNameMap[IPv4]: IPv4,
+ EthernetTypeNameMap[ARP]: ARP,
+ EthernetTypeNameMap[RARP]: RARP,
+ EthernetTypeNameMap[VMTP]: VMTP,
+ EthernetTypeNameMap[APPLE_TALK]: APPLE_TALK,
+ EthernetTypeNameMap[AARP]: AARP,
+ EthernetTypeNameMap[IPX]: IPX,
+ EthernetTypeNameMap[SNMP]: SNMP,
+ EthernetTypeNameMap[NET_BIOS]: NET_BIOS,
+ EthernetTypeNameMap[XTP]: XTP,
+ EthernetTypeNameMap[IPv6]: IPv6,
+ EthernetTypeNameMap[PPPoE_DISCOVERY]: PPPoE_DISCOVERY,
+ EthernetTypeNameMap[PPPoE_SESSION]: PPPoE_SESSION,
+ EthernetTypeNameMap[LOOPBACK]: LOOPBACK,
+}
+
+func (t EthernetType) String() string {
+ n, ok := EthernetTypeNameMap[t]
+ if !ok {
+ return fmt.Sprintf("%d", t)
+ }
+ return n
+}
diff --git a/tools/pyang_plugins/gobgp.yang b/tools/pyang_plugins/gobgp.yang
index a15fe80d..775d851d 100644
--- a/tools/pyang_plugins/gobgp.yang
+++ b/tools/pyang_plugins/gobgp.yang
@@ -119,6 +119,13 @@ module gobgp {
reference "RFC5575";
}
+ identity L2VPN-FLOWSPEC {
+ base bgp-types:afi-safi-type;
+ description
+ "L2VPN flowspec (AFI,SAFI = 25,134)";
+ reference "draft-ietf-idr-flowspec-l2vpn-03";
+ }
+
identity OPAQUE {
base bgp-types:afi-safi-type;
description
@@ -743,7 +750,7 @@ module gobgp {
"Configures a file name to be written.";
}
leaf interval {
- type int64;
+ type uint64;
}
}
}