Skip to content
Snippets Groups Projects
Commit 5a6e7195 authored by Alex Reimers's avatar Alex Reimers
Browse files

Enable Forwarding. This replaces LearningSwitch and uses L2 shortest path...

Enable Forwarding. This replaces LearningSwitch and uses L2 shortest path routing to forward Packets. [#21940749]
parent 52310134
No related branches found
No related tags found
No related merge requests found
......@@ -2,5 +2,6 @@
.classpath
.project
.settings
.DS_Store
target
thrift
......@@ -63,10 +63,12 @@ import static net.floodlightcontroller.counter.CounterValue.CounterType;
import net.floodlightcontroller.counter.CounterStore;
import net.floodlightcontroller.counter.ICounter;
import net.floodlightcontroller.counter.CounterStore.NetworkLayer;
import net.floodlightcontroller.devicemanager.IDeviceManagerAware;
import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl;
import net.floodlightcontroller.learningswitch.LearningSwitch;
import net.floodlightcontroller.forwarding.Forwarding;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.routing.dijkstra.RoutingImpl;
import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher;
import net.floodlightcontroller.perfmon.PktinProcessingTime;
import net.floodlightcontroller.storage.IResultSet;
......@@ -165,7 +167,8 @@ public class Controller
protected IStorageSource storageSource;
protected TopologyImpl topology;
protected DeviceManagerImpl deviceManager;
protected LearningSwitch learningSwitch;
protected RoutingImpl routingEngine;
protected Forwarding forwarding;
protected OFMessageFilterManager messageFilterManager;
protected PktinProcessingTime pktinProcTime;
private StaticFlowEntryPusher staticFlowEntryPusher;
......@@ -1393,9 +1396,7 @@ public class Controller
topology = new TopologyImpl();
deviceManager = new DeviceManagerImpl();
storageSource = new MemoryStorageSource();
learningSwitch = new LearningSwitch();
counterStore = new CounterStore();
messageFilterManager = new OFMessageFilterManager();
pktinProcTime = new PktinProcessingTime();
topology.setFloodlightProvider(this);
......@@ -1405,26 +1406,49 @@ public class Controller
deviceManager.setStorageSource(storageSource);
deviceManager.setTopology(topology);
messageFilterManager.init(this);
staticFlowEntryPusher = new StaticFlowEntryPusher();
staticFlowEntryPusher.setFloodlightProvider(this);
learningSwitch.setFloodlightProvider(this);
learningSwitch.setCounterStore(counterStore);
initMessageFilterManager();
initStaticFlowPusher();
routingEngine = new RoutingImpl();
initForwarding();
// call this explicitly because it does setup
this.setStorageSource(storageSource);
HashSet<ITopologyAware> topologyAware = new HashSet<ITopologyAware>();
topologyAware.add(deviceManager);
topologyAware.add(routingEngine);
topology.setTopologyAware(topologyAware);
topology.setRoutingEngine(routingEngine);
HashSet<IDeviceManagerAware> dmAware =
new HashSet<IDeviceManagerAware>();
dmAware.add(forwarding);
deviceManager.setDeviceManagerAware(dmAware);
restlets.add(new CoreWebRoutable());
restlets.add(new StorageWebRoutable());
JacksonCustomConverter.replaceConverter();
}
protected void initMessageFilterManager() {
messageFilterManager = new OFMessageFilterManager();
messageFilterManager.init(this);
}
protected void initStaticFlowPusher() {
staticFlowEntryPusher = new StaticFlowEntryPusher();
staticFlowEntryPusher.setFloodlightProvider(this);
}
protected void initForwarding() {
forwarding = new Forwarding();
forwarding.setFloodlightProvider(this);
forwarding.setCounterStore(counterStore);
forwarding.setDeviceManager(deviceManager);
forwarding.setRoutingEngine(routingEngine);
forwarding.setTopology(topology);
}
/**
* Initialize the rest context
*/
......@@ -1434,10 +1458,12 @@ public class Controller
context.getAttributes().put("storageSource", storageSource);
context.getAttributes().put("deviceManager", deviceManager);
context.getAttributes().put("messageFilterManager",
messageFilterManager);
messageFilterManager);
context.getAttributes().put("pktinProcessingTime", pktinProcTime);
context.getAttributes().put("staticFlowEntryPusher",
staticFlowEntryPusher);
if (staticFlowEntryPusher != null) {
context.getAttributes().put("staticFlowEntryPusher",
staticFlowEntryPusher);
}
context.getAttributes().put("topology", topology);
}
......@@ -1460,19 +1486,19 @@ public class Controller
// no need to do storageSource.startUp()
log.debug("Starting counterStore service");
counterStore.startUp();
log.debug("Starting learningSwitch service");
learningSwitch.startUp();
log.debug("Starting routingEngine service");
routingEngine.startUp();
log.debug("Starting forwarding service");
forwarding.startUp();
log.debug("Starting messageFilter service");
messageFilterManager.startUp();
log.debug("Starting staticFlowEntryPusher service");
staticFlowEntryPusher.startUp();
}
/**
* Main function entry point; override init() for adding modules
* @param args
* @param args Command line arguments
*/
public static void main(String args[]) throws Exception {
......
......@@ -18,19 +18,29 @@
package net.floodlightcontroller.forwarding;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProvider;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.devicemanager.Device;
import net.floodlightcontroller.devicemanager.DeviceAttachmentPoint;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.routing.ForwardingBase;
import net.floodlightcontroller.routing.IRoutingDecision;
import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.topology.LinkInfo;
import net.floodlightcontroller.topology.SwitchPortTuple;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.openflow.util.HexString;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
import org.openflow.protocol.action.OFAction;
import org.openflow.protocol.action.OFActionOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -39,39 +49,50 @@ public class Forwarding extends ForwardingBase {
@Override
public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
Ethernet eth = IFloodlightProvider.bcStore.get(cntx,
IFloodlightProvider.CONTEXT_PI_PAYLOAD);
if (eth.isBroadcast() || eth.isMulticast()) {
// For now we treat multicast as broadcast
doFlood(sw, pi, cntx);
} else {
doForwardFlow(sw, pi, cntx);
}
return Command.CONTINUE;
}
protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
OFMatch match = new OFMatch();
match.loadFromPacket(pi.getPacketData(), pi.getInPort(), sw.getId());
// Check if we have the location of the destination
Device dstDevice = deviceManager.getDeviceByDataLayerAddress(match.getDataLayerDestination());
// TODO Optimizations -
// Keep attachment points sorted by clusterId so we don't need double for loops
// Bidirectional flow setup
if (dstDevice != null) {
Device srcDevice = deviceManager.getDeviceByDataLayerAddress(match.getDataLayerSource());
Long srcIsland = sw.getSwitchClusterId();
if (srcDevice == null) {
log.error("No device entry found for source device {}", dstDevice.getDataLayerAddress());
return Command.CONTINUE;
return;
}
if (srcIsland == null) {
log.error("No openflow island found for source device {}", dstDevice.getDataLayerAddress());
return Command.CONTINUE;
return;
}
// If we do not find the attachment point on the first hop island we need to flood
// 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 (DeviceAttachmentPoint dstDap : dstDevice.getAttachmentPoints()) {
SwitchPortTuple dstSpt = dstDap.getSwitchPort();
if ((dstSpt != null) && (dstSpt.getSw() != null)) {
Long dstIsland = dstDap.getSwitchPort().getSw().getSwitchClusterId();
SwitchPortTuple dstTuple = dstDap.getSwitchPort();
if ((dstTuple != null) && (dstTuple.getSw() != null)) {
Long dstIsland = dstTuple.getSw().getSwitchClusterId();
if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
on_same_island = true;
if ((sw.getId() == dstDap.getSwitchPort().getSw().getId()) &&
(pi.getInPort() == dstSpt.getPort().shortValue())) {
if ((sw.getId() == dstTuple.getSw().getId()) &&
(pi.getInPort() == dstTuple.getPort().shortValue())) {
on_same_if = true;
}
break;
......@@ -80,63 +101,132 @@ public class Forwarding extends ForwardingBase {
}
if (!on_same_island) {
log.debug("No first hop island found for destination device {}", dstDevice.getDataLayerAddress());
return Command.CONTINUE;
// Flood since we don't know the dst device
if (log.isDebugEnabled()) {
log.debug("No first hop island found for destination device {}, Action = flooding",
dstDevice.getDataLayerAddress());
}
doFlood(sw, pi, cntx);
return;
}
if (on_same_if) {
log.debug("Both source and destination are on the same switch/port {}/{}", sw.toString(), pi.getInPort());
return Command.CONTINUE;
if (log.isDebugEnabled()) {
log.debug("Both source and destination are on the same switch/port {}/{}, Action = NOP",
sw.toString(), pi.getInPort());
}
return;
}
// Find all the routes in the same cluster
for (DeviceAttachmentPoint srcDap : srcDevice.getAttachmentPoints()) {
for (DeviceAttachmentPoint dstDap : dstDevice.getAttachmentPoints()) {
if (srcDap.equals(dstDap)) continue;
IOFSwitch srcSw = srcDap.getSwitchPort().getSw();
IOFSwitch dstSw = dstDap.getSwitchPort().getSw();
Long srcCluster = null;
Long dstCluster = null;
if ((srcSw != null) && (dstSw != null)) {
srcCluster = srcSw.getSwitchClusterId();
dstCluster = dstSw.getSwitchClusterId();
}
if ((srcCluster != null) && (dstCluster != null) && (srcCluster.equals(dstCluster))) {
// 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
DeviceAttachmentPoint[] srcDaps =
srcDevice.getAttachmentPointsSorted(DeviceAttachmentPoint.clusterIdComparator).toArray(new DeviceAttachmentPoint[0]);
DeviceAttachmentPoint[] dstDaps =
dstDevice.getAttachmentPointsSorted(DeviceAttachmentPoint.clusterIdComparator).toArray(new DeviceAttachmentPoint[0]);
int iSrcDaps = 0, iDstDaps = 0;
while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) {
DeviceAttachmentPoint srcDap = srcDaps[iSrcDaps];
DeviceAttachmentPoint dstDap = dstDaps[iDstDaps];
IOFSwitch srcSw = srcDap.getSwitchPort().getSw();
IOFSwitch dstSw = dstDap.getSwitchPort().getSw();
Long srcCluster = null;
Long dstCluster = null;
if ((srcSw != null) && (dstSw != null)) {
srcCluster = srcSw.getSwitchClusterId();
dstCluster = dstSw.getSwitchClusterId();
}
int srcVsDest = srcCluster.compareTo(dstCluster);
if (srcVsDest == 0) {
if (!srcDap.equals(dstDap) && (srcCluster != null) && (dstCluster != null)) {
Route route = routingEngine.getRoute(srcSw.getId(), dstSw.getId());
if (route != null || validLocalHop(srcDap.getSwitchPort(), dstDap.getSwitchPort())) {
if ((route != null) || validLocalHop(srcDap.getSwitchPort(), dstDap.getSwitchPort())) {
int bufferId = OFPacketOut.BUFFER_ID_NONE;
// Set the bufferId for the original PacketIn switch
/*
// TODO - finalize whether we need to set this or not
if (sw.getId() == srcDaps.getSwitchPort().getSw().getId()) {
bufferId = pi.getBufferId();
if (log.isTraceEnabled()) {
log.trace("pushRoute match={} route={} destination={}:{}",
new Object[] {match, route, dstDap.getSwitchPort().getSw(),
dstDap.getSwitchPort().getPort()});
}
*/
log.debug("Pushing route match={} route={} destination={}:{}",
new Object[] {match, route, dstDap.getSwitchPort().getSw(),
dstDap.getSwitchPort().getPort()});
pushRoute(route, match, null,
srcDap.getSwitchPort(), dstDap.getSwitchPort(),
bufferId, sw, pi, cntx);
break;
pushRoute(route, match, 0,
srcDap.getSwitchPort(), dstDap.getSwitchPort(), bufferId,
sw, pi, cntx);
}
}
iSrcDaps++;
iDstDaps++;
} else if (srcVsDest < 0) {
iSrcDaps++;
} else {
iDstDaps++;
}
}
} else {
// filter multicast destinations
if ((match.getDataLayerDestination()[0] & 0x1) == 0) {
log.debug("Unable to locate device with address {}",
HexString.toHexString(match
.getDataLayerDestination()));
// Flood since we don't know the dst device
doFlood(sw, pi, cntx);
}
}
/**
* Creates a OFPacketOut with the OFPacketIn data that is flooded on all ports unless
* the port is blocked, in which case the packet will be dropped.
* @param pi The OFPacketIn that came to the switch
* @param decision The Forwarding decision
* @param cntx The FloodlightContext associated with this OFPacketIn
*/
protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
SwitchPortTuple srcSwTuple = new SwitchPortTuple(sw, pi.getInPort());
LinkInfo linkInfo = topology.getLinkInfo(srcSwTuple, false);
if (log.isTraceEnabled()) {
log.trace("doFlood pi={} srcSwitchTuple={}, link={}",
new Object[] { pi, srcSwTuple, linkInfo});
}
if (linkInfo != null && linkInfo.isBroadcastBlocked()) {
if (log.isDebugEnabled()) {
log.debug("doFlood, drop broadcast packet, pi={}, from a blocked port, " +
"srcSwitchTuple={}, linkInfo={}", new Object[] {pi, srcSwTuple, linkInfo});
}
return Command.CONTINUE;
return;
}
// Set Action to flood
OFPacketOut po =
(OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
List<OFAction> actions = new ArrayList<OFAction>();
if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) {
actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), (short)0));
} else {
actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(), (short)0));
}
po.setActions(actions);
po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
return Command.STOP;
}
// set buffer-id, in-port and packet-data based on packet-in
short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
po.setBufferId(pi.getBufferId());
po.setInPort(pi.getInPort());
if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
byte[] packetData = pi.getPacketData();
poLength += packetData.length;
po.setPacketData(packetData);
}
po.setLength(poLength);
try {
if (log.isTraceEnabled()) {
log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}",
new Object[] {sw, pi, po});
}
sw.write(po, cntx);
} catch (IOException e) {
log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}",
new Object[] {sw, pi, po}, e);
}
return;
}
@Override
protected OFMatch wildcard(OFMatch match, IOFSwitch sw, Integer hints) {
// use same wilcarding as the learning switch
......@@ -151,5 +241,4 @@ public class Forwarding extends ForwardingBase {
return srcTuple.getSw().getId() == dstTuple.getSw().getId() &&
srcTuple.getPort() != dstTuple.getPort();
}
}
......@@ -103,6 +103,7 @@ public abstract class ForwardingBase implements IOFMessageListener, IDeviceManag
IRoutingDecision decision = null;
if (cntx != null) decision =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx);
}
log.error("received an unexpected message {} from switch {}", msg, sw);
......@@ -130,16 +131,13 @@ public abstract class ForwardingBase implements IOFMessageListener, IDeviceManag
/**
* Push routes from back to front
* @param route
* @param match
* @param srcSwPort
* @param dstSwPort
* @param bufferId
* @param srcSwitch
* @param pi
* @return
* @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 bufferId BufferId of the original PacketIn
* @return srcSwitchIincluded True if the source switch is included in this route
*/
public boolean pushRoute(Route route, OFMatch match, Integer wildcard_hints,
SwitchPortTuple srcSwPort,
SwitchPortTuple dstSwPort, int bufferId,
......@@ -187,8 +185,11 @@ public abstract class ForwardingBase implements IOFMessageListener, IDeviceManag
fm.getMatch().setInputPort(link.getInPort());
try {
updateCounterStore(sw, fm);
log.debug("Pushing Route flowmod routeIndx={} sw={} inPort={} outPort={}",
new Object[] { routeIndx, sw, fm.getMatch().getInputPort(), ((OFActionOutput)fm.getActions().get(0)).getPort() });
if (log.isDebugEnabled()) {
log.debug("Pushing Route flowmod routeIndx={} sw={} inPort={} outPort={}",
new Object[] { routeIndx, sw, fm.getMatch().getInputPort(),
((OFActionOutput)fm.getActions().get(0)).getPort() });
}
sw.write(fm, cntx);
// Push the packet out the source switch
......
......@@ -33,9 +33,10 @@ public interface IRoutingDecision {
* if the destination is not known at this time, initiate a discovery action for it (e.g. ARP)
* FORWARD_OR_FLOOD: Forward this packet, and this flow, to the first (and only device) in getDestinationDevices(),
* if the destination is not known at this time, flood this packet on the source switch
* MULTICAST Multicast this packet to all the interfaces and devices attached
* BROADCAST: Broadcast this packet on all links
* MULTICAST: Multicast this packet to all the interfaces and devices attached
*/
NONE, DROP, FORWARD, FORWARD_OR_FLOOD, MULTICAST
NONE, DROP, FORWARD, FORWARD_OR_FLOOD, BROADCAST, MULTICAST
}
public static final FloodlightContextStore<IRoutingDecision> rtStore =
......@@ -54,6 +55,4 @@ public interface IRoutingDecision {
public void setMulticastInterfaces(List<SwitchPortTuple> lspt);
public Integer getWildcards();
public void setWildcards(Integer wildcards);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment