@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);
  }
Пример #2
0
  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());
 }