blob: b97c336284d6047e8a321e36139a60f84d95bf29 [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;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070050import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
51import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080052import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
53import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
54import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
55import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070056import org.projectfloodlight.openflow.protocol.OFMessage;
57import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070058import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070059import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
60import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070061import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070062import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080063import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Marc De Leenheerb9311372015-07-09 11:36:49 -070064import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
65import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080069import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070070import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070071import java.util.LinkedList;
72import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080073import java.util.Set;
74import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070075import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080076import java.util.concurrent.ExecutorService;
77import java.util.concurrent.Executors;
78import java.util.concurrent.locks.Lock;
79import java.util.concurrent.locks.ReentrantLock;
80
81import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070082
83@Component(immediate = true)
84@Service
85public class OpenFlowControllerImpl implements OpenFlowController {
Brian O'Connorff278502015-09-22 14:49:52 -070086 private static final String DEFAULT_OFPORT = "6633,6653";
Charles Chan3b00e1b2015-08-26 23:12:52 +080087 private static final int DEFAULT_WORKER_THREADS = 16;
tom7ef8ff92014-09-17 13:08:06 -070088
89 private static final Logger log =
90 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
91
alshabibb452fd72015-04-22 20:46:20 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DriverService driverService;
94
Thomas Vachuska3358af22015-05-19 18:40:34 -070095 // References exists merely for sequencing purpose to assure drivers are loaded
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected DefaultDriverProviderService defaultDriverProviderService;
98
Charles Chan3b00e1b2015-08-26 23:12:52 +080099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected ComponentConfigService cfgService;
101
Brian O'Connore2a399e2015-09-22 15:32:50 -0700102 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
103 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
104 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800105
106 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
107 label = "Number of controller worker threads; default is 16")
108 private int workerThreads = DEFAULT_WORKER_THREADS;
109
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800110 protected ExecutorService executorMsgs =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800111 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800112
113 private final ExecutorService executorBarrier =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800114 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -0700115
tom7ef8ff92014-09-17 13:08:06 -0700116 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700117 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700118 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700119 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700120 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700121 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700122
123 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700124 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700125
126 protected Multimap<Integer, PacketListener> ofPacketListener =
127 ArrayListMultimap.create();
128
Jonathan Hart6d44d192015-05-11 18:01:19 -0700129 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700130
sangho6a0bb172015-02-05 12:24:48 -0800131 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
132 ArrayListMultimap.create();
133
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700134 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
135 ArrayListMultimap.create();
136
sangho6a0bb172015-02-05 12:24:48 -0800137 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
138 ArrayListMultimap.create();
139
140 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800141 ArrayListMultimap.create();
142
sangho538108b2015-04-08 14:29:20 -0700143 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
144 ArrayListMultimap.create();
145
tom7ef8ff92014-09-17 13:08:06 -0700146 private final Controller ctrl = new Controller();
147
148 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800149 public void activate(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800150 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700151 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700152 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700153 }
154
155 @Deactivate
156 public void deactivate() {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800157 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700158 ctrl.stop();
159 }
160
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800161 @Modified
162 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800163 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700164 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800165 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800166 }
167
tom7ef8ff92014-09-17 13:08:06 -0700168 @Override
169 public Iterable<OpenFlowSwitch> getSwitches() {
170 return connectedSwitches.values();
171 }
172
173 @Override
174 public Iterable<OpenFlowSwitch> getMasterSwitches() {
175 return activeMasterSwitches.values();
176 }
177
178 @Override
179 public Iterable<OpenFlowSwitch> getEqualSwitches() {
180 return activeEqualSwitches.values();
181 }
182
183 @Override
184 public OpenFlowSwitch getSwitch(Dpid dpid) {
185 return connectedSwitches.get(dpid);
186 }
187
188 @Override
189 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
190 return activeMasterSwitches.get(dpid);
191 }
192
193 @Override
194 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
195 return activeEqualSwitches.get(dpid);
196 }
197
198 @Override
199 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700200 if (!ofSwitchListener.contains(listener)) {
201 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700202 }
203 }
204
205 @Override
206 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700207 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700208 }
209
210 @Override
211 public void addPacketListener(int priority, PacketListener listener) {
212 ofPacketListener.put(priority, listener);
213 }
214
215 @Override
216 public void removePacketListener(PacketListener listener) {
217 ofPacketListener.values().remove(listener);
218 }
219
220 @Override
alshabibeec3a062014-09-17 18:01:26 -0700221 public void addEventListener(OpenFlowEventListener listener) {
222 ofEventListener.add(listener);
223 }
224
225 @Override
226 public void removeEventListener(OpenFlowEventListener listener) {
227 ofEventListener.remove(listener);
228 }
229
230 @Override
tom7ef8ff92014-09-17 13:08:06 -0700231 public void write(Dpid dpid, OFMessage msg) {
232 this.getSwitch(dpid).sendMsg(msg);
233 }
234
235 @Override
236 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800237 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700238 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800239 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));
ssyoon9030fbcd92015-08-17 10:42:07 +0900282 rep.setXid(reply.getXid());
sangho6a0bb172015-02-05 12:24:48 -0800283 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
284 }
285 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700286 case TABLE:
287 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
288 if (tableStats != null) {
289 OFTableStatsReply.Builder rep =
290 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
291 rep.setEntries(Lists.newLinkedList(tableStats));
292 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
293 }
294 break;
sangho6a0bb172015-02-05 12:24:48 -0800295 case GROUP:
296 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
297 if (groupStats != null) {
298 OFGroupStatsReply.Builder rep =
299 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
300 rep.setEntries(Lists.newLinkedList(groupStats));
301 rep.setXid(reply.getXid());
302 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
303 }
304 break;
305 case GROUP_DESC:
306 groupDescStats = publishGroupDescStats(dpid,
307 (OFGroupDescStatsReply) reply);
308 if (groupDescStats != null) {
309 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700310 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800311 rep.setEntries(Lists.newLinkedList(groupDescStats));
312 rep.setXid(reply.getXid());
313 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
314 }
315 break;
sangho538108b2015-04-08 14:29:20 -0700316 case PORT:
317 executorMsgs.submit(new OFMessageHandler(dpid, reply));
318 break;
alshabib5eb79392015-08-19 18:09:55 -0700319 case METER:
320 executorMsgs.submit(new OFMessageHandler(dpid, reply));
321 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700322 case EXPERIMENTER:
323 if (reply instanceof OFCalientFlowStatsReply) {
324 // Convert Calient flow statistics to regular flow stats
325 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
326 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
327 List<OFFlowStatsEntry> entries = new LinkedList<>();
328 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
329
330 // Single instruction, i.e., output to port
331 OFActionOutput action = OFFactories
332 .getFactory(msg.getVersion())
333 .actions()
334 .buildOutput()
335 .setPort(entry.getOutPort())
336 .build();
337 OFInstruction instruction = OFFactories
338 .getFactory(msg.getVersion())
339 .instructions()
340 .applyActions(Collections.singletonList(action));
341 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
342 .setMatch(entry.getMatch())
343 .setTableId(entry.getTableId())
344 .setDurationSec(entry.getDurationSec())
345 .setDurationNsec(entry.getDurationNsec())
346 .setPriority(entry.getPriority())
347 .setIdleTimeout(entry.getIdleTimeout())
348 .setHardTimeout(entry.getHardTimeout())
349 .setFlags(entry.getFlags())
350 .setCookie(entry.getCookie())
351 .setInstructions(Collections.singletonList(instruction))
352 .build();
353 entries.add(fs);
354 }
355 fsr.setEntries(entries);
356
357 flowStats = publishFlowStats(dpid, fsr.build());
358 if (flowStats != null) {
359 OFFlowStatsReply.Builder rep =
360 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
361 rep.setEntries(Lists.newLinkedList(flowStats));
362 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
363 }
364 } else {
Michael Bunimovich1b45e1f2015-08-27 07:49:25 -0400365 executorMsgs.submit(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700366 }
367 break;
sangho6a0bb172015-02-05 12:24:48 -0800368 default:
alshabib5eb79392015-08-19 18:09:55 -0700369 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700370 break;
alshabib64def642014-12-02 23:27:37 -0800371 }
372 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700373 case BARRIER_REPLY:
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800374 executorBarrier.submit(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700375 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700376 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700377 long experimenter = ((OFExperimenter) msg).getExperimenter();
378 if (experimenter == 0x748771) {
379 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700380 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
381 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
382 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
383 portDesc.setPortNo(circuitPortStatus.getPortNo())
384 .setHwAddr(circuitPortStatus.getHwAddr())
385 .setName(circuitPortStatus.getName())
386 .setConfig(circuitPortStatus.getConfig())
387 .setState(circuitPortStatus.getState());
388 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
389 for (OpenFlowSwitchListener l : ofSwitchListener) {
390 l.portChanged(dpid, portStatus.build());
391 }
392 } else {
393 log.warn("Handling experimenter type {} not yet implemented",
394 ((OFExperimenter) msg).getExperimenter(), msg);
395 }
396 break;
tom7ef8ff92014-09-17 13:08:06 -0700397 default:
398 log.warn("Handling message type {} not yet implemented {}",
399 msg.getType(), msg);
400 }
401 }
402
sangho6a0bb172015-02-05 12:24:48 -0800403 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
404 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800405 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800406 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800407 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800408 return fullFlowStats.removeAll(dpid);
409 }
410 return null;
411 }
412
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700413 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
414 OFTableStatsReply reply) {
415 //TODO: Get rid of synchronized
416 fullTableStats.putAll(dpid, reply.getEntries());
417 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
418 return fullTableStats.removeAll(dpid);
419 }
420 return null;
421 }
422
sangho6a0bb172015-02-05 12:24:48 -0800423 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
424 OFGroupStatsReply reply) {
425 //TODO: Get rid of synchronized
426 fullGroupStats.putAll(dpid, reply.getEntries());
427 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
428 return fullGroupStats.removeAll(dpid);
429 }
430 return null;
431 }
432
433 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
434 OFGroupDescStatsReply reply) {
435 //TODO: Get rid of synchronized
436 fullGroupDescStats.putAll(dpid, reply.getEntries());
437 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
438 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800439 }
440 return null;
441 }
442
sangho538108b2015-04-08 14:29:20 -0700443 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
444 OFPortStatsReply reply) {
445 fullPortStats.putAll(dpid, reply.getEntries());
446 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
447 return fullPortStats.removeAll(dpid);
448 }
449 return null;
450 }
451
tom7ef8ff92014-09-17 13:08:06 -0700452 @Override
453 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700454 final OpenFlowSwitch sw = getSwitch(dpid);
455 if (sw == null) {
456 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
457 return;
458 }
459 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700460 }
461
462 /**
463 * Implementation of an OpenFlow Agent which is responsible for
464 * keeping track of connected switches and the state in which
465 * they are.
466 */
467 public class OpenFlowSwitchAgent implements OpenFlowAgent {
468
469 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
470 private final Lock switchLock = new ReentrantLock();
471
472 @Override
473 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700474
tom7ef8ff92014-09-17 13:08:06 -0700475 if (connectedSwitches.get(dpid) != null) {
476 log.error("Trying to add connectedSwitch but found a previous "
477 + "value for dpid: {}", dpid);
478 return false;
479 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700480 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700481 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700482 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700483 l.switchAdded(dpid);
484 }
485 return true;
486 }
487 }
488
489 @Override
490 public boolean validActivation(Dpid dpid) {
491 if (connectedSwitches.get(dpid) == null) {
492 log.error("Trying to activate switch but is not in "
493 + "connected switches: dpid {}. Aborting ..",
494 dpid);
495 return false;
496 }
497 if (activeMasterSwitches.get(dpid) != null ||
498 activeEqualSwitches.get(dpid) != null) {
499 log.error("Trying to activate switch but it is already "
500 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800501 + "Found in activeEqual: {}. Aborting ..",
502 dpid,
503 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
504 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700505 return false;
506 }
507 return true;
508 }
509
510
511 @Override
512 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
513 switchLock.lock();
514 try {
515 if (!validActivation(dpid)) {
516 return false;
517 }
518 activeMasterSwitches.put(dpid, sw);
519 return true;
520 } finally {
521 switchLock.unlock();
522 }
523 }
524
525 @Override
526 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
527 switchLock.lock();
528 try {
529 if (!validActivation(dpid)) {
530 return false;
531 }
532 activeEqualSwitches.put(dpid, sw);
533 log.info("Added Activated EQUAL Switch {}", dpid);
534 return true;
535 } finally {
536 switchLock.unlock();
537 }
538 }
539
540 @Override
541 public void transitionToMasterSwitch(Dpid dpid) {
542 switchLock.lock();
543 try {
544 if (activeMasterSwitches.containsKey(dpid)) {
545 return;
546 }
547 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
548 if (sw == null) {
549 sw = getSwitch(dpid);
550 if (sw == null) {
551 log.error("Transition to master called on sw {}, but switch "
552 + "was not found in controller-cache", dpid);
553 return;
554 }
555 }
556 log.info("Transitioned switch {} to MASTER", dpid);
557 activeMasterSwitches.put(dpid, sw);
558 } finally {
559 switchLock.unlock();
560 }
561 }
562
563
564 @Override
565 public void transitionToEqualSwitch(Dpid dpid) {
566 switchLock.lock();
567 try {
568 if (activeEqualSwitches.containsKey(dpid)) {
569 return;
570 }
571 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
572 if (sw == null) {
573 sw = getSwitch(dpid);
574 if (sw == null) {
575 log.error("Transition to equal called on sw {}, but switch "
576 + "was not found in controller-cache", dpid);
577 return;
578 }
579 }
580 log.info("Transitioned switch {} to EQUAL", dpid);
581 activeEqualSwitches.put(dpid, sw);
582 } finally {
583 switchLock.unlock();
584 }
585
586 }
587
588 @Override
589 public void removeConnectedSwitch(Dpid dpid) {
590 connectedSwitches.remove(dpid);
591 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
592 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700593 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700594 sw = activeEqualSwitches.remove(dpid);
595 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700596 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700597 l.switchRemoved(dpid);
598 }
599 }
600
601 @Override
602 public void processMessage(Dpid dpid, OFMessage m) {
603 processPacket(dpid, m);
604 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700605
606 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700607 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700608 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700609 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700610 }
611 }
tom7ef8ff92014-09-17 13:08:06 -0700612 }
613
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800614 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700615
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800616 protected final OFMessage msg;
617 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700618
619 public OFMessageHandler(Dpid dpid, OFMessage msg) {
620 this.msg = msg;
621 this.dpid = dpid;
622 }
623
624 @Override
625 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700626 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700627 listener.handleMessage(dpid, msg);
628 }
629 }
630
631 }
632
tom7ef8ff92014-09-17 13:08:06 -0700633}