@Override void processOFHello(OFHello m) throws IOException { /* * Brocade switches send a second hello after * the controller responds with its hello. This * might be to confirm the protocol version used, * but isn't defined in the OF specification. * * We will ignore such hello messages assuming * the version of the hello is correct according * to the algorithm in the spec. * * TODO Brocade also sets the XID of this second * hello as the same XID the controller used. * Checking for this might help to assure we're * really dealing with the situation we think * we are. */ if (m.getVersion().equals(factory.getVersion())) { log.warn("Ignoring second hello from {} in state {}. Might be a Brocade.", channel.remoteAddress(), state.toString()); } else { super.processOFHello(m); /* Versions don't match as they should; abort */ } }
/** * Send a hello message to the switch using the handshake transactions ids. * @throws IOException */ private void sendHelloMessage() throws IOException { // Send initial hello message OFHello.Builder builder = factory.buildHello(); /* Our highest-configured OFVersion does support version bitmaps, so include it */ if (factory.getVersion().compareTo(OFVersion.OF_13) >= 0) { List<OFHelloElem> he = new ArrayList<OFHelloElem>(); he.add(factory.buildHelloElemVersionbitmap() .setBitmaps(ofBitmaps) .build()); builder.setElements(he); } OFHello m = builder.setXid(handshakeTransactionIds--) .build(); write(m); log.debug("Send hello: {}", m); }
/** write a list of messages */ @Test(timeout = 5000) public void testMessageWriteList() throws InterruptedException, ExecutionException { Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList(); OFHello hello = factory.hello(ImmutableList.<OFHelloElem>of()); OFPacketOut packetOut = factory.buildPacketOut() .setData(new byte[] { 0x01, 0x02, 0x03, 0x04 }) .setActions(ImmutableList.<OFAction>of( factory.actions().output(OFPort.of(1), 0))) .build(); conn.write(ImmutableList.of(hello, packetOut)); eventLoop.runTasks(); assertThat("Write should have been written", cMsgList.hasCaptured(), equalTo(true)); List<OFMessage> value = cMsgList.getValue(); logger.info("Captured channel write: "+value); assertThat("Should have captured MsgList", cMsgList.getValue(), Matchers.<OFMessage> contains(hello, packetOut)); }
/** write a list of messages */ @Test(timeout = 5000) public void testMessageWriteList() throws InterruptedException, ExecutionException { Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList(); OFHello hello = factory.hello(ImmutableList.<OFHelloElem>of()); OFPacketOut packetOut = factory.buildPacketOut() .setData(new byte[] { 0x01, 0x02, 0x03, 0x04 }) .setActions(ImmutableList.<OFAction>of( factory.actions().output(OFPort.of(1), 0))) .build(); conn.write(ImmutableList.of(hello, packetOut)); assertThat("Write should have been written", cMsgList.hasCaptured(), equalTo(true)); List<OFMessage> value = cMsgList.getValue(); logger.info("Captured channel write: "+value); assertThat("Should have captured MsgList", cMsgList.getValue(), Matchers.<OFMessage> contains(hello, packetOut)); }
@Override void processOFHello(OFHello m) throws IOException { /* * Brocade switches send a second hello after * the controller responds with its hello. This * might be to confirm the protocol version used, * but isn't defined in the OF specification. * * We will ignore such hello messages assuming * the version of the hello is correct according * to the algorithm in the spec. * * TODO Brocade also sets the XID of this second * hello as the same XID the controller used. * Checking for this might help to assure we're * really dealing with the situation we think * we are. */ if (m.getVersion().equals(factory.getVersion())) { log.warn("Ignoring second hello from {} in state {}. Might be a Brocade.", channel.getRemoteAddress(), state.toString()); } else { super.processOFHello(m); /* Versions don't match as they should; abort */ } }
/** * Send a hello message to the switch using the handshake transactions ids. * @throws IOException */ private void sendHelloMessage() throws IOException { // Send initial hello message OFHello.Builder builder = factory.buildHello(); /* Our highest-configured OFVersion does support version bitmaps, so include it */ if (factory.getVersion().compareTo(OFVersion.OF_13) >= 0) { List<OFHelloElem> he = new ArrayList<OFHelloElem>(); he.add(factory.buildHelloElemVersionbitmap() .setBitmaps(ofBitmaps) .build()); builder.setElements(he); } OFHello m = builder.setXid(handshakeTransactionIds--) .build(); channel.write(Collections.singletonList(m)); log.debug("Send hello: {}", m); }
@Override void processOFHello(OFChannelHandler h, OFHello m) throws IOException { // TODO We could check for the optional bitmap, but for now // we are just checking the version number. if (m.getVersion() == OFVersion.OF_13) { log.info("Received {} Hello from {}", m.getVersion(), h.channel.getRemoteAddress()); h.ofVersion = OFVersion.OF_13; } else if (m.getVersion() == OFVersion.OF_10) { log.info("Received {} Hello from {} - switching to OF " + "version 1.0", m.getVersion(), h.channel.getRemoteAddress()); h.ofVersion = OFVersion.OF_10; } else { log.error("Received Hello of version {} from switch at {}. " + "This controller works with OF1.0 and OF1.3 " + "switches. Disconnecting switch ...", m.getVersion(), h.channel.getRemoteAddress()); h.channel.disconnect(); return; } h.sendHandshakeFeaturesRequestMessage(); h.setState(WAIT_FEATURES_REPLY); }
@Override void processOFHello(OFChannelHandler h, OFHello m) throws IOException { // TODO We could check for the optional bitmap, but for now // we are just checking the version number. if (m.getVersion().getWireVersion() >= OFVersion.OF_13.getWireVersion()) { log.debug("Received {} Hello from {} - switching to OF " + "version 1.3", m.getVersion(), h.channel.getRemoteAddress()); h.sendHandshakeHelloMessage(); h.ofVersion = OFVersion.OF_13; } else if (m.getVersion().getWireVersion() >= OFVersion.OF_10.getWireVersion()) { log.debug("Received {} Hello from {} - switching to OF " + "version 1.0", m.getVersion(), h.channel.getRemoteAddress()); OFHello hi = h.factory10.buildHello() .setXid(h.handshakeTransactionIds--) .build(); h.channel.write(Collections.singletonList(hi)); h.ofVersion = OFVersion.OF_10; } else { log.error("Received Hello of version {} from switch at {}. " + "This controller works with OF1.0 and OF1.3 " + "switches. Disconnecting switch ...", m.getVersion(), h.channel.getRemoteAddress()); h.channel.disconnect(); return; } h.sendHandshakeFeaturesRequestMessage(); h.setState(WAIT_FEATURES_REPLY); }
/** * Tests decoding a message. * * @throws Exception when an exception is thrown from the decoder */ @Test public void testDecode() throws Exception { OFMessageDecoder decoder = new OFMessageDecoder(); ChannelBuffer channelBuffer = getHelloMessageBuffer(); Object message = decoder.decode(new ChannelHandlerContextAdapter(), new ConnectedChannel(), channelBuffer); assertThat(message, notNullValue()); assertThat(message, instanceOf(OFHello.class)); }
@Override void processOFHello(OFHello m) throws IOException { OFVersion version = m.getVersion(); /* Choose the lower of the two supported versions. */ if (version.compareTo(factory.getVersion()) < 0) { factory = OFFactories.getFactory(version); } /* else The controller's version is < or = the switch's, so keep original controller factory. */ OFMessageDecoder decoder = pipeline.get(OFMessageDecoder.class); decoder.setVersion(version); setState(new WaitFeaturesReplyState()); }
/** * Send a hello message to the switch using the handshake transactions ids. * @throws IOException */ private void sendHelloMessage() throws IOException { // Send initial hello message // FIXME:LOJI: Haven't negotiated version yet, assume 1.3 OFHello.Builder builder = factory.buildHello() .setXid(handshakeTransactionIds--); // FIXME: Need to add code here to set the version bitmap hello element OFHello m = builder.build(); channel.write(Collections.singletonList(m)); log.debug("Send hello: {}", m); }
/** * @see org.jboss.netty.channel.SimpleChannelHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent event) throws Exception { logger.info("Channel connected."); Builder buildHello = factory.buildHello(); OFHello build = buildHello.build(); ctx.getChannel().write(build); }
@Override void processOFHello(OFChannelHandler h, OFHello m) throws IOException { // TODO We could check for the optional bitmap, but for now // we are just checking the version number. if (m.getVersion() == OFVersion.OF_13) { log.debug("Received {} Hello from {}", m.getVersion(), h.channel.getRemoteAddress()); h.sendHandshakeHelloMessage(); h.ofVersion = OFVersion.OF_13; } else if (m.getVersion() == OFVersion.OF_10) { log.debug("Received {} Hello from {} - switching to OF " + "version 1.0", m.getVersion(), h.channel.getRemoteAddress()); OFHello hi = h.factory10.buildHello() .setXid(h.handshakeTransactionIds--) .build(); h.channel.write(Collections.singletonList(hi)); h.ofVersion = OFVersion.OF_10; } else { log.error("Received Hello of version {} from switch at {}. " + "This controller works with OF1.0 and OF1.3 " + "switches. Disconnecting switch ...", m.getVersion(), h.channel.getRemoteAddress()); h.channel.disconnect(); return; } h.sendHandshakeFeaturesRequestMessage(); h.setState(WAIT_FEATURES_REPLY); }
/** * Process an OF message received on the channel and * update state accordingly. * * The main "event" of the state machine. Process the received message, * send follow up message if required and update state if required. * * Switches on the message type and calls more specific event handlers * for each individual OF message type. If we receive a message that * is supposed to be sent from a controller to a switch we throw * a SwitchStateExeption. * * The more specific handlers can also throw SwitchStateExceptions * * @param h The OFChannelHandler that received the message * @param m The message we received. * @throws SwitchStateException * @throws IOException */ void processOFMessage(OFMessage m) throws IOException { // Handle Channel Handshake if (!state.channelHandshakeComplete) { switch(m.getType()) { case HELLO: processOFHello((OFHello)m); break; case ERROR: processOFError((OFErrorMsg)m); break; case FEATURES_REPLY: processOFFeaturesReply((OFFeaturesReply)m); break; case EXPERIMENTER: processOFExperimenter((OFExperimenter)m); break; default: illegalMessageReceived(m); break; } } else{ switch(m.getType()){ // Always handle echos at the channel level! // Echos should only be sent in the complete. case ECHO_REPLY: processOFEchoReply((OFEchoReply)m); break; case ECHO_REQUEST: processOFEchoRequest((OFEchoRequest)m); break; // Send to SwitchManager and thus higher orders of control default: sendMessageToConnection(m); break; } } }
@Override void processOFHello(OFHello m) throws IOException { OFVersion version = m.getVersion(); factory = OFFactories.getFactory(version); OFMessageDecoder decoder = pipeline.get(OFMessageDecoder.class); decoder.setVersion(version); setState(new WaitFeaturesReplyState()); }
/** * Receive a container and process it, forwarding it onwards if required. * * @param incoming the channel the container was received upon * @param container the container being received */ public synchronized void receive(Channel incoming, Container container) { ProxyChannelType channelSource = (incoming == upstream ? ProxyChannelType.SWITCH : ProxyChannelType.CONTROLLER); ProxyChannelType channelDestination = (incoming != upstream ? ProxyChannelType.SWITCH : ProxyChannelType.CONTROLLER); /* Intercept echo replies which are destined for the proxy, and as such shouldn't be forwarded. */ if (container.getMessageType() == Type.OFPT_ECHO_REPLY) { OFEchoReply ofEchoReply = (OFEchoReply) container.getPacket(); if (Arrays.equals(ECHO_DATA, ofEchoReply.getData())) { channelDestination = ProxyChannelType.PROXY; } } /* Intercept the HELLO and record the OpenFlow version. */ if (container.getMessageType() == Type.OFPT_HELLO) { OFHello ofHello = (OFHello) container.getPacket(); if (channelSource == ProxyChannelType.SWITCH) { upstreamVersion = ofHello.getVersion(); } else { downstreamVersion = ofHello.getVersion(); } } /* Record the datapath ID if it passed through. */ if (container.getMessageType() == Type.OFPT_FEATURES_REPLY) { OFFeaturesReply ofFeaturesReply = (OFFeaturesReply) container.getPacket(); setDatapathId(ofFeaturesReply.getDatapathId().getBytes()); } log(channelSource, channelDestination, container); if (channelDestination != ProxyChannelType.PROXY) { send(channelSource, channelDestination, container); } }