2  * Copyright 2014-2015 Open Networking Laboratory
 
   4  * Licensed under the Apache License, Version 2.0 (the "License");
 
   5  * you may not use this file except in compliance with the License.
 
   6  * You may obtain a copy of the License at
 
   8  *     http://www.apache.org/licenses/LICENSE-2.0
 
  10  * Unless required by applicable law or agreed to in writing, software
 
  11  * distributed under the License is distributed on an "AS IS" BASIS,
 
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  13  * See the License for the specific language governing permissions and
 
  14  * limitations under the License.
 
  18 package org.onosproject.openflow.controller.impl;
 
  20 import java.io.IOException;
 
  21 import java.nio.channels.ClosedChannelException;
 
  22 import java.util.ArrayList;
 
  23 import java.util.Collections;
 
  24 import java.util.List;
 
  25 import java.util.concurrent.CopyOnWriteArrayList;
 
  26 import java.util.concurrent.RejectedExecutionException;
 
  28 import org.jboss.netty.channel.Channel;
 
  29 import org.jboss.netty.channel.ChannelHandlerContext;
 
  30 import org.jboss.netty.channel.ChannelStateEvent;
 
  31 import org.jboss.netty.channel.ExceptionEvent;
 
  32 import org.jboss.netty.channel.MessageEvent;
 
  33 import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
 
  34 import org.jboss.netty.handler.timeout.IdleStateEvent;
 
  35 import org.jboss.netty.handler.timeout.ReadTimeoutException;
 
  36 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
 
  37 import org.onosproject.openflow.controller.driver.SwitchStateException;
 
  38 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
  39 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
 
  40 import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
 
  41 import org.projectfloodlight.openflow.protocol.OFBarrierReply;
 
  42 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 
  43 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 
  44 import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
 
  45 import org.projectfloodlight.openflow.protocol.OFEchoReply;
 
  46 import org.projectfloodlight.openflow.protocol.OFEchoRequest;
 
  47 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 
  48 import org.projectfloodlight.openflow.protocol.OFErrorType;
 
  49 import org.projectfloodlight.openflow.protocol.OFExperimenter;
 
  50 import org.projectfloodlight.openflow.protocol.OFFactory;
 
  51 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
 
  52 import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
 
  53 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 
  54 import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
 
  55 import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
 
  56 import org.projectfloodlight.openflow.protocol.OFHello;
 
  57 import org.projectfloodlight.openflow.protocol.OFHelloElem;
 
  58 import org.projectfloodlight.openflow.protocol.OFMessage;
 
  59 import org.projectfloodlight.openflow.protocol.OFPacketIn;
 
  60 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
 
  61 import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
 
  62 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 
  63 import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
 
  64 import org.projectfloodlight.openflow.protocol.OFRoleReply;
 
  65 import org.projectfloodlight.openflow.protocol.OFSetConfig;
 
  66 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 
  67 import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
 
  68 import org.projectfloodlight.openflow.protocol.OFStatsType;
 
  69 import org.projectfloodlight.openflow.protocol.OFType;
 
  70 import org.projectfloodlight.openflow.protocol.OFVersion;
 
  71 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
 
  72 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
 
  73 import org.projectfloodlight.openflow.types.U32;
 
  74 import org.slf4j.Logger;
 
  75 import org.slf4j.LoggerFactory;
 
  78  * Channel handler deals with the switch connection and dispatches
 
  79  * switch messages to the appropriate locations.
 
  81 class OFChannelHandler extends IdleStateAwareChannelHandler {
 
  82     private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
 
  84     private static final String RESET_BY_PEER = "Connection reset by peer";
 
  85     private static final String BROKEN_PIPE = "Broken pipe";
 
  87     private final Controller controller;
 
  88     private OpenFlowSwitchDriver sw;
 
  89     private long thisdpid; // channelHandler cached value of connected switch id
 
  90     private Channel channel;
 
  91     // State needs to be volatile because the HandshakeTimeoutHandler
 
  92     // needs to check if the handshake is complete
 
  93     private volatile ChannelState state;
 
  95     // When a switch with a duplicate dpid is found (i.e we already have a
 
  96     // connected switch with the same dpid), the new switch is immediately
 
  97     // disconnected. At that point netty callsback channelDisconnected() which
 
  98     // proceeds to cleaup switch state - we need to ensure that it does not cleanup
 
  99     // switch state for the older (still connected) switch
 
 100     private volatile Boolean duplicateDpidFound;
 
 102     // Temporary storage for switch-features and port-description
 
 103     private OFFeaturesReply featuresReply;
 
 104     private List<OFPortDescStatsReply> portDescReplies;
 
 105     //private OFPortDescStatsReply portDescReply;
 
 106     // a concurrent ArrayList to temporarily store port status messages
 
 107     // before we are ready to deal with them
 
 108     private final CopyOnWriteArrayList<OFPortStatus> pendingPortStatusMsg;
 
 110     //Indicates the openflow version used by this switch
 
 111     protected OFVersion ofVersion;
 
 112     protected OFFactory factory13;
 
 113     protected OFFactory factory10;
 
 115     /** transaction Ids to use during handshake. Since only one thread
 
 116      * calls into an OFChannelHandler instance, we don't need atomic.
 
 119     private int handshakeTransactionIds = -1;
 
 122      * Create a new unconnected OFChannelHandler.
 
 123      * @param controller parent controller
 
 125     OFChannelHandler(Controller controller) {
 
 126         this.controller = controller;
 
 127         this.state = ChannelState.INIT;
 
 128         this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
 
 129         this.portDescReplies = new ArrayList<OFPortDescStatsReply>();
 
 130         factory13 = controller.getOFMessageFactory13();
 
 131         factory10 = controller.getOFMessageFactory10();
 
 132         duplicateDpidFound = Boolean.FALSE;
 
 137     // XXX S consider if necessary
 
 138     public void disconnectSwitch() {
 
 139         sw.disconnectSwitch();
 
 144     //*************************
 
 145     //  Channel State Machine
 
 146     //*************************
 
 149      * The state machine for handling the switch/channel state. All state
 
 150      * transitions should happen from within the state machine (and not from other
 
 155          * Initial state before channel is connected.
 
 159             void processOFMessage(OFChannelHandler h, OFMessage m)
 
 160                     throws IOException, SwitchStateException {
 
 161                 illegalMessageReceived(h, m);
 
 165             void processOFError(OFChannelHandler h, OFErrorMsg m)
 
 167                 // need to implement since its abstract but it will never
 
 172             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 174                 unhandledMessageReceived(h, m);
 
 179          * We send a OF 1.3 HELLO to the switch and wait for a Hello from the switch.
 
 180          * Once we receive the reply, we decide on OF 1.3 or 1.0 switch - no other
 
 181          * protocol version is accepted.
 
 182          * We send an OFFeaturesRequest depending on the protocol version selected
 
 183          * Next state is WAIT_FEATURES_REPLY
 
 187             void processOFHello(OFChannelHandler h, OFHello m)
 
 189                 // TODO We could check for the optional bitmap, but for now
 
 190                 // we are just checking the version number.
 
 191                 if (m.getVersion().getWireVersion() >= OFVersion.OF_13.getWireVersion()) {
 
 192                     log.debug("Received {} Hello from {} - switching to OF "
 
 193                             + "version 1.3", m.getVersion(),
 
 194                             h.channel.getRemoteAddress());
 
 195                     h.sendHandshakeHelloMessage();
 
 196                     h.ofVersion = OFVersion.OF_13;
 
 197                 } else if (m.getVersion().getWireVersion() >= OFVersion.OF_10.getWireVersion()) {
 
 198                     log.debug("Received {} Hello from {} - switching to OF "
 
 199                             + "version 1.0", m.getVersion(),
 
 200                             h.channel.getRemoteAddress());
 
 202                             h.factory10.buildHello()
 
 203                                     .setXid(h.handshakeTransactionIds--)
 
 205                     h.channel.write(Collections.singletonList(hi));
 
 206                     h.ofVersion = OFVersion.OF_10;
 
 208                     log.error("Received Hello of version {} from switch at {}. "
 
 209                             + "This controller works with OF1.0 and OF1.3 "
 
 210                             + "switches. Disconnecting switch ...",
 
 211                             m.getVersion(), h.channel.getRemoteAddress());
 
 212                     h.channel.disconnect();
 
 215                 h.sendHandshakeFeaturesRequestMessage();
 
 216                 h.setState(WAIT_FEATURES_REPLY);
 
 219             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
 
 220                     throws IOException, SwitchStateException {
 
 221                 illegalMessageReceived(h, m);
 
 224             void processOFStatisticsReply(OFChannelHandler h,
 
 226                             throws IOException, SwitchStateException {
 
 227                 illegalMessageReceived(h, m);
 
 230             void processOFError(OFChannelHandler h, OFErrorMsg m) {
 
 231                 logErrorDisconnect(h, m);
 
 235             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 237                 unhandledMessageReceived(h, m);
 
 243          * We are waiting for a features reply message. Once we receive it, the
 
 244          * behavior depends on whether this is a 1.0 or 1.3 switch. For 1.0,
 
 245          * we send a SetConfig request, barrier, and GetConfig request and the
 
 246          * next state is WAIT_CONFIG_REPLY. For 1.3, we send a Port description
 
 247          * request and the next state is WAIT_PORT_DESC_REPLY.
 
 249         WAIT_FEATURES_REPLY(false) {
 
 251             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
 
 253                 h.thisdpid = m.getDatapathId().getLong();
 
 254                 log.debug("Received features reply for switch at {} with dpid {}",
 
 255                         h.getSwitchInfoString(), h.thisdpid);
 
 257                 h.featuresReply = m; //temp store
 
 258                 if (h.ofVersion == OFVersion.OF_10) {
 
 259                     h.sendHandshakeSetConfig();
 
 260                     h.setState(WAIT_CONFIG_REPLY);
 
 262                     //version is 1.3, must get switchport information
 
 263                     h.sendHandshakeOFPortDescRequest();
 
 264                     h.setState(WAIT_PORT_DESC_REPLY);
 
 268             void processOFStatisticsReply(OFChannelHandler h,
 
 270                             throws IOException, SwitchStateException {
 
 271                 illegalMessageReceived(h, m);
 
 274             void processOFError(OFChannelHandler h, OFErrorMsg m) {
 
 275                 logErrorDisconnect(h, m);
 
 279             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 281                 h.pendingPortStatusMsg.add(m);
 
 286          * We are waiting for a description of the 1.3 switch ports.
 
 287          * Once received, we send a SetConfig request
 
 288          * Next State is WAIT_CONFIG_REPLY
 
 290         WAIT_PORT_DESC_REPLY(false) {
 
 293             void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
 
 294                     throws SwitchStateException {
 
 295                 // Read port description
 
 296                 if (m.getStatsType() != OFStatsType.PORT_DESC) {
 
 297                     log.warn("Expecting port description stats but received stats "
 
 298                             + "type {} from {}. Ignoring ...", m.getStatsType(),
 
 299                             h.channel.getRemoteAddress());
 
 302                 if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
 
 303                     log.debug("Stats reply indicates more stats from sw {} for "
 
 304                             + "port description",
 
 305                             h.getSwitchInfoString());
 
 306                     h.portDescReplies.add((OFPortDescStatsReply)m);
 
 310                     h.portDescReplies.add((OFPortDescStatsReply)m);
 
 312                 //h.portDescReply = (OFPortDescStatsReply) m; // temp store
 
 313                 log.info("Received port desc reply for switch at {}",
 
 314                         h.getSwitchInfoString());
 
 316                     h.sendHandshakeSetConfig();
 
 317                 } catch (IOException e) {
 
 318                     log.error("Unable to send setConfig after PortDescReply. "
 
 319                             + "Error: {}", e.getMessage());
 
 321                 h.setState(WAIT_CONFIG_REPLY);
 
 325             void processOFError(OFChannelHandler h, OFErrorMsg m)
 
 326                     throws IOException, SwitchStateException {
 
 327                 logErrorDisconnect(h, m);
 
 332             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 333                     throws IOException, SwitchStateException {
 
 334                 h.pendingPortStatusMsg.add(m);
 
 340          * We are waiting for a config reply message. Once we receive it
 
 341          * we send a DescriptionStatsRequest to the switch.
 
 342          * Next state: WAIT_DESCRIPTION_STAT_REPLY
 
 344         WAIT_CONFIG_REPLY(false) {
 
 346             void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
 
 348                 if (m.getMissSendLen() == 0xffff) {
 
 349                     log.trace("Config Reply from switch {} confirms "
 
 350                             + "miss length set to 0xffff",
 
 351                             h.getSwitchInfoString());
 
 353                     // FIXME: we can't really deal with switches that don't send
 
 354                     // full packets. Shouldn't we drop the connection here?
 
 355                     log.warn("Config Reply from switch {} has"
 
 356                             + "miss length set to {}",
 
 357                             h.getSwitchInfoString(),
 
 360                 h.sendHandshakeDescriptionStatsRequest();
 
 361                 h.setState(WAIT_DESCRIPTION_STAT_REPLY);
 
 365             void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
 
 370             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
 
 371                     throws IOException, SwitchStateException {
 
 372                 illegalMessageReceived(h, m);
 
 375             void processOFStatisticsReply(OFChannelHandler h,
 
 377                             throws IOException, SwitchStateException {
 
 378                 log.error("Received multipart(stats) message sub-type {}",
 
 380                 illegalMessageReceived(h, m);
 
 384             void processOFError(OFChannelHandler h, OFErrorMsg m) {
 
 385                 logErrorDisconnect(h, m);
 
 389             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 391                 h.pendingPortStatusMsg.add(m);
 
 397          * We are waiting for a OFDescriptionStat message from the switch.
 
 398          * Once we receive any stat message we try to parse it. If it's not
 
 399          * a description stats message we disconnect. If its the expected
 
 400          * description stats message, we:
 
 401          *    - use the switch driver to bind the switch and get an IOFSwitch instance
 
 402          *    - setup the IOFSwitch instance
 
 403          *    - add switch controller and send the initial role
 
 404          *      request to the switch.
 
 405          * Next state: WAIT_INITIAL_ROLE
 
 406          *      In the typical case, where switches support role request messages
 
 407          *      the next state is where we expect the role reply message.
 
 408          *      In the special case that where the switch does not support any kind
 
 409          *      of role request messages, we don't send a role message, but we do
 
 410          *      request mastership from the registry service. This controller
 
 411          *      should become master once we hear back from the registry service.
 
 412          * All following states will have a h.sw instance!
 
 414         WAIT_DESCRIPTION_STAT_REPLY(false) {
 
 416             void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
 
 417                     throws SwitchStateException {
 
 418                 // Read description, if it has been updated
 
 419                 if (m.getStatsType() != OFStatsType.DESC) {
 
 420                     log.warn("Expecting Description stats but received stats "
 
 421                             + "type {} from {}. Ignoring ...", m.getStatsType(),
 
 422                             h.channel.getRemoteAddress());
 
 425                 OFDescStatsReply drep = (OFDescStatsReply) m;
 
 426                 log.info("Received switch description reply {} from switch at {}",
 
 427                          drep, h.channel.getRemoteAddress());
 
 428                 // Here is where we differentiate between different kinds of switches
 
 429                 h.sw = h.controller.getOFSwitchInstance(h.thisdpid, drep, h.ofVersion);
 
 431                 h.sw.setOFVersion(h.ofVersion);
 
 432                 h.sw.setFeaturesReply(h.featuresReply);
 
 433                 //h.sw.setPortDescReply(h.portDescReply);
 
 434                 h.sw.setPortDescReplies(h.portDescReplies);
 
 435                 h.sw.setConnected(true);
 
 436                 h.sw.setChannel(h.channel);
 
 437 //                boolean success = h.sw.connectSwitch();
 
 440 //                    disconnectDuplicate(h);
 
 443                 // set switch information
 
 447                 log.debug("Switch {} bound to class {}, description {}",
 
 448                         new Object[] {h.sw, h.sw.getClass(), drep });
 
 449                 //Put switch in EQUAL mode until we hear back from the global registry
 
 450                 //log.debug("Setting new switch {} to EQUAL and sending Role request",
 
 451                 //        h.sw.getStringId());
 
 452                 //h.sw.activateEqualSwitch();
 
 453                 //h.setSwitchRole(RoleState.EQUAL);
 
 455                 h.sw.startDriverHandshake();
 
 456                 if (h.sw.isDriverHandshakeComplete()) {
 
 457                     if (!h.sw.connectSwitch()) {
 
 458                         disconnectDuplicate(h);
 
 460                     handlePendingPortStatusMessages(h);
 
 463                     h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
 
 469             void processOFError(OFChannelHandler h, OFErrorMsg m) {
 
 470                 logErrorDisconnect(h, m);
 
 474             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
 
 475                     throws IOException, SwitchStateException {
 
 476                 illegalMessageReceived(h, m);
 
 480             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 482                 h.pendingPortStatusMsg.add(m);
 
 488          * We are waiting for the respective switch driver to complete its
 
 489          * configuration. Notice that we do not consider this to be part of the main
 
 490          * switch-controller handshake. But we do consider it as a step that comes
 
 491          * before we declare the switch as available to the controller.
 
 492          * Next State: depends on the role of this controller for this switch - either
 
 495         WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
 
 498             void processOFError(OFChannelHandler h, OFErrorMsg m)
 
 500                 // will never be called. We override processOFMessage
 
 506             void processOFMessage(OFChannelHandler h, OFMessage m)
 
 507                     throws IOException, SwitchStateException {
 
 509                 if (h.sw.isDriverHandshakeComplete()) {
 
 511                     h.state.processOFMessage(h, m);
 
 516                 if (m.getType() == OFType.ECHO_REQUEST) {
 
 517                     processOFEchoRequest(h, (OFEchoRequest) m);
 
 518                 } else if (m.getType() == OFType.ECHO_REPLY) {
 
 519                     processOFEchoReply(h, (OFEchoReply) m);
 
 520                 } else if (m.getType() == OFType.ROLE_REPLY) {
 
 522                 } else if (m.getType() == OFType.ERROR) {
 
 523                     if (!h.sw.handleRoleError((OFErrorMsg)m)) {
 
 524                         h.sw.processDriverHandshakeMessage(m);
 
 525                         if (h.sw.isDriverHandshakeComplete()) {
 
 530                     if (m.getType() == OFType.EXPERIMENTER &&
 
 531                             ((OFExperimenter) m).getExperimenter() ==
 
 532                             RoleManager.NICIRA_EXPERIMENTER) {
 
 533                         h.sw.handleNiciraRole(m);
 
 535                         h.sw.processDriverHandshakeMessage(m);
 
 536                         if (h.sw.isDriverHandshakeComplete()) {
 
 544             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 545                     throws IOException, SwitchStateException {
 
 546                 h.pendingPortStatusMsg.add(m);
 
 549             private void moveToActive(OFChannelHandler h) {
 
 550                 boolean success = h.sw.connectSwitch();
 
 551                 handlePendingPortStatusMessages(h);
 
 554                     disconnectDuplicate(h);
 
 562          * This controller is in MASTER role for this switch. We enter this state
 
 563          * after requesting and winning control from the global registry.
 
 564          * The main handshake as well as the switch-driver sub-handshake
 
 565          * is complete at this point.
 
 566          * // XXX S reconsider below
 
 567          * In the (near) future we may deterministically assign controllers to
 
 568          * switches at startup.
 
 569          * We only leave this state if the switch disconnects or
 
 570          * if we send a role request for SLAVE /and/ receive the role reply for
 
 575             void processOFError(OFChannelHandler h, OFErrorMsg m)
 
 576                     throws IOException, SwitchStateException {
 
 577                 // if we get here, then the error message is for something else
 
 578                 if (m.getErrType() == OFErrorType.BAD_REQUEST &&
 
 579                         ((OFBadRequestErrorMsg) m).getCode() ==
 
 580                         OFBadRequestCode.EPERM) {
 
 581                     // We are the master controller and the switch returned
 
 582                     // a permission error. This is a likely indicator that
 
 583                     // the switch thinks we are slave. Reassert our
 
 585                     // FIXME: this could be really bad during role transitions
 
 586                     // if two controllers are master (even if its only for
 
 587                     // a brief period). We might need to see if these errors
 
 588                     // persist before we reassert
 
 591                 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
 
 592                         ((OFFlowModFailedErrorMsg) m).getCode() ==
 
 593                         OFFlowModFailedCode.ALL_TABLES_FULL) {
 
 594                     h.sw.setTableFull(true);
 
 598                 h.dispatchMessage(m);
 
 602             void processOFStatisticsReply(OFChannelHandler h,
 
 604                 if (m.getStatsType().equals(OFStatsType.PORT_DESC)) {
 
 605                     h.sw.setPortDescReply((OFPortDescStatsReply) m);
 
 607                 h.dispatchMessage(m);
 
 611             void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
 
 612                     throws SwitchStateException {
 
 613                 h.sw.handleNiciraRole(m);
 
 617             void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
 
 618                     throws SwitchStateException {
 
 623             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
 624                     throws SwitchStateException {
 
 625                 handlePortStatusMessage(h, m, true);
 
 626                 //h.dispatchMessage(m);
 
 630             void processOFPacketIn(OFChannelHandler h, OFPacketIn m) {
 
 632 //                        h.sw.factory().buildPacketOut()
 
 633 //                                .setXid(m.getXid())
 
 634 //                                .setBufferId(m.getBufferId()).build();
 
 635 //                h.sw.sendMsg(out);
 
 636                 h.dispatchMessage(m);
 
 640             void processOFFlowRemoved(OFChannelHandler h,
 
 642                 h.dispatchMessage(m);
 
 646             void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
 
 647                 h.dispatchMessage(m);
 
 651             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m) {
 
 652                 h.sw.setFeaturesReply(m);
 
 653                 h.dispatchMessage(m);
 
 658         private final boolean handshakeComplete;
 
 659         ChannelState(boolean handshakeComplete) {
 
 660             this.handshakeComplete = handshakeComplete;
 
 664          * Is this a state in which the handshake has completed?
 
 665          * @return true if the handshake is complete
 
 667         public boolean isHandshakeComplete() {
 
 668             return handshakeComplete;
 
 672          * Get a string specifying the switch connection, state, and
 
 673          * message received. To be used as message for SwitchStateException
 
 675          * @param h The channel handler (to get switch information_
 
 676          * @param m The OFMessage that has just been received
 
 677          * @param details A string giving more details about the exact nature
 
 679          * @return display string
 
 681         // needs to be protected because enum members are actually subclasses
 
 682         protected String getSwitchStateMessage(OFChannelHandler h,
 
 685             return String.format("Switch: [%s], State: [%s], received: [%s]"
 
 687                     h.getSwitchInfoString(),
 
 689                     m.getType().toString(),
 
 694          * We have an OFMessage we didn't expect given the current state and
 
 695          * we want to treat this as an error.
 
 696          * We currently throw an exception that will terminate the connection
 
 697          * However, we could be more forgiving
 
 698          * @param h the channel handler that received the message
 
 699          * @param m the message
 
 700          * @throws SwitchStateException we always throw the exception
 
 702         // needs to be protected because enum members are actually subclasses
 
 703         protected void illegalMessageReceived(OFChannelHandler h, OFMessage m)
 
 704                 throws SwitchStateException {
 
 705             String msg = getSwitchStateMessage(h, m,
 
 706                     "Switch should never send this message in the current state");
 
 707             throw new SwitchStateException(msg);
 
 712          * We have an OFMessage we didn't expect given the current state and
 
 713          * we want to ignore the message.
 
 714          * @param h the channel handler the received the message
 
 715          * @param m the message
 
 717         protected void unhandledMessageReceived(OFChannelHandler h,
 
 719             if (log.isDebugEnabled()) {
 
 720                 String msg = getSwitchStateMessage(h, m,
 
 721                         "Ignoring unexpected message");
 
 727          * Log an OpenFlow error message from a switch.
 
 728          * @param h The switch that sent the error
 
 729          * @param error The error message
 
 731         protected void logError(OFChannelHandler h, OFErrorMsg error) {
 
 732             log.error("{} from switch {} in state {}",
 
 735                     h.getSwitchInfoString(),
 
 740          * Log an OpenFlow error message from a switch and disconnect the
 
 743          * @param h the IO channel for this switch.
 
 744          * @param error The error message
 
 746         protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
 
 748             h.channel.disconnect();
 
 752          * log an error message for a duplicate dpid and disconnect this channel.
 
 753          * @param h the IO channel for this switch.
 
 755         protected void disconnectDuplicate(OFChannelHandler h) {
 
 756             log.error("Duplicated dpid or incompleted cleanup - "
 
 757                     + "disconnecting channel {}", h.getSwitchInfoString());
 
 758             h.duplicateDpidFound = Boolean.TRUE;
 
 759             h.channel.disconnect();
 
 765          * Handles all pending port status messages before a switch is declared
 
 766          * activated in MASTER or EQUAL role. Note that since this handling
 
 767          * precedes the activation (and therefore notification to IOFSwitchListerners)
 
 768          * the changes to ports will already be visible once the switch is
 
 769          * activated. As a result, no notifications are sent out for these
 
 770          * pending portStatus messages.
 
 772          * @param h the channel handler that received the message
 
 774         protected void handlePendingPortStatusMessages(OFChannelHandler h) {
 
 776                 handlePendingPortStatusMessages(h, 0);
 
 777             } catch (SwitchStateException e) {
 
 778                 log.error(e.getMessage());
 
 782         private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
 
 783                 throws SwitchStateException {
 
 785                 String msg = "State machine error: switch is null. Should never " +
 
 787                 throw new SwitchStateException(msg);
 
 789             log.info("Processing {} pending port status messages for {}",
 
 790                      h.pendingPortStatusMsg.size(), h.sw.getStringId());
 
 792             ArrayList<OFPortStatus> temp  = new ArrayList<OFPortStatus>();
 
 793             for (OFPortStatus ps: h.pendingPortStatusMsg) {
 
 795                 handlePortStatusMessage(h, ps, false);
 
 797             // expensive but ok - we don't expect too many port-status messages
 
 798             // note that we cannot use clear(), because of the reasons below
 
 799             h.pendingPortStatusMsg.removeAll(temp);
 
 801             // the iterator above takes a snapshot of the list - so while we were
 
 802             // dealing with the pending port-status messages, we could have received
 
 803             // newer ones. Handle them recursively, but break the recursion after
 
 804             // five steps to avoid an attack.
 
 805             if (!h.pendingPortStatusMsg.isEmpty() && ++index < 5) {
 
 806                 handlePendingPortStatusMessages(h, index);
 
 811          * Handle a port status message.
 
 813          * Handle a port status message by updating the port maps in the
 
 814          * IOFSwitch instance and notifying Controller about the change so
 
 815          * it can dispatch a switch update.
 
 817          * @param h The OFChannelHhandler that received the message
 
 818          * @param m The PortStatus message we received
 
 819          * @param doNotify if true switch port changed events will be
 
 821          * @throws SwitchStateException if the switch is not bound to the channel
 
 824         protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
 
 825                 boolean doNotify) throws SwitchStateException {
 
 827                 String msg = getSwitchStateMessage(h, m,
 
 828                         "State machine error: switch is null. Should never " +
 
 830                 throw new SwitchStateException(msg);
 
 833             h.sw.handleMessage(m);
 
 838          * Process an OF message received on the channel and
 
 839          * update state accordingly.
 
 841          * The main "event" of the state machine. Process the received message,
 
 842          * send follow up message if required and update state if required.
 
 844          * Switches on the message type and calls more specific event handlers
 
 845          * for each individual OF message type. If we receive a message that
 
 846          * is supposed to be sent from a controller to a switch we throw
 
 847          * a SwitchStateExeption.
 
 849          * The more specific handlers can also throw SwitchStateExceptions
 
 851          * @param h The OFChannelHandler that received the message
 
 852          * @param m The message we received.
 
 853          * @throws SwitchStateException if the switch is not bound to the channel
 
 854          * @throws IOException if unable to send message back to the switch
 
 856         void processOFMessage(OFChannelHandler h, OFMessage m)
 
 857                 throws IOException, SwitchStateException {
 
 858             switch(m.getType()) {
 
 860                 processOFHello(h, (OFHello) m);
 
 863                 processOFBarrierReply(h, (OFBarrierReply) m);
 
 866                 processOFEchoReply(h, (OFEchoReply) m);
 
 869                 processOFEchoRequest(h, (OFEchoRequest) m);
 
 872                 processOFError(h, (OFErrorMsg) m);
 
 875                 processOFFeaturesReply(h, (OFFeaturesReply) m);
 
 878                 processOFFlowRemoved(h, (OFFlowRemoved) m);
 
 880             case GET_CONFIG_REPLY:
 
 881                 processOFGetConfigReply(h, (OFGetConfigReply) m);
 
 884                 processOFPacketIn(h, (OFPacketIn) m);
 
 887                 processOFPortStatus(h, (OFPortStatus) m);
 
 889             case QUEUE_GET_CONFIG_REPLY:
 
 890                 processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
 
 892             case STATS_REPLY: // multipart_reply in 1.3
 
 893                 processOFStatisticsReply(h, (OFStatsReply) m);
 
 896                 processOFExperimenter(h, (OFExperimenter) m);
 
 899                 processOFRoleReply(h, (OFRoleReply) m);
 
 901             case GET_ASYNC_REPLY:
 
 902                 processOFGetAsyncReply(h, (OFAsyncGetReply) m);
 
 905                 // The following messages are sent to switches. The controller
 
 906                 // should never receive them
 
 908             case GET_CONFIG_REQUEST:
 
 911             case QUEUE_GET_CONFIG_REQUEST:
 
 912             case BARRIER_REQUEST:
 
 913             case STATS_REQUEST: // multipart request in 1.3
 
 914             case FEATURES_REQUEST:
 
 918             case GET_ASYNC_REQUEST:
 
 922                 illegalMessageReceived(h, m);
 
 927         /*-----------------------------------------------------------------
 
 928          * Default implementation for message handlers in any state.
 
 930          * Individual states must override these if they want a behavior
 
 931          * that differs from the default.
 
 933          * In general, these handlers simply ignore the message and do
 
 936          * There are some exceptions though, since some messages really
 
 937          * are handled the same way in every state (e.g., ECHO_REQUST) or
 
 938          * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
 
 939          -----------------------------------------------------------------*/
 
 941         void processOFHello(OFChannelHandler h, OFHello m)
 
 942                 throws IOException, SwitchStateException {
 
 943             // we only expect hello in the WAIT_HELLO state
 
 944             log.warn("Received Hello outside WAIT_HELLO state; switch {} is not complaint.",
 
 945                      h.channel.getRemoteAddress());
 
 948         void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
 
 953         void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
 
 955             if (h.ofVersion == null) {
 
 956                 log.error("No OF version set for {}. Not sending Echo REPLY",
 
 957                         h.channel.getRemoteAddress());
 
 960             OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
 
 961                     h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
 
 962                     OFEchoReply reply = factory
 
 965                             .setData(m.getData())
 
 967                     h.channel.write(Collections.singletonList(reply));
 
 970         void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
 
 972             // Do nothing with EchoReplies !!
 
 975         // no default implementation for OFError
 
 976         // every state must override it
 
 977         abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
 
 978                 throws IOException, SwitchStateException;
 
 981         void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
 
 982                 throws IOException, SwitchStateException {
 
 983             unhandledMessageReceived(h, m);
 
 986         void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
 
 988             unhandledMessageReceived(h, m);
 
 991         void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
 
 992                 throws IOException, SwitchStateException {
 
 993             // we only expect config replies in the WAIT_CONFIG_REPLY state
 
 994             illegalMessageReceived(h, m);
 
 997         void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
 
 999             unhandledMessageReceived(h, m);
 
1002         // no default implementation. Every state needs to handle it.
 
1003         abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
 
1004                 throws IOException, SwitchStateException;
 
1006         void processOFQueueGetConfigReply(OFChannelHandler h,
 
1007                 OFQueueGetConfigReply m)
 
1008                         throws IOException {
 
1009             unhandledMessageReceived(h, m);
 
1012         void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
 
1013                 throws IOException, SwitchStateException {
 
1014             unhandledMessageReceived(h, m);
 
1017         void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
 
1018                 throws IOException, SwitchStateException {
 
1019             // TODO: it might make sense to parse the vendor message here
 
1020             // into the known vendor messages we support and then call more
 
1021             // specific event handlers
 
1022             unhandledMessageReceived(h, m);
 
1025         void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
 
1026                 throws SwitchStateException, IOException {
 
1027             unhandledMessageReceived(h, m);
 
1030         void processOFGetAsyncReply(OFChannelHandler h,
 
1031                 OFAsyncGetReply m) {
 
1032             unhandledMessageReceived(h, m);
 
1039     //*************************
 
1040     //  Channel handler methods
 
1041     //*************************
 
1044     public void channelConnected(ChannelHandlerContext ctx,
 
1045             ChannelStateEvent e) throws Exception {
 
1046         channel = e.getChannel();
 
1047         log.info("New switch connection from {}",
 
1048                 channel.getRemoteAddress());
 
1050             hack to wait for the switch to tell us what it's
 
1051             max version is. This is not spec compliant and should
 
1052             be removed as soon as switches behave better.
 
1054         //sendHandshakeHelloMessage();
 
1055         setState(ChannelState.WAIT_HELLO);
 
1059     public void channelDisconnected(ChannelHandlerContext ctx,
 
1060             ChannelStateEvent e) throws Exception {
 
1061         log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
 
1062                 getSwitchInfoString());
 
1063         if (thisdpid != 0) {
 
1064             if (!duplicateDpidFound) {
 
1065                 // if the disconnected switch (on this ChannelHandler)
 
1066                 // was not one with a duplicate-dpid, it is safe to remove all
 
1067                 // state for it at the controller. Notice that if the disconnected
 
1068                 // switch was a duplicate-dpid, calling the method below would clear
 
1069                 // all state for the original switch (with the same dpid),
 
1070                 // which we obviously don't want.
 
1071                 log.info("{}:removal called", getSwitchInfoString());
 
1073                     sw.removeConnectedSwitch();
 
1076                 // A duplicate was disconnected on this ChannelHandler,
 
1077                 // this is the same switch reconnecting, but the original state was
 
1078                 // not cleaned up - XXX check liveness of original ChannelHandler
 
1079                 log.info("{}:duplicate found", getSwitchInfoString());
 
1080                 duplicateDpidFound = Boolean.FALSE;
 
1083             log.warn("no dpid in channelHandler registered for "
 
1084                     + "disconnected switch {}", getSwitchInfoString());
 
1089     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
 
1091         if (e.getCause() instanceof ReadTimeoutException) {
 
1093             log.error("Disconnecting switch {} due to read timeout",
 
1094                     getSwitchInfoString());
 
1095             ctx.getChannel().close();
 
1096         } else if (e.getCause() instanceof HandshakeTimeoutException) {
 
1097             log.error("Disconnecting switch {}: failed to complete handshake",
 
1098                     getSwitchInfoString());
 
1099             ctx.getChannel().close();
 
1100         } else if (e.getCause() instanceof ClosedChannelException) {
 
1101             log.debug("Channel for sw {} already closed", getSwitchInfoString());
 
1102         } else if (e.getCause() instanceof IOException) {
 
1103             if (!e.getCause().getMessage().equals(RESET_BY_PEER) &&
 
1104                     !e.getCause().getMessage().equals(BROKEN_PIPE)) {
 
1105                 log.error("Disconnecting switch {} due to IO Error: {}",
 
1106                           getSwitchInfoString(), e.getCause().getMessage());
 
1107                 if (log.isDebugEnabled()) {
 
1108                     // still print stack trace if debug is enabled
 
1109                     log.debug("StackTrace for previous Exception: ", e.getCause());
 
1112             ctx.getChannel().close();
 
1113         } else if (e.getCause() instanceof SwitchStateException) {
 
1114             log.error("Disconnecting switch {} due to switch state error: {}",
 
1115                     getSwitchInfoString(), e.getCause().getMessage());
 
1116             if (log.isDebugEnabled()) {
 
1117                 // still print stack trace if debug is enabled
 
1118                 log.debug("StackTrace for previous Exception: ", e.getCause());
 
1120             ctx.getChannel().close();
 
1121         } else if (e.getCause() instanceof OFParseError) {
 
1122             log.error("Disconnecting switch "
 
1123                     + getSwitchInfoString() +
 
1124                     " due to message parse failure",
 
1126             ctx.getChannel().close();
 
1127         } else if (e.getCause() instanceof RejectedExecutionException) {
 
1128             log.warn("Could not process message: queue full");
 
1130             log.error("Error while processing message from switch "
 
1131                     + getSwitchInfoString()
 
1132                     + "state " + this.state, e.getCause());
 
1133             ctx.getChannel().close();
 
1138     public String toString() {
 
1139         return getSwitchInfoString();
 
1143     public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
 
1145         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
 
1146         OFMessage m = factory.buildEchoRequest().build();
 
1147         log.debug("Sending Echo Request on idle channel: {}",
 
1148                 e.getChannel().getPipeline().getLast().toString());
 
1149         e.getChannel().write(Collections.singletonList(m));
 
1150         // XXX S some problems here -- echo request has no transaction id, and
 
1151         // echo reply is not correlated to the echo request.
 
1155     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
 
1157         if (e.getMessage() instanceof List) {
 
1158             @SuppressWarnings("unchecked")
 
1159             List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
 
1162             for (OFMessage ofm : msglist) {
 
1163                 // Do the actual packet processing
 
1164                 state.processOFMessage(this, ofm);
 
1167             state.processOFMessage(this, (OFMessage) e.getMessage());
 
1173     //*************************
 
1174     //  Channel utility methods
 
1175     //*************************
 
1178      * Is this a state in which the handshake has completed?
 
1179      * @return true if the handshake is complete
 
1181     public boolean isHandshakeComplete() {
 
1182         return this.state.isHandshakeComplete();
 
1185     private void dispatchMessage(OFMessage m) {
 
1186         sw.handleMessage(m);
 
1190      * Return a string describing this switch based on the already available
 
1191      * information (DPID and/or remote socket).
 
1192      * @return display string
 
1194     private String getSwitchInfoString() {
 
1196             return sw.toString();
 
1198         String channelString;
 
1199         if (channel == null || channel.getRemoteAddress() == null) {
 
1200             channelString = "?";
 
1202             channelString = channel.getRemoteAddress().toString();
 
1205         if (featuresReply == null) {
 
1208             dpidString = featuresReply.getDatapathId().toString();
 
1210         return String.format("[%s DPID[%s]]", channelString, dpidString);
 
1214      * Update the channels state. Only called from the state machine.
 
1215      * TODO: enforce restricted state transitions
 
1218     private void setState(ChannelState state) {
 
1223      * Send hello message to the switch using the handshake transactions ids.
 
1224      * @throws IOException
 
1226     private void sendHandshakeHelloMessage() throws IOException {
 
1227         // The OF protocol requires us to start things off by sending the highest
 
1228         // version of the protocol supported.
 
1230         // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
 
1231         // see Sec. 7.5.1 of the OF1.3.4 spec
 
1232         U32 bitmap = U32.ofRaw(0x00000012);
 
1233         OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
 
1234                 .setBitmaps(Collections.singletonList(bitmap))
 
1236         OFMessage.Builder mb = factory13.buildHello()
 
1237                 .setXid(this.handshakeTransactionIds--)
 
1238                 .setElements(Collections.singletonList(hem));
 
1239         log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
 
1240         channel.write(Collections.singletonList(mb.build()));
 
1244      * Send featuresRequest msg to the switch using the handshake transactions ids.
 
1245      * @throws IOException
 
1247     private void sendHandshakeFeaturesRequestMessage() throws IOException {
 
1248         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
 
1249         OFMessage m = factory.buildFeaturesRequest()
 
1250                 .setXid(this.handshakeTransactionIds--)
 
1252         channel.write(Collections.singletonList(m));
 
1256      * Send the configuration requests to tell the switch we want full
 
1258      * @throws IOException
 
1260     private void sendHandshakeSetConfig() throws IOException {
 
1261         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
 
1262         //log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
 
1263         List<OFMessage> msglist = new ArrayList<OFMessage>(3);
 
1265         // Ensure we receive the full packet via PacketIn
 
1266         // FIXME: We don't set the reassembly flags.
 
1267         // Only send config to switches to send full packets, if they have a buffer.
 
1268         // Saves a packet & OFSetConfig can't be handled by certain switches.
 
1269         if(this.featuresReply.getNBuffers() > 0) {
 
1270             OFSetConfig sc = factory
 
1272                     .setMissSendLen((short) 0xffff)
 
1273                     .setXid(this.handshakeTransactionIds--)
 
1279         OFBarrierRequest br = factory
 
1280                 .buildBarrierRequest()
 
1281                 .setXid(this.handshakeTransactionIds--)
 
1285         // Verify (need barrier?)
 
1286         OFGetConfigRequest gcr = factory
 
1287                 .buildGetConfigRequest()
 
1288                 .setXid(this.handshakeTransactionIds--)
 
1291         channel.write(msglist);
 
1295      * send a description state request.
 
1296      * @throws IOException
 
1298     private void sendHandshakeDescriptionStatsRequest() throws IOException {
 
1299         // Get Description to set switch-specific flags
 
1300         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
 
1301         OFDescStatsRequest dreq = factory
 
1302                 .buildDescStatsRequest()
 
1303                 .setXid(handshakeTransactionIds--)
 
1305         channel.write(Collections.singletonList(dreq));
 
1308     private void sendHandshakeOFPortDescRequest() throws IOException {
 
1309         // Get port description for 1.3 switch
 
1310         OFPortDescStatsRequest preq = factory13
 
1311                 .buildPortDescStatsRequest()
 
1312                 .setXid(handshakeTransactionIds--)
 
1314         channel.write(Collections.singletonList(preq));
 
1317     ChannelState getStateForTesting() {