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