@LogMessageDoc( level = "ERROR", message = "Failure writing drop flow mod", explanation = "An I/O error occured while trying to write a " + "drop flow mod to a switch", recommendation = LogMessageDoc.CHECK_SWITCH) protected void doDropFlow( IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { // initialize match structure and populate it using the packet OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); if (decision.getWildcards() != null) { match.setWildcards(decision.getWildcards()); } // Create flow-mod based on packet-in and src-switch OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to // drop long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); fm.setCookie(cookie) .setHardTimeout((short) 0) .setIdleTimeout((short) 5) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH); try { if (log.isDebugEnabled()) { log.debug("write drop flow-mod sw={} match={} flow-mod={}", new Object[] {sw, match, fm}); } messageDamper.write(sw, fm, cntx); } catch (IOException e) { log.error("Failure writing drop flow mod", e); } }
protected void doForwardFlow( IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, boolean requestFlowRemovedNotifn) { OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); // Check if we have the location of the destination IDevice dstDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE); if (dstDevice != null) { IDevice srcDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); Long srcIsland = topology.getL2DomainId(sw.getId()); if (srcDevice == null) { log.debug("No device entry found for source device"); return; } if (srcIsland == null) { log.debug("No openflow island found for source {}/{}", sw.getStringId(), pi.getInPort()); return; } // Validate that we have a destination known on the same island // Validate that the source and destination are not on the same switchport boolean on_same_island = false; boolean on_same_if = false; for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { long dstSwDpid = dstDap.getSwitchDPID(); Long dstIsland = topology.getL2DomainId(dstSwDpid); if ((dstIsland != null) && dstIsland.equals(srcIsland)) { on_same_island = true; if ((sw.getId() == dstSwDpid) && (pi.getInPort() == dstDap.getPort())) { on_same_if = true; } break; } } if (!on_same_island) { // Flood since we don't know the dst device if (log.isTraceEnabled()) { log.trace( "No first hop island found for destination " + "device {}, Action = flooding", dstDevice); } doFlood(sw, pi, cntx); return; } if (on_same_if) { if (log.isTraceEnabled()) { log.trace( "Both source and destination are on the same " + "switch/port {}/{}, Action = NOP", sw.toString(), pi.getInPort()); } return; } // Install all the routes where both src and dst have attachment // points. Since the lists are stored in sorted order we can // traverse the attachment points in O(m+n) time SwitchPort[] srcDaps = srcDevice.getAttachmentPoints(); Arrays.sort(srcDaps, clusterIdComparator); SwitchPort[] dstDaps = dstDevice.getAttachmentPoints(); Arrays.sort(dstDaps, clusterIdComparator); int iSrcDaps = 0, iDstDaps = 0; while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { SwitchPort srcDap = srcDaps[iSrcDaps]; SwitchPort dstDap = dstDaps[iDstDaps]; Long srcCluster = topology.getL2DomainId(srcDap.getSwitchDPID()); Long dstCluster = topology.getL2DomainId(dstDap.getSwitchDPID()); int srcVsDest = srcCluster.compareTo(dstCluster); if (srcVsDest == 0) { if (!srcDap.equals(dstDap) && (srcCluster != null) && (dstCluster != null)) { Route route = routingEngine.getRoute( srcDap.getSwitchDPID(), (short) srcDap.getPort(), dstDap.getSwitchDPID(), (short) dstDap.getPort()); if (route != null) { if (log.isTraceEnabled()) { log.trace( "pushRoute match={} route={} " + "destination={}:{}", new Object[] {match, route, dstDap.getSwitchDPID(), dstDap.getPort()}); } long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); pushRoute( route, match, 0, pi, sw.getId(), cookie, cntx, requestFlowRemovedNotifn, false, OFFlowMod.OFPFC_ADD); } } iSrcDaps++; iDstDaps++; } else if (srcVsDest < 0) { iSrcDaps++; } else { iDstDaps++; } } } else { // Flood since we don't know the dst device doFlood(sw, pi, cntx); } }
static { AppCookie.registerApp(OFSwitch.OFSWITCH_APP_ID, "switch"); }
protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { // Setup fields for our packets OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); // Check if we have the location of the destination IDevice dstDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE); if (dstDevice != null) { IDevice srcDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); Long srcIsland = topology.getL2DomainId(sw.getId()); if (srcDevice == null) { log.debug("No device entry found for source device"); return; } if (srcIsland == null) { log.debug("No openflow island found for source {}/{}", sw.getStringId(), pi.getInPort()); return; } // Validate that we have a destination known on the same // island // Validate that the source and destination are not on // the same switchport boolean on_same_island = false; boolean on_same_if = false; for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { long dstSwDpid = dstDap.getSwitchDPID(); Long dstIsland = topology.getL2DomainId(dstSwDpid); if ((dstIsland != null) && dstIsland.equals(srcIsland)) { on_same_island = true; if ((sw.getId() == dstSwDpid) && (pi.getInPort() == dstDap.getPort())) { on_same_if = true; } break; } } if (!on_same_island) { // Flood since we don't know the dst device if (log.isTraceEnabled()) { log.trace( "No first hop island found for destination " + "device {}, Action = flooding", dstDevice); } doFlood(sw, pi, cntx); return; } if (on_same_if) { if (log.isTraceEnabled()) { log.trace( "Both source and destination are on the same " + "switch/port {}/{}, Action = NOP", sw.toString(), pi.getInPort()); } return; } // Install all the routes where both src and dst have // attachment // points. Since the lists are stored in sorted order we // can // traverse the attachment points in O(m+n) time SwitchPort[] srcDaps = srcDevice.getAttachmentPoints(); Arrays.sort(srcDaps, clusterIdComparator); SwitchPort[] dstDaps = dstDevice.getAttachmentPoints(); Arrays.sort(dstDaps, clusterIdComparator); int iSrcDaps = 0, iDstDaps = 0; while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { SwitchPort srcDap = srcDaps[iSrcDaps]; SwitchPort dstDap = dstDaps[iDstDaps]; Long srcCluster = topology.getL2DomainId(srcDap.getSwitchDPID()); Long dstCluster = topology.getL2DomainId(dstDap.getSwitchDPID()); int srcVsDest = srcCluster.compareTo(dstCluster); if (srcVsDest == 0) { if (!srcDap.equals(dstDap) && (srcCluster != null) && (dstCluster != null)) { // TODO: INSERT DIJKSTRA HERE FOR OUR VIDEO FLOWS // AND CALCULATE FLOWS // Call getroute also with weights!! Route route = getRoute( srcDap.getSwitchDPID(), (short) srcDap.getPort(), dstDap.getSwitchDPID(), (short) dstDap.getPort()); if (route != null) { if (log.isTraceEnabled()) { log.trace( "pushRoute match={} route={} " + "destination={}:{}", new Object[] {match, route, dstDap.getSwitchDPID(), dstDap.getPort()}); } long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); // if there is prior routing decision // use wildcard Integer wildcard_hints = null; IRoutingDecision decision = null; if (cntx != null) { decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); } if (decision != null) { wildcard_hints = decision.getWildcards(); } else { // L2 only wildcard if there is no // prior route decision wildcard_hints = ((Integer) sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue() & ~OFMatch.OFPFW_IN_PORT & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK; } pushRoute( route, match, wildcard_hints, pi, sw.getId(), cookie, cntx, false, false, OFFlowMod.OFPFC_ADD); } } iSrcDaps++; iDstDaps++; } else if (srcVsDest < 0) { iSrcDaps++; } else { iDstDaps++; } } } else { // Flood since we don't know the dst device doFlood(sw, pi, cntx); } }
/** * Abstract base class for implementing a forwarding module. Forwarding is responsible for * programming flows to a switch in response to a policy decision. */ @LogMessageCategory("Flow Programming") public abstract class ForwardingBase implements IOFMessageListener, IDeviceListener { protected static Logger log = LoggerFactory.getLogger(ForwardingBase.class); protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite protected IFloodlightProviderService floodlightProvider; protected IDeviceService deviceManager; protected IRoutingService routingEngine; protected ITopologyService topology; protected ICounterStoreService counterStore; protected OFMessageDamper messageDamper; // for broadcast loop suppression protected boolean broadcastCacheFeature = true; public final int prime1 = 2633; // for hash calculation public static final int prime2 = 4357; // for hash calculation public TimedCache<Long> broadcastCache = new TimedCache<Long>(100, 5 * 1000); // 5 seconds interval; // flow-mod - for use in the cookie public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed // by a global APP_ID class public long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); // Comparator for sorting by SwitchCluster public Comparator<SwitchPort> clusterIdComparator = new Comparator<SwitchPort>() { @Override public int compare(SwitchPort d1, SwitchPort d2) { Long d1ClusterId = topology.getL2DomainId(d1.getSwitchDPID()); Long d2ClusterId = topology.getL2DomainId(d2.getSwitchDPID()); return d1ClusterId.compareTo(d2ClusterId); } }; /** init data structures */ protected void init() { messageDamper = new OFMessageDamper( OFMESSAGE_DAMPER_CAPACITY, EnumSet.of(OFType.FLOW_MOD), OFMESSAGE_DAMPER_TIMEOUT); } /** Adds a listener for devicemanager and registers for PacketIns. */ protected void startUp() { deviceManager.addListener(this); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); } /** Returns the application name "forwarding". */ @Override public String getName() { return "forwarding"; } /** * All subclasses must define this function if they want any specific forwarding action * * @param sw Switch that the packet came in from * @param pi The packet that came in * @param decision Any decision made by a policy engine */ public abstract Command processPacketInMessage( IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx); @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: IRoutingDecision decision = null; if (cntx != null) decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx); default: break; } return Command.CONTINUE; } /** * 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; } protected OFMatch wildcard(OFMatch match, IOFSwitch sw, Integer wildcard_hints) { if (wildcard_hints != null) { return match.clone().setWildcards(wildcard_hints.intValue()); } return match.clone(); } /** * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we assume that the packetOut * switch is the same as the packetIn switch and we will use the bufferId. In this case the packet * can be null Caller needs to make sure that inPort and outPort differs * * @param packet packet data to send. * @param sw switch from which packet-out is sent * @param bufferId bufferId * @param inPort input port * @param outPort output port * @param cntx context of the packet * @param flush force to flush the packet. */ @LogMessageDocs({ @LogMessageDoc( level = "ERROR", message = "BufferId is not and packet data is null. " + "Cannot send packetOut. " + "srcSwitch={dpid} inPort={port} outPort={port}", explanation = "The switch send a malformed packet-in." + "The packet will be dropped", recommendation = LogMessageDoc.REPORT_SWITCH_BUG), @LogMessageDoc( level = "ERROR", message = "Failure writing packet out", explanation = "An I/O error occurred while writing a " + "packet out to a switch", recommendation = LogMessageDoc.CHECK_SWITCH) }) public void pushPacket( IPacket packet, IOFSwitch sw, int bufferId, short inPort, short outPort, FloodlightContext cntx, boolean flush) { if (log.isTraceEnabled()) { log.trace("PacketOut srcSwitch={} inPort={} outPort={}", new Object[] {sw, inPort, outPort}); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); // set actions List<OFAction> actions = new ArrayList<OFAction>(); actions.add(new OFActionOutput(outPort, (short) 0xffff)); po.setActions(actions).setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); // set buffer_id, in_port po.setBufferId(bufferId); po.setInPort(inPort); // set data - only if buffer_id == -1 if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { if (packet == null) { log.error( "BufferId is not set and packet data is null. " + "Cannot send packetOut. " + "srcSwitch={} inPort={} outPort={}", new Object[] {sw, inPort, outPort}); return; } byte[] packetData = packet.serialize(); poLength += packetData.length; po.setPacketData(packetData); } po.setLength(poLength); try { counterStore.updatePktOutFMCounterStoreLocal(sw, po); messageDamper.write(sw, po, cntx, flush); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * Pushes a packet-out to a switch. The assumption here is that the packet-in was also generated * from the same switch. Thus, if the input port of the packet-in and the outport are the same, * the function will not push the packet-out. * * @param sw switch that generated the packet-in, and from which packet-out is sent * @param pi packet-in * @param useBufferId if true, use the bufferId from the packet in and do not add the packetIn's * payload. If false set bufferId to BUFFER_ID_NONE and use the packetIn's payload * @param outport output port * @param cntx context of the packet */ protected void pushPacket( IOFSwitch sw, OFPacketIn pi, boolean useBufferId, short outport, FloodlightContext cntx) { if (pi == null) { return; } // The assumption here is (sw) is the switch that generated the // packet-in. If the input port is the same as output port, then // the packet-out should be ignored. if (pi.getInPort() == outport) { if (log.isDebugEnabled()) { log.debug( "Attempting to do packet-out to the same " + "interface as packet-in. Dropping packet. " + " SrcSwitch={}, pi={}", new Object[] {sw, pi}); return; } } if (log.isTraceEnabled()) { log.trace("PacketOut srcSwitch={} pi={}", new Object[] {sw, pi}); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); // set actions List<OFAction> actions = new ArrayList<OFAction>(); actions.add(new OFActionOutput(outport, (short) 0xffff)); po.setActions(actions).setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); if (useBufferId) { po.setBufferId(pi.getBufferId()); } else { po.setBufferId(OFPacketOut.BUFFER_ID_NONE); } if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { byte[] packetData = pi.getPacketData(); poLength += packetData.length; po.setPacketData(packetData); } po.setInPort(pi.getInPort()); po.setLength(poLength); try { counterStore.updatePktOutFMCounterStoreLocal(sw, po); messageDamper.write(sw, po, cntx); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * Write packetout message to sw with output actions to one or more output ports with * inPort/outPorts passed in. * * @param packetData * @param sw * @param inPort * @param ports * @param cntx */ public void packetOutMultiPort( byte[] packetData, IOFSwitch sw, short inPort, Set<Integer> outPorts, FloodlightContext cntx) { // setting actions List<OFAction> actions = new ArrayList<OFAction>(); Iterator<Integer> j = outPorts.iterator(); while (j.hasNext()) { actions.add(new OFActionOutput(j.next().shortValue(), (short) 0)); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); po.setActions(actions); po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * outPorts.size())); // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE po.setBufferId(OFPacketOut.BUFFER_ID_NONE); po.setInPort(inPort); // data (note buffer_id is always BUFFER_ID_NONE) and length short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); poLength += packetData.length; po.setPacketData(packetData); po.setLength(poLength); try { counterStore.updatePktOutFMCounterStoreLocal(sw, po); if (log.isTraceEnabled()) { log.trace( "write broadcast packet on switch-id={} " + "interfaces={} packet-out={}", new Object[] {sw.getId(), outPorts, po}); } messageDamper.write(sw, po, cntx); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * @see packetOutMultiPort Accepts a PacketIn instead of raw packet data. Note that the inPort and * switch can be different than the packet in switch/port */ public void packetOutMultiPort( OFPacketIn pi, IOFSwitch sw, short inPort, Set<Integer> outPorts, FloodlightContext cntx) { packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx); } /** * @see packetOutMultiPort Accepts an IPacket instead of raw packet data. Note that the inPort and * switch can be different than the packet in switch/port */ public void packetOutMultiPort( IPacket packet, IOFSwitch sw, short inPort, Set<Integer> outPorts, FloodlightContext cntx) { packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx); } protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { // Get the cluster id of the switch. // Get the hash of the Ethernet packet. if (sw == null) return true; // If the feature is disabled, always return false; if (!broadcastCacheFeature) return false; Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); Long broadcastHash; broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 + pi.getInPort() * prime2 + eth.hashCode(); if (broadcastCache.update(broadcastHash)) { sw.updateBroadcastCache(broadcastHash, pi.getInPort()); return true; } else { return false; } } protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { if (sw == null) return true; // If the feature is disabled, always return false; if (!broadcastCacheFeature) return false; // Get the hash of the Ethernet packet. Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); long hash = pi.getInPort() * prime2 + eth.hashCode(); // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac return sw.updateBroadcastCache(hash, pi.getInPort()); } @LogMessageDocs({ @LogMessageDoc( level = "ERROR", message = "Failure writing deny flow mod", explanation = "An I/O error occurred while writing a " + "deny flow mod to a switch", recommendation = LogMessageDoc.CHECK_SWITCH) }) public static boolean blockHost( IFloodlightProviderService floodlightProvider, SwitchPort sw_tup, long host_mac, short hardTimeout, long cookie) { if (sw_tup == null) { return false; } IOFSwitch sw = floodlightProvider.getSwitches().get(sw_tup.getSwitchDPID()); if (sw == null) return false; int inputPort = sw_tup.getPort(); log.debug( "blockHost sw={} port={} mac={}", new Object[] {sw, sw_tup.getPort(), new Long(host_mac)}); // Create flow-mod based on packet-in and src-switch OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); OFMatch match = new OFMatch(); List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to // drop match .setDataLayerSource(Ethernet.toByteArray(host_mac)) .setInputPort((short) inputPort) .setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_IN_PORT); fm.setCookie(cookie) .setHardTimeout(hardTimeout) .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH); try { log.debug("write drop flow-mod sw={} match={} flow-mod={}", new Object[] {sw, match, fm}); // TODO: can't use the message damper sine this method is static sw.write(fm, null); } catch (IOException e) { log.error("Failure writing deny flow mod", e); return false; } return true; } @Override public void deviceAdded(IDevice device) { // NOOP } @Override public void deviceRemoved(IDevice device) { // NOOP } @Override public void deviceMoved(IDevice device) {} @Override public void deviceIPV4AddrChanged(IDevice device) {} @Override public void deviceVlanChanged(IDevice device) {} @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return (type.equals(OFType.PACKET_IN) && (name.equals("topology") || name.equals("devicemanager"))); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } }