diff options
-rw-r--r-- | gobgp/cmd/global.go | 34 | ||||
-rw-r--r-- | packet/bgp/bgp.go | 61 |
2 files changed, 57 insertions, 38 deletions
diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go index 6ab87024..d1aa38a9 100644 --- a/gobgp/cmd/global.go +++ b/gobgp/cmd/global.go @@ -324,19 +324,31 @@ func ParseExtendedCommunities(args []string) ([]bgp.ExtendedCommunityInterface, } func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string, rd bgp.RouteDistinguisherInterface) (bgp.AddrPrefixInterface, []string, error) { - thenPos := len(args) - for idx, v := range args { - if v == "then" { - thenPos = idx - break - } + // Format: + // match <rule>... [then <action>...] [rt <rt>...] + req := 3 // match <key1> <arg1> [<key2> <arg2>...] + if len(args) < req { + return nil, nil, fmt.Errorf("%d args required at least, but got %d", req, len(args)) + } + m := extractReserved(args, []string{"match", "then", "rt"}) + if len(m["match"]) == 0 { + return nil, nil, fmt.Errorf("specify filtering rules with keyword 'match'") } - if len(args) < 4 || args[0] != "match" || thenPos > len(args)-2 { - return nil, nil, fmt.Errorf("invalid format") + + extcomms := m["then"] + switch rf { + case bgp.RF_FS_IPv4_VPN, bgp.RF_FS_IPv6_VPN, bgp.RF_FS_L2_VPN: + if len(m["rt"]) > 0 { + extcomms = append(extcomms, "rt") + extcomms = append(extcomms, m["rt"]...) + } + default: + if len(m["rt"]) > 0 { + return nil, nil, fmt.Errorf("cannot specify rt for %s", rf.String()) + } } - matchArgs := args[1:thenPos] - rules, err := bgp.ParseFlowSpecComponents(rf, strings.Join(matchArgs, " ")) + rules, err := bgp.ParseFlowSpecComponents(rf, strings.Join(m["match"], " ")) if err != nil { return nil, nil, err } @@ -357,7 +369,7 @@ func ParseFlowSpecArgs(rf bgp.RouteFamily, args []string, rd bgp.RouteDistinguis return nil, nil, fmt.Errorf("invalid route family") } - return nlri, args[thenPos+1:], nil + return nlri, extcomms, nil } func ParseEvpnEthernetAutoDiscoveryArgs(args []string) (bgp.AddrPrefixInterface, []string, error) { diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index 987bf328..8c4400ba 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -3364,39 +3364,46 @@ var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, []string) (FlowSpe FLOW_SPEC_TYPE_INNER_COS: flowSpecNumericParser, } -func ParseFlowSpecComponents(rf RouteFamily, input string) ([]FlowSpecComponentInterface, error) { - idxs := make([]struct { - t BGPFlowSpecType - i int - }, 0, 8) - args := strings.Split(input, " ") - for idx, v := range args { - if t, ok := FlowSpecValueMap[v]; ok { - idxs = append(idxs, struct { - t BGPFlowSpecType - i int - }{t, idx}) - } - } - if len(idxs) == 0 { - return nil, fmt.Errorf("failed to parse: %s", input) - } - cmps := make([]FlowSpecComponentInterface, 0, len(idxs)) - for i, idx := range idxs { - var a []string - f := flowSpecParserMap[idx.t] - if i < len(idxs)-1 { - a = args[idx.i:idxs[i+1].i] +func extractFlowSpecArgs(args []string) map[BGPFlowSpecType][]string { + m := make(map[BGPFlowSpecType][]string, len(FlowSpecValueMap)) + var typ BGPFlowSpecType + for _, arg := range args { + if t, ok := FlowSpecValueMap[arg]; ok { + typ = t + m[typ] = make([]string, 0) } else { - a = args[idx.i:] + m[typ] = append(m[typ], arg) } - cmp, err := f(rf, a) + } + return m +} + +func ParseFlowSpecComponents(rf RouteFamily, arg string) ([]FlowSpecComponentInterface, error) { + _, safi := RouteFamilyToAfiSafi(rf) + switch safi { + case SAFI_FLOW_SPEC_UNICAST, SAFI_FLOW_SPEC_VPN: + // Valid + default: + return nil, fmt.Errorf("invalid address family: %s", rf.String()) + } + + typeArgs := extractFlowSpecArgs(strings.Split(arg, " ")) + rules := make([]FlowSpecComponentInterface, 0, len(typeArgs)) + for typ, args := range typeArgs { + parser, ok := flowSpecParserMap[typ] + if !ok { + return nil, fmt.Errorf("unsupported traffic filtering rule type: %s", typ.String()) + } + if len(args) == 0 { + return nil, fmt.Errorf("specify traffic filtering rules for %s", typ.String()) + } + rule, err := parser(rf, typ, args) if err != nil { return nil, err } - cmps = append(cmps, cmp) + rules = append(rules, rule) } - return cmps, nil + return rules, nil } func (t BGPFlowSpecType) String() string { |