blob: 0943ed165bc649e2e4de2ef028a565d1f3cab560 [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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070019import com.google.common.base.MoreObjects;
Brian O'Connore755caa2015-11-16 16:43:09 -080020import com.google.common.collect.Lists;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070021
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;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070025import org.onosproject.openflow.controller.OpenFlowSession;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070027import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
Jian Li152b8852015-12-07 14:47:25 -080028import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Marc De Leenheerc662d322016-02-18 16:05:10 -080029import org.projectfloodlight.openflow.protocol.OFExperimenter;
30import org.projectfloodlight.openflow.protocol.OFFactories;
Jian Li152b8852015-12-07 14:47:25 -080031import org.projectfloodlight.openflow.protocol.OFFactory;
Marc De Leenheerc662d322016-02-18 16:05:10 -080032import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
33import org.projectfloodlight.openflow.protocol.OFMessage;
Jordi Ortizaa8de492016-12-01 00:21:36 +010034import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
Jordi Ortiz91477b82016-11-29 15:22:50 +010035import org.projectfloodlight.openflow.protocol.OFMeterFeaturesStatsReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080036import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
37import org.projectfloodlight.openflow.protocol.OFPortDesc;
38import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
39import org.projectfloodlight.openflow.protocol.OFPortStatus;
Jian Li152b8852015-12-07 14:47:25 -080040import org.projectfloodlight.openflow.protocol.OFRoleReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080041import org.projectfloodlight.openflow.protocol.OFRoleRequest;
Marc De Leenheerc662d322016-02-18 16:05:10 -080042import org.projectfloodlight.openflow.protocol.OFVersion;
tom7ef8ff92014-09-17 13:08:06 -070043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
Thomas Vachuska1c681d72015-05-18 14:58:53 -070046import java.io.IOException;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070047import 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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070063 private OpenFlowSession 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;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070073 private OFFactory ofFactory;
tom7ef8ff92014-09-17 13:08:06 -070074
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);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700109 this.channel.closeSession();
tom7ef8ff92014-09-17 13:08:06 -0700110 }
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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700154 log.warn("Dropping message for switch {} (role: {}, active: {}): {}",
155 dpid, role, channel.isActive(), msgs);
Brian O'Connore755caa2015-11-16 16:43:09 -0800156 }
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) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700161 if (channel.sendMsg(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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700199 public final void setChannel(OpenFlowSession channel) {
tom7ef8ff92014-09-17 13:08:06 -0700200 this.channel = channel;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700201 channelId = channel.sessionInfo().toString();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700202 }
tom7ef8ff92014-09-17 13:08:06 -0700203
Ray Milkeye53f1712015-01-16 09:17:16 -0800204 @Override
205 public String channelId() {
206 return channelId;
207 }
208
tom7ef8ff92014-09-17 13:08:06 -0700209 //************************
210 // Switch features related
211 //************************
212
213 @Override
214 public final long getId() {
215 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700216 }
tom7ef8ff92014-09-17 13:08:06 -0700217
218 @Override
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700219 public Dpid getDpid() {
220 return this.dpid;
221 }
222
223 @Override
tom7ef8ff92014-09-17 13:08:06 -0700224 public final String getStringId() {
225 return this.dpid.toString();
226 }
227
228 @Override
229 public final void setOFVersion(OFVersion ofV) {
230 this.ofVersion = ofV;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700231 this.ofFactory = OFFactories.getFactory(ofV);
tom7ef8ff92014-09-17 13:08:06 -0700232 }
233
234 @Override
235 public void setTableFull(boolean full) {
236 this.tableFull = full;
237 }
238
239 @Override
240 public void setFeaturesReply(OFFeaturesReply featuresReply) {
241 this.features = featuresReply;
242 }
243
244 @Override
Jordi Ortiz91477b82016-11-29 15:22:50 +0100245 public void setMeterFeaturesReply(OFMeterFeaturesStatsReply meterFeaturesReply) {
246 meterfeatures = meterFeaturesReply;
247 }
248
249 @Override
tom7ef8ff92014-09-17 13:08:06 -0700250 public abstract Boolean supportNxRole();
251
252 //************************
253 // Message handling
254 //************************
255 /**
256 * Handle the message coming from the dataplane.
257 *
258 * @param m the actual message
259 */
260 @Override
261 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800262 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700263 try {
264 this.agent.processMessage(dpid, m);
265 } catch (Exception e) {
266 log.warn("Unhandled exception processing {}@{}", m, dpid, e);
267 }
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() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700322 return ofFactory;
tom7ef8ff92014-09-17 13:08:06 -0700323 }
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() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700516 return MoreObjects.toStringHelper(getClass())
517 .add("session", channel.sessionInfo())
518 .add("dpid", dpid)
519 .toString();
alshabibb452fd72015-04-22 20:46:20 -0700520 }
tom7ef8ff92014-09-17 13:08:06 -0700521}