From 3f7e23fb4bf4bfe62c63cac2a85c0f1d783f2e14 Mon Sep 17 00:00:00 2001 From: IWASE Yusuke Date: Mon, 25 Dec 2017 11:47:32 +0900 Subject: cli: Slash separated offset arg for FlowSpec Prefix Currently, "gobgp" command supports only; "/ " # space separated format to specify the prefix offset for the FlowSpec destination/source rules, but the displayed format with "rib" command is; "//" # slash separated and the slash separated format is not allowed as command arguments. This patch enables to specify the slash separated format for the FlowSpec destination/source rules arguments and resolve unmatch of the input/output formats. Example: $ gobgp global rib -a ipv6-flowspec add match destination 0:db8:1::1/64/16 then accept $ gobgp global rib -a ipv6-flowspec Network Next Hop AS_PATH Age Attrs *> [destination: 0:db8:1::/64/16] fictitious 00:00:00 [{Origin: ?} Signed-off-by: IWASE Yusuke --- packet/bgp/bgp.go | 102 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index 28d47cfd..2670d63f 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -3099,35 +3099,40 @@ func flowSpecPrefixParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (F // - IPv6 Prefix // args := []string{"2001:db8:1::/64"} // - IPv6 Prefix with offset - // args := []string{"2001:db8:1::/64", "16"} + // args := []string{"0:db8:1::/64/16"} + // args := []string{"0:db8:1::/64", "16"} + // - IPv6 Address + // args := []string{"2001:db8:1::1"} + // - IPv6 Address with offset + // args := []string{"0:db8:1::1", "16"} afi, _ := RouteFamilyToAfiSafi(rf) - var prefix net.IP - var prefixLen int - _, nw, err := net.ParseCIDR(args[0]) - if err != nil { - prefix = net.ParseIP(args[0]) - if prefix == nil { - return nil, fmt.Errorf("invalid ip prefix: %s", args[0]) - } - switch afi { - case AFI_IP: - prefixLen = net.IPv4len * 8 - case AFI_IP6: - prefixLen = net.IPv6len * 8 - } - } else { - prefix = nw.IP - prefixLen, _ = nw.Mask.Size() - } - switch afi { case AFI_IP: - if prefix.To4() == nil { - return nil, fmt.Errorf("invalid ipv4 prefix: %s", args[0]) - } if len(args) > 1 { return nil, fmt.Errorf("cannot specify offset for ipv4 prefix") } + invalidIPv4PrefixError := fmt.Errorf("invalid ipv4 prefix: %s", args[0]) + re := regexp.MustCompile("^([\\d.]+)(/(\\d{1,2}))?") + // re.FindStringSubmatch("192.168.0.0/24") + // >>> ["192.168.0.0/24" "192.168.0.0" "/24" "24"] + // re.FindStringSubmatch("192.168.0.1") + // >>> ["192.168.0.1" "192.168.0.1" "" ""] + m := re.FindStringSubmatch(args[0]) + if len(m) < 4 { + return nil, invalidIPv4PrefixError + } + prefix := net.ParseIP(m[1]) + if prefix.To4() == nil { + return nil, invalidIPv4PrefixError + } + var prefixLen uint64 = 32 + if m[3] != "" { + var err error + prefixLen, err = strconv.ParseUint(m[3], 10, 8) + if err != nil || prefixLen > 32 { + return nil, invalidIPv4PrefixError + } + } switch typ { case FLOW_SPEC_TYPE_DST_PREFIX: return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil @@ -3136,22 +3141,55 @@ func flowSpecPrefixParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (F } return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) case AFI_IP6: + if len(args) > 2 { + return nil, fmt.Errorf("invalid arguments for ipv6 prefix: %q", args) + } + invalidIPv6PrefixError := fmt.Errorf("invalid ipv6 prefix: %s", args[0]) + re := regexp.MustCompile("^([a-fA-F\\d:.]+)(/(\\d{1,3}))?(/(\\d{1,3}))?") + // re.FindStringSubmatch("2001:dB8::/64") + // >>> ["2001:dB8::/64" "2001:dB8::" "/64" "64" "" ""] + // re.FindStringSubmatch("2001:dB8::/64/8") + // >>> ["2001:dB8::/64/8" "2001:dB8::" "/64" "64" "/8" "8"] + // re.FindStringSubmatch("2001:dB8::1") + // >>> ["2001:dB8::1" "2001:dB8::1" "" "" "" ""] + m := re.FindStringSubmatch(args[0]) + if len(m) < 4 { + return nil, invalidIPv6PrefixError + } + prefix := net.ParseIP(m[1]) if prefix.To16() == nil { - return nil, fmt.Errorf("invalid ipv6 prefix: %s", args[0]) + return nil, invalidIPv6PrefixError + } + var prefixLen uint64 = 128 + if m[3] != "" { + var err error + prefixLen, err = strconv.ParseUint(m[3], 10, 8) + if err != nil || prefixLen > 128 { + return nil, invalidIPv6PrefixError + } } - var offset uint8 - if len(args) > 1 { - o, err := strconv.Atoi(args[1]) - if err != nil { - return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", args[0]) + var offset uint64 + if len(args) == 1 && m[5] != "" { + var err error + offset, err = strconv.ParseUint(m[5], 10, 8) + if err != nil || offset > 128 { + return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", m[5]) + } + } else if len(args) == 2 { + if m[5] != "" { + return nil, fmt.Errorf("multiple ipv6 prefix offset arguments detected: %q", args) + } + var err error + offset, err = strconv.ParseUint(args[1], 10, 8) + if err != nil || offset > 128 { + return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", args[1]) } - offset = uint8(o) } switch typ { case FLOW_SPEC_TYPE_DST_PREFIX: - return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), offset), nil + return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil case FLOW_SPEC_TYPE_SRC_PREFIX: - return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), offset), nil + return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil } return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) } -- cgit v1.2.3