diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java index 36b2be09f955572166d73e6c4a3e9a969cb614fe..0b219e087d42d7cec5d4da2c378e6be4b36025eb 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java @@ -3,6 +3,7 @@ package net.floodlightcontroller.core.internal; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -24,10 +25,12 @@ import net.floodlightcontroller.core.SwitchDescription; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType; +import net.floodlightcontroller.util.OFDPAUtils; import org.projectfloodlight.openflow.protocol.OFBadRequestCode; import org.projectfloodlight.openflow.protocol.OFBarrierReply; import org.projectfloodlight.openflow.protocol.OFBarrierRequest; +import org.projectfloodlight.openflow.protocol.OFBucket; import org.projectfloodlight.openflow.protocol.OFControllerRole; import org.projectfloodlight.openflow.protocol.OFDescStatsReply; import org.projectfloodlight.openflow.protocol.OFDescStatsRequest; @@ -44,6 +47,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode; import org.projectfloodlight.openflow.protocol.OFFlowRemoved; import org.projectfloodlight.openflow.protocol.OFGetConfigReply; import org.projectfloodlight.openflow.protocol.OFGetConfigRequest; +import org.projectfloodlight.openflow.protocol.OFGroupAdd; import org.projectfloodlight.openflow.protocol.OFGroupDelete; import org.projectfloodlight.openflow.protocol.OFGroupType; import org.projectfloodlight.openflow.protocol.OFMessage; @@ -51,6 +55,7 @@ import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole; import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply; import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest; import org.projectfloodlight.openflow.protocol.OFPacketIn; +import org.projectfloodlight.openflow.protocol.OFPortDesc; import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; import org.projectfloodlight.openflow.protocol.OFPortStatus; import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply; @@ -68,12 +73,18 @@ import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; +import org.projectfloodlight.openflow.protocol.match.MatchField; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.OFAuxId; +import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFGroup; import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.OFVlanVidMatch; import org.projectfloodlight.openflow.types.TableId; +import org.projectfloodlight.openflow.types.U16; import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.VlanVid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -521,6 +532,142 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener { } } + private void addBroadcomOFDPAFlows() { + /* + * By default, we'll assume everyone's on the same VLAN, + * and all switch ports are configured as access ports. + * As such, all packets on the wire will be untagged + * and will only be tagged internally in the switch for + * pipeline processing. + * + * If you would like to configure trunks on switches, then + * each switch will need to be configured specifically, as + * we won't be able to automatically handle such a topology. + * + * Ingress port table (0) = empty --> default to VLAN table + * VLAN table (10) = match untagged, apply internal tag, goto termination MAC + * Termination MAC table (20) = match vlan tag and dst MAC, goto bridging table (default miss-->bridging) + * match only vlan tag, goto controller (DLF or Dest Lookup Failure) + * Bridging table (50) = default send to policy ACL table + * Policy ACL table (60) = priority=0 go to controller + * write action group of forwarding decision + * Group tables + * One per interface per VLAN + * One per VLAN (for flooding) + * + * TABLE_INGRESS = 0 + * TABLE_VLAN = 10 + * TABLE_MAC = 20 + * TABLE_UNICAST = 30 + * TABLE_MULTICAST = 40 + * TABLE_BRIDGING = 50 + * TABLE_ACL = 60 + */ + + /* + * Add flow to match all untagged packets from all ports in VLAN table + */ + List<OFAction> al = new ArrayList<OFAction>(1); + /* al.add(factory.actions().pushVlan(EthType.IPv4)); might not need this */ + al.add(factory.actions().setVlanVid(VlanVid.ofVlan(1))); /* we'll use 1 internally, just because */ + + List<OFInstruction> il = new ArrayList<OFInstruction>(2); + il.add(factory.instructions().gotoTable(TableId.of(20))); /* 20 is the termination MAC table */ + il.add(factory.instructions().applyActions(al)); + OFFlowAdd fa = factory.buildFlowAdd() + .setTableId(TableId.of(10)) + .setOutPort(OFPort.ANY) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.ZERO) + .setMatch(factory.buildMatch() + .setExact(MatchField.VLAN_VID, OFVlanVidMatch.UNTAGGED) /* this flow handles untagged */ + /* do we have to match on the in port here? */ + .build() + ) + .setInstructions(il) + .setPriority(1000) + .build(); + sw.write(fa); + + /* + * The termination MAC flow table must proactively forward to controller specific dst MACs, + * so we need to wait to do wildcarded dst MACs in bridging table upon a miss. Send to bridging + * table by default here. + */ + + /* + * Add flow to match all vlan=1 packets to forward to controller in bridging table (DLF). + * Default is to send to policy ACL if this does not match. + */ + al = new ArrayList<OFAction>(1); + al.add(factory.actions().output(OFPort.CONTROLLER, 0xffFFffFF)); + + il = new ArrayList<OFInstruction>(1); + il.add(factory.instructions().applyActions(al)); + fa = factory.buildFlowAdd() + .setTableId(TableId.of(50)) + .setOutPort(OFPort.ANY) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.ZERO) + .setMatch(factory.buildMatch() + .setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(1)) /* this flow handles recently-tagged VLAN=1 */ + .build() + ) + .setInstructions(il) + .setPriority(1) + .build(); + sw.write(fa); + + /* + * Lastly, add a group for flooding and for each port. + * This group is only for VLAN=1. + * + * The flood group has buckets with goto group actions + * for each port's individual L2 group for VLAN=1. + * + * This means we must first add the individual groups. + */ + ArrayList<OFBucket> buckets = new ArrayList<OFBucket>(); + for (OFPortDesc pd : this.sw.getPorts()) { + OFPort p = pd.getPortNo(); + if ((p.getShortPortNumber() & 0xFF00) == 0) { /* TODO Is this correct for special ports? */ + OFGroupAdd ga = factory.buildGroupAdd() + .setGroupType(OFGroupType.INDIRECT) + .setBuckets(Collections.singletonList(factory.buildBucket() + .setActions( + Collections.singletonList((OFAction) factory.actions().buildOutput() + .setMaxLen(0xffFFffFF) + .setPort(p) + .build())) + .build())) + .setGroup(OFDPAUtils.GroupIds.createL2Interface(p, VlanVid.ofVlan(100))) + .build(); + sw.write(ga); + + /* + * Add the port+bucket for creating the FLOOD group below. + * All L2_INTERFACE groups in a VLAN should be within a + * corresponding L2_FLOOD group of type ALL. + */ + buckets.add(factory.buildBucket().setActions( + Collections.singletonList( + (OFAction) factory.actions().buildOutput() + .setMaxLen(0xffFFffFF) + .setPort(p) + .build() + ) + ).build()); + } + } + + OFGroupAdd ga = factory.buildGroupAdd() + .setGroupType(OFGroupType.ALL) + .setBuckets(buckets) + .setGroup(OFDPAUtils.GroupIds.createL2Flood(U16.ZERO, VlanVid.ofVlan(100))) + .build(); + sw.write(ga); + } + /** * Default implementation for message handlers in any state. * @@ -865,7 +1012,6 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener { } break; default: - illegalMessageReceived(m); break; } } diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java index cd829e308e07ccb67a401ef7815ee790e809e4ec..5e311a3d426fbbe678b0e393ae3dab3d234e938d 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java @@ -118,7 +118,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen private ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler> switchHandlers; private ConcurrentHashMap<DatapathId, IOFSwitchBackend> switches; private ConcurrentHashMap<DatapathId, IOFSwitch> syncedSwitches; - + private Set<DatapathId> pastSwitches; private ISwitchDriverRegistry driverRegistry; @@ -676,6 +676,8 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen driverRegistry = new NaiveSwitchDriverRegistry(this); this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>(); + + this.pastSwitches = new HashSet<DatapathId>(); /* TODO @Ryan try { @@ -1010,7 +1012,7 @@ public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListen ChannelPipelineFactory pfact = useSsl ? new OpenflowPipelineFactory(this, floodlightProvider.getTimer(), this, debugCounterService, ofBitmaps, defaultFactory, keyStore, keyStorePassword) : new OpenflowPipelineFactory(this, floodlightProvider.getTimer(), this, debugCounterService, ofBitmaps, defaultFactory); - + bootstrap.setPipelineFactory(pfact); InetSocketAddress sa = new InetSocketAddress(floodlightProvider.getOFPort()); final ChannelGroup cg = new DefaultChannelGroup();