mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
packet: support draft-ietf-idr-flow-spec-v6-06
you can add ipv6 flowspec routes like below
$ gobgp global rib add match destination 2001::/64 10 label '=200' then discard -a ipv6-flowspec
$ gobgp global rib -a ipv6-flowspec
Network Next Hop AS_PATH Age Attrs
*> [destination:2001::/64/10][label: =200] fictitious 00:00:23 [{Origin: i} {Extcomms: [discard]}]
scenario_test is also added
Signed-off-by: ISHIDA Wataru <[email protected]>
This commit is contained in:
+3
-1
@@ -39,7 +39,9 @@ func SetDefaultConfigValues(md toml.MetaData, bt *Bgp) error {
|
||||
AfiSafi{AfiSafiName: "encap"},
|
||||
AfiSafi{AfiSafiName: "rtc"},
|
||||
AfiSafi{AfiSafiName: "ipv4-flowspec"},
|
||||
AfiSafi{AfiSafiName: "l3vpn-ipnv4-flowspec"},
|
||||
AfiSafi{AfiSafiName: "l3vpn-ipv4-flowspec"},
|
||||
AfiSafi{AfiSafiName: "ipv6-flowspec"},
|
||||
AfiSafi{AfiSafiName: "l3vpn-ipv6-flowspec"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -458,6 +458,8 @@ func checkAddressFamily(ip net.IP) (bgp.RouteFamily, error) {
|
||||
rf = bgp.RF_RTC_UC
|
||||
case "ipv4-flowspec", "ipv4-flow", "flow4":
|
||||
rf = bgp.RF_FS_IPv4_UC
|
||||
case "ipv6-flowspec", "ipv6-flow", "flow6":
|
||||
rf = bgp.RF_FS_IPv6_UC
|
||||
case "":
|
||||
if len(ip) == 0 || ip.To4() != nil {
|
||||
rf = bgp.RF_IPv4_UC
|
||||
|
||||
+23
-12
@@ -235,7 +235,7 @@ func ParseExtendedCommunities(input string) ([]bgp.ExtendedCommunityInterface, e
|
||||
return exts, nil
|
||||
}
|
||||
|
||||
func ParseFlowSpecArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
|
||||
func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string) (bgp.AddrPrefixInterface, []string, error) {
|
||||
thenPos := len(args)
|
||||
for idx, v := range args {
|
||||
if v == "then" {
|
||||
@@ -246,13 +246,20 @@ func ParseFlowSpecArgs(args []string) (bgp.AddrPrefixInterface, []string, error)
|
||||
return nil, nil, fmt.Errorf("invalid format")
|
||||
}
|
||||
matchArgs := args[1:thenPos]
|
||||
cmp, err := bgp.ParseFlowSpecComponents(strings.Join(matchArgs, " "))
|
||||
cmp, err := bgp.ParseFlowSpecComponents(rf, strings.Join(matchArgs, " "))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
nlri := bgp.NewFlowSpecIPv4Unicast(cmp)
|
||||
extcomms := args[thenPos:]
|
||||
return nlri, extcomms, nil
|
||||
var nlri bgp.AddrPrefixInterface
|
||||
switch rf {
|
||||
case bgp.RF_FS_IPv4_UC:
|
||||
nlri = bgp.NewFlowSpecIPv4Unicast(cmp)
|
||||
case bgp.RF_FS_IPv6_UC:
|
||||
nlri = bgp.NewFlowSpecIPv6Unicast(cmp)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid route family")
|
||||
}
|
||||
return nlri, args[thenPos:], nil
|
||||
}
|
||||
|
||||
func ParseEvpnMacAdvArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
|
||||
@@ -449,8 +456,8 @@ 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:
|
||||
nlri, extcomms, err = ParseFlowSpecArgs(args)
|
||||
case bgp.RF_FS_IPv4_UC, bgp.RF_FS_IPv6_UC:
|
||||
nlri, extcomms, err = ParseFlowSpecArgs(rf, args)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported route family: %s", rf)
|
||||
}
|
||||
@@ -520,16 +527,17 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
|
||||
helpErrMap := map[bgp.RouteFamily]error{}
|
||||
helpErrMap[bgp.RF_IPv4_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [nexthop <ADDRESS>] -a ipv4", cmdstr, modtype)
|
||||
helpErrMap[bgp.RF_IPv6_UC] = fmt.Errorf("usage: %s rib %s <PREFIX> [nexthop <ADDRESS>] -a ipv6", cmdstr, modtype)
|
||||
helpErrMap[bgp.RF_FS_IPv4_UC] = fmt.Errorf(`usage: %s rib %s match <MATCH_EXPR> then <THEN_EXPR> [nexthop <ADDRESS>] -a ipv4-flowspec
|
||||
<MATCH_EXPR> : { %s <PREFIX> | %s <PREFIX> |
|
||||
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 <TCPFLAG>... |
|
||||
{ %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
|
||||
{ %s | %s | %s | %s | %s | %s | %s | %s } <ITEM>... }...
|
||||
<PROTO> : %s
|
||||
<FRAGMENT_TYPE> : not-a-fragment, is-a-fragment, first-fragment, last-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`, cmdstr, modtype,
|
||||
<RT> : xxx:yyy, xx.xx.xx.xx:yyy, xxx.xxx:yyy`, err, cmdstr, modtype,
|
||||
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_DST_PREFIX],
|
||||
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_SRC_PREFIX],
|
||||
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_IP_PROTO],
|
||||
@@ -542,11 +550,14 @@ func modPath(resource api.Resource, name, modtype string, args []string) error {
|
||||
bgp.FlowSpecNameMap[bgp.FLOW_SPEC_TYPE_ICMP_CODE],
|
||||
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_EVPN] = fmt.Errorf(`usage: %s rib %s { macadv <MACADV> | multicast <MULTICAST> } [nexthop <ADDRESS>] -a evpn
|
||||
helpErrMap[bgp.RF_FS_IPv4_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv4-flowspec")
|
||||
helpErrMap[bgp.RF_FS_IPv6_UC] = fmt.Errorf(fsHelpMsgFmt, "ipv6-flowspec")
|
||||
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)
|
||||
if err, ok := helpErrMap[rf]; ok {
|
||||
|
||||
+191
-27
@@ -1860,6 +1860,7 @@ const (
|
||||
FLOW_SPEC_TYPE_PKT_LEN
|
||||
FLOW_SPEC_TYPE_DSCP
|
||||
FLOW_SPEC_TYPE_FRAGMENT
|
||||
FLOW_SPEC_TYPE_LABEL
|
||||
)
|
||||
|
||||
var FlowSpecNameMap = map[BGPFlowSpecType]string{
|
||||
@@ -1876,6 +1877,7 @@ var FlowSpecNameMap = map[BGPFlowSpecType]string{
|
||||
FLOW_SPEC_TYPE_PKT_LEN: "packet-length",
|
||||
FLOW_SPEC_TYPE_DSCP: "dscp",
|
||||
FLOW_SPEC_TYPE_FRAGMENT: "fragment",
|
||||
FLOW_SPEC_TYPE_LABEL: "label",
|
||||
}
|
||||
|
||||
var FlowSpecValueMap = map[string]BGPFlowSpecType{
|
||||
@@ -1891,29 +1893,58 @@ var FlowSpecValueMap = map[string]BGPFlowSpecType{
|
||||
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,
|
||||
}
|
||||
|
||||
func flowSpecPrefixParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
func flowSpecPrefixParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
|
||||
if len(args) < 2 {
|
||||
return nil, fmt.Errorf("invalid flowspec dst/src prefix")
|
||||
}
|
||||
typ := args[0]
|
||||
ip, net, _ := net.ParseCIDR(args[1])
|
||||
if ip.To4() == nil {
|
||||
ip, net, err := net.ParseCIDR(args[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ip prefix")
|
||||
}
|
||||
afi, _ := RouteFamilyToAfiSafi(rf)
|
||||
if afi == AFI_IP && ip.To4() == nil {
|
||||
return nil, fmt.Errorf("invalid ipv4 prefix")
|
||||
} else if afi == AFI_IP6 && !strings.Contains(ip.String(), ":") {
|
||||
return nil, fmt.Errorf("invalid ipv6 prefix")
|
||||
}
|
||||
ones, _ := net.Mask.Size()
|
||||
var offset uint8
|
||||
if len(args) > 2 {
|
||||
o, err := strconv.Atoi(args[2])
|
||||
offset = uint8(o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]:
|
||||
return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
|
||||
switch rf {
|
||||
case RF_FS_IPv4_UC:
|
||||
return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
|
||||
case RF_FS_IPv6_UC:
|
||||
return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
|
||||
}
|
||||
case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]:
|
||||
return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
|
||||
switch rf {
|
||||
case RF_FS_IPv4_UC:
|
||||
return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
|
||||
case RF_FS_IPv6_UC:
|
||||
return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("invalid type. only destination or source is allowed")
|
||||
}
|
||||
|
||||
func flowSpecIpProtoParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
func flowSpecIpProtoParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
|
||||
ss := make([]string, 0, len(ProtocolNameMap))
|
||||
for _, v := range ProtocolNameMap {
|
||||
ss = append(ss, v)
|
||||
@@ -1936,7 +1967,7 @@ func flowSpecIpProtoParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
return NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, items), nil
|
||||
}
|
||||
|
||||
func flowSpecTcpFlagParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
func flowSpecTcpFlagParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
|
||||
ss := make([]string, 0, len(TCPFlagNameMap))
|
||||
for _, v := range TCPFlagNameMap {
|
||||
ss = append(ss, v)
|
||||
@@ -1958,7 +1989,10 @@ func flowSpecTcpFlagParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
return NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, items), nil
|
||||
}
|
||||
|
||||
func flowSpecNumericParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
func flowSpecNumericParser(rf RouteFamily, args []string) (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")
|
||||
}
|
||||
exp := regexp.MustCompile("^((<=|>=|[<>=])(\\d+)&)?(<=|>=|[<>=])?(\\d+)$")
|
||||
items := make([]*FlowSpecComponentItem, 0)
|
||||
|
||||
@@ -2000,16 +2034,20 @@ func flowSpecNumericParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
items = append(items, f(and, elems[4], elems[5]))
|
||||
|
||||
}
|
||||
|
||||
return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
|
||||
}
|
||||
|
||||
func flowSpecFragmentParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
|
||||
if len(args) < 2 {
|
||||
return nil, fmt.Errorf("invalid flowspec fragment specifier")
|
||||
}
|
||||
value := 0
|
||||
switch args[1] {
|
||||
case "not-a-fragment":
|
||||
if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP6 {
|
||||
return nil, fmt.Errorf("can't specify not-a-fragment for ipv6")
|
||||
}
|
||||
value = 0x1
|
||||
case "is-a-fragment":
|
||||
value = 0x2
|
||||
@@ -2024,7 +2062,7 @@ func flowSpecFragmentParser(args []string) (FlowSpecComponentInterface, error) {
|
||||
return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
|
||||
}
|
||||
|
||||
var flowSpecParserMap = map[BGPFlowSpecType]func([]string) (FlowSpecComponentInterface, error){
|
||||
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,
|
||||
@@ -2037,9 +2075,10 @@ var flowSpecParserMap = map[BGPFlowSpecType]func([]string) (FlowSpecComponentInt
|
||||
FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumericParser,
|
||||
FLOW_SPEC_TYPE_DSCP: flowSpecNumericParser,
|
||||
FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser,
|
||||
FLOW_SPEC_TYPE_LABEL: flowSpecNumericParser,
|
||||
}
|
||||
|
||||
func ParseFlowSpecComponents(input string) ([]FlowSpecComponentInterface, error) {
|
||||
func ParseFlowSpecComponents(rf RouteFamily, input string) ([]FlowSpecComponentInterface, error) {
|
||||
idxs := make([]struct {
|
||||
t BGPFlowSpecType
|
||||
i int
|
||||
@@ -2065,7 +2104,7 @@ func ParseFlowSpecComponents(input string) ([]FlowSpecComponentInterface, error)
|
||||
} else {
|
||||
a = args[idx.i:]
|
||||
}
|
||||
cmp, err := f(a)
|
||||
cmp, err := f(rf, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2110,12 +2149,8 @@ func (p *flowSpecPrefix) Serialize() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix) Len() int {
|
||||
l := p.Prefix.Len()
|
||||
if l < 0xf0 {
|
||||
return l + 1
|
||||
} else {
|
||||
return l + 2
|
||||
}
|
||||
buf, _ := p.Serialize()
|
||||
return len(buf)
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix) Type() BGPFlowSpecType {
|
||||
@@ -2136,6 +2171,57 @@ func (p *flowSpecPrefix) MarshalJSON() ([]byte, error) {
|
||||
})
|
||||
}
|
||||
|
||||
type flowSpecPrefix6 struct {
|
||||
Prefix AddrPrefixInterface
|
||||
Offset uint8
|
||||
type_ BGPFlowSpecType
|
||||
}
|
||||
|
||||
// draft-ietf-idr-flow-spec-v6-06
|
||||
// <type (1 octet), prefix length (1 octet), prefix offset(1 octet), prefix>
|
||||
func (p *flowSpecPrefix6) DecodeFromBytes(data []byte) error {
|
||||
p.type_ = BGPFlowSpecType(data[0])
|
||||
p.Offset = data[2]
|
||||
prefix := append([]byte{data[1]}, data[3:]...)
|
||||
return p.Prefix.DecodeFromBytes(prefix)
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix6) Serialize() ([]byte, error) {
|
||||
buf := []byte{byte(p.Type())}
|
||||
bbuf, err := p.Prefix.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = append(buf, bbuf[0])
|
||||
buf = append(buf, p.Offset)
|
||||
return append(buf, bbuf[1:]...), nil
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix6) Len() int {
|
||||
buf, _ := p.Serialize()
|
||||
return len(buf)
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix6) Type() BGPFlowSpecType {
|
||||
return p.type_
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix6) String() string {
|
||||
return fmt.Sprintf("[%s:%s/%d]", p.Type(), p.Prefix.String(), p.Offset)
|
||||
}
|
||||
|
||||
func (p *flowSpecPrefix6) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Type BGPFlowSpecType `json:"type"`
|
||||
Value AddrPrefixInterface `json:"value"`
|
||||
Offset uint8 `json:"offset"`
|
||||
}{
|
||||
Type: p.Type(),
|
||||
Value: p.Prefix,
|
||||
Offset: p.Offset,
|
||||
})
|
||||
}
|
||||
|
||||
type FlowSpecDestinationPrefix struct {
|
||||
flowSpecPrefix
|
||||
}
|
||||
@@ -2152,6 +2238,22 @@ func NewFlowSpecSourcePrefix(prefix AddrPrefixInterface) *FlowSpecSourcePrefix {
|
||||
return &FlowSpecSourcePrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_SRC_PREFIX}}
|
||||
}
|
||||
|
||||
type FlowSpecDestinationPrefix6 struct {
|
||||
flowSpecPrefix6
|
||||
}
|
||||
|
||||
func NewFlowSpecDestinationPrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecDestinationPrefix6 {
|
||||
return &FlowSpecDestinationPrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_DST_PREFIX}}
|
||||
}
|
||||
|
||||
type FlowSpecSourcePrefix6 struct {
|
||||
flowSpecPrefix6
|
||||
}
|
||||
|
||||
func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecSourcePrefix6 {
|
||||
return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}}
|
||||
}
|
||||
|
||||
type FlowSpecComponentItem struct {
|
||||
Op int `json:"op"`
|
||||
Value int `json:"value"`
|
||||
@@ -2332,6 +2434,7 @@ var flowSpecFormatMap = map[BGPFlowSpecType]func(op int, value int) string{
|
||||
FLOW_SPEC_TYPE_PKT_LEN: formatNumeric,
|
||||
FLOW_SPEC_TYPE_DSCP: formatNumeric,
|
||||
FLOW_SPEC_TYPE_FRAGMENT: formatFragment,
|
||||
FLOW_SPEC_TYPE_LABEL: formatNumeric,
|
||||
}
|
||||
|
||||
func (p *FlowSpecComponent) String() string {
|
||||
@@ -2414,30 +2517,34 @@ func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error {
|
||||
var i FlowSpecComponentInterface
|
||||
switch t {
|
||||
case FLOW_SPEC_TYPE_DST_PREFIX:
|
||||
p := &FlowSpecDestinationPrefix{}
|
||||
switch rf {
|
||||
case RF_FS_IPv4_UC:
|
||||
p.Prefix = &IPAddrPrefix{}
|
||||
i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, ""))
|
||||
case RF_FS_IPv4_VPN:
|
||||
p.Prefix = &LabeledVPNIPAddrPrefix{}
|
||||
i = NewFlowSpecDestinationPrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
|
||||
case RF_FS_IPv6_UC:
|
||||
i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0)
|
||||
case RF_FS_IPv6_VPN:
|
||||
i = NewFlowSpecDestinationPrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
|
||||
default:
|
||||
return fmt.Errorf("Invalid RF: %v", rf)
|
||||
}
|
||||
i = p
|
||||
case FLOW_SPEC_TYPE_SRC_PREFIX:
|
||||
p := &FlowSpecSourcePrefix{}
|
||||
switch rf {
|
||||
case RF_FS_IPv4_UC:
|
||||
p.Prefix = &IPAddrPrefix{}
|
||||
i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, ""))
|
||||
case RF_FS_IPv4_VPN:
|
||||
p.Prefix = &LabeledVPNIPAddrPrefix{}
|
||||
i = NewFlowSpecSourcePrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
|
||||
case RF_FS_IPv6_UC:
|
||||
i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0)
|
||||
case RF_FS_IPv6_VPN:
|
||||
i = NewFlowSpecSourcePrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
|
||||
default:
|
||||
return fmt.Errorf("Invalid RF: %v", rf)
|
||||
}
|
||||
i = p
|
||||
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_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL:
|
||||
i = NewFlowSpecComponent(t, nil)
|
||||
default:
|
||||
i = &FlowSpecUnknown{}
|
||||
@@ -2547,6 +2654,53 @@ func (n *FlowSpecIPv4VPN) SAFI() uint8 {
|
||||
func NewFlowSpecIPv4VPN(value []FlowSpecComponentInterface) *FlowSpecIPv4VPN {
|
||||
return &FlowSpecIPv4VPN{FlowSpecNLRI{value, RF_FS_IPv4_VPN}}
|
||||
}
|
||||
|
||||
type FlowSpecIPv6Unicast struct {
|
||||
FlowSpecNLRI
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte) error {
|
||||
return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6Unicast) AFI() uint16 {
|
||||
return AFI_IP6
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6Unicast) SAFI() uint8 {
|
||||
return SAFI_FLOW_SPEC_UNICAST
|
||||
}
|
||||
|
||||
func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast {
|
||||
return &FlowSpecIPv6Unicast{FlowSpecNLRI{
|
||||
Value: value,
|
||||
rf: RF_FS_IPv6_UC,
|
||||
}}
|
||||
}
|
||||
|
||||
type FlowSpecIPv6VPN struct {
|
||||
FlowSpecNLRI
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte) error {
|
||||
return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6VPN) AFI() uint16 {
|
||||
return AFI_IP6
|
||||
}
|
||||
|
||||
func (n *FlowSpecIPv6VPN) SAFI() uint8 {
|
||||
return SAFI_FLOW_SPEC_VPN
|
||||
}
|
||||
|
||||
func NewFlowSpecIPv6VPN(value []FlowSpecComponentInterface) *FlowSpecIPv6VPN {
|
||||
return &FlowSpecIPv6VPN{FlowSpecNLRI{
|
||||
Value: value,
|
||||
rf: RF_FS_IPv6_VPN,
|
||||
}}
|
||||
}
|
||||
|
||||
func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily {
|
||||
return RouteFamily(int(afi)<<16 | int(safi))
|
||||
}
|
||||
@@ -2574,6 +2728,8 @@ const (
|
||||
RF_ENCAP RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION
|
||||
RF_FS_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_UNICAST
|
||||
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
|
||||
)
|
||||
|
||||
func GetRouteFamily(name string) (RouteFamily, error) {
|
||||
@@ -2610,6 +2766,10 @@ func GetRouteFamily(name string) (RouteFamily, error) {
|
||||
return RF_FS_IPv4_UC, nil
|
||||
case "l3vpn-ipv4-flowspec":
|
||||
return RF_FS_IPv4_VPN, nil
|
||||
case "ipv6-flowspec":
|
||||
return RF_FS_IPv6_UC, nil
|
||||
case "l3vpn-ipv6-flowspec":
|
||||
return RF_FS_IPv6_VPN, nil
|
||||
}
|
||||
return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name)
|
||||
}
|
||||
@@ -2638,6 +2798,10 @@ func NewPrefixFromRouteFamily(afi uint16, safi uint8) (prefix AddrPrefixInterfac
|
||||
prefix = &FlowSpecIPv4Unicast{}
|
||||
case RF_FS_IPv4_VPN:
|
||||
prefix = &FlowSpecIPv4VPN{}
|
||||
case RF_FS_IPv6_UC:
|
||||
prefix = &FlowSpecIPv6Unicast{}
|
||||
case RF_FS_IPv6_VPN:
|
||||
prefix = &FlowSpecIPv6VPN{}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown route family. AFI: %d, SAFI: %d", afi, safi)
|
||||
}
|
||||
|
||||
@@ -464,3 +464,50 @@ func Test_FlowSpecExtended(t *testing.T) {
|
||||
t.Error(len(buf2), m2, buf2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FlowSpecNlriv6(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
cmp := make([]FlowSpecComponentInterface, 0)
|
||||
cmp = append(cmp, NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(64, "2001::"), 12))
|
||||
cmp = append(cmp, NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(64, "2001::"), 12))
|
||||
eq := 0x1
|
||||
gt := 0x2
|
||||
lt := 0x4
|
||||
and := 0x40
|
||||
not := 0x2
|
||||
item1 := NewFlowSpecComponentItem(eq, TCP)
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1}))
|
||||
item2 := NewFlowSpecComponentItem(gt|eq, 20)
|
||||
item3 := NewFlowSpecComponentItem(and|lt|eq, 30)
|
||||
item4 := NewFlowSpecComponentItem(eq, 10)
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PKT_LEN, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DSCP, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_LABEL, []*FlowSpecComponentItem{item2, item3, item4}))
|
||||
isFlagment := 0x02
|
||||
item5 := NewFlowSpecComponentItem(isFlagment, 0)
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5}))
|
||||
item6 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK)
|
||||
item7 := NewFlowSpecComponentItem(and|not, TCP_FLAG_URGENT)
|
||||
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item6, item7}))
|
||||
n1 := NewFlowSpecIPv6Unicast(cmp)
|
||||
buf1, err := n1.Serialize()
|
||||
assert.Nil(err)
|
||||
n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv6_UC))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ class GoBGPTestBase(unittest.TestCase):
|
||||
matchs2 = ['tcp-flags syn', 'protocol tcp udp', "packet-length '>1000&<2000'"]
|
||||
thens2 = ['rate-limit 9600', 'redirect 0.10:100', 'mark 20', 'action sample']
|
||||
g1.add_route(route='flow1', rf='ipv4-flowspec', matchs=matchs2, thens=thens2)
|
||||
matchs3 = ['destination 2001::/24/10', 'source 2002::/24/15']
|
||||
thens3 = ['discard']
|
||||
e1.add_route(route='flow2', rf='ipv6-flowspec', matchs=matchs3, thens=thens3)
|
||||
matchs4 = ['destination 2001::/24 10', "label '=100'"]
|
||||
thens4 = ['discard']
|
||||
g1.add_route(route='flow2', rf='ipv6-flowspec', matchs=matchs4, thens=thens4)
|
||||
|
||||
initial_wait_time = max(ctn.run() for ctn in ctns)
|
||||
|
||||
@@ -71,6 +77,9 @@ class GoBGPTestBase(unittest.TestCase):
|
||||
def test_02_check_gobgp_global_rib(self):
|
||||
self.assertTrue(len(self.gobgp.get_global_rib(rf='ipv4-flowspec')) == 2)
|
||||
|
||||
def test_03_check_gobgp_global_rib(self):
|
||||
self.assertTrue(len(self.gobgp.get_global_rib(rf='ipv6-flowspec')) == 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.geteuid() is not 0:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from base import *
|
||||
|
||||
from itertools import chain
|
||||
|
||||
class ExaBGPContainer(BGPContainer):
|
||||
|
||||
@@ -101,8 +101,7 @@ class ExaBGPContainer(BGPContainer):
|
||||
cmd << '{0};'.format(str(r))
|
||||
cmd << ' }'
|
||||
|
||||
routes = [r for r in self.routes.values() if r['rf'] == 'ipv4-flowspec']
|
||||
|
||||
routes = [r for r in self.routes.itervalues() if 'flowspec' in r['rf']]
|
||||
if len(routes) > 0:
|
||||
cmd << ' flow {'
|
||||
for route in routes:
|
||||
|
||||
@@ -189,6 +189,9 @@ class GoBGPContainer(BGPContainer):
|
||||
|
||||
if info['flowspec']:
|
||||
afi_safi_list.append({'AfiSafiName': 'ipv4-flowspec'})
|
||||
afi_safi_list.append({'AfiSafiName': 'l3vpn-ipv4-flowspec'})
|
||||
afi_safi_list.append({'AfiSafiName': 'ipv6-flowspec'})
|
||||
afi_safi_list.append({'AfiSafiName': 'l3vpn-ipv6-flowspec'})
|
||||
|
||||
n = {'NeighborConfig':
|
||||
{'NeighborAddress': info['neigh_addr'].split('/')[0],
|
||||
@@ -301,7 +304,7 @@ class GoBGPContainer(BGPContainer):
|
||||
if v['rf'] == 'ipv4' or v['rf'] == 'ipv6':
|
||||
cmd = 'gobgp global '\
|
||||
'rib add {0} -a {1}'.format(v['prefix'], v['rf'])
|
||||
elif v['rf']== 'ipv4-flowspec':
|
||||
elif v['rf'] == 'ipv4-flowspec' or v['rf'] == 'ipv6-flowspec':
|
||||
cmd = 'gobgp global '\
|
||||
'rib add match {0} then {1} -a {2}'.format(' '.join(v['matchs']), ' '.join(v['thens']), v['rf'])
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user