blob: 5c46d8e374fbe7bb5231bf91bed758a7755c5200 [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;
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -070031import org.onosproject.net.device.DeviceEvent;
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -070032import org.onosproject.net.device.DeviceListener;
33import org.onosproject.net.device.DeviceService;
alshabibb452fd72015-04-22 20:46:20 -070034import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
36import org.onosproject.openflow.controller.Dpid;
37import org.onosproject.openflow.controller.OpenFlowController;
38import org.onosproject.openflow.controller.OpenFlowEventListener;
Jian Lia78cdb22016-04-21 13:03:58 -070039import org.onosproject.openflow.controller.OpenFlowMessageListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.openflow.controller.OpenFlowPacketContext;
41import org.onosproject.openflow.controller.OpenFlowSwitch;
42import org.onosproject.openflow.controller.OpenFlowSwitchListener;
43import org.onosproject.openflow.controller.PacketListener;
44import org.onosproject.openflow.controller.RoleState;
45import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080046import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070047import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
48import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070049import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
50import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080051import org.projectfloodlight.openflow.protocol.OFFactories;
Cem Türker3baff672017-10-12 15:09:01 +030052import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsEntry;
53import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib64def642014-12-02 23:27:37 -080054import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
55import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080056import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
57import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
58import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
59import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070060import org.projectfloodlight.openflow.protocol.OFMessage;
61import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070062import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070063import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
tom7ef8ff92014-09-17 13:08:06 -070064import org.projectfloodlight.openflow.protocol.OFPortStatus;
Cem Türker3baff672017-10-12 15:09:01 +030065import org.projectfloodlight.openflow.protocol.OFQueueStatsEntry;
66import org.projectfloodlight.openflow.protocol.OFQueueStatsReply;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070067import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080068import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Jian Li2266bff2016-04-21 11:01:25 -070069import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
70import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Marc De Leenheerb9311372015-07-09 11:36:49 -070071import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
72import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070073import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
75
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -070076import java.util.ArrayList;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080077import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070078import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070079import java.util.List;
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -070080import java.util.Optional;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080081import java.util.Set;
Marc De Leenheer8aba62f2017-04-25 14:33:37 -070082import java.util.concurrent.CompletableFuture;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080083import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080084import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070085import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080086import java.util.concurrent.ExecutorService;
87import java.util.concurrent.Executors;
88import java.util.concurrent.locks.Lock;
89import java.util.concurrent.locks.ReentrantLock;
Jian Li2266bff2016-04-21 11:01:25 -070090
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080091import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moone71494d2016-11-15 14:45:25 -080092import static org.onosproject.net.Device.Type.CONTROLLER;
93import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -070094import static org.onosproject.openflow.controller.Dpid.dpid;
Ozge AYAZ60aded22017-06-20 08:35:30 +000095
tom7ef8ff92014-09-17 13:08:06 -070096
97@Component(immediate = true)
98@Service
99public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -0800100 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -0700101 private static final String DEFAULT_OFPORT = "6633,6653";
Yuta HIGUCHI8552b172016-07-25 12:10:08 -0700102 private static final int DEFAULT_WORKER_THREADS = 0;
Andrea Campanella86e0c562017-11-23 16:38:24 +0100103 protected static final String SCHEME = "of";
tom7ef8ff92014-09-17 13:08:06 -0700104
105 private static final Logger log =
106 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
107
alshabibb452fd72015-04-22 20:46:20 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -0800109 protected CoreService coreService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -0700112 protected DriverService driverService;
113
Charles Chan3b00e1b2015-08-26 23:12:52 +0800114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected ComponentConfigService cfgService;
116
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected DeviceService deviceService;
119
120
Brian O'Connore2a399e2015-09-22 15:32:50 -0700121 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
122 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
123 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800124
125 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
Yuta HIGUCHI8552b172016-07-25 12:10:08 -0700126 label = "Number of controller worker threads")
Charles Chan3b00e1b2015-08-26 23:12:52 +0800127 private int workerThreads = DEFAULT_WORKER_THREADS;
128
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800129 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800130 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800131
132 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800133 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700134
Prince Pereirae7798032016-07-08 16:31:58 +0530135 //Separate executor thread for handling error messages and barrier replies for same failed
136 // transactions to avoid context switching of thread
137 protected ExecutorService executorErrorMsgs =
138 Executors.newSingleThreadExecutor(groupedThreads("onos/of", "event-error-msg-%d", log));
139
140 //concurrent hashmap to track failed transactions
141 protected ConcurrentMap<Long, Boolean> errorMsgs =
142 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800143 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700144 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800145 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700146 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800147 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700148 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700149
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700150 // Key: dpid, value: map with key: long (XID), value: completable future
151 protected ConcurrentMap<Dpid, ConcurrentMap<Long, CompletableFuture<OFMessage>>> responses =
152 new ConcurrentHashMap<>();
153
tom7ef8ff92014-09-17 13:08:06 -0700154 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700155 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700156
157 protected Multimap<Integer, PacketListener> ofPacketListener =
158 ArrayListMultimap.create();
159
Jonathan Hart6d44d192015-05-11 18:01:19 -0700160 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700161
Jian Lia78cdb22016-04-21 13:03:58 -0700162 protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
Jian Li28247b52016-01-07 17:24:15 -0800163
sangho6a0bb172015-02-05 12:24:48 -0800164 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
165 ArrayListMultimap.create();
166
Cem Türker3baff672017-10-12 15:09:01 +0300167 protected Multimap<Dpid, OFFlowLightweightStatsEntry> fullFlowLightweightStats =
168 ArrayListMultimap.create();
169
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700170 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
171 ArrayListMultimap.create();
172
sangho6a0bb172015-02-05 12:24:48 -0800173 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
174 ArrayListMultimap.create();
175
176 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800177 ArrayListMultimap.create();
178
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700179 // deprecated in 1.11.0, no longer referenced from anywhere
180 @Deprecated
sangho538108b2015-04-08 14:29:20 -0700181 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
182 ArrayListMultimap.create();
183
Ozge AYAZ60aded22017-06-20 08:35:30 +0000184 protected Multimap<Dpid, OFQueueStatsEntry> fullQueueStats =
185 ArrayListMultimap.create();
186
tom7ef8ff92014-09-17 13:08:06 -0700187 private final Controller ctrl = new Controller();
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700188 private InternalDeviceListener listener = new InternalDeviceListener();
tom7ef8ff92014-09-17 13:08:06 -0700189
190 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800191 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700192 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800193 cfgService.registerProperties(getClass());
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700194 deviceService.addListener(listener);
Brian O'Connorff278502015-09-22 14:49:52 -0700195 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700196 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700197 }
198
Andrea Campanella3556f362016-04-28 15:18:10 -0700199 private void cleanup() {
200 // Close listening channel and all OF channels. Clean information about switches
201 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800202 ctrl.stop();
203 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700204 connectedSwitches.clear();
205 activeMasterSwitches.clear();
206 activeEqualSwitches.clear();
Charles Chanecfdfb72015-11-24 19:05:50 -0800207 }
208
tom7ef8ff92014-09-17 13:08:06 -0700209 @Deactivate
210 public void deactivate() {
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700211 deviceService.removeListener(listener);
Thiago Santos61725402016-08-05 17:58:56 -0300212 cleanup();
Charles Chan3b00e1b2015-08-26 23:12:52 +0800213 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700214 }
215
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800216 @Modified
217 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800218 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700219 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800220 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800221 }
222
tom7ef8ff92014-09-17 13:08:06 -0700223 @Override
224 public Iterable<OpenFlowSwitch> getSwitches() {
225 return connectedSwitches.values();
226 }
227
228 @Override
229 public Iterable<OpenFlowSwitch> getMasterSwitches() {
230 return activeMasterSwitches.values();
231 }
232
233 @Override
234 public Iterable<OpenFlowSwitch> getEqualSwitches() {
235 return activeEqualSwitches.values();
236 }
237
238 @Override
239 public OpenFlowSwitch getSwitch(Dpid dpid) {
240 return connectedSwitches.get(dpid);
241 }
242
243 @Override
244 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
245 return activeMasterSwitches.get(dpid);
246 }
247
248 @Override
249 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
250 return activeEqualSwitches.get(dpid);
251 }
252
253 @Override
254 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700255 if (!ofSwitchListener.contains(listener)) {
256 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700257 }
258 }
259
260 @Override
261 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700262 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700263 }
264
265 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700266 public void addMessageListener(OpenFlowMessageListener listener) {
267 ofMessageListener.add(listener);
268 }
269
270 @Override
271 public void removeMessageListener(OpenFlowMessageListener listener) {
272 ofMessageListener.remove(listener);
273 }
274
275 @Override
tom7ef8ff92014-09-17 13:08:06 -0700276 public void addPacketListener(int priority, PacketListener listener) {
277 ofPacketListener.put(priority, listener);
278 }
279
280 @Override
281 public void removePacketListener(PacketListener listener) {
282 ofPacketListener.values().remove(listener);
283 }
284
285 @Override
alshabibeec3a062014-09-17 18:01:26 -0700286 public void addEventListener(OpenFlowEventListener listener) {
287 ofEventListener.add(listener);
288 }
289
290 @Override
291 public void removeEventListener(OpenFlowEventListener listener) {
292 ofEventListener.remove(listener);
293 }
294
295 @Override
tom7ef8ff92014-09-17 13:08:06 -0700296 public void write(Dpid dpid, OFMessage msg) {
297 this.getSwitch(dpid).sendMsg(msg);
298 }
299
300 @Override
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700301 public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
302 write(dpid, msg);
303
304 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids =
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700305 responses.computeIfAbsent(dpid, k -> new ConcurrentHashMap<>());
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700306
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700307 CompletableFuture<OFMessage> future = new CompletableFuture<>();
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700308 xids.put(msg.getXid(), future);
309
310 return future;
311 }
312
313 @Override
tom7ef8ff92014-09-17 13:08:06 -0700314 public void processPacket(Dpid dpid, OFMessage msg) {
sangyun-han69ed4462016-07-27 12:10:12 +0900315 OpenFlowSwitch sw = this.getSwitch(dpid);
Laszlo Pappb68fe7e2017-11-24 17:06:59 +0000316 if (log.isTraceEnabled()) {
317 log.trace("Processing message from switch {} via openflow: {}", dpid, msg);
318 }
sangyun-han69ed4462016-07-27 12:10:12 +0900319
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700320 // Check if someone is waiting for this message
321 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids = responses.get(dpid);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700322 if (xids != null) {
323 CompletableFuture<OFMessage> future = xids.remove(msg.getXid());
324 if (future != null) {
325 future.complete(msg);
326 }
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700327 }
328
tom7ef8ff92014-09-17 13:08:06 -0700329 switch (msg.getType()) {
330 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700331 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700332 l.portChanged(dpid, (OFPortStatus) msg);
333 }
334 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700335 case FEATURES_REPLY:
336 for (OpenFlowSwitchListener l : ofSwitchListener) {
337 l.switchChanged(dpid);
338 }
339 break;
tom7ef8ff92014-09-17 13:08:06 -0700340 case PACKET_IN:
sangyun-han69ed4462016-07-27 12:10:12 +0900341 if (sw == null) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700342 log.error("Ignoring PACKET_IN, switch {} is not found", dpid);
sangyun-han69ed4462016-07-27 12:10:12 +0900343 break;
344 }
tom7ef8ff92014-09-17 13:08:06 -0700345 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
Ozge AYAZ60aded22017-06-20 08:35:30 +0000346 .packetContextFromPacketIn(sw, (OFPacketIn) msg);
tom7ef8ff92014-09-17 13:08:06 -0700347 for (PacketListener p : ofPacketListener.values()) {
348 p.handlePacket(pktCtx);
349 }
350 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800351 // TODO: Consider using separate threadpool for sensitive messages.
352 // ie. Back to back error could cause us to starve.
353 case FLOW_REMOVED:
Andrea Campanelladda93562016-03-02 11:08:12 -0800354 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800355 break;
Prince Pereirae7798032016-07-08 16:31:58 +0530356 case ERROR:
357 log.debug("Received error message from {}: {}", dpid, msg);
358 errorMsgs.putIfAbsent(msg.getXid(), true);
359 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
360 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700361 case STATS_REPLY:
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700362 processStatsReply(dpid, (OFStatsReply) msg);
alshabib64def642014-12-02 23:27:37 -0800363 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700364 case BARRIER_REPLY:
Prince Pereirae7798032016-07-08 16:31:58 +0530365 if (errorMsgs.containsKey(msg.getXid())) {
366 //To make oferror msg handling and corresponding barrier reply serialized,
367 // executorErrorMsgs is used for both transaction
368 errorMsgs.remove(msg.getXid());
369 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
370 } else {
371 executorBarrier.execute(new OFMessageHandler(dpid, msg));
372 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700373 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700374 case EXPERIMENTER:
sangyun-han69ed4462016-07-27 12:10:12 +0900375 if (sw == null) {
376 log.error("Switch {} is not found", dpid);
377 break;
378 }
Marc De Leenheerb9311372015-07-09 11:36:49 -0700379 long experimenter = ((OFExperimenter) msg).getExperimenter();
380 if (experimenter == 0x748771) {
381 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700382 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
sangyun-han69ed4462016-07-27 12:10:12 +0900383 OFPortStatus.Builder portStatus = sw.factory().buildPortStatus();
384 OFPortDesc.Builder portDesc = sw.factory().buildPortDesc();
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700385 portDesc.setPortNo(circuitPortStatus.getPortNo())
386 .setHwAddr(circuitPortStatus.getHwAddr())
387 .setName(circuitPortStatus.getName())
388 .setConfig(circuitPortStatus.getConfig())
389 .setState(circuitPortStatus.getState());
390 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
391 for (OpenFlowSwitchListener l : ofSwitchListener) {
392 l.portChanged(dpid, portStatus.build());
393 }
394 } else {
395 log.warn("Handling experimenter type {} not yet implemented",
396 ((OFExperimenter) msg).getExperimenter(), msg);
397 }
398 break;
tom7ef8ff92014-09-17 13:08:06 -0700399 default:
400 log.warn("Handling message type {} not yet implemented {}",
401 msg.getType(), msg);
402 }
403 }
404
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700405 private void processStatsReply(Dpid dpid, OFStatsReply reply) {
406 switch (reply.getStatsType()) {
407 case QUEUE:
408 Collection<OFQueueStatsEntry> queueStatsEntries = publishQueueStats(dpid, (OFQueueStatsReply) reply);
409 if (queueStatsEntries != null) {
410 OFQueueStatsReply.Builder rep =
411 OFFactories.getFactory(reply.getVersion()).buildQueueStatsReply();
412 rep.setEntries(ImmutableList.copyOf(queueStatsEntries));
413 rep.setXid(reply.getXid());
414 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
415 }
416 break;
417
418 case PORT_DESC:
419 for (OpenFlowSwitchListener l : ofSwitchListener) {
420 l.switchChanged(dpid);
421 }
422 break;
423
424 case FLOW:
425 Collection<OFFlowStatsEntry> flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
426 if (flowStats != null) {
427 OFFlowStatsReply.Builder rep =
428 OFFactories.getFactory(reply.getVersion()).buildFlowStatsReply();
429 rep.setEntries(ImmutableList.copyOf(flowStats));
430 rep.setXid(reply.getXid());
431 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
432 }
433 break;
Cem Türker3baff672017-10-12 15:09:01 +0300434 case FLOW_LIGHTWEIGHT:
435 Collection<OFFlowLightweightStatsEntry> flowLightweightStats =
436 publishFlowStatsLightweight(dpid, (OFFlowLightweightStatsReply) reply);
437 if (flowLightweightStats != null) {
438 OFFlowLightweightStatsReply.Builder rep =
439 OFFactories.getFactory(reply.getVersion()).buildFlowLightweightStatsReply();
440 rep.setEntries(ImmutableList.copyOf(flowLightweightStats));
441 rep.setXid(reply.getXid());
442 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
443 }
444 break;
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700445 case TABLE:
446 Collection<OFTableStatsEntry> tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
447 if (tableStats != null) {
448 OFTableStatsReply.Builder rep =
449 OFFactories.getFactory(reply.getVersion()).buildTableStatsReply();
450 rep.setEntries(ImmutableList.copyOf(tableStats));
451 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
452 }
453 break;
454
455 case GROUP:
456 Collection<OFGroupStatsEntry> groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
457 if (groupStats != null) {
458 OFGroupStatsReply.Builder rep =
459 OFFactories.getFactory(reply.getVersion()).buildGroupStatsReply();
460 rep.setEntries(ImmutableList.copyOf(groupStats));
461 rep.setXid(reply.getXid());
462 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
463 }
464 break;
465
466 case GROUP_DESC:
467 Collection<OFGroupDescStatsEntry> groupDescStats = publishGroupDescStats(dpid,
468 (OFGroupDescStatsReply) reply);
469 if (groupDescStats != null) {
470 OFGroupDescStatsReply.Builder rep =
471 OFFactories.getFactory(reply.getVersion()).buildGroupDescStatsReply();
472 rep.setEntries(ImmutableList.copyOf(groupDescStats));
473 rep.setXid(reply.getXid());
474 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
475 }
476 break;
477
478 case PORT:
479 executorMsgs.execute(new OFMessageHandler(dpid, reply));
480 break;
481
482 case METER:
483 executorMsgs.execute(new OFMessageHandler(dpid, reply));
484 break;
485
486 case EXPERIMENTER:
487 if (reply instanceof OFCalientFlowStatsReply) {
488 OpenFlowSwitch sw = this.getSwitch(dpid);
489 // Convert Calient flow statistics to regular flow stats
490 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
491 if (sw == null) {
492 log.error("Switch {} is not found", dpid);
493 break;
494 }
495 OFFlowStatsReply.Builder fsr = sw.factory().buildFlowStatsReply();
496 List<OFFlowStatsEntry> entries = new ArrayList<>();
497 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) reply).getEntries()) {
498
499 // Single instruction, i.e., output to port
500 OFActionOutput action = sw.factory()
501 .actions()
502 .buildOutput()
503 .setPort(entry.getOutPort())
504 .build();
505 OFInstruction instruction = sw.factory()
506 .instructions()
507 .applyActions(Collections.singletonList(action));
508 OFFlowStatsEntry fs = sw.factory().buildFlowStatsEntry()
509 .setMatch(entry.getMatch())
510 .setTableId(entry.getTableId())
511 .setDurationSec(entry.getDurationSec())
512 .setDurationNsec(entry.getDurationNsec())
513 .setPriority(entry.getPriority())
514 .setIdleTimeout(entry.getIdleTimeout())
515 .setHardTimeout(entry.getHardTimeout())
516 .setFlags(entry.getFlags())
517 .setCookie(entry.getCookie())
518 .setInstructions(Collections.singletonList(instruction))
519 .build();
520 entries.add(fs);
521 }
522 fsr.setEntries(entries);
523
524 flowStats = publishFlowStats(dpid, fsr.build());
525 if (flowStats != null) {
526 OFFlowStatsReply.Builder rep =
527 sw.factory().buildFlowStatsReply();
528 rep.setEntries(ImmutableList.copyOf(flowStats));
529 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
530 }
531 } else {
532 executorMsgs.execute(new OFMessageHandler(dpid, reply));
533 }
534 break;
535 default:
536 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
537 break;
538 }
539 }
540
sangho6a0bb172015-02-05 12:24:48 -0800541 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
542 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800543 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800544 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800545 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800546 return fullFlowStats.removeAll(dpid);
547 }
548 return null;
549 }
550
Cem Türker3baff672017-10-12 15:09:01 +0300551 private synchronized Collection<OFFlowLightweightStatsEntry> publishFlowStatsLightweight(
552 Dpid dpid,
553 OFFlowLightweightStatsReply reply) {
554 //TODO: Get rid of synchronized
555 fullFlowLightweightStats.putAll(dpid, reply.getEntries());
556 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
557 return fullFlowLightweightStats.removeAll(dpid);
558 }
559 return null;
560 }
561
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700562 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
563 OFTableStatsReply reply) {
564 //TODO: Get rid of synchronized
565 fullTableStats.putAll(dpid, reply.getEntries());
566 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
567 return fullTableStats.removeAll(dpid);
568 }
569 return null;
570 }
571
sangho6a0bb172015-02-05 12:24:48 -0800572 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
573 OFGroupStatsReply reply) {
574 //TODO: Get rid of synchronized
575 fullGroupStats.putAll(dpid, reply.getEntries());
576 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
577 return fullGroupStats.removeAll(dpid);
578 }
579 return null;
580 }
581
582 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
583 OFGroupDescStatsReply reply) {
584 //TODO: Get rid of synchronized
585 fullGroupDescStats.putAll(dpid, reply.getEntries());
586 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
587 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800588 }
589 return null;
590 }
591
Ozge AYAZ60aded22017-06-20 08:35:30 +0000592 private synchronized Collection<OFQueueStatsEntry> publishQueueStats(Dpid dpid, OFQueueStatsReply reply) {
593 fullQueueStats.putAll(dpid, reply.getEntries());
594 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
595 return fullQueueStats.removeAll(dpid);
596 }
597 return null;
598 }
599
tom7ef8ff92014-09-17 13:08:06 -0700600 @Override
601 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700602 final OpenFlowSwitch sw = getSwitch(dpid);
603 if (sw == null) {
604 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
605 return;
606 }
607 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700608 }
609
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700610 class InternalDeviceListener implements DeviceListener {
611
612 @Override
613 public boolean isRelevant(DeviceEvent event) {
Andrea Campanella86e0c562017-11-23 16:38:24 +0100614 return event.subject().type() != CONTROLLER && event.type() == DEVICE_REMOVED
615 && event.subject().id().uri().getScheme().equals(SCHEME);
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700616 }
617
618 @Override
619 public void event(DeviceEvent event) {
620 switch (event.type()) {
621 case DEVICE_ADDED:
622 break;
623 case DEVICE_AVAILABILITY_CHANGED:
624 break;
625 case DEVICE_REMOVED:
626 // Device administratively removed, disconnect
627 Optional.ofNullable(getSwitch(dpid(event.subject().id().uri())))
628 .ifPresent(OpenFlowSwitch::disconnectSwitch);
629 break;
630 case DEVICE_SUSPENDED:
631 break;
632 case DEVICE_UPDATED:
633 break;
634 case PORT_ADDED:
635 break;
636 case PORT_REMOVED:
637 break;
638 case PORT_STATS_UPDATED:
639 break;
640 case PORT_UPDATED:
641 break;
642 default:
643 break;
644
645 }
646
647 }
648
649 }
650
tom7ef8ff92014-09-17 13:08:06 -0700651 /**
652 * Implementation of an OpenFlow Agent which is responsible for
653 * keeping track of connected switches and the state in which
654 * they are.
655 */
656 public class OpenFlowSwitchAgent implements OpenFlowAgent {
657
658 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
659 private final Lock switchLock = new ReentrantLock();
660
661 @Override
662 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700663
tom7ef8ff92014-09-17 13:08:06 -0700664 if (connectedSwitches.get(dpid) != null) {
665 log.error("Trying to add connectedSwitch but found a previous "
666 + "value for dpid: {}", dpid);
667 return false;
668 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700669 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700670 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700671 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700672 l.switchAdded(dpid);
673 }
674 return true;
675 }
676 }
677
678 @Override
679 public boolean validActivation(Dpid dpid) {
680 if (connectedSwitches.get(dpid) == null) {
681 log.error("Trying to activate switch but is not in "
682 + "connected switches: dpid {}. Aborting ..",
683 dpid);
684 return false;
685 }
686 if (activeMasterSwitches.get(dpid) != null ||
687 activeEqualSwitches.get(dpid) != null) {
688 log.error("Trying to activate switch but it is already "
689 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800690 + "Found in activeEqual: {}. Aborting ..",
691 dpid,
692 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
693 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700694 return false;
695 }
696 return true;
697 }
698
699
700 @Override
701 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
702 switchLock.lock();
703 try {
704 if (!validActivation(dpid)) {
705 return false;
706 }
707 activeMasterSwitches.put(dpid, sw);
708 return true;
709 } finally {
710 switchLock.unlock();
711 }
712 }
713
714 @Override
715 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
716 switchLock.lock();
717 try {
718 if (!validActivation(dpid)) {
719 return false;
720 }
721 activeEqualSwitches.put(dpid, sw);
722 log.info("Added Activated EQUAL Switch {}", dpid);
723 return true;
724 } finally {
725 switchLock.unlock();
726 }
727 }
728
729 @Override
730 public void transitionToMasterSwitch(Dpid dpid) {
731 switchLock.lock();
732 try {
733 if (activeMasterSwitches.containsKey(dpid)) {
734 return;
735 }
736 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
737 if (sw == null) {
738 sw = getSwitch(dpid);
739 if (sw == null) {
740 log.error("Transition to master called on sw {}, but switch "
741 + "was not found in controller-cache", dpid);
742 return;
743 }
744 }
745 log.info("Transitioned switch {} to MASTER", dpid);
746 activeMasterSwitches.put(dpid, sw);
747 } finally {
748 switchLock.unlock();
749 }
750 }
751
752
753 @Override
754 public void transitionToEqualSwitch(Dpid dpid) {
755 switchLock.lock();
756 try {
757 if (activeEqualSwitches.containsKey(dpid)) {
758 return;
759 }
760 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
761 if (sw == null) {
762 sw = getSwitch(dpid);
763 if (sw == null) {
764 log.error("Transition to equal called on sw {}, but switch "
765 + "was not found in controller-cache", dpid);
766 return;
767 }
768 }
769 log.info("Transitioned switch {} to EQUAL", dpid);
770 activeEqualSwitches.put(dpid, sw);
771 } finally {
772 switchLock.unlock();
773 }
774
775 }
776
777 @Override
778 public void removeConnectedSwitch(Dpid dpid) {
779 connectedSwitches.remove(dpid);
780 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
781 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700782 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700783 sw = activeEqualSwitches.remove(dpid);
784 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700785 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700786 l.switchRemoved(dpid);
787 }
788 }
789
790 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700791 public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
792 for (OpenFlowMessageListener listener : ofMessageListener) {
793 listener.handleOutgoingMessage(dpid, m);
794 }
795 }
796
797
798 @Override
tom7ef8ff92014-09-17 13:08:06 -0700799 public void processMessage(Dpid dpid, OFMessage m) {
800 processPacket(dpid, m);
Jian Lia78cdb22016-04-21 13:03:58 -0700801
802 for (OpenFlowMessageListener listener : ofMessageListener) {
803 listener.handleIncomingMessage(dpid, m);
804 }
tom7ef8ff92014-09-17 13:08:06 -0700805 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700806
807 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700808 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700809 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700810 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700811 }
812 }
tom7ef8ff92014-09-17 13:08:06 -0700813 }
814
Jian Li152b8852015-12-07 14:47:25 -0800815 /**
Jian Li2266bff2016-04-21 11:01:25 -0700816 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800817 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800818 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700819
Ray Milkey9c9cde42018-01-12 14:22:06 -0800820 final OFMessage msg;
821 final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700822
823 public OFMessageHandler(Dpid dpid, OFMessage msg) {
824 this.msg = msg;
825 this.dpid = dpid;
826 }
827
828 @Override
829 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700830 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700831 listener.handleMessage(dpid, msg);
832 }
833 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700834 }
tom7ef8ff92014-09-17 13:08:06 -0700835}