blob: 4ef4d8187018bc1ef5e2b1cfb86f93de631fd28c [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
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;
tom7ef8ff92014-09-17 13:08:06 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080024import org.apache.felix.scr.annotations.Modified;
alshabibb452fd72015-04-22 20:46:20 -070025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
tom7ef8ff92014-09-17 13:08:06 -070027import org.apache.felix.scr.annotations.Service;
Thomas Vachuska3358af22015-05-19 18:40:34 -070028import org.onosproject.net.driver.DefaultDriverProviderService;
alshabibb452fd72015-04-22 20:46:20 -070029import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
31import org.onosproject.openflow.controller.Dpid;
32import org.onosproject.openflow.controller.OpenFlowController;
33import org.onosproject.openflow.controller.OpenFlowEventListener;
34import org.onosproject.openflow.controller.OpenFlowPacketContext;
35import org.onosproject.openflow.controller.OpenFlowSwitch;
36import org.onosproject.openflow.controller.OpenFlowSwitchListener;
37import org.onosproject.openflow.controller.PacketListener;
38import org.onosproject.openflow.controller.RoleState;
39import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080040import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070041import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
42import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070043import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
44import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080045import org.projectfloodlight.openflow.protocol.OFFactories;
46import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
47import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080048import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
49import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
50import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
51import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070052import org.projectfloodlight.openflow.protocol.OFMessage;
53import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070054import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070055import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
56import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070057import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070058import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080059import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Marc De Leenheerb9311372015-07-09 11:36:49 -070060import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
61import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080065import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070066import java.util.Collections;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080067import java.util.Dictionary;
68import java.util.HashMap;
Marc De Leenheerb9311372015-07-09 11:36:49 -070069import java.util.LinkedList;
70import java.util.List;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080071import java.util.Map;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080072import java.util.Set;
73import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070074import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080075import java.util.concurrent.ExecutorService;
76import java.util.concurrent.Executors;
77import java.util.concurrent.locks.Lock;
78import java.util.concurrent.locks.ReentrantLock;
79
80import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070081
82@Component(immediate = true)
83@Service
84public class OpenFlowControllerImpl implements OpenFlowController {
85
86 private static final Logger log =
87 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
88
alshabibb452fd72015-04-22 20:46:20 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected DriverService driverService;
91
Thomas Vachuska3358af22015-05-19 18:40:34 -070092 // References exists merely for sequencing purpose to assure drivers are loaded
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DefaultDriverProviderService defaultDriverProviderService;
95
Pavlin Radoslavov369c6432014-12-03 16:25:14 -080096 private final ExecutorService executorMsgs =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080097 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -080098
99 private final ExecutorService executorBarrier =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800100 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -0700101
tom7ef8ff92014-09-17 13:08:06 -0700102 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700103 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700104 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700105 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700106 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700107 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700108
109 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700110 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700111
112 protected Multimap<Integer, PacketListener> ofPacketListener =
113 ArrayListMultimap.create();
114
Jonathan Hart6d44d192015-05-11 18:01:19 -0700115 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700116
sangho6a0bb172015-02-05 12:24:48 -0800117 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
118 ArrayListMultimap.create();
119
120 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
121 ArrayListMultimap.create();
122
123 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800124 ArrayListMultimap.create();
125
sangho538108b2015-04-08 14:29:20 -0700126 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
127 ArrayListMultimap.create();
128
tom7ef8ff92014-09-17 13:08:06 -0700129 private final Controller ctrl = new Controller();
130
131 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800132 public void activate(ComponentContext context) {
133 Map<String, String> properties = readComponentConfiguration(context);
134 ctrl.setConfigParams(properties);
alshabibb452fd72015-04-22 20:46:20 -0700135 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700136 }
137
138 @Deactivate
139 public void deactivate() {
140 ctrl.stop();
141 }
142
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800143 /**
144 * Extracts properties from the component configuration context.
145 *
146 * @param context the component context
147 */
148 private Map<String, String> readComponentConfiguration(ComponentContext context) {
149 Dictionary<?, ?> properties = context.getProperties();
150 Map<String, String> outProperties = new HashMap<>();
151 try {
152 String strDpid = (String) properties.get("corsaDpid");
153 if (strDpid != null) {
154 outProperties.put("corsaDpid", strDpid);
155 }
156 } catch (ClassCastException e) {
157 return outProperties;
158 }
159 return outProperties;
160 }
161
162 @Modified
163 public void modified(ComponentContext context) {
164 // Blank @Modified method to catch modifications to the context.
165 // If no @Modified method exists, @Activate is called again
166 // when the context is modified.
167 }
168
tom7ef8ff92014-09-17 13:08:06 -0700169 @Override
170 public Iterable<OpenFlowSwitch> getSwitches() {
171 return connectedSwitches.values();
172 }
173
174 @Override
175 public Iterable<OpenFlowSwitch> getMasterSwitches() {
176 return activeMasterSwitches.values();
177 }
178
179 @Override
180 public Iterable<OpenFlowSwitch> getEqualSwitches() {
181 return activeEqualSwitches.values();
182 }
183
184 @Override
185 public OpenFlowSwitch getSwitch(Dpid dpid) {
186 return connectedSwitches.get(dpid);
187 }
188
189 @Override
190 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
191 return activeMasterSwitches.get(dpid);
192 }
193
194 @Override
195 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
196 return activeEqualSwitches.get(dpid);
197 }
198
199 @Override
200 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700201 if (!ofSwitchListener.contains(listener)) {
202 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700203 }
204 }
205
206 @Override
207 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700208 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700209 }
210
211 @Override
212 public void addPacketListener(int priority, PacketListener listener) {
213 ofPacketListener.put(priority, listener);
214 }
215
216 @Override
217 public void removePacketListener(PacketListener listener) {
218 ofPacketListener.values().remove(listener);
219 }
220
221 @Override
alshabibeec3a062014-09-17 18:01:26 -0700222 public void addEventListener(OpenFlowEventListener listener) {
223 ofEventListener.add(listener);
224 }
225
226 @Override
227 public void removeEventListener(OpenFlowEventListener listener) {
228 ofEventListener.remove(listener);
229 }
230
231 @Override
tom7ef8ff92014-09-17 13:08:06 -0700232 public void write(Dpid dpid, OFMessage msg) {
233 this.getSwitch(dpid).sendMsg(msg);
234 }
235
236 @Override
237 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800238 Collection<OFFlowStatsEntry> flowStats;
239 Collection<OFGroupStatsEntry> groupStats;
240 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700241 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800242
tom7ef8ff92014-09-17 13:08:06 -0700243 switch (msg.getType()) {
244 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700245 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700246 l.portChanged(dpid, (OFPortStatus) msg);
247 }
248 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700249 case FEATURES_REPLY:
250 for (OpenFlowSwitchListener l : ofSwitchListener) {
251 l.switchChanged(dpid);
252 }
253 break;
tom7ef8ff92014-09-17 13:08:06 -0700254 case PACKET_IN:
255 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
256 .packetContextFromPacketIn(this.getSwitch(dpid),
257 (OFPacketIn) msg);
258 for (PacketListener p : ofPacketListener.values()) {
259 p.handlePacket(pktCtx);
260 }
261 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800262 // TODO: Consider using separate threadpool for sensitive messages.
263 // ie. Back to back error could cause us to starve.
264 case FLOW_REMOVED:
265 case ERROR:
266 executorMsgs.submit(new OFMessageHandler(dpid, msg));
267 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700268 case STATS_REPLY:
269 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800270 switch (reply.getStatsType()) {
271 case PORT_DESC:
272 for (OpenFlowSwitchListener l : ofSwitchListener) {
273 l.switchChanged(dpid);
274 }
275 break;
276 case FLOW:
277 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
278 if (flowStats != null) {
279 OFFlowStatsReply.Builder rep =
280 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
281 rep.setEntries(Lists.newLinkedList(flowStats));
282 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
283 }
284 break;
285 case GROUP:
286 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
287 if (groupStats != null) {
288 OFGroupStatsReply.Builder rep =
289 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
290 rep.setEntries(Lists.newLinkedList(groupStats));
291 rep.setXid(reply.getXid());
292 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
293 }
294 break;
295 case GROUP_DESC:
296 groupDescStats = publishGroupDescStats(dpid,
297 (OFGroupDescStatsReply) reply);
298 if (groupDescStats != null) {
299 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700300 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800301 rep.setEntries(Lists.newLinkedList(groupDescStats));
302 rep.setXid(reply.getXid());
303 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
304 }
305 break;
sangho538108b2015-04-08 14:29:20 -0700306 case PORT:
307 executorMsgs.submit(new OFMessageHandler(dpid, reply));
308 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700309 case EXPERIMENTER:
310 if (reply instanceof OFCalientFlowStatsReply) {
311 // Convert Calient flow statistics to regular flow stats
312 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
313 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
314 List<OFFlowStatsEntry> entries = new LinkedList<>();
315 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
316
317 // Single instruction, i.e., output to port
318 OFActionOutput action = OFFactories
319 .getFactory(msg.getVersion())
320 .actions()
321 .buildOutput()
322 .setPort(entry.getOutPort())
323 .build();
324 OFInstruction instruction = OFFactories
325 .getFactory(msg.getVersion())
326 .instructions()
327 .applyActions(Collections.singletonList(action));
328 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
329 .setMatch(entry.getMatch())
330 .setTableId(entry.getTableId())
331 .setDurationSec(entry.getDurationSec())
332 .setDurationNsec(entry.getDurationNsec())
333 .setPriority(entry.getPriority())
334 .setIdleTimeout(entry.getIdleTimeout())
335 .setHardTimeout(entry.getHardTimeout())
336 .setFlags(entry.getFlags())
337 .setCookie(entry.getCookie())
338 .setInstructions(Collections.singletonList(instruction))
339 .build();
340 entries.add(fs);
341 }
342 fsr.setEntries(entries);
343
344 flowStats = publishFlowStats(dpid, fsr.build());
345 if (flowStats != null) {
346 OFFlowStatsReply.Builder rep =
347 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
348 rep.setEntries(Lists.newLinkedList(flowStats));
349 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
350 }
351 } else {
352 log.warn("Unsupported stats type : {}", reply.getStatsType());
353 }
354 break;
sangho6a0bb172015-02-05 12:24:48 -0800355 default:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700356 break;
alshabib64def642014-12-02 23:27:37 -0800357 }
358 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700359 case BARRIER_REPLY:
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800360 executorBarrier.submit(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700361 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700362 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700363 long experimenter = ((OFExperimenter) msg).getExperimenter();
364 if (experimenter == 0x748771) {
365 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700366 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
367 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
368 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
369 portDesc.setPortNo(circuitPortStatus.getPortNo())
370 .setHwAddr(circuitPortStatus.getHwAddr())
371 .setName(circuitPortStatus.getName())
372 .setConfig(circuitPortStatus.getConfig())
373 .setState(circuitPortStatus.getState());
374 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
375 for (OpenFlowSwitchListener l : ofSwitchListener) {
376 l.portChanged(dpid, portStatus.build());
377 }
378 } else {
379 log.warn("Handling experimenter type {} not yet implemented",
380 ((OFExperimenter) msg).getExperimenter(), msg);
381 }
382 break;
tom7ef8ff92014-09-17 13:08:06 -0700383 default:
384 log.warn("Handling message type {} not yet implemented {}",
385 msg.getType(), msg);
386 }
387 }
388
sangho6a0bb172015-02-05 12:24:48 -0800389 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
390 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800391 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800392 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800393 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800394 return fullFlowStats.removeAll(dpid);
395 }
396 return null;
397 }
398
399 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
400 OFGroupStatsReply reply) {
401 //TODO: Get rid of synchronized
402 fullGroupStats.putAll(dpid, reply.getEntries());
403 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
404 return fullGroupStats.removeAll(dpid);
405 }
406 return null;
407 }
408
409 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
410 OFGroupDescStatsReply reply) {
411 //TODO: Get rid of synchronized
412 fullGroupDescStats.putAll(dpid, reply.getEntries());
413 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
414 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800415 }
416 return null;
417 }
418
sangho538108b2015-04-08 14:29:20 -0700419 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
420 OFPortStatsReply reply) {
421 fullPortStats.putAll(dpid, reply.getEntries());
422 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
423 return fullPortStats.removeAll(dpid);
424 }
425 return null;
426 }
427
tom7ef8ff92014-09-17 13:08:06 -0700428 @Override
429 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700430 final OpenFlowSwitch sw = getSwitch(dpid);
431 if (sw == null) {
432 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
433 return;
434 }
435 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700436 }
437
438 /**
439 * Implementation of an OpenFlow Agent which is responsible for
440 * keeping track of connected switches and the state in which
441 * they are.
442 */
443 public class OpenFlowSwitchAgent implements OpenFlowAgent {
444
445 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
446 private final Lock switchLock = new ReentrantLock();
447
448 @Override
449 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700450
tom7ef8ff92014-09-17 13:08:06 -0700451 if (connectedSwitches.get(dpid) != null) {
452 log.error("Trying to add connectedSwitch but found a previous "
453 + "value for dpid: {}", dpid);
454 return false;
455 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700456 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700457 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700458 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700459 l.switchAdded(dpid);
460 }
461 return true;
462 }
463 }
464
465 @Override
466 public boolean validActivation(Dpid dpid) {
467 if (connectedSwitches.get(dpid) == null) {
468 log.error("Trying to activate switch but is not in "
469 + "connected switches: dpid {}. Aborting ..",
470 dpid);
471 return false;
472 }
473 if (activeMasterSwitches.get(dpid) != null ||
474 activeEqualSwitches.get(dpid) != null) {
475 log.error("Trying to activate switch but it is already "
476 + "activated: dpid {}. Found in activeMaster: {} "
477 + "Found in activeEqual: {}. Aborting ..", new Object[]{
478 dpid,
479 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
480 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
481 return false;
482 }
483 return true;
484 }
485
486
487 @Override
488 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
489 switchLock.lock();
490 try {
491 if (!validActivation(dpid)) {
492 return false;
493 }
494 activeMasterSwitches.put(dpid, sw);
495 return true;
496 } finally {
497 switchLock.unlock();
498 }
499 }
500
501 @Override
502 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
503 switchLock.lock();
504 try {
505 if (!validActivation(dpid)) {
506 return false;
507 }
508 activeEqualSwitches.put(dpid, sw);
509 log.info("Added Activated EQUAL Switch {}", dpid);
510 return true;
511 } finally {
512 switchLock.unlock();
513 }
514 }
515
516 @Override
517 public void transitionToMasterSwitch(Dpid dpid) {
518 switchLock.lock();
519 try {
520 if (activeMasterSwitches.containsKey(dpid)) {
521 return;
522 }
523 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
524 if (sw == null) {
525 sw = getSwitch(dpid);
526 if (sw == null) {
527 log.error("Transition to master called on sw {}, but switch "
528 + "was not found in controller-cache", dpid);
529 return;
530 }
531 }
532 log.info("Transitioned switch {} to MASTER", dpid);
533 activeMasterSwitches.put(dpid, sw);
534 } finally {
535 switchLock.unlock();
536 }
537 }
538
539
540 @Override
541 public void transitionToEqualSwitch(Dpid dpid) {
542 switchLock.lock();
543 try {
544 if (activeEqualSwitches.containsKey(dpid)) {
545 return;
546 }
547 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
548 if (sw == null) {
549 sw = getSwitch(dpid);
550 if (sw == null) {
551 log.error("Transition to equal called on sw {}, but switch "
552 + "was not found in controller-cache", dpid);
553 return;
554 }
555 }
556 log.info("Transitioned switch {} to EQUAL", dpid);
557 activeEqualSwitches.put(dpid, sw);
558 } finally {
559 switchLock.unlock();
560 }
561
562 }
563
564 @Override
565 public void removeConnectedSwitch(Dpid dpid) {
566 connectedSwitches.remove(dpid);
567 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
568 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700569 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700570 sw = activeEqualSwitches.remove(dpid);
571 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700572 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700573 l.switchRemoved(dpid);
574 }
575 }
576
577 @Override
578 public void processMessage(Dpid dpid, OFMessage m) {
579 processPacket(dpid, m);
580 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700581
582 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700583 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700584 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700585 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700586 }
587 }
tom7ef8ff92014-09-17 13:08:06 -0700588 }
589
alshabib8f1cf4a2014-09-17 14:44:48 -0700590 private final class OFMessageHandler implements Runnable {
591
592 private final OFMessage msg;
593 private final Dpid dpid;
594
595 public OFMessageHandler(Dpid dpid, OFMessage msg) {
596 this.msg = msg;
597 this.dpid = dpid;
598 }
599
600 @Override
601 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700602 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700603 listener.handleMessage(dpid, msg);
604 }
605 }
606
607 }
608
tom7ef8ff92014-09-17 13:08:06 -0700609}