blob: 11c9f20e434e862775581254ad233c612a29ae80 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present 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;
Charles Chanecfdfb72015-11-24 19:05:50 -080030import org.onosproject.core.CoreService;
Thomas Vachuska3358af22015-05-19 18:40:34 -070031import org.onosproject.net.driver.DefaultDriverProviderService;
alshabibb452fd72015-04-22 20:46:20 -070032import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
34import org.onosproject.openflow.controller.Dpid;
35import org.onosproject.openflow.controller.OpenFlowController;
36import org.onosproject.openflow.controller.OpenFlowEventListener;
37import org.onosproject.openflow.controller.OpenFlowPacketContext;
38import org.onosproject.openflow.controller.OpenFlowSwitch;
39import org.onosproject.openflow.controller.OpenFlowSwitchListener;
40import org.onosproject.openflow.controller.PacketListener;
41import org.onosproject.openflow.controller.RoleState;
42import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080043import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070044import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
45import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070046import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
47import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080048import org.projectfloodlight.openflow.protocol.OFFactories;
49import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
50import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070051import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
52import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080053import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
54import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
55import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
56import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070057import org.projectfloodlight.openflow.protocol.OFMessage;
58import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070059import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070060import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
61import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070062import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070063import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080064import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Marc De Leenheerb9311372015-07-09 11:36:49 -070065import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
66import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080070import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070071import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070072import java.util.LinkedList;
73import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080074import java.util.Set;
75import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080076import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070077import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080078import java.util.concurrent.ExecutorService;
79import java.util.concurrent.Executors;
80import java.util.concurrent.locks.Lock;
81import java.util.concurrent.locks.ReentrantLock;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080082import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070083
84@Component(immediate = true)
85@Service
86public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -080087 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -070088 private static final String DEFAULT_OFPORT = "6633,6653";
Charles Chan3b00e1b2015-08-26 23:12:52 +080089 private static final int DEFAULT_WORKER_THREADS = 16;
tom7ef8ff92014-09-17 13:08:06 -070090
91 private static final Logger log =
92 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
93
alshabibb452fd72015-04-22 20:46:20 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -080095 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -070098 protected DriverService driverService;
99
Thomas Vachuska3358af22015-05-19 18:40:34 -0700100 // References exists merely for sequencing purpose to assure drivers are loaded
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DefaultDriverProviderService defaultDriverProviderService;
103
Charles Chan3b00e1b2015-08-26 23:12:52 +0800104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected ComponentConfigService cfgService;
106
Brian O'Connore2a399e2015-09-22 15:32:50 -0700107 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
108 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
109 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800110
111 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
112 label = "Number of controller worker threads; default is 16")
113 private int workerThreads = DEFAULT_WORKER_THREADS;
114
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800115 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800116 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800117
Jian Li28247b52016-01-07 17:24:15 -0800118 protected ExecutorService executorPacketIn =
Andrea Campanelladda93562016-03-02 11:08:12 -0800119 Executors.newCachedThreadPool(groupedThreads("onos/of", "event-pkt-in-stats-%d", log));
Jian Li28247b52016-01-07 17:24:15 -0800120
121 protected ExecutorService executorFlowRemoved =
Andrea Campanelladda93562016-03-02 11:08:12 -0800122 Executors.newCachedThreadPool(groupedThreads("onos/of", "event-flow-removed-stats-%d", log));
Jian Li28247b52016-01-07 17:24:15 -0800123
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800124 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800125 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700126
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800127 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700128 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800129 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700130 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800131 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700132 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700133
134 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700135 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700136
137 protected Multimap<Integer, PacketListener> ofPacketListener =
138 ArrayListMultimap.create();
139
Jonathan Hart6d44d192015-05-11 18:01:19 -0700140 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700141
Jian Li28247b52016-01-07 17:24:15 -0800142 protected boolean monitorAllEvents = false;
143
sangho6a0bb172015-02-05 12:24:48 -0800144 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
145 ArrayListMultimap.create();
146
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700147 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
148 ArrayListMultimap.create();
149
sangho6a0bb172015-02-05 12:24:48 -0800150 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
151 ArrayListMultimap.create();
152
153 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800154 ArrayListMultimap.create();
155
sangho538108b2015-04-08 14:29:20 -0700156 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
157 ArrayListMultimap.create();
158
tom7ef8ff92014-09-17 13:08:06 -0700159 private final Controller ctrl = new Controller();
160
161 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800162 public void activate(ComponentContext context) {
Charles Chanecfdfb72015-11-24 19:05:50 -0800163 coreService.registerApplication(APP_ID, this::preDeactivate);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800164 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700165 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700166 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700167 }
168
Charles Chanecfdfb72015-11-24 19:05:50 -0800169 private void preDeactivate() {
170 // Close listening channel and all OF channels before deactivating
171 ctrl.stop();
172 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
173 }
174
tom7ef8ff92014-09-17 13:08:06 -0700175 @Deactivate
176 public void deactivate() {
Ray Milkeyeba68172016-03-07 11:03:25 -0800177 preDeactivate();
Charles Chan3b00e1b2015-08-26 23:12:52 +0800178 cfgService.unregisterProperties(getClass(), false);
Charles Chanecfdfb72015-11-24 19:05:50 -0800179 connectedSwitches.clear();
180 activeMasterSwitches.clear();
181 activeEqualSwitches.clear();
tom7ef8ff92014-09-17 13:08:06 -0700182 }
183
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800184 @Modified
185 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800186 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700187 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800188 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800189 }
190
tom7ef8ff92014-09-17 13:08:06 -0700191 @Override
192 public Iterable<OpenFlowSwitch> getSwitches() {
193 return connectedSwitches.values();
194 }
195
196 @Override
197 public Iterable<OpenFlowSwitch> getMasterSwitches() {
198 return activeMasterSwitches.values();
199 }
200
201 @Override
202 public Iterable<OpenFlowSwitch> getEqualSwitches() {
203 return activeEqualSwitches.values();
204 }
205
206 @Override
207 public OpenFlowSwitch getSwitch(Dpid dpid) {
208 return connectedSwitches.get(dpid);
209 }
210
211 @Override
212 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
213 return activeMasterSwitches.get(dpid);
214 }
215
216 @Override
217 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
218 return activeEqualSwitches.get(dpid);
219 }
220
221 @Override
Jian Li28247b52016-01-07 17:24:15 -0800222 public void monitorAllEvents(boolean monitor) {
223 this.monitorAllEvents = monitor;
224 }
225
226 @Override
tom7ef8ff92014-09-17 13:08:06 -0700227 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700228 if (!ofSwitchListener.contains(listener)) {
229 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700230 }
231 }
232
233 @Override
234 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700235 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700236 }
237
238 @Override
239 public void addPacketListener(int priority, PacketListener listener) {
240 ofPacketListener.put(priority, listener);
241 }
242
243 @Override
244 public void removePacketListener(PacketListener listener) {
245 ofPacketListener.values().remove(listener);
246 }
247
248 @Override
alshabibeec3a062014-09-17 18:01:26 -0700249 public void addEventListener(OpenFlowEventListener listener) {
250 ofEventListener.add(listener);
251 }
252
253 @Override
254 public void removeEventListener(OpenFlowEventListener listener) {
255 ofEventListener.remove(listener);
256 }
257
258 @Override
tom7ef8ff92014-09-17 13:08:06 -0700259 public void write(Dpid dpid, OFMessage msg) {
260 this.getSwitch(dpid).sendMsg(msg);
261 }
262
263 @Override
264 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800265 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700266 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800267 Collection<OFGroupStatsEntry> groupStats;
268 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700269 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800270
tom7ef8ff92014-09-17 13:08:06 -0700271 switch (msg.getType()) {
272 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700273 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700274 l.portChanged(dpid, (OFPortStatus) msg);
275 }
276 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700277 case FEATURES_REPLY:
278 for (OpenFlowSwitchListener l : ofSwitchListener) {
279 l.switchChanged(dpid);
280 }
281 break;
tom7ef8ff92014-09-17 13:08:06 -0700282 case PACKET_IN:
283 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
284 .packetContextFromPacketIn(this.getSwitch(dpid),
285 (OFPacketIn) msg);
286 for (PacketListener p : ofPacketListener.values()) {
287 p.handlePacket(pktCtx);
288 }
Jian Li28247b52016-01-07 17:24:15 -0800289 if (monitorAllEvents) {
Andrea Campanelladda93562016-03-02 11:08:12 -0800290 executorPacketIn.execute(new OFMessageHandler(dpid, msg));
Jian Li28247b52016-01-07 17:24:15 -0800291 }
tom7ef8ff92014-09-17 13:08:06 -0700292 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800293 // TODO: Consider using separate threadpool for sensitive messages.
294 // ie. Back to back error could cause us to starve.
295 case FLOW_REMOVED:
Jian Li28247b52016-01-07 17:24:15 -0800296 if (monitorAllEvents) {
Andrea Campanelladda93562016-03-02 11:08:12 -0800297 executorFlowRemoved.execute(new OFMessageHandler(dpid, msg));
Jian Li28247b52016-01-07 17:24:15 -0800298 }
Jonathan Hart019877f2016-04-07 18:44:58 -0700299 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800300 case ERROR:
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800301 log.debug("Received error message from {}: {}", dpid, msg);
Andrea Campanelladda93562016-03-02 11:08:12 -0800302 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800303 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700304 case STATS_REPLY:
305 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800306 switch (reply.getStatsType()) {
307 case PORT_DESC:
308 for (OpenFlowSwitchListener l : ofSwitchListener) {
309 l.switchChanged(dpid);
310 }
311 break;
312 case FLOW:
313 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
314 if (flowStats != null) {
315 OFFlowStatsReply.Builder rep =
316 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
317 rep.setEntries(Lists.newLinkedList(flowStats));
ssyoon9030fbcd92015-08-17 10:42:07 +0900318 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800319 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800320 }
321 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700322 case TABLE:
323 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
324 if (tableStats != null) {
325 OFTableStatsReply.Builder rep =
326 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
327 rep.setEntries(Lists.newLinkedList(tableStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800328 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700329 }
330 break;
sangho6a0bb172015-02-05 12:24:48 -0800331 case GROUP:
332 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
333 if (groupStats != null) {
334 OFGroupStatsReply.Builder rep =
335 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
336 rep.setEntries(Lists.newLinkedList(groupStats));
337 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800338 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800339 }
340 break;
341 case GROUP_DESC:
342 groupDescStats = publishGroupDescStats(dpid,
343 (OFGroupDescStatsReply) reply);
344 if (groupDescStats != null) {
345 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700346 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800347 rep.setEntries(Lists.newLinkedList(groupDescStats));
348 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800349 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800350 }
351 break;
sangho538108b2015-04-08 14:29:20 -0700352 case PORT:
Andrea Campanelladda93562016-03-02 11:08:12 -0800353 executorMsgs.execute(new OFMessageHandler(dpid, reply));
sangho538108b2015-04-08 14:29:20 -0700354 break;
alshabib5eb79392015-08-19 18:09:55 -0700355 case METER:
Andrea Campanelladda93562016-03-02 11:08:12 -0800356 executorMsgs.execute(new OFMessageHandler(dpid, reply));
alshabib5eb79392015-08-19 18:09:55 -0700357 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700358 case EXPERIMENTER:
359 if (reply instanceof OFCalientFlowStatsReply) {
360 // Convert Calient flow statistics to regular flow stats
361 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
362 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
363 List<OFFlowStatsEntry> entries = new LinkedList<>();
364 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
365
366 // Single instruction, i.e., output to port
367 OFActionOutput action = OFFactories
368 .getFactory(msg.getVersion())
369 .actions()
370 .buildOutput()
371 .setPort(entry.getOutPort())
372 .build();
373 OFInstruction instruction = OFFactories
374 .getFactory(msg.getVersion())
375 .instructions()
376 .applyActions(Collections.singletonList(action));
377 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
378 .setMatch(entry.getMatch())
379 .setTableId(entry.getTableId())
380 .setDurationSec(entry.getDurationSec())
381 .setDurationNsec(entry.getDurationNsec())
382 .setPriority(entry.getPriority())
383 .setIdleTimeout(entry.getIdleTimeout())
384 .setHardTimeout(entry.getHardTimeout())
385 .setFlags(entry.getFlags())
386 .setCookie(entry.getCookie())
387 .setInstructions(Collections.singletonList(instruction))
388 .build();
389 entries.add(fs);
390 }
391 fsr.setEntries(entries);
392
393 flowStats = publishFlowStats(dpid, fsr.build());
394 if (flowStats != null) {
395 OFFlowStatsReply.Builder rep =
396 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
397 rep.setEntries(Lists.newLinkedList(flowStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800398 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700399 }
400 } else {
Andrea Campanelladda93562016-03-02 11:08:12 -0800401 executorMsgs.execute(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700402 }
403 break;
sangho6a0bb172015-02-05 12:24:48 -0800404 default:
alshabib5eb79392015-08-19 18:09:55 -0700405 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700406 break;
alshabib64def642014-12-02 23:27:37 -0800407 }
408 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700409 case BARRIER_REPLY:
Andrea Campanelladda93562016-03-02 11:08:12 -0800410 executorBarrier.execute(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700411 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700412 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700413 long experimenter = ((OFExperimenter) msg).getExperimenter();
414 if (experimenter == 0x748771) {
415 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700416 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
417 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
418 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
419 portDesc.setPortNo(circuitPortStatus.getPortNo())
420 .setHwAddr(circuitPortStatus.getHwAddr())
421 .setName(circuitPortStatus.getName())
422 .setConfig(circuitPortStatus.getConfig())
423 .setState(circuitPortStatus.getState());
424 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
425 for (OpenFlowSwitchListener l : ofSwitchListener) {
426 l.portChanged(dpid, portStatus.build());
427 }
428 } else {
429 log.warn("Handling experimenter type {} not yet implemented",
430 ((OFExperimenter) msg).getExperimenter(), msg);
431 }
432 break;
tom7ef8ff92014-09-17 13:08:06 -0700433 default:
434 log.warn("Handling message type {} not yet implemented {}",
435 msg.getType(), msg);
436 }
437 }
438
sangho6a0bb172015-02-05 12:24:48 -0800439 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
440 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800441 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800442 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800443 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800444 return fullFlowStats.removeAll(dpid);
445 }
446 return null;
447 }
448
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700449 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
450 OFTableStatsReply reply) {
451 //TODO: Get rid of synchronized
452 fullTableStats.putAll(dpid, reply.getEntries());
453 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
454 return fullTableStats.removeAll(dpid);
455 }
456 return null;
457 }
458
sangho6a0bb172015-02-05 12:24:48 -0800459 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
460 OFGroupStatsReply reply) {
461 //TODO: Get rid of synchronized
462 fullGroupStats.putAll(dpid, reply.getEntries());
463 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
464 return fullGroupStats.removeAll(dpid);
465 }
466 return null;
467 }
468
469 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
470 OFGroupDescStatsReply reply) {
471 //TODO: Get rid of synchronized
472 fullGroupDescStats.putAll(dpid, reply.getEntries());
473 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
474 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800475 }
476 return null;
477 }
478
sangho538108b2015-04-08 14:29:20 -0700479 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
480 OFPortStatsReply reply) {
481 fullPortStats.putAll(dpid, reply.getEntries());
482 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
483 return fullPortStats.removeAll(dpid);
484 }
485 return null;
486 }
487
tom7ef8ff92014-09-17 13:08:06 -0700488 @Override
489 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700490 final OpenFlowSwitch sw = getSwitch(dpid);
491 if (sw == null) {
492 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
493 return;
494 }
495 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700496 }
497
498 /**
499 * Implementation of an OpenFlow Agent which is responsible for
500 * keeping track of connected switches and the state in which
501 * they are.
502 */
503 public class OpenFlowSwitchAgent implements OpenFlowAgent {
504
505 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
506 private final Lock switchLock = new ReentrantLock();
507
508 @Override
509 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700510
tom7ef8ff92014-09-17 13:08:06 -0700511 if (connectedSwitches.get(dpid) != null) {
512 log.error("Trying to add connectedSwitch but found a previous "
513 + "value for dpid: {}", dpid);
514 return false;
515 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700516 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700517 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700518 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700519 l.switchAdded(dpid);
520 }
521 return true;
522 }
523 }
524
525 @Override
526 public boolean validActivation(Dpid dpid) {
527 if (connectedSwitches.get(dpid) == null) {
528 log.error("Trying to activate switch but is not in "
529 + "connected switches: dpid {}. Aborting ..",
530 dpid);
531 return false;
532 }
533 if (activeMasterSwitches.get(dpid) != null ||
534 activeEqualSwitches.get(dpid) != null) {
535 log.error("Trying to activate switch but it is already "
536 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800537 + "Found in activeEqual: {}. Aborting ..",
538 dpid,
539 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
540 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700541 return false;
542 }
543 return true;
544 }
545
546
547 @Override
548 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
549 switchLock.lock();
550 try {
551 if (!validActivation(dpid)) {
552 return false;
553 }
554 activeMasterSwitches.put(dpid, sw);
555 return true;
556 } finally {
557 switchLock.unlock();
558 }
559 }
560
561 @Override
562 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
563 switchLock.lock();
564 try {
565 if (!validActivation(dpid)) {
566 return false;
567 }
568 activeEqualSwitches.put(dpid, sw);
569 log.info("Added Activated EQUAL Switch {}", dpid);
570 return true;
571 } finally {
572 switchLock.unlock();
573 }
574 }
575
576 @Override
577 public void transitionToMasterSwitch(Dpid dpid) {
578 switchLock.lock();
579 try {
580 if (activeMasterSwitches.containsKey(dpid)) {
581 return;
582 }
583 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
584 if (sw == null) {
585 sw = getSwitch(dpid);
586 if (sw == null) {
587 log.error("Transition to master called on sw {}, but switch "
588 + "was not found in controller-cache", dpid);
589 return;
590 }
591 }
592 log.info("Transitioned switch {} to MASTER", dpid);
593 activeMasterSwitches.put(dpid, sw);
594 } finally {
595 switchLock.unlock();
596 }
597 }
598
599
600 @Override
601 public void transitionToEqualSwitch(Dpid dpid) {
602 switchLock.lock();
603 try {
604 if (activeEqualSwitches.containsKey(dpid)) {
605 return;
606 }
607 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
608 if (sw == null) {
609 sw = getSwitch(dpid);
610 if (sw == null) {
611 log.error("Transition to equal called on sw {}, but switch "
612 + "was not found in controller-cache", dpid);
613 return;
614 }
615 }
616 log.info("Transitioned switch {} to EQUAL", dpid);
617 activeEqualSwitches.put(dpid, sw);
618 } finally {
619 switchLock.unlock();
620 }
621
622 }
623
624 @Override
625 public void removeConnectedSwitch(Dpid dpid) {
626 connectedSwitches.remove(dpid);
627 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
628 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700629 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700630 sw = activeEqualSwitches.remove(dpid);
631 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700632 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700633 l.switchRemoved(dpid);
634 }
635 }
636
637 @Override
638 public void processMessage(Dpid dpid, OFMessage m) {
639 processPacket(dpid, m);
640 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700641
642 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700643 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700644 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700645 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700646 }
647 }
tom7ef8ff92014-09-17 13:08:06 -0700648 }
649
Jian Li152b8852015-12-07 14:47:25 -0800650 /**
651 * OpenFlow message handler for incoming control messages.
652 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800653 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700654
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800655 protected final OFMessage msg;
656 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700657
658 public OFMessageHandler(Dpid dpid, OFMessage msg) {
659 this.msg = msg;
660 this.dpid = dpid;
661 }
662
663 @Override
664 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700665 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700666 listener.handleMessage(dpid, msg);
667 }
668 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700669 }
tom7ef8ff92014-09-17 13:08:06 -0700670}