/** * Push routes from back to front * * @param route Route to push * @param match OpenFlow fields to match on * @param srcSwPort Source switch port for the first hop * @param dstSwPort Destination switch port for final hop * @param cookie The cookie to set in each flow_mod * @param cntx The floodlight context * @param reqeustFlowRemovedNotifn if set to true then the switch would send a flow mod removal * notification when the flow mod expires * @param doFlush if set to true then the flow mod would be immediately written to the switch * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD, * OFFlowMod.OFPFC_MODIFY etc. * @return srcSwitchIincluded True if the source switch is included in this route */ @LogMessageDocs({ @LogMessageDoc( level = "WARN", message = "Unable to push route, switch at DPID {dpid} not available", explanation = "A switch along the calculated path for the " + "flow has disconnected.", recommendation = LogMessageDoc.CHECK_SWITCH), @LogMessageDoc( level = "ERROR", message = "Failure writing flow mod", explanation = "An I/O error occurred while writing a " + "flow modification to a switch", recommendation = LogMessageDoc.CHECK_SWITCH) }) public boolean pushRoute( Route route, OFMatch match, Integer wildcard_hints, OFPacketIn pi, long pinSwitch, long cookie, FloodlightContext cntx, boolean reqeustFlowRemovedNotifn, 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 - TODO generalize check if ((reqeustFlowRemovedNotifn) && (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) { // TODO: Instead of doing a packetOut here we could also // send a flowMod with bufferId set.... pushPacket(sw, pi, false, 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; }