blob: eb6571e84ee31bf763c019d8b6dc0bdd2b06c01f [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 Ortizaa8de492016-12-01 00:21:36 +010033import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
Jordi Ortiz91477b82016-11-29 15:22:50 +010034import org.projectfloodlight.openflow.protocol.OFMeterFeaturesStatsReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080035import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
36import org.projectfloodlight.openflow.protocol.OFPortDesc;
37import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
38import org.projectfloodlight.openflow.protocol.OFPortStatus;
Jian Li152b8852015-12-07 14:47:25 -080039import org.projectfloodlight.openflow.protocol.OFRoleReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080040import org.projectfloodlight.openflow.protocol.OFRoleRequest;
Marc De Leenheerc662d322016-02-18 16:05:10 -080041import org.projectfloodlight.openflow.protocol.OFVersion;
tom7ef8ff92014-09-17 13:08:06 -070042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
Thomas Vachuska1c681d72015-05-18 14:58:53 -070045import java.io.IOException;
46import java.net.InetSocketAddress;
47import java.net.SocketAddress;
48import java.util.ArrayList;
49import java.util.Collections;
50import java.util.List;
51import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connore755caa2015-11-16 16:43:09 -080052import java.util.concurrent.atomic.AtomicReference;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070053import java.util.stream.Collectors;
54
tom7ef8ff92014-09-17 13:08:06 -070055/**
56 * An abstract representation of an OpenFlow switch. Can be extended by others
57 * to serve as a base for their vendor specific representation of a switch.
58 */
alshabibb452fd72015-04-22 20:46:20 -070059public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
60 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070061
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070062 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070063
alshabibb452fd72015-04-22 20:46:20 -070064 private Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080065 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070066
67 private boolean connected;
68 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070069 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070070 private OpenFlowAgent agent;
71 private final AtomicInteger xidCounter = new AtomicInteger(0);
72
73 private OFVersion ofVersion;
74
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070075 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070076
77 protected boolean tableFull;
78
79 private RoleHandler roleMan;
80
Brian O'Connore755caa2015-11-16 16:43:09 -080081 // TODO this is accessed from multiple threads, but volatile may have performance implications
82 protected volatile RoleState role;
tom7ef8ff92014-09-17 13:08:06 -070083
84 protected OFFeaturesReply features;
85 protected OFDescStatsReply desc;
86
Jordi Ortiz91477b82016-11-29 15:22:50 +010087 protected OFMeterFeaturesStatsReply meterfeatures;
88
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080089 // messagesPendingMastership is used as synchronization variable for
90 // all mastership related changes. In this block, mastership (including
91 // role update) will have either occurred or not.
Brian O'Connore755caa2015-11-16 16:43:09 -080092 private final AtomicReference<List<OFMessage>> messagesPendingMastership
93 = new AtomicReference<>();
Charles Chan5b7ec342015-10-18 20:55:41 -070094
alshabibb452fd72015-04-22 20:46:20 -070095 @Override
96 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -070097 this.dpid = dpid;
98 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -070099 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -0700100 }
101
102 //************************
103 // Channel related
104 //************************
105
106 @Override
107 public final void disconnectSwitch() {
Charles Chanecfdfb72015-11-24 19:05:50 -0800108 setConnected(false);
tom7ef8ff92014-09-17 13:08:06 -0700109 this.channel.close();
110 }
111
112 @Override
Charles Chan5b7ec342015-10-18 20:55:41 -0700113 public void sendMsg(OFMessage msg) {
114 this.sendMsg(Collections.singletonList(msg));
tom7ef8ff92014-09-17 13:08:06 -0700115 }
116
117 @Override
118 public final void sendMsg(List<OFMessage> msgs) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800119 /*
120 It is possible that in this block, we transition to SLAVE/EQUAL.
121 If this is the case, the supplied messages will race with the
122 RoleRequest message, and they could be rejected by the switch.
123 In the interest of performance, we will not protect this block with
124 a synchronization primitive, because the message would have just been
125 dropped anyway.
126 */
Jian Lia78cdb22016-04-21 13:03:58 -0700127
Brian O'Connore755caa2015-11-16 16:43:09 -0800128 if (role == RoleState.MASTER) {
129 // fast path send when we are master
Brian O'Connore755caa2015-11-16 16:43:09 -0800130 sendMsgsOnChannel(msgs);
131 return;
132 }
133 // check to see if mastership transition is in progress
134 synchronized (messagesPendingMastership) {
135 /*
136 messagesPendingMastership is used as synchronization variable for
137 all mastership related changes. In this block, mastership (including
138 role update) will have either occurred or not.
139 */
140 if (role == RoleState.MASTER) {
141 // transition to MASTER complete, send messages
142 sendMsgsOnChannel(msgs);
143 return;
144 }
145
146 List<OFMessage> messages = messagesPendingMastership.get();
147 if (messages != null) {
148 // we are transitioning to MASTER, so add messages to queue
149 messages.addAll(msgs);
150 log.debug("Enqueue message for switch {}. queue size after is {}",
151 dpid, messages.size());
152 } else {
153 // not transitioning to MASTER
154 log.warn("Dropping message for switch {} (role: {}, connected: {}): {}",
155 dpid, role, channel.isConnected(), msgs);
156 }
157 }
Jian Li11111972016-04-01 23:49:00 -0700158 }
Jian Li152b8852015-12-07 14:47:25 -0800159
Brian O'Connore755caa2015-11-16 16:43:09 -0800160 private void sendMsgsOnChannel(List<OFMessage> msgs) {
161 if (channel.isConnected()) {
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700162 channel.write(msgs);
Jian Lia78cdb22016-04-21 13:03:58 -0700163 agent.processDownstreamMessage(dpid, msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700164 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800165 log.warn("Dropping messages for switch {} because channel is not connected: {}",
166 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700167 }
tom7ef8ff92014-09-17 13:08:06 -0700168 }
169
170 @Override
alshabibb452fd72015-04-22 20:46:20 -0700171 public final void sendRoleRequest(OFMessage msg) {
172 if (msg instanceof OFRoleRequest ||
173 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800174 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700175 return;
176 }
177 throw new IllegalArgumentException("Someone is trying to send " +
178 "a non role request message");
179 }
tom7ef8ff92014-09-17 13:08:06 -0700180
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700181 @Override
Marc De Leenheerc662d322016-02-18 16:05:10 -0800182 public final void
183 sendHandshakeMessage(OFMessage message) {
alshabiba2df7b2a2015-05-06 13:57:10 -0700184 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800185 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700186 }
187 }
188
tom7ef8ff92014-09-17 13:08:06 -0700189 @Override
190 public final boolean isConnected() {
191 return this.connected;
192 }
193
194 @Override
195 public final void setConnected(boolean connected) {
196 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700197 }
tom7ef8ff92014-09-17 13:08:06 -0700198
199 @Override
200 public final void setChannel(Channel channel) {
201 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800202 final SocketAddress address = channel.getRemoteAddress();
203 if (address instanceof InetSocketAddress) {
204 final InetSocketAddress inetAddress = (InetSocketAddress) address;
205 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700206 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800207 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
208 } else {
209 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
210 }
211 }
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700212 }
tom7ef8ff92014-09-17 13:08:06 -0700213
Ray Milkeye53f1712015-01-16 09:17:16 -0800214 @Override
215 public String channelId() {
216 return channelId;
217 }
218
tom7ef8ff92014-09-17 13:08:06 -0700219 //************************
220 // Switch features related
221 //************************
222
223 @Override
224 public final long getId() {
225 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700226 }
tom7ef8ff92014-09-17 13:08:06 -0700227
228 @Override
229 public final String getStringId() {
230 return this.dpid.toString();
231 }
232
233 @Override
234 public final void setOFVersion(OFVersion ofV) {
235 this.ofVersion = ofV;
236 }
237
238 @Override
239 public void setTableFull(boolean full) {
240 this.tableFull = full;
241 }
242
243 @Override
244 public void setFeaturesReply(OFFeaturesReply featuresReply) {
245 this.features = featuresReply;
246 }
247
248 @Override
Jordi Ortiz91477b82016-11-29 15:22:50 +0100249 public void setMeterFeaturesReply(OFMeterFeaturesStatsReply meterFeaturesReply) {
250 meterfeatures = meterFeaturesReply;
251 }
252
253 @Override
tom7ef8ff92014-09-17 13:08:06 -0700254 public abstract Boolean supportNxRole();
255
256 //************************
257 // Message handling
258 //************************
259 /**
260 * Handle the message coming from the dataplane.
261 *
262 * @param m the actual message
263 */
264 @Override
265 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800266 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700267 this.agent.processMessage(dpid, m);
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800268 } else {
269 log.trace("Dropping received message {}, was not MASTER", m);
alshabib339a3d92014-09-26 17:54:32 -0700270 }
tom7ef8ff92014-09-17 13:08:06 -0700271 }
272
273 @Override
274 public RoleState getRole() {
275 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700276 }
tom7ef8ff92014-09-17 13:08:06 -0700277
278 @Override
279 public final boolean connectSwitch() {
280 return this.agent.addConnectedSwitch(dpid, this);
281 }
282
283 @Override
284 public final boolean activateMasterSwitch() {
285 return this.agent.addActivatedMasterSwitch(dpid, this);
286 }
287
288 @Override
289 public final boolean activateEqualSwitch() {
290 return this.agent.addActivatedEqualSwitch(dpid, this);
291 }
292
293 @Override
294 public final void transitionToEqualSwitch() {
295 this.agent.transitionToEqualSwitch(dpid);
296 }
297
298 @Override
299 public final void transitionToMasterSwitch() {
300 this.agent.transitionToMasterSwitch(dpid);
Brian O'Connore755caa2015-11-16 16:43:09 -0800301 synchronized (messagesPendingMastership) {
302 List<OFMessage> messages = messagesPendingMastership.get();
303 if (messages != null) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800304 // Cannot use sendMsg here. It will only append to pending list.
305 sendMsgsOnChannel(messages);
Brian O'Connore755caa2015-11-16 16:43:09 -0800306 log.debug("Sending {} pending messages to switch {}",
307 messages.size(), dpid);
308 messagesPendingMastership.set(null);
309 }
310 // perform role transition after clearing messages queue
311 this.role = RoleState.MASTER;
Charles Chan5b7ec342015-10-18 20:55:41 -0700312 }
tom7ef8ff92014-09-17 13:08:06 -0700313 }
314
315 @Override
316 public final void removeConnectedSwitch() {
317 this.agent.removeConnectedSwitch(dpid);
318 }
319
320 @Override
321 public OFFactory factory() {
322 return OFFactories.getFactory(ofVersion);
323 }
324
325 @Override
326 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700327 this.ports.add(portDescReply);
328 }
329
330 @Override
331 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
332 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700333 }
334
335 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700336 public void returnRoleReply(RoleState requested, RoleState response) {
337 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700338 }
339
340 @Override
tom7ef8ff92014-09-17 13:08:06 -0700341 public abstract void startDriverHandshake();
342
343 @Override
344 public abstract boolean isDriverHandshakeComplete();
345
346 @Override
347 public abstract void processDriverHandshakeMessage(OFMessage m);
348
alshabib339a3d92014-09-26 17:54:32 -0700349
350 // Role Handling
351
tom7ef8ff92014-09-17 13:08:06 -0700352 @Override
353 public void setRole(RoleState role) {
354 try {
Brian O'Connore755caa2015-11-16 16:43:09 -0800355 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
356 // perform role transition to SLAVE/EQUAL before sending role request
357 this.role = role;
358 }
tom7ef8ff92014-09-17 13:08:06 -0700359 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700360 log.debug("Sending role {} to switch {}", role, getStringId());
Brian O'Connore755caa2015-11-16 16:43:09 -0800361 if (role == RoleState.MASTER) {
362 synchronized (messagesPendingMastership) {
363 if (messagesPendingMastership.get() == null) {
364 log.debug("Initializing new message queue for switch {}", dpid);
365 /*
366 The presence of messagesPendingMastership indicates that
367 a switch is currently transitioning to MASTER, but
368 is still awaiting role reply from switch.
369 */
370 messagesPendingMastership.set(Lists.newArrayList());
371 }
Charles Chan5b7ec342015-10-18 20:55:41 -0700372 }
alshabib339a3d92014-09-26 17:54:32 -0700373 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800374 } else if (role == RoleState.MASTER) {
375 // role request not support; transition switch to MASTER
alshabib7814e9f2014-09-30 11:52:12 -0700376 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700377 }
378 } catch (IOException e) {
379 log.error("Unable to write to switch {}.", this.dpid);
380 }
381 }
382
alshabib339a3d92014-09-26 17:54:32 -0700383 @Override
384 public void reassertRole() {
Brian O'Connore755caa2015-11-16 16:43:09 -0800385 // TODO should messages be sent directly or queue during reassertion?
alshabib339a3d92014-09-26 17:54:32 -0700386 if (this.getRole() == RoleState.MASTER) {
387 log.warn("Received permission error from switch {} while " +
388 "being master. Reasserting master role.",
389 this.getStringId());
390 this.setRole(RoleState.MASTER);
391 }
392 }
393
tom7ef8ff92014-09-17 13:08:06 -0700394 @Override
395 public void handleRole(OFMessage m) throws SwitchStateException {
396 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
397 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
398 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
399 if (rri.getRole() == RoleState.MASTER) {
400 this.transitionToMasterSwitch();
401 } else if (rri.getRole() == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800402 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700403 this.transitionToEqualSwitch();
404 }
alshabib339a3d92014-09-26 17:54:32 -0700405 } else {
alshabib4785eec2014-12-04 16:45:45 -0800406 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700407 }
408 }
409
410 @Override
411 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
412 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
413 if (r == null) {
414 // The message wasn't really a Nicira role reply. We just
415 // dispatch it to the OFMessage listeners in this case.
416 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700417 return;
tom7ef8ff92014-09-17 13:08:06 -0700418 }
419
420 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
421 new RoleReplyInfo(r, null, m.getXid()));
422 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
423 if (r == RoleState.MASTER) {
424 this.transitionToMasterSwitch();
425 } else if (r == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800426 r == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700427 this.transitionToEqualSwitch();
428 }
alshabib339a3d92014-09-26 17:54:32 -0700429 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700430 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700431 }
432 }
433
434 @Override
435 public boolean handleRoleError(OFErrorMsg error) {
436 try {
437 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
438 } catch (SwitchStateException e) {
439 this.disconnectSwitch();
440 }
441 return true;
442 }
443
tom7ef8ff92014-09-17 13:08:06 -0700444 @Override
445 public final void setAgent(OpenFlowAgent ag) {
446 if (this.agent == null) {
447 this.agent = ag;
448 }
449 }
450
451 @Override
452 public final void setRoleHandler(RoleHandler roleHandler) {
453 if (this.roleMan == null) {
454 this.roleMan = roleHandler;
455 }
456 }
457
458 @Override
459 public void setSwitchDescription(OFDescStatsReply d) {
460 this.desc = d;
461 }
462
463 @Override
464 public int getNextTransactionId() {
465 return this.xidCounter.getAndIncrement();
466 }
467
468 @Override
469 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700470 return this.ports.stream()
Brian O'Connore755caa2015-11-16 16:43:09 -0800471 .flatMap(portReply -> portReply.getEntries().stream())
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700472 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700473 }
474
475 @Override
Jordi Ortizaa8de492016-12-01 00:21:36 +0100476 public OFMeterFeatures getMeterFeatures() {
477 if (this.meterfeatures != null) {
478 return this.meterfeatures.getFeatures();
479 } else {
480 return null;
481 }
482 }
483
484 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800485 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700486 return this.desc.getMfrDesc();
487 }
488
tom7ef8ff92014-09-17 13:08:06 -0700489 @Override
490 public String datapathDescription() {
491 return this.desc.getDpDesc();
492 }
493
tom7ef8ff92014-09-17 13:08:06 -0700494 @Override
495 public String hardwareDescription() {
496 return this.desc.getHwDesc();
497 }
498
499 @Override
500 public String softwareDescription() {
501 return this.desc.getSwDesc();
502 }
503
504 @Override
505 public String serialNumber() {
506 return this.desc.getSerialNum();
507 }
508
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700509 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700510 public Device.Type deviceType() {
511 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700512 }
513
alshabibb452fd72015-04-22 20:46:20 -0700514 @Override
515 public String toString() {
516 return this.getClass().getName() + " [" + ((channel != null)
517 ? channel.getRemoteAddress() : "?")
518 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
519 }
tom7ef8ff92014-09-17 13:08:06 -0700520}