diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java index 4ecc605c40e359ea828e3d380d2b18b9cc1886b6..1b2f2c6076b30f5e6824b39b33aa47552378a54d 100644 --- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java +++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java @@ -66,6 +66,7 @@ import net.floodlightcontroller.routing.RoutingDecision; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.StorageException; +import net.floodlightcontroller.util.OFMessageUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,10 +87,10 @@ IFloodlightModule { static { AppCookie.registerApp(APP_ID, "Firewall"); } - private static final U64 DENY_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0xaaaaaaaa); - private static final U64 ALLOW_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0x55555555); - private static final U64 RULE_MISS_COOKIE = AppCookie.makeCookie(APP_ID, -1); - static final U64 DEFAULT_COOKIE = AppCookie.makeCookie(APP_ID, 0); + private static final U64 DENY_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0xaaaaaaL); + private static final U64 ALLOW_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0x555555L); + private static final U64 RULE_MISS_COOKIE = AppCookie.makeCookie(APP_ID, 0xffffffL); + static final U64 DEFAULT_COOKIE = AppCookie.makeCookie(APP_ID, 0xffffffL); // service modules needed protected IFloodlightProviderService floodlightProvider; @@ -592,7 +593,7 @@ IFloodlightModule { public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)); + OFPort inPort = OFMessageUtils.getInPort(pi); // Allowing L2 broadcast + ARP broadcast request (also deny malformed // broadcasts -> L2 broadcast + L3 unicast) diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java index 5cb01303b1ab62e8b832c9f7e96cc46616ed1714..78c3272f002eee797285b658a5ee00e3a605e130 100644 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java @@ -21,9 +21,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; @@ -92,11 +94,133 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Forwarding extends ForwardingBase implements IFloodlightModule, IOFSwitchListener, ILinkDiscoveryListener, IRoutingDecisionChangedListener { - protected static Logger log = LoggerFactory.getLogger(Forwarding.class); - final static U64 DEFAULT_FORWARDING_COOKIE = AppCookie.makeCookie(FORWARDING_APP_ID, 0); + protected static final Logger log = LoggerFactory.getLogger(Forwarding.class); - // This mask determines how much of each cookie will contain IRoutingDecision descriptor bits. - private final long DECISION_MASK = 0x00000000ffffffffL; // TODO: shrink this mask if you need to add more sub-fields. + /* + * Cookies are 64 bits: + * Example: 0x0123456789ABCDEF + * App ID: 0xFFF0000000000000 + * User: 0x000FFFFFFFFFFFFF + * + * Of the user portion, we further subdivide into routing decision + * bits and flowset bits. The former relates the flow to routing + * decisions, such as firewall allow or deny/drop. It allows for + * modification of the flows upon a future change in the routing + * decision. The latter indicates a "family" of flows or "flowset" + * used to complete an end-to-end connection between two devices + * or hosts in the network. It is used to assist in the entire + * flowset removal upon a link or port down event anywhere along + * the path. This is required in order to allow a new path to be + * used and a new flowset installed. + * + * TODO: shrink these masks if you need to add more subfields + * or need to allow for a larger number of routing decisions + * or flowsets + */ + + private static final short DECISION_BITS = 24; + private static final short DECISION_SHIFT = 0; + private static final long DECISION_MASK = ((1L << DECISION_BITS) - 1) << DECISION_SHIFT; + + private static final short FLOWSET_BITS = 28; + protected static final short FLOWSET_SHIFT = DECISION_BITS; + private static final long FLOWSET_MASK = ((1L << FLOWSET_BITS) - 1) << FLOWSET_SHIFT; + private static final long FLOWSET_MAX = (long) (Math.pow(2, FLOWSET_BITS) - 1); + protected static FlowSetIdRegistry flowSetIdRegistry; + + protected static class FlowSetIdRegistry { + private volatile Map<NodePortTuple, Set<U64>> nptToFlowSetIds; + private volatile Map<U64, Set<NodePortTuple>> flowSetIdToNpts; + + private volatile long flowSetGenerator = -1; + + private static volatile FlowSetIdRegistry instance; + + private FlowSetIdRegistry() { + nptToFlowSetIds = new ConcurrentHashMap<NodePortTuple, Set<U64>>(); + flowSetIdToNpts = new ConcurrentHashMap<U64, Set<NodePortTuple>>(); + } + + protected static FlowSetIdRegistry getInstance() { + if (instance == null) { + instance = new FlowSetIdRegistry(); + } + return instance; + } + + /** + * Only for use by unit test to help w/ordering + * @param seed + */ + protected void seedFlowSetIdForUnitTest(int seed) { + flowSetGenerator = seed; + } + + protected synchronized U64 generateFlowSetId() { + flowSetGenerator += 1; + if (flowSetGenerator == FLOWSET_MAX) { + flowSetGenerator = 0; + log.warn("Flowset IDs have exceeded capacity of {}. Flowset ID generator resetting back to 0", FLOWSET_MAX); + } + U64 id = U64.of(flowSetGenerator << FLOWSET_SHIFT); + log.warn("Generating flowset ID {}, shifted {}", flowSetGenerator, id.toString()); + return id; + } + + private void registerFlowSetId(NodePortTuple npt, U64 flowSetId) { + if (nptToFlowSetIds.containsKey(npt)) { + Set<U64> ids = nptToFlowSetIds.get(npt); + if (ids == null) { + ids = new HashSet<U64>(); + } + ids.add(flowSetId); + } else { + Set<U64> ids = new HashSet<U64>(); + ids.add(flowSetId); + nptToFlowSetIds.put(npt, ids); + } + + if (flowSetIdToNpts.containsKey(flowSetId)) { + Set<NodePortTuple> npts = flowSetIdToNpts.get(flowSetId); + if (npts == null) { + npts = new HashSet<NodePortTuple>(); + } + npts.add(npt); + } else { + Set<NodePortTuple> npts = new HashSet<NodePortTuple>(); + npts.add(npt); + flowSetIdToNpts.put(flowSetId, npts); + } + } + + private Set<U64> getFlowSetIds(NodePortTuple npt) { + return nptToFlowSetIds.get(npt); + } + + private Set<NodePortTuple> getNodePortTuples(U64 flowSetId) { + return flowSetIdToNpts.get(flowSetId); + } + + private void removeNodePortTuple(NodePortTuple npt) { + nptToFlowSetIds.remove(npt); + + Iterator<Set<NodePortTuple>> itr = flowSetIdToNpts.values().iterator(); + while (itr.hasNext()) { + Set<NodePortTuple> npts = itr.next(); + npts.remove(npt); + } + } + + private void removeExpiredFlowSetId(U64 flowSetId) { + flowSetIdToNpts.remove(flowSetId); + + Iterator<Set<U64>> itr = nptToFlowSetIds.values().iterator(); + while (itr.hasNext()) { + Set<U64> ids = itr.next(); + ids.remove(flowSetId); + } + } + } @Override public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { @@ -145,17 +269,21 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF * Builds a cookie that includes routing decision information. * * @param decision The routing decision providing a descriptor, or null - * @return A cookie with our app id and the required routing fields masked-in + * @return A cookie with our app id and the required fields masked-in */ - protected U64 makeForwardingCookie(IRoutingDecision decision) { - int user_fields = 0; + protected U64 makeForwardingCookie(IRoutingDecision decision, U64 flowSetId) { + long user_fields = 0; U64 decision_cookie = (decision == null) ? null : decision.getDescriptor(); if (decision_cookie != null) { user_fields |= AppCookie.extractUser(decision_cookie) & DECISION_MASK; } - // TODO: Mask in any other required fields here (e.g. link failure flowset ID) + if (flowSetId != null) { + user_fields |= AppCookie.extractUser(flowSetId) & FLOWSET_MASK; + } + + // TODO: Mask in any other required fields here if (user_fields == 0) { return DEFAULT_FORWARDING_COOKIE; @@ -181,7 +309,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF * @return A collection of masked cookies suitable for flow-mod operations */ protected Collection<Masked<U64>> convertRoutingDecisionDescriptors(Iterable<Masked<U64>> maskedDescriptors) { - if(maskedDescriptors == null) { + if (maskedDescriptors == null) { return null; } @@ -194,7 +322,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF resultBuilder.add( Masked.of( - AppCookie.makeCookie(FORWARDING_APP_ID, (int)user_value), + AppCookie.makeCookie(FORWARDING_APP_ID, user_value), AppCookie.getAppFieldMask().or(U64.of(user_mask)) ) ); @@ -247,9 +375,16 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { OFPort inPort = OFMessageUtils.getInPort(pi); Match m = createMatchFromPacket(sw, inPort, cntx); - OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd(); // this will be a drop-flow; a flow that will not output to any ports + OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd(); List<OFAction> actions = new ArrayList<OFAction>(); // set no action to drop - U64 cookie = makeForwardingCookie(decision); + U64 flowSetId = flowSetIdRegistry.generateFlowSetId(); + U64 cookie = makeForwardingCookie(decision, flowSetId); + + /* If link goes down, we'll remember to remove this flow */ + if (! m.isFullyWildcarded(MatchField.IN_PORT)) { + flowSetIdRegistry.registerFlowSetId(new NodePortTuple(sw.getId(), m.get(MatchField.IN_PORT)), flowSetId); + } + log.info("Dropping"); fmb.setCookie(cookie) .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) @@ -284,7 +419,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF doFlood(sw, pi, decision, cntx); return; } - + if (srcDevice == null) { log.error("No device entry found for source device. Is the device manager running? If so, report bug."); return; @@ -298,7 +433,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF doFlood(sw, pi, decision, cntx); return; } - + /* This packet-in is from a switch in the path before its flow was installed along the path */ if (!topologyService.isEdge(srcSw, srcPort)) { log.debug("Packet destination is known, but packet was not received on an edge port (rx on {}/{}). Flooding packet", srcSw, srcPort); @@ -343,7 +478,8 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF return; } - U64 cookie = makeForwardingCookie(decision); + U64 flowSetId = flowSetIdRegistry.generateFlowSetId(); + U64 cookie = makeForwardingCookie(decision, flowSetId); Path path = routingEngineService.getPath(srcSw, srcPort, dstAp.getNodeId(), @@ -367,18 +503,26 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF } else { /* Route traverses no links --> src/dst devices on same switch */ log.debug("Could not compute route. Devices should be on same switch src={} and dst={}", srcDevice, dstDevice); - Path p = new Path(srcDevice.getAttachmentPoints()[0].getNodeId(), dstDevice.getAttachmentPoints()[0].getNodeId()); + path = new Path(srcDevice.getAttachmentPoints()[0].getNodeId(), dstDevice.getAttachmentPoints()[0].getNodeId()); List<NodePortTuple> npts = new ArrayList<NodePortTuple>(2); npts.add(new NodePortTuple(srcDevice.getAttachmentPoints()[0].getNodeId(), srcDevice.getAttachmentPoints()[0].getPortId())); npts.add(new NodePortTuple(dstDevice.getAttachmentPoints()[0].getNodeId(), dstDevice.getAttachmentPoints()[0].getPortId())); - p.setPath(npts); - pushRoute(p, m, pi, sw.getId(), cookie, + path.setPath(npts); + pushRoute(path, m, pi, sw.getId(), cookie, cntx, requestFlowRemovedNotifn, OFFlowModCommand.ADD); } + /* + * Register this flowset with ingress and egress ports for link down + * flow removal. This is done after we push the path as it is blocking. + */ + for (NodePortTuple npt : path.getPath()) { + flowSetIdRegistry.registerFlowSetId(npt, flowSetId); + } + } /** @@ -593,6 +737,8 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF this.switchService = context.getServiceImpl(IOFSwitchService.class); this.linkService = context.getServiceImpl(ILinkDiscoveryService.class); + flowSetIdRegistry = FlowSetIdRegistry.getInstance(); + Map<String, String> configParameters = context.getConfigParams(this); String tmp = configParameters.get("hard-timeout"); if (tmp != null) { @@ -777,23 +923,64 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF IOFSwitch srcSw = switchService.getSwitch(u.getSrc()); /* src side of link */ if (srcSw != null) { - /* flows matching on src port */ - msgs.add(srcSw.getOFFactory().buildFlowDelete() - .setCookie(DEFAULT_FORWARDING_COOKIE) - .setCookieMask(AppCookie.getAppFieldMask()) - .setMatch(srcSw.getOFFactory().buildMatch() - .setExact(MatchField.IN_PORT, u.getSrcPort()) - .build()) - .build()); - /* flows outputting to src port */ - msgs.add(srcSw.getOFFactory().buildFlowDelete() - .setCookie(DEFAULT_FORWARDING_COOKIE) - .setCookieMask(AppCookie.getAppFieldMask()) - .setOutPort(u.getSrcPort()) - .build()); - messageDamper.write(srcSw, msgs); - log.warn("{}. Removing flows to/from DPID={}, port={}", new Object[] { u.getType(), u.getSrc(), u.getSrcPort() }); + Set<U64> ids = flowSetIdRegistry.getFlowSetIds( + new NodePortTuple(u.getSrc(), u.getSrcPort())); + if (ids != null) { + for (U64 id : ids) { + U64 cookie = id.or(DEFAULT_FORWARDING_COOKIE); + U64 cookieMask = U64.of(FLOWSET_MASK).or(AppCookie.getAppFieldMask()); + /* flows matching on src port */ + msgs.add(srcSw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setMatch(srcSw.getOFFactory().buildMatch() + .setExact(MatchField.IN_PORT, u.getSrcPort()) + .build()) + .build()); + /* flows outputting to src port */ + msgs.add(srcSw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setOutPort(u.getSrcPort()) + .build()); + messageDamper.write(srcSw, msgs); + log.warn("Removing flows to/from DPID={}, port={}", u.getSrc(), u.getSrcPort()); + log.warn("Cookie/mask {}/{}", cookie, cookieMask); + + /* + * Now, for each ID on this particular failed link, remove + * all other flows in the network using this ID. + */ + Set<NodePortTuple> npts = flowSetIdRegistry.getNodePortTuples(id); + if (npts != null) { + for (NodePortTuple npt : npts) { + msgs.clear(); + IOFSwitch sw = switchService.getSwitch(npt.getNodeId()); + if (sw != null) { + msgs.add(sw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setMatch(sw.getOFFactory().buildMatch() + .setExact(MatchField.IN_PORT, npt.getPortId()) + .build()) + .build()); + /* flows outputting to port */ + msgs.add(sw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setOutPort(npt.getPortId()) + .build()); + messageDamper.write(sw, msgs); + log.warn("Removing flows to/from DPID={}, port={}", npt.getNodeId(), npt.getPortId()); + log.warn("Cookie/mask {}/{}", cookie, cookieMask); + } + } + } + flowSetIdRegistry.removeExpiredFlowSetId(id); + } + } } + flowSetIdRegistry.removeNodePortTuple(new NodePortTuple(u.getSrc(), u.getSrcPort())); } /* must be a link, not just a port down, if we have a dst switch */ @@ -801,24 +988,65 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF /* dst side of link */ IOFSwitch dstSw = switchService.getSwitch(u.getDst()); if (dstSw != null) { - /* flows matching on dst port */ - msgs.clear(); - msgs.add(dstSw.getOFFactory().buildFlowDelete() - .setCookie(DEFAULT_FORWARDING_COOKIE) - .setCookieMask(AppCookie.getAppFieldMask()) - .setMatch(dstSw.getOFFactory().buildMatch() - .setExact(MatchField.IN_PORT, u.getDstPort()) - .build()) - .build()); - /* flows outputting to dst port */ - msgs.add(dstSw.getOFFactory().buildFlowDelete() - .setCookie(DEFAULT_FORWARDING_COOKIE) - .setCookieMask(AppCookie.getAppFieldMask()) - .setOutPort(u.getDstPort()) - .build()); - messageDamper.write(dstSw, msgs); - log.warn("{}. Removing flows to/from DPID={}, port={}", new Object[] { u.getType(), u.getDst(), u.getDstPort() }); + Set<U64> ids = flowSetIdRegistry.getFlowSetIds( + new NodePortTuple(u.getSrc(), u.getSrcPort())); + if (ids != null) { + for (U64 id : ids) { + U64 cookie = id.or(DEFAULT_FORWARDING_COOKIE); + U64 cookieMask = U64.of(FLOWSET_MASK).or(AppCookie.getAppFieldMask()); + /* flows matching on dst port */ + msgs.clear(); + msgs.add(dstSw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setMatch(dstSw.getOFFactory().buildMatch() + .setExact(MatchField.IN_PORT, u.getDstPort()) + .build()) + .build()); + /* flows outputting to dst port */ + msgs.add(dstSw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setOutPort(u.getDstPort()) + .build()); + messageDamper.write(dstSw, msgs); + log.warn("Removing flows to/from DPID={}, port={}", u.getDst(), u.getDstPort()); + log.warn("Cookie/mask {}/{}", cookie, cookieMask); + + /* + * Now, for each ID on this particular failed link, remove + * all other flows in the network using this ID. + */ + Set<NodePortTuple> npts = flowSetIdRegistry.getNodePortTuples(id); + if (npts != null) { + for (NodePortTuple npt : npts) { + msgs.clear(); + IOFSwitch sw = switchService.getSwitch(npt.getNodeId()); + if (sw != null) { + msgs.add(sw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setMatch(sw.getOFFactory().buildMatch() + .setExact(MatchField.IN_PORT, npt.getPortId()) + .build()) + .build()); + /* flows outputting to port */ + msgs.add(sw.getOFFactory().buildFlowDelete() + .setCookie(cookie) + .setCookieMask(cookieMask) + .setOutPort(npt.getPortId()) + .build()); + messageDamper.write(sw, msgs); + log.warn("Removing flows to/from DPID={}, port={}", npt.getNodeId(), npt.getPortId()); + log.warn("Cookie/mask {}/{}", cookie, cookieMask); + } + } + } + flowSetIdRegistry.removeExpiredFlowSetId(id); + } + } } + flowSetIdRegistry.removeNodePortTuple(new NodePortTuple(u.getDst(), u.getDstPort())); } } } diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java index 9b8299466a966b556ea17676e14025b93b7e0aa1..cfb7f8eddf46bf5bac79f39df444666c28d3a728 100644 --- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java +++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java @@ -19,7 +19,6 @@ package net.floodlightcontroller.routing; import java.util.EnumSet; import java.util.ArrayList; -import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -45,7 +44,6 @@ import net.floodlightcontroller.util.FlowModUtils; import net.floodlightcontroller.util.MatchUtils; import net.floodlightcontroller.util.OFDPAUtils; import net.floodlightcontroller.util.OFMessageDamper; -import net.floodlightcontroller.util.TimedCache; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.match.Match; @@ -76,14 +74,11 @@ import org.slf4j.LoggerFactory; public abstract class ForwardingBase implements IOFMessageListener { 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 int FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds public static int FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite public static int FLOWMOD_DEFAULT_PRIORITY = 1; // 0 is the default table-miss flow in OF1.3+, so we need to use 1 - public static TableId FLOWMOD_DEFAULT_TABLE_ID = TableId.ZERO; + protected static TableId FLOWMOD_DEFAULT_TABLE_ID = TableId.ZERO; protected static boolean FLOWMOD_DEFAULT_SET_SEND_FLOW_REM_FLAG = false; @@ -100,9 +95,6 @@ public abstract class ForwardingBase implements IOFMessageListener { protected static boolean FLOWMOD_DEFAULT_MATCH_TRANSPORT_SRC = true; protected static boolean FLOWMOD_DEFAULT_MATCH_TRANSPORT_DST = true; - protected static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT_CONSTANT = 5; - protected static final short FLOWMOD_DEFAULT_HARD_TIMEOUT_CONSTANT = 0; - protected static boolean FLOOD_ALL_ARP_PACKETS = false; protected static boolean REMOVE_FLOWS_ON_LINK_OR_PORT_DOWN = true; @@ -115,33 +107,17 @@ public abstract class ForwardingBase implements IOFMessageListener { protected IDebugCounterService debugCounterService; protected ILinkDiscoveryService linkService; - protected OFMessageDamper messageDamper; - - // for broadcast loop suppression - protected boolean broadcastCacheFeature = true; - public final int prime1 = 2633; // for hash calculation - public final static 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 static final int FORWARDING_APP_ID = 2; static { - AppCookie.registerApp(FORWARDING_APP_ID, "Forwarding"); + AppCookie.registerApp(FORWARDING_APP_ID, "forwarding"); } - public static final U64 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) { - DatapathId d1ClusterId = topologyService.getClusterId(d1.getNodeId()); - DatapathId d2ClusterId = topologyService.getClusterId(d2.getNodeId()); - return d1ClusterId.compareTo(d2ClusterId); - } - }; + protected static final U64 DEFAULT_FORWARDING_COOKIE = AppCookie.makeCookie(FORWARDING_APP_ID, 0); + protected OFMessageDamper messageDamper; + private static int OFMESSAGE_DAMPER_CAPACITY = 10000; + private static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms + protected void init() { messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, EnumSet.of(OFType.FLOW_MOD), @@ -277,7 +253,7 @@ public abstract class ForwardingBase implements IOFMessageListener { if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) != 0) { fmb.setTableId(FLOWMOD_DEFAULT_TABLE_ID); } - + if (log.isTraceEnabled()) { log.trace("Pushing Route flowmod routeIndx={} " + "sw={} inPort={} outPort={}",