summaryrefslogtreecommitdiffhomepage
path: root/packet
diff options
context:
space:
mode:
authorSatoshi Fujimoto <satoshi.fujimoto7@gmail.com>2017-06-19 16:32:38 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-07-10 15:39:14 +0900
commit4b5e13376c70481aacc1c2c508738279f8cc9e5c (patch)
treeeb653f3d42af5e31dc90c186834a49384f8dfd0f /packet
parent15cd58e01f47357be5280ef6aa0775f42b811854 (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.go85
-rw-r--r--packet/bgp/bgp_test.go13
-rw-r--r--packet/bgp/constant.go26
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 (