blob: 4f5334245d57553f796407d06379deffa74dc1c2 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.staticflowentry;
2
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08003
Jonathan Hart2fa28062013-11-25 20:16:28 -08004/*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08005public class StaticFlowTests extends FloodlightTestCase {
6
7 static String TestSwitch1DPID = "00:00:00:00:00:00:00:01";
8 static int TotalTestRules = 3;
9
Jonathan Hart2fa28062013-11-25 20:16:28 -080010 //
11 // Create TestRuleXXX and the corresponding FlowModXXX
12 // for X = 1..3
13 //
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080014 static Map<String,Object> TestRule1;
15 static OFFlowMod FlowMod1;
16 static {
17 FlowMod1 = new OFFlowMod();
18 TestRule1 = new HashMap<String,Object>();
19 TestRule1.put(COLUMN_NAME, "TestRule1");
20 TestRule1.put(COLUMN_SWITCH, TestSwitch1DPID);
21 // setup match
22 OFMatch match = new OFMatch();
23 TestRule1.put(COLUMN_DL_DST, "00:20:30:40:50:60");
24 match.fromString("dl_dst=00:20:30:40:50:60");
25 // setup actions
26 List<OFAction> actions = new LinkedList<OFAction>();
27 TestRule1.put(COLUMN_ACTIONS, "output=1");
28 actions.add(new OFActionOutput((short)1, (short) Short.MAX_VALUE));
29 // done
30 FlowMod1.setMatch(match);
31 FlowMod1.setActions(actions);
32 FlowMod1.setBufferId(-1);
33 FlowMod1.setOutPort(OFPort.OFPP_NONE.getValue());
34 FlowMod1.setPriority(Short.MAX_VALUE);
35 FlowMod1.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions
36 }
37
38 static Map<String,Object> TestRule2;
39 static OFFlowMod FlowMod2;
40
41 static {
42 FlowMod2 = new OFFlowMod();
43 TestRule2 = new HashMap<String,Object>();
44 TestRule2.put(COLUMN_NAME, "TestRule2");
45 TestRule2.put(COLUMN_SWITCH, TestSwitch1DPID);
46 // setup match
47 OFMatch match = new OFMatch();
48 TestRule2.put(COLUMN_NW_DST, "192.168.1.0/24");
49 match.fromString("nw_dst=192.168.1.0/24");
50 // setup actions
51 List<OFAction> actions = new LinkedList<OFAction>();
52 TestRule2.put(COLUMN_ACTIONS, "output=1");
53 actions.add(new OFActionOutput((short)1, (short) Short.MAX_VALUE));
54 // done
55 FlowMod2.setMatch(match);
56 FlowMod2.setActions(actions);
57 FlowMod2.setBufferId(-1);
58 FlowMod2.setOutPort(OFPort.OFPP_NONE.getValue());
59 FlowMod2.setPriority(Short.MAX_VALUE);
60 FlowMod2.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions
61
62 }
63
64
65 static Map<String,Object> TestRule3;
66 static OFFlowMod FlowMod3;
67 static {
68 FlowMod3 = new OFFlowMod();
69 TestRule3 = new HashMap<String,Object>();
70 TestRule3.put(COLUMN_NAME, "TestRule3");
71 TestRule3.put(COLUMN_SWITCH, TestSwitch1DPID);
72 // setup match
73 OFMatch match = new OFMatch();
74 TestRule3.put(COLUMN_DL_DST, "00:20:30:40:50:60");
75 TestRule3.put(COLUMN_DL_VLAN, 4096);
76 match.fromString("dl_dst=00:20:30:40:50:60,dl_vlan=4096");
77 // setup actions
78 TestRule3.put(COLUMN_ACTIONS, "output=controller");
79 List<OFAction> actions = new LinkedList<OFAction>();
80 actions.add(new OFActionOutput(OFPort.OFPP_CONTROLLER.getValue(), (short) Short.MAX_VALUE));
81 // done
82 FlowMod3.setMatch(match);
83 FlowMod3.setActions(actions);
84 FlowMod3.setBufferId(-1);
85 FlowMod3.setOutPort(OFPort.OFPP_NONE.getValue());
86 FlowMod3.setPriority(Short.MAX_VALUE);
87 FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions
88
89 }
90
91 private void verifyFlowMod(OFFlowMod testFlowMod,
92 OFFlowMod goodFlowMod) {
93 verifyMatch(testFlowMod, goodFlowMod);
94 verifyActions(testFlowMod, goodFlowMod);
95 // dont' bother testing the cookie; just copy it over
96 goodFlowMod.setCookie(testFlowMod.getCookie());
97 // .. so we can continue to use .equals()
98 assertEquals(goodFlowMod, testFlowMod);
99 }
100
101
102 private void verifyMatch(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) {
103 assertEquals(goodFlowMod.getMatch(), testFlowMod.getMatch());
104 }
105
106
107 private void verifyActions(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) {
108 List<OFAction> goodActions = goodFlowMod.getActions();
109 List<OFAction> testActions = testFlowMod.getActions();
110 assertNotNull(goodActions);
111 assertNotNull(testActions);
112 assertEquals(goodActions.size(), testActions.size());
113 // assumes actions are marshalled in same order; should be safe
114 for(int i = 0; i < goodActions.size(); i++) {
115 assertEquals(goodActions.get(i), testActions.get(i));
116 }
117
118 }
119
120
121 @Override
122 public void setUp() throws Exception {
123 super.setUp();
124 }
125
126 @Test
127 public void testStaticFlowPush() throws IOException {
128 StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher();
129 IStorageSourceService storage = createStorageWithFlowEntries();
130 long dpid = HexString.toLong(TestSwitch1DPID);
131
132 // Create a Switch and attach a switch
133 IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
134 Capture<OFMessage> writeCapture = new Capture<OFMessage>(CaptureType.ALL);
135 Capture<FloodlightContext> contextCapture = new Capture<FloodlightContext>(CaptureType.ALL);
136 Capture<List<OFMessage>> writeCaptureList = new Capture<List<OFMessage>>(CaptureType.ALL);
137
138 //OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class);
139 mockSwitch.write(capture(writeCapture), capture(contextCapture));
140 expectLastCall().anyTimes();
141 mockSwitch.write(capture(writeCaptureList), capture(contextCapture));
142 expectLastCall().anyTimes();
143 mockSwitch.flush();
144 expectLastCall().anyTimes();
145
146 staticFlowEntryPusher.setStorageSource(storage);
147
148 FloodlightModuleContext fmc = new FloodlightModuleContext();
149
150 MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider();
151 Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>();
152 switchMap.put(dpid, mockSwitch);
153 // NO ! expect(mockFloodlightProvider.getSwitches()).andReturn(switchMap).anyTimes();
154 mockFloodlightProvider.setSwitches(switchMap);
155 staticFlowEntryPusher.setFloodlightProvider(mockFloodlightProvider);
156 RestApiServer restApi = new RestApiServer();
157 try {
158 restApi.init(fmc);
159 } catch (FloodlightModuleException e) {
160 e.printStackTrace();
161 }
162 staticFlowEntryPusher.restApi = restApi;
163 staticFlowEntryPusher.startUp(null); // again, to hack unittest
164
165 // verify that flowpusher read all three entries from storage
166 assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries());
167
168 // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead
169 //expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes();
170
171 // if someone calls getId(), return this dpid instead
172 expect(mockSwitch.getId()).andReturn(dpid).anyTimes();
173 expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes();
174 replay(mockSwitch);
175
176 // hook the static pusher up to the fake switch
177 staticFlowEntryPusher.addedSwitch(mockSwitch);
178
179 verify(mockSwitch);
180
181 // Verify that the switch has gotten some flow_mods
182 assertEquals(true, writeCapture.hasCaptured());
183 assertEquals(TotalTestRules, writeCapture.getValues().size());
184
185 // Order assumes how things are stored in hash bucket;
186 // should be fixed because OFMessage.hashCode() is deterministic
187 OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2);
188 verifyFlowMod(firstFlowMod, FlowMod1);
189 OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1);
190 verifyFlowMod(secondFlowMod, FlowMod2);
191 OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0);
192 verifyFlowMod(thirdFlowMod, FlowMod3);
193
194 writeCapture.reset();
195 contextCapture.reset();
196
197
198 // delete two rules and verify they've been removed
199 // this should invoke staticFlowPusher.rowsDeleted()
200 storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1");
201 storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2");
202
203 assertEquals(1, staticFlowEntryPusher.countEntries());
204 assertEquals(2, writeCapture.getValues().size());
205
206 OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0);
207 FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
208 verifyFlowMod(firstDelete, FlowMod1);
209
210 OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1);
211 FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
212 verifyFlowMod(secondDelete, FlowMod2);
213
214 // add rules back to make sure that staticFlowPusher.rowsInserted() works
215 writeCapture.reset();
216 FlowMod2.setCommand(OFFlowMod.OFPFC_ADD);
217 storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2);
218 assertEquals(2, staticFlowEntryPusher.countEntries());
219 assertEquals(1, writeCaptureList.getValues().size());
220 List<OFMessage> outList =
221 (List<OFMessage>) writeCaptureList.getValues().get(0);
222 assertEquals(1, outList.size());
223 OFFlowMod firstAdd = (OFFlowMod) outList.get(0);
224 verifyFlowMod(firstAdd, FlowMod2);
225 writeCapture.reset();
226 contextCapture.reset();
227 writeCaptureList.reset();
228
229 // now try an update, calling staticFlowPusher.rowUpdated()
230 TestRule3.put(COLUMN_DL_VLAN, 333);
231 storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
232 assertEquals(2, staticFlowEntryPusher.countEntries());
233 assertEquals(1, writeCaptureList.getValues().size());
234
235 outList = (List<OFMessage>) writeCaptureList.getValues().get(0);
236 assertEquals(2, outList.size());
237 OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0);
238 FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
239 verifyFlowMod(removeFlowMod, FlowMod3);
240 FlowMod3.setCommand(OFFlowMod.OFPFC_ADD);
241 FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333");
242 OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1);
243 verifyFlowMod(updateFlowMod, FlowMod3);
244
245 }
246
247
248 IStorageSourceService createStorageWithFlowEntries() {
249 return populateStorageWithFlowEntries(new MemoryStorageSource());
250 }
251
252 IStorageSourceService populateStorageWithFlowEntries(IStorageSourceService storage) {
253 Set<String> indexedColumns = new HashSet<String>();
254 indexedColumns.add(COLUMN_NAME);
255 storage.createTable(StaticFlowEntryPusher.TABLE_NAME, indexedColumns);
256 storage.setTablePrimaryKeyName(StaticFlowEntryPusher.TABLE_NAME, COLUMN_NAME);
257
258 storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule1);
259 storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2);
260 storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3);
261
262 return storage;
263 }
264
265 @Test
266 public void testHARoleChanged() throws IOException {
267 StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher();
268 IStorageSourceService storage = createStorageWithFlowEntries();
269 MockFloodlightProvider mfp = getMockFloodlightProvider();
270 staticFlowEntryPusher.setFloodlightProvider(mfp);
271 staticFlowEntryPusher.setStorageSource(storage);
272 RestApiServer restApi = new RestApiServer();
273 try {
274 FloodlightModuleContext fmc = new FloodlightModuleContext();
275 restApi.init(fmc);
276 } catch (FloodlightModuleException e) {
277 e.printStackTrace();
278 }
279 staticFlowEntryPusher.restApi = restApi;
280 staticFlowEntryPusher.startUp(null); // again, to hack unittest
281
282 assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID));
283 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1));
284 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2));
285 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3));
286
287 // Send a notification that we've changed to slave
288 mfp.dispatchRoleChanged(null, Role.SLAVE);
289 // Make sure we've removed all our entries
290 assert(staticFlowEntryPusher.entry2dpid.isEmpty());
291 assert(staticFlowEntryPusher.entriesFromStorage.isEmpty());
292
293 // Send a notification that we've changed to master
294 mfp.dispatchRoleChanged(Role.SLAVE, Role.MASTER);
295 // Make sure we've learned the entries
296 assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID));
297 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1));
298 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2));
299 assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3));
300 }
301}
Jonathan Hart2fa28062013-11-25 20:16:28 -0800302*/