blob: 9113e5c5956b4c415ec84f99608c0f57e8c6fe48 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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;
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -070019import com.google.common.collect.ImmutableList;
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;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070031import org.onosproject.net.DeviceId;
32import org.onosproject.net.config.ConfigFactory;
33import org.onosproject.net.config.NetworkConfigRegistry;
34import org.onosproject.net.config.basics.SubjectFactories;
alshabibb452fd72015-04-22 20:46:20 -070035import org.onosproject.net.driver.DriverService;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070036import org.onosproject.openflow.config.OpenFlowDeviceConfig;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
38import org.onosproject.openflow.controller.Dpid;
39import org.onosproject.openflow.controller.OpenFlowController;
40import org.onosproject.openflow.controller.OpenFlowEventListener;
Jian Lia78cdb22016-04-21 13:03:58 -070041import org.onosproject.openflow.controller.OpenFlowMessageListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.openflow.controller.OpenFlowPacketContext;
43import org.onosproject.openflow.controller.OpenFlowSwitch;
44import org.onosproject.openflow.controller.OpenFlowSwitchListener;
45import org.onosproject.openflow.controller.PacketListener;
46import org.onosproject.openflow.controller.RoleState;
47import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080048import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070049import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
50import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070051import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
52import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080053import org.projectfloodlight.openflow.protocol.OFFactories;
Cem Türker3baff672017-10-12 15:09:01 +030054import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsEntry;
55import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib64def642014-12-02 23:27:37 -080056import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
57import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080058import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
59import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
60import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
61import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070062import org.projectfloodlight.openflow.protocol.OFMessage;
63import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070064import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070065import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
tom7ef8ff92014-09-17 13:08:06 -070066import org.projectfloodlight.openflow.protocol.OFPortStatus;
Cem Türker3baff672017-10-12 15:09:01 +030067import org.projectfloodlight.openflow.protocol.OFQueueStatsEntry;
68import org.projectfloodlight.openflow.protocol.OFQueueStatsReply;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070069import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080070import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Jian Li2266bff2016-04-21 11:01:25 -070071import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
72import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Marc De Leenheerb9311372015-07-09 11:36:49 -070073import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
74import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070075import org.slf4j.Logger;
76import org.slf4j.LoggerFactory;
77
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -070078import java.util.ArrayList;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080079import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070080import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070081import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080082import java.util.Set;
Marc De Leenheer8aba62f2017-04-25 14:33:37 -070083import java.util.concurrent.CompletableFuture;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080084import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080085import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070086import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080087import java.util.concurrent.ExecutorService;
88import java.util.concurrent.Executors;
89import java.util.concurrent.locks.Lock;
90import java.util.concurrent.locks.ReentrantLock;
Jian Li2266bff2016-04-21 11:01:25 -070091
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080092import static org.onlab.util.Tools.groupedThreads;
Ozge AYAZ60aded22017-06-20 08:35:30 +000093
tom7ef8ff92014-09-17 13:08:06 -070094
95@Component(immediate = true)
96@Service
97public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -080098 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -070099 private static final String DEFAULT_OFPORT = "6633,6653";
Yuta HIGUCHI8552b172016-07-25 12:10:08 -0700100 private static final int DEFAULT_WORKER_THREADS = 0;
Andrea Campanella86e0c562017-11-23 16:38:24 +0100101 protected static final String SCHEME = "of";
tom7ef8ff92014-09-17 13:08:06 -0700102
103 private static final Logger log =
104 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
105
alshabibb452fd72015-04-22 20:46:20 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -0800107 protected CoreService coreService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -0700110 protected DriverService driverService;
111
Charles Chan3b00e1b2015-08-26 23:12:52 +0800112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected ComponentConfigService cfgService;
114
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected NetworkConfigRegistry netCfgService;
117
Brian O'Connore2a399e2015-09-22 15:32:50 -0700118 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
119 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
120 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800121
122 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
Yuta HIGUCHI8552b172016-07-25 12:10:08 -0700123 label = "Number of controller worker threads")
Charles Chan3b00e1b2015-08-26 23:12:52 +0800124 private int workerThreads = DEFAULT_WORKER_THREADS;
125
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800126 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800127 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800128
129 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800130 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700131
Prince Pereirae7798032016-07-08 16:31:58 +0530132 //Separate executor thread for handling error messages and barrier replies for same failed
133 // transactions to avoid context switching of thread
134 protected ExecutorService executorErrorMsgs =
135 Executors.newSingleThreadExecutor(groupedThreads("onos/of", "event-error-msg-%d", log));
136
137 //concurrent hashmap to track failed transactions
138 protected ConcurrentMap<Long, Boolean> errorMsgs =
139 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800140 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700141 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800142 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700143 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800144 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700145 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700146
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700147 // Key: dpid, value: map with key: long (XID), value: completable future
148 protected ConcurrentMap<Dpid, ConcurrentMap<Long, CompletableFuture<OFMessage>>> responses =
149 new ConcurrentHashMap<>();
150
tom7ef8ff92014-09-17 13:08:06 -0700151 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700152 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700153
154 protected Multimap<Integer, PacketListener> ofPacketListener =
155 ArrayListMultimap.create();
156
Jonathan Hart6d44d192015-05-11 18:01:19 -0700157 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700158
Jian Lia78cdb22016-04-21 13:03:58 -0700159 protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
Jian Li28247b52016-01-07 17:24:15 -0800160
sangho6a0bb172015-02-05 12:24:48 -0800161 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
162 ArrayListMultimap.create();
163
Cem Türker3baff672017-10-12 15:09:01 +0300164 protected Multimap<Dpid, OFFlowLightweightStatsEntry> fullFlowLightweightStats =
165 ArrayListMultimap.create();
166
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700167 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
168 ArrayListMultimap.create();
169
sangho6a0bb172015-02-05 12:24:48 -0800170 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
171 ArrayListMultimap.create();
172
173 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800174 ArrayListMultimap.create();
175
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700176 // deprecated in 1.11.0, no longer referenced from anywhere
177 @Deprecated
sangho538108b2015-04-08 14:29:20 -0700178 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
179 ArrayListMultimap.create();
180
Ozge AYAZ60aded22017-06-20 08:35:30 +0000181 protected Multimap<Dpid, OFQueueStatsEntry> fullQueueStats =
182 ArrayListMultimap.create();
183
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700184 protected final ConfigFactory factory =
185 new ConfigFactory<DeviceId, OpenFlowDeviceConfig>(
186 SubjectFactories.DEVICE_SUBJECT_FACTORY,
187 OpenFlowDeviceConfig.class, OpenFlowDeviceConfig.CONFIG_KEY) {
188 @Override
189 public OpenFlowDeviceConfig createConfig() {
190 return new OpenFlowDeviceConfig();
191 }
192 };
193
tom7ef8ff92014-09-17 13:08:06 -0700194 private final Controller ctrl = new Controller();
195
196 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800197 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700198 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800199 cfgService.registerProperties(getClass());
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700200 netCfgService.registerConfigFactory(factory);
Brian O'Connorff278502015-09-22 14:49:52 -0700201 ctrl.setConfigParams(context.getProperties());
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700202 ctrl.start(agent, driverService, netCfgService);
tom7ef8ff92014-09-17 13:08:06 -0700203 }
204
Andrea Campanella3556f362016-04-28 15:18:10 -0700205 private void cleanup() {
206 // Close listening channel and all OF channels. Clean information about switches
207 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800208 ctrl.stop();
209 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700210 connectedSwitches.clear();
211 activeMasterSwitches.clear();
212 activeEqualSwitches.clear();
Charles Chanecfdfb72015-11-24 19:05:50 -0800213 }
214
tom7ef8ff92014-09-17 13:08:06 -0700215 @Deactivate
216 public void deactivate() {
Thiago Santos61725402016-08-05 17:58:56 -0300217 cleanup();
Charles Chan3b00e1b2015-08-26 23:12:52 +0800218 cfgService.unregisterProperties(getClass(), false);
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700219 netCfgService.unregisterConfigFactory(factory);
tom7ef8ff92014-09-17 13:08:06 -0700220 }
221
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800222 @Modified
223 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800224 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700225 ctrl.setConfigParams(context.getProperties());
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700226 ctrl.start(agent, driverService, netCfgService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800227 }
228
tom7ef8ff92014-09-17 13:08:06 -0700229 @Override
230 public Iterable<OpenFlowSwitch> getSwitches() {
231 return connectedSwitches.values();
232 }
233
234 @Override
235 public Iterable<OpenFlowSwitch> getMasterSwitches() {
236 return activeMasterSwitches.values();
237 }
238
239 @Override
240 public Iterable<OpenFlowSwitch> getEqualSwitches() {
241 return activeEqualSwitches.values();
242 }
243
244 @Override
245 public OpenFlowSwitch getSwitch(Dpid dpid) {
246 return connectedSwitches.get(dpid);
247 }
248
249 @Override
250 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
251 return activeMasterSwitches.get(dpid);
252 }
253
254 @Override
255 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
256 return activeEqualSwitches.get(dpid);
257 }
258
259 @Override
260 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700261 if (!ofSwitchListener.contains(listener)) {
262 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700263 }
264 }
265
266 @Override
267 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700268 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700269 }
270
271 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700272 public void addMessageListener(OpenFlowMessageListener listener) {
273 ofMessageListener.add(listener);
274 }
275
276 @Override
277 public void removeMessageListener(OpenFlowMessageListener listener) {
278 ofMessageListener.remove(listener);
279 }
280
281 @Override
tom7ef8ff92014-09-17 13:08:06 -0700282 public void addPacketListener(int priority, PacketListener listener) {
283 ofPacketListener.put(priority, listener);
284 }
285
286 @Override
287 public void removePacketListener(PacketListener listener) {
288 ofPacketListener.values().remove(listener);
289 }
290
291 @Override
alshabibeec3a062014-09-17 18:01:26 -0700292 public void addEventListener(OpenFlowEventListener listener) {
293 ofEventListener.add(listener);
294 }
295
296 @Override
297 public void removeEventListener(OpenFlowEventListener listener) {
298 ofEventListener.remove(listener);
299 }
300
301 @Override
tom7ef8ff92014-09-17 13:08:06 -0700302 public void write(Dpid dpid, OFMessage msg) {
303 this.getSwitch(dpid).sendMsg(msg);
304 }
305
306 @Override
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700307 public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
308 write(dpid, msg);
309
310 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids =
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700311 responses.computeIfAbsent(dpid, k -> new ConcurrentHashMap<>());
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700312
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700313 CompletableFuture<OFMessage> future = new CompletableFuture<>();
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700314 xids.put(msg.getXid(), future);
315
316 return future;
317 }
318
319 @Override
tom7ef8ff92014-09-17 13:08:06 -0700320 public void processPacket(Dpid dpid, OFMessage msg) {
sangyun-han69ed4462016-07-27 12:10:12 +0900321 OpenFlowSwitch sw = this.getSwitch(dpid);
Laszlo Pappb68fe7e2017-11-24 17:06:59 +0000322 if (log.isTraceEnabled()) {
323 log.trace("Processing message from switch {} via openflow: {}", dpid, msg);
324 }
sangyun-han69ed4462016-07-27 12:10:12 +0900325
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700326 // Check if someone is waiting for this message
327 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids = responses.get(dpid);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700328 if (xids != null) {
329 CompletableFuture<OFMessage> future = xids.remove(msg.getXid());
330 if (future != null) {
331 future.complete(msg);
332 }
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700333 }
334
tom7ef8ff92014-09-17 13:08:06 -0700335 switch (msg.getType()) {
336 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700337 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700338 l.portChanged(dpid, (OFPortStatus) msg);
339 }
340 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700341 case FEATURES_REPLY:
342 for (OpenFlowSwitchListener l : ofSwitchListener) {
343 l.switchChanged(dpid);
344 }
345 break;
tom7ef8ff92014-09-17 13:08:06 -0700346 case PACKET_IN:
sangyun-han69ed4462016-07-27 12:10:12 +0900347 if (sw == null) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700348 log.error("Ignoring PACKET_IN, switch {} is not found", dpid);
sangyun-han69ed4462016-07-27 12:10:12 +0900349 break;
350 }
tom7ef8ff92014-09-17 13:08:06 -0700351 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
Ozge AYAZ60aded22017-06-20 08:35:30 +0000352 .packetContextFromPacketIn(sw, (OFPacketIn) msg);
tom7ef8ff92014-09-17 13:08:06 -0700353 for (PacketListener p : ofPacketListener.values()) {
354 p.handlePacket(pktCtx);
355 }
356 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800357 // TODO: Consider using separate threadpool for sensitive messages.
358 // ie. Back to back error could cause us to starve.
359 case FLOW_REMOVED:
Andrea Campanelladda93562016-03-02 11:08:12 -0800360 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800361 break;
Prince Pereirae7798032016-07-08 16:31:58 +0530362 case ERROR:
363 log.debug("Received error message from {}: {}", dpid, msg);
364 errorMsgs.putIfAbsent(msg.getXid(), true);
365 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
366 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700367 case STATS_REPLY:
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700368 processStatsReply(dpid, (OFStatsReply) msg);
alshabib64def642014-12-02 23:27:37 -0800369 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700370 case BARRIER_REPLY:
Prince Pereirae7798032016-07-08 16:31:58 +0530371 if (errorMsgs.containsKey(msg.getXid())) {
372 //To make oferror msg handling and corresponding barrier reply serialized,
373 // executorErrorMsgs is used for both transaction
374 errorMsgs.remove(msg.getXid());
375 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
376 } else {
377 executorBarrier.execute(new OFMessageHandler(dpid, msg));
378 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700379 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700380 case EXPERIMENTER:
sangyun-han69ed4462016-07-27 12:10:12 +0900381 if (sw == null) {
382 log.error("Switch {} is not found", dpid);
383 break;
384 }
Marc De Leenheerb9311372015-07-09 11:36:49 -0700385 long experimenter = ((OFExperimenter) msg).getExperimenter();
386 if (experimenter == 0x748771) {
387 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700388 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
sangyun-han69ed4462016-07-27 12:10:12 +0900389 OFPortStatus.Builder portStatus = sw.factory().buildPortStatus();
390 OFPortDesc.Builder portDesc = sw.factory().buildPortDesc();
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700391 portDesc.setPortNo(circuitPortStatus.getPortNo())
392 .setHwAddr(circuitPortStatus.getHwAddr())
393 .setName(circuitPortStatus.getName())
394 .setConfig(circuitPortStatus.getConfig())
395 .setState(circuitPortStatus.getState());
396 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
397 for (OpenFlowSwitchListener l : ofSwitchListener) {
398 l.portChanged(dpid, portStatus.build());
399 }
400 } else {
401 log.warn("Handling experimenter type {} not yet implemented",
402 ((OFExperimenter) msg).getExperimenter(), msg);
403 }
404 break;
tom7ef8ff92014-09-17 13:08:06 -0700405 default:
406 log.warn("Handling message type {} not yet implemented {}",
407 msg.getType(), msg);
408 }
409 }
410
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700411 private void processStatsReply(Dpid dpid, OFStatsReply reply) {
412 switch (reply.getStatsType()) {
413 case QUEUE:
414 Collection<OFQueueStatsEntry> queueStatsEntries = publishQueueStats(dpid, (OFQueueStatsReply) reply);
415 if (queueStatsEntries != null) {
416 OFQueueStatsReply.Builder rep =
417 OFFactories.getFactory(reply.getVersion()).buildQueueStatsReply();
418 rep.setEntries(ImmutableList.copyOf(queueStatsEntries));
419 rep.setXid(reply.getXid());
420 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
421 }
422 break;
423
424 case PORT_DESC:
425 for (OpenFlowSwitchListener l : ofSwitchListener) {
426 l.switchChanged(dpid);
427 }
428 break;
429
430 case FLOW:
431 Collection<OFFlowStatsEntry> flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
432 if (flowStats != null) {
433 OFFlowStatsReply.Builder rep =
434 OFFactories.getFactory(reply.getVersion()).buildFlowStatsReply();
435 rep.setEntries(ImmutableList.copyOf(flowStats));
436 rep.setXid(reply.getXid());
437 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
438 }
439 break;
Cem Türker3baff672017-10-12 15:09:01 +0300440 case FLOW_LIGHTWEIGHT:
441 Collection<OFFlowLightweightStatsEntry> flowLightweightStats =
442 publishFlowStatsLightweight(dpid, (OFFlowLightweightStatsReply) reply);
443 if (flowLightweightStats != null) {
444 OFFlowLightweightStatsReply.Builder rep =
445 OFFactories.getFactory(reply.getVersion()).buildFlowLightweightStatsReply();
446 rep.setEntries(ImmutableList.copyOf(flowLightweightStats));
447 rep.setXid(reply.getXid());
448 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
449 }
450 break;
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700451 case TABLE:
452 Collection<OFTableStatsEntry> tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
453 if (tableStats != null) {
454 OFTableStatsReply.Builder rep =
455 OFFactories.getFactory(reply.getVersion()).buildTableStatsReply();
456 rep.setEntries(ImmutableList.copyOf(tableStats));
457 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
458 }
459 break;
460
461 case GROUP:
462 Collection<OFGroupStatsEntry> groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
463 if (groupStats != null) {
464 OFGroupStatsReply.Builder rep =
465 OFFactories.getFactory(reply.getVersion()).buildGroupStatsReply();
466 rep.setEntries(ImmutableList.copyOf(groupStats));
467 rep.setXid(reply.getXid());
468 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
469 }
470 break;
471
472 case GROUP_DESC:
473 Collection<OFGroupDescStatsEntry> groupDescStats = publishGroupDescStats(dpid,
474 (OFGroupDescStatsReply) reply);
475 if (groupDescStats != null) {
476 OFGroupDescStatsReply.Builder rep =
477 OFFactories.getFactory(reply.getVersion()).buildGroupDescStatsReply();
478 rep.setEntries(ImmutableList.copyOf(groupDescStats));
479 rep.setXid(reply.getXid());
480 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
481 }
482 break;
483
484 case PORT:
485 executorMsgs.execute(new OFMessageHandler(dpid, reply));
486 break;
487
488 case METER:
489 executorMsgs.execute(new OFMessageHandler(dpid, reply));
490 break;
491
492 case EXPERIMENTER:
493 if (reply instanceof OFCalientFlowStatsReply) {
494 OpenFlowSwitch sw = this.getSwitch(dpid);
495 // Convert Calient flow statistics to regular flow stats
496 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
497 if (sw == null) {
498 log.error("Switch {} is not found", dpid);
499 break;
500 }
501 OFFlowStatsReply.Builder fsr = sw.factory().buildFlowStatsReply();
502 List<OFFlowStatsEntry> entries = new ArrayList<>();
503 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) reply).getEntries()) {
504
505 // Single instruction, i.e., output to port
506 OFActionOutput action = sw.factory()
507 .actions()
508 .buildOutput()
509 .setPort(entry.getOutPort())
510 .build();
511 OFInstruction instruction = sw.factory()
512 .instructions()
513 .applyActions(Collections.singletonList(action));
514 OFFlowStatsEntry fs = sw.factory().buildFlowStatsEntry()
515 .setMatch(entry.getMatch())
516 .setTableId(entry.getTableId())
517 .setDurationSec(entry.getDurationSec())
518 .setDurationNsec(entry.getDurationNsec())
519 .setPriority(entry.getPriority())
520 .setIdleTimeout(entry.getIdleTimeout())
521 .setHardTimeout(entry.getHardTimeout())
522 .setFlags(entry.getFlags())
523 .setCookie(entry.getCookie())
524 .setInstructions(Collections.singletonList(instruction))
525 .build();
526 entries.add(fs);
527 }
528 fsr.setEntries(entries);
529
530 flowStats = publishFlowStats(dpid, fsr.build());
531 if (flowStats != null) {
532 OFFlowStatsReply.Builder rep =
533 sw.factory().buildFlowStatsReply();
534 rep.setEntries(ImmutableList.copyOf(flowStats));
535 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
536 }
537 } else {
538 executorMsgs.execute(new OFMessageHandler(dpid, reply));
539 }
540 break;
541 default:
542 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
543 break;
544 }
545 }
546
sangho6a0bb172015-02-05 12:24:48 -0800547 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
548 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800549 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800550 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800551 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800552 return fullFlowStats.removeAll(dpid);
553 }
554 return null;
555 }
556
Cem Türker3baff672017-10-12 15:09:01 +0300557 private synchronized Collection<OFFlowLightweightStatsEntry> publishFlowStatsLightweight(
558 Dpid dpid,
559 OFFlowLightweightStatsReply reply) {
560 //TODO: Get rid of synchronized
561 fullFlowLightweightStats.putAll(dpid, reply.getEntries());
562 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
563 return fullFlowLightweightStats.removeAll(dpid);
564 }
565 return null;
566 }
567
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700568 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
569 OFTableStatsReply reply) {
570 //TODO: Get rid of synchronized
571 fullTableStats.putAll(dpid, reply.getEntries());
572 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
573 return fullTableStats.removeAll(dpid);
574 }
575 return null;
576 }
577
sangho6a0bb172015-02-05 12:24:48 -0800578 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
579 OFGroupStatsReply reply) {
580 //TODO: Get rid of synchronized
581 fullGroupStats.putAll(dpid, reply.getEntries());
582 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
583 return fullGroupStats.removeAll(dpid);
584 }
585 return null;
586 }
587
588 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
589 OFGroupDescStatsReply reply) {
590 //TODO: Get rid of synchronized
591 fullGroupDescStats.putAll(dpid, reply.getEntries());
592 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
593 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800594 }
595 return null;
596 }
597
Ozge AYAZ60aded22017-06-20 08:35:30 +0000598 private synchronized Collection<OFQueueStatsEntry> publishQueueStats(Dpid dpid, OFQueueStatsReply reply) {
599 fullQueueStats.putAll(dpid, reply.getEntries());
600 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
601 return fullQueueStats.removeAll(dpid);
602 }
603 return null;
604 }
605
tom7ef8ff92014-09-17 13:08:06 -0700606 @Override
607 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700608 final OpenFlowSwitch sw = getSwitch(dpid);
609 if (sw == null) {
610 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
611 return;
612 }
613 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700614 }
615
616 /**
617 * Implementation of an OpenFlow Agent which is responsible for
618 * keeping track of connected switches and the state in which
619 * they are.
620 */
621 public class OpenFlowSwitchAgent implements OpenFlowAgent {
622
623 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
624 private final Lock switchLock = new ReentrantLock();
625
626 @Override
627 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700628
tom7ef8ff92014-09-17 13:08:06 -0700629 if (connectedSwitches.get(dpid) != null) {
630 log.error("Trying to add connectedSwitch but found a previous "
631 + "value for dpid: {}", dpid);
632 return false;
633 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700634 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700635 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700636 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700637 l.switchAdded(dpid);
638 }
639 return true;
640 }
641 }
642
643 @Override
644 public boolean validActivation(Dpid dpid) {
645 if (connectedSwitches.get(dpid) == null) {
646 log.error("Trying to activate switch but is not in "
647 + "connected switches: dpid {}. Aborting ..",
648 dpid);
649 return false;
650 }
651 if (activeMasterSwitches.get(dpid) != null ||
652 activeEqualSwitches.get(dpid) != null) {
653 log.error("Trying to activate switch but it is already "
654 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800655 + "Found in activeEqual: {}. Aborting ..",
656 dpid,
657 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
658 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700659 return false;
660 }
661 return true;
662 }
663
664
665 @Override
666 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
667 switchLock.lock();
668 try {
669 if (!validActivation(dpid)) {
670 return false;
671 }
672 activeMasterSwitches.put(dpid, sw);
673 return true;
674 } finally {
675 switchLock.unlock();
676 }
677 }
678
679 @Override
680 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
681 switchLock.lock();
682 try {
683 if (!validActivation(dpid)) {
684 return false;
685 }
686 activeEqualSwitches.put(dpid, sw);
687 log.info("Added Activated EQUAL Switch {}", dpid);
688 return true;
689 } finally {
690 switchLock.unlock();
691 }
692 }
693
694 @Override
695 public void transitionToMasterSwitch(Dpid dpid) {
696 switchLock.lock();
697 try {
698 if (activeMasterSwitches.containsKey(dpid)) {
699 return;
700 }
701 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
702 if (sw == null) {
703 sw = getSwitch(dpid);
704 if (sw == null) {
705 log.error("Transition to master called on sw {}, but switch "
706 + "was not found in controller-cache", dpid);
707 return;
708 }
709 }
710 log.info("Transitioned switch {} to MASTER", dpid);
711 activeMasterSwitches.put(dpid, sw);
712 } finally {
713 switchLock.unlock();
714 }
715 }
716
717
718 @Override
719 public void transitionToEqualSwitch(Dpid dpid) {
720 switchLock.lock();
721 try {
722 if (activeEqualSwitches.containsKey(dpid)) {
723 return;
724 }
725 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
726 if (sw == null) {
727 sw = getSwitch(dpid);
728 if (sw == null) {
729 log.error("Transition to equal called on sw {}, but switch "
730 + "was not found in controller-cache", dpid);
731 return;
732 }
733 }
734 log.info("Transitioned switch {} to EQUAL", dpid);
735 activeEqualSwitches.put(dpid, sw);
736 } finally {
737 switchLock.unlock();
738 }
739
740 }
741
742 @Override
743 public void removeConnectedSwitch(Dpid dpid) {
744 connectedSwitches.remove(dpid);
745 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
746 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700747 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700748 sw = activeEqualSwitches.remove(dpid);
749 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700750 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700751 l.switchRemoved(dpid);
752 }
753 }
754
755 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700756 public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
757 for (OpenFlowMessageListener listener : ofMessageListener) {
758 listener.handleOutgoingMessage(dpid, m);
759 }
760 }
761
762
763 @Override
tom7ef8ff92014-09-17 13:08:06 -0700764 public void processMessage(Dpid dpid, OFMessage m) {
765 processPacket(dpid, m);
Jian Lia78cdb22016-04-21 13:03:58 -0700766
767 for (OpenFlowMessageListener listener : ofMessageListener) {
768 listener.handleIncomingMessage(dpid, m);
769 }
tom7ef8ff92014-09-17 13:08:06 -0700770 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700771
772 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700773 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700774 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700775 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700776 }
777 }
tom7ef8ff92014-09-17 13:08:06 -0700778 }
779
Jian Li152b8852015-12-07 14:47:25 -0800780 /**
Jian Li2266bff2016-04-21 11:01:25 -0700781 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800782 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800783 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700784
Ray Milkey9c9cde42018-01-12 14:22:06 -0800785 final OFMessage msg;
786 final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700787
788 public OFMessageHandler(Dpid dpid, OFMessage msg) {
789 this.msg = msg;
790 this.dpid = dpid;
791 }
792
793 @Override
794 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700795 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700796 listener.handleMessage(dpid, msg);
797 }
798 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700799 }
tom7ef8ff92014-09-17 13:08:06 -0700800}