@Override public void startUp(FloodlightModuleContext context) { clearCurrentTopology(); // Initialize role to floodlight provider role. this.role = floodlightProvider.getRole(); ScheduledExecutorService ses = threadPool.getScheduledExecutor(); newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker()); if (role != Role.SLAVE) newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS); linkDiscovery.addListener(this); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addHAListener(this.haListener); addRestletRoutable(); }
/** * Send NX role request message to the switch requesting the specified * role. * * @param sw switch to send the role request message to * @param role role to request */ private int sendNxRoleRequest(Role role) throws IOException { int xid = sw.getNextTransactionId(); // Convert the role enum to the appropriate integer constant used // in the NX role request message int nxRole = role.toNxRole(); // Construct the role request message OFVendor roleRequest = (OFVendor)BasicFactory.getInstance() .getMessage(OFType.VENDOR); roleRequest.setXid(xid); roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID); OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData(); roleRequestData.setRole(nxRole); roleRequest.setVendorData(roleRequestData); roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH + roleRequestData.getLength()); // Send it to the switch sw.write(Collections.<OFMessage>singletonList(roleRequest), new FloodlightContext()); return xid; }
/** * Send a role request with the given role to the switch. * * Send a role request with the given role to the switch and update * the pending request and timestamp. * * @param role * @throws IOException */ synchronized void sendRoleRequest(Role role) throws IOException { /* * There are three cases to consider for SUPPORTS_NX_ROLE: * * 1) unset. We have neither received a role reply from the * switch nor has a request timed out. Send a request. * 2) TRUE: We've already send a request earlier and received * a reply. The switch supports role and we should send one. * 3) FALSE: We have already send a role and received an error. * The switch does not support roles. Don't send a role request, * set the switch's role directly. */ Boolean supportsNxRole = (Boolean) sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE); if ((supportsNxRole != null) && !supportsNxRole) { setSwitchRole(role, RoleRecvStatus.UNSUPPORTED); } else { pendingXid = sendNxRoleRequest(role); pendingRole = role; roleSubmitTime = System.currentTimeMillis(); requestPending = true; } }
@Override @LogMessageDoc(level="WARN", message="Received PacketIn from switch {} while" + "being slave. Reasserting slave role.", explanation="The switch has receive a PacketIn despite being " + "in slave role indicating inconsistent controller roles", recommendation="This situation can occurs transiently during role" + " changes. If, however, the condition persists or happens" + " frequently this indicates a role inconsistency. " + LogMessageDoc.CHECK_CONTROLLER ) void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException { // we don't expect packetIn while slave, reassert we are slave h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush(); log.warn("Received PacketIn from switch {} while" + "being slave. Reasserting slave role.", h.sw); h.controller.reassertRole(h, Role.SLAVE); }
/** * Extract the role from an OFVendor message. * * Extract the role from an OFVendor message if the message is a * Nicira role reply. Otherwise return null. * * @param h The channel handler receiving the message * @param vendorMessage The vendor message to parse. * @return The role in the message if the message is a Nicira role * reply, null otherwise. * @throws SwitchStateException If the message is a Nicira role reply * but the numeric role value is unknown. * FIXME: The message parser should make sure that the Nicira role is * actually valid. Why do we need to take care of it ?!? */ protected Role extractNiciraRoleReply(OFChannelHandler h, OFVendor vendorMessage) { int vendor = vendorMessage.getVendor(); if (vendor != OFNiciraVendorData.NX_VENDOR_ID) return null; if (! (vendorMessage.getVendorData() instanceof OFRoleReplyVendorData)) return null; OFRoleReplyVendorData roleReplyVendorData = (OFRoleReplyVendorData) vendorMessage.getVendorData(); Role role = Role.fromNxRole(roleReplyVendorData.getRole()); if (role == null) { String msg = String.format("Switch: [%s], State: [%s], " + "received NX_ROLE_REPLY with invalid role " + "value %d", h.getSwitchInfoString(), this.toString(), roleReplyVendorData.getRole()); throw new SwitchStateException(msg); } return role; }
/** * Test interaction with OFChannelHandler when the current role is * master. */ @Test public void testChannelHandlerMaster() { OFChannelHandler h = createMock(OFChannelHandler.class); // Add the handler. The controller should call sendRoleRequest h.sendRoleRequest(Role.MASTER); expectLastCall().once(); replay(h); controller.addSwitchChannelAndSendInitialRole(h); verify(h); // Reassert the role. reset(h); h.sendRoleRequestIfNotPending(Role.MASTER); replay(h); controller.reassertRole(h, Role.MASTER); verify(h); // reassert a different role: no-op reset(h); replay(h); controller.reassertRole(h, Role.SLAVE); verify(h); }
/** * Setup the mock switch and write capture for a role request, set the * role and verify mocks. * @param supportsNxRole whether the switch supports role request messages * to setup the attribute. This must be null (don't yet know if roles * supported: send to check) or true. * @param xid The xid to use in the role request * @param role The role to send * @throws IOException */ private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole, int xid, Role role) throws IOException { assertTrue("This internal test helper method most not be called " + "with supportsNxRole==false. Test setup broken", supportsNxRole == null || supportsNxRole == true); reset(sw); expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(supportsNxRole).atLeastOnce(); expect(sw.getNextTransactionId()).andReturn(xid).once(); sw.write(capture(writeCapture), EasyMock.<FloodlightContext>anyObject()); expectLastCall().anyTimes(); replay(sw); handler.sendRoleRequest(role); List<OFMessage> msgs = getMessagesFromCapture(); assertEquals(1, msgs.size()); verifyRoleRequest(msgs.get(0), xid, role); verify(sw); }
/** Move channel from scratch to WAIT_INITIAL_STATE, then MASTER, * then SLAVE for cases where the switch does not support roles. * I.e., the final SLAVE transition should disconnect the switch. */ @Test public void testNoRoleInitialToMasterToSlave() throws Exception { int xid = 46; // First, lets move the state to MASTER without role support testInitialMoveToMasterNoRole(); assertEquals(OFChannelHandler.ChannelState.MASTER, handler.getStateForTesting()); // try to set master role again. should be a no-op setupSwitchRoleChangeUnsupported(xid, Role.MASTER); assertEquals(OFChannelHandler.ChannelState.MASTER, handler.getStateForTesting()); setupSwitchRoleChangeUnsupported(xid, Role.SLAVE); assertEquals(OFChannelHandler.ChannelState.SLAVE, handler.getStateForTesting()); }
/** * Test re-assert MASTER * */ @Test public void testReassertMaster() throws Exception { testInitialMoveToMasterWithRole(); OFError err = (OFError) BasicFactory.getInstance().getMessage(OFType.ERROR); err.setXid(42); err.setErrorType(OFErrorType.OFPET_BAD_REQUEST); err.setErrorCode(OFBadRequestCode.OFPBRC_EPERM); reset(controller); controller.reassertRole(handler, Role.MASTER); expectLastCall().once(); controller.handleMessage(sw, err, null); expectLastCall().once(); sendMessageToHandlerNoControllerReset( Collections.<OFMessage>singletonList(err)); verify(sw); verify(controller); }
@Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case MASTER: if (oldRole == Role.SLAVE) { log.debug("Re-reading static flows from storage due " + "to HA change from SLAVE->MASTER"); entriesFromStorage = readEntriesFromStorage(); entry2dpid = computeEntry2DpidMap(entriesFromStorage); } break; case SLAVE: log.debug("Clearing in-memory flows due to " + "HA change to SLAVE"); entry2dpid.clear(); entriesFromStorage.clear(); break; default: break; } }
@Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case MASTER: if (oldRole == Role.SLAVE) { log.debug("Re-computing topology due " + "to HA change from SLAVE->MASTER"); newInstanceTask.reschedule(1, TimeUnit.MILLISECONDS); } break; case SLAVE: log.debug("Clearing topology due to " + "HA change to SLAVE"); clearCurrentTopology(); break; default: break; } }
@Test public void testDeliverRoleReplyOk() { // test normal case PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleReply(pending.xid, pending.role); verify(sw.channel); assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(pending.role, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testDeliverRoleReplyOkRepeated() { // test normal case. Not the first role reply PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleReply(pending.xid, pending.role); verify(sw.channel); assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(pending.role, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testDeliverRoleReplyWrongXid() { // wrong xid received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleReply(pending.xid+1, pending.role); verify(sw.channel); assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testDeliverRoleReplyWrongRole() { // correct xid but incorrect role received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleReply(pending.xid, Role.SLAVE); verify(sw.channel); assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testDeliverRoleRequestNotSupported () { // normal case. xid is pending PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.role = Role.SLAVE; sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleRequestNotSupported(pending.xid); verify(sw.channel); assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(null, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testDeliverRoleRequestNotSupportedWrongXid() { // wrong xid received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.role = Role.SLAVE; sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleRequestNotSupported(pending.xid+1); verify(sw.channel); assertEquals(null, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); }
@Test public void testSetRole() { controller.connectedSwitches.add(new OFSwitchImpl()); RoleChanger roleChanger = createMock(RoleChanger.class); roleChanger.submitRequest(controller.connectedSwitches, Role.SLAVE); controller.roleChanger = roleChanger; assertEquals("Check that update queue is empty", 0, controller.updates.size()); replay(roleChanger); controller.setRole(Role.SLAVE); verify(roleChanger); Controller.IUpdate upd = controller.updates.poll(); assertNotNull("Check that update queue has an update", upd); assertTrue("Check that update is HARoleUpdate", upd instanceof Controller.HARoleUpdate); Controller.HARoleUpdate roleUpd = (Controller.HARoleUpdate)upd; assertSame(null, roleUpd.oldRole); assertSame(Role.SLAVE, roleUpd.newRole); }
/** First role reply message received: transition from slave to master */ @Test public void testNiciraRoleReplySlave2MasterFristTime() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.sw.clearAllFlowMods(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); }
/** Not first role reply message received: transition from slave to master */ @Test public void testNiciraRoleReplySlave2MasterNotFristTime() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.state.firstRoleReplyReceived = true; // Flow table shouldn't be wipe replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); }
/** transition from slave to equal */ @Test public void testNiciraRoleReplySlave2Equal() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_OTHER); chdlr.sw.deliverRoleReply(xid, Role.EQUAL); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.sw.clearAllFlowMods(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); }
@Test /** Slave2Slave transition ==> no change */ public void testNiciraRoleReplySlave2Slave() throws Exception{ int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_SLAVE); chdlr.sw.deliverRoleReply(xid, Role.SLAVE); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); expect(chdlr.sw.isActive()).andReturn(false); // don't add switch to activeSwitches ==> slave2slave chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); }
@Test /** Equal2Master transition ==> no change */ public void testNiciraRoleReplyEqual2Master() throws Exception{ int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); expect(chdlr.sw.isActive()).andReturn(true); controller.activeSwitches.put(1L, chdlr.sw); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); }
@Test public void testNiciraRoleReplyMaster2Slave() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_SLAVE); chdlr.sw.deliverRoleReply(xid, Role.SLAVE); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); controller.activeSwitches.put(1L, chdlr.sw); expect(chdlr.sw.isActive()).andReturn(false); expect(chdlr.sw.isConnected()).andReturn(true); chdlr.sw.cancelAllStatisticsReplies(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); }
/** * Send a role request for SLAVE to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestSlaveNotSupported() { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1, channel1); roleChanger.sendRoleRequest(switches, Role.SLAVE, 123456); verify(sw1, channel1); // sendRoleRequest needs to remove the switch from the list since // it closed its connection assertTrue(switches.isEmpty()); }
/** * Send a role request for MASTER to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestMasterNotSupported() { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertEquals(1, switches.size()); }
/** * Send a role request a switch that supports it and one that * hasn't had a role request send to it yet */ @Test public void testSendRoleRequestErrorHandling () throws Exception { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)) .andThrow(new IOException()).once(); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertTrue(switches.isEmpty()); }
@Override public void transitionToMaster() { if (log.isTraceEnabled()) { log.trace("Sending LLDPs " + "to HA change from SLAVE->MASTER"); } LinkDiscoveryManager.this.role = Role.MASTER; clearAllLinks(); readTopologyConfigFromStorage(); log.debug("Role Change to Master: Rescheduling discovery task."); discoveryTask.reschedule(1, TimeUnit.MICROSECONDS); }
@Override public void run() { try { if (ldUpdates.peek() != null) updateTopology(); handleMiscellaneousPeriodicEvents(); } catch (Exception e) { log.error("Error in topology instance task thread", e); } finally { if (floodlightProvider.getRole() != Role.SLAVE) newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS); } }
@Override public void transitionToMaster() { role = Role.MASTER; log.debug("Re-computing topology due " + "to HA change from SLAVE->MASTER"); newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS); }
public void informListeners(List<LDUpdate> linkUpdates) { if (role != null && role != Role.MASTER) return; for(int i=0; i<topologyAware.size(); ++i) { ITopologyListener listener = topologyAware.get(i); listener.topologyChanged(linkUpdates); } }