@Test public void testStaticFlowPush() throws IOException { StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher(); IStorageSourceService storage = createStorageWithFlowEntries(); long dpid = HexString.toLong(TestSwitch1DPID); // Create a Switch and attach a switch IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class); Capture<OFMessage> writeCapture = new Capture<OFMessage>(CaptureType.ALL); Capture<ListenerContext> contextCapture = new Capture<ListenerContext>(CaptureType.ALL); Capture<List<OFMessage>> writeCaptureList = new Capture<List<OFMessage>>(CaptureType.ALL); // OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class); mockSwitch.write(capture(writeCapture), capture(contextCapture)); expectLastCall().anyTimes(); mockSwitch.write(capture(writeCaptureList), capture(contextCapture)); expectLastCall().anyTimes(); mockSwitch.flush(); expectLastCall().anyTimes(); staticFlowEntryPusher.setStorageSource(storage); ModuleContext fmc = new ModuleContext(); MockControllerProvider mockControllerProvider = getMockControllerProvider(); Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>(); switchMap.put(dpid, mockSwitch); // NO ! expect(mockControllerProvider.getSwitches()).andReturn(switchMap).anyTimes(); mockControllerProvider.setSwitches(switchMap); staticFlowEntryPusher.setControllerProvider(mockControllerProvider); RestApiServer restApi = new RestApiServer(); try { restApi.init(fmc); } catch (ModuleException e) { e.printStackTrace(); } staticFlowEntryPusher.restApi = restApi; staticFlowEntryPusher.startUp(null); // again, to hack unittest // verify that flowpusher read all three entries from storage assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries()); // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead // expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes(); // if someone calls getId(), return this dpid instead expect(mockSwitch.getId()).andReturn(dpid).anyTimes(); expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes(); replay(mockSwitch); // hook the static pusher up to the fake switch staticFlowEntryPusher.addedSwitch(mockSwitch); verify(mockSwitch); // Verify that the switch has gotten some flow_mods assertEquals(true, writeCapture.hasCaptured()); assertEquals(TotalTestRules, writeCapture.getValues().size()); // Order assumes how things are stored in hash bucket; // should be fixed because OFMessage.hashCode() is deterministic OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2); verifyFlowMod(firstFlowMod, FlowMod1); OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1); verifyFlowMod(secondFlowMod, FlowMod2); OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0); verifyFlowMod(thirdFlowMod, FlowMod3); writeCapture.reset(); contextCapture.reset(); // delete two rules and verify they've been removed // this should invoke staticFlowPusher.rowsDeleted() storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1"); storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2"); assertEquals(1, staticFlowEntryPusher.countEntries()); assertEquals(2, writeCapture.getValues().size()); OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0); FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(firstDelete, FlowMod1); OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1); FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(secondDelete, FlowMod2); // add rules back to make sure that staticFlowPusher.rowsInserted() works writeCapture.reset(); FlowMod2.setCommand(OFFlowMod.OFPFC_ADD); storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2); assertEquals(2, staticFlowEntryPusher.countEntries()); assertEquals(1, writeCaptureList.getValues().size()); List<OFMessage> outList = (List<OFMessage>) writeCaptureList.getValues().get(0); assertEquals(1, outList.size()); OFFlowMod firstAdd = (OFFlowMod) outList.get(0); verifyFlowMod(firstAdd, FlowMod2); writeCapture.reset(); contextCapture.reset(); writeCaptureList.reset(); // now try an overwriting update, calling staticFlowPusher.rowUpdated() TestRule3.put(COLUMN_DL_VLAN, 333); storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); assertEquals(2, staticFlowEntryPusher.countEntries()); assertEquals(1, writeCaptureList.getValues().size()); outList = (List<OFMessage>) writeCaptureList.getValues().get(0); assertEquals(2, outList.size()); OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0); FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(removeFlowMod, FlowMod3); FlowMod3.setCommand(OFFlowMod.OFPFC_ADD); FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333"); OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1); verifyFlowMod(updateFlowMod, FlowMod3); writeCaptureList.reset(); // now try an action modifying update, calling staticFlowPusher.rowUpdated() TestRule3.put(COLUMN_ACTIONS, "output=controller,strip-vlan"); // added strip-vlan storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); assertEquals(2, staticFlowEntryPusher.countEntries()); assertEquals(1, writeCaptureList.getValues().size()); outList = (List<OFMessage>) writeCaptureList.getValues().get(0); assertEquals(1, outList.size()); OFFlowMod modifyFlowMod = (OFFlowMod) outList.get(0); FlowMod3.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT); List<OFAction> modifiedActions = FlowMod3.getActions(); modifiedActions.add( new OFActionStripVirtualLan()); // add the new action to what we should expect FlowMod3.setActions(modifiedActions); FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 16); // accommodate the addition of new actions verifyFlowMod(modifyFlowMod, FlowMod3); }
public boolean pushRoute( Route route, OFMatch match, Integer wildcard_hints, OFPacketIn pi, long pinSwitch, long cookie, FloodlightContext cntx, boolean requestFlowRemovedNotifn, boolean doFlush, short flowModCommand) { boolean srcSwitchIncluded = false; OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); OFActionOutput action = new OFActionOutput(); action.setMaxLength((short) 0xffff); List<OFAction> actions = new ArrayList<OFAction>(); actions.add(action); fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(cookie) .setCommand(flowModCommand) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH); List<NodePortTuple> switchPortList = route.getPath(); for (int indx = switchPortList.size() - 1; indx > 0; indx -= 2) { // indx and indx-1 will always have the same switch DPID. long switchDPID = switchPortList.get(indx).getNodeId(); IOFSwitch sw = floodlightProvider.getSwitches().get(switchDPID); if (sw == null) { if (log.isWarnEnabled()) { log.warn("Unable to push route, switch at DPID {} " + "not available", switchDPID); } return srcSwitchIncluded; } // set the match. fm.setMatch(wildcard(match, sw, wildcard_hints)); // set buffer id if it is the source switch if (1 == indx) { // Set the flag to request flow-mod removal notifications only // for the // source switch. The removal message is used to maintain the // flow // cache. Don't set the flag for ARP messages if ((requestFlowRemovedNotifn) && (match.getDataLayerType() != Ethernet.TYPE_ARP)) { fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM); match.setWildcards(fm.getMatch().getWildcards()); } } short outPort = switchPortList.get(indx).getPortId(); short inPort = switchPortList.get(indx - 1).getPortId(); // set input and output ports on the switch fm.getMatch().setInputPort(inPort); ((OFActionOutput) fm.getActions().get(0)).setPort(outPort); try { counterStore.updatePktOutFMCounterStoreLocal(sw, fm); if (log.isTraceEnabled()) { log.trace( "Pushing Route flowmod routeIndx={} " + "sw={} inPort={} outPort={}", new Object[] {indx, sw, fm.getMatch().getInputPort(), outPort}); } messageDamper.write(sw, fm, cntx); if (doFlush) { sw.flush(); counterStore.updateFlush(); } // Push the packet out the source switch if (sw.getId() == pinSwitch) { pushPacket(sw, match, pi, outPort, cntx); srcSwitchIncluded = true; } } catch (IOException e) { log.error("Failure writing flow mod", e); } try { fm = fm.clone(); } catch (CloneNotSupportedException e) { log.error("Failure cloning flow mod", e); } } return srcSwitchIncluded; }
private void verifyMatch(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { assertEquals(goodFlowMod.getMatch(), testFlowMod.getMatch()); }