blob: 4696778129b6f2f0a3b04407904d3c231d9cb525 [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;
Charles Chan3b00e1b2015-08-26 23:12:52 +080021import org.onosproject.cfg.ComponentConfigService;
Charles Chanecfdfb72015-11-24 19:05:50 -080022import org.onosproject.core.CoreService;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070023import org.onosproject.net.DeviceId;
24import org.onosproject.net.config.ConfigFactory;
Brian O'Connor1bd4a9f2018-05-10 22:40:41 -070025import org.onosproject.net.config.NetworkConfigEvent;
26import org.onosproject.net.config.NetworkConfigListener;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070027import org.onosproject.net.config.NetworkConfigRegistry;
28import org.onosproject.net.config.basics.SubjectFactories;
alshabibb452fd72015-04-22 20:46:20 -070029import org.onosproject.net.driver.DriverService;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070030import org.onosproject.openflow.config.OpenFlowDeviceConfig;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
32import org.onosproject.openflow.controller.Dpid;
Anton Chigrin4af4f872019-01-14 17:29:56 +020033import org.onosproject.openflow.controller.OpenFlowClassifierListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.openflow.controller.OpenFlowController;
35import org.onosproject.openflow.controller.OpenFlowEventListener;
Jian Lia78cdb22016-04-21 13:03:58 -070036import org.onosproject.openflow.controller.OpenFlowMessageListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.openflow.controller.OpenFlowPacketContext;
38import org.onosproject.openflow.controller.OpenFlowSwitch;
39import org.onosproject.openflow.controller.OpenFlowSwitchListener;
Anton Chigrin4af4f872019-01-14 17:29:56 +020040import org.onosproject.openflow.controller.OpenFlowListener;
41import org.onosproject.openflow.controller.OpenFlowService;
42import org.onosproject.openflow.controller.OpenFlowEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import 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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070047import org.osgi.service.component.annotations.Activate;
48import org.osgi.service.component.annotations.Component;
49import org.osgi.service.component.annotations.Deactivate;
50import org.osgi.service.component.annotations.Modified;
51import org.osgi.service.component.annotations.Reference;
52import org.osgi.service.component.annotations.ReferenceCardinality;
Marc De Leenheerb9311372015-07-09 11:36:49 -070053import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
54import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070055import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
56import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080057import org.projectfloodlight.openflow.protocol.OFFactories;
Cem Türker3baff672017-10-12 15:09:01 +030058import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsEntry;
59import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib64def642014-12-02 23:27:37 -080060import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
61import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080062import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
63import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
64import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
65import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070066import org.projectfloodlight.openflow.protocol.OFMessage;
67import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070068import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070069import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
tom7ef8ff92014-09-17 13:08:06 -070070import org.projectfloodlight.openflow.protocol.OFPortStatus;
Cem Türker3baff672017-10-12 15:09:01 +030071import org.projectfloodlight.openflow.protocol.OFQueueStatsEntry;
72import org.projectfloodlight.openflow.protocol.OFQueueStatsReply;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070073import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080074import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Jian Li2266bff2016-04-21 11:01:25 -070075import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
76import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Marc De Leenheerb9311372015-07-09 11:36:49 -070077import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
78import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070079import org.slf4j.Logger;
80import org.slf4j.LoggerFactory;
81
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -070082import java.util.ArrayList;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080083import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070084import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070085import java.util.List;
Brian O'Connor1bd4a9f2018-05-10 22:40:41 -070086import java.util.Objects;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080087import java.util.Set;
Marc De Leenheer8aba62f2017-04-25 14:33:37 -070088import java.util.concurrent.CompletableFuture;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080089import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080090import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070091import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080092import java.util.concurrent.ExecutorService;
93import java.util.concurrent.Executors;
94import java.util.concurrent.locks.Lock;
95import java.util.concurrent.locks.ReentrantLock;
Jian Li2266bff2016-04-21 11:01:25 -070096
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080097import static org.onlab.util.Tools.groupedThreads;
Ray Milkey309f9a02018-10-12 14:09:37 -070098import static org.onosproject.openflow.controller.impl.OsgiPropertyConstants.*;
Ozge AYAZ60aded22017-06-20 08:35:30 +000099
Ray Milkey309f9a02018-10-12 14:09:37 -0700100@Component(
101 immediate = true,
102 service = OpenFlowController.class,
103 property = {
104 OFPORTS + "=" + OFPORTS_DEFAULT,
Ray Milkey2d7bca12018-10-17 14:51:52 -0700105 WORKER_THREADS + ":Integer=" + WORKER_THREADS_DEFAULT,
Ray Milkey309f9a02018-10-12 14:09:37 -0700106 TLS_MODE + "=" + TLS_MODE_DEFAULT,
107 KEY_STORE + "=" + KEY_STORE_DEFAULT,
108 KEY_STORE_PASSWORD + "=" + KEY_STORE_PASSWORD_DEFAULT,
109 TRUST_STORE + "=" + TRUST_STORE_DEFAULT,
110 TRUST_STORE_PASSWORD + "=" + TRUST_STORE_PASSWORD_DEFAULT,
Anton Chigrin4af4f872019-01-14 17:29:56 +0200111 DEFAULT_QUEUE_SIZE + ":Integer=" + DEFAULT_QUEUE_SIZE_DEFAULT,
112 DEBAULT_BULK_SIZE + ":Integer=" + BULK_SIZE_DEFAULT,
113 QUEUE_SIZE_N0 + ":Integer=" + QUEUE_SIZE_N0_DEFAULT,
114 BULK_SIZE_N0 + ":Integer=" + BULK_SIZE_DEFAULT,
115 QUEUE_SIZE_N1 + ":Integer=" + QUEUE_SIZE_DEFAULT,
116 BULK_SIZE_N1 + ":Integer=" + BULK_SIZE_DEFAULT,
117 QUEUE_SIZE_N2 + ":Integer=" + QUEUE_SIZE_DEFAULT,
118 BULK_SIZE_N2 + ":Integer=" + BULK_SIZE_DEFAULT,
119 QUEUE_SIZE_N3 + ":Integer=" + QUEUE_SIZE_DEFAULT,
120 BULK_SIZE_N3 + ":Integer=" + BULK_SIZE_DEFAULT,
121 QUEUE_SIZE_N4 + ":Integer=" + QUEUE_SIZE_DEFAULT,
122 BULK_SIZE_N4 + ":Integer=" + BULK_SIZE_DEFAULT,
123 QUEUE_SIZE_N5 + ":Integer=" + QUEUE_SIZE_DEFAULT,
124 BULK_SIZE_N5 + ":Integer=" + BULK_SIZE_DEFAULT,
125 QUEUE_SIZE_N6 + ":Integer=" + QUEUE_SIZE_DEFAULT,
126 BULK_SIZE_N6 + ":Integer=" + BULK_SIZE_DEFAULT,
Ray Milkey309f9a02018-10-12 14:09:37 -0700127 }
128)
Anton Chigrin4af4f872019-01-14 17:29:56 +0200129
tom7ef8ff92014-09-17 13:08:06 -0700130public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -0800131 private static final String APP_ID = "org.onosproject.openflow-base";
Andrea Campanella86e0c562017-11-23 16:38:24 +0100132 protected static final String SCHEME = "of";
tom7ef8ff92014-09-17 13:08:06 -0700133
134 private static final Logger log =
135 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chanecfdfb72015-11-24 19:05:50 -0800138 protected CoreService coreService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibb452fd72015-04-22 20:46:20 -0700141 protected DriverService driverService;
142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chan3b00e1b2015-08-26 23:12:52 +0800144 protected ComponentConfigService cfgService;
145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700147 protected NetworkConfigRegistry netCfgService;
148
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700149 /** Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653. */
Ray Milkeybd508ed2019-03-19 14:22:02 -0700150 private String openflowPorts = OFPORTS_DEFAULT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800151
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700152 /** Number of controller worker threads. */
153 private int workerThreads = WORKER_THREADS_DEFAULT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800154
Anton Chigrin4af4f872019-01-14 17:29:56 +0200155 /** TLS mode for OpenFlow channel; options are: disabled [default], enabled, strict. */
Ray Milkeybd508ed2019-03-19 14:22:02 -0700156 private String tlsMode;
Brian O'Connorf7215b82018-05-10 19:12:44 -0700157
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700158 /** File path to key store for TLS connections. */
159 private String keyStore;
Brian O'Connorf7215b82018-05-10 19:12:44 -0700160
Anton Chigrin4af4f872019-01-14 17:29:56 +0200161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
162 protected OpenFlowService openFlowManager;
163
164 private final OpenFlowListener openFlowListener = new InternalOpenFlowListener();
165
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700166 /** Key store password. */
167 private String keyStorePassword;
Brian O'Connorf7215b82018-05-10 19:12:44 -0700168
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700169 /** File path to trust store for TLS connections. */
170 private String trustStore;
Brian O'Connorf7215b82018-05-10 19:12:44 -0700171
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700172 /** Trust store password. */
173 private String trustStorePassword;
Brian O'Connorf7215b82018-05-10 19:12:44 -0700174
Anton Chigrin4af4f872019-01-14 17:29:56 +0200175 /** Size of deafult queue. */
176 private int defaultQueueSize = DEFAULT_QUEUE_SIZE_DEFAULT;
177
178 /** Size of deafult bulk. */
179 private int defaultBulkSize = BULK_SIZE_DEFAULT;
180
181 /** Size of queue N0. */
182 private int queueSizeN0 = QUEUE_SIZE_N0_DEFAULT;
183
184 /** Size of bulk N0. */
185 private int bulkSizeN0 = BULK_SIZE_DEFAULT;
186
187 /** Size of queue N1. */
188 private int queueSizeN1 = QUEUE_SIZE_DEFAULT;
189
190 /** Size of bulk N1. */
191 private int bulkSizeN1 = BULK_SIZE_DEFAULT;
192
193 /** Size of queue N2. */
194 private int queueSizeN2 = QUEUE_SIZE_DEFAULT;
195
196 /** Size of bulk N2. */
197 private int bulkSizeN2 = BULK_SIZE_DEFAULT;
198
199 /** Size of queue N3. */
200 private int queueSizeN3 = QUEUE_SIZE_DEFAULT;
201
202 /** Size of bulk N3. */
203 private int bulkSizeN3 = BULK_SIZE_DEFAULT;
204
205 /** Size of queue N4. */
206 private int queueSizeN4 = QUEUE_SIZE_DEFAULT;
207
208 /** Size of bulk N4. */
209 private int bulkSizeN4 = BULK_SIZE_DEFAULT;
210
211 /** Size of queue N5. */
212 private int queueSizeN5 = QUEUE_SIZE_DEFAULT;
213
214 /** Size of bulk N5. */
215 private int bulkSizeN5 = BULK_SIZE_DEFAULT;
216
217 /** Size of queue N6. */
218 private int queueSizeN6 = QUEUE_SIZE_DEFAULT;
219
220 /** Size of bulk N6. */
221 private int bulkSizeN6 = BULK_SIZE_DEFAULT;
222
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800223 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800224 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800225
226 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800227 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700228
Prince Pereirae7798032016-07-08 16:31:58 +0530229 //Separate executor thread for handling error messages and barrier replies for same failed
230 // transactions to avoid context switching of thread
231 protected ExecutorService executorErrorMsgs =
232 Executors.newSingleThreadExecutor(groupedThreads("onos/of", "event-error-msg-%d", log));
233
234 //concurrent hashmap to track failed transactions
235 protected ConcurrentMap<Long, Boolean> errorMsgs =
236 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800237 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700238 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800239 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700240 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800241 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700242 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700243
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700244 // Key: dpid, value: map with key: long (XID), value: completable future
245 protected ConcurrentMap<Dpid, ConcurrentMap<Long, CompletableFuture<OFMessage>>> responses =
246 new ConcurrentHashMap<>();
247
tom7ef8ff92014-09-17 13:08:06 -0700248 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700249 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700250
251 protected Multimap<Integer, PacketListener> ofPacketListener =
252 ArrayListMultimap.create();
253
Jonathan Hart6d44d192015-05-11 18:01:19 -0700254 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700255
Anton Chigrin4af4f872019-01-14 17:29:56 +0200256 protected Set<OpenFlowClassifierListener> ofClassifierListener = new CopyOnWriteArraySet<>();
257
Jian Lia78cdb22016-04-21 13:03:58 -0700258 protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
Jian Li28247b52016-01-07 17:24:15 -0800259
sangho6a0bb172015-02-05 12:24:48 -0800260 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
261 ArrayListMultimap.create();
262
Cem Türker3baff672017-10-12 15:09:01 +0300263 protected Multimap<Dpid, OFFlowLightweightStatsEntry> fullFlowLightweightStats =
264 ArrayListMultimap.create();
265
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700266 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
267 ArrayListMultimap.create();
268
sangho6a0bb172015-02-05 12:24:48 -0800269 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
270 ArrayListMultimap.create();
271
272 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800273 ArrayListMultimap.create();
274
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700275 // deprecated in 1.11.0, no longer referenced from anywhere
276 @Deprecated
sangho538108b2015-04-08 14:29:20 -0700277 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
278 ArrayListMultimap.create();
279
Ozge AYAZ60aded22017-06-20 08:35:30 +0000280 protected Multimap<Dpid, OFQueueStatsEntry> fullQueueStats =
281 ArrayListMultimap.create();
282
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700283 protected final ConfigFactory factory =
284 new ConfigFactory<DeviceId, OpenFlowDeviceConfig>(
285 SubjectFactories.DEVICE_SUBJECT_FACTORY,
286 OpenFlowDeviceConfig.class, OpenFlowDeviceConfig.CONFIG_KEY) {
287 @Override
288 public OpenFlowDeviceConfig createConfig() {
289 return new OpenFlowDeviceConfig();
290 }
291 };
292
tom7ef8ff92014-09-17 13:08:06 -0700293 private final Controller ctrl = new Controller();
294
Brian O'Connor1bd4a9f2018-05-10 22:40:41 -0700295 private final NetworkConfigListener netCfgListener = new NetworkConfigListener() {
296 @Override
297 public boolean isRelevant(NetworkConfigEvent event) {
298 return OpenFlowDeviceConfig.class.equals(event.configClass());
299 }
300
301 @Override
302 public void event(NetworkConfigEvent event) {
303 // We only receive NetworkConfigEvents
304 OpenFlowDeviceConfig prevConfig = null;
305 if (event.prevConfig().isPresent()) {
306 prevConfig = (OpenFlowDeviceConfig) event.prevConfig().get();
307 }
308
309 OpenFlowDeviceConfig newConfig = null;
310 if (event.config().isPresent()) {
311 newConfig = (OpenFlowDeviceConfig) event.config().get();
312 }
313
314 boolean closeConnection = false;
315 if (prevConfig != null && newConfig != null) {
316 if (!Objects.equals(prevConfig.keyAlias(), newConfig.keyAlias())) {
317 closeConnection = true;
318 }
319 } else if (prevConfig != null) {
320 // config was removed
321 closeConnection = true;
322 }
323 if (closeConnection) {
324 if (event.subject() instanceof DeviceId) {
325 DeviceId deviceId = (DeviceId) event.subject();
326 Dpid dpid = Dpid.dpid(deviceId.uri());
327 OpenFlowSwitch sw = getSwitch(dpid);
328 if (sw != null && ctrl.tlsParams.mode == Controller.TlsMode.STRICT) {
329 sw.disconnectSwitch();
330 log.info("Disconnecting switch {} because key has been updated or removed", dpid);
331 }
332 }
333 }
334 }
335 };
336
tom7ef8ff92014-09-17 13:08:06 -0700337 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800338 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700339 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800340 cfgService.registerProperties(getClass());
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700341 netCfgService.registerConfigFactory(factory);
Brian O'Connor1bd4a9f2018-05-10 22:40:41 -0700342 netCfgService.addListener(netCfgListener);
Brian O'Connorff278502015-09-22 14:49:52 -0700343 ctrl.setConfigParams(context.getProperties());
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700344 ctrl.start(agent, driverService, netCfgService);
Anton Chigrin4af4f872019-01-14 17:29:56 +0200345 openFlowManager.addListener(openFlowListener);
tom7ef8ff92014-09-17 13:08:06 -0700346 }
347
Andrea Campanella3556f362016-04-28 15:18:10 -0700348 private void cleanup() {
349 // Close listening channel and all OF channels. Clean information about switches
350 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800351 ctrl.stop();
352 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700353 connectedSwitches.clear();
354 activeMasterSwitches.clear();
355 activeEqualSwitches.clear();
Anton Chigrin4af4f872019-01-14 17:29:56 +0200356 openFlowManager.removeListener(openFlowListener);
Charles Chanecfdfb72015-11-24 19:05:50 -0800357 }
358
tom7ef8ff92014-09-17 13:08:06 -0700359 @Deactivate
360 public void deactivate() {
Thiago Santos61725402016-08-05 17:58:56 -0300361 cleanup();
Charles Chan3b00e1b2015-08-26 23:12:52 +0800362 cfgService.unregisterProperties(getClass(), false);
Brian O'Connor1bd4a9f2018-05-10 22:40:41 -0700363 netCfgService.removeListener(netCfgListener);
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700364 netCfgService.unregisterConfigFactory(factory);
tom7ef8ff92014-09-17 13:08:06 -0700365 }
366
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800367 @Modified
368 public void modified(ComponentContext context) {
Brian O'Connorff278502015-09-22 14:49:52 -0700369 ctrl.setConfigParams(context.getProperties());
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800370 }
371
tom7ef8ff92014-09-17 13:08:06 -0700372 @Override
373 public Iterable<OpenFlowSwitch> getSwitches() {
374 return connectedSwitches.values();
375 }
376
377 @Override
378 public Iterable<OpenFlowSwitch> getMasterSwitches() {
379 return activeMasterSwitches.values();
380 }
381
382 @Override
383 public Iterable<OpenFlowSwitch> getEqualSwitches() {
384 return activeEqualSwitches.values();
385 }
386
387 @Override
388 public OpenFlowSwitch getSwitch(Dpid dpid) {
389 return connectedSwitches.get(dpid);
390 }
391
392 @Override
393 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
394 return activeMasterSwitches.get(dpid);
395 }
396
397 @Override
398 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
399 return activeEqualSwitches.get(dpid);
400 }
401
402 @Override
403 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700404 if (!ofSwitchListener.contains(listener)) {
405 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700406 }
407 }
408
409 @Override
410 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700411 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700412 }
413
414 @Override
Anton Chigrin4af4f872019-01-14 17:29:56 +0200415 public void addClassifierListener(OpenFlowClassifierListener listener) {
416 this.ofClassifierListener.add(listener);
417 }
418
419 @Override
420 public void removeClassifierListener(OpenFlowClassifierListener listener) {
421 this.ofClassifierListener.remove(listener);
422 }
423
424 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700425 public void addMessageListener(OpenFlowMessageListener listener) {
426 ofMessageListener.add(listener);
427 }
428
429 @Override
430 public void removeMessageListener(OpenFlowMessageListener listener) {
431 ofMessageListener.remove(listener);
432 }
433
434 @Override
tom7ef8ff92014-09-17 13:08:06 -0700435 public void addPacketListener(int priority, PacketListener listener) {
436 ofPacketListener.put(priority, listener);
437 }
438
439 @Override
440 public void removePacketListener(PacketListener listener) {
441 ofPacketListener.values().remove(listener);
442 }
443
444 @Override
alshabibeec3a062014-09-17 18:01:26 -0700445 public void addEventListener(OpenFlowEventListener listener) {
446 ofEventListener.add(listener);
447 }
448
449 @Override
450 public void removeEventListener(OpenFlowEventListener listener) {
451 ofEventListener.remove(listener);
452 }
453
454 @Override
tom7ef8ff92014-09-17 13:08:06 -0700455 public void write(Dpid dpid, OFMessage msg) {
456 this.getSwitch(dpid).sendMsg(msg);
457 }
458
459 @Override
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700460 public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
461 write(dpid, msg);
462
463 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids =
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700464 responses.computeIfAbsent(dpid, k -> new ConcurrentHashMap<>());
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700465
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700466 CompletableFuture<OFMessage> future = new CompletableFuture<>();
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700467 xids.put(msg.getXid(), future);
468
469 return future;
470 }
471
472 @Override
tom7ef8ff92014-09-17 13:08:06 -0700473 public void processPacket(Dpid dpid, OFMessage msg) {
sangyun-han69ed4462016-07-27 12:10:12 +0900474 OpenFlowSwitch sw = this.getSwitch(dpid);
Laszlo Pappb68fe7e2017-11-24 17:06:59 +0000475 if (log.isTraceEnabled()) {
476 log.trace("Processing message from switch {} via openflow: {}", dpid, msg);
477 }
sangyun-han69ed4462016-07-27 12:10:12 +0900478
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700479 // Check if someone is waiting for this message
480 ConcurrentMap<Long, CompletableFuture<OFMessage>> xids = responses.get(dpid);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700481 if (xids != null) {
482 CompletableFuture<OFMessage> future = xids.remove(msg.getXid());
483 if (future != null) {
484 future.complete(msg);
485 }
Marc De Leenheer8aba62f2017-04-25 14:33:37 -0700486 }
487
tom7ef8ff92014-09-17 13:08:06 -0700488 switch (msg.getType()) {
489 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700490 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700491 l.portChanged(dpid, (OFPortStatus) msg);
492 }
493 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700494 case FEATURES_REPLY:
495 for (OpenFlowSwitchListener l : ofSwitchListener) {
496 l.switchChanged(dpid);
497 }
498 break;
tom7ef8ff92014-09-17 13:08:06 -0700499 case PACKET_IN:
sangyun-han69ed4462016-07-27 12:10:12 +0900500 if (sw == null) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700501 log.error("Ignoring PACKET_IN, switch {} is not found", dpid);
sangyun-han69ed4462016-07-27 12:10:12 +0900502 break;
503 }
tom7ef8ff92014-09-17 13:08:06 -0700504 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
Ozge AYAZ60aded22017-06-20 08:35:30 +0000505 .packetContextFromPacketIn(sw, (OFPacketIn) msg);
tom7ef8ff92014-09-17 13:08:06 -0700506 for (PacketListener p : ofPacketListener.values()) {
507 p.handlePacket(pktCtx);
508 }
509 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800510 // TODO: Consider using separate threadpool for sensitive messages.
511 // ie. Back to back error could cause us to starve.
512 case FLOW_REMOVED:
Andrea Campanelladda93562016-03-02 11:08:12 -0800513 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800514 break;
Prince Pereirae7798032016-07-08 16:31:58 +0530515 case ERROR:
516 log.debug("Received error message from {}: {}", dpid, msg);
517 errorMsgs.putIfAbsent(msg.getXid(), true);
518 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
519 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700520 case STATS_REPLY:
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700521 processStatsReply(dpid, (OFStatsReply) msg);
alshabib64def642014-12-02 23:27:37 -0800522 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700523 case BARRIER_REPLY:
Prince Pereirae7798032016-07-08 16:31:58 +0530524 if (errorMsgs.containsKey(msg.getXid())) {
525 //To make oferror msg handling and corresponding barrier reply serialized,
526 // executorErrorMsgs is used for both transaction
527 errorMsgs.remove(msg.getXid());
528 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
529 } else {
530 executorBarrier.execute(new OFMessageHandler(dpid, msg));
531 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700532 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700533 case EXPERIMENTER:
sangyun-han69ed4462016-07-27 12:10:12 +0900534 if (sw == null) {
535 log.error("Switch {} is not found", dpid);
536 break;
537 }
Marc De Leenheerb9311372015-07-09 11:36:49 -0700538 long experimenter = ((OFExperimenter) msg).getExperimenter();
539 if (experimenter == 0x748771) {
540 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700541 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
sangyun-han69ed4462016-07-27 12:10:12 +0900542 OFPortStatus.Builder portStatus = sw.factory().buildPortStatus();
543 OFPortDesc.Builder portDesc = sw.factory().buildPortDesc();
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700544 portDesc.setPortNo(circuitPortStatus.getPortNo())
545 .setHwAddr(circuitPortStatus.getHwAddr())
546 .setName(circuitPortStatus.getName())
547 .setConfig(circuitPortStatus.getConfig())
548 .setState(circuitPortStatus.getState());
549 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
550 for (OpenFlowSwitchListener l : ofSwitchListener) {
551 l.portChanged(dpid, portStatus.build());
552 }
553 } else {
554 log.warn("Handling experimenter type {} not yet implemented",
555 ((OFExperimenter) msg).getExperimenter(), msg);
556 }
557 break;
tom7ef8ff92014-09-17 13:08:06 -0700558 default:
559 log.warn("Handling message type {} not yet implemented {}",
560 msg.getType(), msg);
561 }
562 }
563
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700564 private void processStatsReply(Dpid dpid, OFStatsReply reply) {
565 switch (reply.getStatsType()) {
566 case QUEUE:
567 Collection<OFQueueStatsEntry> queueStatsEntries = publishQueueStats(dpid, (OFQueueStatsReply) reply);
568 if (queueStatsEntries != null) {
569 OFQueueStatsReply.Builder rep =
570 OFFactories.getFactory(reply.getVersion()).buildQueueStatsReply();
571 rep.setEntries(ImmutableList.copyOf(queueStatsEntries));
572 rep.setXid(reply.getXid());
573 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
574 }
575 break;
576
577 case PORT_DESC:
578 for (OpenFlowSwitchListener l : ofSwitchListener) {
579 l.switchChanged(dpid);
580 }
581 break;
582
583 case FLOW:
584 Collection<OFFlowStatsEntry> flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
585 if (flowStats != null) {
586 OFFlowStatsReply.Builder rep =
587 OFFactories.getFactory(reply.getVersion()).buildFlowStatsReply();
588 rep.setEntries(ImmutableList.copyOf(flowStats));
589 rep.setXid(reply.getXid());
590 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
591 }
592 break;
Cem Türker3baff672017-10-12 15:09:01 +0300593 case FLOW_LIGHTWEIGHT:
594 Collection<OFFlowLightweightStatsEntry> flowLightweightStats =
595 publishFlowStatsLightweight(dpid, (OFFlowLightweightStatsReply) reply);
596 if (flowLightweightStats != null) {
597 OFFlowLightweightStatsReply.Builder rep =
598 OFFactories.getFactory(reply.getVersion()).buildFlowLightweightStatsReply();
599 rep.setEntries(ImmutableList.copyOf(flowLightweightStats));
600 rep.setXid(reply.getXid());
601 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
602 }
603 break;
Yuta HIGUCHI7b41dc92017-06-22 19:37:06 -0700604 case TABLE:
605 Collection<OFTableStatsEntry> tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
606 if (tableStats != null) {
607 OFTableStatsReply.Builder rep =
608 OFFactories.getFactory(reply.getVersion()).buildTableStatsReply();
609 rep.setEntries(ImmutableList.copyOf(tableStats));
610 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
611 }
612 break;
613
614 case GROUP:
615 Collection<OFGroupStatsEntry> groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
616 if (groupStats != null) {
617 OFGroupStatsReply.Builder rep =
618 OFFactories.getFactory(reply.getVersion()).buildGroupStatsReply();
619 rep.setEntries(ImmutableList.copyOf(groupStats));
620 rep.setXid(reply.getXid());
621 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
622 }
623 break;
624
625 case GROUP_DESC:
626 Collection<OFGroupDescStatsEntry> groupDescStats = publishGroupDescStats(dpid,
627 (OFGroupDescStatsReply) reply);
628 if (groupDescStats != null) {
629 OFGroupDescStatsReply.Builder rep =
630 OFFactories.getFactory(reply.getVersion()).buildGroupDescStatsReply();
631 rep.setEntries(ImmutableList.copyOf(groupDescStats));
632 rep.setXid(reply.getXid());
633 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
634 }
635 break;
636
637 case PORT:
638 executorMsgs.execute(new OFMessageHandler(dpid, reply));
639 break;
640
641 case METER:
642 executorMsgs.execute(new OFMessageHandler(dpid, reply));
643 break;
644
645 case EXPERIMENTER:
646 if (reply instanceof OFCalientFlowStatsReply) {
647 OpenFlowSwitch sw = this.getSwitch(dpid);
648 // Convert Calient flow statistics to regular flow stats
649 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
650 if (sw == null) {
651 log.error("Switch {} is not found", dpid);
652 break;
653 }
654 OFFlowStatsReply.Builder fsr = sw.factory().buildFlowStatsReply();
655 List<OFFlowStatsEntry> entries = new ArrayList<>();
656 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) reply).getEntries()) {
657
658 // Single instruction, i.e., output to port
659 OFActionOutput action = sw.factory()
660 .actions()
661 .buildOutput()
662 .setPort(entry.getOutPort())
663 .build();
664 OFInstruction instruction = sw.factory()
665 .instructions()
666 .applyActions(Collections.singletonList(action));
667 OFFlowStatsEntry fs = sw.factory().buildFlowStatsEntry()
668 .setMatch(entry.getMatch())
669 .setTableId(entry.getTableId())
670 .setDurationSec(entry.getDurationSec())
671 .setDurationNsec(entry.getDurationNsec())
672 .setPriority(entry.getPriority())
673 .setIdleTimeout(entry.getIdleTimeout())
674 .setHardTimeout(entry.getHardTimeout())
675 .setFlags(entry.getFlags())
676 .setCookie(entry.getCookie())
677 .setInstructions(Collections.singletonList(instruction))
678 .build();
679 entries.add(fs);
680 }
681 fsr.setEntries(entries);
682
683 flowStats = publishFlowStats(dpid, fsr.build());
684 if (flowStats != null) {
685 OFFlowStatsReply.Builder rep =
686 sw.factory().buildFlowStatsReply();
687 rep.setEntries(ImmutableList.copyOf(flowStats));
688 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
689 }
690 } else {
691 executorMsgs.execute(new OFMessageHandler(dpid, reply));
692 }
693 break;
694 default:
695 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
696 break;
697 }
698 }
699
sangho6a0bb172015-02-05 12:24:48 -0800700 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
701 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800702 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800703 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800704 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800705 return fullFlowStats.removeAll(dpid);
706 }
707 return null;
708 }
709
Cem Türker3baff672017-10-12 15:09:01 +0300710 private synchronized Collection<OFFlowLightweightStatsEntry> publishFlowStatsLightweight(
711 Dpid dpid,
712 OFFlowLightweightStatsReply reply) {
713 //TODO: Get rid of synchronized
714 fullFlowLightweightStats.putAll(dpid, reply.getEntries());
715 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
716 return fullFlowLightweightStats.removeAll(dpid);
717 }
718 return null;
719 }
720
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700721 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
722 OFTableStatsReply reply) {
723 //TODO: Get rid of synchronized
724 fullTableStats.putAll(dpid, reply.getEntries());
725 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
726 return fullTableStats.removeAll(dpid);
727 }
728 return null;
729 }
730
sangho6a0bb172015-02-05 12:24:48 -0800731 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
732 OFGroupStatsReply reply) {
733 //TODO: Get rid of synchronized
734 fullGroupStats.putAll(dpid, reply.getEntries());
735 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
736 return fullGroupStats.removeAll(dpid);
737 }
738 return null;
739 }
740
741 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
742 OFGroupDescStatsReply reply) {
743 //TODO: Get rid of synchronized
744 fullGroupDescStats.putAll(dpid, reply.getEntries());
745 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
746 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800747 }
748 return null;
749 }
750
Ozge AYAZ60aded22017-06-20 08:35:30 +0000751 private synchronized Collection<OFQueueStatsEntry> publishQueueStats(Dpid dpid, OFQueueStatsReply reply) {
752 fullQueueStats.putAll(dpid, reply.getEntries());
753 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
754 return fullQueueStats.removeAll(dpid);
755 }
756 return null;
757 }
758
tom7ef8ff92014-09-17 13:08:06 -0700759 @Override
760 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700761 final OpenFlowSwitch sw = getSwitch(dpid);
762 if (sw == null) {
763 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
764 return;
765 }
766 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700767 }
768
769 /**
770 * Implementation of an OpenFlow Agent which is responsible for
771 * keeping track of connected switches and the state in which
772 * they are.
773 */
774 public class OpenFlowSwitchAgent implements OpenFlowAgent {
775
776 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
777 private final Lock switchLock = new ReentrantLock();
778
779 @Override
780 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700781
tom7ef8ff92014-09-17 13:08:06 -0700782 if (connectedSwitches.get(dpid) != null) {
783 log.error("Trying to add connectedSwitch but found a previous "
784 + "value for dpid: {}", dpid);
785 return false;
786 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700787 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700788 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700789 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700790 l.switchAdded(dpid);
791 }
792 return true;
793 }
794 }
795
796 @Override
797 public boolean validActivation(Dpid dpid) {
798 if (connectedSwitches.get(dpid) == null) {
799 log.error("Trying to activate switch but is not in "
800 + "connected switches: dpid {}. Aborting ..",
801 dpid);
802 return false;
803 }
804 if (activeMasterSwitches.get(dpid) != null ||
805 activeEqualSwitches.get(dpid) != null) {
806 log.error("Trying to activate switch but it is already "
807 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800808 + "Found in activeEqual: {}. Aborting ..",
809 dpid,
810 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
811 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700812 return false;
813 }
814 return true;
815 }
816
817
818 @Override
819 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
820 switchLock.lock();
821 try {
822 if (!validActivation(dpid)) {
823 return false;
824 }
825 activeMasterSwitches.put(dpid, sw);
826 return true;
827 } finally {
828 switchLock.unlock();
829 }
830 }
831
832 @Override
833 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
834 switchLock.lock();
835 try {
836 if (!validActivation(dpid)) {
837 return false;
838 }
839 activeEqualSwitches.put(dpid, sw);
840 log.info("Added Activated EQUAL Switch {}", dpid);
841 return true;
842 } finally {
843 switchLock.unlock();
844 }
845 }
846
847 @Override
848 public void transitionToMasterSwitch(Dpid dpid) {
849 switchLock.lock();
850 try {
851 if (activeMasterSwitches.containsKey(dpid)) {
852 return;
853 }
854 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
855 if (sw == null) {
856 sw = getSwitch(dpid);
857 if (sw == null) {
858 log.error("Transition to master called on sw {}, but switch "
859 + "was not found in controller-cache", dpid);
860 return;
861 }
862 }
863 log.info("Transitioned switch {} to MASTER", dpid);
864 activeMasterSwitches.put(dpid, sw);
865 } finally {
866 switchLock.unlock();
867 }
868 }
869
870
871 @Override
872 public void transitionToEqualSwitch(Dpid dpid) {
873 switchLock.lock();
874 try {
875 if (activeEqualSwitches.containsKey(dpid)) {
876 return;
877 }
878 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
879 if (sw == null) {
880 sw = getSwitch(dpid);
881 if (sw == null) {
882 log.error("Transition to equal called on sw {}, but switch "
883 + "was not found in controller-cache", dpid);
884 return;
885 }
886 }
887 log.info("Transitioned switch {} to EQUAL", dpid);
888 activeEqualSwitches.put(dpid, sw);
889 } finally {
890 switchLock.unlock();
891 }
892
893 }
894
895 @Override
896 public void removeConnectedSwitch(Dpid dpid) {
897 connectedSwitches.remove(dpid);
898 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
899 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700900 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700901 sw = activeEqualSwitches.remove(dpid);
902 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700903 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700904 l.switchRemoved(dpid);
905 }
906 }
907
908 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700909 public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
910 for (OpenFlowMessageListener listener : ofMessageListener) {
911 listener.handleOutgoingMessage(dpid, m);
912 }
913 }
914
915
916 @Override
tom7ef8ff92014-09-17 13:08:06 -0700917 public void processMessage(Dpid dpid, OFMessage m) {
918 processPacket(dpid, m);
Jian Lia78cdb22016-04-21 13:03:58 -0700919
920 for (OpenFlowMessageListener listener : ofMessageListener) {
921 listener.handleIncomingMessage(dpid, m);
922 }
tom7ef8ff92014-09-17 13:08:06 -0700923 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700924
925 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700926 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700927 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700928 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700929 }
930 }
Anton Chigrin4af4f872019-01-14 17:29:56 +0200931
932 @Override
933 public void addClassifierListener(OpenFlowClassifierListener listener) {
934 ofClassifierListener.add(listener);
935 }
936
937 @Override
938 public void removeClassifierListener(OpenFlowClassifierListener listener) {
939 ofClassifierListener.remove(listener);
940 }
tom7ef8ff92014-09-17 13:08:06 -0700941 }
942
Jian Li152b8852015-12-07 14:47:25 -0800943 /**
Jian Li2266bff2016-04-21 11:01:25 -0700944 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800945 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800946 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700947
Ray Milkey9c9cde42018-01-12 14:22:06 -0800948 final OFMessage msg;
949 final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700950
951 public OFMessageHandler(Dpid dpid, OFMessage msg) {
952 this.msg = msg;
953 this.dpid = dpid;
954 }
955
956 @Override
957 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700958 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700959 listener.handleMessage(dpid, msg);
960 }
961 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700962 }
Anton Chigrin4af4f872019-01-14 17:29:56 +0200963
964 private class InternalOpenFlowListener implements OpenFlowListener {
965 public void event(OpenFlowEvent event) {
966 try {
967 switch (event.type()) {
968 case INSERT:
969 for (OpenFlowClassifierListener listener : ofClassifierListener) {
970 listener.handleClassifiersAdd(event.subject());
971 }
972 break;
973 case REMOVE:
974 for (OpenFlowClassifierListener listener : ofClassifierListener) {
975 listener.handleClassifiersRemove(event.subject());
976 }
977 break;
978 default:
979 log.warn("Unknown OpenFlow classifier event type: {}", event.type());
980 break;
981 }
982 } catch (Exception e) {
983 log.error("Internal OpenFlowListener exception: {}", e.getMessage());
984 }
985 }
986 }
tom7ef8ff92014-09-17 13:08:06 -0700987}