blob: 762a8f5cea2af047e11176a8757f059ef490a09f [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -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
Thomas Vachuska781d18b2014-10-27 10:31:25 -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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -070017
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080018import com.google.common.collect.ArrayListMultimap;
alshabib64def642014-12-02 23:27:37 -080019import com.google.common.collect.Lists;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080020import com.google.common.collect.Multimap;
21import com.google.common.collect.Sets;
tom7ef8ff92014-09-17 13:08:06 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080025import org.apache.felix.scr.annotations.Modified;
tom7ef8ff92014-09-17 13:08:06 -070026import org.apache.felix.scr.annotations.Service;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
28import org.onosproject.openflow.controller.Dpid;
29import org.onosproject.openflow.controller.OpenFlowController;
30import org.onosproject.openflow.controller.OpenFlowEventListener;
31import org.onosproject.openflow.controller.OpenFlowPacketContext;
32import org.onosproject.openflow.controller.OpenFlowSwitch;
33import org.onosproject.openflow.controller.OpenFlowSwitchListener;
34import org.onosproject.openflow.controller.PacketListener;
35import org.onosproject.openflow.controller.RoleState;
36import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080037import org.osgi.service.component.ComponentContext;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070038import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
39import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080040import org.projectfloodlight.openflow.protocol.OFFactories;
41import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
42import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080043import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
44import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
45import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
46import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070047import org.projectfloodlight.openflow.protocol.OFMessage;
48import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070049import org.projectfloodlight.openflow.protocol.OFPortDesc;
tom7ef8ff92014-09-17 13:08:06 -070050import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070051import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080052import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
tom7ef8ff92014-09-17 13:08:06 -070053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080056import java.util.Collection;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080057import java.util.Dictionary;
58import java.util.HashMap;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080059import java.util.HashSet;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080060import java.util.Map;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080061import java.util.Set;
62import java.util.concurrent.ConcurrentHashMap;
63import java.util.concurrent.ExecutorService;
64import java.util.concurrent.Executors;
65import java.util.concurrent.locks.Lock;
66import java.util.concurrent.locks.ReentrantLock;
67
68import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070069
70@Component(immediate = true)
71@Service
72public class OpenFlowControllerImpl implements OpenFlowController {
73
74 private static final Logger log =
75 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
76
Pavlin Radoslavov369c6432014-12-03 16:25:14 -080077 private final ExecutorService executorMsgs =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080078 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -080079
80 private final ExecutorService executorBarrier =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080081 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -070082
tom7ef8ff92014-09-17 13:08:06 -070083 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
84 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
85 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
86 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
87 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
88 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
89
90 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
alshabib8f1cf4a2014-09-17 14:44:48 -070091 protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
tom7ef8ff92014-09-17 13:08:06 -070092
93 protected Multimap<Integer, PacketListener> ofPacketListener =
94 ArrayListMultimap.create();
95
alshabibeec3a062014-09-17 18:01:26 -070096 protected Set<OpenFlowEventListener> ofEventListener = Sets.newHashSet();
tom7ef8ff92014-09-17 13:08:06 -070097
sangho6a0bb172015-02-05 12:24:48 -080098 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
99 ArrayListMultimap.create();
100
101 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
102 ArrayListMultimap.create();
103
104 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800105 ArrayListMultimap.create();
106
tom7ef8ff92014-09-17 13:08:06 -0700107 private final Controller ctrl = new Controller();
108
109 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800110 public void activate(ComponentContext context) {
111 Map<String, String> properties = readComponentConfiguration(context);
112 ctrl.setConfigParams(properties);
tom7ef8ff92014-09-17 13:08:06 -0700113 ctrl.start(agent);
114 }
115
116 @Deactivate
117 public void deactivate() {
118 ctrl.stop();
119 }
120
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800121 /**
122 * Extracts properties from the component configuration context.
123 *
124 * @param context the component context
125 */
126 private Map<String, String> readComponentConfiguration(ComponentContext context) {
127 Dictionary<?, ?> properties = context.getProperties();
128 Map<String, String> outProperties = new HashMap<>();
129 try {
130 String strDpid = (String) properties.get("corsaDpid");
131 if (strDpid != null) {
132 outProperties.put("corsaDpid", strDpid);
133 }
134 } catch (ClassCastException e) {
135 return outProperties;
136 }
137 return outProperties;
138 }
139
140 @Modified
141 public void modified(ComponentContext context) {
142 // Blank @Modified method to catch modifications to the context.
143 // If no @Modified method exists, @Activate is called again
144 // when the context is modified.
145 }
146
tom7ef8ff92014-09-17 13:08:06 -0700147 @Override
148 public Iterable<OpenFlowSwitch> getSwitches() {
149 return connectedSwitches.values();
150 }
151
152 @Override
153 public Iterable<OpenFlowSwitch> getMasterSwitches() {
154 return activeMasterSwitches.values();
155 }
156
157 @Override
158 public Iterable<OpenFlowSwitch> getEqualSwitches() {
159 return activeEqualSwitches.values();
160 }
161
162 @Override
163 public OpenFlowSwitch getSwitch(Dpid dpid) {
164 return connectedSwitches.get(dpid);
165 }
166
167 @Override
168 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
169 return activeMasterSwitches.get(dpid);
170 }
171
172 @Override
173 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
174 return activeEqualSwitches.get(dpid);
175 }
176
177 @Override
178 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700179 if (!ofSwitchListener.contains(listener)) {
180 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700181 }
182 }
183
184 @Override
185 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700186 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700187 }
188
189 @Override
190 public void addPacketListener(int priority, PacketListener listener) {
191 ofPacketListener.put(priority, listener);
192 }
193
194 @Override
195 public void removePacketListener(PacketListener listener) {
196 ofPacketListener.values().remove(listener);
197 }
198
199 @Override
alshabibeec3a062014-09-17 18:01:26 -0700200 public void addEventListener(OpenFlowEventListener listener) {
201 ofEventListener.add(listener);
202 }
203
204 @Override
205 public void removeEventListener(OpenFlowEventListener listener) {
206 ofEventListener.remove(listener);
207 }
208
209 @Override
tom7ef8ff92014-09-17 13:08:06 -0700210 public void write(Dpid dpid, OFMessage msg) {
211 this.getSwitch(dpid).sendMsg(msg);
212 }
213
214 @Override
215 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800216 Collection<OFFlowStatsEntry> flowStats;
217 Collection<OFGroupStatsEntry> groupStats;
218 Collection<OFGroupDescStatsEntry> groupDescStats;
219
tom7ef8ff92014-09-17 13:08:06 -0700220 switch (msg.getType()) {
221 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700222 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700223 l.portChanged(dpid, (OFPortStatus) msg);
224 }
225 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700226 case FEATURES_REPLY:
227 for (OpenFlowSwitchListener l : ofSwitchListener) {
228 l.switchChanged(dpid);
229 }
230 break;
tom7ef8ff92014-09-17 13:08:06 -0700231 case PACKET_IN:
232 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
233 .packetContextFromPacketIn(this.getSwitch(dpid),
234 (OFPacketIn) msg);
235 for (PacketListener p : ofPacketListener.values()) {
236 p.handlePacket(pktCtx);
237 }
238 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800239 // TODO: Consider using separate threadpool for sensitive messages.
240 // ie. Back to back error could cause us to starve.
241 case FLOW_REMOVED:
242 case ERROR:
243 executorMsgs.submit(new OFMessageHandler(dpid, msg));
244 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700245 case STATS_REPLY:
246 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800247 switch (reply.getStatsType()) {
248 case PORT_DESC:
249 for (OpenFlowSwitchListener l : ofSwitchListener) {
250 l.switchChanged(dpid);
251 }
252 break;
253 case FLOW:
254 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
255 if (flowStats != null) {
256 OFFlowStatsReply.Builder rep =
257 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
258 rep.setEntries(Lists.newLinkedList(flowStats));
259 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
260 }
261 break;
262 case GROUP:
263 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
264 if (groupStats != null) {
265 OFGroupStatsReply.Builder rep =
266 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
267 rep.setEntries(Lists.newLinkedList(groupStats));
268 rep.setXid(reply.getXid());
269 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
270 }
271 break;
272 case GROUP_DESC:
273 groupDescStats = publishGroupDescStats(dpid,
274 (OFGroupDescStatsReply) reply);
275 if (groupDescStats != null) {
276 OFGroupDescStatsReply.Builder rep =
277 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
278 rep.setEntries(Lists.newLinkedList(groupDescStats));
279 rep.setXid(reply.getXid());
280 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
281 }
282 break;
283 default:
284 log.warn("Unsupported stats type : {}", reply.getStatsType());
alshabib64def642014-12-02 23:27:37 -0800285 }
286 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700287 case BARRIER_REPLY:
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800288 executorBarrier.submit(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700289 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700290 case EXPERIMENTER:
291 // Handle optical port stats
292 if (((OFExperimenter) msg).getExperimenter() == 0x748771) {
293 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
294 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
295 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
296 portDesc.setPortNo(circuitPortStatus.getPortNo())
297 .setHwAddr(circuitPortStatus.getHwAddr())
298 .setName(circuitPortStatus.getName())
299 .setConfig(circuitPortStatus.getConfig())
300 .setState(circuitPortStatus.getState());
301 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
302 for (OpenFlowSwitchListener l : ofSwitchListener) {
303 l.portChanged(dpid, portStatus.build());
304 }
305 } else {
306 log.warn("Handling experimenter type {} not yet implemented",
307 ((OFExperimenter) msg).getExperimenter(), msg);
308 }
309 break;
tom7ef8ff92014-09-17 13:08:06 -0700310 default:
311 log.warn("Handling message type {} not yet implemented {}",
312 msg.getType(), msg);
313 }
314 }
315
sangho6a0bb172015-02-05 12:24:48 -0800316 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
317 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800318 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800319 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800320 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800321 return fullFlowStats.removeAll(dpid);
322 }
323 return null;
324 }
325
326 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
327 OFGroupStatsReply reply) {
328 //TODO: Get rid of synchronized
329 fullGroupStats.putAll(dpid, reply.getEntries());
330 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
331 return fullGroupStats.removeAll(dpid);
332 }
333 return null;
334 }
335
336 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
337 OFGroupDescStatsReply reply) {
338 //TODO: Get rid of synchronized
339 fullGroupDescStats.putAll(dpid, reply.getEntries());
340 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
341 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800342 }
343 return null;
344 }
345
tom7ef8ff92014-09-17 13:08:06 -0700346 @Override
347 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700348 final OpenFlowSwitch sw = getSwitch(dpid);
349 if (sw == null) {
350 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
351 return;
352 }
353 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700354 }
355
356 /**
357 * Implementation of an OpenFlow Agent which is responsible for
358 * keeping track of connected switches and the state in which
359 * they are.
360 */
361 public class OpenFlowSwitchAgent implements OpenFlowAgent {
362
363 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
364 private final Lock switchLock = new ReentrantLock();
365
366 @Override
367 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700368
tom7ef8ff92014-09-17 13:08:06 -0700369 if (connectedSwitches.get(dpid) != null) {
370 log.error("Trying to add connectedSwitch but found a previous "
371 + "value for dpid: {}", dpid);
372 return false;
373 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700374 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700375 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700376 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700377 l.switchAdded(dpid);
378 }
379 return true;
380 }
381 }
382
383 @Override
384 public boolean validActivation(Dpid dpid) {
385 if (connectedSwitches.get(dpid) == null) {
386 log.error("Trying to activate switch but is not in "
387 + "connected switches: dpid {}. Aborting ..",
388 dpid);
389 return false;
390 }
391 if (activeMasterSwitches.get(dpid) != null ||
392 activeEqualSwitches.get(dpid) != null) {
393 log.error("Trying to activate switch but it is already "
394 + "activated: dpid {}. Found in activeMaster: {} "
395 + "Found in activeEqual: {}. Aborting ..", new Object[]{
396 dpid,
397 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
398 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
399 return false;
400 }
401 return true;
402 }
403
404
405 @Override
406 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
407 switchLock.lock();
408 try {
409 if (!validActivation(dpid)) {
410 return false;
411 }
412 activeMasterSwitches.put(dpid, sw);
413 return true;
414 } finally {
415 switchLock.unlock();
416 }
417 }
418
419 @Override
420 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
421 switchLock.lock();
422 try {
423 if (!validActivation(dpid)) {
424 return false;
425 }
426 activeEqualSwitches.put(dpid, sw);
427 log.info("Added Activated EQUAL Switch {}", dpid);
428 return true;
429 } finally {
430 switchLock.unlock();
431 }
432 }
433
434 @Override
435 public void transitionToMasterSwitch(Dpid dpid) {
436 switchLock.lock();
437 try {
438 if (activeMasterSwitches.containsKey(dpid)) {
439 return;
440 }
441 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
442 if (sw == null) {
443 sw = getSwitch(dpid);
444 if (sw == null) {
445 log.error("Transition to master called on sw {}, but switch "
446 + "was not found in controller-cache", dpid);
447 return;
448 }
449 }
450 log.info("Transitioned switch {} to MASTER", dpid);
451 activeMasterSwitches.put(dpid, sw);
452 } finally {
453 switchLock.unlock();
454 }
455 }
456
457
458 @Override
459 public void transitionToEqualSwitch(Dpid dpid) {
460 switchLock.lock();
461 try {
462 if (activeEqualSwitches.containsKey(dpid)) {
463 return;
464 }
465 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
466 if (sw == null) {
467 sw = getSwitch(dpid);
468 if (sw == null) {
469 log.error("Transition to equal called on sw {}, but switch "
470 + "was not found in controller-cache", dpid);
471 return;
472 }
473 }
474 log.info("Transitioned switch {} to EQUAL", dpid);
475 activeEqualSwitches.put(dpid, sw);
476 } finally {
477 switchLock.unlock();
478 }
479
480 }
481
482 @Override
483 public void removeConnectedSwitch(Dpid dpid) {
484 connectedSwitches.remove(dpid);
485 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
486 if (sw == null) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700487 log.warn("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700488 sw = activeEqualSwitches.remove(dpid);
489 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700490 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700491 log.warn("removal for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700492 l.switchRemoved(dpid);
493 }
494 }
495
496 @Override
497 public void processMessage(Dpid dpid, OFMessage m) {
498 processPacket(dpid, m);
499 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700500
501 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700502 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700503 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700504 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700505 }
506 }
tom7ef8ff92014-09-17 13:08:06 -0700507 }
508
alshabib8f1cf4a2014-09-17 14:44:48 -0700509 private final class OFMessageHandler implements Runnable {
510
511 private final OFMessage msg;
512 private final Dpid dpid;
513
514 public OFMessageHandler(Dpid dpid, OFMessage msg) {
515 this.msg = msg;
516 this.dpid = dpid;
517 }
518
519 @Override
520 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700521 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700522 listener.handleMessage(dpid, msg);
523 }
524 }
525
526 }
527
tom7ef8ff92014-09-17 13:08:06 -0700528}