blob: 323e03a8769e242d6a39b01eb95571714d822a36 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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.Collections;
48import java.util.List;
49import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connore755caa2015-11-16 16:43:09 -080050import java.util.concurrent.atomic.AtomicReference;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070051import java.util.stream.Collectors;
52
tom7ef8ff92014-09-17 13:08:06 -070053/**
54 * An abstract representation of an OpenFlow switch. Can be extended by others
55 * to serve as a base for their vendor specific representation of a switch.
56 */
alshabibb452fd72015-04-22 20:46:20 -070057public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
58 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070059
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070060 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070061
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070062 private OpenFlowSession channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080063 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070064
65 private boolean connected;
66 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070067 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070068 private OpenFlowAgent agent;
69 private final AtomicInteger xidCounter = new AtomicInteger(0);
70
71 private OFVersion ofVersion;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070072 private OFFactory ofFactory;
tom7ef8ff92014-09-17 13:08:06 -070073
Jordan Halterman415817c2017-11-29 22:27:00 -080074 protected List<OFPortDescStatsReply> ports = Lists.newCopyOnWriteArrayList();
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);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700108 this.channel.closeSession();
tom7ef8ff92014-09-17 13:08:06 -0700109 }
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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700153 log.warn("Dropping message for switch {} (role: {}, active: {}): {}",
154 dpid, role, channel.isActive(), msgs);
Brian O'Connore755caa2015-11-16 16:43:09 -0800155 }
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) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700160 if (channel.sendMsg(msgs)) {
Jian Lia78cdb22016-04-21 13:03:58 -0700161 agent.processDownstreamMessage(dpid, msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700162 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800163 log.warn("Dropping messages for switch {} because channel is not connected: {}",
164 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700165 }
tom7ef8ff92014-09-17 13:08:06 -0700166 }
167
168 @Override
alshabibb452fd72015-04-22 20:46:20 -0700169 public final void sendRoleRequest(OFMessage msg) {
170 if (msg instanceof OFRoleRequest ||
171 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800172 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700173 return;
174 }
175 throw new IllegalArgumentException("Someone is trying to send " +
176 "a non role request message");
177 }
tom7ef8ff92014-09-17 13:08:06 -0700178
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700179 @Override
Marc De Leenheerc662d322016-02-18 16:05:10 -0800180 public final void
181 sendHandshakeMessage(OFMessage message) {
alshabiba2df7b2a2015-05-06 13:57:10 -0700182 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800183 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700184 }
185 }
186
tom7ef8ff92014-09-17 13:08:06 -0700187 @Override
188 public final boolean isConnected() {
189 return this.connected;
190 }
191
192 @Override
193 public final void setConnected(boolean connected) {
194 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700195 }
tom7ef8ff92014-09-17 13:08:06 -0700196
197 @Override
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700198 public final void setChannel(OpenFlowSession channel) {
tom7ef8ff92014-09-17 13:08:06 -0700199 this.channel = channel;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700200 channelId = channel.sessionInfo().toString();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700201 }
tom7ef8ff92014-09-17 13:08:06 -0700202
Ray Milkeye53f1712015-01-16 09:17:16 -0800203 @Override
204 public String channelId() {
205 return channelId;
206 }
207
tom7ef8ff92014-09-17 13:08:06 -0700208 //************************
209 // Switch features related
210 //************************
211
212 @Override
213 public final long getId() {
214 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700215 }
tom7ef8ff92014-09-17 13:08:06 -0700216
217 @Override
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700218 public Dpid getDpid() {
219 return this.dpid;
220 }
221
222 @Override
tom7ef8ff92014-09-17 13:08:06 -0700223 public final String getStringId() {
224 return this.dpid.toString();
225 }
226
227 @Override
228 public final void setOFVersion(OFVersion ofV) {
229 this.ofVersion = ofV;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700230 this.ofFactory = OFFactories.getFactory(ofV);
tom7ef8ff92014-09-17 13:08:06 -0700231 }
232
233 @Override
234 public void setTableFull(boolean full) {
235 this.tableFull = full;
236 }
237
238 @Override
239 public void setFeaturesReply(OFFeaturesReply featuresReply) {
240 this.features = featuresReply;
241 }
242
243 @Override
Jordi Ortiz91477b82016-11-29 15:22:50 +0100244 public void setMeterFeaturesReply(OFMeterFeaturesStatsReply meterFeaturesReply) {
245 meterfeatures = meterFeaturesReply;
246 }
247
248 @Override
tom7ef8ff92014-09-17 13:08:06 -0700249 public abstract Boolean supportNxRole();
250
251 //************************
252 // Message handling
253 //************************
254 /**
255 * Handle the message coming from the dataplane.
256 *
257 * @param m the actual message
258 */
259 @Override
260 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800261 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700262 try {
263 this.agent.processMessage(dpid, m);
264 } catch (Exception e) {
265 log.warn("Unhandled exception processing {}@{}", m, dpid, e);
266 }
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() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700321 return ofFactory;
tom7ef8ff92014-09-17 13:08:06 -0700322 }
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
Jordi Ortizaa8de492016-12-01 00:21:36 +0100475 public OFMeterFeatures getMeterFeatures() {
476 if (this.meterfeatures != null) {
477 return this.meterfeatures.getFeatures();
478 } else {
479 return null;
480 }
481 }
482
483 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800484 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700485 return this.desc.getMfrDesc();
486 }
487
tom7ef8ff92014-09-17 13:08:06 -0700488 @Override
489 public String datapathDescription() {
490 return this.desc.getDpDesc();
491 }
492
tom7ef8ff92014-09-17 13:08:06 -0700493 @Override
494 public String hardwareDescription() {
495 return this.desc.getHwDesc();
496 }
497
498 @Override
499 public String softwareDescription() {
500 return this.desc.getSwDesc();
501 }
502
503 @Override
504 public String serialNumber() {
505 return this.desc.getSerialNum();
506 }
507
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700508 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700509 public Device.Type deviceType() {
510 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700511 }
512
alshabibb452fd72015-04-22 20:46:20 -0700513 @Override
514 public String toString() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700515 return MoreObjects.toStringHelper(getClass())
516 .add("session", channel.sessionInfo())
517 .add("dpid", dpid)
518 .toString();
alshabibb452fd72015-04-22 20:46:20 -0700519 }
tom7ef8ff92014-09-17 13:08:06 -0700520}