blob: cff8cdce139eb2d5d399fac460ffb21a8e3d57e1 [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;
Charles Chan3b00e1b2015-08-26 23:12:52 +080025import org.apache.felix.scr.annotations.Property;
alshabibb452fd72015-04-22 20:46:20 -070026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
tom7ef8ff92014-09-17 13:08:06 -070028import org.apache.felix.scr.annotations.Service;
Charles Chan3b00e1b2015-08-26 23:12:52 +080029import org.onosproject.cfg.ComponentConfigService;
Thomas Vachuska3358af22015-05-19 18:40:34 -070030import org.onosproject.net.driver.DefaultDriverProviderService;
alshabibb452fd72015-04-22 20:46:20 -070031import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
33import org.onosproject.openflow.controller.Dpid;
34import org.onosproject.openflow.controller.OpenFlowController;
35import org.onosproject.openflow.controller.OpenFlowEventListener;
36import org.onosproject.openflow.controller.OpenFlowPacketContext;
37import org.onosproject.openflow.controller.OpenFlowSwitch;
38import org.onosproject.openflow.controller.OpenFlowSwitchListener;
39import org.onosproject.openflow.controller.PacketListener;
40import org.onosproject.openflow.controller.RoleState;
41import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080042import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070043import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
44import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070045import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
46import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080047import org.projectfloodlight.openflow.protocol.OFFactories;
48import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
49import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080050import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
51import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
52import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
53import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070054import org.projectfloodlight.openflow.protocol.OFMessage;
55import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070056import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070057import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
58import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070059import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070060import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080061import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Marc De Leenheerb9311372015-07-09 11:36:49 -070062import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
63import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080067import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070068import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070069import java.util.LinkedList;
70import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080071import java.util.Set;
72import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070073import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080074import java.util.concurrent.ExecutorService;
75import java.util.concurrent.Executors;
76import java.util.concurrent.locks.Lock;
77import java.util.concurrent.locks.ReentrantLock;
78
79import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070080
81@Component(immediate = true)
82@Service
83public class OpenFlowControllerImpl implements OpenFlowController {
Brian O'Connorff278502015-09-22 14:49:52 -070084 private static final String DEFAULT_OFPORT = "6633,6653";
Charles Chan3b00e1b2015-08-26 23:12:52 +080085 private static final int DEFAULT_WORKER_THREADS = 16;
tom7ef8ff92014-09-17 13:08:06 -070086
87 private static final Logger log =
88 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
89
alshabibb452fd72015-04-22 20:46:20 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DriverService driverService;
92
Thomas Vachuska3358af22015-05-19 18:40:34 -070093 // References exists merely for sequencing purpose to assure drivers are loaded
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DefaultDriverProviderService defaultDriverProviderService;
96
Charles Chan3b00e1b2015-08-26 23:12:52 +080097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected ComponentConfigService cfgService;
99
Brian O'Connorff278502015-09-22 14:49:52 -0700100 @Property(name = "openflowPort", value = DEFAULT_OFPORT,
Charles Chan45624b82015-08-24 00:29:20 +0800101 label = "Port number used by OpenFlow protocol; default is 6653")
Brian O'Connorff278502015-09-22 14:49:52 -0700102 private String openflowPort = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800103
104 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
105 label = "Number of controller worker threads; default is 16")
106 private int workerThreads = DEFAULT_WORKER_THREADS;
107
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800108 private final ExecutorService executorMsgs =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800109 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800110
111 private final ExecutorService executorBarrier =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800112 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -0700113
tom7ef8ff92014-09-17 13:08:06 -0700114 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700115 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700116 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700117 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700118 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700119 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700120
121 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700122 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700123
124 protected Multimap<Integer, PacketListener> ofPacketListener =
125 ArrayListMultimap.create();
126
Jonathan Hart6d44d192015-05-11 18:01:19 -0700127 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700128
sangho6a0bb172015-02-05 12:24:48 -0800129 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
130 ArrayListMultimap.create();
131
132 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
133 ArrayListMultimap.create();
134
135 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800136 ArrayListMultimap.create();
137
sangho538108b2015-04-08 14:29:20 -0700138 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
139 ArrayListMultimap.create();
140
tom7ef8ff92014-09-17 13:08:06 -0700141 private final Controller ctrl = new Controller();
142
143 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800144 public void activate(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800145 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700146 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700147 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700148 }
149
150 @Deactivate
151 public void deactivate() {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800152 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700153 ctrl.stop();
154 }
155
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800156 @Modified
157 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800158 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700159 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800160 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800161 }
162
tom7ef8ff92014-09-17 13:08:06 -0700163 @Override
164 public Iterable<OpenFlowSwitch> getSwitches() {
165 return connectedSwitches.values();
166 }
167
168 @Override
169 public Iterable<OpenFlowSwitch> getMasterSwitches() {
170 return activeMasterSwitches.values();
171 }
172
173 @Override
174 public Iterable<OpenFlowSwitch> getEqualSwitches() {
175 return activeEqualSwitches.values();
176 }
177
178 @Override
179 public OpenFlowSwitch getSwitch(Dpid dpid) {
180 return connectedSwitches.get(dpid);
181 }
182
183 @Override
184 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
185 return activeMasterSwitches.get(dpid);
186 }
187
188 @Override
189 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
190 return activeEqualSwitches.get(dpid);
191 }
192
193 @Override
194 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700195 if (!ofSwitchListener.contains(listener)) {
196 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700197 }
198 }
199
200 @Override
201 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700202 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700203 }
204
205 @Override
206 public void addPacketListener(int priority, PacketListener listener) {
207 ofPacketListener.put(priority, listener);
208 }
209
210 @Override
211 public void removePacketListener(PacketListener listener) {
212 ofPacketListener.values().remove(listener);
213 }
214
215 @Override
alshabibeec3a062014-09-17 18:01:26 -0700216 public void addEventListener(OpenFlowEventListener listener) {
217 ofEventListener.add(listener);
218 }
219
220 @Override
221 public void removeEventListener(OpenFlowEventListener listener) {
222 ofEventListener.remove(listener);
223 }
224
225 @Override
tom7ef8ff92014-09-17 13:08:06 -0700226 public void write(Dpid dpid, OFMessage msg) {
227 this.getSwitch(dpid).sendMsg(msg);
228 }
229
230 @Override
231 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800232 Collection<OFFlowStatsEntry> flowStats;
233 Collection<OFGroupStatsEntry> groupStats;
234 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700235 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800236
tom7ef8ff92014-09-17 13:08:06 -0700237 switch (msg.getType()) {
238 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700239 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700240 l.portChanged(dpid, (OFPortStatus) msg);
241 }
242 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700243 case FEATURES_REPLY:
244 for (OpenFlowSwitchListener l : ofSwitchListener) {
245 l.switchChanged(dpid);
246 }
247 break;
tom7ef8ff92014-09-17 13:08:06 -0700248 case PACKET_IN:
249 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
250 .packetContextFromPacketIn(this.getSwitch(dpid),
251 (OFPacketIn) msg);
252 for (PacketListener p : ofPacketListener.values()) {
253 p.handlePacket(pktCtx);
254 }
255 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800256 // TODO: Consider using separate threadpool for sensitive messages.
257 // ie. Back to back error could cause us to starve.
258 case FLOW_REMOVED:
259 case ERROR:
260 executorMsgs.submit(new OFMessageHandler(dpid, msg));
261 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700262 case STATS_REPLY:
263 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800264 switch (reply.getStatsType()) {
265 case PORT_DESC:
266 for (OpenFlowSwitchListener l : ofSwitchListener) {
267 l.switchChanged(dpid);
268 }
269 break;
270 case FLOW:
271 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
272 if (flowStats != null) {
273 OFFlowStatsReply.Builder rep =
274 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
275 rep.setEntries(Lists.newLinkedList(flowStats));
276 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
277 }
278 break;
279 case GROUP:
280 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
281 if (groupStats != null) {
282 OFGroupStatsReply.Builder rep =
283 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
284 rep.setEntries(Lists.newLinkedList(groupStats));
285 rep.setXid(reply.getXid());
286 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
287 }
288 break;
289 case GROUP_DESC:
290 groupDescStats = publishGroupDescStats(dpid,
291 (OFGroupDescStatsReply) reply);
292 if (groupDescStats != null) {
293 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700294 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800295 rep.setEntries(Lists.newLinkedList(groupDescStats));
296 rep.setXid(reply.getXid());
297 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
298 }
299 break;
sangho538108b2015-04-08 14:29:20 -0700300 case PORT:
301 executorMsgs.submit(new OFMessageHandler(dpid, reply));
302 break;
alshabib5eb79392015-08-19 18:09:55 -0700303 case METER:
304 executorMsgs.submit(new OFMessageHandler(dpid, reply));
305 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700306 case EXPERIMENTER:
307 if (reply instanceof OFCalientFlowStatsReply) {
308 // Convert Calient flow statistics to regular flow stats
309 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
310 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
311 List<OFFlowStatsEntry> entries = new LinkedList<>();
312 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
313
314 // Single instruction, i.e., output to port
315 OFActionOutput action = OFFactories
316 .getFactory(msg.getVersion())
317 .actions()
318 .buildOutput()
319 .setPort(entry.getOutPort())
320 .build();
321 OFInstruction instruction = OFFactories
322 .getFactory(msg.getVersion())
323 .instructions()
324 .applyActions(Collections.singletonList(action));
325 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
326 .setMatch(entry.getMatch())
327 .setTableId(entry.getTableId())
328 .setDurationSec(entry.getDurationSec())
329 .setDurationNsec(entry.getDurationNsec())
330 .setPriority(entry.getPriority())
331 .setIdleTimeout(entry.getIdleTimeout())
332 .setHardTimeout(entry.getHardTimeout())
333 .setFlags(entry.getFlags())
334 .setCookie(entry.getCookie())
335 .setInstructions(Collections.singletonList(instruction))
336 .build();
337 entries.add(fs);
338 }
339 fsr.setEntries(entries);
340
341 flowStats = publishFlowStats(dpid, fsr.build());
342 if (flowStats != null) {
343 OFFlowStatsReply.Builder rep =
344 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
345 rep.setEntries(Lists.newLinkedList(flowStats));
346 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
347 }
348 } else {
Michael Bunimovich1b45e1f2015-08-27 07:49:25 -0400349 executorMsgs.submit(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700350 }
351 break;
sangho6a0bb172015-02-05 12:24:48 -0800352 default:
alshabib5eb79392015-08-19 18:09:55 -0700353 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700354 break;
alshabib64def642014-12-02 23:27:37 -0800355 }
356 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700357 case BARRIER_REPLY:
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800358 executorBarrier.submit(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700359 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700360 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700361 long experimenter = ((OFExperimenter) msg).getExperimenter();
362 if (experimenter == 0x748771) {
363 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700364 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
365 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
366 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
367 portDesc.setPortNo(circuitPortStatus.getPortNo())
368 .setHwAddr(circuitPortStatus.getHwAddr())
369 .setName(circuitPortStatus.getName())
370 .setConfig(circuitPortStatus.getConfig())
371 .setState(circuitPortStatus.getState());
372 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
373 for (OpenFlowSwitchListener l : ofSwitchListener) {
374 l.portChanged(dpid, portStatus.build());
375 }
376 } else {
377 log.warn("Handling experimenter type {} not yet implemented",
378 ((OFExperimenter) msg).getExperimenter(), msg);
379 }
380 break;
tom7ef8ff92014-09-17 13:08:06 -0700381 default:
382 log.warn("Handling message type {} not yet implemented {}",
383 msg.getType(), msg);
384 }
385 }
386
sangho6a0bb172015-02-05 12:24:48 -0800387 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
388 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800389 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800390 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800391 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800392 return fullFlowStats.removeAll(dpid);
393 }
394 return null;
395 }
396
397 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
398 OFGroupStatsReply reply) {
399 //TODO: Get rid of synchronized
400 fullGroupStats.putAll(dpid, reply.getEntries());
401 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
402 return fullGroupStats.removeAll(dpid);
403 }
404 return null;
405 }
406
407 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
408 OFGroupDescStatsReply reply) {
409 //TODO: Get rid of synchronized
410 fullGroupDescStats.putAll(dpid, reply.getEntries());
411 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
412 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800413 }
414 return null;
415 }
416
sangho538108b2015-04-08 14:29:20 -0700417 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
418 OFPortStatsReply reply) {
419 fullPortStats.putAll(dpid, reply.getEntries());
420 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
421 return fullPortStats.removeAll(dpid);
422 }
423 return null;
424 }
425
tom7ef8ff92014-09-17 13:08:06 -0700426 @Override
427 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700428 final OpenFlowSwitch sw = getSwitch(dpid);
429 if (sw == null) {
430 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
431 return;
432 }
433 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700434 }
435
436 /**
437 * Implementation of an OpenFlow Agent which is responsible for
438 * keeping track of connected switches and the state in which
439 * they are.
440 */
441 public class OpenFlowSwitchAgent implements OpenFlowAgent {
442
443 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
444 private final Lock switchLock = new ReentrantLock();
445
446 @Override
447 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700448
tom7ef8ff92014-09-17 13:08:06 -0700449 if (connectedSwitches.get(dpid) != null) {
450 log.error("Trying to add connectedSwitch but found a previous "
451 + "value for dpid: {}", dpid);
452 return false;
453 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700454 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700455 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700456 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700457 l.switchAdded(dpid);
458 }
459 return true;
460 }
461 }
462
463 @Override
464 public boolean validActivation(Dpid dpid) {
465 if (connectedSwitches.get(dpid) == null) {
466 log.error("Trying to activate switch but is not in "
467 + "connected switches: dpid {}. Aborting ..",
468 dpid);
469 return false;
470 }
471 if (activeMasterSwitches.get(dpid) != null ||
472 activeEqualSwitches.get(dpid) != null) {
473 log.error("Trying to activate switch but it is already "
474 + "activated: dpid {}. Found in activeMaster: {} "
475 + "Found in activeEqual: {}. Aborting ..", new Object[]{
476 dpid,
477 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
478 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
479 return false;
480 }
481 return true;
482 }
483
484
485 @Override
486 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
487 switchLock.lock();
488 try {
489 if (!validActivation(dpid)) {
490 return false;
491 }
492 activeMasterSwitches.put(dpid, sw);
493 return true;
494 } finally {
495 switchLock.unlock();
496 }
497 }
498
499 @Override
500 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
501 switchLock.lock();
502 try {
503 if (!validActivation(dpid)) {
504 return false;
505 }
506 activeEqualSwitches.put(dpid, sw);
507 log.info("Added Activated EQUAL Switch {}", dpid);
508 return true;
509 } finally {
510 switchLock.unlock();
511 }
512 }
513
514 @Override
515 public void transitionToMasterSwitch(Dpid dpid) {
516 switchLock.lock();
517 try {
518 if (activeMasterSwitches.containsKey(dpid)) {
519 return;
520 }
521 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
522 if (sw == null) {
523 sw = getSwitch(dpid);
524 if (sw == null) {
525 log.error("Transition to master called on sw {}, but switch "
526 + "was not found in controller-cache", dpid);
527 return;
528 }
529 }
530 log.info("Transitioned switch {} to MASTER", dpid);
531 activeMasterSwitches.put(dpid, sw);
532 } finally {
533 switchLock.unlock();
534 }
535 }
536
537
538 @Override
539 public void transitionToEqualSwitch(Dpid dpid) {
540 switchLock.lock();
541 try {
542 if (activeEqualSwitches.containsKey(dpid)) {
543 return;
544 }
545 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
546 if (sw == null) {
547 sw = getSwitch(dpid);
548 if (sw == null) {
549 log.error("Transition to equal called on sw {}, but switch "
550 + "was not found in controller-cache", dpid);
551 return;
552 }
553 }
554 log.info("Transitioned switch {} to EQUAL", dpid);
555 activeEqualSwitches.put(dpid, sw);
556 } finally {
557 switchLock.unlock();
558 }
559
560 }
561
562 @Override
563 public void removeConnectedSwitch(Dpid dpid) {
564 connectedSwitches.remove(dpid);
565 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
566 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700567 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700568 sw = activeEqualSwitches.remove(dpid);
569 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700570 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700571 l.switchRemoved(dpid);
572 }
573 }
574
575 @Override
576 public void processMessage(Dpid dpid, OFMessage m) {
577 processPacket(dpid, m);
578 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700579
580 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700581 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700582 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700583 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700584 }
585 }
tom7ef8ff92014-09-17 13:08:06 -0700586 }
587
alshabib8f1cf4a2014-09-17 14:44:48 -0700588 private final class OFMessageHandler implements Runnable {
589
590 private final OFMessage msg;
591 private final Dpid dpid;
592
593 public OFMessageHandler(Dpid dpid, OFMessage msg) {
594 this.msg = msg;
595 this.dpid = dpid;
596 }
597
598 @Override
599 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700600 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700601 listener.handleMessage(dpid, msg);
602 }
603 }
604
605 }
606
tom7ef8ff92014-09-17 13:08:06 -0700607}