Skip to content

Commit 3f51df4

Browse files
committed
feat: support set flowid range in allocator
1 parent 6c489f8 commit 3f51df4

File tree

4 files changed

+183
-40
lines changed

4 files changed

+183
-40
lines changed

ofctrl/cookie/allocator.go

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cookie
22

33
import (
4+
"fmt"
45
"sync"
56
)
67

@@ -10,8 +11,11 @@ const (
1011
BitWidthFlowId = 64 - BitWidthReserved - BitWidthRoundNum
1112
RoundNumMask uint64 = 0x0000_0000_f000_0000
1213
FlowIdMask uint64 = 0x0000_0000_0fff_ffff
14+
InitFlowID uint64 = 1
1315
)
1416

17+
var FlowIDExhausted error = fmt.Errorf("flow id has exhausted")
18+
1519
type ID uint64
1620

1721
func newId(round uint64, flowId uint64) ID {
@@ -31,37 +35,82 @@ func (i ID) Round() uint64 {
3135
}
3236

3337
type Allocator interface {
34-
RequestCookie() uint64
38+
RequestCookie() (uint64, error)
3539
SetFixedMask(uint64)
3640
}
3741

42+
type AllocatorOption func(*allocator) error
43+
3844
type allocator struct {
3945
roundNum uint64
4046
flowID uint64
4147
fixedMask uint64
4248
flowIDLock sync.RWMutex
49+
maxFlowID uint64
4350
}
4451

4552
// cookie will 'OR' fixed mask
4653
func (a *allocator) SetFixedMask(mask uint64) {
4754
a.fixedMask = mask
4855
}
4956

50-
func (a *allocator) RequestCookie() uint64 {
57+
func (a *allocator) RequestCookie() (uint64, error) {
5158
a.flowIDLock.Lock()
5259
defer a.flowIDLock.Unlock()
5360

61+
if a.maxFlowID != 0 && a.flowID > a.maxFlowID {
62+
return 0, FlowIDExhausted
63+
}
5464
rawID := newId(a.roundNum, a.flowID).RawId()
5565
a.flowID += 1
56-
return rawID | a.fixedMask
66+
return rawID | a.fixedMask, nil
5767
}
5868

59-
func NewAllocator(roundNum uint64) Allocator {
69+
func (a *allocator) setFlowIDRange(start, end uint64) error {
70+
if start > end {
71+
return fmt.Errorf("param error, start %x can't bigger than end %x", start, end)
72+
}
73+
maxFlowIDOrigin := uint64(1<<BitWidthFlowId - 1)
74+
if start < InitFlowID {
75+
return fmt.Errorf("start %x can't small than minFlowID %x", start, InitFlowID)
76+
}
77+
if end > maxFlowIDOrigin {
78+
return fmt.Errorf("end %x can't biggger than maxFlowID %x", end, maxFlowIDOrigin)
79+
}
80+
a.flowID = start
81+
a.maxFlowID = end
82+
return nil
83+
}
84+
85+
func (a *allocator) setDefaultFlowIDRange() {
86+
a.flowID = InitFlowID
87+
a.maxFlowID = uint64(1<<BitWidthFlowId - 1)
88+
}
89+
90+
func SetFlowIDRange(start, end uint64) AllocatorOption {
91+
return func(a *allocator) error {
92+
return a.setFlowIDRange(start, end)
93+
}
94+
}
95+
96+
func SetDefaultFlowIDRange() AllocatorOption {
97+
return func(a *allocator) error {
98+
a.setDefaultFlowIDRange()
99+
return nil
100+
}
101+
}
102+
103+
func NewAllocator(roundNum uint64, options ...AllocatorOption) Allocator {
60104
a := &allocator{
61105
roundNum: roundNum,
62-
flowID: 1,
106+
flowID: InitFlowID,
63107
flowIDLock: sync.RWMutex{},
64108
}
109+
for _, o := range options {
110+
if err := o(a); err != nil {
111+
return nil
112+
}
113+
}
65114
return a
66115
}
67116

ofctrl/cookie/allocator_test.go

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,105 @@ import (
77
func TestAllocateCookie(t *testing.T) {
88
allocator := NewAllocator(0)
99

10-
cookie := allocator.RequestCookie()
10+
cookie, err := allocator.RequestCookie()
11+
if err != nil {
12+
t.Errorf("unexpectd return err %s", err)
13+
}
1114
if cookie != 0x1 {
1215
t.Errorf("request cookie fail, expect 0x1, got %x", cookie)
1316
}
1417

15-
cookie = allocator.RequestCookie()
18+
cookie, err = allocator.RequestCookie()
19+
if err != nil {
20+
t.Errorf("unexpectd return err %s", err)
21+
}
1622
if cookie != 0x2 {
1723
t.Errorf("request cookie fail, expect 0x2, got %x", cookie)
1824
}
1925

2026
allocator.SetFixedMask(0x10)
2127

22-
cookie = allocator.RequestCookie()
28+
cookie, err = allocator.RequestCookie()
29+
if err != nil {
30+
t.Errorf("unexpectd return err %s", err)
31+
}
2332
if cookie != 0x13 {
2433
t.Errorf("request cookie fail, expect 0x13, got %x", cookie)
2534
}
2635

2736
allocator = NewAllocator(1)
2837

29-
cookie = allocator.RequestCookie()
38+
cookie, err = allocator.RequestCookie()
39+
if err != nil {
40+
t.Errorf("unexpectd return err %s", err)
41+
}
3042
if cookie != 0x10000001 {
3143
t.Errorf("request cookie fail, expect 0x10000001, got %x", cookie)
3244
}
3345

34-
cookie = allocator.RequestCookie()
46+
cookie, err = allocator.RequestCookie()
47+
if err != nil {
48+
t.Errorf("unexpectd return err %s", err)
49+
}
3550
if cookie != 0x10000002 {
3651
t.Errorf("request cookie fail, expect 0x10000002, got %x", cookie)
3752
}
3853

3954
allocator.SetFixedMask(0x100000000)
4055

41-
cookie = allocator.RequestCookie()
56+
cookie, err = allocator.RequestCookie()
57+
if err != nil {
58+
t.Errorf("unexpectd return err %s", err)
59+
}
4260
if cookie != 0x110000003 {
4361
t.Errorf("request cookie fail, expect 0x110000003, got %x", cookie)
4462
}
63+
64+
allocator = NewAllocator(1, SetFlowIDRange(10, 9))
65+
if allocator != nil {
66+
t.Errorf("expect allocator is nil, but real is not")
67+
}
68+
69+
allocator = NewAllocator(1, SetFlowIDRange(0, 9))
70+
if allocator != nil {
71+
t.Errorf("expect allocator is nil, but real is not")
72+
}
73+
74+
allocator = NewAllocator(1, SetFlowIDRange(10, 1<<BitWidthFlowId))
75+
if allocator != nil {
76+
t.Errorf("expect allocator is nil, but real is not")
77+
}
78+
79+
allocator = NewAllocator(1, SetFlowIDRange(10, 11))
80+
81+
cookie, err = allocator.RequestCookie()
82+
if err != nil {
83+
t.Errorf("unexpectd return err %s", err)
84+
}
85+
if cookie != 0x1000000a {
86+
t.Errorf("request cookie fail, expect 0x1000000a , got %x", cookie)
87+
}
88+
cookie, err = allocator.RequestCookie()
89+
if err != nil {
90+
t.Errorf("unexpectd return err %s", err)
91+
}
92+
if cookie != 0x1000000b {
93+
t.Errorf("request cookie fail, expect 0x1000000b, got %x", cookie)
94+
}
95+
cookie, err = allocator.RequestCookie()
96+
if err == nil {
97+
t.Errorf("expect allocate cookie failed, but success")
98+
}
99+
100+
allocator = NewAllocator(1, SetDefaultFlowIDRange())
101+
if allocator == nil {
102+
t.Errorf("new allocator failed, is unexpected")
103+
}
104+
cookie, err = allocator.RequestCookie()
105+
if err != nil {
106+
t.Errorf("unexpectd return err %s", err)
107+
}
108+
if cookie != 0x10000001 {
109+
t.Errorf("request cookie fail, expect 0x10000001, got %x", cookie)
110+
}
45111
}

ofctrl/fgraphTable.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,35 @@ var globalFlowID uint64 = 1
4646

4747
// Create a new flow on the table
4848
func (self *Table) NewFlow(match FlowMatch) (*Flow, error) {
49-
flow := new(Flow)
50-
flow.Table = self
51-
flow.Match = match
52-
flow.isInstalled = false
5349
if self.Switch == nil {
5450
return nil, dperror.NewDpError(dperror.SwitchDisconnectedError.Code, dperror.SwitchDisconnectedError.Msg, fmt.Errorf("ofSwitch disconnected"))
5551
}
52+
53+
var flowID uint64
5654
if self.Switch.CookieAllocator != nil {
57-
flow.FlowID = self.Switch.CookieAllocator.RequestCookie()
55+
var err error
56+
flowID, err = self.Switch.CookieAllocator.RequestCookie()
57+
if err != nil {
58+
return nil, err
59+
}
5860
} else {
59-
flow.FlowID = globalFlowID // FIXME: need a better id allocation
61+
flowID = globalFlowID // FIXME: need a better id allocation
6062
globalFlowID += 1
6163
}
64+
65+
return self.NewFlowWithFlowID(match, flowID)
66+
}
67+
68+
func (self *Table) NewFlowWithFlowID(match FlowMatch, flowID uint64) (*Flow, error) {
69+
if self.Switch == nil {
70+
return nil, dperror.NewDpError(dperror.SwitchDisconnectedError.Code, dperror.SwitchDisconnectedError.Msg, fmt.Errorf("ofSwitch disconnected"))
71+
}
72+
flow := new(Flow)
73+
flow.Table = self
74+
flow.Match = match
75+
flow.isInstalled = false
76+
77+
flow.FlowID = flowID
6278
flow.flowActions = make([]Action, 0)
6379

6480
log.Debugf("Creating new flow for match: %+v", match)

ofctrl/ofctrl_test.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ func ofctlFlowMatch(flowList []string, tableId int, matchStr, actStr string) boo
127127
return false
128128
}
129129

130+
func ofctlFlowMatchCookieID(flowList []string, cookieID uint64) bool {
131+
mStr := fmt.Sprintf("cookie=%#x", cookieID)
132+
for _, flowEntry := range flowList {
133+
if strings.Contains(flowEntry, mStr) {
134+
return true
135+
}
136+
}
137+
return false
138+
}
139+
130140
// ofctlDumpFlowMatch dumps flows and finds a match
131141
func ofctlDumpFlowMatch(brName string, tableId int, matchStr, actStr string) bool {
132142
// dump flows
@@ -292,6 +302,21 @@ func TestCreateDeleteFlow(t *testing.T) {
292302
t.Errorf("Error installing the tcp flow")
293303
}
294304

305+
// newflow with flowid
306+
idFlow, err := ofActor.inputTable.NewFlowWithFlowID(FlowMatch{
307+
Priority: 100,
308+
Ethertype: 0x0800,
309+
IpProto: 6,
310+
TcpDstPort: 8080,
311+
}, 0x80)
312+
if err != nil {
313+
t.Errorf("Error creating flow with flowid")
314+
}
315+
log.Infof("Creating id flow: %+v", idFlow)
316+
if err := idFlow.Next(output); err != nil {
317+
t.Errorf("Error installing the id flow")
318+
}
319+
295320
// verify it got installed
296321
flowList, err := ofctlFlowDump("ovsbr11")
297322
if err != nil {
@@ -323,6 +348,10 @@ func TestCreateDeleteFlow(t *testing.T) {
323348
t.Errorf("IP flow not found in OVS.")
324349
}
325350

351+
if !ofctlFlowMatchCookieID(flowList, 0x80) {
352+
t.Errorf("fix cookieID flow not found in OVS.")
353+
}
354+
326355
// Delete the flow
327356
err = inPortFlow.Delete()
328357
if err != nil {
@@ -347,34 +376,17 @@ func TestCreateDeleteFlow(t *testing.T) {
347376
t.Errorf("Error deleting the tcp flow. Err: %v", err)
348377
}
349378

379+
if err = idFlow.Delete(); err != nil {
380+
t.Errorf("Error deleting the id flow. Err: %v", err)
381+
}
382+
350383
// Make sure they are really gone
351384
flowList, err = ofctlFlowDump("ovsbr11")
352385
if err != nil {
353386
t.Errorf("Error getting flow entry")
354387
}
355-
356-
// Match inport flow and see if its still there..
357-
if ofctlFlowMatch(flowList, 0, "priority=100,in_port=1",
358-
"push_vlan:0x8100,set_field:4097->vlan_vid,goto_table:1") {
359-
t.Errorf("in port flow still found in OVS after deleting it.")
360-
}
361-
362-
// match ip flow
363-
if ofctlFlowMatch(flowList, 1, "priority=100,ip,nw_dst=10.10.10.10",
364-
"output:1") {
365-
t.Errorf("IP flow not found in OVS.")
366-
}
367-
368-
// match mac flow
369-
if ofctlFlowMatch(flowList, 1, "priority=100,dl_vlan=1,dl_dst=02:01:01:01:01:01",
370-
"pop_vlan,output:1") {
371-
t.Errorf("Mac flow not found in OVS.")
372-
}
373-
374-
// match tcp flow
375-
if ofctlFlowMatch(flowList, 1, "priority=100,tcp,tp_dst=80,tcp_flags=+syn",
376-
"output:1") {
377-
t.Errorf("IP flow not found in OVS.")
388+
if len(flowList) != 0 {
389+
t.Errorf("doesn't delete all flow: %s", flowList)
378390
}
379391
}
380392

0 commit comments

Comments
 (0)