450aa8271f4e1aa18596fd3fb617e174af4340df
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 Open Networking Laboratory
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 //CHECKSTYLE:OFF
18 package org.onosproject.openflow.controller.impl;
19
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;
27
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;
76
77 /**
78  * Channel handler deals with the switch connection and dispatches
79  * switch messages to the appropriate locations.
80  */
81 class OFChannelHandler extends IdleStateAwareChannelHandler {
82     private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
83
84     private static final String RESET_BY_PEER = "Connection reset by peer";
85     private static final String BROKEN_PIPE = "Broken pipe";
86
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;
94
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;
101
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;
109
110     //Indicates the openflow version used by this switch
111     protected OFVersion ofVersion;
112     protected OFFactory factory13;
113     protected OFFactory factory10;
114
115     /** transaction Ids to use during handshake. Since only one thread
116      * calls into an OFChannelHandler instance, we don't need atomic.
117      * We will count down
118      */
119     private int handshakeTransactionIds = -1;
120
121     /**
122      * Create a new unconnected OFChannelHandler.
123      * @param controller parent controller
124      */
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;
133     }
134
135
136
137     // XXX S consider if necessary
138     public void disconnectSwitch() {
139         sw.disconnectSwitch();
140     }
141
142
143
144     //*************************
145     //  Channel State Machine
146     //*************************
147
148     /**
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
151      * parts of the code)
152      */
153     enum ChannelState {
154         /**
155          * Initial state before channel is connected.
156          */
157         INIT(false) {
158             @Override
159             void processOFMessage(OFChannelHandler h, OFMessage m)
160                     throws IOException, SwitchStateException {
161                 illegalMessageReceived(h, m);
162             }
163
164             @Override
165             void processOFError(OFChannelHandler h, OFErrorMsg m)
166                     throws IOException {
167                 // need to implement since its abstract but it will never
168                 // be called
169             }
170
171             @Override
172             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
173                     throws IOException {
174                 unhandledMessageReceived(h, m);
175             }
176         },
177
178         /**
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
184          */
185         WAIT_HELLO(false) {
186             @Override
187             void processOFHello(OFChannelHandler h, OFHello m)
188                     throws IOException {
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());
201                     OFHello hi =
202                             h.factory10.buildHello()
203                                     .setXid(h.handshakeTransactionIds--)
204                                     .build();
205                     h.channel.write(Collections.singletonList(hi));
206                     h.ofVersion = OFVersion.OF_10;
207                 } else {
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();
213                     return;
214                 }
215                 h.sendHandshakeFeaturesRequestMessage();
216                 h.setState(WAIT_FEATURES_REPLY);
217             }
218             @Override
219             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
220                     throws IOException, SwitchStateException {
221                 illegalMessageReceived(h, m);
222             }
223             @Override
224             void processOFStatisticsReply(OFChannelHandler h,
225                     OFStatsReply  m)
226                             throws IOException, SwitchStateException {
227                 illegalMessageReceived(h, m);
228             }
229             @Override
230             void processOFError(OFChannelHandler h, OFErrorMsg m) {
231                 logErrorDisconnect(h, m);
232             }
233
234             @Override
235             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
236                     throws IOException {
237                 unhandledMessageReceived(h, m);
238             }
239         },
240
241
242         /**
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.
248          */
249         WAIT_FEATURES_REPLY(false) {
250             @Override
251             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
252                     throws IOException {
253                 h.thisdpid = m.getDatapathId().getLong();
254                 log.debug("Received features reply for switch at {} with dpid {}",
255                         h.getSwitchInfoString(), h.thisdpid);
256
257                 h.featuresReply = m; //temp store
258                 if (h.ofVersion == OFVersion.OF_10) {
259                     h.sendHandshakeSetConfig();
260                     h.setState(WAIT_CONFIG_REPLY);
261                 } else {
262                     //version is 1.3, must get switchport information
263                     h.sendHandshakeOFPortDescRequest();
264                     h.setState(WAIT_PORT_DESC_REPLY);
265                 }
266             }
267             @Override
268             void processOFStatisticsReply(OFChannelHandler h,
269                     OFStatsReply  m)
270                             throws IOException, SwitchStateException {
271                 illegalMessageReceived(h, m);
272             }
273             @Override
274             void processOFError(OFChannelHandler h, OFErrorMsg m) {
275                 logErrorDisconnect(h, m);
276             }
277
278             @Override
279             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
280                     throws IOException {
281                 h.pendingPortStatusMsg.add(m);
282             }
283         },
284
285         /**
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
289          */
290         WAIT_PORT_DESC_REPLY(false) {
291
292             @Override
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());
300                     return;
301                 }
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);
307                     return;
308                 }
309                 else {
310                     h.portDescReplies.add((OFPortDescStatsReply)m);
311                 }
312                 //h.portDescReply = (OFPortDescStatsReply) m; // temp store
313                 log.info("Received port desc reply for switch at {}",
314                         h.getSwitchInfoString());
315                 try {
316                     h.sendHandshakeSetConfig();
317                 } catch (IOException e) {
318                     log.error("Unable to send setConfig after PortDescReply. "
319                             + "Error: {}", e.getMessage());
320                 }
321                 h.setState(WAIT_CONFIG_REPLY);
322             }
323
324             @Override
325             void processOFError(OFChannelHandler h, OFErrorMsg m)
326                     throws IOException, SwitchStateException {
327                 logErrorDisconnect(h, m);
328
329             }
330
331             @Override
332             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
333                     throws IOException, SwitchStateException {
334                 h.pendingPortStatusMsg.add(m);
335
336             }
337         },
338
339         /**
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
343          */
344         WAIT_CONFIG_REPLY(false) {
345             @Override
346             void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
347                     throws IOException {
348                 if (m.getMissSendLen() == 0xffff) {
349                     log.trace("Config Reply from switch {} confirms "
350                             + "miss length set to 0xffff",
351                             h.getSwitchInfoString());
352                 } else {
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(),
358                             m.getMissSendLen());
359                 }
360                 h.sendHandshakeDescriptionStatsRequest();
361                 h.setState(WAIT_DESCRIPTION_STAT_REPLY);
362             }
363
364             @Override
365             void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
366                 // do nothing;
367             }
368
369             @Override
370             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
371                     throws IOException, SwitchStateException {
372                 illegalMessageReceived(h, m);
373             }
374             @Override
375             void processOFStatisticsReply(OFChannelHandler h,
376                     OFStatsReply  m)
377                             throws IOException, SwitchStateException {
378                 log.error("Received multipart(stats) message sub-type {}",
379                         m.getStatsType());
380                 illegalMessageReceived(h, m);
381             }
382
383             @Override
384             void processOFError(OFChannelHandler h, OFErrorMsg m) {
385                 logErrorDisconnect(h, m);
386             }
387
388             @Override
389             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
390                     throws IOException {
391                 h.pendingPortStatusMsg.add(m);
392             }
393         },
394
395
396         /**
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!
413          */
414         WAIT_DESCRIPTION_STAT_REPLY(false) {
415             @Override
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());
423                     return;
424                 }
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);
430
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();
438 //
439 //                if (!success) {
440 //                    disconnectDuplicate(h);
441 //                    return;
442 //                }
443                 // set switch information
444
445
446
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);
454
455                 h.sw.startDriverHandshake();
456                 if (h.sw.isDriverHandshakeComplete()) {
457                     if (!h.sw.connectSwitch()) {
458                         disconnectDuplicate(h);
459                     }
460                     handlePendingPortStatusMessages(h);
461                     h.setState(ACTIVE);
462                 } else {
463                     h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
464                 }
465
466             }
467
468             @Override
469             void processOFError(OFChannelHandler h, OFErrorMsg m) {
470                 logErrorDisconnect(h, m);
471             }
472
473             @Override
474             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
475                     throws IOException, SwitchStateException {
476                 illegalMessageReceived(h, m);
477             }
478
479             @Override
480             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
481                     throws IOException {
482                 h.pendingPortStatusMsg.add(m);
483             }
484         },
485
486
487         /**
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
493          * MASTER or EQUAL.
494          */
495         WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
496
497             @Override
498             void processOFError(OFChannelHandler h, OFErrorMsg m)
499                     throws IOException {
500                 // will never be called. We override processOFMessage
501             }
502
503
504
505             @Override
506             void processOFMessage(OFChannelHandler h, OFMessage m)
507                     throws IOException, SwitchStateException {
508
509                 if (h.sw.isDriverHandshakeComplete()) {
510                     moveToActive(h);
511                     h.state.processOFMessage(h, m);
512                     return;
513
514                 }
515
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) {
521                     h.sw.handleRole(m);
522                 } else if (m.getType() == OFType.ERROR) {
523                     if (!h.sw.handleRoleError((OFErrorMsg)m)) {
524                         h.sw.processDriverHandshakeMessage(m);
525                         if (h.sw.isDriverHandshakeComplete()) {
526                             moveToActive(h);
527                         }
528                     }
529                 } else {
530                     if (m.getType() == OFType.EXPERIMENTER &&
531                             ((OFExperimenter) m).getExperimenter() ==
532                             RoleManager.NICIRA_EXPERIMENTER) {
533                         h.sw.handleNiciraRole(m);
534                     } else {
535                         h.sw.processDriverHandshakeMessage(m);
536                         if (h.sw.isDriverHandshakeComplete()) {
537                             moveToActive(h);
538                         }
539                     }
540                 }
541             }
542
543             @Override
544             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
545                     throws IOException, SwitchStateException {
546                 h.pendingPortStatusMsg.add(m);
547             }
548
549             private void moveToActive(OFChannelHandler h) {
550                 boolean success = h.sw.connectSwitch();
551                 handlePendingPortStatusMessages(h);
552                 h.setState(ACTIVE);
553                 if (!success) {
554                     disconnectDuplicate(h);
555                 }
556             }
557
558         },
559
560
561         /**
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
571          * SLAVE.
572          */
573         ACTIVE(true) {
574             @Override
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
584                     // role
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
589
590                     h.sw.reassertRole();
591                 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
592                         ((OFFlowModFailedErrorMsg) m).getCode() ==
593                         OFFlowModFailedCode.ALL_TABLES_FULL) {
594                     h.sw.setTableFull(true);
595                 } else {
596                     logError(h, m);
597                 }
598                 h.dispatchMessage(m);
599             }
600
601             @Override
602             void processOFStatisticsReply(OFChannelHandler h,
603                     OFStatsReply m) {
604                 if (m.getStatsType().equals(OFStatsType.PORT_DESC)) {
605                     h.sw.setPortDescReply((OFPortDescStatsReply) m);
606                 }
607                 h.dispatchMessage(m);
608             }
609
610             @Override
611             void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
612                     throws SwitchStateException {
613                 h.sw.handleNiciraRole(m);
614             }
615
616             @Override
617             void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
618                     throws SwitchStateException {
619                 h.sw.handleRole(m);
620             }
621
622             @Override
623             void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
624                     throws SwitchStateException {
625                 handlePortStatusMessage(h, m, true);
626                 //h.dispatchMessage(m);
627             }
628
629             @Override
630             void processOFPacketIn(OFChannelHandler h, OFPacketIn m) {
631 //                OFPacketOut out =
632 //                        h.sw.factory().buildPacketOut()
633 //                                .setXid(m.getXid())
634 //                                .setBufferId(m.getBufferId()).build();
635 //                h.sw.sendMsg(out);
636                 h.dispatchMessage(m);
637             }
638
639             @Override
640             void processOFFlowRemoved(OFChannelHandler h,
641                     OFFlowRemoved m) {
642                 h.dispatchMessage(m);
643             }
644
645             @Override
646             void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
647                 h.dispatchMessage(m);
648             }
649
650             @Override
651             void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m) {
652                 h.sw.setFeaturesReply(m);
653                 h.dispatchMessage(m);
654             }
655
656         };
657
658         private final boolean handshakeComplete;
659         ChannelState(boolean handshakeComplete) {
660             this.handshakeComplete = handshakeComplete;
661         }
662
663         /**
664          * Is this a state in which the handshake has completed?
665          * @return true if the handshake is complete
666          */
667         public boolean isHandshakeComplete() {
668             return handshakeComplete;
669         }
670
671         /**
672          * Get a string specifying the switch connection, state, and
673          * message received. To be used as message for SwitchStateException
674          * or log messages
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
678          * of the problem.
679          * @return display string
680          */
681         // needs to be protected because enum members are actually subclasses
682         protected String getSwitchStateMessage(OFChannelHandler h,
683                 OFMessage m,
684                 String details) {
685             return String.format("Switch: [%s], State: [%s], received: [%s]"
686                     + ", details: %s",
687                     h.getSwitchInfoString(),
688                     this.toString(),
689                     m.getType().toString(),
690                     details);
691         }
692
693         /**
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
701          */
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);
708
709         }
710
711         /**
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
716          */
717         protected void unhandledMessageReceived(OFChannelHandler h,
718                 OFMessage m) {
719             if (log.isDebugEnabled()) {
720                 String msg = getSwitchStateMessage(h, m,
721                         "Ignoring unexpected message");
722                 log.debug(msg);
723             }
724         }
725
726         /**
727          * Log an OpenFlow error message from a switch.
728          * @param h The switch that sent the error
729          * @param error The error message
730          */
731         protected void logError(OFChannelHandler h, OFErrorMsg error) {
732             log.error("{} from switch {} in state {}",
733                     new Object[] {
734                     error,
735                     h.getSwitchInfoString(),
736                     this.toString()});
737         }
738
739         /**
740          * Log an OpenFlow error message from a switch and disconnect the
741          * channel.
742          *
743          * @param h the IO channel for this switch.
744          * @param error The error message
745          */
746         protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
747             logError(h, error);
748             h.channel.disconnect();
749         }
750
751         /**
752          * log an error message for a duplicate dpid and disconnect this channel.
753          * @param h the IO channel for this switch.
754          */
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();
760         }
761
762
763
764         /**
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.
771          *
772          * @param h the channel handler that received the message
773          */
774         protected void handlePendingPortStatusMessages(OFChannelHandler h) {
775             try {
776                 handlePendingPortStatusMessages(h, 0);
777             } catch (SwitchStateException e) {
778                 log.error(e.getMessage());
779             }
780         }
781
782         private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
783                 throws SwitchStateException {
784             if (h.sw == null) {
785                 String msg = "State machine error: switch is null. Should never " +
786                         "happen";
787                 throw new SwitchStateException(msg);
788             }
789             log.info("Processing {} pending port status messages for {}",
790                      h.pendingPortStatusMsg.size(), h.sw.getStringId());
791
792             ArrayList<OFPortStatus> temp  = new ArrayList<OFPortStatus>();
793             for (OFPortStatus ps: h.pendingPortStatusMsg) {
794                 temp.add(ps);
795                 handlePortStatusMessage(h, ps, false);
796             }
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);
800             temp.clear();
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);
807             }
808         }
809
810         /**
811          * Handle a port status message.
812          *
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.
816          *
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
820          * dispatched
821          * @throws SwitchStateException if the switch is not bound to the channel
822          *
823          */
824         protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
825                 boolean doNotify) throws SwitchStateException {
826             if (h.sw == null) {
827                 String msg = getSwitchStateMessage(h, m,
828                         "State machine error: switch is null. Should never " +
829                         "happen");
830                 throw new SwitchStateException(msg);
831             }
832
833             h.sw.handleMessage(m);
834         }
835
836
837         /**
838          * Process an OF message received on the channel and
839          * update state accordingly.
840          *
841          * The main "event" of the state machine. Process the received message,
842          * send follow up message if required and update state if required.
843          *
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.
848          *
849          * The more specific handlers can also throw SwitchStateExceptions
850          *
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
855          */
856         void processOFMessage(OFChannelHandler h, OFMessage m)
857                 throws IOException, SwitchStateException {
858             switch(m.getType()) {
859             case HELLO:
860                 processOFHello(h, (OFHello) m);
861                 break;
862             case BARRIER_REPLY:
863                 processOFBarrierReply(h, (OFBarrierReply) m);
864                 break;
865             case ECHO_REPLY:
866                 processOFEchoReply(h, (OFEchoReply) m);
867                 break;
868             case ECHO_REQUEST:
869                 processOFEchoRequest(h, (OFEchoRequest) m);
870                 break;
871             case ERROR:
872                 processOFError(h, (OFErrorMsg) m);
873                 break;
874             case FEATURES_REPLY:
875                 processOFFeaturesReply(h, (OFFeaturesReply) m);
876                 break;
877             case FLOW_REMOVED:
878                 processOFFlowRemoved(h, (OFFlowRemoved) m);
879                 break;
880             case GET_CONFIG_REPLY:
881                 processOFGetConfigReply(h, (OFGetConfigReply) m);
882                 break;
883             case PACKET_IN:
884                 processOFPacketIn(h, (OFPacketIn) m);
885                 break;
886             case PORT_STATUS:
887                 processOFPortStatus(h, (OFPortStatus) m);
888                 break;
889             case QUEUE_GET_CONFIG_REPLY:
890                 processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
891                 break;
892             case STATS_REPLY: // multipart_reply in 1.3
893                 processOFStatisticsReply(h, (OFStatsReply) m);
894                 break;
895             case EXPERIMENTER:
896                 processOFExperimenter(h, (OFExperimenter) m);
897                 break;
898             case ROLE_REPLY:
899                 processOFRoleReply(h, (OFRoleReply) m);
900                 break;
901             case GET_ASYNC_REPLY:
902                 processOFGetAsyncReply(h, (OFAsyncGetReply) m);
903                 break;
904
905                 // The following messages are sent to switches. The controller
906                 // should never receive them
907             case SET_CONFIG:
908             case GET_CONFIG_REQUEST:
909             case PACKET_OUT:
910             case PORT_MOD:
911             case QUEUE_GET_CONFIG_REQUEST:
912             case BARRIER_REQUEST:
913             case STATS_REQUEST: // multipart request in 1.3
914             case FEATURES_REQUEST:
915             case FLOW_MOD:
916             case GROUP_MOD:
917             case TABLE_MOD:
918             case GET_ASYNC_REQUEST:
919             case SET_ASYNC:
920             case METER_MOD:
921             default:
922                 illegalMessageReceived(h, m);
923                 break;
924             }
925         }
926
927         /*-----------------------------------------------------------------
928          * Default implementation for message handlers in any state.
929          *
930          * Individual states must override these if they want a behavior
931          * that differs from the default.
932          *
933          * In general, these handlers simply ignore the message and do
934          * nothing.
935          *
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          -----------------------------------------------------------------*/
940
941         void processOFHello(OFChannelHandler h, OFHello m)
942                 throws IOException, SwitchStateException {
943             // we only expect hello in the WAIT_HELLO state
944             illegalMessageReceived(h, m);
945         }
946
947         void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
948                 throws IOException {
949             // Silently ignore.
950         }
951
952         void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
953                 throws IOException {
954             if (h.ofVersion == null) {
955                 log.error("No OF version set for {}. Not sending Echo REPLY",
956                         h.channel.getRemoteAddress());
957                 return;
958             }
959             OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
960                     h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
961                     OFEchoReply reply = factory
962                             .buildEchoReply()
963                             .setXid(m.getXid())
964                             .setData(m.getData())
965                             .build();
966                     h.channel.write(Collections.singletonList(reply));
967         }
968
969         void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
970                 throws IOException {
971             // Do nothing with EchoReplies !!
972         }
973
974         // no default implementation for OFError
975         // every state must override it
976         abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
977                 throws IOException, SwitchStateException;
978
979
980         void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
981                 throws IOException, SwitchStateException {
982             unhandledMessageReceived(h, m);
983         }
984
985         void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
986                 throws IOException {
987             unhandledMessageReceived(h, m);
988         }
989
990         void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
991                 throws IOException, SwitchStateException {
992             // we only expect config replies in the WAIT_CONFIG_REPLY state
993             illegalMessageReceived(h, m);
994         }
995
996         void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
997                 throws IOException {
998             unhandledMessageReceived(h, m);
999         }
1000
1001         // no default implementation. Every state needs to handle it.
1002         abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1003                 throws IOException, SwitchStateException;
1004
1005         void processOFQueueGetConfigReply(OFChannelHandler h,
1006                 OFQueueGetConfigReply m)
1007                         throws IOException {
1008             unhandledMessageReceived(h, m);
1009         }
1010
1011         void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
1012                 throws IOException, SwitchStateException {
1013             unhandledMessageReceived(h, m);
1014         }
1015
1016         void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1017                 throws IOException, SwitchStateException {
1018             // TODO: it might make sense to parse the vendor message here
1019             // into the known vendor messages we support and then call more
1020             // specific event handlers
1021             unhandledMessageReceived(h, m);
1022         }
1023
1024         void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1025                 throws SwitchStateException, IOException {
1026             unhandledMessageReceived(h, m);
1027         }
1028
1029         void processOFGetAsyncReply(OFChannelHandler h,
1030                 OFAsyncGetReply m) {
1031             unhandledMessageReceived(h, m);
1032         }
1033
1034     }
1035
1036
1037
1038     //*************************
1039     //  Channel handler methods
1040     //*************************
1041
1042     @Override
1043     public void channelConnected(ChannelHandlerContext ctx,
1044             ChannelStateEvent e) throws Exception {
1045         channel = e.getChannel();
1046         log.info("New switch connection from {}",
1047                 channel.getRemoteAddress());
1048         /*
1049             hack to wait for the switch to tell us what it's
1050             max version is. This is not spec compliant and should
1051             be removed as soon as switches behave better.
1052          */
1053         //sendHandshakeHelloMessage();
1054         setState(ChannelState.WAIT_HELLO);
1055     }
1056
1057     @Override
1058     public void channelDisconnected(ChannelHandlerContext ctx,
1059             ChannelStateEvent e) throws Exception {
1060         log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
1061                 getSwitchInfoString());
1062         if (thisdpid != 0) {
1063             if (!duplicateDpidFound) {
1064                 // if the disconnected switch (on this ChannelHandler)
1065                 // was not one with a duplicate-dpid, it is safe to remove all
1066                 // state for it at the controller. Notice that if the disconnected
1067                 // switch was a duplicate-dpid, calling the method below would clear
1068                 // all state for the original switch (with the same dpid),
1069                 // which we obviously don't want.
1070                 log.info("{}:removal called", getSwitchInfoString());
1071                 if (sw != null) {
1072                     sw.removeConnectedSwitch();
1073                 }
1074             } else {
1075                 // A duplicate was disconnected on this ChannelHandler,
1076                 // this is the same switch reconnecting, but the original state was
1077                 // not cleaned up - XXX check liveness of original ChannelHandler
1078                 log.info("{}:duplicate found", getSwitchInfoString());
1079                 duplicateDpidFound = Boolean.FALSE;
1080             }
1081         } else {
1082             log.warn("no dpid in channelHandler registered for "
1083                     + "disconnected switch {}", getSwitchInfoString());
1084         }
1085     }
1086
1087     @Override
1088     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
1089             throws Exception {
1090         if (e.getCause() instanceof ReadTimeoutException) {
1091             // switch timeout
1092             log.error("Disconnecting switch {} due to read timeout",
1093                     getSwitchInfoString());
1094             ctx.getChannel().close();
1095         } else if (e.getCause() instanceof HandshakeTimeoutException) {
1096             log.error("Disconnecting switch {}: failed to complete handshake",
1097                     getSwitchInfoString());
1098             ctx.getChannel().close();
1099         } else if (e.getCause() instanceof ClosedChannelException) {
1100             log.debug("Channel for sw {} already closed", getSwitchInfoString());
1101         } else if (e.getCause() instanceof IOException) {
1102             if (!e.getCause().getMessage().equals(RESET_BY_PEER) &&
1103                     !e.getCause().getMessage().equals(BROKEN_PIPE)) {
1104                 log.error("Disconnecting switch {} due to IO Error: {}",
1105                           getSwitchInfoString(), e.getCause().getMessage());
1106                 if (log.isDebugEnabled()) {
1107                     // still print stack trace if debug is enabled
1108                     log.debug("StackTrace for previous Exception: ", e.getCause());
1109                 }
1110             }
1111             ctx.getChannel().close();
1112         } else if (e.getCause() instanceof SwitchStateException) {
1113             log.error("Disconnecting switch {} due to switch state error: {}",
1114                     getSwitchInfoString(), e.getCause().getMessage());
1115             if (log.isDebugEnabled()) {
1116                 // still print stack trace if debug is enabled
1117                 log.debug("StackTrace for previous Exception: ", e.getCause());
1118             }
1119             ctx.getChannel().close();
1120         } else if (e.getCause() instanceof OFParseError) {
1121             log.error("Disconnecting switch "
1122                     + getSwitchInfoString() +
1123                     " due to message parse failure",
1124                     e.getCause());
1125             ctx.getChannel().close();
1126         } else if (e.getCause() instanceof RejectedExecutionException) {
1127             log.warn("Could not process message: queue full");
1128         } else {
1129             log.error("Error while processing message from switch "
1130                     + getSwitchInfoString()
1131                     + "state " + this.state, e.getCause());
1132             ctx.getChannel().close();
1133         }
1134     }
1135
1136     @Override
1137     public String toString() {
1138         return getSwitchInfoString();
1139     }
1140
1141     @Override
1142     public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
1143             throws Exception {
1144         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1145         OFMessage m = factory.buildEchoRequest().build();
1146         log.debug("Sending Echo Request on idle channel: {}",
1147                 e.getChannel().getPipeline().getLast().toString());
1148         e.getChannel().write(Collections.singletonList(m));
1149         // XXX S some problems here -- echo request has no transaction id, and
1150         // echo reply is not correlated to the echo request.
1151     }
1152
1153     @Override
1154     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
1155             throws Exception {
1156         if (e.getMessage() instanceof List) {
1157             @SuppressWarnings("unchecked")
1158             List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
1159
1160
1161             for (OFMessage ofm : msglist) {
1162                 // Do the actual packet processing
1163                 state.processOFMessage(this, ofm);
1164             }
1165         } else {
1166             state.processOFMessage(this, (OFMessage) e.getMessage());
1167         }
1168     }
1169
1170
1171
1172     //*************************
1173     //  Channel utility methods
1174     //*************************
1175
1176     /**
1177      * Is this a state in which the handshake has completed?
1178      * @return true if the handshake is complete
1179      */
1180     public boolean isHandshakeComplete() {
1181         return this.state.isHandshakeComplete();
1182     }
1183
1184     private void dispatchMessage(OFMessage m) {
1185         sw.handleMessage(m);
1186     }
1187
1188     /**
1189      * Return a string describing this switch based on the already available
1190      * information (DPID and/or remote socket).
1191      * @return display string
1192      */
1193     private String getSwitchInfoString() {
1194         if (sw != null) {
1195             return sw.toString();
1196         }
1197         String channelString;
1198         if (channel == null || channel.getRemoteAddress() == null) {
1199             channelString = "?";
1200         } else {
1201             channelString = channel.getRemoteAddress().toString();
1202         }
1203         String dpidString;
1204         if (featuresReply == null) {
1205             dpidString = "?";
1206         } else {
1207             dpidString = featuresReply.getDatapathId().toString();
1208         }
1209         return String.format("[%s DPID[%s]]", channelString, dpidString);
1210     }
1211
1212     /**
1213      * Update the channels state. Only called from the state machine.
1214      * TODO: enforce restricted state transitions
1215      * @param state
1216      */
1217     private void setState(ChannelState state) {
1218         this.state = state;
1219     }
1220
1221     /**
1222      * Send hello message to the switch using the handshake transactions ids.
1223      * @throws IOException
1224      */
1225     private void sendHandshakeHelloMessage() throws IOException {
1226         // The OF protocol requires us to start things off by sending the highest
1227         // version of the protocol supported.
1228
1229         // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
1230         // see Sec. 7.5.1 of the OF1.3.4 spec
1231         U32 bitmap = U32.ofRaw(0x00000012);
1232         OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
1233                 .setBitmaps(Collections.singletonList(bitmap))
1234                 .build();
1235         OFMessage.Builder mb = factory13.buildHello()
1236                 .setXid(this.handshakeTransactionIds--)
1237                 .setElements(Collections.singletonList(hem));
1238         log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
1239         channel.write(Collections.singletonList(mb.build()));
1240     }
1241
1242     /**
1243      * Send featuresRequest msg to the switch using the handshake transactions ids.
1244      * @throws IOException
1245      */
1246     private void sendHandshakeFeaturesRequestMessage() throws IOException {
1247         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1248         OFMessage m = factory.buildFeaturesRequest()
1249                 .setXid(this.handshakeTransactionIds--)
1250                 .build();
1251         channel.write(Collections.singletonList(m));
1252     }
1253
1254     /**
1255      * Send the configuration requests to tell the switch we want full
1256      * packets.
1257      * @throws IOException
1258      */
1259     private void sendHandshakeSetConfig() throws IOException {
1260         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1261         //log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
1262         List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1263
1264         // Ensure we receive the full packet via PacketIn
1265         // FIXME: We don't set the reassembly flags.
1266         // Only send config to switches to send full packets, if they have a buffer.
1267         // Saves a packet & OFSetConfig can't be handled by certain switches.
1268         if(this.featuresReply.getNBuffers() > 0) {
1269             OFSetConfig sc = factory
1270                     .buildSetConfig()
1271                     .setMissSendLen((short) 0xffff)
1272                     .setXid(this.handshakeTransactionIds--)
1273                     .build();
1274             msglist.add(sc);
1275         }
1276
1277         // Barrier
1278         OFBarrierRequest br = factory
1279                 .buildBarrierRequest()
1280                 .setXid(this.handshakeTransactionIds--)
1281                 .build();
1282         msglist.add(br);
1283
1284         // Verify (need barrier?)
1285         OFGetConfigRequest gcr = factory
1286                 .buildGetConfigRequest()
1287                 .setXid(this.handshakeTransactionIds--)
1288                 .build();
1289         msglist.add(gcr);
1290         channel.write(msglist);
1291     }
1292
1293     /**
1294      * send a description state request.
1295      * @throws IOException
1296      */
1297     private void sendHandshakeDescriptionStatsRequest() throws IOException {
1298         // Get Description to set switch-specific flags
1299         OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1300         OFDescStatsRequest dreq = factory
1301                 .buildDescStatsRequest()
1302                 .setXid(handshakeTransactionIds--)
1303                 .build();
1304         channel.write(Collections.singletonList(dreq));
1305     }
1306
1307     private void sendHandshakeOFPortDescRequest() throws IOException {
1308         // Get port description for 1.3 switch
1309         OFPortDescStatsRequest preq = factory13
1310                 .buildPortDescStatsRequest()
1311                 .setXid(handshakeTransactionIds--)
1312                 .build();
1313         channel.write(Collections.singletonList(preq));
1314     }
1315
1316     ChannelState getStateForTesting() {
1317         return state;
1318     }
1319
1320 }