blob: 3a999a2a9a5c61cebee079b2c1b499574c082611 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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
Jian Li152b8852015-12-07 14:47:25 -080019import static org.onlab.util.Tools.groupedThreads;
20
Brian O'Connore755caa2015-11-16 16:43:09 -080021import com.google.common.collect.Lists;
tom7ef8ff92014-09-17 13:08:06 -070022import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080023import org.onlab.packet.IpAddress;
Marc De Leenheerb9311372015-07-09 11:36:49 -070024import org.onosproject.net.Device;
alshabibb452fd72015-04-22 20:46:20 -070025import org.onosproject.net.driver.AbstractHandlerBehaviour;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.openflow.controller.Dpid;
Jian Li152b8852015-12-07 14:47:25 -080027import org.onosproject.openflow.controller.OpenFlowEventListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.openflow.controller.RoleState;
Jian Li152b8852015-12-07 14:47:25 -080029
tom7ef8ff92014-09-17 13:08:06 -070030import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070031import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
tom7ef8ff92014-09-17 13:08:06 -070032import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070033import org.projectfloodlight.openflow.protocol.OFVersion;
Jian Li152b8852015-12-07 14:47:25 -080034import org.projectfloodlight.openflow.protocol.OFMessage;
35import org.projectfloodlight.openflow.protocol.OFType;
36import org.projectfloodlight.openflow.protocol.OFFactories;
37import org.projectfloodlight.openflow.protocol.OFPortDesc;
38import org.projectfloodlight.openflow.protocol.OFExperimenter;
39import org.projectfloodlight.openflow.protocol.OFErrorMsg;
40import org.projectfloodlight.openflow.protocol.OFRoleRequest;
41import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
42import org.projectfloodlight.openflow.protocol.OFPortStatus;
43import org.projectfloodlight.openflow.protocol.OFFactory;
44import org.projectfloodlight.openflow.protocol.OFRoleReply;
45
tom7ef8ff92014-09-17 13:08:06 -070046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Thomas Vachuska1c681d72015-05-18 14:58:53 -070049import java.io.IOException;
50import java.net.InetSocketAddress;
51import java.net.SocketAddress;
52import java.util.ArrayList;
53import java.util.Collections;
54import java.util.List;
Jian Li152b8852015-12-07 14:47:25 -080055import java.util.Set;
56import java.util.concurrent.CopyOnWriteArraySet;
57import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Executors;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070059import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connore755caa2015-11-16 16:43:09 -080060import java.util.concurrent.atomic.AtomicReference;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070061import java.util.stream.Collectors;
62
tom7ef8ff92014-09-17 13:08:06 -070063/**
64 * An abstract representation of an OpenFlow switch. Can be extended by others
65 * to serve as a base for their vendor specific representation of a switch.
66 */
alshabibb452fd72015-04-22 20:46:20 -070067public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
68 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070069
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070070 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070071
alshabibb452fd72015-04-22 20:46:20 -070072 private Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080073 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070074
75 private boolean connected;
76 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070077 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070078 private OpenFlowAgent agent;
79 private final AtomicInteger xidCounter = new AtomicInteger(0);
80
81 private OFVersion ofVersion;
82
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070083 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070084
85 protected boolean tableFull;
86
87 private RoleHandler roleMan;
88
Brian O'Connore755caa2015-11-16 16:43:09 -080089 // TODO this is accessed from multiple threads, but volatile may have performance implications
90 protected volatile RoleState role;
tom7ef8ff92014-09-17 13:08:06 -070091
92 protected OFFeaturesReply features;
93 protected OFDescStatsReply desc;
94
Jian Li28247b52016-01-07 17:24:15 -080095 protected Set<OpenFlowEventListener> ofOutgoingMsgListener = new CopyOnWriteArraySet<>();
Jian Li152b8852015-12-07 14:47:25 -080096
97 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -080098 Executors.newCachedThreadPool(groupedThreads("onos/of", "event-outgoing-msg-stats-%d", log));
Jian Li152b8852015-12-07 14:47:25 -080099
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800100 // messagesPendingMastership is used as synchronization variable for
101 // all mastership related changes. In this block, mastership (including
102 // role update) will have either occurred or not.
Brian O'Connore755caa2015-11-16 16:43:09 -0800103 private final AtomicReference<List<OFMessage>> messagesPendingMastership
104 = new AtomicReference<>();
Charles Chan5b7ec342015-10-18 20:55:41 -0700105
alshabibb452fd72015-04-22 20:46:20 -0700106 @Override
107 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -0700108 this.dpid = dpid;
109 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -0700110 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -0700111 }
112
113 //************************
114 // Channel related
115 //************************
116
117 @Override
118 public final void disconnectSwitch() {
Charles Chanecfdfb72015-11-24 19:05:50 -0800119 setConnected(false);
tom7ef8ff92014-09-17 13:08:06 -0700120 this.channel.close();
121 }
122
123 @Override
Charles Chan5b7ec342015-10-18 20:55:41 -0700124 public void sendMsg(OFMessage msg) {
125 this.sendMsg(Collections.singletonList(msg));
tom7ef8ff92014-09-17 13:08:06 -0700126 }
127
128 @Override
129 public final void sendMsg(List<OFMessage> msgs) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800130 /*
131 It is possible that in this block, we transition to SLAVE/EQUAL.
132 If this is the case, the supplied messages will race with the
133 RoleRequest message, and they could be rejected by the switch.
134 In the interest of performance, we will not protect this block with
135 a synchronization primitive, because the message would have just been
136 dropped anyway.
137 */
138 if (role == RoleState.MASTER) {
139 // fast path send when we are master
140
141 sendMsgsOnChannel(msgs);
142 return;
143 }
144 // check to see if mastership transition is in progress
145 synchronized (messagesPendingMastership) {
146 /*
147 messagesPendingMastership is used as synchronization variable for
148 all mastership related changes. In this block, mastership (including
149 role update) will have either occurred or not.
150 */
151 if (role == RoleState.MASTER) {
152 // transition to MASTER complete, send messages
153 sendMsgsOnChannel(msgs);
154 return;
155 }
156
157 List<OFMessage> messages = messagesPendingMastership.get();
158 if (messages != null) {
159 // we are transitioning to MASTER, so add messages to queue
160 messages.addAll(msgs);
161 log.debug("Enqueue message for switch {}. queue size after is {}",
162 dpid, messages.size());
163 } else {
164 // not transitioning to MASTER
165 log.warn("Dropping message for switch {} (role: {}, connected: {}): {}",
166 dpid, role, channel.isConnected(), msgs);
167 }
168 }
Jian Li152b8852015-12-07 14:47:25 -0800169
Jian Li28247b52016-01-07 17:24:15 -0800170 // listen to outgoing control messages only if listeners are registered
171 if (ofOutgoingMsgListener.size() != 0) {
172 msgs.forEach(m -> {
173 if (m.getType() == OFType.PACKET_OUT ||
174 m.getType() == OFType.FLOW_MOD ||
175 m.getType() == OFType.STATS_REQUEST) {
Andrea Campanelladda93562016-03-02 11:08:12 -0800176 executorMsgs.execute(new OFMessageHandler(dpid, m));
Jian Li28247b52016-01-07 17:24:15 -0800177 }
178 });
179 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800180 }
181
182 private void sendMsgsOnChannel(List<OFMessage> msgs) {
183 if (channel.isConnected()) {
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700184 channel.write(msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700185 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800186 log.warn("Dropping messages for switch {} because channel is not connected: {}",
187 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700188 }
tom7ef8ff92014-09-17 13:08:06 -0700189 }
190
191 @Override
alshabibb452fd72015-04-22 20:46:20 -0700192 public final void sendRoleRequest(OFMessage msg) {
193 if (msg instanceof OFRoleRequest ||
194 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800195 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700196 return;
197 }
198 throw new IllegalArgumentException("Someone is trying to send " +
199 "a non role request message");
200 }
tom7ef8ff92014-09-17 13:08:06 -0700201
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700202 @Override
alshabiba2df7b2a2015-05-06 13:57:10 -0700203 public final void sendHandshakeMessage(OFMessage message) {
204 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800205 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700206 }
207 }
208
tom7ef8ff92014-09-17 13:08:06 -0700209 @Override
210 public final boolean isConnected() {
211 return this.connected;
212 }
213
214 @Override
215 public final void setConnected(boolean connected) {
216 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700217 }
tom7ef8ff92014-09-17 13:08:06 -0700218
219 @Override
220 public final void setChannel(Channel channel) {
221 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800222 final SocketAddress address = channel.getRemoteAddress();
223 if (address instanceof InetSocketAddress) {
224 final InetSocketAddress inetAddress = (InetSocketAddress) address;
225 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700226 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800227 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
228 } else {
229 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
230 }
231 }
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700232 }
tom7ef8ff92014-09-17 13:08:06 -0700233
Ray Milkeye53f1712015-01-16 09:17:16 -0800234 @Override
235 public String channelId() {
236 return channelId;
237 }
238
tom7ef8ff92014-09-17 13:08:06 -0700239 //************************
240 // Switch features related
241 //************************
242
243 @Override
244 public final long getId() {
245 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700246 }
tom7ef8ff92014-09-17 13:08:06 -0700247
248 @Override
249 public final String getStringId() {
250 return this.dpid.toString();
251 }
252
253 @Override
254 public final void setOFVersion(OFVersion ofV) {
255 this.ofVersion = ofV;
256 }
257
258 @Override
259 public void setTableFull(boolean full) {
260 this.tableFull = full;
261 }
262
263 @Override
264 public void setFeaturesReply(OFFeaturesReply featuresReply) {
265 this.features = featuresReply;
266 }
267
268 @Override
269 public abstract Boolean supportNxRole();
270
271 //************************
272 // Message handling
273 //************************
274 /**
275 * Handle the message coming from the dataplane.
276 *
277 * @param m the actual message
278 */
279 @Override
280 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800281 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700282 this.agent.processMessage(dpid, m);
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800283 } else {
284 log.trace("Dropping received message {}, was not MASTER", m);
alshabib339a3d92014-09-26 17:54:32 -0700285 }
tom7ef8ff92014-09-17 13:08:06 -0700286 }
287
288 @Override
289 public RoleState getRole() {
290 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700291 }
tom7ef8ff92014-09-17 13:08:06 -0700292
293 @Override
294 public final boolean connectSwitch() {
295 return this.agent.addConnectedSwitch(dpid, this);
296 }
297
298 @Override
299 public final boolean activateMasterSwitch() {
300 return this.agent.addActivatedMasterSwitch(dpid, this);
301 }
302
303 @Override
304 public final boolean activateEqualSwitch() {
305 return this.agent.addActivatedEqualSwitch(dpid, this);
306 }
307
308 @Override
309 public final void transitionToEqualSwitch() {
310 this.agent.transitionToEqualSwitch(dpid);
311 }
312
313 @Override
314 public final void transitionToMasterSwitch() {
315 this.agent.transitionToMasterSwitch(dpid);
Brian O'Connore755caa2015-11-16 16:43:09 -0800316 synchronized (messagesPendingMastership) {
317 List<OFMessage> messages = messagesPendingMastership.get();
318 if (messages != null) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800319 // Cannot use sendMsg here. It will only append to pending list.
320 sendMsgsOnChannel(messages);
Brian O'Connore755caa2015-11-16 16:43:09 -0800321 log.debug("Sending {} pending messages to switch {}",
322 messages.size(), dpid);
323 messagesPendingMastership.set(null);
324 }
325 // perform role transition after clearing messages queue
326 this.role = RoleState.MASTER;
Charles Chan5b7ec342015-10-18 20:55:41 -0700327 }
tom7ef8ff92014-09-17 13:08:06 -0700328 }
329
330 @Override
331 public final void removeConnectedSwitch() {
332 this.agent.removeConnectedSwitch(dpid);
333 }
334
335 @Override
Jian Li152b8852015-12-07 14:47:25 -0800336 public void addEventListener(OpenFlowEventListener listener) {
Jian Li28247b52016-01-07 17:24:15 -0800337 ofOutgoingMsgListener.add(listener);
Jian Li152b8852015-12-07 14:47:25 -0800338 }
339
340 @Override
341 public void removeEventListener(OpenFlowEventListener listener) {
Jian Li28247b52016-01-07 17:24:15 -0800342 ofOutgoingMsgListener.remove(listener);
Jian Li152b8852015-12-07 14:47:25 -0800343 }
344
345 @Override
tom7ef8ff92014-09-17 13:08:06 -0700346 public OFFactory factory() {
347 return OFFactories.getFactory(ofVersion);
348 }
349
350 @Override
351 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700352 this.ports.add(portDescReply);
353 }
354
355 @Override
356 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
357 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700358 }
359
360 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700361 public void returnRoleReply(RoleState requested, RoleState response) {
362 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700363 }
364
365 @Override
tom7ef8ff92014-09-17 13:08:06 -0700366 public abstract void startDriverHandshake();
367
368 @Override
369 public abstract boolean isDriverHandshakeComplete();
370
371 @Override
372 public abstract void processDriverHandshakeMessage(OFMessage m);
373
alshabib339a3d92014-09-26 17:54:32 -0700374
375 // Role Handling
376
tom7ef8ff92014-09-17 13:08:06 -0700377 @Override
378 public void setRole(RoleState role) {
379 try {
Brian O'Connore755caa2015-11-16 16:43:09 -0800380 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
381 // perform role transition to SLAVE/EQUAL before sending role request
382 this.role = role;
383 }
tom7ef8ff92014-09-17 13:08:06 -0700384 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700385 log.debug("Sending role {} to switch {}", role, getStringId());
Brian O'Connore755caa2015-11-16 16:43:09 -0800386 if (role == RoleState.MASTER) {
387 synchronized (messagesPendingMastership) {
388 if (messagesPendingMastership.get() == null) {
389 log.debug("Initializing new message queue for switch {}", dpid);
390 /*
391 The presence of messagesPendingMastership indicates that
392 a switch is currently transitioning to MASTER, but
393 is still awaiting role reply from switch.
394 */
395 messagesPendingMastership.set(Lists.newArrayList());
396 }
Charles Chan5b7ec342015-10-18 20:55:41 -0700397 }
alshabib339a3d92014-09-26 17:54:32 -0700398 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800399 } else if (role == RoleState.MASTER) {
400 // role request not support; transition switch to MASTER
alshabib7814e9f2014-09-30 11:52:12 -0700401 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700402 }
403 } catch (IOException e) {
404 log.error("Unable to write to switch {}.", this.dpid);
405 }
406 }
407
alshabib339a3d92014-09-26 17:54:32 -0700408 @Override
409 public void reassertRole() {
Brian O'Connore755caa2015-11-16 16:43:09 -0800410 // TODO should messages be sent directly or queue during reassertion?
alshabib339a3d92014-09-26 17:54:32 -0700411 if (this.getRole() == RoleState.MASTER) {
412 log.warn("Received permission error from switch {} while " +
413 "being master. Reasserting master role.",
414 this.getStringId());
415 this.setRole(RoleState.MASTER);
416 }
417 }
418
tom7ef8ff92014-09-17 13:08:06 -0700419 @Override
420 public void handleRole(OFMessage m) throws SwitchStateException {
421 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
422 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
423 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
424 if (rri.getRole() == RoleState.MASTER) {
425 this.transitionToMasterSwitch();
426 } else if (rri.getRole() == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800427 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700428 this.transitionToEqualSwitch();
429 }
alshabib339a3d92014-09-26 17:54:32 -0700430 } else {
alshabib4785eec2014-12-04 16:45:45 -0800431 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700432 }
433 }
434
435 @Override
436 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
437 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
438 if (r == null) {
439 // The message wasn't really a Nicira role reply. We just
440 // dispatch it to the OFMessage listeners in this case.
441 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700442 return;
tom7ef8ff92014-09-17 13:08:06 -0700443 }
444
445 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
446 new RoleReplyInfo(r, null, m.getXid()));
447 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
448 if (r == RoleState.MASTER) {
449 this.transitionToMasterSwitch();
450 } else if (r == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800451 r == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700452 this.transitionToEqualSwitch();
453 }
alshabib339a3d92014-09-26 17:54:32 -0700454 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700455 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700456 }
457 }
458
459 @Override
460 public boolean handleRoleError(OFErrorMsg error) {
461 try {
462 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
463 } catch (SwitchStateException e) {
464 this.disconnectSwitch();
465 }
466 return true;
467 }
468
tom7ef8ff92014-09-17 13:08:06 -0700469 @Override
470 public final void setAgent(OpenFlowAgent ag) {
471 if (this.agent == null) {
472 this.agent = ag;
473 }
474 }
475
476 @Override
477 public final void setRoleHandler(RoleHandler roleHandler) {
478 if (this.roleMan == null) {
479 this.roleMan = roleHandler;
480 }
481 }
482
483 @Override
484 public void setSwitchDescription(OFDescStatsReply d) {
485 this.desc = d;
486 }
487
488 @Override
489 public int getNextTransactionId() {
490 return this.xidCounter.getAndIncrement();
491 }
492
493 @Override
494 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700495 return this.ports.stream()
Brian O'Connore755caa2015-11-16 16:43:09 -0800496 .flatMap(portReply -> portReply.getEntries().stream())
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700497 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700498 }
499
500 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800501 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700502 return this.desc.getMfrDesc();
503 }
504
tom7ef8ff92014-09-17 13:08:06 -0700505 @Override
506 public String datapathDescription() {
507 return this.desc.getDpDesc();
508 }
509
tom7ef8ff92014-09-17 13:08:06 -0700510 @Override
511 public String hardwareDescription() {
512 return this.desc.getHwDesc();
513 }
514
515 @Override
516 public String softwareDescription() {
517 return this.desc.getSwDesc();
518 }
519
520 @Override
521 public String serialNumber() {
522 return this.desc.getSerialNum();
523 }
524
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700525 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700526 public Device.Type deviceType() {
527 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700528 }
529
alshabibb452fd72015-04-22 20:46:20 -0700530 @Override
531 public String toString() {
532 return this.getClass().getName() + " [" + ((channel != null)
533 ? channel.getRemoteAddress() : "?")
534 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
535 }
Jian Li152b8852015-12-07 14:47:25 -0800536
537 /**
538 * OpenFlow message handler for outgoing control messages.
539 */
540 protected final class OFMessageHandler implements Runnable {
541
542 protected final OFMessage msg;
543 protected final Dpid dpid;
544
545 public OFMessageHandler(Dpid dpid, OFMessage msg) {
546 this.msg = msg;
547 this.dpid = dpid;
548 }
549
550 @Override
551 public void run() {
Jian Li28247b52016-01-07 17:24:15 -0800552 for (OpenFlowEventListener listener : ofOutgoingMsgListener) {
Jian Li152b8852015-12-07 14:47:25 -0800553 listener.handleMessage(dpid, msg);
554 }
555 }
556 }
tom7ef8ff92014-09-17 13:08:06 -0700557}