blob: 3b18a5959646a2adc900a0001ff166633561a4d0 [file] [log] [blame]
tom0eb04ca2014-08-25 14:34:51 -07001package net.onrc.onos.of.ctl.internal;
2
3import java.io.IOException;
4import java.nio.channels.ClosedChannelException;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.List;
9import java.util.concurrent.CopyOnWriteArrayList;
10import java.util.concurrent.RejectedExecutionException;
11
12import net.onrc.onos.of.ctl.IOFSwitch;
13import net.onrc.onos.of.ctl.IOFSwitch.PortChangeEvent;
14import net.onrc.onos.of.ctl.Role;
15import net.onrc.onos.of.ctl.annotations.LogMessageDoc;
16import net.onrc.onos.of.ctl.annotations.LogMessageDocs;
17import net.onrc.onos.of.ctl.debugcounter.IDebugCounterService.CounterException;
18import net.onrc.onos.of.ctl.internal.Controller.Counters;
19import net.onrc.onos.of.ctl.internal.OFChannelHandler.ChannelState.RoleReplyInfo;
20
21import org.jboss.netty.channel.Channel;
22import org.jboss.netty.channel.ChannelHandlerContext;
23import org.jboss.netty.channel.ChannelStateEvent;
24import org.jboss.netty.channel.ExceptionEvent;
25import org.jboss.netty.channel.MessageEvent;
26import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
27import org.jboss.netty.handler.timeout.IdleStateEvent;
28import org.jboss.netty.handler.timeout.ReadTimeoutException;
29import org.projectfloodlight.openflow.exceptions.OFParseError;
30import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
31import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
32import org.projectfloodlight.openflow.protocol.OFBarrierReply;
33import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
34import org.projectfloodlight.openflow.protocol.OFControllerRole;
35import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
37import org.projectfloodlight.openflow.protocol.OFEchoReply;
38import org.projectfloodlight.openflow.protocol.OFEchoRequest;
39import org.projectfloodlight.openflow.protocol.OFErrorMsg;
40import org.projectfloodlight.openflow.protocol.OFErrorType;
41import org.projectfloodlight.openflow.protocol.OFExperimenter;
42import org.projectfloodlight.openflow.protocol.OFFactory;
43import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
44import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
45import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
46import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
47import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
48import org.projectfloodlight.openflow.protocol.OFHello;
49import org.projectfloodlight.openflow.protocol.OFHelloElem;
50import org.projectfloodlight.openflow.protocol.OFMessage;
51import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
52import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
53import org.projectfloodlight.openflow.protocol.OFPacketIn;
54import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
55import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
56import org.projectfloodlight.openflow.protocol.OFPortStatus;
57import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
58import org.projectfloodlight.openflow.protocol.OFRoleReply;
59import org.projectfloodlight.openflow.protocol.OFRoleRequest;
60import org.projectfloodlight.openflow.protocol.OFSetConfig;
61import org.projectfloodlight.openflow.protocol.OFStatsReply;
62import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
63import org.projectfloodlight.openflow.protocol.OFStatsType;
64import org.projectfloodlight.openflow.protocol.OFType;
65import org.projectfloodlight.openflow.protocol.OFVersion;
66import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
67import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
68import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
69import org.projectfloodlight.openflow.types.U32;
70import org.projectfloodlight.openflow.types.U64;
71import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73/**
74 * Channel handler deals with the switch connection and dispatches
75 * switch messages to the appropriate locations.
76 */
77class OFChannelHandler extends IdleStateAwareChannelHandler {
78 private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
79 private static final long DEFAULT_ROLE_TIMEOUT_MS = 2 * 1000; // 10 sec
80 private final Controller controller;
81 private final Counters counters;
82 private IOFSwitch sw;
83 private long thisdpid; // channelHandler cached value of connected switch id
84 private Channel channel;
85 // State needs to be volatile because the HandshakeTimeoutHandler
86 // needs to check if the handshake is complete
87 private volatile ChannelState state;
88
89 // All role messaging is handled by the roleChanger. The channel state machine
90 // coordinates between the roleChanger and the controller-global-registry-service
91 // to determine controller roles per switch.
92 private RoleChanger roleChanger;
93 // Used to coordinate between the controller and the cleanup thread(?)
94 // for access to the global registry on a per switch basis.
95 volatile Boolean controlRequested;
96 // When a switch with a duplicate dpid is found (i.e we already have a
97 // connected switch with the same dpid), the new switch is immediately
98 // disconnected. At that point netty callsback channelDisconnected() which
99 // proceeds to cleaup switch state - we need to ensure that it does not cleanup
100 // switch state for the older (still connected) switch
101 private volatile Boolean duplicateDpidFound;
102
103 // Temporary storage for switch-features and port-description
104 private OFFeaturesReply featuresReply;
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
124 */
125 OFChannelHandler(Controller controller) {
126 this.controller = controller;
127 this.counters = controller.getCounters();
128 this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
129 this.state = ChannelState.INIT;
130 this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
131 factory13 = controller.getOFMessageFactory13();
132 factory10 = controller.getOFMessageFactory10();
133 controlRequested = Boolean.FALSE;
134 duplicateDpidFound = Boolean.FALSE;
135 }
136
137 //*******************
138 // Role Handling
139 //*******************
140
141 /**
142 * When we remove a pending role request we use this enum to indicate how we
143 * arrived at the decision. When we send a role request to the switch, we
144 * also use this enum to indicate what we expect back from the switch, so the
145 * role changer can match the reply to our expectation.
146 */
147 public enum RoleRecvStatus {
148 /** The switch returned an error indicating that roles are not.
149 * supported*/
150 UNSUPPORTED,
151 /** The request timed out. */
152 NO_REPLY,
153 /** The reply was old, there is a newer request pending. */
154 OLD_REPLY,
155 /**
156 * The reply's role matched the role that this controller set in the
157 * request message - invoked either initially at startup or to reassert
158 * current role.
159 */
160 MATCHED_CURRENT_ROLE,
161 /**
162 * The reply's role matched the role that this controller set in the
163 * request message - this is the result of a callback from the
164 * global registry, followed by a role request sent to the switch.
165 */
166 MATCHED_SET_ROLE,
167 /**
168 * The reply's role was a response to the query made by this controller.
169 */
170 REPLY_QUERY,
171 /** We received a role reply message from the switch
172 * but the expectation was unclear, or there was no expectation.
173 */
174 OTHER_EXPECTATION,
175 }
176
177 /**
178 * Forwards to RoleChanger. See there.
179 * @param role
180 */
181 public void sendRoleRequest(Role role, RoleRecvStatus expectation) {
182 try {
183 roleChanger.sendRoleRequest(role, expectation);
184 } catch (IOException e) {
185 log.error("Disconnecting switch {} due to IO Error: {}",
186 getSwitchInfoString(), e.getMessage());
187 channel.close();
188 }
189 }
190
191 // XXX S consider if necessary
192 public void disconnectSwitch() {
193 sw.disconnectSwitch();
194 }
195
196 /**
197 * A utility class to handle role requests and replies for this channel.
198 * After a role request is submitted the role changer keeps track of the
199 * pending request, collects the reply (if any) and times out the request
200 * if necessary.
201 *
202 * To simplify role handling we only keep track of the /last/ pending
203 * role reply send to the switch. If multiple requests are pending and
204 * we receive replies for earlier requests we ignore them. However, this
205 * way of handling pending requests implies that we could wait forever if
206 * a new request is submitted before the timeout triggers. If necessary
207 * we could work around that though.
208 */
209 private class RoleChanger {
210 // indicates that a request is currently pending
211 // needs to be volatile to allow correct double-check idiom
212 private volatile boolean requestPending;
213 // the transaction Id of the pending request
214 private int pendingXid;
215 // the role that's pending
216 private Role pendingRole;
217 // system time in MS when we send the request
218 private long roleSubmitTime;
219 // the timeout to use
220 private final long roleTimeoutMs;
221 // the expectation set by the caller for the returned role
222 private RoleRecvStatus expectation;
223
224 public RoleChanger(long roleTimeoutMs) {
225 this.requestPending = false;
226 this.roleSubmitTime = 0;
227 this.pendingXid = -1;
228 this.pendingRole = null;
229 this.roleTimeoutMs = roleTimeoutMs;
230 this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
231 }
232
233 /**
234 * Send NX role request message to the switch requesting the specified
235 * role.
236 *
237 * @param sw switch to send the role request message to
238 * @param role role to request
239 */
240 private int sendNxRoleRequest(Role role) throws IOException {
241 // Convert the role enum to the appropriate role to send
242 OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
243 switch (role) {
244 case MASTER:
245 roleToSend = OFNiciraControllerRole.ROLE_MASTER;
246 break;
247 case SLAVE:
248 case EQUAL:
249 default:
250 // ensuring that the only two roles sent to 1.0 switches with
251 // Nicira role support, are MASTER and SLAVE
252 roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
253 log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
254 }
255 int xid = sw.getNextTransactionId();
256 OFExperimenter roleRequest = factory10
257 .buildNiciraControllerRoleRequest()
258 .setXid(xid)
259 .setRole(roleToSend)
260 .build();
261 sw.write(Collections.<OFMessage>singletonList(roleRequest));
262 return xid;
263 }
264
265 private int sendOF13RoleRequest(Role role) throws IOException {
266 // Convert the role enum to the appropriate role to send
267 OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
268 switch (role) {
269 case EQUAL:
270 roleToSend = OFControllerRole.ROLE_EQUAL;
271 break;
272 case MASTER:
273 roleToSend = OFControllerRole.ROLE_MASTER;
274 break;
275 case SLAVE:
276 roleToSend = OFControllerRole.ROLE_SLAVE;
277 break;
278 default:
279 log.warn("Sending default role.noChange to switch {}."
280 + " Should only be used for queries.", sw);
281 }
282
283 int xid = sw.getNextTransactionId();
284 OFRoleRequest rrm = factory13
285 .buildRoleRequest()
286 .setRole(roleToSend)
287 .setXid(xid)
288 .setGenerationId(sw.getNextGenerationId())
289 .build();
290 sw.write(rrm);
291 return xid;
292 }
293
294 /**
295 * Send a role request with the given role to the switch and update
296 * the pending request and timestamp.
297 * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
298 * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
299 * in the IOFSwitch driver. If not supported, this method sends nothing
300 * and returns 'false'. The caller should take appropriate action.
301 *
302 * One other optimization we do here is that for OF1.0 switches with
303 * Nicira role message support, we force the Role.EQUAL to become
304 * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
305 * We cannot expect it to behave like SLAVE. We don't have this problem with
306 * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
307 * SLAVE behavior by using ASYNC messages.
308 *
309 * @param role
310 * @throws IOException
311 * @returns false if and only if the switch does not support role-request
312 * messages, according to the switch driver; true otherwise.
313 */
314 synchronized boolean sendRoleRequest(Role role, RoleRecvStatus exp)
315 throws IOException {
316 this.expectation = exp;
317
318 if (ofVersion == OFVersion.OF_10) {
319 Boolean supportsNxRole = (Boolean)
320 sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
321 if (!supportsNxRole) {
322 log.debug("Switch driver indicates no support for Nicira "
323 + "role request messages. Not sending ...");
324 state.handleUnsentRoleMessage(OFChannelHandler.this, role,
325 expectation);
326 return false;
327 }
328 // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
329 // make Role.EQUAL become Role.SLAVE
330 role = (role == Role.EQUAL) ? Role.SLAVE : role;
331 pendingXid = sendNxRoleRequest(role);
332 pendingRole = role;
333 roleSubmitTime = System.currentTimeMillis();
334 requestPending = true;
335 } else {
336 // OF1.3 switch, use OFPT_ROLE_REQUEST message
337 pendingXid = sendOF13RoleRequest(role);
338 pendingRole = role;
339 roleSubmitTime = System.currentTimeMillis();
340 requestPending = true;
341 }
342 return true;
343 }
344
345 /**
346 * Deliver a received role reply.
347 *
348 * Check if a request is pending and if the received reply matches the
349 * the expected pending reply (we check both role and xid) we set
350 * the role for the switch/channel.
351 *
352 * If a request is pending but doesn't match the reply we ignore it, and
353 * return
354 *
355 * If no request is pending we disconnect with a SwitchStateException
356 *
357 * @param RoleReplyInfo information about role-reply in format that
358 * controller can understand.
359 * @throws SwitchStateException if no request is pending
360 */
361 synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
362 throws SwitchStateException {
363 if (!requestPending) {
364 Role currentRole = (sw != null) ? sw.getRole() : null;
365 if (currentRole != null) {
366 if (currentRole == rri.getRole()) {
367 // Don't disconnect if the role reply we received is
368 // for the same role we are already in.
369 log.debug("Received unexpected RoleReply from "
370 + "Switch: {} in State: {}. "
371 + "Role in reply is same as current role of this "
372 + "controller for this sw. Ignoring ...",
373 getSwitchInfoString(), state.toString());
374 return RoleRecvStatus.OTHER_EXPECTATION;
375 } else {
376 String msg = String.format("Switch: [%s], State: [%s], "
377 + "received unexpected RoleReply[%s]. "
378 + "No roles are pending, and this controller's "
379 + "current role:[%s] does not match reply. "
380 + "Disconnecting switch ... ",
381 OFChannelHandler.this.getSwitchInfoString(),
382 OFChannelHandler.this.state.toString(),
383 rri, currentRole);
384 throw new SwitchStateException(msg);
385 }
386 }
387 log.debug("Received unexpected RoleReply {} from "
388 + "Switch: {} in State: {}. "
389 + "This controller has no current role for this sw. "
390 + "Ignoring ...", new Object[] {rri,
391 getSwitchInfoString(), state});
392 return RoleRecvStatus.OTHER_EXPECTATION;
393 }
394
395 int xid = (int) rri.getXid();
396 Role role = rri.getRole();
397 // XXX S should check generation id meaningfully and other cases of expectations
398 // U64 genId = rri.getGenId();
399
400 if (pendingXid != xid) {
401 log.debug("Received older role reply from " +
402 "switch {} ({}). Ignoring. " +
403 "Waiting for {}, xid={}",
404 new Object[] {getSwitchInfoString(), rri,
405 pendingRole, pendingXid });
406 return RoleRecvStatus.OLD_REPLY;
407 }
408
409 if (pendingRole == role) {
410 log.debug("Received role reply message from {} that matched "
411 + "expected role-reply {} with expectations {}",
412 new Object[] {getSwitchInfoString(), role, expectation});
413 counters.roleReplyReceived.updateCounterWithFlush();
414 //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
415 if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
416 expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
417 return expectation;
418 } else {
419 return RoleRecvStatus.OTHER_EXPECTATION;
420 }
421 }
422
423 // if xids match but role's don't, perhaps its a query (OF1.3)
424 if (expectation == RoleRecvStatus.REPLY_QUERY) {
425 return expectation;
426 }
427
428 return RoleRecvStatus.OTHER_EXPECTATION;
429 }
430
431 /**
432 * Called if we receive an error message. If the xid matches the
433 * pending request we handle it otherwise we ignore it.
434 *
435 * Note: since we only keep the last pending request we might get
436 * error messages for earlier role requests that we won't be able
437 * to handle
438 */
439 synchronized RoleRecvStatus deliverError(OFErrorMsg error)
440 throws SwitchStateException {
441 if (!requestPending) {
442 log.debug("Received an error msg from sw {}, but no pending "
443 + "requests in role-changer; not handling ...",
444 getSwitchInfoString());
445 return RoleRecvStatus.OTHER_EXPECTATION;
446 }
447 if (pendingXid != error.getXid()) {
448 if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
449 log.debug("Received an error msg from sw {} for a role request,"
450 + " but not for pending request in role-changer; "
451 + " ignoring error {} ...",
452 getSwitchInfoString(), error);
453 }
454 return RoleRecvStatus.OTHER_EXPECTATION;
455 }
456 // it is an error related to a currently pending role request message
457 if (error.getErrType() == OFErrorType.BAD_REQUEST) {
458 counters.roleReplyErrorUnsupported.updateCounterWithFlush();
459 log.error("Received a error msg {} from sw {} in state {} for "
460 + "pending role request {}. Switch driver indicates "
461 + "role-messaging is supported. Possible issues in "
462 + "switch driver configuration?", new Object[] {
463 ((OFBadRequestErrorMsg) error).toString(),
464 getSwitchInfoString(), state, pendingRole
465 });
466 return RoleRecvStatus.UNSUPPORTED;
467 }
468
469 if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
470 OFRoleRequestFailedErrorMsg rrerr =
471 (OFRoleRequestFailedErrorMsg) error;
472 switch (rrerr.getCode()) {
473 case BAD_ROLE:
474 // switch says that current-role-req has bad role?
475 // for now we disconnect
476 // fall-thru
477 case STALE:
478 // switch says that current-role-req has stale gen-id?
479 // for now we disconnect
480 // fall-thru
481 case UNSUP:
482 // switch says that current-role-req has role that
483 // cannot be supported? for now we disconnect
484 String msgx = String.format("Switch: [%s], State: [%s], "
485 + "received Error to for pending role request [%s]. "
486 + "Error:[%s]. Disconnecting switch ... ",
487 OFChannelHandler.this.getSwitchInfoString(),
488 OFChannelHandler.this.state.toString(),
489 pendingRole, rrerr);
490 throw new SwitchStateException(msgx);
491 default:
492 break;
493 }
494 }
495
496 // This error message was for a role request message but we dont know
497 // how to handle errors for nicira role request messages
498 return RoleRecvStatus.OTHER_EXPECTATION;
499 }
500
501 /**
502 * Check if a pending role request has timed out.
503 */
504 void checkTimeout() {
505 if (!requestPending) {
506 return;
507 }
508 synchronized (this) {
509 if (!requestPending) {
510 return;
511 }
512 long now = System.currentTimeMillis();
513 if (now - roleSubmitTime > roleTimeoutMs) {
514 // timeout triggered.
515 counters.roleReplyTimeout.updateCounterWithFlush();
516 //setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
517 // XXX S come back to this
518 }
519 }
520 }
521
522 }
523
524 //*************************
525 // Channel State Machine
526 //*************************
527
528 /**
529 * The state machine for handling the switch/channel state. All state
530 * transitions should happen from within the state machine (and not from other
531 * parts of the code)
532 */
533 enum ChannelState {
534 /**
535 * Initial state before channel is connected.
536 */
537 INIT(false) {
538 @Override
539 void processOFMessage(OFChannelHandler h, OFMessage m)
540 throws IOException, SwitchStateException {
541 illegalMessageReceived(h, m);
542 }
543
544 @Override
545 void processOFError(OFChannelHandler h, OFErrorMsg m)
546 throws IOException {
547 // need to implement since its abstract but it will never
548 // be called
549 }
550
551 @Override
552 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
553 throws IOException {
554 unhandledMessageReceived(h, m);
555 }
556 },
557
558 /**
559 * We send a OF 1.3 HELLO to the switch and wait for a Hello from the switch.
560 * Once we receive the reply, we decide on OF 1.3 or 1.0 switch - no other
561 * protocol version is accepted.
562 * We send an OFFeaturesRequest depending on the protocol version selected
563 * Next state is WAIT_FEATURES_REPLY
564 */
565 WAIT_HELLO(false) {
566 @Override
567 void processOFHello(OFChannelHandler h, OFHello m)
568 throws IOException {
569 // TODO We could check for the optional bitmap, but for now
570 // we are just checking the version number.
571 if (m.getVersion() == OFVersion.OF_13) {
572 log.info("Received {} Hello from {}", m.getVersion(),
573 h.channel.getRemoteAddress());
574 h.ofVersion = OFVersion.OF_13;
575 } else if (m.getVersion() == OFVersion.OF_10) {
576 log.info("Received {} Hello from {} - switching to OF "
577 + "version 1.0", m.getVersion(),
578 h.channel.getRemoteAddress());
579 h.ofVersion = OFVersion.OF_10;
580 } else {
581 log.error("Received Hello of version {} from switch at {}. "
582 + "This controller works with OF1.0 and OF1.3 "
583 + "switches. Disconnecting switch ...",
584 m.getVersion(), h.channel.getRemoteAddress());
585 h.channel.disconnect();
586 return;
587 }
588 h.sendHandshakeFeaturesRequestMessage();
589 h.setState(WAIT_FEATURES_REPLY);
590 }
591 @Override
592 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
593 throws IOException, SwitchStateException {
594 illegalMessageReceived(h, m);
595 }
596 @Override
597 void processOFStatisticsReply(OFChannelHandler h,
598 OFStatsReply m)
599 throws IOException, SwitchStateException {
600 illegalMessageReceived(h, m);
601 }
602 @Override
603 void processOFError(OFChannelHandler h, OFErrorMsg m) {
604 logErrorDisconnect(h, m);
605 }
606
607 @Override
608 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
609 throws IOException {
610 unhandledMessageReceived(h, m);
611 }
612 },
613
614
615 /**
616 * We are waiting for a features reply message. Once we receive it, the
617 * behavior depends on whether this is a 1.0 or 1.3 switch. For 1.0,
618 * we send a SetConfig request, barrier, and GetConfig request and the
619 * next state is WAIT_CONFIG_REPLY. For 1.3, we send a Port description
620 * request and the next state is WAIT_PORT_DESC_REPLY.
621 */
622 WAIT_FEATURES_REPLY(false) {
623 @Override
624 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
625 throws IOException {
626 h.thisdpid = m.getDatapathId().getLong();
627 log.info("Received features reply for switch at {} with dpid {}",
628 h.getSwitchInfoString(), h.thisdpid);
629 //update the controller about this connected switch
630 boolean success = h.controller.addConnectedSwitch(
631 h.thisdpid, h);
632 if (!success) {
633 disconnectDuplicate(h);
634 return;
635 }
636
637 h.featuresReply = m; //temp store
638 if (h.ofVersion == OFVersion.OF_10) {
639 h.sendHandshakeSetConfig();
640 h.setState(WAIT_CONFIG_REPLY);
641 } else {
642 //version is 1.3, must get switchport information
643 h.sendHandshakeOFPortDescRequest();
644 h.setState(WAIT_PORT_DESC_REPLY);
645 }
646 }
647 @Override
648 void processOFStatisticsReply(OFChannelHandler h,
649 OFStatsReply m)
650 throws IOException, SwitchStateException {
651 illegalMessageReceived(h, m);
652 }
653 @Override
654 void processOFError(OFChannelHandler h, OFErrorMsg m) {
655 logErrorDisconnect(h, m);
656 }
657
658 @Override
659 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
660 throws IOException {
661 unhandledMessageReceived(h, m);
662 }
663 },
664
665 /**
666 * We are waiting for a description of the 1.3 switch ports.
667 * Once received, we send a SetConfig request
668 * Next State is WAIT_CONFIG_REPLY
669 */
670 WAIT_PORT_DESC_REPLY(false) {
671
672 @Override
673 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
674 throws SwitchStateException {
675 // Read port description
676 if (m.getStatsType() != OFStatsType.PORT_DESC) {
677 log.warn("Expecting port description stats but received stats "
678 + "type {} from {}. Ignoring ...", m.getStatsType(),
679 h.channel.getRemoteAddress());
680 return;
681 }
682 if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
683 log.warn("Stats reply indicates more stats from sw {} for "
684 + "port description - not currently handled",
685 h.getSwitchInfoString());
686 }
687 h.portDescReply = (OFPortDescStatsReply) m; // temp store
688 log.info("Received port desc reply for switch at {}",
689 h.getSwitchInfoString());
690 try {
691 h.sendHandshakeSetConfig();
692 } catch (IOException e) {
693 log.error("Unable to send setConfig after PortDescReply. "
694 + "Error: {}", e.getMessage());
695 }
696 h.setState(WAIT_CONFIG_REPLY);
697 }
698
699 @Override
700 void processOFError(OFChannelHandler h, OFErrorMsg m)
701 throws IOException, SwitchStateException {
702 logErrorDisconnect(h, m);
703
704 }
705
706 @Override
707 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
708 throws IOException, SwitchStateException {
709 unhandledMessageReceived(h, m);
710
711 }
712 },
713
714 /**
715 * We are waiting for a config reply message. Once we receive it
716 * we send a DescriptionStatsRequest to the switch.
717 * Next state: WAIT_DESCRIPTION_STAT_REPLY
718 */
719 WAIT_CONFIG_REPLY(false) {
720 @Override
721 @LogMessageDocs({
722 @LogMessageDoc(level = "WARN",
723 message = "Config Reply from {switch} has "
724 + "miss length set to {length}",
725 explanation = "The controller requires that the switch "
726 + "use a miss length of 0xffff for correct "
727 + "function",
728 recommendation = "Use a different switch to ensure "
729 + "correct function")
730 })
731 void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
732 throws IOException {
733 if (m.getMissSendLen() == 0xffff) {
734 log.trace("Config Reply from switch {} confirms "
735 + "miss length set to 0xffff",
736 h.getSwitchInfoString());
737 } else {
738 // FIXME: we can't really deal with switches that don't send
739 // full packets. Shouldn't we drop the connection here?
740 log.warn("Config Reply from switch {} has"
741 + "miss length set to {}",
742 h.getSwitchInfoString(),
743 m.getMissSendLen());
744 }
745 h.sendHandshakeDescriptionStatsRequest();
746 h.setState(WAIT_DESCRIPTION_STAT_REPLY);
747 }
748
749 @Override
750 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
751 // do nothing;
752 }
753
754 @Override
755 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
756 throws IOException, SwitchStateException {
757 illegalMessageReceived(h, m);
758 }
759 @Override
760 void processOFStatisticsReply(OFChannelHandler h,
761 OFStatsReply m)
762 throws IOException, SwitchStateException {
763 log.error("Received multipart(stats) message sub-type {}",
764 m.getStatsType());
765 illegalMessageReceived(h, m);
766 }
767
768 @Override
769 void processOFError(OFChannelHandler h, OFErrorMsg m) {
770 logErrorDisconnect(h, m);
771 }
772
773 @Override
774 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
775 throws IOException {
776 h.pendingPortStatusMsg.add(m);
777 }
778 },
779
780
781 /**
782 * We are waiting for a OFDescriptionStat message from the switch.
783 * Once we receive any stat message we try to parse it. If it's not
784 * a description stats message we disconnect. If its the expected
785 * description stats message, we:
786 * - use the switch driver to bind the switch and get an IOFSwitch instance
787 * - setup the IOFSwitch instance
788 * - add switch controller and send the initial role
789 * request to the switch.
790 * Next state: WAIT_INITIAL_ROLE
791 * In the typical case, where switches support role request messages
792 * the next state is where we expect the role reply message.
793 * In the special case that where the switch does not support any kind
794 * of role request messages, we don't send a role message, but we do
795 * request mastership from the registry service. This controller
796 * should become master once we hear back from the registry service.
797 * All following states will have a h.sw instance!
798 */
799 WAIT_DESCRIPTION_STAT_REPLY(false) {
800 @LogMessageDoc(message = "Switch {switch info} bound to class "
801 + "{switch driver}, description {switch description}",
802 explanation = "The specified switch has been bound to "
803 + "a switch driver based on the switch description"
804 + "received from the switch")
805 @Override
806 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
807 throws SwitchStateException {
808 // Read description, if it has been updated
809 if (m.getStatsType() != OFStatsType.DESC) {
810 log.warn("Expecting Description stats but received stats "
811 + "type {} from {}. Ignoring ...", m.getStatsType(),
812 h.channel.getRemoteAddress());
813 return;
814 }
815 log.info("Received switch description reply from switch at {}",
816 h.channel.getRemoteAddress());
817 OFDescStatsReply drep = (OFDescStatsReply) m;
818 // Here is where we differentiate between different kinds of switches
819 h.sw = h.controller.getOFSwitchInstance(drep, h.ofVersion);
820 // set switch information
821 h.sw.setOFVersion(h.ofVersion);
822 h.sw.setFeaturesReply(h.featuresReply);
823 h.sw.setPortDescReply(h.portDescReply);
824 h.sw.setConnected(true);
825 h.sw.setChannel(h.channel);
826
827 try {
828 h.sw.setDebugCounterService(h.controller.getDebugCounter());
829 } catch (CounterException e) {
830 h.counters.switchCounterRegistrationFailed
831 .updateCounterNoFlush();
832 log.warn("Could not register counters for switch {} ",
833 h.getSwitchInfoString(), e);
834 }
835
836 log.info("Switch {} bound to class {}, description {}",
837 new Object[] {h.sw, h.sw.getClass(), drep });
838 //Put switch in EQUAL mode until we hear back from the global registry
839 log.debug("Setting new switch {} to EQUAL and sending Role request",
840 h.sw.getStringId());
841 h.setSwitchRole(Role.EQUAL);
842 try {
843 boolean supportsRRMsg = h.roleChanger.sendRoleRequest(Role.EQUAL,
844 RoleRecvStatus.MATCHED_CURRENT_ROLE);
845 if (!supportsRRMsg) {
846 log.warn("Switch {} does not support role request messages "
847 + "of any kind. No role messages were sent. "
848 + "This controller instance SHOULD become MASTER "
849 + "from the registry process. ",
850 h.getSwitchInfoString());
851 }
852 h.setState(WAIT_INITIAL_ROLE);
853 // request control of switch from global registry -
854 // necessary even if this is the only controller the
855 // switch is connected to.
856 h.controller.submitRegistryRequest(h.sw.getId());
857 } catch (IOException e) {
858 log.error("Exception when sending role request: {} ",
859 e.getMessage());
860 // FIXME shouldn't we disconnect?
861 }
862 }
863
864 @Override
865 void processOFError(OFChannelHandler h, OFErrorMsg m) {
866 logErrorDisconnect(h, m);
867 }
868
869 @Override
870 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
871 throws IOException, SwitchStateException {
872 illegalMessageReceived(h, m);
873 }
874
875 @Override
876 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
877 throws IOException {
878 h.pendingPortStatusMsg.add(m);
879 }
880 },
881
882 /**
883 * We are waiting for a role reply message in response to a role request
884 * sent after hearing back from the registry service -- OR -- we are
885 * just waiting to hear back from the registry service in the case that
886 * the switch does not support role messages. If completed successfully,
887 * the controller's role for this switch will be set here.
888 * Before we move to the state corresponding to the role, we allow the
889 * switch specific driver to complete its configuration. This configuration
890 * typically depends on the role the controller is playing for this switch.
891 * And so we set the switch role (for 'this' controller) before we start
892 * the driver-sub-handshake.
893 * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
894 */
895 WAIT_INITIAL_ROLE(false) {
896 @Override
897 void processOFError(OFChannelHandler h, OFErrorMsg m)
898 throws SwitchStateException {
899 // role changer will ignore the error if it isn't for it
900 RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
901 if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
902 logError(h, m);
903 }
904 }
905
906 @Override
907 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
908 throws IOException, SwitchStateException {
909 Role role = extractNiciraRoleReply(h, m);
910 // If role == null it means the vendor (experimenter) message
911 // wasn't really a Nicira role reply. We ignore this case.
912 if (role != null) {
913 RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
914 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
915 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
916 setRoleAndStartDriverHandshake(h, rri.getRole());
917 } // else do nothing - wait for the correct expected reply
918 } else {
919 unhandledMessageReceived(h, m);
920 }
921 }
922
923 @Override
924 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
925 throws SwitchStateException, IOException {
926 RoleReplyInfo rri = extractOFRoleReply(h, m);
927 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
928 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
929 setRoleAndStartDriverHandshake(h, rri.getRole());
930 } // else do nothing - wait for the correct expected reply
931 }
932
933 @Override
934 void handleUnsentRoleMessage(OFChannelHandler h, Role role,
935 RoleRecvStatus expectation) throws IOException {
936 // typically this is triggered for a switch where role messages
937 // are not supported - we confirm that the role being set is
938 // master and move to the next state
939 if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
940 if (role == Role.MASTER) {
941 setRoleAndStartDriverHandshake(h, role);
942 } else {
943 log.error("Expected MASTER role from registry for switch "
944 + "which has no support for role-messages."
945 + "Received {}. It is possible that this switch "
946 + "is connected to other controllers, in which "
947 + "case it should support role messages - not "
948 + "moving forward.", role);
949 }
950 } // else do nothing - wait to hear back from registry
951
952 }
953
954 private void setRoleAndStartDriverHandshake(OFChannelHandler h,
955 Role role) throws IOException {
956 h.setSwitchRole(role);
957 h.sw.startDriverHandshake();
958 if (h.sw.isDriverHandshakeComplete()) {
959 Role mySwitchRole = h.sw.getRole();
960 if (mySwitchRole == Role.MASTER) {
961 log.info("Switch-driver sub-handshake complete. "
962 + "Activating switch {} with Role: MASTER",
963 h.getSwitchInfoString());
964 handlePendingPortStatusMessages(h); //before activation
965 boolean success = h.controller.addActivatedMasterSwitch(
966 h.sw.getId(), h.sw);
967 if (!success) {
968 disconnectDuplicate(h);
969 return;
970 }
971 h.setState(MASTER);
972 } else {
973 log.info("Switch-driver sub-handshake complete. "
974 + "Activating switch {} with Role: EQUAL",
975 h.getSwitchInfoString());
976 handlePendingPortStatusMessages(h); //before activation
977 boolean success = h.controller.addActivatedEqualSwitch(
978 h.sw.getId(), h.sw);
979 if (!success) {
980 disconnectDuplicate(h);
981 return;
982 }
983 h.setState(EQUAL);
984 }
985 } else {
986 h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
987 }
988 }
989
990 @Override
991 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
992 throws IOException, SwitchStateException {
993 illegalMessageReceived(h, m);
994 }
995
996 @Override
997 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
998 throws SwitchStateException {
999 illegalMessageReceived(h, m);
1000 }
1001
1002 @Override
1003 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1004 throws IOException, SwitchStateException {
1005 h.pendingPortStatusMsg.add(m);
1006
1007 }
1008 },
1009
1010 /**
1011 * We are waiting for the respective switch driver to complete its
1012 * configuration. Notice that we do not consider this to be part of the main
1013 * switch-controller handshake. But we do consider it as a step that comes
1014 * before we declare the switch as available to the controller.
1015 * Next State: depends on the role of this controller for this switch - either
1016 * MASTER or EQUAL.
1017 */
1018 WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
1019
1020 @Override
1021 void processOFError(OFChannelHandler h, OFErrorMsg m)
1022 throws IOException {
1023 // will never be called. We override processOFMessage
1024 }
1025
1026 @Override
1027 void processOFMessage(OFChannelHandler h, OFMessage m)
1028 throws IOException {
1029 if (m.getType() == OFType.ECHO_REQUEST) {
1030 processOFEchoRequest(h, (OFEchoRequest) m);
1031 } else {
1032 // FIXME: other message to handle here?
1033 h.sw.processDriverHandshakeMessage(m);
1034 if (h.sw.isDriverHandshakeComplete()) {
1035 // consult the h.sw role and goto that state
1036 Role mySwitchRole = h.sw.getRole();
1037 if (mySwitchRole == Role.MASTER) {
1038 log.info("Switch-driver sub-handshake complete. "
1039 + "Activating switch {} with Role: MASTER",
1040 h.getSwitchInfoString());
1041 handlePendingPortStatusMessages(h); //before activation
1042 boolean success = h.controller.addActivatedMasterSwitch(
1043 h.sw.getId(), h.sw);
1044 if (!success) {
1045 disconnectDuplicate(h);
1046 return;
1047 }
1048 h.setState(MASTER);
1049 } else {
1050 log.info("Switch-driver sub-handshake complete. "
1051 + "Activating switch {} with Role: EQUAL",
1052 h.getSwitchInfoString());
1053 handlePendingPortStatusMessages(h); //before activation
1054 boolean success = h.controller.addActivatedEqualSwitch(
1055 h.sw.getId(), h.sw);
1056 if (!success) {
1057 disconnectDuplicate(h);
1058 return;
1059 }
1060 h.setState(EQUAL);
1061 }
1062 }
1063 }
1064 }
1065
1066 @Override
1067 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1068 throws IOException, SwitchStateException {
1069 h.pendingPortStatusMsg.add(m);
1070 }
1071 },
1072
1073
1074 /**
1075 * This controller is in MASTER role for this switch. We enter this state
1076 * after requesting and winning control from the global registry.
1077 * The main handshake as well as the switch-driver sub-handshake
1078 * is complete at this point.
1079 * // XXX S reconsider below
1080 * In the (near) future we may deterministically assign controllers to
1081 * switches at startup.
1082 * We only leave this state if the switch disconnects or
1083 * if we send a role request for SLAVE /and/ receive the role reply for
1084 * SLAVE.
1085 */
1086 MASTER(true) {
1087 @LogMessageDoc(level = "WARN",
1088 message = "Received permission error from switch {} while"
1089 + "being master. Reasserting master role.",
1090 explanation = "The switch has denied an operation likely "
1091 + "indicating inconsistent controller roles",
1092 recommendation = "This situation can occurs transiently during role"
1093 + " changes. If, however, the condition persists or happens"
1094 + " frequently this indicates a role inconsistency. "
1095 + LogMessageDoc.CHECK_CONTROLLER)
1096 @Override
1097 void processOFError(OFChannelHandler h, OFErrorMsg m)
1098 throws IOException, SwitchStateException {
1099 // first check if the error msg is in response to a role-request message
1100 RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
1101 if (rrstatus != RoleRecvStatus.OTHER_EXPECTATION) {
1102 // rolechanger has handled the error message - we are done
1103 return;
1104 }
1105
1106 // if we get here, then the error message is for something else
1107 if (m.getErrType() == OFErrorType.BAD_REQUEST &&
1108 ((OFBadRequestErrorMsg) m).getCode() ==
1109 OFBadRequestCode.EPERM) {
1110 // We are the master controller and the switch returned
1111 // a permission error. This is a likely indicator that
1112 // the switch thinks we are slave. Reassert our
1113 // role
1114 // FIXME: this could be really bad during role transitions
1115 // if two controllers are master (even if its only for
1116 // a brief period). We might need to see if these errors
1117 // persist before we reassert
1118 h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
1119 log.warn("Received permission error from switch {} while" +
1120 "being master. Reasserting master role.",
1121 h.getSwitchInfoString());
1122 //h.controller.reassertRole(h, Role.MASTER);
1123 // XXX S reassert in role changer or reconsider if all this
1124 // stuff is really needed
1125 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
1126 ((OFFlowModFailedErrorMsg) m).getCode() ==
1127 OFFlowModFailedCode.ALL_TABLES_FULL) {
1128 h.sw.setTableFull(true);
1129 } else {
1130 logError(h, m);
1131 }
1132 h.dispatchMessage(m);
1133 }
1134
1135 @Override
1136 void processOFStatisticsReply(OFChannelHandler h,
1137 OFStatsReply m) {
1138 h.sw.deliverStatisticsReply(m);
1139 }
1140
1141 @Override
1142 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1143 throws IOException, SwitchStateException {
1144 Role role = extractNiciraRoleReply(h, m);
1145 if (role == null) {
1146 // The message wasn't really a Nicira role reply. We just
1147 // dispatch it to the OFMessage listeners in this case.
1148 h.dispatchMessage(m);
1149 return;
1150 }
1151
1152 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
1153 new RoleReplyInfo(role, null, m.getXid()));
1154 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1155 checkAndSetRoleTransition(h, role);
1156 }
1157 }
1158
1159 @Override
1160 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1161 throws SwitchStateException, IOException {
1162 RoleReplyInfo rri = extractOFRoleReply(h, m);
1163 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
1164 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1165 checkAndSetRoleTransition(h, rri.getRole());
1166 }
1167 }
1168
1169 @Override
1170 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1171 throws IOException, SwitchStateException {
1172 handlePortStatusMessage(h, m, true);
1173 h.dispatchMessage(m);
1174 }
1175
1176 @Override
1177 void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
1178 throws IOException {
1179 h.dispatchMessage(m);
1180 }
1181
1182 @Override
1183 void processOFFlowRemoved(OFChannelHandler h,
1184 OFFlowRemoved m) throws IOException {
1185 h.dispatchMessage(m);
1186 }
1187
1188 @Override
1189 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
1190 throws IOException {
1191 h.dispatchMessage(m);
1192 }
1193
1194 },
1195
1196 /**
1197 * This controller is in EQUAL role for this switch. We enter this state
1198 * after some /other/ controller instance wins mastership-role over this
1199 * switch. The EQUAL role can be considered the same as the SLAVE role
1200 * if this controller does NOT send commands or packets to the switch.
1201 * This should always be true for OF1.0 switches. XXX S need to enforce.
1202 *
1203 * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
1204 * gives us the flexibility that if an app wants to send commands/packets
1205 * to switches, it can, even thought it is running on a controller instance
1206 * that is not in a MASTER role for this switch. Of course, it is the job
1207 * of the app to ensure that commands/packets sent by this (EQUAL) controller
1208 * instance does not clash/conflict with commands/packets sent by the MASTER
1209 * controller for this switch. Neither the controller instances, nor the
1210 * switch provides any kind of resolution mechanism should conflicts occur.
1211 */
1212 EQUAL(true) {
1213 @Override
1214 void processOFError(OFChannelHandler h, OFErrorMsg m)
1215 throws IOException, SwitchStateException {
1216 // role changer will ignore the error if it isn't for it
1217 RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
1218 if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
1219 logError(h, m);
1220 h.dispatchMessage(m);
1221 }
1222 }
1223
1224 @Override
1225 void processOFStatisticsReply(OFChannelHandler h,
1226 OFStatsReply m) {
1227 h.sw.deliverStatisticsReply(m);
1228 }
1229
1230 @Override
1231 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1232 throws IOException, SwitchStateException {
1233 Role role = extractNiciraRoleReply(h, m);
1234 // If role == null it means the message wasn't really a
1235 // Nicira role reply. We ignore it in this state.
1236 if (role != null) {
1237 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
1238 new RoleReplyInfo(role, null, m.getXid()));
1239 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1240 checkAndSetRoleTransition(h, role);
1241 }
1242 } else {
1243 unhandledMessageReceived(h, m);
1244 }
1245 }
1246
1247 @Override
1248 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1249 throws SwitchStateException, IOException {
1250 RoleReplyInfo rri = extractOFRoleReply(h, m);
1251 RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
1252 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1253 checkAndSetRoleTransition(h, rri.getRole());
1254 }
1255 }
1256
1257 // XXX S needs more handlers for 1.3 switches in equal role
1258
1259 @Override
1260 void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1261 throws IOException, SwitchStateException {
1262 handlePortStatusMessage(h, m, true);
1263 }
1264
1265 @Override
1266 @LogMessageDoc(level = "WARN",
1267 message = "Received PacketIn from switch {} while "
1268 + "being slave. Reasserting slave role.",
1269 explanation = "The switch has receive a PacketIn despite being "
1270 + "in slave role indicating inconsistent controller roles",
1271 recommendation = "This situation can occurs transiently during role"
1272 + " changes. If, however, the condition persists or happens"
1273 + " frequently this indicates a role inconsistency. "
1274 + LogMessageDoc.CHECK_CONTROLLER)
1275 void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
1276 // we don't expect packetIn while slave, reassert we are slave
1277 h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
1278 log.warn("Received PacketIn from switch {} while" +
1279 "being slave. Reasserting slave role.", h.sw);
1280 //h.controller.reassertRole(h, Role.SLAVE);
1281 // XXX reassert in role changer
1282 }
1283 };
1284
1285 private final boolean handshakeComplete;
1286 ChannelState(boolean handshakeComplete) {
1287 this.handshakeComplete = handshakeComplete;
1288 }
1289
1290 /**
1291 * Is this a state in which the handshake has completed?
1292 * @return true if the handshake is complete
1293 */
1294 public boolean isHandshakeComplete() {
1295 return handshakeComplete;
1296 }
1297
1298 /**
1299 * Get a string specifying the switch connection, state, and
1300 * message received. To be used as message for SwitchStateException
1301 * or log messages
1302 * @param h The channel handler (to get switch information_
1303 * @param m The OFMessage that has just been received
1304 * @param details A string giving more details about the exact nature
1305 * of the problem.
1306 * @return
1307 */
1308 // needs to be protected because enum members are actually subclasses
1309 protected String getSwitchStateMessage(OFChannelHandler h,
1310 OFMessage m,
1311 String details) {
1312 return String.format("Switch: [%s], State: [%s], received: [%s]"
1313 + ", details: %s",
1314 h.getSwitchInfoString(),
1315 this.toString(),
1316 m.getType().toString(),
1317 details);
1318 }
1319
1320 /**
1321 * We have an OFMessage we didn't expect given the current state and
1322 * we want to treat this as an error.
1323 * We currently throw an exception that will terminate the connection
1324 * However, we could be more forgiving
1325 * @param h the channel handler that received the message
1326 * @param m the message
1327 * @throws SwitchStateException
1328 * @throws SwitchStateExeption we always through the execption
1329 */
1330 // needs to be protected because enum members are acutally subclasses
1331 protected void illegalMessageReceived(OFChannelHandler h, OFMessage m)
1332 throws SwitchStateException {
1333 String msg = getSwitchStateMessage(h, m,
1334 "Switch should never send this message in the current state");
1335 throw new SwitchStateException(msg);
1336
1337 }
1338
1339 /**
1340 * We have an OFMessage we didn't expect given the current state and
1341 * we want to ignore the message.
1342 * @param h the channel handler the received the message
1343 * @param m the message
1344 */
1345 protected void unhandledMessageReceived(OFChannelHandler h,
1346 OFMessage m) {
1347 h.counters.unhandledMessage.updateCounterNoFlush();
1348 if (log.isDebugEnabled()) {
1349 String msg = getSwitchStateMessage(h, m,
1350 "Ignoring unexpected message");
1351 log.debug(msg);
1352 }
1353 }
1354
1355 /**
1356 * Log an OpenFlow error message from a switch.
1357 * @param sw The switch that sent the error
1358 * @param error The error message
1359 */
1360 @LogMessageDoc(level = "ERROR",
1361 message = "Error {error type} {error code} from {switch} "
1362 + "in state {state}",
1363 explanation = "The switch responded with an unexpected error"
1364 + "to an OpenFlow message from the controller",
1365 recommendation = "This could indicate improper network operation. "
1366 + "If the problem persists restarting the switch and "
1367 + "controller may help."
1368 )
1369 protected void logError(OFChannelHandler h, OFErrorMsg error) {
1370 log.error("{} from switch {} in state {}",
1371 new Object[] {
1372 error,
1373 h.getSwitchInfoString(),
1374 this.toString()});
1375 }
1376
1377 /**
1378 * Log an OpenFlow error message from a switch and disconnect the
1379 * channel.
1380 *
1381 * @param h the IO channel for this switch.
1382 * @param error The error message
1383 */
1384 protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
1385 logError(h, error);
1386 h.channel.disconnect();
1387 }
1388
1389 /**
1390 * log an error message for a duplicate dpid and disconnect this channel.
1391 * @param h the IO channel for this switch.
1392 */
1393 protected void disconnectDuplicate(OFChannelHandler h) {
1394 log.error("Duplicated dpid or incompleted cleanup - "
1395 + "disconnecting channel {}", h.getSwitchInfoString());
1396 h.duplicateDpidFound = Boolean.TRUE;
1397 h.channel.disconnect();
1398 }
1399
1400 /**
1401 * Extract the role from an OFVendor message.
1402 *
1403 * Extract the role from an OFVendor message if the message is a
1404 * Nicira role reply. Otherwise return null.
1405 *
1406 * @param h The channel handler receiving the message
1407 * @param vendorMessage The vendor message to parse.
1408 * @return The role in the message if the message is a Nicira role
1409 * reply, null otherwise.
1410 * @throws SwitchStateException If the message is a Nicira role reply
1411 * but the numeric role value is unknown.
1412 */
1413 protected Role extractNiciraRoleReply(OFChannelHandler h,
1414 OFExperimenter experimenterMsg) throws SwitchStateException {
1415 int vendor = (int) experimenterMsg.getExperimenter();
1416 if (vendor != 0x2320) {
1417 return null;
1418 }
1419 OFNiciraControllerRoleReply nrr =
1420 (OFNiciraControllerRoleReply) experimenterMsg;
1421
1422 Role role = null;
1423 OFNiciraControllerRole ncr = nrr.getRole();
1424 switch(ncr) {
1425 case ROLE_MASTER:
1426 role = Role.MASTER;
1427 break;
1428 case ROLE_OTHER:
1429 role = Role.EQUAL;
1430 break;
1431 case ROLE_SLAVE:
1432 role = Role.SLAVE;
1433 break;
1434 default: //handled below
1435 }
1436
1437 if (role == null) {
1438 String msg = String.format("Switch: [%s], State: [%s], "
1439 + "received NX_ROLE_REPLY with invalid role "
1440 + "value %s",
1441 h.getSwitchInfoString(),
1442 this.toString(),
1443 nrr.getRole());
1444 throw new SwitchStateException(msg);
1445 }
1446 return role;
1447 }
1448
1449 /**
1450 * Helper class returns role reply information in the format understood
1451 * by the controller.
1452 */
1453 protected static class RoleReplyInfo {
1454 private Role role;
1455 private U64 genId;
1456 private long xid;
1457
1458 RoleReplyInfo(Role role, U64 genId, long xid) {
1459 this.role = role;
1460 this.genId = genId;
1461 this.xid = xid;
1462 }
1463 public Role getRole() { return role; }
1464 public U64 getGenId() { return genId; }
1465 public long getXid() { return xid; }
1466 @Override
1467 public String toString() {
1468 return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
1469 }
1470 }
1471
1472 /**
1473 * Extract the role information from an OF1.3 Role Reply Message.
1474 * @param h
1475 * @param rrmsg
1476 * @return RoleReplyInfo object
1477 * @throws SwitchStateException
1478 */
1479 protected RoleReplyInfo extractOFRoleReply(OFChannelHandler h,
1480 OFRoleReply rrmsg) throws SwitchStateException {
1481 OFControllerRole cr = rrmsg.getRole();
1482 Role role = null;
1483 switch(cr) {
1484 case ROLE_EQUAL:
1485 role = Role.EQUAL;
1486 break;
1487 case ROLE_MASTER:
1488 role = Role.MASTER;
1489 break;
1490 case ROLE_SLAVE:
1491 role = Role.SLAVE;
1492 break;
1493 case ROLE_NOCHANGE: // switch should send current role
1494 default:
1495 String msg = String.format("Unknown controller role %s "
1496 + "received from switch %s", cr, h.sw);
1497 throw new SwitchStateException(msg);
1498 }
1499
1500 return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
1501 }
1502
1503 /**
1504 * Handles all pending port status messages before a switch is declared
1505 * activated in MASTER or EQUAL role. Note that since this handling
1506 * precedes the activation (and therefore notification to IOFSwitchListerners)
1507 * the changes to ports will already be visible once the switch is
1508 * activated. As a result, no notifications are sent out for these
1509 * pending portStatus messages.
1510 * @param h
1511 * @throws SwitchStateException
1512 */
1513 protected void handlePendingPortStatusMessages(OFChannelHandler h) {
1514 try {
1515 handlePendingPortStatusMessages(h, 0);
1516 } catch (SwitchStateException e) {
1517 log.error(e.getMessage());
1518 }
1519 }
1520
1521 private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
1522 throws SwitchStateException {
1523 if (h.sw == null) {
1524 String msg = "State machine error: switch is null. Should never " +
1525 "happen";
1526 throw new SwitchStateException(msg);
1527 }
1528 ArrayList<OFPortStatus> temp = new ArrayList<OFPortStatus>();
1529 for (OFPortStatus ps: h.pendingPortStatusMsg) {
1530 temp.add(ps);
1531 handlePortStatusMessage(h, ps, false);
1532 }
1533 temp.clear();
1534 // expensive but ok - we don't expect too many port-status messages
1535 // note that we cannot use clear(), because of the reasons below
1536 h.pendingPortStatusMsg.removeAll(temp);
1537 // the iterator above takes a snapshot of the list - so while we were
1538 // dealing with the pending port-status messages, we could have received
1539 // newer ones. Handle them recursively, but break the recursion after
1540 // five steps to avoid an attack.
1541 if (!h.pendingPortStatusMsg.isEmpty() && ++index < 5) {
1542 handlePendingPortStatusMessages(h, index);
1543 }
1544 }
1545
1546 /**
1547 * Handle a port status message.
1548 *
1549 * Handle a port status message by updating the port maps in the
1550 * IOFSwitch instance and notifying Controller about the change so
1551 * it can dispatch a switch update.
1552 *
1553 * @param h The OFChannelHhandler that received the message
1554 * @param m The PortStatus message we received
1555 * @param doNotify if true switch port changed events will be
1556 * dispatched
1557 * @throws SwitchStateException
1558 *
1559 */
1560 protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
1561 boolean doNotify) throws SwitchStateException {
1562 if (h.sw == null) {
1563 String msg = getSwitchStateMessage(h, m,
1564 "State machine error: switch is null. Should never " +
1565 "happen");
1566 throw new SwitchStateException(msg);
1567 }
1568
1569 Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m);
1570 if (doNotify) {
1571 for (PortChangeEvent ev: changes) {
1572 h.controller.notifyPortChanged(h.sw.getId(), ev.port, ev.type);
1573 }
1574 }
1575 }
1576
1577 /**
1578 * Checks if the role received (from the role-reply msg) is different
1579 * from the existing role in the IOFSwitch object for this controller.
1580 * If so, it transitions the controller to the new role. Note that
1581 * the caller should have already verified that the role-reply msg
1582 * received was in response to a role-request msg sent out by this
1583 * controller after hearing from the registry service.
1584 *
1585 * @param h the ChannelHandler that received the message
1586 * @param role the role in the recieved role reply message
1587 */
1588 protected void checkAndSetRoleTransition(OFChannelHandler h, Role role) {
1589 // we received a role-reply in response to a role message
1590 // sent after hearing from the registry service. It is
1591 // possible that the role of this controller instance for
1592 // this switch has changed:
1593 // for 1.0 switch: from MASTER to SLAVE
1594 // for 1.3 switch: from MASTER to EQUAL
1595 if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
1596 (h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
1597 // the mastership has changed
1598 h.sw.setRole(role);
1599 h.setState(EQUAL);
1600 h.controller.transitionToEqualSwitch(h.sw.getId());
1601 return;
1602 }
1603
1604 // or for both 1.0 and 1.3 switches from EQUAL to MASTER.
1605 // note that for 1.0, even though we mean SLAVE,
1606 // internally we call the role EQUAL.
1607 if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
1608 // the mastership has changed
1609 h.sw.setRole(role);
1610 h.setState(MASTER);
1611 h.controller.transitionToMasterSwitch(h.sw.getId());
1612 return;
1613 }
1614 }
1615
1616 /**
1617 * Process an OF message received on the channel and
1618 * update state accordingly.
1619 *
1620 * The main "event" of the state machine. Process the received message,
1621 * send follow up message if required and update state if required.
1622 *
1623 * Switches on the message type and calls more specific event handlers
1624 * for each individual OF message type. If we receive a message that
1625 * is supposed to be sent from a controller to a switch we throw
1626 * a SwitchStateExeption.
1627 *
1628 * The more specific handlers can also throw SwitchStateExceptions
1629 *
1630 * @param h The OFChannelHandler that received the message
1631 * @param m The message we received.
1632 * @throws SwitchStateException
1633 * @throws IOException
1634 */
1635 void processOFMessage(OFChannelHandler h, OFMessage m)
1636 throws IOException, SwitchStateException {
1637 h.roleChanger.checkTimeout();
1638 switch(m.getType()) {
1639 case HELLO:
1640 processOFHello(h, (OFHello) m);
1641 break;
1642 case BARRIER_REPLY:
1643 processOFBarrierReply(h, (OFBarrierReply) m);
1644 break;
1645 case ECHO_REPLY:
1646 processOFEchoReply(h, (OFEchoReply) m);
1647 break;
1648 case ECHO_REQUEST:
1649 processOFEchoRequest(h, (OFEchoRequest) m);
1650 break;
1651 case ERROR:
1652 processOFError(h, (OFErrorMsg) m);
1653 break;
1654 case FEATURES_REPLY:
1655 processOFFeaturesReply(h, (OFFeaturesReply) m);
1656 break;
1657 case FLOW_REMOVED:
1658 processOFFlowRemoved(h, (OFFlowRemoved) m);
1659 break;
1660 case GET_CONFIG_REPLY:
1661 processOFGetConfigReply(h, (OFGetConfigReply) m);
1662 break;
1663 case PACKET_IN:
1664 processOFPacketIn(h, (OFPacketIn) m);
1665 break;
1666 case PORT_STATUS:
1667 processOFPortStatus(h, (OFPortStatus) m);
1668 break;
1669 case QUEUE_GET_CONFIG_REPLY:
1670 processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
1671 break;
1672 case STATS_REPLY: // multipart_reply in 1.3
1673 processOFStatisticsReply(h, (OFStatsReply) m);
1674 break;
1675 case EXPERIMENTER:
1676 processOFExperimenter(h, (OFExperimenter) m);
1677 break;
1678 case ROLE_REPLY:
1679 processOFRoleReply(h, (OFRoleReply) m);
1680 break;
1681 case GET_ASYNC_REPLY:
1682 processOFGetAsyncReply(h, (OFAsyncGetReply) m);
1683 break;
1684
1685 // The following messages are sent to switches. The controller
1686 // should never receive them
1687 case SET_CONFIG:
1688 case GET_CONFIG_REQUEST:
1689 case PACKET_OUT:
1690 case PORT_MOD:
1691 case QUEUE_GET_CONFIG_REQUEST:
1692 case BARRIER_REQUEST:
1693 case STATS_REQUEST: // multipart request in 1.3
1694 case FEATURES_REQUEST:
1695 case FLOW_MOD:
1696 case GROUP_MOD:
1697 case TABLE_MOD:
1698 case GET_ASYNC_REQUEST:
1699 case SET_ASYNC:
1700 case METER_MOD:
1701 default:
1702 illegalMessageReceived(h, m);
1703 break;
1704 }
1705 }
1706
1707 /*-----------------------------------------------------------------
1708 * Default implementation for message handlers in any state.
1709 *
1710 * Individual states must override these if they want a behavior
1711 * that differs from the default.
1712 *
1713 * In general, these handlers simply ignore the message and do
1714 * nothing.
1715 *
1716 * There are some exceptions though, since some messages really
1717 * are handled the same way in every state (e.g., ECHO_REQUST) or
1718 * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
1719 -----------------------------------------------------------------*/
1720
1721 void processOFHello(OFChannelHandler h, OFHello m)
1722 throws IOException, SwitchStateException {
1723 // we only expect hello in the WAIT_HELLO state
1724 illegalMessageReceived(h, m);
1725 }
1726
1727 void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
1728 throws IOException {
1729 // Silently ignore.
1730 }
1731
1732 void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
1733 throws IOException {
1734 if (h.ofVersion == null) {
1735 log.error("No OF version set for {}. Not sending Echo REPLY",
1736 h.channel.getRemoteAddress());
1737 return;
1738 }
1739 OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
1740 h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
1741 OFEchoReply reply = factory
1742 .buildEchoReply()
1743 .setXid(m.getXid())
1744 .setData(m.getData())
1745 .build();
1746 h.channel.write(Collections.singletonList(reply));
1747 }
1748
1749 void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
1750 throws IOException {
1751 // Do nothing with EchoReplies !!
1752 }
1753
1754 // no default implementation for OFError
1755 // every state must override it
1756 abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
1757 throws IOException, SwitchStateException;
1758
1759
1760 void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
1761 throws IOException, SwitchStateException {
1762 unhandledMessageReceived(h, m);
1763 }
1764
1765 void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
1766 throws IOException {
1767 unhandledMessageReceived(h, m);
1768 }
1769
1770 void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
1771 throws IOException, SwitchStateException {
1772 // we only expect config replies in the WAIT_CONFIG_REPLY state
1773 illegalMessageReceived(h, m);
1774 }
1775
1776 void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
1777 throws IOException {
1778 unhandledMessageReceived(h, m);
1779 }
1780
1781 // no default implementation. Every state needs to handle it.
1782 abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1783 throws IOException, SwitchStateException;
1784
1785 void processOFQueueGetConfigReply(OFChannelHandler h,
1786 OFQueueGetConfigReply m)
1787 throws IOException {
1788 unhandledMessageReceived(h, m);
1789 }
1790
1791 void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
1792 throws IOException, SwitchStateException {
1793 unhandledMessageReceived(h, m);
1794 }
1795
1796 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1797 throws IOException, SwitchStateException {
1798 // TODO: it might make sense to parse the vendor message here
1799 // into the known vendor messages we support and then call more
1800 // specific event handlers
1801 unhandledMessageReceived(h, m);
1802 }
1803
1804 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1805 throws SwitchStateException, IOException {
1806 unhandledMessageReceived(h, m);
1807 }
1808
1809 void processOFGetAsyncReply(OFChannelHandler h,
1810 OFAsyncGetReply m) {
1811 unhandledMessageReceived(h, m);
1812 }
1813
1814 void handleUnsentRoleMessage(OFChannelHandler h, Role role,
1815 RoleRecvStatus expectation) throws IOException {
1816 // do nothing in most states
1817 }
1818 }
1819
1820
1821
1822 //*************************
1823 // Channel handler methods
1824 //*************************
1825
1826 @Override
1827 @LogMessageDoc(message = "New switch connection from {ip address}",
1828 explanation = "A new switch has connected from the "
1829 + "specified IP address")
1830 public void channelConnected(ChannelHandlerContext ctx,
1831 ChannelStateEvent e) throws Exception {
1832 counters.switchConnected.updateCounterWithFlush();
1833 channel = e.getChannel();
1834 log.info("New switch connection from {}",
1835 channel.getRemoteAddress());
1836 sendHandshakeHelloMessage();
1837 setState(ChannelState.WAIT_HELLO);
1838 }
1839
1840 @Override
1841 @LogMessageDoc(message = "Disconnected switch {switch information}",
1842 explanation = "The specified switch has disconnected.")
1843 public void channelDisconnected(ChannelHandlerContext ctx,
1844 ChannelStateEvent e) throws Exception {
1845 log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
1846 getSwitchInfoString());
1847 if (thisdpid != 0) {
1848 if (!duplicateDpidFound) {
1849 // if the disconnected switch (on this ChannelHandler)
1850 // was not one with a duplicate-dpid, it is safe to remove all
1851 // state for it at the controller. Notice that if the disconnected
1852 // switch was a duplicate-dpid, calling the method below would clear
1853 // all state for the original switch (with the same dpid),
1854 // which we obviously don't want.
1855 controller.removeConnectedSwitch(thisdpid);
1856 } else {
1857 // A duplicate was disconnected on this ChannelHandler,
1858 // this is the same switch reconnecting, but the original state was
1859 // not cleaned up - XXX check liveness of original ChannelHandler
1860 duplicateDpidFound = Boolean.FALSE;
1861 }
1862 } else {
1863 log.warn("no dpid in channelHandler registered for "
1864 + "disconnected switch {}", getSwitchInfoString());
1865 }
1866 }
1867
1868 @Override
1869 @LogMessageDocs({
1870 @LogMessageDoc(level = "ERROR",
1871 message = "Disconnecting switch {switch} due to read timeout",
1872 explanation = "The connected switch has failed to send any "
1873 + "messages or respond to echo requests",
1874 recommendation = LogMessageDoc.CHECK_SWITCH),
1875 @LogMessageDoc(level = "ERROR",
1876 message = "Disconnecting switch {switch}: failed to "
1877 + "complete handshake",
1878 explanation = "The switch did not respond correctly "
1879 + "to handshake messages",
1880 recommendation = LogMessageDoc.CHECK_SWITCH),
1881 @LogMessageDoc(level = "ERROR",
1882 message = "Disconnecting switch {switch} due to IO Error: {}",
1883 explanation = "There was an error communicating with the switch",
1884 recommendation = LogMessageDoc.CHECK_SWITCH),
1885 @LogMessageDoc(level = "ERROR",
1886 message = "Disconnecting switch {switch} due to switch "
1887 + "state error: {error}",
1888 explanation = "The switch sent an unexpected message",
1889 recommendation = LogMessageDoc.CHECK_SWITCH),
1890 @LogMessageDoc(level = "ERROR",
1891 message = "Disconnecting switch {switch} due to "
1892 + "message parse failure",
1893 explanation = "Could not parse a message from the switch",
1894 recommendation = LogMessageDoc.CHECK_SWITCH),
1895 @LogMessageDoc(level = "ERROR",
1896 message = "Terminating controller due to storage exception",
1897 explanation = Controller.ERROR_DATABASE,
1898 recommendation = LogMessageDoc.CHECK_CONTROLLER),
1899 @LogMessageDoc(level = "ERROR",
1900 message = "Could not process message: queue full",
1901 explanation = "OpenFlow messages are arriving faster than "
1902 + "the controller can process them.",
1903 recommendation = LogMessageDoc.CHECK_CONTROLLER),
1904 @LogMessageDoc(level = "ERROR",
1905 message = "Error while processing message "
1906 + "from switch {switch} {cause}",
1907 explanation = "An error occurred processing the switch message",
1908 recommendation = LogMessageDoc.GENERIC_ACTION)
1909 })
1910 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
1911 throws Exception {
1912 if (e.getCause() instanceof ReadTimeoutException) {
1913 // switch timeout
1914 log.error("Disconnecting switch {} due to read timeout",
1915 getSwitchInfoString());
1916 counters.switchDisconnectReadTimeout.updateCounterWithFlush();
1917 ctx.getChannel().close();
1918 } else if (e.getCause() instanceof HandshakeTimeoutException) {
1919 log.error("Disconnecting switch {}: failed to complete handshake",
1920 getSwitchInfoString());
1921 counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
1922 ctx.getChannel().close();
1923 } else if (e.getCause() instanceof ClosedChannelException) {
1924 log.debug("Channel for sw {} already closed", getSwitchInfoString());
1925 } else if (e.getCause() instanceof IOException) {
1926 log.error("Disconnecting switch {} due to IO Error: {}",
1927 getSwitchInfoString(), e.getCause().getMessage());
1928 if (log.isDebugEnabled()) {
1929 // still print stack trace if debug is enabled
1930 log.debug("StackTrace for previous Exception: ", e.getCause());
1931 }
1932 counters.switchDisconnectIOError.updateCounterWithFlush();
1933 ctx.getChannel().close();
1934 } else if (e.getCause() instanceof SwitchStateException) {
1935 log.error("Disconnecting switch {} due to switch state error: {}",
1936 getSwitchInfoString(), e.getCause().getMessage());
1937 if (log.isDebugEnabled()) {
1938 // still print stack trace if debug is enabled
1939 log.debug("StackTrace for previous Exception: ", e.getCause());
1940 }
1941 counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
1942 ctx.getChannel().close();
1943 } else if (e.getCause() instanceof OFParseError) {
1944 log.error("Disconnecting switch "
1945 + getSwitchInfoString() +
1946 " due to message parse failure",
1947 e.getCause());
1948 counters.switchDisconnectParseError.updateCounterWithFlush();
1949 ctx.getChannel().close();
1950 } else if (e.getCause() instanceof RejectedExecutionException) {
1951 log.warn("Could not process message: queue full");
1952 counters.rejectedExecutionException.updateCounterWithFlush();
1953 } else {
1954 log.error("Error while processing message from switch "
1955 + getSwitchInfoString()
1956 + "state " + this.state, e.getCause());
1957 counters.switchDisconnectOtherException.updateCounterWithFlush();
1958 ctx.getChannel().close();
1959 }
1960 }
1961
1962 @Override
1963 public String toString() {
1964 return getSwitchInfoString();
1965 }
1966
1967 @Override
1968 public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
1969 throws Exception {
1970 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
1971 OFMessage m = factory.buildEchoRequest().build();
1972 log.info("Sending Echo Request on idle channel: {}",
1973 e.getChannel().getPipeline().getLast().toString());
1974 e.getChannel().write(Collections.singletonList(m));
1975 // XXX S some problems here -- echo request has no transaction id, and
1976 // echo reply is not correlated to the echo request.
1977 }
1978
1979 @Override
1980 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
1981 throws Exception {
1982 if (e.getMessage() instanceof List) {
1983 @SuppressWarnings("unchecked")
1984 List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
1985
1986
1987 for (OFMessage ofm : msglist) {
1988 counters.messageReceived.updateCounterNoFlush();
1989 // Do the actual packet processing
1990 state.processOFMessage(this, ofm);
1991 }
1992 } else {
1993 counters.messageReceived.updateCounterNoFlush();
1994 state.processOFMessage(this, (OFMessage) e.getMessage());
1995 }
1996 }
1997
1998
1999
2000 //*************************
2001 // Channel utility methods
2002 //*************************
2003
2004 /**
2005 * Is this a state in which the handshake has completed?
2006 * @return true if the handshake is complete
2007 */
2008 public boolean isHandshakeComplete() {
2009 return this.state.isHandshakeComplete();
2010 }
2011
2012 private void dispatchMessage(OFMessage m) throws IOException {
2013 sw.handleMessage(m);
2014 }
2015
2016 /**
2017 * Return a string describing this switch based on the already available
2018 * information (DPID and/or remote socket).
2019 * @return
2020 */
2021 private String getSwitchInfoString() {
2022 if (sw != null) {
2023 return sw.toString();
2024 }
2025 String channelString;
2026 if (channel == null || channel.getRemoteAddress() == null) {
2027 channelString = "?";
2028 } else {
2029 channelString = channel.getRemoteAddress().toString();
2030 }
2031 String dpidString;
2032 if (featuresReply == null) {
2033 dpidString = "?";
2034 } else {
2035 dpidString = featuresReply.getDatapathId().toString();
2036 }
2037 return String.format("[%s DPID[%s]]", channelString, dpidString);
2038 }
2039
2040 /**
2041 * Update the channels state. Only called from the state machine.
2042 * TODO: enforce restricted state transitions
2043 * @param state
2044 */
2045 private void setState(ChannelState state) {
2046 this.state = state;
2047 }
2048
2049 /**
2050 * Send hello message to the switch using the handshake transactions ids.
2051 * @throws IOException
2052 */
2053 private void sendHandshakeHelloMessage() throws IOException {
2054 // The OF protocol requires us to start things off by sending the highest
2055 // version of the protocol supported.
2056
2057 // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
2058 // see Sec. 7.5.1 of the OF1.3.4 spec
2059 U32 bitmap = U32.ofRaw(0x00000012);
2060 OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
2061 .setBitmaps(Collections.singletonList(bitmap))
2062 .build();
2063 OFMessage.Builder mb = factory13.buildHello()
2064 .setXid(this.handshakeTransactionIds--)
2065 .setElements(Collections.singletonList(hem));
2066 log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
2067 channel.write(Collections.singletonList(mb.build()));
2068 }
2069
2070 /**
2071 * Send featuresRequest msg to the switch using the handshake transactions ids.
2072 * @throws IOException
2073 */
2074 private void sendHandshakeFeaturesRequestMessage() throws IOException {
2075 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
2076 OFMessage m = factory.buildFeaturesRequest()
2077 .setXid(this.handshakeTransactionIds--)
2078 .build();
2079 channel.write(Collections.singletonList(m));
2080 }
2081
2082 private void setSwitchRole(Role role) {
2083 sw.setRole(role);
2084 }
2085
2086 /**
2087 * Send the configuration requests to tell the switch we want full
2088 * packets.
2089 * @throws IOException
2090 */
2091 private void sendHandshakeSetConfig() throws IOException {
2092 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
2093 //log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
2094 List<OFMessage> msglist = new ArrayList<OFMessage>(3);
2095
2096 // Ensure we receive the full packet via PacketIn
2097 // FIXME: We don't set the reassembly flags.
2098 OFSetConfig sc = factory
2099 .buildSetConfig()
2100 .setMissSendLen((short) 0xffff)
2101 .setXid(this.handshakeTransactionIds--)
2102 .build();
2103 msglist.add(sc);
2104
2105 // Barrier
2106 OFBarrierRequest br = factory
2107 .buildBarrierRequest()
2108 .setXid(this.handshakeTransactionIds--)
2109 .build();
2110 msglist.add(br);
2111
2112 // Verify (need barrier?)
2113 OFGetConfigRequest gcr = factory
2114 .buildGetConfigRequest()
2115 .setXid(this.handshakeTransactionIds--)
2116 .build();
2117 msglist.add(gcr);
2118 channel.write(msglist);
2119 }
2120
2121 /**
2122 * send a description state request.
2123 * @throws IOException
2124 */
2125 private void sendHandshakeDescriptionStatsRequest() throws IOException {
2126 // Get Description to set switch-specific flags
2127 OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
2128 OFDescStatsRequest dreq = factory
2129 .buildDescStatsRequest()
2130 .setXid(handshakeTransactionIds--)
2131 .build();
2132 channel.write(Collections.singletonList(dreq));
2133 }
2134
2135 private void sendHandshakeOFPortDescRequest() throws IOException {
2136 // Get port description for 1.3 switch
2137 OFPortDescStatsRequest preq = factory13
2138 .buildPortDescStatsRequest()
2139 .setXid(handshakeTransactionIds--)
2140 .build();
2141 channel.write(Collections.singletonList(preq));
2142 }
2143
2144 ChannelState getStateForTesting() {
2145 return state;
2146 }
2147
2148 void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
2149 roleChanger = new RoleChanger(roleTimeoutMs);
2150 }
2151
2152
2153}