blob: 4779c5dd0a6361f23119840477aa22d953f81eba [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
16
tom7ef8ff92014-09-17 13:08:06 -070017//CHECKSTYLE:OFF
Brian O'Connorabafb502014-12-02 22:26:20 -080018package org.onosproject.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -070019
20import java.io.IOException;
21import java.nio.channels.ClosedChannelException;
22import java.util.ArrayList;
23import java.util.Collections;
24import java.util.List;
25import java.util.concurrent.CopyOnWriteArrayList;
26import java.util.concurrent.RejectedExecutionException;
27
28import org.jboss.netty.channel.Channel;
29import org.jboss.netty.channel.ChannelHandlerContext;
30import org.jboss.netty.channel.ChannelStateEvent;
31import org.jboss.netty.channel.ExceptionEvent;
32import org.jboss.netty.channel.MessageEvent;
33import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
34import org.jboss.netty.handler.timeout.IdleStateEvent;
35import org.jboss.netty.handler.timeout.ReadTimeoutException;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
37import org.onosproject.openflow.controller.driver.SwitchStateException;
tom7ef8ff92014-09-17 13:08:06 -070038import org.projectfloodlight.openflow.exceptions.OFParseError;
39import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
40import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
41import org.projectfloodlight.openflow.protocol.OFBarrierReply;
42import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
43import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
44import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
45import org.projectfloodlight.openflow.protocol.OFEchoReply;
46import org.projectfloodlight.openflow.protocol.OFEchoRequest;
47import org.projectfloodlight.openflow.protocol.OFErrorMsg;
48import org.projectfloodlight.openflow.protocol.OFErrorType;
49import org.projectfloodlight.openflow.protocol.OFExperimenter;
50import org.projectfloodlight.openflow.protocol.OFFactory;
51import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
52import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
53import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
54import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
55import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
56import org.projectfloodlight.openflow.protocol.OFHello;
57import org.projectfloodlight.openflow.protocol.OFHelloElem;
58import org.projectfloodlight.openflow.protocol.OFMessage;
59import org.projectfloodlight.openflow.protocol.OFPacketIn;
60import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
61import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
62import org.projectfloodlight.openflow.protocol.OFPortStatus;
63import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
64import org.projectfloodlight.openflow.protocol.OFRoleReply;
65import org.projectfloodlight.openflow.protocol.OFSetConfig;
66import org.projectfloodlight.openflow.protocol.OFStatsReply;
67import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
68import org.projectfloodlight.openflow.protocol.OFStatsType;
69import org.projectfloodlight.openflow.protocol.OFType;
70import org.projectfloodlight.openflow.protocol.OFVersion;
71import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
72import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
73import org.projectfloodlight.openflow.types.U32;
74import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
77/**
78 * Channel handler deals with the switch connection and dispatches
79 * switch messages to the appropriate locations.
80 */
81class OFChannelHandler extends IdleStateAwareChannelHandler {
82 private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
83 private final Controller controller;
84 private OpenFlowSwitchDriver sw;
85 private long thisdpid; // channelHandler cached value of connected switch id
86 private Channel channel;
87 // State needs to be volatile because the HandshakeTimeoutHandler
88 // needs to check if the handshake is complete
89 private volatile ChannelState state;
90
91 // When a switch with a duplicate dpid is found (i.e we already have a
92 // connected switch with the same dpid), the new switch is immediately
93 // disconnected. At that point netty callsback channelDisconnected() which
94 // proceeds to cleaup switch state - we need to ensure that it does not cleanup
95 // switch state for the older (still connected) switch
96 private volatile Boolean duplicateDpidFound;
97
98 // Temporary storage for switch-features and port-description
99 private OFFeaturesReply featuresReply;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700100 private List<OFPortDescStatsReply> portDescReplies;
101 //private OFPortDescStatsReply portDescReply;
tom7ef8ff92014-09-17 13:08:06 -0700102 // a concurrent ArrayList to temporarily store port status messages
103 // before we are ready to deal with them
104 private final CopyOnWriteArrayList<OFPortStatus> pendingPortStatusMsg;
105
106 //Indicates the openflow version used by this switch
107 protected OFVersion ofVersion;
108 protected OFFactory factory13;
109 protected OFFactory factory10;
110
111 /** transaction Ids to use during handshake. Since only one thread
112 * calls into an OFChannelHandler instance, we don't need atomic.
113 * We will count down
114 */
115 private int handshakeTransactionIds = -1;
116
117 /**
118 * Create a new unconnected OFChannelHandler.
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800119 * @param controller parent controller
tom7ef8ff92014-09-17 13:08:06 -0700120 */
121 OFChannelHandler(Controller controller) {
122 this.controller = controller;
123 this.state = ChannelState.INIT;
124 this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700125 this.portDescReplies = new ArrayList<OFPortDescStatsReply>();
tom7ef8ff92014-09-17 13:08:06 -0700126 factory13 = controller.getOFMessageFactory13();
127 factory10 = controller.getOFMessageFactory10();
128 duplicateDpidFound = Boolean.FALSE;
129 }
130
131
132
133 // XXX S consider if necessary
134 public void disconnectSwitch() {
135 sw.disconnectSwitch();
136 }
137
138
139
140 //*************************
141 // Channel State Machine
142 //*************************
143
144 /**
145 * The state machine for handling the switch/channel state. All state
146 * transitions should happen from within the state machine (and not from other
147 * parts of the code)
148 */
149 enum ChannelState {
150 /**
151 * Initial state before channel is connected.
152 */
153 INIT(false) {
154 @Override
155 void processOFMessage(OFChannelHandler h, OFMessage m)
156 throws IOException, SwitchStateException {
157 illegalMessageReceived(h, m);
158 }
159
160 @Override
161 void processOFError(OFChannelHandler h, OFErrorMsg m)
162 throws IOException {
163 // need to implement since its abstract but it will never
164 // be called
165 }
166
167 @Override
168 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
169 throws IOException {
170 unhandledMessageReceived(h, m);
171 }
172 },
173
174 /**
175 * We send a OF 1.3 HELLO to the switch and wait for a Hello from the switch.
176 * Once we receive the reply, we decide on OF 1.3 or 1.0 switch - no other
177 * protocol version is accepted.
178 * We send an OFFeaturesRequest depending on the protocol version selected
179 * Next state is WAIT_FEATURES_REPLY
180 */
181 WAIT_HELLO(false) {
182 @Override
183 void processOFHello(OFChannelHandler h, OFHello m)
184 throws IOException {
185 // TODO We could check for the optional bitmap, but for now
186 // we are just checking the version number.
187 if (m.getVersion() == OFVersion.OF_13) {
alshabib09d48be2014-10-03 15:43:33 -0700188 log.debug("Received {} Hello from {}", m.getVersion(),
tom7ef8ff92014-09-17 13:08:06 -0700189 h.channel.getRemoteAddress());
alshabib70fc7fb2015-01-06 11:04:29 -0800190 h.sendHandshakeHelloMessage();
tom7ef8ff92014-09-17 13:08:06 -0700191 h.ofVersion = OFVersion.OF_13;
192 } else if (m.getVersion() == OFVersion.OF_10) {
alshabib09d48be2014-10-03 15:43:33 -0700193 log.debug("Received {} Hello from {} - switching to OF "
tom7ef8ff92014-09-17 13:08:06 -0700194 + "version 1.0", m.getVersion(),
195 h.channel.getRemoteAddress());
alshabib70fc7fb2015-01-06 11:04:29 -0800196 OFHello hi =
197 h.factory10.buildHello()
198 .setXid(h.handshakeTransactionIds--)
199 .build();
200 h.channel.write(Collections.singletonList(hi));
tom7ef8ff92014-09-17 13:08:06 -0700201 h.ofVersion = OFVersion.OF_10;
202 } else {
203 log.error("Received Hello of version {} from switch at {}. "
204 + "This controller works with OF1.0 and OF1.3 "
205 + "switches. Disconnecting switch ...",
206 m.getVersion(), h.channel.getRemoteAddress());
207 h.channel.disconnect();
208 return;
209 }
210 h.sendHandshakeFeaturesRequestMessage();
211 h.setState(WAIT_FEATURES_REPLY);
212 }
213 @Override
214 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
215 throws IOException, SwitchStateException {
216 illegalMessageReceived(h, m);
217 }
218 @Override
219 void processOFStatisticsReply(OFChannelHandler h,
220 OFStatsReply m)
221 throws IOException, SwitchStateException {
222 illegalMessageReceived(h, m);
223 }
224 @Override
225 void processOFError(OFChannelHandler h, OFErrorMsg m) {
226 logErrorDisconnect(h, m);
227 }
228
229 @Override
230 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
231 throws IOException {
232 unhandledMessageReceived(h, m);
233 }
234 },
235
236
237 /**
238 * We are waiting for a features reply message. Once we receive it, the
239 * behavior depends on whether this is a 1.0 or 1.3 switch. For 1.0,
240 * we send a SetConfig request, barrier, and GetConfig request and the
241 * next state is WAIT_CONFIG_REPLY. For 1.3, we send a Port description
242 * request and the next state is WAIT_PORT_DESC_REPLY.
243 */
244 WAIT_FEATURES_REPLY(false) {
245 @Override
246 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
247 throws IOException {
248 h.thisdpid = m.getDatapathId().getLong();
alshabib09d48be2014-10-03 15:43:33 -0700249 log.debug("Received features reply for switch at {} with dpid {}",
tom7ef8ff92014-09-17 13:08:06 -0700250 h.getSwitchInfoString(), h.thisdpid);
251
252 h.featuresReply = m; //temp store
253 if (h.ofVersion == OFVersion.OF_10) {
254 h.sendHandshakeSetConfig();
255 h.setState(WAIT_CONFIG_REPLY);
256 } else {
257 //version is 1.3, must get switchport information
258 h.sendHandshakeOFPortDescRequest();
259 h.setState(WAIT_PORT_DESC_REPLY);
260 }
261 }
262 @Override
263 void processOFStatisticsReply(OFChannelHandler h,
264 OFStatsReply m)
265 throws IOException, SwitchStateException {
266 illegalMessageReceived(h, m);
267 }
268 @Override
269 void processOFError(OFChannelHandler h, OFErrorMsg m) {
270 logErrorDisconnect(h, m);
271 }
272
273 @Override
274 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
275 throws IOException {
Thomas Vachuska39274462014-12-02 13:23:50 -0800276 h.pendingPortStatusMsg.add(m);
tom7ef8ff92014-09-17 13:08:06 -0700277 }
278 },
279
280 /**
281 * We are waiting for a description of the 1.3 switch ports.
282 * Once received, we send a SetConfig request
283 * Next State is WAIT_CONFIG_REPLY
284 */
285 WAIT_PORT_DESC_REPLY(false) {
286
287 @Override
288 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
289 throws SwitchStateException {
290 // Read port description
291 if (m.getStatsType() != OFStatsType.PORT_DESC) {
292 log.warn("Expecting port description stats but received stats "
293 + "type {} from {}. Ignoring ...", m.getStatsType(),
294 h.channel.getRemoteAddress());
295 return;
296 }
297 if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
298 log.warn("Stats reply indicates more stats from sw {} for "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700299 + "port description",
tom7ef8ff92014-09-17 13:08:06 -0700300 h.getSwitchInfoString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700301 h.portDescReplies.add((OFPortDescStatsReply)m);
302 return;
tom7ef8ff92014-09-17 13:08:06 -0700303 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700304 else {
305 h.portDescReplies.add((OFPortDescStatsReply)m);
306 }
307 //h.portDescReply = (OFPortDescStatsReply) m; // temp store
tom7ef8ff92014-09-17 13:08:06 -0700308 log.info("Received port desc reply for switch at {}",
309 h.getSwitchInfoString());
310 try {
311 h.sendHandshakeSetConfig();
312 } catch (IOException e) {
313 log.error("Unable to send setConfig after PortDescReply. "
314 + "Error: {}", e.getMessage());
315 }
316 h.setState(WAIT_CONFIG_REPLY);
317 }
318
319 @Override
320 void processOFError(OFChannelHandler h, OFErrorMsg m)
321 throws IOException, SwitchStateException {
322 logErrorDisconnect(h, m);
323
324 }
325
326 @Override
327 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
328 throws IOException, SwitchStateException {
Thomas Vachuska39274462014-12-02 13:23:50 -0800329 h.pendingPortStatusMsg.add(m);
tom7ef8ff92014-09-17 13:08:06 -0700330
331 }
332 },
333
334 /**
335 * We are waiting for a config reply message. Once we receive it
336 * we send a DescriptionStatsRequest to the switch.
337 * Next state: WAIT_DESCRIPTION_STAT_REPLY
338 */
339 WAIT_CONFIG_REPLY(false) {
340 @Override
341 void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
342 throws IOException {
343 if (m.getMissSendLen() == 0xffff) {
344 log.trace("Config Reply from switch {} confirms "
345 + "miss length set to 0xffff",
346 h.getSwitchInfoString());
347 } else {
348 // FIXME: we can't really deal with switches that don't send
349 // full packets. Shouldn't we drop the connection here?
350 log.warn("Config Reply from switch {} has"
351 + "miss length set to {}",
352 h.getSwitchInfoString(),
353 m.getMissSendLen());
354 }
355 h.sendHandshakeDescriptionStatsRequest();
356 h.setState(WAIT_DESCRIPTION_STAT_REPLY);
357 }
358
359 @Override
360 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
361 // do nothing;
362 }
363
364 @Override
365 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
366 throws IOException, SwitchStateException {
367 illegalMessageReceived(h, m);
368 }
369 @Override
370 void processOFStatisticsReply(OFChannelHandler h,
371 OFStatsReply m)
372 throws IOException, SwitchStateException {
373 log.error("Received multipart(stats) message sub-type {}",
374 m.getStatsType());
375 illegalMessageReceived(h, m);
376 }
377
378 @Override
379 void processOFError(OFChannelHandler h, OFErrorMsg m) {
380 logErrorDisconnect(h, m);
381 }
382
383 @Override
384 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
385 throws IOException {
386 h.pendingPortStatusMsg.add(m);
387 }
388 },
389
390
391 /**
392 * We are waiting for a OFDescriptionStat message from the switch.
393 * Once we receive any stat message we try to parse it. If it's not
394 * a description stats message we disconnect. If its the expected
395 * description stats message, we:
396 * - use the switch driver to bind the switch and get an IOFSwitch instance
397 * - setup the IOFSwitch instance
398 * - add switch controller and send the initial role
399 * request to the switch.
400 * Next state: WAIT_INITIAL_ROLE
401 * In the typical case, where switches support role request messages
402 * the next state is where we expect the role reply message.
403 * In the special case that where the switch does not support any kind
404 * of role request messages, we don't send a role message, but we do
405 * request mastership from the registry service. This controller
406 * should become master once we hear back from the registry service.
407 * All following states will have a h.sw instance!
408 */
409 WAIT_DESCRIPTION_STAT_REPLY(false) {
410 @Override
411 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
412 throws SwitchStateException {
413 // Read description, if it has been updated
414 if (m.getStatsType() != OFStatsType.DESC) {
415 log.warn("Expecting Description stats but received stats "
416 + "type {} from {}. Ignoring ...", m.getStatsType(),
417 h.channel.getRemoteAddress());
418 return;
419 }
420 log.info("Received switch description reply from switch at {}",
421 h.channel.getRemoteAddress());
422 OFDescStatsReply drep = (OFDescStatsReply) m;
423 // Here is where we differentiate between different kinds of switches
424 h.sw = h.controller.getOFSwitchInstance(h.thisdpid, drep, h.ofVersion);
425
426 h.sw.setOFVersion(h.ofVersion);
427 h.sw.setFeaturesReply(h.featuresReply);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700428 //h.sw.setPortDescReply(h.portDescReply);
429 h.sw.setPortDescReplies(h.portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700430 h.sw.setConnected(true);
431 h.sw.setChannel(h.channel);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700432// boolean success = h.sw.connectSwitch();
433//
434// if (!success) {
435// disconnectDuplicate(h);
436// return;
437// }
tom7ef8ff92014-09-17 13:08:06 -0700438 // set switch information
439
440
441
alshabib09d48be2014-10-03 15:43:33 -0700442 log.debug("Switch {} bound to class {}, description {}",
tom7ef8ff92014-09-17 13:08:06 -0700443 new Object[] {h.sw, h.sw.getClass(), drep });
444 //Put switch in EQUAL mode until we hear back from the global registry
445 //log.debug("Setting new switch {} to EQUAL and sending Role request",
446 // h.sw.getStringId());
447 //h.sw.activateEqualSwitch();
448 //h.setSwitchRole(RoleState.EQUAL);
449
450 h.sw.startDriverHandshake();
alshabib9eab22f2014-10-20 17:17:31 -0700451 if (h.sw.isDriverHandshakeComplete()) {
452 if (!h.sw.connectSwitch()) {
453 disconnectDuplicate(h);
454 }
Thomas Vachuska39274462014-12-02 13:23:50 -0800455 handlePendingPortStatusMessages(h);
alshabib9eab22f2014-10-20 17:17:31 -0700456 h.setState(ACTIVE);
457 } else {
458 h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
459 }
tom7ef8ff92014-09-17 13:08:06 -0700460
461 }
462
463 @Override
464 void processOFError(OFChannelHandler h, OFErrorMsg m) {
465 logErrorDisconnect(h, m);
466 }
467
468 @Override
469 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
470 throws IOException, SwitchStateException {
471 illegalMessageReceived(h, m);
472 }
473
474 @Override
475 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
476 throws IOException {
477 h.pendingPortStatusMsg.add(m);
478 }
479 },
480
481
482 /**
483 * We are waiting for the respective switch driver to complete its
484 * configuration. Notice that we do not consider this to be part of the main
485 * switch-controller handshake. But we do consider it as a step that comes
486 * before we declare the switch as available to the controller.
487 * Next State: depends on the role of this controller for this switch - either
488 * MASTER or EQUAL.
489 */
490 WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
491
492 @Override
493 void processOFError(OFChannelHandler h, OFErrorMsg m)
494 throws IOException {
495 // will never be called. We override processOFMessage
496 }
497
alshabibd7963912014-10-20 14:52:04 -0700498
499
tom7ef8ff92014-09-17 13:08:06 -0700500 @Override
501 void processOFMessage(OFChannelHandler h, OFMessage m)
502 throws IOException, SwitchStateException {
alshabibd7963912014-10-20 14:52:04 -0700503
504 if (h.sw.isDriverHandshakeComplete()) {
505 moveToActive(h);
alshabib9eab22f2014-10-20 17:17:31 -0700506 h.state.processOFMessage(h, m);
507 return;
alshabibd7963912014-10-20 14:52:04 -0700508
509 }
510
tom7ef8ff92014-09-17 13:08:06 -0700511 if (m.getType() == OFType.ECHO_REQUEST) {
512 processOFEchoRequest(h, (OFEchoRequest) m);
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700513 } else if (m.getType() == OFType.ECHO_REPLY) {
514 processOFEchoReply(h, (OFEchoReply) m);
tom7ef8ff92014-09-17 13:08:06 -0700515 } else if (m.getType() == OFType.ROLE_REPLY) {
516 h.sw.handleRole(m);
517 } else if (m.getType() == OFType.ERROR) {
518 if (!h.sw.handleRoleError((OFErrorMsg)m)) {
519 h.sw.processDriverHandshakeMessage(m);
520 if (h.sw.isDriverHandshakeComplete()) {
alshabibd7963912014-10-20 14:52:04 -0700521 moveToActive(h);
tom7ef8ff92014-09-17 13:08:06 -0700522 }
523 }
524 } else {
525 if (m.getType() == OFType.EXPERIMENTER &&
526 ((OFExperimenter) m).getExperimenter() ==
527 RoleManager.NICIRA_EXPERIMENTER) {
528 h.sw.handleNiciraRole(m);
529 } else {
530 h.sw.processDriverHandshakeMessage(m);
531 if (h.sw.isDriverHandshakeComplete()) {
alshabibd7963912014-10-20 14:52:04 -0700532 moveToActive(h);
tom7ef8ff92014-09-17 13:08:06 -0700533 }
534 }
535 }
536 }
537
538 @Override
539 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
540 throws IOException, SwitchStateException {
541 h.pendingPortStatusMsg.add(m);
542 }
alshabibd7963912014-10-20 14:52:04 -0700543
544 private void moveToActive(OFChannelHandler h) {
545 boolean success = h.sw.connectSwitch();
Thomas Vachuska39274462014-12-02 13:23:50 -0800546 handlePendingPortStatusMessages(h);
alshabibd7963912014-10-20 14:52:04 -0700547 h.setState(ACTIVE);
548 if (!success) {
549 disconnectDuplicate(h);
alshabibd7963912014-10-20 14:52:04 -0700550 }
551 }
552
tom7ef8ff92014-09-17 13:08:06 -0700553 },
554
555
556 /**
557 * This controller is in MASTER role for this switch. We enter this state
558 * after requesting and winning control from the global registry.
559 * The main handshake as well as the switch-driver sub-handshake
560 * is complete at this point.
561 * // XXX S reconsider below
562 * In the (near) future we may deterministically assign controllers to
563 * switches at startup.
564 * We only leave this state if the switch disconnects or
565 * if we send a role request for SLAVE /and/ receive the role reply for
566 * SLAVE.
567 */
568 ACTIVE(true) {
569 @Override
570 void processOFError(OFChannelHandler h, OFErrorMsg m)
571 throws IOException, SwitchStateException {
572 // if we get here, then the error message is for something else
573 if (m.getErrType() == OFErrorType.BAD_REQUEST &&
574 ((OFBadRequestErrorMsg) m).getCode() ==
575 OFBadRequestCode.EPERM) {
576 // We are the master controller and the switch returned
577 // a permission error. This is a likely indicator that
578 // the switch thinks we are slave. Reassert our
579 // role
580 // FIXME: this could be really bad during role transitions
581 // if two controllers are master (even if its only for
582 // a brief period). We might need to see if these errors
583 // persist before we reassert
alshabib339a3d92014-09-26 17:54:32 -0700584
tom7ef8ff92014-09-17 13:08:06 -0700585 h.sw.reassertRole();
586 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
587 ((OFFlowModFailedErrorMsg) m).getCode() ==
588 OFFlowModFailedCode.ALL_TABLES_FULL) {
589 h.sw.setTableFull(true);
590 } else {
591 logError(h, m);
592 }
593 h.dispatchMessage(m);
594 }
595
596 @Override
597 void processOFStatisticsReply(OFChannelHandler h,
598 OFStatsReply m) {
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700599 if (m.getStatsType().equals(OFStatsType.PORT_DESC)) {
600 h.sw.setPortDescReply((OFPortDescStatsReply) m);
601 }
tom7ef8ff92014-09-17 13:08:06 -0700602 h.dispatchMessage(m);
603 }
604
605 @Override
606 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
607 throws SwitchStateException {
608 h.sw.handleNiciraRole(m);
609 }
610
611 @Override
612 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
613 throws SwitchStateException {
614 h.sw.handleRole(m);
615 }
616
617 @Override
618 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
619 throws SwitchStateException {
620 handlePortStatusMessage(h, m, true);
Thomas Vachuska39274462014-12-02 13:23:50 -0800621 //h.dispatchMessage(m);
tom7ef8ff92014-09-17 13:08:06 -0700622 }
623
624 @Override
625 void processOFPacketIn(OFChannelHandler h, OFPacketIn m) {
alshabib9eab22f2014-10-20 17:17:31 -0700626// OFPacketOut out =
627// h.sw.factory().buildPacketOut()
628// .setXid(m.getXid())
629// .setBufferId(m.getBufferId()).build();
630// h.sw.sendMsg(out);
tom7ef8ff92014-09-17 13:08:06 -0700631 h.dispatchMessage(m);
632 }
633
634 @Override
635 void processOFFlowRemoved(OFChannelHandler h,
636 OFFlowRemoved m) {
637 h.dispatchMessage(m);
638 }
639
640 @Override
641 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
642 h.dispatchMessage(m);
643 }
644
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700645 @Override
646 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m) {
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700647 h.sw.setFeaturesReply(m);
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700648 h.dispatchMessage(m);
649 }
650
tom7ef8ff92014-09-17 13:08:06 -0700651 };
652
653 private final boolean handshakeComplete;
654 ChannelState(boolean handshakeComplete) {
655 this.handshakeComplete = handshakeComplete;
656 }
657
658 /**
659 * Is this a state in which the handshake has completed?
660 * @return true if the handshake is complete
661 */
662 public boolean isHandshakeComplete() {
663 return handshakeComplete;
664 }
665
666 /**
667 * Get a string specifying the switch connection, state, and
668 * message received. To be used as message for SwitchStateException
669 * or log messages
670 * @param h The channel handler (to get switch information_
671 * @param m The OFMessage that has just been received
672 * @param details A string giving more details about the exact nature
673 * of the problem.
674 * @return display string
675 */
676 // needs to be protected because enum members are actually subclasses
677 protected String getSwitchStateMessage(OFChannelHandler h,
678 OFMessage m,
679 String details) {
680 return String.format("Switch: [%s], State: [%s], received: [%s]"
681 + ", details: %s",
682 h.getSwitchInfoString(),
683 this.toString(),
684 m.getType().toString(),
685 details);
686 }
687
688 /**
689 * We have an OFMessage we didn't expect given the current state and
690 * we want to treat this as an error.
691 * We currently throw an exception that will terminate the connection
692 * However, we could be more forgiving
693 * @param h the channel handler that received the message
694 * @param m the message
Jonathan Hart147b2ac2014-10-23 10:03:52 -0700695 * @throws SwitchStateException we always throw the exception
tom7ef8ff92014-09-17 13:08:06 -0700696 */
Jonathan Hart147b2ac2014-10-23 10:03:52 -0700697 // needs to be protected because enum members are actually subclasses
tom7ef8ff92014-09-17 13:08:06 -0700698 protected void illegalMessageReceived(OFChannelHandler h, OFMessage m)
699 throws SwitchStateException {
700 String msg = getSwitchStateMessage(h, m,
701 "Switch should never send this message in the current state");
702 throw new SwitchStateException(msg);
703
704 }
705
706 /**
707 * We have an OFMessage we didn't expect given the current state and
708 * we want to ignore the message.
709 * @param h the channel handler the received the message
710 * @param m the message
711 */
712 protected void unhandledMessageReceived(OFChannelHandler h,
713 OFMessage m) {
714 if (log.isDebugEnabled()) {
715 String msg = getSwitchStateMessage(h, m,
716 "Ignoring unexpected message");
717 log.debug(msg);
718 }
719 }
720
721 /**
722 * Log an OpenFlow error message from a switch.
723 * @param h The switch that sent the error
724 * @param error The error message
725 */
726 protected void logError(OFChannelHandler h, OFErrorMsg error) {
alshabib09d48be2014-10-03 15:43:33 -0700727 log.error("{} from switch {} in state {}",
tom7ef8ff92014-09-17 13:08:06 -0700728 new Object[] {
729 error,
730 h.getSwitchInfoString(),
731 this.toString()});
732 }
733
734 /**
735 * Log an OpenFlow error message from a switch and disconnect the
736 * channel.
737 *
738 * @param h the IO channel for this switch.
739 * @param error The error message
740 */
741 protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
742 logError(h, error);
743 h.channel.disconnect();
744 }
745
746 /**
747 * log an error message for a duplicate dpid and disconnect this channel.
748 * @param h the IO channel for this switch.
749 */
750 protected void disconnectDuplicate(OFChannelHandler h) {
751 log.error("Duplicated dpid or incompleted cleanup - "
752 + "disconnecting channel {}", h.getSwitchInfoString());
753 h.duplicateDpidFound = Boolean.TRUE;
754 h.channel.disconnect();
755 }
756
757
758
759 /**
760 * Handles all pending port status messages before a switch is declared
761 * activated in MASTER or EQUAL role. Note that since this handling
762 * precedes the activation (and therefore notification to IOFSwitchListerners)
763 * the changes to ports will already be visible once the switch is
764 * activated. As a result, no notifications are sent out for these
765 * pending portStatus messages.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700766 *
767 * @param h the channel handler that received the message
tom7ef8ff92014-09-17 13:08:06 -0700768 */
769 protected void handlePendingPortStatusMessages(OFChannelHandler h) {
770 try {
771 handlePendingPortStatusMessages(h, 0);
772 } catch (SwitchStateException e) {
773 log.error(e.getMessage());
774 }
775 }
776
777 private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
778 throws SwitchStateException {
779 if (h.sw == null) {
780 String msg = "State machine error: switch is null. Should never " +
781 "happen";
782 throw new SwitchStateException(msg);
783 }
Thomas Vachuska39274462014-12-02 13:23:50 -0800784 log.info("Processing {} pending port status messages for {}",
785 h.pendingPortStatusMsg.size(), h.sw.getStringId());
786
tom7ef8ff92014-09-17 13:08:06 -0700787 ArrayList<OFPortStatus> temp = new ArrayList<OFPortStatus>();
788 for (OFPortStatus ps: h.pendingPortStatusMsg) {
789 temp.add(ps);
790 handlePortStatusMessage(h, ps, false);
791 }
tom7ef8ff92014-09-17 13:08:06 -0700792 // expensive but ok - we don't expect too many port-status messages
793 // note that we cannot use clear(), because of the reasons below
794 h.pendingPortStatusMsg.removeAll(temp);
Thomas Vachuska39274462014-12-02 13:23:50 -0800795 temp.clear();
tom7ef8ff92014-09-17 13:08:06 -0700796 // the iterator above takes a snapshot of the list - so while we were
797 // dealing with the pending port-status messages, we could have received
798 // newer ones. Handle them recursively, but break the recursion after
799 // five steps to avoid an attack.
800 if (!h.pendingPortStatusMsg.isEmpty() && ++index < 5) {
801 handlePendingPortStatusMessages(h, index);
802 }
803 }
804
805 /**
806 * Handle a port status message.
807 *
808 * Handle a port status message by updating the port maps in the
809 * IOFSwitch instance and notifying Controller about the change so
810 * it can dispatch a switch update.
811 *
812 * @param h The OFChannelHhandler that received the message
813 * @param m The PortStatus message we received
814 * @param doNotify if true switch port changed events will be
815 * dispatched
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800816 * @throws SwitchStateException if the switch is not bound to the channel
tom7ef8ff92014-09-17 13:08:06 -0700817 *
818 */
819 protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
820 boolean doNotify) throws SwitchStateException {
821 if (h.sw == null) {
822 String msg = getSwitchStateMessage(h, m,
823 "State machine error: switch is null. Should never " +
824 "happen");
825 throw new SwitchStateException(msg);
826 }
827
828 h.sw.handleMessage(m);
829 }
830
831
832 /**
833 * Process an OF message received on the channel and
834 * update state accordingly.
835 *
836 * The main "event" of the state machine. Process the received message,
837 * send follow up message if required and update state if required.
838 *
839 * Switches on the message type and calls more specific event handlers
840 * for each individual OF message type. If we receive a message that
841 * is supposed to be sent from a controller to a switch we throw
842 * a SwitchStateExeption.
843 *
844 * The more specific handlers can also throw SwitchStateExceptions
845 *
846 * @param h The OFChannelHandler that received the message
847 * @param m The message we received.
Thomas Vachuskab14c77a2014-11-04 18:08:01 -0800848 * @throws SwitchStateException if the switch is not bound to the channel
849 * @throws IOException if unable to send message back to the switch
tom7ef8ff92014-09-17 13:08:06 -0700850 */
851 void processOFMessage(OFChannelHandler h, OFMessage m)
852 throws IOException, SwitchStateException {
853 switch(m.getType()) {
854 case HELLO:
855 processOFHello(h, (OFHello) m);
856 break;
857 case BARRIER_REPLY:
858 processOFBarrierReply(h, (OFBarrierReply) m);
859 break;
860 case ECHO_REPLY:
861 processOFEchoReply(h, (OFEchoReply) m);
862 break;
863 case ECHO_REQUEST:
864 processOFEchoRequest(h, (OFEchoRequest) m);
865 break;
866 case ERROR:
867 processOFError(h, (OFErrorMsg) m);
868 break;
869 case FEATURES_REPLY:
870 processOFFeaturesReply(h, (OFFeaturesReply) m);
871 break;
872 case FLOW_REMOVED:
873 processOFFlowRemoved(h, (OFFlowRemoved) m);
874 break;
875 case GET_CONFIG_REPLY:
876 processOFGetConfigReply(h, (OFGetConfigReply) m);
877 break;
878 case PACKET_IN:
879 processOFPacketIn(h, (OFPacketIn) m);
880 break;
881 case PORT_STATUS:
882 processOFPortStatus(h, (OFPortStatus) m);
883 break;
884 case QUEUE_GET_CONFIG_REPLY:
885 processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
886 break;
887 case STATS_REPLY: // multipart_reply in 1.3
888 processOFStatisticsReply(h, (OFStatsReply) m);
889 break;
890 case EXPERIMENTER:
891 processOFExperimenter(h, (OFExperimenter) m);
892 break;
893 case ROLE_REPLY:
894 processOFRoleReply(h, (OFRoleReply) m);
895 break;
896 case GET_ASYNC_REPLY:
897 processOFGetAsyncReply(h, (OFAsyncGetReply) m);
898 break;
899
900 // The following messages are sent to switches. The controller
901 // should never receive them
902 case SET_CONFIG:
903 case GET_CONFIG_REQUEST:
904 case PACKET_OUT:
905 case PORT_MOD:
906 case QUEUE_GET_CONFIG_REQUEST:
907 case BARRIER_REQUEST:
908 case STATS_REQUEST: // multipart request in 1.3
909 case FEATURES_REQUEST:
910 case FLOW_MOD:
911 case GROUP_MOD:
912 case TABLE_MOD:
913 case GET_ASYNC_REQUEST:
914 case SET_ASYNC:
915 case METER_MOD:
916 default:
917 illegalMessageReceived(h, m);
918 break;
919 }
920 }
921
922 /*-----------------------------------------------------------------
923 * Default implementation for message handlers in any state.
924 *
925 * Individual states must override these if they want a behavior
926 * that differs from the default.
927 *
928 * In general, these handlers simply ignore the message and do
929 * nothing.
930 *
931 * There are some exceptions though, since some messages really
932 * are handled the same way in every state (e.g., ECHO_REQUST) or
933 * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
934 -----------------------------------------------------------------*/
935
936 void processOFHello(OFChannelHandler h, OFHello m)
937 throws IOException, SwitchStateException {
938 // we only expect hello in the WAIT_HELLO state
939 illegalMessageReceived(h, m);
940 }
941
942 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
943 throws IOException {
944 // Silently ignore.
945 }
946
947 void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
948 throws IOException {
949 if (h.ofVersion == null) {
950 log.error("No OF version set for {}. Not sending Echo REPLY",
951 h.channel.getRemoteAddress());
952 return;
953 }
954 OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
955 h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
956 OFEchoReply reply = factory
957 .buildEchoReply()
958 .setXid(m.getXid())
959 .setData(m.getData())
960 .build();
961 h.channel.write(Collections.singletonList(reply));
962 }
963
964 void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
965 throws IOException {
966 // Do nothing with EchoReplies !!
967 }
968
969 // no default implementation for OFError
970 // every state must override it
971 abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
972 throws IOException, SwitchStateException;
973
974
975 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
976 throws IOException, SwitchStateException {
977 unhandledMessageReceived(h, m);
978 }
979
980 void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
981 throws IOException {
982 unhandledMessageReceived(h, m);
983 }
984
985 void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
986 throws IOException, SwitchStateException {
987 // we only expect config replies in the WAIT_CONFIG_REPLY state
988 illegalMessageReceived(h, m);
989 }
990
991 void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
992 throws IOException {
993 unhandledMessageReceived(h, m);
994 }
995
996 // no default implementation. Every state needs to handle it.
997 abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
998 throws IOException, SwitchStateException;
999
1000 void processOFQueueGetConfigReply(OFChannelHandler h,
1001 OFQueueGetConfigReply m)
1002 throws IOException {
1003 unhandledMessageReceived(h, m);
1004 }
1005
1006 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
1007 throws IOException, SwitchStateException {
1008 unhandledMessageReceived(h, m);
1009 }
1010
1011 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1012 throws IOException, SwitchStateException {
1013 // TODO: it might make sense to parse the vendor message here
1014 // into the known vendor messages we support and then call more
1015 // specific event handlers
1016 unhandledMessageReceived(h, m);
1017 }
1018
1019 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1020 throws SwitchStateException, IOException {
1021 unhandledMessageReceived(h, m);
1022 }
1023
1024 void processOFGetAsyncReply(OFChannelHandler h,
1025 OFAsyncGetReply m) {
1026 unhandledMessageReceived(h, m);
1027 }
1028
1029 }
1030
1031
1032
1033 //*************************
1034 // Channel handler methods
1035 //*************************
1036
1037 @Override
1038 public void channelConnected(ChannelHandlerContext ctx,
1039 ChannelStateEvent e) throws Exception {
1040 channel = e.getChannel();
1041 log.info("New switch connection from {}",
1042 channel.getRemoteAddress());
alshabib70fc7fb2015-01-06 11:04:29 -08001043 /*
1044 hack to wait for the switch to tell us what it's
1045 max version is. This is not spec compliant and should
1046 be removed as soon as switches behave better.
1047 */
1048 //sendHandshakeHelloMessage();
tom7ef8ff92014-09-17 13:08:06 -07001049 setState(ChannelState.WAIT_HELLO);
1050 }
1051
1052 @Override
1053 public void channelDisconnected(ChannelHandlerContext ctx,
1054 ChannelStateEvent e) throws Exception {
1055 log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
1056 getSwitchInfoString());
1057 if (thisdpid != 0) {
1058 if (!duplicateDpidFound) {
1059 // if the disconnected switch (on this ChannelHandler)
1060 // was not one with a duplicate-dpid, it is safe to remove all
1061 // state for it at the controller. Notice that if the disconnected
1062 // switch was a duplicate-dpid, calling the method below would clear
1063 // all state for the original switch (with the same dpid),
1064 // which we obviously don't want.
Yuta HIGUCHI17679472014-10-09 21:53:14 -07001065 log.info("{}:removal called", getSwitchInfoString());
Jonathan Hart147b2ac2014-10-23 10:03:52 -07001066 if (sw != null) {
1067 sw.removeConnectedSwitch();
1068 }
tom7ef8ff92014-09-17 13:08:06 -07001069 } else {
1070 // A duplicate was disconnected on this ChannelHandler,
1071 // this is the same switch reconnecting, but the original state was
1072 // not cleaned up - XXX check liveness of original ChannelHandler
Yuta HIGUCHI17679472014-10-09 21:53:14 -07001073 log.info("{}:duplicate found", getSwitchInfoString());
tom7ef8ff92014-09-17 13:08:06 -07001074 duplicateDpidFound = Boolean.FALSE;
1075 }
1076 } else {
1077 log.warn("no dpid in channelHandler registered for "
1078 + "disconnected switch {}", getSwitchInfoString());
1079 }
1080 }
1081
1082 @Override
1083 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
1084 throws Exception {
1085 if (e.getCause() instanceof ReadTimeoutException) {
1086 // switch timeout
1087 log.error("Disconnecting switch {} due to read timeout",
1088 getSwitchInfoString());
1089 ctx.getChannel().close();
1090 } else if (e.getCause() instanceof HandshakeTimeoutException) {
1091 log.error("Disconnecting switch {}: failed to complete handshake",
1092 getSwitchInfoString());
1093 ctx.getChannel().close();
1094 } else if (e.getCause() instanceof ClosedChannelException) {
1095 log.debug("Channel for sw {} already closed", getSwitchInfoString());
1096 } else if (e.getCause() instanceof IOException) {
1097 log.error("Disconnecting switch {} due to IO Error: {}",
1098 getSwitchInfoString(), e.getCause().getMessage());
1099 if (log.isDebugEnabled()) {
1100 // still print stack trace if debug is enabled
1101 log.debug("StackTrace for previous Exception: ", e.getCause());
1102 }
1103 ctx.getChannel().close();
1104 } else if (e.getCause() instanceof SwitchStateException) {
1105 log.error("Disconnecting switch {} due to switch state 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());
1110 }
1111 ctx.getChannel().close();
1112 } else if (e.getCause() instanceof OFParseError) {
1113 log.error("Disconnecting switch "
1114 + getSwitchInfoString() +
1115 " due to message parse failure",
1116 e.getCause());
1117 ctx.getChannel().close();
1118 } else if (e.getCause() instanceof RejectedExecutionException) {
1119 log.warn("Could not process message: queue full");
1120 } else {
1121 log.error("Error while processing message from switch "
1122 + getSwitchInfoString()
1123 + "state " + this.state, e.getCause());
1124 ctx.getChannel().close();
1125 }
1126 }
1127
1128 @Override
1129 public String toString() {
1130 return getSwitchInfoString();
1131 }
1132
1133 @Override
1134 public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
1135 throws Exception {
1136 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1137 OFMessage m = factory.buildEchoRequest().build();
alshabib09d48be2014-10-03 15:43:33 -07001138 log.debug("Sending Echo Request on idle channel: {}",
tom7ef8ff92014-09-17 13:08:06 -07001139 e.getChannel().getPipeline().getLast().toString());
1140 e.getChannel().write(Collections.singletonList(m));
1141 // XXX S some problems here -- echo request has no transaction id, and
1142 // echo reply is not correlated to the echo request.
1143 }
1144
1145 @Override
1146 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
1147 throws Exception {
1148 if (e.getMessage() instanceof List) {
1149 @SuppressWarnings("unchecked")
1150 List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
1151
1152
1153 for (OFMessage ofm : msglist) {
1154 // Do the actual packet processing
1155 state.processOFMessage(this, ofm);
1156 }
1157 } else {
1158 state.processOFMessage(this, (OFMessage) e.getMessage());
1159 }
1160 }
1161
1162
1163
1164 //*************************
1165 // Channel utility methods
1166 //*************************
1167
1168 /**
1169 * Is this a state in which the handshake has completed?
1170 * @return true if the handshake is complete
1171 */
1172 public boolean isHandshakeComplete() {
1173 return this.state.isHandshakeComplete();
1174 }
1175
1176 private void dispatchMessage(OFMessage m) {
1177 sw.handleMessage(m);
1178 }
1179
1180 /**
1181 * Return a string describing this switch based on the already available
1182 * information (DPID and/or remote socket).
1183 * @return display string
1184 */
1185 private String getSwitchInfoString() {
1186 if (sw != null) {
1187 return sw.toString();
1188 }
1189 String channelString;
1190 if (channel == null || channel.getRemoteAddress() == null) {
1191 channelString = "?";
1192 } else {
1193 channelString = channel.getRemoteAddress().toString();
1194 }
1195 String dpidString;
1196 if (featuresReply == null) {
1197 dpidString = "?";
1198 } else {
1199 dpidString = featuresReply.getDatapathId().toString();
1200 }
1201 return String.format("[%s DPID[%s]]", channelString, dpidString);
1202 }
1203
1204 /**
1205 * Update the channels state. Only called from the state machine.
1206 * TODO: enforce restricted state transitions
1207 * @param state
1208 */
1209 private void setState(ChannelState state) {
1210 this.state = state;
1211 }
1212
1213 /**
1214 * Send hello message to the switch using the handshake transactions ids.
1215 * @throws IOException
1216 */
1217 private void sendHandshakeHelloMessage() throws IOException {
1218 // The OF protocol requires us to start things off by sending the highest
1219 // version of the protocol supported.
1220
1221 // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
1222 // see Sec. 7.5.1 of the OF1.3.4 spec
1223 U32 bitmap = U32.ofRaw(0x00000012);
1224 OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
1225 .setBitmaps(Collections.singletonList(bitmap))
1226 .build();
1227 OFMessage.Builder mb = factory13.buildHello()
1228 .setXid(this.handshakeTransactionIds--)
1229 .setElements(Collections.singletonList(hem));
1230 log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
1231 channel.write(Collections.singletonList(mb.build()));
1232 }
1233
1234 /**
1235 * Send featuresRequest msg to the switch using the handshake transactions ids.
1236 * @throws IOException
1237 */
1238 private void sendHandshakeFeaturesRequestMessage() throws IOException {
1239 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1240 OFMessage m = factory.buildFeaturesRequest()
1241 .setXid(this.handshakeTransactionIds--)
1242 .build();
1243 channel.write(Collections.singletonList(m));
1244 }
1245
1246 /**
1247 * Send the configuration requests to tell the switch we want full
1248 * packets.
1249 * @throws IOException
1250 */
1251 private void sendHandshakeSetConfig() throws IOException {
1252 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1253 //log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
1254 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
1255
1256 // Ensure we receive the full packet via PacketIn
1257 // FIXME: We don't set the reassembly flags.
1258 OFSetConfig sc = factory
1259 .buildSetConfig()
1260 .setMissSendLen((short) 0xffff)
1261 .setXid(this.handshakeTransactionIds--)
1262 .build();
1263 msglist.add(sc);
1264
1265 // Barrier
1266 OFBarrierRequest br = factory
1267 .buildBarrierRequest()
1268 .setXid(this.handshakeTransactionIds--)
1269 .build();
1270 msglist.add(br);
1271
1272 // Verify (need barrier?)
1273 OFGetConfigRequest gcr = factory
1274 .buildGetConfigRequest()
1275 .setXid(this.handshakeTransactionIds--)
1276 .build();
1277 msglist.add(gcr);
1278 channel.write(msglist);
1279 }
1280
1281 /**
1282 * send a description state request.
1283 * @throws IOException
1284 */
1285 private void sendHandshakeDescriptionStatsRequest() throws IOException {
1286 // Get Description to set switch-specific flags
1287 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1288 OFDescStatsRequest dreq = factory
1289 .buildDescStatsRequest()
1290 .setXid(handshakeTransactionIds--)
1291 .build();
1292 channel.write(Collections.singletonList(dreq));
1293 }
1294
1295 private void sendHandshakeOFPortDescRequest() throws IOException {
1296 // Get port description for 1.3 switch
1297 OFPortDescStatsRequest preq = factory13
1298 .buildPortDescStatsRequest()
1299 .setXid(handshakeTransactionIds--)
1300 .build();
1301 channel.write(Collections.singletonList(preq));
1302 }
1303
1304 ChannelState getStateForTesting() {
1305 return state;
1306 }
1307
1308}