blob: 098ff07c1faa6c0af59805cd8be8560c01af7f00 [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 Li152b8852015-12-07 14:47:25 -080095 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
96
97 protected ExecutorService executorMsgs =
98 Executors.newFixedThreadPool(2, groupedThreads("onos/of", "ctrl-msg-stats-%d"));
99
Brian O'Connore755caa2015-11-16 16:43:09 -0800100 private final AtomicReference<List<OFMessage>> messagesPendingMastership
101 = new AtomicReference<>();
Charles Chan5b7ec342015-10-18 20:55:41 -0700102
alshabibb452fd72015-04-22 20:46:20 -0700103 @Override
104 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -0700105 this.dpid = dpid;
106 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -0700107 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -0700108 }
109
110 //************************
111 // Channel related
112 //************************
113
114 @Override
115 public final void disconnectSwitch() {
Charles Chanecfdfb72015-11-24 19:05:50 -0800116 setConnected(false);
tom7ef8ff92014-09-17 13:08:06 -0700117 this.channel.close();
118 }
119
120 @Override
Charles Chan5b7ec342015-10-18 20:55:41 -0700121 public void sendMsg(OFMessage msg) {
122 this.sendMsg(Collections.singletonList(msg));
tom7ef8ff92014-09-17 13:08:06 -0700123 }
124
125 @Override
126 public final void sendMsg(List<OFMessage> msgs) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800127 /*
128 It is possible that in this block, we transition to SLAVE/EQUAL.
129 If this is the case, the supplied messages will race with the
130 RoleRequest message, and they could be rejected by the switch.
131 In the interest of performance, we will not protect this block with
132 a synchronization primitive, because the message would have just been
133 dropped anyway.
134 */
135 if (role == RoleState.MASTER) {
136 // fast path send when we are master
137
138 sendMsgsOnChannel(msgs);
139 return;
140 }
141 // check to see if mastership transition is in progress
142 synchronized (messagesPendingMastership) {
143 /*
144 messagesPendingMastership is used as synchronization variable for
145 all mastership related changes. In this block, mastership (including
146 role update) will have either occurred or not.
147 */
148 if (role == RoleState.MASTER) {
149 // transition to MASTER complete, send messages
150 sendMsgsOnChannel(msgs);
151 return;
152 }
153
154 List<OFMessage> messages = messagesPendingMastership.get();
155 if (messages != null) {
156 // we are transitioning to MASTER, so add messages to queue
157 messages.addAll(msgs);
158 log.debug("Enqueue message for switch {}. queue size after is {}",
159 dpid, messages.size());
160 } else {
161 // not transitioning to MASTER
162 log.warn("Dropping message for switch {} (role: {}, connected: {}): {}",
163 dpid, role, channel.isConnected(), msgs);
164 }
165 }
Jian Li152b8852015-12-07 14:47:25 -0800166
167 // listen to outgoing control messages
168 msgs.forEach(m -> {
169 if (m.getType() == OFType.PACKET_OUT ||
170 m.getType() == OFType.FLOW_MOD ||
171 m.getType() == OFType.STATS_REQUEST) {
172 executorMsgs.submit(new OFMessageHandler(dpid, m));
173 }
174 });
Brian O'Connore755caa2015-11-16 16:43:09 -0800175 }
176
177 private void sendMsgsOnChannel(List<OFMessage> msgs) {
178 if (channel.isConnected()) {
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700179 channel.write(msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700180 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800181 log.warn("Dropping messages for switch {} because channel is not connected: {}",
182 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700183 }
tom7ef8ff92014-09-17 13:08:06 -0700184 }
185
186 @Override
alshabibb452fd72015-04-22 20:46:20 -0700187 public final void sendRoleRequest(OFMessage msg) {
188 if (msg instanceof OFRoleRequest ||
189 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800190 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700191 return;
192 }
193 throw new IllegalArgumentException("Someone is trying to send " +
194 "a non role request message");
195 }
tom7ef8ff92014-09-17 13:08:06 -0700196
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700197 @Override
alshabiba2df7b2a2015-05-06 13:57:10 -0700198 public final void sendHandshakeMessage(OFMessage message) {
199 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800200 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700201 }
202 }
203
tom7ef8ff92014-09-17 13:08:06 -0700204 @Override
205 public final boolean isConnected() {
206 return this.connected;
207 }
208
209 @Override
210 public final void setConnected(boolean connected) {
211 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700212 }
tom7ef8ff92014-09-17 13:08:06 -0700213
214 @Override
215 public final void setChannel(Channel channel) {
216 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800217 final SocketAddress address = channel.getRemoteAddress();
218 if (address instanceof InetSocketAddress) {
219 final InetSocketAddress inetAddress = (InetSocketAddress) address;
220 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700221 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800222 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
223 } else {
224 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
225 }
226 }
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700227 }
tom7ef8ff92014-09-17 13:08:06 -0700228
Ray Milkeye53f1712015-01-16 09:17:16 -0800229 @Override
230 public String channelId() {
231 return channelId;
232 }
233
tom7ef8ff92014-09-17 13:08:06 -0700234 //************************
235 // Switch features related
236 //************************
237
238 @Override
239 public final long getId() {
240 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700241 }
tom7ef8ff92014-09-17 13:08:06 -0700242
243 @Override
244 public final String getStringId() {
245 return this.dpid.toString();
246 }
247
248 @Override
249 public final void setOFVersion(OFVersion ofV) {
250 this.ofVersion = ofV;
251 }
252
253 @Override
254 public void setTableFull(boolean full) {
255 this.tableFull = full;
256 }
257
258 @Override
259 public void setFeaturesReply(OFFeaturesReply featuresReply) {
260 this.features = featuresReply;
261 }
262
263 @Override
264 public abstract Boolean supportNxRole();
265
266 //************************
267 // Message handling
268 //************************
269 /**
270 * Handle the message coming from the dataplane.
271 *
272 * @param m the actual message
273 */
274 @Override
275 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800276 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700277 this.agent.processMessage(dpid, m);
278 }
tom7ef8ff92014-09-17 13:08:06 -0700279 }
280
281 @Override
282 public RoleState getRole() {
283 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700284 }
tom7ef8ff92014-09-17 13:08:06 -0700285
286 @Override
287 public final boolean connectSwitch() {
288 return this.agent.addConnectedSwitch(dpid, this);
289 }
290
291 @Override
292 public final boolean activateMasterSwitch() {
293 return this.agent.addActivatedMasterSwitch(dpid, this);
294 }
295
296 @Override
297 public final boolean activateEqualSwitch() {
298 return this.agent.addActivatedEqualSwitch(dpid, this);
299 }
300
301 @Override
302 public final void transitionToEqualSwitch() {
303 this.agent.transitionToEqualSwitch(dpid);
304 }
305
306 @Override
307 public final void transitionToMasterSwitch() {
308 this.agent.transitionToMasterSwitch(dpid);
Brian O'Connore755caa2015-11-16 16:43:09 -0800309 synchronized (messagesPendingMastership) {
310 List<OFMessage> messages = messagesPendingMastership.get();
311 if (messages != null) {
312 this.sendMsg(messages);
313 log.debug("Sending {} pending messages to switch {}",
314 messages.size(), dpid);
315 messagesPendingMastership.set(null);
316 }
317 // perform role transition after clearing messages queue
318 this.role = RoleState.MASTER;
Charles Chan5b7ec342015-10-18 20:55:41 -0700319 }
tom7ef8ff92014-09-17 13:08:06 -0700320 }
321
322 @Override
323 public final void removeConnectedSwitch() {
324 this.agent.removeConnectedSwitch(dpid);
325 }
326
327 @Override
Jian Li152b8852015-12-07 14:47:25 -0800328 public void addEventListener(OpenFlowEventListener listener) {
329 ofEventListener.add(listener);
330 }
331
332 @Override
333 public void removeEventListener(OpenFlowEventListener listener) {
334 ofEventListener.remove(listener);
335 }
336
337 @Override
tom7ef8ff92014-09-17 13:08:06 -0700338 public OFFactory factory() {
339 return OFFactories.getFactory(ofVersion);
340 }
341
342 @Override
343 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700344 this.ports.add(portDescReply);
345 }
346
347 @Override
348 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
349 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700350 }
351
352 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700353 public void returnRoleReply(RoleState requested, RoleState response) {
354 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700355 }
356
357 @Override
tom7ef8ff92014-09-17 13:08:06 -0700358 public abstract void startDriverHandshake();
359
360 @Override
361 public abstract boolean isDriverHandshakeComplete();
362
363 @Override
364 public abstract void processDriverHandshakeMessage(OFMessage m);
365
alshabib339a3d92014-09-26 17:54:32 -0700366
367 // Role Handling
368
tom7ef8ff92014-09-17 13:08:06 -0700369 @Override
370 public void setRole(RoleState role) {
371 try {
Brian O'Connore755caa2015-11-16 16:43:09 -0800372 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
373 // perform role transition to SLAVE/EQUAL before sending role request
374 this.role = role;
375 }
tom7ef8ff92014-09-17 13:08:06 -0700376 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700377 log.debug("Sending role {} to switch {}", role, getStringId());
Brian O'Connore755caa2015-11-16 16:43:09 -0800378 if (role == RoleState.MASTER) {
379 synchronized (messagesPendingMastership) {
380 if (messagesPendingMastership.get() == null) {
381 log.debug("Initializing new message queue for switch {}", dpid);
382 /*
383 The presence of messagesPendingMastership indicates that
384 a switch is currently transitioning to MASTER, but
385 is still awaiting role reply from switch.
386 */
387 messagesPendingMastership.set(Lists.newArrayList());
388 }
Charles Chan5b7ec342015-10-18 20:55:41 -0700389 }
alshabib339a3d92014-09-26 17:54:32 -0700390 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800391 } else if (role == RoleState.MASTER) {
392 // role request not support; transition switch to MASTER
alshabib7814e9f2014-09-30 11:52:12 -0700393 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700394 }
395 } catch (IOException e) {
396 log.error("Unable to write to switch {}.", this.dpid);
397 }
398 }
399
alshabib339a3d92014-09-26 17:54:32 -0700400 @Override
401 public void reassertRole() {
Brian O'Connore755caa2015-11-16 16:43:09 -0800402 // TODO should messages be sent directly or queue during reassertion?
alshabib339a3d92014-09-26 17:54:32 -0700403 if (this.getRole() == RoleState.MASTER) {
404 log.warn("Received permission error from switch {} while " +
405 "being master. Reasserting master role.",
406 this.getStringId());
407 this.setRole(RoleState.MASTER);
408 }
409 }
410
tom7ef8ff92014-09-17 13:08:06 -0700411 @Override
412 public void handleRole(OFMessage m) throws SwitchStateException {
413 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
414 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
415 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
416 if (rri.getRole() == RoleState.MASTER) {
417 this.transitionToMasterSwitch();
418 } else if (rri.getRole() == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800419 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700420 this.transitionToEqualSwitch();
421 }
alshabib339a3d92014-09-26 17:54:32 -0700422 } else {
alshabib4785eec2014-12-04 16:45:45 -0800423 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700424 }
425 }
426
427 @Override
428 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
429 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
430 if (r == null) {
431 // The message wasn't really a Nicira role reply. We just
432 // dispatch it to the OFMessage listeners in this case.
433 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700434 return;
tom7ef8ff92014-09-17 13:08:06 -0700435 }
436
437 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
438 new RoleReplyInfo(r, null, m.getXid()));
439 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
440 if (r == RoleState.MASTER) {
441 this.transitionToMasterSwitch();
442 } else if (r == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800443 r == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700444 this.transitionToEqualSwitch();
445 }
alshabib339a3d92014-09-26 17:54:32 -0700446 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700447 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700448 }
449 }
450
451 @Override
452 public boolean handleRoleError(OFErrorMsg error) {
453 try {
454 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
455 } catch (SwitchStateException e) {
456 this.disconnectSwitch();
457 }
458 return true;
459 }
460
tom7ef8ff92014-09-17 13:08:06 -0700461 @Override
462 public final void setAgent(OpenFlowAgent ag) {
463 if (this.agent == null) {
464 this.agent = ag;
465 }
466 }
467
468 @Override
469 public final void setRoleHandler(RoleHandler roleHandler) {
470 if (this.roleMan == null) {
471 this.roleMan = roleHandler;
472 }
473 }
474
475 @Override
476 public void setSwitchDescription(OFDescStatsReply d) {
477 this.desc = d;
478 }
479
480 @Override
481 public int getNextTransactionId() {
482 return this.xidCounter.getAndIncrement();
483 }
484
485 @Override
486 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700487 return this.ports.stream()
Brian O'Connore755caa2015-11-16 16:43:09 -0800488 .flatMap(portReply -> portReply.getEntries().stream())
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700489 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700490 }
491
492 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800493 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700494 return this.desc.getMfrDesc();
495 }
496
tom7ef8ff92014-09-17 13:08:06 -0700497 @Override
498 public String datapathDescription() {
499 return this.desc.getDpDesc();
500 }
501
tom7ef8ff92014-09-17 13:08:06 -0700502 @Override
503 public String hardwareDescription() {
504 return this.desc.getHwDesc();
505 }
506
507 @Override
508 public String softwareDescription() {
509 return this.desc.getSwDesc();
510 }
511
512 @Override
513 public String serialNumber() {
514 return this.desc.getSerialNum();
515 }
516
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700517 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700518 public Device.Type deviceType() {
519 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700520 }
521
alshabibb452fd72015-04-22 20:46:20 -0700522 @Override
523 public String toString() {
524 return this.getClass().getName() + " [" + ((channel != null)
525 ? channel.getRemoteAddress() : "?")
526 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
527 }
Jian Li152b8852015-12-07 14:47:25 -0800528
529 /**
530 * OpenFlow message handler for outgoing control messages.
531 */
532 protected final class OFMessageHandler implements Runnable {
533
534 protected final OFMessage msg;
535 protected final Dpid dpid;
536
537 public OFMessageHandler(Dpid dpid, OFMessage msg) {
538 this.msg = msg;
539 this.dpid = dpid;
540 }
541
542 @Override
543 public void run() {
544 for (OpenFlowEventListener listener : ofEventListener) {
545 listener.handleMessage(dpid, msg);
546 }
547 }
548 }
tom7ef8ff92014-09-17 13:08:06 -0700549}