/** Disconnect the switch from Beacon */ protected void disconnectSwitch(SelectionKey key, IOFSwitchExt sw) { /** * Must synchronize here to ensure we don't transition into active while simultaneously being * disconnected. */ synchronized (sw) { key.cancel(); OFStream stream = (OFStream) sw.getInputStream(); stream.getIOLoop().removeStream(stream); removeSwitch(sw); try { sw.getSocketChannel().socket().close(); } catch (IOException e1) { } this.initializerMap.remove(sw); if (!OFSwitchState.DISCONNECTED.equals(sw.getState())) { sw.transitionToState(OFSwitchState.DISCONNECTED); } log.info("Switch disconnected {}", sw); } }
protected void handleSwitchEvent(SelectionKey key, IOFSwitchExt sw) { OFStream out = ((OFStream) sw.getOutputStream()); OFStream in = (OFStream) sw.getInputStream(); try { /** * A key may not be valid here if it has been disconnected while it was in a select operation. */ if (!key.isValid()) return; if (key.isReadable()) { List<OFMessage> msgs = in.read(); if (msgs == null) { // graceful disconnect disconnectSwitch(key, sw); return; } sw.setLastReceivedMessageTime(System.currentTimeMillis()); handleMessages(sw, msgs); } if (key.isWritable()) { out.clearSelect(); key.interestOps(SelectionKey.OP_READ); } if (out.getWriteFailure()) { disconnectSwitch(key, sw); return; } } catch (IOException e) { // if we have an exception, disconnect the switch log.error("Exception during IOloop", e); disconnectSwitch(key, sw); } catch (CancelledKeyException e) { // if we have an exception, disconnect the switch log.error("Exception during IOloop", e); disconnectSwitch(key, sw); } }
/** * Checks all the switches to ensure they are still connected by sending an echo request and * receiving a response. */ protected void checkSwitchLiveness() { long now = System.currentTimeMillis(); log.trace("Liveness timer running"); for (Iterator<IOFSwitchExt> it = allSwitches.iterator(); it.hasNext(); ) { IOFSwitchExt sw = it.next(); long last = sw.getLastReceivedMessageTime(); SelectionKey key = ((OFStream) sw.getInputStream()).getKey(); if (now - last >= (2 * LIVENESS_TIMEOUT)) { log.info("Switch liveness timeout detected {}ms, disconnecting {}", now - last, sw); disconnectSwitch(key, sw); } else if (now - last >= LIVENESS_TIMEOUT) { // send echo OFEchoRequest echo = new OFEchoRequest(); try { sw.getOutputStream().write(echo); } catch (IOException e) { log.error("Failure sending liveness probe, disconnecting switch " + sw.toString(), e); disconnectSwitch(key, sw); } } } }
/** * Handle replies to certain OFMessages, and pass others off to listeners * * @param sw * @param msgs * @throws IOException */ @SuppressWarnings("unchecked") protected void handleMessages(IOFSwitchExt sw, List<OFMessage> msgs) throws IOException { for (OFMessage m : msgs) { // If we detect a write failure, break early so we can disconnect if (((OFStream) sw.getInputStream()).getWriteFailure()) { break; } // Always handle ECHO REQUESTS, regardless of state switch (m.getType()) { case ECHO_REQUEST: OFMessageInStream in = sw.getInputStream(); OFMessageOutStream out = sw.getOutputStream(); OFEchoReply reply = (OFEchoReply) in.getMessageFactory().getMessage(OFType.ECHO_REPLY); reply.setXid(m.getXid()); out.write(reply); break; case ECHO_REPLY: // *Note, ECHO REPLIES need no handling due to last message timestamp break; case ERROR: logError(sw, (OFError) m); // fall through intentionally so error can be listened for default: switch (sw.getState()) { case DISCONNECTED: log.info("Switch {} in state DISCONNECTED, exiting message processing loop", sw); return; case HELLO_SENT: if (m.getType() == OFType.HELLO) { log.debug("HELLO from {}", sw); sw.transitionToState(OFSwitchState.FEATURES_REQUEST_SENT); // Send initial Features Request sw.getOutputStream().write(factory.getMessage(OFType.FEATURES_REQUEST)); } break; case FEATURES_REQUEST_SENT: if (m.getType() == OFType.FEATURES_REPLY) { log.debug("Features Reply from {}", sw); sw.setFeaturesReply((OFFeaturesReply) m); // Send Description Statistics Request OFStatisticsRequest sr = new OFStatisticsRequest(); sr.setStatisticType(OFStatisticsType.DESC); sw.getOutputStream().write(sr); sw.transitionToState(OFSwitchState.DESCRIPTION_STATISTICS_REQUEST_SENT); } break; case DESCRIPTION_STATISTICS_REQUEST_SENT: if (m.getType() == OFType.STATS_REPLY) { OFStatisticsReply sr = (OFStatisticsReply) m; if (sr.getStatisticType() == OFStatisticsType.DESC && sr.getStatistics().size() > 0) { OFDescriptionStatistics desc = (OFDescriptionStatistics) sr.getStatistics().get(0); sw.setDescriptionStatistics(desc); log.debug("Description Statistics Reply from {}: {}", sw, desc); // Set config and request to receive the config OFSetConfig config = (OFSetConfig) factory.getMessage(OFType.SET_CONFIG); config.setMissSendLength((short) 0xffff).setLengthU(OFSetConfig.MINIMUM_LENGTH); sw.getOutputStream().write(config); sw.getOutputStream().write(factory.getMessage(OFType.BARRIER_REQUEST)); sw.getOutputStream().write(factory.getMessage(OFType.GET_CONFIG_REQUEST)); sw.transitionToState(OFSwitchState.GET_CONFIG_REQUEST_SENT); } } break; case GET_CONFIG_REQUEST_SENT: if (m.getType() == OFType.GET_CONFIG_REPLY) { OFGetConfigReply cr = (OFGetConfigReply) m; if (cr.getMissSendLength() == (short) 0xffff) { log.debug("Config Reply from {} confirms miss length set to 0xffff", sw); sw.transitionToState(OFSwitchState.INITIALIZING); CopyOnWriteArrayList<IOFInitializerListener> initializers = (CopyOnWriteArrayList<IOFInitializerListener>) initializerList.clone(); // Add all existing initializers to the list this.initializerMap.put(sw, initializers); log.debug( "Remaining initializers for switch {}: {}", sw, this.initializerMap.get(sw)); // Delete all pre-existing flows if (deletePreExistingFlows) { OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL); OFMessage fm = ((OFFlowMod) sw.getInputStream().getMessageFactory().getMessage(OFType.FLOW_MOD)) .setMatch(match) .setCommand(OFFlowMod.OFPFC_DELETE) .setOutPort(OFPort.OFPP_NONE) .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); sw.getOutputStream().write(fm); sw.getOutputStream().write(factory.getMessage(OFType.BARRIER_REQUEST)); } if (initializers.size() > 0) queueInitializer(sw, initializers.iterator().next()); else advanceInitializers(sw); } else { log.error( "Switch {} refused to set miss send length to 0xffff, disconnecting", sw); disconnectSwitch(((OFStream) sw.getInputStream()).getKey(), sw); return; } } break; case INITIALIZING: CopyOnWriteArrayList<IOFInitializerListener> initializers = initializerMap.get(sw); Iterator<IOFInitializerListener> it = initializers.iterator(); if (it.hasNext()) { IOFInitializerListener listener = it.next(); try { listener.initializerReceive(sw, m); } catch (Exception e) { log.error( "Error calling initializer listener: {} on switch: {} for message: {}, removing listener", new Object[] {listener, sw, m}); advanceInitializers(sw); } } break; case ACTIVE: List<IOFMessageListener> listeners = messageListeners.get(m.getType()); if (listeners != null) { for (IOFMessageListener listener : listeners) { try { if (listener instanceof IOFSwitchFilter) { if (!((IOFSwitchFilter) listener).isInterested(sw)) { continue; } } if (Command.STOP.equals(listener.receive(sw, m))) { break; } } catch (Exception e) { log.error( "Failure calling listener [" + listener.toString() + "] with message [" + m.toString() + "]", e); } } } else { log.debug("Unhandled OF Message: {} from {}", m, sw); } break; } // end switch(sw.getState()) } // end switch(m.getType()) } }