summaryrefslogtreecommitdiffhomepage
path: root/packet
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2016-03-30 17:57:56 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-03-31 11:38:17 +0900
commit051621bf3aecbe0fd6292a3b4ee41ab42169eea1 (patch)
treedafa1b882570e059d57692c14e8a9537ff8c6f07 /packet
parent63788325a04d2c1956f79713fabcb00d68782f37 (diff)
*: support draft-ietf-idr-flowspec-l2vpn-03
$ gobgp g ri add -a l2vpn-flowspec match destination-mac 01:01:01:01:01:01 ether-type ipv4 vid 10 cos 20 $ gobgp g ri add -a l2vpn-flowspec match source-mac 01:01:01:01:01:01 ether-type arp inner-vid 20 inner-cos 20 Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'packet')
-rw-r--r--packet/bgp.go327
-rw-r--r--packet/bgp_test.go29
-rw-r--r--packet/constant.go61
3 files changed, 358 insertions, 59 deletions
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
+}