diff options
author | Satoshi Fujimoto <satoshi.fujimoto7@gmail.com> | 2017-06-19 16:32:38 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-07-10 15:39:14 +0900 |
commit | 4b5e13376c70481aacc1c2c508738279f8cc9e5c (patch) | |
tree | eb653f3d42af5e31dc90c186834a49384f8dfd0f /packet | |
parent | 15cd58e01f47357be5280ef6aa0775f42b811854 (diff) |
packet: Use bitmask operand format to fragment
RFC 5575 suggests using "bitmask operand format" for fragmentation
field, but GoBGP does not have an interface to configure it.
This patch introduce the way to configure bitmask operands for
"fragment" field.
The syntax is similar to TCP flags rules.
For example:
=not-a-fragment
=is-fragment&!last-fragment
Signed-off-by: Satoshi Fujimoto <satoshi.fujimoto7@gmail.com>
Diffstat (limited to 'packet')
-rw-r--r-- | packet/bgp/bgp.go | 85 | ||||
-rw-r--r-- | packet/bgp/bgp_test.go | 13 | ||||
-rw-r--r-- | packet/bgp/constant.go | 26 |
3 files changed, 86 insertions, 38 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index dd924624..a07cd5e5 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -3057,27 +3057,48 @@ func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInt return nil, fmt.Errorf("invalid flowspec fragment specifier") } items := make([]*FlowSpecComponentItem, 0) - for _, a := range args[1:] { - value := 0 - switch a { - case "dont-fragment": - if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP6 { - return nil, fmt.Errorf("can't specify dont-fragment for ipv6") + cmd := strings.Join(args[1:], " ") + var op byte + var flags byte + for cmd != "" { + next := 1 + c := cmd[0:1] + switch c { + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]: + if op&BITMASK_FLAG_OP_MATCH != 0 { + err := fmt.Errorf("invalid flowspec fragment specifier: '=' flag appears multiple time", cmd) + return nil, err + } + op |= BITMASK_FLAG_OP_MATCH + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]: + if op&BITMASK_FLAG_OP_NOT != 0 { + err := fmt.Errorf("invalid flowspec fragment specifier: '!' flag appears multiple time", cmd) + return nil, err } - value = 0x1 - case "is-fragment": - value = 0x2 - case "first-fragment": - value = 0x4 - case "last-fragment": - value = 0x8 - case "not-a-fragment": - value = 0x0 + op = op | BITMASK_FLAG_OP_NOT + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]: + operand := BitmaskFlagOpValueMap[c] + items = append(items, NewFlowSpecComponentItem(int(op), int(flags))) + op = byte(operand) + flags = byte(0) default: - return nil, fmt.Errorf("invalid flowspec fragment specifier") + for k, v := range FragmentFlagNameMap { + length := len(v) + if (len(cmd) >= length) && (cmd[:length] == v) { + flags = flags | byte(k) + next = length + break + } + } + // if not matched with any of FragmentFlags + if next == 1 { + return nil, fmt.Errorf("invalid flowspec fragment specifier: %s", cmd) + } } - items = append(items, NewFlowSpecComponentItem(0, value)) + cmd = cmd[next:] } + op = op | BITMASK_FLAG_OP_END + items = append(items, NewFlowSpecComponentItem(int(op), int(flags))) return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil } @@ -3550,26 +3571,24 @@ func formatFlag(op int, value int) string { } func formatFragment(op int, value int) string { - ss := make([]string, 0) - if value == 0 { - ss = append(ss, "not-a-fragment") - } - if value&0x1 > 0 { - ss = append(ss, "dont-fragment") - } - if value&0x2 > 0 { - ss = append(ss, "is-fragment") + var retString string + if op&BITMASK_FLAG_OP_MATCH > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]) } - if value&0x4 > 0 { - ss = append(ss, "first-fragment") + if op&BITMASK_FLAG_OP_NOT > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]) } - if value&0x8 > 0 { - ss = append(ss, "last-fragment") + for flag, valueFlag := range FragmentFlagValueMap { + if value&int(valueFlag) > 0 { + retString = fmt.Sprintf("%s%s", retString, flag) + } } - if len(ss) > 1 { - return fmt.Sprintf("%s(%s)", formatNumericOp(op), strings.Join(ss, "|")) + if op&BITMASK_FLAG_OP_AND > 0 { + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], retString) + } else { // default is or + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR], retString) } - return fmt.Sprintf("%s%s", formatNumericOp(op), ss[0]) + return retString } func formatEtherType(op int, value int) string { diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go index 998d0568..5731dd32 100644 --- a/packet/bgp/bgp_test.go +++ b/packet/bgp/bgp_test.go @@ -305,11 +305,14 @@ func Test_FlowSpecNlri(t *testing.T) { 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})) 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})) + lastFlagment := 0x08 + match := 0x1 + item5 := NewFlowSpecComponentItem(match, isFlagment) + item6 := NewFlowSpecComponentItem(and, lastFlagment) + cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5, item6})) + item7 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) + item8 := NewFlowSpecComponentItem(and|not, TCP_FLAG_URGENT) + cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item7, item8})) n1 := NewFlowSpecIPv4Unicast(cmp) buf1, err := n1.Serialize() assert.Nil(err) diff --git a/packet/bgp/constant.go b/packet/bgp/constant.go index 2cee1f31..0741d8e8 100644 --- a/packet/bgp/constant.go +++ b/packet/bgp/constant.go @@ -154,6 +154,32 @@ var BitmaskFlagOpValueMap = map[string]BitmaskFlagOp{ BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]: BITMASK_FLAG_OP_MATCH, } +type FragmentFlag int + +const ( + FRAG_FLAG_NOT = 0x00 + FRAG_FLAG_DONT = 0x01 + FRAG_FLAG_IS = 0x02 + FRAG_FLAG_FIRST = 0x04 + FRAG_FLAG_LAST = 0x08 +) + +var FragmentFlagNameMap = map[FragmentFlag]string{ + FRAG_FLAG_NOT: "not-a-fragment", + FRAG_FLAG_DONT: "dont-fragment", + FRAG_FLAG_IS: "is-fragment", + FRAG_FLAG_FIRST: "first-fragment", + FRAG_FLAG_LAST: "last-fragment", +} + +var FragmentFlagValueMap = map[string]FragmentFlag{ + FragmentFlagNameMap[FRAG_FLAG_NOT]: FRAG_FLAG_NOT, + FragmentFlagNameMap[FRAG_FLAG_DONT]: FRAG_FLAG_DONT, + FragmentFlagNameMap[FRAG_FLAG_IS]: FRAG_FLAG_IS, + FragmentFlagNameMap[FRAG_FLAG_FIRST]: FRAG_FLAG_FIRST, + FragmentFlagNameMap[FRAG_FLAG_LAST]: FRAG_FLAG_LAST, +} + type DECNumOp int const ( |