blob: 128863ea92d620eb7e315a77150070bf803833fe [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
tom7ef8ff92014-09-17 13:08:06 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
tom7ef8ff92014-09-17 13:08:06 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
tom7ef8ff92014-09-17 13:08:06 -070016
Brian O'Connorabafb502014-12-02 22:26:20 -080017package org.onosproject.openflow.controller.driver;
tom7ef8ff92014-09-17 13:08:06 -070018
Brian O'Connore755caa2015-11-16 16:43:09 -080019import com.google.common.collect.Lists;
tom7ef8ff92014-09-17 13:08:06 -070020import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080021import org.onlab.packet.IpAddress;
Marc De Leenheerb9311372015-07-09 11:36:49 -070022import org.onosproject.net.Device;
alshabibb452fd72015-04-22 20:46:20 -070023import org.onosproject.net.driver.AbstractHandlerBehaviour;
Brian O'Connorabafb502014-12-02 22:26:20 -080024import org.onosproject.openflow.controller.Dpid;
25import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070026import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
Jian Li152b8852015-12-07 14:47:25 -080027import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Marc De Leenheerc662d322016-02-18 16:05:10 -080028import org.projectfloodlight.openflow.protocol.OFExperimenter;
29import org.projectfloodlight.openflow.protocol.OFFactories;
Jian Li152b8852015-12-07 14:47:25 -080030import org.projectfloodlight.openflow.protocol.OFFactory;
Marc De Leenheerc662d322016-02-18 16:05:10 -080031import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
32import org.projectfloodlight.openflow.protocol.OFMessage;
Jordi Ortiz91477b82016-11-29 15:22:50 +010033import org.projectfloodlight.openflow.protocol.OFMeterFeaturesStatsReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080034import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
35import org.projectfloodlight.openflow.protocol.OFPortDesc;
36import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
37import org.projectfloodlight.openflow.protocol.OFPortStatus;
Jian Li152b8852015-12-07 14:47:25 -080038import org.projectfloodlight.openflow.protocol.OFRoleReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080039import org.projectfloodlight.openflow.protocol.OFRoleRequest;
Marc De Leenheerc662d322016-02-18 16:05:10 -080040import org.projectfloodlight.openflow.protocol.OFVersion;
tom7ef8ff92014-09-17 13:08:06 -070041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
Thomas Vachuska1c681d72015-05-18 14:58:53 -070044import java.io.IOException;
45import java.net.InetSocketAddress;
46import java.net.SocketAddress;
47import java.util.ArrayList;
48import java.util.Collections;
49import java.util.List;
50import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connore755caa2015-11-16 16:43:09 -080051import java.util.concurrent.atomic.AtomicReference;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070052import java.util.stream.Collectors;
53
tom7ef8ff92014-09-17 13:08:06 -070054/**
55 * An abstract representation of an OpenFlow switch. Can be extended by others
56 * to serve as a base for their vendor specific representation of a switch.
57 */
alshabibb452fd72015-04-22 20:46:20 -070058public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
59 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070060
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070061 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070062
alshabibb452fd72015-04-22 20:46:20 -070063 private Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080064 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070065
66 private boolean connected;
67 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070068 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070069 private OpenFlowAgent agent;
70 private final AtomicInteger xidCounter = new AtomicInteger(0);
71
72 private OFVersion ofVersion;
73
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070074 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070075
76 protected boolean tableFull;
77
78 private RoleHandler roleMan;
79
Brian O'Connore755caa2015-11-16 16:43:09 -080080 // TODO this is accessed from multiple threads, but volatile may have performance implications
81 protected volatile RoleState role;
tom7ef8ff92014-09-17 13:08:06 -070082
83 protected OFFeaturesReply features;
84 protected OFDescStatsReply desc;
85
Jordi Ortiz91477b82016-11-29 15:22:50 +010086 protected OFMeterFeaturesStatsReply meterfeatures;
87
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080088 // messagesPendingMastership is used as synchronization variable for
89 // all mastership related changes. In this block, mastership (including
90 // role update) will have either occurred or not.
Brian O'Connore755caa2015-11-16 16:43:09 -080091 private final AtomicReference<List<OFMessage>> messagesPendingMastership
92 = new AtomicReference<>();
Charles Chan5b7ec342015-10-18 20:55:41 -070093
alshabibb452fd72015-04-22 20:46:20 -070094 @Override
95 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -070096 this.dpid = dpid;
97 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -070098 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -070099 }
100
101 //************************
102 // Channel related
103 //************************
104
105 @Override
106 public final void disconnectSwitch() {
Charles Chanecfdfb72015-11-24 19:05:50 -0800107 setConnected(false);
tom7ef8ff92014-09-17 13:08:06 -0700108 this.channel.close();
109 }
110
111 @Override
Charles Chan5b7ec342015-10-18 20:55:41 -0700112 public void sendMsg(OFMessage msg) {
113 this.sendMsg(Collections.singletonList(msg));
tom7ef8ff92014-09-17 13:08:06 -0700114 }
115
116 @Override
117 public final void sendMsg(List<OFMessage> msgs) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800118 /*
119 It is possible that in this block, we transition to SLAVE/EQUAL.
120 If this is the case, the supplied messages will race with the
121 RoleRequest message, and they could be rejected by the switch.
122 In the interest of performance, we will not protect this block with
123 a synchronization primitive, because the message would have just been
124 dropped anyway.
125 */
Jian Lia78cdb22016-04-21 13:03:58 -0700126
Brian O'Connore755caa2015-11-16 16:43:09 -0800127 if (role == RoleState.MASTER) {
128 // fast path send when we are master
Brian O'Connore755caa2015-11-16 16:43:09 -0800129 sendMsgsOnChannel(msgs);
130 return;
131 }
132 // check to see if mastership transition is in progress
133 synchronized (messagesPendingMastership) {
134 /*
135 messagesPendingMastership is used as synchronization variable for
136 all mastership related changes. In this block, mastership (including
137 role update) will have either occurred or not.
138 */
139 if (role == RoleState.MASTER) {
140 // transition to MASTER complete, send messages
141 sendMsgsOnChannel(msgs);
142 return;
143 }
144
145 List<OFMessage> messages = messagesPendingMastership.get();
146 if (messages != null) {
147 // we are transitioning to MASTER, so add messages to queue
148 messages.addAll(msgs);
149 log.debug("Enqueue message for switch {}. queue size after is {}",
150 dpid, messages.size());
151 } else {
152 // not transitioning to MASTER
153 log.warn("Dropping message for switch {} (role: {}, connected: {}): {}",
154 dpid, role, channel.isConnected(), msgs);
155 }
156 }
Jian Li11111972016-04-01 23:49:00 -0700157 }
Jian Li152b8852015-12-07 14:47:25 -0800158
Brian O'Connore755caa2015-11-16 16:43:09 -0800159 private void sendMsgsOnChannel(List<OFMessage> msgs) {
160 if (channel.isConnected()) {
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700161 channel.write(msgs);
Jian Lia78cdb22016-04-21 13:03:58 -0700162 agent.processDownstreamMessage(dpid, msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700163 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800164 log.warn("Dropping messages for switch {} because channel is not connected: {}",
165 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700166 }
tom7ef8ff92014-09-17 13:08:06 -0700167 }
168
169 @Override
alshabibb452fd72015-04-22 20:46:20 -0700170 public final void sendRoleRequest(OFMessage msg) {
171 if (msg instanceof OFRoleRequest ||
172 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800173 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700174 return;
175 }
176 throw new IllegalArgumentException("Someone is trying to send " +
177 "a non role request message");
178 }
tom7ef8ff92014-09-17 13:08:06 -0700179
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700180 @Override
Marc De Leenheerc662d322016-02-18 16:05:10 -0800181 public final void
182 sendHandshakeMessage(OFMessage message) {
alshabiba2df7b2a2015-05-06 13:57:10 -0700183 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800184 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700185 }
186 }
187
tom7ef8ff92014-09-17 13:08:06 -0700188 @Override
189 public final boolean isConnected() {
190 return this.connected;
191 }
192
193 @Override
194 public final void setConnected(boolean connected) {
195 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700196 }
tom7ef8ff92014-09-17 13:08:06 -0700197
198 @Override
199 public final void setChannel(Channel channel) {
200 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800201 final SocketAddress address = channel.getRemoteAddress();
202 if (address instanceof InetSocketAddress) {
203 final InetSocketAddress inetAddress = (InetSocketAddress) address;
204 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700205 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800206 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
207 } else {
208 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
209 }
210 }
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700211 }
tom7ef8ff92014-09-17 13:08:06 -0700212
Ray Milkeye53f1712015-01-16 09:17:16 -0800213 @Override
214 public String channelId() {
215 return channelId;
216 }
217
tom7ef8ff92014-09-17 13:08:06 -0700218 //************************
219 // Switch features related
220 //************************
221
222 @Override
223 public final long getId() {
224 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700225 }
tom7ef8ff92014-09-17 13:08:06 -0700226
227 @Override
228 public final String getStringId() {
229 return this.dpid.toString();
230 }
231
232 @Override
233 public final void setOFVersion(OFVersion ofV) {
234 this.ofVersion = ofV;
235 }
236
237 @Override
238 public void setTableFull(boolean full) {
239 this.tableFull = full;
240 }
241
242 @Override
243 public void setFeaturesReply(OFFeaturesReply featuresReply) {
244 this.features = featuresReply;
245 }
246
247 @Override
Jordi Ortiz91477b82016-11-29 15:22:50 +0100248 public void setMeterFeaturesReply(OFMeterFeaturesStatsReply meterFeaturesReply) {
249 meterfeatures = meterFeaturesReply;
250 }
251
252 @Override
tom7ef8ff92014-09-17 13:08:06 -0700253 public abstract Boolean supportNxRole();
254
255 //************************
256 // Message handling
257 //************************
258 /**
259 * Handle the message coming from the dataplane.
260 *
261 * @param m the actual message
262 */
263 @Override
264 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800265 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700266 this.agent.processMessage(dpid, m);
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800267 } else {
268 log.trace("Dropping received message {}, was not MASTER", m);
alshabib339a3d92014-09-26 17:54:32 -0700269 }
tom7ef8ff92014-09-17 13:08:06 -0700270 }
271
272 @Override
273 public RoleState getRole() {
274 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700275 }
tom7ef8ff92014-09-17 13:08:06 -0700276
277 @Override
278 public final boolean connectSwitch() {
279 return this.agent.addConnectedSwitch(dpid, this);
280 }
281
282 @Override
283 public final boolean activateMasterSwitch() {
284 return this.agent.addActivatedMasterSwitch(dpid, this);
285 }
286
287 @Override
288 public final boolean activateEqualSwitch() {
289 return this.agent.addActivatedEqualSwitch(dpid, this);
290 }
291
292 @Override
293 public final void transitionToEqualSwitch() {
294 this.agent.transitionToEqualSwitch(dpid);
295 }
296
297 @Override
298 public final void transitionToMasterSwitch() {
299 this.agent.transitionToMasterSwitch(dpid);
Brian O'Connore755caa2015-11-16 16:43:09 -0800300 synchronized (messagesPendingMastership) {
301 List<OFMessage> messages = messagesPendingMastership.get();
302 if (messages != null) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800303 // Cannot use sendMsg here. It will only append to pending list.
304 sendMsgsOnChannel(messages);
Brian O'Connore755caa2015-11-16 16:43:09 -0800305 log.debug("Sending {} pending messages to switch {}",
306 messages.size(), dpid);
307 messagesPendingMastership.set(null);
308 }
309 // perform role transition after clearing messages queue
310 this.role = RoleState.MASTER;
Charles Chan5b7ec342015-10-18 20:55:41 -0700311 }
tom7ef8ff92014-09-17 13:08:06 -0700312 }
313
314 @Override
315 public final void removeConnectedSwitch() {
316 this.agent.removeConnectedSwitch(dpid);
317 }
318
319 @Override
320 public OFFactory factory() {
321 return OFFactories.getFactory(ofVersion);
322 }
323
324 @Override
325 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700326 this.ports.add(portDescReply);
327 }
328
329 @Override
330 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
331 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700332 }
333
334 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700335 public void returnRoleReply(RoleState requested, RoleState response) {
336 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700337 }
338
339 @Override
tom7ef8ff92014-09-17 13:08:06 -0700340 public abstract void startDriverHandshake();
341
342 @Override
343 public abstract boolean isDriverHandshakeComplete();
344
345 @Override
346 public abstract void processDriverHandshakeMessage(OFMessage m);
347
alshabib339a3d92014-09-26 17:54:32 -0700348
349 // Role Handling
350
tom7ef8ff92014-09-17 13:08:06 -0700351 @Override
352 public void setRole(RoleState role) {
353 try {
Brian O'Connore755caa2015-11-16 16:43:09 -0800354 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
355 // perform role transition to SLAVE/EQUAL before sending role request
356 this.role = role;
357 }
tom7ef8ff92014-09-17 13:08:06 -0700358 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700359 log.debug("Sending role {} to switch {}", role, getStringId());
Brian O'Connore755caa2015-11-16 16:43:09 -0800360 if (role == RoleState.MASTER) {
361 synchronized (messagesPendingMastership) {
362 if (messagesPendingMastership.get() == null) {
363 log.debug("Initializing new message queue for switch {}", dpid);
364 /*
365 The presence of messagesPendingMastership indicates that
366 a switch is currently transitioning to MASTER, but
367 is still awaiting role reply from switch.
368 */
369 messagesPendingMastership.set(Lists.newArrayList());
370 }
Charles Chan5b7ec342015-10-18 20:55:41 -0700371 }
alshabib339a3d92014-09-26 17:54:32 -0700372 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800373 } else if (role == RoleState.MASTER) {
374 // role request not support; transition switch to MASTER
alshabib7814e9f2014-09-30 11:52:12 -0700375 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700376 }
377 } catch (IOException e) {
378 log.error("Unable to write to switch {}.", this.dpid);
379 }
380 }
381
alshabib339a3d92014-09-26 17:54:32 -0700382 @Override
383 public void reassertRole() {
Brian O'Connore755caa2015-11-16 16:43:09 -0800384 // TODO should messages be sent directly or queue during reassertion?
alshabib339a3d92014-09-26 17:54:32 -0700385 if (this.getRole() == RoleState.MASTER) {
386 log.warn("Received permission error from switch {} while " +
387 "being master. Reasserting master role.",
388 this.getStringId());
389 this.setRole(RoleState.MASTER);
390 }
391 }
392
tom7ef8ff92014-09-17 13:08:06 -0700393 @Override
394 public void handleRole(OFMessage m) throws SwitchStateException {
395 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
396 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
397 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
398 if (rri.getRole() == RoleState.MASTER) {
399 this.transitionToMasterSwitch();
400 } else if (rri.getRole() == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800401 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700402 this.transitionToEqualSwitch();
403 }
alshabib339a3d92014-09-26 17:54:32 -0700404 } else {
alshabib4785eec2014-12-04 16:45:45 -0800405 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700406 }
407 }
408
409 @Override
410 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
411 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
412 if (r == null) {
413 // The message wasn't really a Nicira role reply. We just
414 // dispatch it to the OFMessage listeners in this case.
415 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700416 return;
tom7ef8ff92014-09-17 13:08:06 -0700417 }
418
419 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
420 new RoleReplyInfo(r, null, m.getXid()));
421 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
422 if (r == RoleState.MASTER) {
423 this.transitionToMasterSwitch();
424 } else if (r == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800425 r == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700426 this.transitionToEqualSwitch();
427 }
alshabib339a3d92014-09-26 17:54:32 -0700428 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700429 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700430 }
431 }
432
433 @Override
434 public boolean handleRoleError(OFErrorMsg error) {
435 try {
436 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
437 } catch (SwitchStateException e) {
438 this.disconnectSwitch();
439 }
440 return true;
441 }
442
tom7ef8ff92014-09-17 13:08:06 -0700443 @Override
444 public final void setAgent(OpenFlowAgent ag) {
445 if (this.agent == null) {
446 this.agent = ag;
447 }
448 }
449
450 @Override
451 public final void setRoleHandler(RoleHandler roleHandler) {
452 if (this.roleMan == null) {
453 this.roleMan = roleHandler;
454 }
455 }
456
457 @Override
458 public void setSwitchDescription(OFDescStatsReply d) {
459 this.desc = d;
460 }
461
462 @Override
463 public int getNextTransactionId() {
464 return this.xidCounter.getAndIncrement();
465 }
466
467 @Override
468 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700469 return this.ports.stream()
Brian O'Connore755caa2015-11-16 16:43:09 -0800470 .flatMap(portReply -> portReply.getEntries().stream())
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700471 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700472 }
473
474 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800475 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700476 return this.desc.getMfrDesc();
477 }
478
tom7ef8ff92014-09-17 13:08:06 -0700479 @Override
480 public String datapathDescription() {
481 return this.desc.getDpDesc();
482 }
483
tom7ef8ff92014-09-17 13:08:06 -0700484 @Override
485 public String hardwareDescription() {
486 return this.desc.getHwDesc();
487 }
488
489 @Override
490 public String softwareDescription() {
491 return this.desc.getSwDesc();
492 }
493
494 @Override
495 public String serialNumber() {
496 return this.desc.getSerialNum();
497 }
498
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700499 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700500 public Device.Type deviceType() {
501 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700502 }
503
alshabibb452fd72015-04-22 20:46:20 -0700504 @Override
505 public String toString() {
506 return this.getClass().getName() + " [" + ((channel != null)
507 ? channel.getRemoteAddress() : "?")
508 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
509 }
tom7ef8ff92014-09-17 13:08:06 -0700510}