diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java index 377eb4f5d83f6fb234975749bd07fbf2587fb7e1..e70b43c36b74d4ff62b9ecf156eb86413f10cbd4 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java @@ -37,6 +37,8 @@ import org.projectfloodlight.openflow.protocol.OFExperimenter; import org.projectfloodlight.openflow.protocol.OFFactories; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFeaturesReply; +import org.projectfloodlight.openflow.protocol.OFFlowAdd; +import org.projectfloodlight.openflow.protocol.OFFlowDelete; import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode; import org.projectfloodlight.openflow.protocol.OFFlowRemoved; import org.projectfloodlight.openflow.protocol.OFGetConfigReply; @@ -57,10 +59,13 @@ import org.projectfloodlight.openflow.protocol.OFStatsRequestFlags; import org.projectfloodlight.openflow.protocol.OFStatsType; import org.projectfloodlight.openflow.protocol.OFType; 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.types.DatapathId; import org.projectfloodlight.openflow.types.OFAuxId; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.TableId; import org.projectfloodlight.openflow.types.U64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -417,6 +422,51 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener { } } + /** + * Removes all present flows and adds an initial table-miss flow to each + * and every table on the switch. This replaces the default behavior of + * forwarding table-miss packets to the controller. The table-miss flows + * inserted will forward all packets that do not match a flow to the + * controller for processing. + * + * Adding the default flow only applies to OpenFlow 1.3+ switches, which + * remove the default forward-to-controller behavior of flow tables. + */ + private void clearAndSetDefaultFlows() { + /* + * No tables for OF1.0, so omit that field for flow deletion. + */ + if (this.sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) == 0) { + OFFlowDelete deleteFlows = this.factory.buildFlowDelete() + .build(); + this.sw.write(deleteFlows); + } else { /* All other OFVersions support multiple tables. */ + OFFlowDelete deleteFlows = this.factory.buildFlowDelete() + .setTableId(TableId.ALL) + .build(); + this.sw.write(deleteFlows); + } + + /* + * Only for OF1.3+, insert the default forward-to-controller flow for + * each table. This is priority=0 with no Match. + */ + if (this.sw.getOFFactory().getVersion().compareTo(OFVersion.OF_13) >= 0) { + ArrayList<OFAction> actions = new ArrayList<OFAction>(1); + actions.add(factory.actions().output(OFPort.CONTROLLER, 0xffFFffFF)); + ArrayList<OFMessage> flows = new ArrayList<OFMessage>(); + for (int tableId = 0; tableId < this.sw.getTables(); tableId++) { + OFFlowAdd defaultFlow = this.factory.buildFlowAdd() + .setTableId(TableId.of(tableId)) + .setPriority(0) + .setActions(actions) + .build(); + flows.add(defaultFlow); + } + this.sw.write(flows); + } + } + /** * Default implementation for message handlers in any state. * @@ -1084,6 +1134,7 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener { @Override void enterState() { setSwitchStatus(SwitchStatus.MASTER); + clearAndSetDefaultFlows(); } @LogMessageDoc(level="WARN", diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java index f2b4bfcf82c591d363408ce694b72fe791701d47..f9ffc92559e556b1bf3613d7d3c6b06c79b3b903 100644 --- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java +++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java @@ -32,6 +32,7 @@ import org.jboss.netty.util.TimerTask; import org.junit.After; import org.junit.Before; import org.junit.Test; + import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitch.SwitchStatus; @@ -43,6 +44,7 @@ import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.Quarantin import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState; import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl; import net.floodlightcontroller.debugcounter.IDebugCounterService; + import org.projectfloodlight.openflow.protocol.OFBadActionCode; import org.projectfloodlight.openflow.protocol.OFBadRequestCode; import org.projectfloodlight.openflow.protocol.OFControllerRole; @@ -65,6 +67,7 @@ import org.projectfloodlight.openflow.protocol.match.Match; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.OFAuxId; import org.projectfloodlight.openflow.types.OFPort; + import net.floodlightcontroller.util.LinkedHashSetWrapper; import net.floodlightcontroller.util.OrderedCollection; @@ -139,7 +142,7 @@ public abstract class OFSwitchHandlerTestBase { replay(switchManager); connection = new MockOFConnection(featuresReply.getDatapathId(), OFAuxId.MAIN); switchHandler = new OFSwitchHandshakeHandler(connection, featuresReply, switchManager, roleManager, timer); - + // replay sw. Reset it if you need more specific behavior replay(sw); } @@ -473,7 +476,8 @@ public abstract class OFSwitchHandlerTestBase { * Needs to verify and reset the controller since we need to set * an expectation */ - private void setupSwitchRoleChangeUnsupported(int xid, + @SuppressWarnings("unchecked") + private void setupSwitchRoleChangeUnsupported(int xid, OFControllerRole role) { SwitchStatus newStatus = role != OFControllerRole.ROLE_SLAVE ? SwitchStatus.MASTER : SwitchStatus.SLAVE; boolean supportsNxRole = false; @@ -483,6 +487,12 @@ public abstract class OFSwitchHandlerTestBase { .andReturn(supportsNxRole).atLeastOnce(); // TODO: hmmm. While it's not incorrect that we set the attribute // again it looks odd. Maybe change + expect(sw.getOFFactory()).andReturn(factory).anyTimes(); + sw.write(anyObject(OFMessage.class)); + expectLastCall().anyTimes(); + sw.write(anyObject(Iterable.class)); + expectLastCall().anyTimes(); + expect(sw.getTables()).andStubReturn((short)0); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole); expectLastCall().anyTimes(); sw.setControllerRole(role); @@ -530,7 +540,8 @@ public abstract class OFSwitchHandlerTestBase { * This method tests only the simple case that the switch supports roles * and transitions to MASTER */ - @Test + @SuppressWarnings("unchecked") + @Test public void testInitialMoveToMasterWithRole() throws Exception { // first, move us to WAIT_INITIAL_ROLE_STATE moveToWaitInitialRole(); @@ -542,6 +553,12 @@ public abstract class OFSwitchHandlerTestBase { // prepare mocks and inject the role reply message reset(sw); + expect(sw.getOFFactory()).andReturn(factory).anyTimes(); + sw.write(anyObject(OFMessage.class)); + expectLastCall().anyTimes(); + sw.write(anyObject(Iterable.class)); + expectLastCall().anyTimes(); + expect(sw.getTables()).andStubReturn((short)0); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); expectLastCall().once(); sw.setControllerRole(OFControllerRole.ROLE_MASTER); @@ -613,7 +630,8 @@ public abstract class OFSwitchHandlerTestBase { * The channel handler still needs to send the initial request to find * out that whether the switch supports roles. */ - @Test + @SuppressWarnings("unchecked") + @Test public void testInitialMoveToMasterNoRole() throws Exception { // first, move us to WAIT_INITIAL_ROLE_STATE moveToWaitInitialRole(); @@ -625,6 +643,12 @@ public abstract class OFSwitchHandlerTestBase { // prepare mocks and inject the role reply message reset(sw); + expect(sw.getOFFactory()).andReturn(factory).anyTimes(); + sw.write(anyObject(OFMessage.class)); + expectLastCall().anyTimes(); + sw.write(anyObject(Iterable.class)); + expectLastCall().anyTimes(); + expect(sw.getTables()).andStubReturn((short)0); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); expectLastCall().once(); sw.setControllerRole(OFControllerRole.ROLE_MASTER); @@ -661,7 +685,8 @@ public abstract class OFSwitchHandlerTestBase { * We let the initial role request time out. Role support should be * disabled but the switch should be activated. */ - @Test + @SuppressWarnings("unchecked") + @Test public void testInitialMoveToMasterTimeout() throws Exception { int timeout = 50; switchHandler.useRoleChangerWithOtherTimeoutForTesting(timeout); @@ -676,6 +701,12 @@ public abstract class OFSwitchHandlerTestBase { // prepare mocks and inject the role reply message reset(sw); + expect(sw.getOFFactory()).andReturn(factory).anyTimes(); + sw.write(anyObject(OFMessage.class)); + expectLastCall().anyTimes(); + sw.write(anyObject(Iterable.class)); + expectLastCall().anyTimes(); + expect(sw.getTables()).andStubReturn((short)0); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); expectLastCall().once(); sw.setControllerRole(OFControllerRole.ROLE_MASTER); @@ -820,7 +851,8 @@ public abstract class OFSwitchHandlerTestBase { * Expects that the channel is in MASTER or SLAVE state. * */ - public void changeRoleToMasterWithRequest() throws Exception { + @SuppressWarnings("unchecked") + public void changeRoleToMasterWithRequest() throws Exception { assertTrue("This method can only be called when handler is in " + "MASTER or SLAVE role", switchHandler.isHandshakeComplete()); @@ -829,6 +861,12 @@ public abstract class OFSwitchHandlerTestBase { // prepare mocks and inject the role reply message reset(sw); + expect(sw.getOFFactory()).andReturn(factory).anyTimes(); + sw.write(anyObject(OFMessage.class)); + expectLastCall().anyTimes(); + sw.write(anyObject(Iterable.class)); + expectLastCall().anyTimes(); + expect(sw.getTables()).andStubReturn((short)0); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); expectLastCall().once(); sw.setControllerRole(OFControllerRole.ROLE_MASTER);