Skip to content

Commit cf8cd58

Browse files
author
Ravi Sankar Penta
committed
Fix fake ovs transaction to support ovs controller testing
1 parent adc05c8 commit cf8cd58

File tree

2 files changed

+159
-48
lines changed

2 files changed

+159
-48
lines changed

pkg/util/ovs/fake_ovs.go

+59-25
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,12 @@ func (fake *ovsFake) Clear(table, record string, columns ...string) error {
161161
}
162162

163163
type ovsFakeTx struct {
164-
fake *ovsFake
165-
err error
164+
fake *ovsFake
165+
flows []string
166166
}
167167

168168
func (fake *ovsFake) NewTransaction() Transaction {
169-
return &ovsFakeTx{fake: fake, err: fake.ensureExists()}
169+
return &ovsFakeTx{fake: fake, flows: []string{}}
170170
}
171171

172172
// sort.Interface support
@@ -200,51 +200,85 @@ func fixFlowFields(flow *OvsFlow) {
200200
}
201201

202202
func (tx *ovsFakeTx) AddFlow(flow string, args ...interface{}) {
203-
if tx.err != nil {
204-
return
203+
if len(args) > 0 {
204+
flow = fmt.Sprintf(flow, args...)
205205
}
206-
parsed, err := ParseFlow(ParseForAdd, flow, args...)
206+
tx.flows = append(tx.flows, fmt.Sprintf("add %s", flow))
207+
}
208+
209+
func (fake *ovsFake) addFlowHelper(flow string) error {
210+
parsed, err := ParseFlow(ParseForAdd, flow)
207211
if err != nil {
208-
tx.err = err
209-
return
212+
return err
210213
}
211214
fixFlowFields(parsed)
212215

213216
// If there is already an exact match for this flow, then the new flow replaces it.
214-
for i := range tx.fake.flows {
215-
if FlowMatches(&tx.fake.flows[i], parsed) {
216-
tx.fake.flows[i] = *parsed
217-
return
217+
for i := range fake.flows {
218+
if FlowMatches(&fake.flows[i], parsed) {
219+
fake.flows[i] = *parsed
220+
return nil
218221
}
219222
}
220223

221-
tx.fake.flows = append(tx.fake.flows, *parsed)
222-
sort.Sort(ovsFlows(tx.fake.flows))
224+
fake.flows = append(fake.flows, *parsed)
225+
sort.Sort(ovsFlows(fake.flows))
226+
return nil
223227
}
224228

225229
func (tx *ovsFakeTx) DeleteFlows(flow string, args ...interface{}) {
226-
if tx.err != nil {
227-
return
230+
if len(args) > 0 {
231+
flow = fmt.Sprintf(flow, args...)
228232
}
229-
parsed, err := ParseFlow(ParseForFilter, flow, args...)
233+
tx.flows = append(tx.flows, fmt.Sprintf("delete %s", flow))
234+
}
235+
236+
func (fake *ovsFake) deleteFlowsHelper(flow string) error {
237+
parsed, err := ParseFlow(ParseForFilter, flow)
230238
if err != nil {
231-
tx.err = err
232-
return
239+
return err
233240
}
234241
fixFlowFields(parsed)
235242

236-
newFlows := make([]OvsFlow, 0, len(tx.fake.flows))
237-
for _, flow := range tx.fake.flows {
243+
newFlows := make([]OvsFlow, 0, len(fake.flows))
244+
for _, flow := range fake.flows {
238245
if !FlowMatches(&flow, parsed) {
239246
newFlows = append(newFlows, flow)
240247
}
241248
}
242-
tx.fake.flows = newFlows
249+
fake.flows = newFlows
250+
return nil
243251
}
244252

245-
func (tx *ovsFakeTx) EndTransaction() error {
246-
err := tx.err
247-
tx.err = nil
253+
func (tx *ovsFakeTx) Commit() error {
254+
var err error
255+
if err = tx.fake.ensureExists(); err != nil {
256+
return err
257+
}
258+
259+
oldFlows := make(ovsFlows, len(tx.fake.flows))
260+
copy(oldFlows, tx.fake.flows)
261+
262+
for _, flow := range tx.flows {
263+
if strings.HasPrefix(flow, "add") {
264+
flow = strings.TrimLeft(flow, "add")
265+
err = tx.fake.addFlowHelper(flow)
266+
} else if strings.HasPrefix(flow, "delete") {
267+
flow = strings.TrimLeft(flow, "delete")
268+
err = tx.fake.deleteFlowsHelper(flow)
269+
} else {
270+
err = fmt.Errorf("invalid flow %q", flow)
271+
}
272+
if err != nil {
273+
// Transaction failed, restore to old state
274+
tx.fake.flows = oldFlows
275+
break
276+
}
277+
}
278+
279+
// Reset flows
280+
tx.flows = []string{}
281+
248282
return err
249283
}
250284

pkg/util/ovs/fake_ovs_test.go

+100-23
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ import (
99
func TestFakePorts(t *testing.T) {
1010
ovsif := NewFake("br0")
1111

12-
_, err := ovsif.AddPort("tun0", 1)
13-
if err == nil {
12+
if _, err := ovsif.AddPort("tun0", 1); err == nil {
1413
t.Fatalf("unexpected lack of error adding port on non-existent bridge")
1514
}
1615

17-
err = ovsif.AddBridge()
18-
if err != nil {
16+
if err := ovsif.AddBridge(); err != nil {
1917
t.Fatalf("unexpected error adding bridge: %v", err)
2018
}
2119
ofport, err := ovsif.AddPort("tun0", 17)
@@ -29,20 +27,105 @@ func TestFakePorts(t *testing.T) {
2927
if ofport != 17 {
3028
t.Fatalf("unexpected ofport %d returned from GetOFPort", ofport)
3129
}
32-
err = ovsif.DeletePort("tun0")
33-
if err != nil {
30+
if err = ovsif.DeletePort("tun0"); err != nil {
3431
t.Fatalf("unexpected error deleting port: %v", err)
3532
}
36-
_, err = ovsif.GetOFPort("tun0")
37-
if err == nil {
33+
if _, err = ovsif.GetOFPort("tun0"); err == nil {
3834
t.Fatalf("unexpected lack of error getting non-existent port")
3935
}
4036
}
4137

38+
func TestTransaction(t *testing.T) {
39+
ovsif := NewFake("br0")
40+
if err := ovsif.AddBridge(); err != nil {
41+
t.Fatalf("unexpected error adding bridge: %v", err)
42+
}
43+
44+
// Empty transaction
45+
otx := ovsif.NewTransaction()
46+
if err := otx.Commit(); err != nil {
47+
t.Fatalf("unexpected error: %v", err)
48+
}
49+
if err := checkDump(ovsif, "", []string{}); err != nil {
50+
t.Fatalf(err.Error())
51+
}
52+
53+
// Add flows transaction
54+
otx.AddFlow("table=100, priority=100, reg0=1, actions=one")
55+
otx.AddFlow("table=100, priority=200, reg0=2, cookie=1, actions=two")
56+
if err := otx.Commit(); err != nil {
57+
t.Fatalf("unexpected error: %v", err)
58+
}
59+
expectedFlows := []string{
60+
" cookie=1, table=100, priority=200, reg0=2, actions=two",
61+
" cookie=0, table=100, priority=100, reg0=1, actions=one",
62+
}
63+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
64+
t.Fatalf(err.Error())
65+
}
66+
67+
// Add flows failed transaction, invalid action
68+
otx.AddFlow("table=100, priority=300, reg0=3, actions=three")
69+
otx.AddFlow("table=100, priority=400, reg0=2, actions")
70+
if err := otx.Commit(); err == nil {
71+
t.Fatalf("expected no error but got %v", err)
72+
}
73+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
74+
t.Fatalf(err.Error())
75+
}
76+
77+
// Delete flows transaction
78+
otx.DeleteFlows("table=100, reg0=1")
79+
if err := otx.Commit(); err != nil {
80+
t.Fatalf("unexpected error: %v", err)
81+
}
82+
expectedFlows = []string{
83+
" cookie=1, table=100, priority=200, reg0=2, actions=two",
84+
}
85+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
86+
t.Fatalf(err.Error())
87+
}
88+
89+
// Delete flows failed transaction, invalid cookie(missing mask)
90+
otx.DeleteFlows("table=100, cookie=1")
91+
if err := otx.Commit(); err == nil {
92+
t.Fatalf("expected no error but got %v", err)
93+
}
94+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
95+
t.Fatalf(err.Error())
96+
}
97+
98+
// Add and Delete flows transaction
99+
otx.AddFlow("table=100, priority=300, reg0=3, actions=three")
100+
otx.AddFlow("table=101, priority=100, reg0=1, actions=one")
101+
otx.DeleteFlows("table=100")
102+
otx.AddFlow("table=101, priority=200, reg0=2, actions=two")
103+
if err := otx.Commit(); err != nil {
104+
t.Fatalf("unexpected error: %v", err)
105+
}
106+
expectedFlows = []string{
107+
" cookie=0, table=101, priority=200, reg0=2, actions=two",
108+
" cookie=0, table=101, priority=100, reg0=1, actions=one",
109+
}
110+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
111+
t.Fatalf(err.Error())
112+
}
113+
114+
// Add and Delete flows failed transaction, missing action
115+
otx.AddFlow("table=101, priority=300, reg0=3, actions=three")
116+
otx.DeleteFlows("table=101")
117+
otx.AddFlow("table=101, priority=400, reg0=4, actions")
118+
if err := otx.Commit(); err == nil {
119+
t.Fatalf("expected no error but got %v", err)
120+
}
121+
if err := checkDump(ovsif, "", expectedFlows); err != nil {
122+
t.Fatalf(err.Error())
123+
}
124+
}
125+
42126
func TestFind(t *testing.T) {
43127
ovsif := NewFake("br0")
44-
err := ovsif.AddBridge()
45-
if err != nil {
128+
if err := ovsif.AddBridge(); err != nil {
46129
t.Fatalf("unexpected error adding bridge: %v", err)
47130
}
48131

@@ -114,8 +197,7 @@ func checkDump(ovsif Interface, filter string, cmpFlows []string) error {
114197

115198
func TestFakeDumpFlows(t *testing.T) {
116199
ovsif := NewFake("br0")
117-
err := ovsif.AddBridge()
118-
if err != nil {
200+
if err := ovsif.AddBridge(); err != nil {
119201
t.Fatalf("unexpected error adding bridge: %v", err)
120202
}
121203

@@ -165,13 +247,12 @@ func TestFakeDumpFlows(t *testing.T) {
165247
otx.AddFlow("table=30, priority=300, ip, nw_dst=%s, actions=output:2", localSubnetGateway)
166248
otx.AddFlow("table=35, priority=300, ip, nw_dst=%s, actions=ct(commit,exec(set_field:1->ct_mark),table=70)", localSubnetGateway)
167249

168-
err = otx.Commit()
169-
if err != nil {
250+
if err := otx.Commit(); err != nil {
170251
t.Fatalf("unexpected error from AddFlow: %v", err)
171252
}
172253

173254
// fake DumpFlows sorts first by table, then by priority (decreasing), then by creation time
174-
err = checkDump(ovsif, "", []string{
255+
err := checkDump(ovsif, "", []string{
175256
" cookie=0, table=0, priority=250, in_port=2, ip, nw_dst=224.0.0.0/4, actions=drop",
176257
" cookie=0, table=0, priority=200, in_port=2, ip, actions=goto_table:30",
177258
" cookie=0, table=0, priority=200, in_port=1, ip, nw_src=10.128.0.0/14, nw_dst=10.129.0.0/23, actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10",
@@ -270,8 +351,7 @@ func matchActions(flows []string, actions ...string) bool {
270351

271352
func TestFlowMatchesMasked(t *testing.T) {
272353
ovsif := NewFake("br0")
273-
err := ovsif.AddBridge()
274-
if err != nil {
354+
if err := ovsif.AddBridge(); err != nil {
275355
t.Fatalf("unexpected error adding bridge: %v", err)
276356
}
277357

@@ -280,8 +360,7 @@ func TestFlowMatchesMasked(t *testing.T) {
280360
otx.AddFlow("table=100, priority=200, reg0=2, actions=two")
281361
otx.AddFlow("table=100, priority=300, reg0=3, cookie=1, actions=three")
282362
otx.AddFlow("table=100, priority=400, reg0=4, cookie=0xe, actions=four")
283-
err = otx.Commit()
284-
if err != nil {
363+
if err := otx.Commit(); err != nil {
285364
t.Fatalf("unexpected error from AddFlow: %v", err)
286365
}
287366
flows, err := ovsif.DumpFlows("")
@@ -294,8 +373,7 @@ func TestFlowMatchesMasked(t *testing.T) {
294373

295374
otx = ovsif.NewTransaction()
296375
otx.DeleteFlows("table=100, cookie=0/0xFFFF")
297-
err = otx.Commit()
298-
if err != nil {
376+
if err = otx.Commit(); err != nil {
299377
t.Fatalf("unexpected error from AddFlow: %v", err)
300378
}
301379
flows, err = ovsif.DumpFlows("")
@@ -308,8 +386,7 @@ func TestFlowMatchesMasked(t *testing.T) {
308386

309387
otx = ovsif.NewTransaction()
310388
otx.DeleteFlows("table=100, cookie=2/2")
311-
err = otx.Commit()
312-
if err != nil {
389+
if err = otx.Commit(); err != nil {
313390
t.Fatalf("unexpected error from AddFlow: %v", err)
314391
}
315392
flows, err = ovsif.DumpFlows("")

0 commit comments

Comments
 (0)