From 93e57d4825b5b6f3ae3a7c1fe0dba68c8f1da9ce Mon Sep 17 00:00:00 2001
From: Ryan Izard <rizard@g.clemson.edu>
Date: Tue, 22 Dec 2015 16:30:28 -0500
Subject: [PATCH] Added unit test for writing messages while in MASTER/SLAVE.
 Changed to a blacklist mechanism instead of a whitelist (to match how the
 spec describes invalid (write) SLAVE messages). Completed invalid SLAVE
 messages for each OF version.

---
 .../core/internal/OFSwitch.java               |  34 ++-
 .../core/internal/OFSwitchBaseTest.java       |  36 ++-
 .../core/internal/OFSwitchTest.java           | 224 +++++++++---------
 3 files changed, 168 insertions(+), 126 deletions(-)

diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
index afb7eed40..b31c37966 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitch.java
@@ -682,29 +682,39 @@ public class OFSwitch implements IOFSwitchBackend {
 	}
 
 	protected static class SwitchRoleMessageValidator {
-		private static final Map<OFVersion, Set<OFType>> validSlaveMsgsByOFVersion;
+		private static final Map<OFVersion, Set<OFType>> invalidSlaveMsgsByOFVersion;
 		static {
 			Map<OFVersion, Set<OFType>> m = new HashMap<OFVersion, Set<OFType>>();
 			Set<OFType> s = new HashSet<OFType>();
-			s.add(OFType.ROLE_REQUEST);
-			s.add(OFType.SET_ASYNC);
-			s.add(OFType.SET_CONFIG);
-			s.add(OFType.GET_ASYNC_REQUEST);
-			s.add(OFType.ECHO_REQUEST);
-			s.add(OFType.GET_CONFIG_REQUEST);
-			s.add(OFType.STATS_REQUEST);
-			s.add(OFType.FEATURES_REQUEST);
+			s.add(OFType.PACKET_OUT);
+			s.add(OFType.FLOW_MOD);
+			s.add(OFType.PORT_MOD);
+			s.add(OFType.TABLE_MOD);
+			s.add(OFType.BARRIER_REQUEST);
 			m.put(OFVersion.OF_10, Collections.unmodifiableSet(s));
+			
 			s = new HashSet<OFType>();
+			s.addAll(m.get(OFVersion.OF_10));
+			s.add(OFType.GROUP_MOD);
+			s.add(OFType.TABLE_MOD);
 			m.put(OFVersion.OF_11, Collections.unmodifiableSet(s));
+			
 			s = new HashSet<OFType>();
+			s.addAll(m.get(OFVersion.OF_11));
 			m.put(OFVersion.OF_12, Collections.unmodifiableSet(s));
+			
 			s = new HashSet<OFType>();
+			s.addAll(m.get(OFVersion.OF_12));
+			s.add(OFType.METER_MOD);
 			m.put(OFVersion.OF_13, Collections.unmodifiableSet(s));
+			
 			s = new HashSet<OFType>();
+			s.addAll(m.get(OFVersion.OF_13));
+			s.add(OFType.BUNDLE_ADD_MESSAGE);
+			s.add(OFType.BUNDLE_CONTROL);
 			m.put(OFVersion.OF_14, Collections.unmodifiableSet(s));
 
-			validSlaveMsgsByOFVersion = Collections.unmodifiableMap(m);
+			invalidSlaveMsgsByOFVersion = Collections.unmodifiableMap(m);
 		}
 
 		/**
@@ -724,12 +734,12 @@ public class OFSwitch implements IOFSwitchBackend {
 				valid.addAll(IterableUtils.toCollection(msgList));
 				return Collections.emptyList();
 			} else { /* slave */
-				Set<OFType> validSlaveMsgs = validSlaveMsgsByOFVersion.get(swVersion);
+				Set<OFType> invalidSlaveMsgs = invalidSlaveMsgsByOFVersion.get(swVersion);
 				List<OFMessage> invalid = new ArrayList<OFMessage>();
 				Iterator<OFMessage> itr = msgList.iterator();
 				while (itr.hasNext()) {
 					OFMessage m = itr.next();
-					if (!validSlaveMsgs.contains(m.getType())) {
+					if (invalidSlaveMsgs.contains(m.getType())) {
 						invalid.add(m);
 					} else {
 						valid.add(m);
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
index 5b73331d7..5c067f060 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
@@ -59,6 +59,8 @@ import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
@@ -145,7 +147,7 @@ public class OFSwitchBaseTest {
 
         IOFConnectionBackend conn = EasyMock.createNiceMock(IOFConnectionBackend.class);
         capturedMessage = new Capture<Iterable<OFMessage>>();
-        expect(conn.write(EasyMock.capture(capturedMessage))).andReturn(Collections.<OFMessage>emptyList()).once();
+        expect(conn.write(EasyMock.capture(capturedMessage))).andReturn(Collections.<OFMessage>emptyList()).atLeastOnce();
         expect(conn.getOFFactory()).andReturn(factory).anyTimes();
         expect(conn.getAuxId()).andReturn(OFAuxId.MAIN).anyTimes();
         EasyMock.replay(conn);
@@ -1413,4 +1415,34 @@ public class OFSwitchBaseTest {
         verify(switchManager);
     }
 
-}
+
+	@Test
+	public void testMasterSlaveWrites() {
+		OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+		OFFlowAdd fa = factory.buildFlowAdd().build();
+		OFFlowStatsRequest fsr = factory.buildFlowStatsRequest().build();
+		List<OFMessage> msgList = new ArrayList<OFMessage>();
+		msgList.add(fa);
+		msgList.add(fsr);
+		
+		reset(switchManager);
+        expect(switchManager.isCategoryRegistered(LogicalOFMessageCategory.MAIN)).andReturn(true).times(6);
+        switchManager.handleOutgoingMessage(sw, fa);
+        expectLastCall().times(2);
+        switchManager.handleOutgoingMessage(sw, fsr);
+        expectLastCall().times(4);
+        replay(switchManager);
+
+		/* test master -- both messages should be written */
+		sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+		assertTrue(sw.write(fa));
+		assertTrue(sw.write(fsr));
+		assertEquals(Collections.<OFMessage>emptyList(), sw.write(msgList));
+		
+		/* test slave -- flow-add (mod op) should fail each time; flow stats (read op) should pass */
+		sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+		assertFalse(sw.write(fa)); /* flow-add should be stopped (mod op) */
+		assertTrue(sw.write(fsr)); /* stats request makes it (read op) */
+		assertEquals(Collections.<OFMessage>singletonList(fa), sw.write(msgList)); /* return bad flow-add */
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
index 4ddef9978..483aab250 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
@@ -49,116 +49,116 @@ import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFAuxId;
 
 public class OFSwitchTest {
-    protected OFSwitch sw;
-    protected OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
-
-    @Before
-    public void setUp() throws Exception {
-        MockOFConnection mockConnection = new MockOFConnection(DatapathId.of(1), OFAuxId.MAIN);
-        sw = new OFSwitch(mockConnection, OFFactories.getFactory(OFVersion.OF_10),
-                EasyMock.createMock(IOFSwitchManager.class), DatapathId.of(1));
-    }
-
-    @Test
-    public void testSetHARoleReply() {
-        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
-        assertEquals(OFControllerRole.ROLE_MASTER, sw.getControllerRole());
-
-        sw.setControllerRole(OFControllerRole.ROLE_EQUAL);
-        assertEquals(OFControllerRole.ROLE_EQUAL, sw.getControllerRole());
-
-        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
-        assertEquals(OFControllerRole.ROLE_SLAVE, sw.getControllerRole());
-    }
-
-    @Test
-    public void testSubHandshake() {
-        OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
-        OFMessage m = factory.buildNiciraControllerRoleReply()
-                .setXid(1)
-                .setRole(OFNiciraControllerRole.ROLE_MASTER)
-                .build();
-        // test exceptions before handshake is started
-        try {
-            sw.processDriverHandshakeMessage(m);
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
-        try {
-            sw.isDriverHandshakeComplete();
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
-
-        // start the handshake -- it should immediately complete
-        sw.startDriverHandshake();
-        assertTrue("Handshake should be complete",
-                   sw.isDriverHandshakeComplete());
-
-        // test exceptions after handshake is completed
-        try {
-            sw.processDriverHandshakeMessage(m);
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
-        try {
-            sw.startDriverHandshake();
-            fail("Expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
-    }
-
-    /**
-     * Helper to load controller connection messages into a switch for testing.
-     * @param sw the switch to insert the message on
-     * @param role the role for the controller connection message
-     * @param state the state for the controller connection message
-     * @param uri the URI for the controller connection message
-     */
-    public void updateControllerConnections(IOFSwitchBackend sw, OFControllerRole role1, OFBsnControllerConnectionState state1, String uri1
-                                            ,  OFControllerRole role2, OFBsnControllerConnectionState state2, String uri2) {
-        OFBsnControllerConnection connection1 = factory.buildBsnControllerConnection()
-                .setAuxiliaryId(OFAuxId.MAIN)
-                .setRole(role1)
-                .setState(state1)
-                .setUri(uri1)
-                .build();
-
-        OFBsnControllerConnection connection2 = factory.buildBsnControllerConnection()
-                .setAuxiliaryId(OFAuxId.MAIN)
-                .setRole(role2)
-                .setState(state2)
-                .setUri(uri2)
-                .build();
-
-        List<OFBsnControllerConnection> connections = new ArrayList<OFBsnControllerConnection>();
-        connections.add(connection1);
-        connections.add(connection2);
-
-        OFBsnControllerConnectionsReply reply = factory.buildBsnControllerConnectionsReply()
-                .setConnections(connections)
-                .build();
-
-        sw.updateControllerConnections(reply);
-    }
-
-    /**
-     * This test ensures that the switch accurately determined if another master
-     * exists in the cluster by examining the controller connections it has.
-     */
-    @Test
-    public void testHasAnotherMaster() {
-        URI cokeUri = URIUtil.createURI("1.2.3.4", 6653);
-        InetSocketAddress address = (InetSocketAddress) sw.getConnection(OFAuxId.MAIN).getLocalInetAddress();
-        URI pepsiUri = URIUtil.createURI(address.getHostName(), address.getPort());
-
-        updateControllerConnections(sw, OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
-                                    OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
-
-        // From the perspective of pepsi, the cluster currently does NOT have another master controller
-        assertFalse(sw.hasAnotherMaster());
-
-        // Switch the controller connections so that pepsi is no longer master
-        updateControllerConnections(sw, OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
-                                    OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
-
-        // From the perspective of pepsi, the cluster currently has another master controller
-        assertTrue(sw.hasAnotherMaster());
-    }
+	protected OFSwitch sw;
+	protected OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+
+	@Before
+	public void setUp() throws Exception {
+		MockOFConnection mockConnection = new MockOFConnection(DatapathId.of(1), OFAuxId.MAIN);
+		sw = new OFSwitch(mockConnection, OFFactories.getFactory(OFVersion.OF_10),
+				EasyMock.createMock(IOFSwitchManager.class), DatapathId.of(1));
+	}
+
+	@Test
+	public void testSetHARoleReply() {
+		sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+		assertEquals(OFControllerRole.ROLE_MASTER, sw.getControllerRole());
+
+		sw.setControllerRole(OFControllerRole.ROLE_EQUAL);
+		assertEquals(OFControllerRole.ROLE_EQUAL, sw.getControllerRole());
+
+		sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+		assertEquals(OFControllerRole.ROLE_SLAVE, sw.getControllerRole());
+	}
+
+	@Test
+	public void testSubHandshake() {
+		OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+		OFMessage m = factory.buildNiciraControllerRoleReply()
+				.setXid(1)
+				.setRole(OFNiciraControllerRole.ROLE_MASTER)
+				.build();
+		// test exceptions before handshake is started
+		try {
+			sw.processDriverHandshakeMessage(m);
+			fail("expected exception not thrown");
+		} catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
+		try {
+			sw.isDriverHandshakeComplete();
+			fail("expected exception not thrown");
+		} catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
+
+		// start the handshake -- it should immediately complete
+		sw.startDriverHandshake();
+		assertTrue("Handshake should be complete",
+				sw.isDriverHandshakeComplete());
+
+		// test exceptions after handshake is completed
+		try {
+			sw.processDriverHandshakeMessage(m);
+			fail("expected exception not thrown");
+		} catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
+		try {
+			sw.startDriverHandshake();
+			fail("Expected exception not thrown");
+		} catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
+	}
+
+	/**
+	 * Helper to load controller connection messages into a switch for testing.
+	 * @param sw the switch to insert the message on
+	 * @param role the role for the controller connection message
+	 * @param state the state for the controller connection message
+	 * @param uri the URI for the controller connection message
+	 */
+	public void updateControllerConnections(IOFSwitchBackend sw, OFControllerRole role1, OFBsnControllerConnectionState state1, String uri1
+			,  OFControllerRole role2, OFBsnControllerConnectionState state2, String uri2) {
+		OFBsnControllerConnection connection1 = factory.buildBsnControllerConnection()
+				.setAuxiliaryId(OFAuxId.MAIN)
+				.setRole(role1)
+				.setState(state1)
+				.setUri(uri1)
+				.build();
+
+		OFBsnControllerConnection connection2 = factory.buildBsnControllerConnection()
+				.setAuxiliaryId(OFAuxId.MAIN)
+				.setRole(role2)
+				.setState(state2)
+				.setUri(uri2)
+				.build();
+
+		List<OFBsnControllerConnection> connections = new ArrayList<OFBsnControllerConnection>();
+		connections.add(connection1);
+		connections.add(connection2);
+
+		OFBsnControllerConnectionsReply reply = factory.buildBsnControllerConnectionsReply()
+				.setConnections(connections)
+				.build();
+
+		sw.updateControllerConnections(reply);
+	}
+
+	/**
+	 * This test ensures that the switch accurately determined if another master
+	 * exists in the cluster by examining the controller connections it has.
+	 */
+	@Test
+	public void testHasAnotherMaster() {
+		URI cokeUri = URIUtil.createURI("1.2.3.4", 6653);
+		InetSocketAddress address = (InetSocketAddress) sw.getConnection(OFAuxId.MAIN).getLocalInetAddress();
+		URI pepsiUri = URIUtil.createURI(address.getHostName(), address.getPort());
+
+		updateControllerConnections(sw, OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
+				OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
+
+		// From the perspective of pepsi, the cluster currently does NOT have another master controller
+		assertFalse(sw.hasAnotherMaster());
+
+		// Switch the controller connections so that pepsi is no longer master
+		updateControllerConnections(sw, OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
+				OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
+
+		// From the perspective of pepsi, the cluster currently has another master controller
+		assertTrue(sw.hasAnotherMaster());
+	}
 }
-- 
GitLab