blob: c07328fad66157dd18677026464fda0aeb400bea [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -070017
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080018import com.google.common.collect.ArrayListMultimap;
alshabib64def642014-12-02 23:27:37 -080019import com.google.common.collect.Lists;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080020import com.google.common.collect.Multimap;
tom7ef8ff92014-09-17 13:08:06 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080024import org.apache.felix.scr.annotations.Modified;
Charles Chan3b00e1b2015-08-26 23:12:52 +080025import org.apache.felix.scr.annotations.Property;
alshabibb452fd72015-04-22 20:46:20 -070026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
tom7ef8ff92014-09-17 13:08:06 -070028import org.apache.felix.scr.annotations.Service;
Charles Chan3b00e1b2015-08-26 23:12:52 +080029import org.onosproject.cfg.ComponentConfigService;
Charles Chanecfdfb72015-11-24 19:05:50 -080030import org.onosproject.core.CoreService;
Thomas Vachuska3358af22015-05-19 18:40:34 -070031import org.onosproject.net.driver.DefaultDriverProviderService;
alshabibb452fd72015-04-22 20:46:20 -070032import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
34import org.onosproject.openflow.controller.Dpid;
35import org.onosproject.openflow.controller.OpenFlowController;
36import org.onosproject.openflow.controller.OpenFlowEventListener;
Jian Lia78cdb22016-04-21 13:03:58 -070037import org.onosproject.openflow.controller.OpenFlowMessageListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.openflow.controller.OpenFlowPacketContext;
39import org.onosproject.openflow.controller.OpenFlowSwitch;
40import org.onosproject.openflow.controller.OpenFlowSwitchListener;
41import org.onosproject.openflow.controller.PacketListener;
42import org.onosproject.openflow.controller.RoleState;
43import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080044import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070045import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
46import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070047import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
48import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080049import org.projectfloodlight.openflow.protocol.OFFactories;
50import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
51import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080052import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
53import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
54import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
55import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070056import org.projectfloodlight.openflow.protocol.OFMessage;
57import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070058import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070059import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
60import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070061import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070062import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080063import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Jian Li2266bff2016-04-21 11:01:25 -070064import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
65import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Marc De Leenheerb9311372015-07-09 11:36:49 -070066import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
67import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080071import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070072import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070073import java.util.LinkedList;
74import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080075import java.util.Set;
76import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080077import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070078import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080079import java.util.concurrent.ExecutorService;
80import java.util.concurrent.Executors;
81import java.util.concurrent.locks.Lock;
82import java.util.concurrent.locks.ReentrantLock;
Jian Li2266bff2016-04-21 11:01:25 -070083
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080084import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070085
86@Component(immediate = true)
87@Service
88public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -080089 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -070090 private static final String DEFAULT_OFPORT = "6633,6653";
Yuta HIGUCHI8552b172016-07-25 12:10:08 -070091 private static final int DEFAULT_WORKER_THREADS = 0;
tom7ef8ff92014-09-17 13:08:06 -070092
93 private static final Logger log =
94 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
95
alshabibb452fd72015-04-22 20:46:20 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -080097 protected CoreService coreService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -0700100 protected DriverService driverService;
101
Thomas Vachuska3358af22015-05-19 18:40:34 -0700102 // References exists merely for sequencing purpose to assure drivers are loaded
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected DefaultDriverProviderService defaultDriverProviderService;
105
Charles Chan3b00e1b2015-08-26 23:12:52 +0800106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected ComponentConfigService cfgService;
108
Brian O'Connore2a399e2015-09-22 15:32:50 -0700109 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
110 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
111 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800112
113 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
Yuta HIGUCHI8552b172016-07-25 12:10:08 -0700114 label = "Number of controller worker threads")
Charles Chan3b00e1b2015-08-26 23:12:52 +0800115 private int workerThreads = DEFAULT_WORKER_THREADS;
116
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800117 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800118 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800119
120 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800121 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700122
Prince Pereirae7798032016-07-08 16:31:58 +0530123 //Separate executor thread for handling error messages and barrier replies for same failed
124 // transactions to avoid context switching of thread
125 protected ExecutorService executorErrorMsgs =
126 Executors.newSingleThreadExecutor(groupedThreads("onos/of", "event-error-msg-%d", log));
127
128 //concurrent hashmap to track failed transactions
129 protected ConcurrentMap<Long, Boolean> errorMsgs =
130 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800131 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700132 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800133 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700134 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800135 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700136 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700137
138 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700139 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700140
141 protected Multimap<Integer, PacketListener> ofPacketListener =
142 ArrayListMultimap.create();
143
Jonathan Hart6d44d192015-05-11 18:01:19 -0700144 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700145
Jian Lia78cdb22016-04-21 13:03:58 -0700146 protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
Jian Li28247b52016-01-07 17:24:15 -0800147
sangho6a0bb172015-02-05 12:24:48 -0800148 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
149 ArrayListMultimap.create();
150
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700151 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
152 ArrayListMultimap.create();
153
sangho6a0bb172015-02-05 12:24:48 -0800154 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
155 ArrayListMultimap.create();
156
157 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800158 ArrayListMultimap.create();
159
sangho538108b2015-04-08 14:29:20 -0700160 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
161 ArrayListMultimap.create();
162
tom7ef8ff92014-09-17 13:08:06 -0700163 private final Controller ctrl = new Controller();
164
165 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800166 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700167 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800168 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700169 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700170 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700171 }
172
Andrea Campanella3556f362016-04-28 15:18:10 -0700173 private void cleanup() {
174 // Close listening channel and all OF channels. Clean information about switches
175 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800176 ctrl.stop();
177 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700178 connectedSwitches.clear();
179 activeMasterSwitches.clear();
180 activeEqualSwitches.clear();
Charles Chanecfdfb72015-11-24 19:05:50 -0800181 }
182
tom7ef8ff92014-09-17 13:08:06 -0700183 @Deactivate
184 public void deactivate() {
Thiago Santos61725402016-08-05 17:58:56 -0300185 cleanup();
Charles Chan3b00e1b2015-08-26 23:12:52 +0800186 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700187 }
188
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800189 @Modified
190 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800191 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700192 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800193 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800194 }
195
tom7ef8ff92014-09-17 13:08:06 -0700196 @Override
197 public Iterable<OpenFlowSwitch> getSwitches() {
198 return connectedSwitches.values();
199 }
200
201 @Override
202 public Iterable<OpenFlowSwitch> getMasterSwitches() {
203 return activeMasterSwitches.values();
204 }
205
206 @Override
207 public Iterable<OpenFlowSwitch> getEqualSwitches() {
208 return activeEqualSwitches.values();
209 }
210
211 @Override
212 public OpenFlowSwitch getSwitch(Dpid dpid) {
213 return connectedSwitches.get(dpid);
214 }
215
216 @Override
217 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
218 return activeMasterSwitches.get(dpid);
219 }
220
221 @Override
222 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
223 return activeEqualSwitches.get(dpid);
224 }
225
226 @Override
227 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700228 if (!ofSwitchListener.contains(listener)) {
229 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700230 }
231 }
232
233 @Override
234 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700235 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700236 }
237
238 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700239 public void addMessageListener(OpenFlowMessageListener listener) {
240 ofMessageListener.add(listener);
241 }
242
243 @Override
244 public void removeMessageListener(OpenFlowMessageListener listener) {
245 ofMessageListener.remove(listener);
246 }
247
248 @Override
tom7ef8ff92014-09-17 13:08:06 -0700249 public void addPacketListener(int priority, PacketListener listener) {
250 ofPacketListener.put(priority, listener);
251 }
252
253 @Override
254 public void removePacketListener(PacketListener listener) {
255 ofPacketListener.values().remove(listener);
256 }
257
258 @Override
alshabibeec3a062014-09-17 18:01:26 -0700259 public void addEventListener(OpenFlowEventListener listener) {
260 ofEventListener.add(listener);
261 }
262
263 @Override
264 public void removeEventListener(OpenFlowEventListener listener) {
265 ofEventListener.remove(listener);
266 }
267
268 @Override
tom7ef8ff92014-09-17 13:08:06 -0700269 public void write(Dpid dpid, OFMessage msg) {
270 this.getSwitch(dpid).sendMsg(msg);
271 }
272
273 @Override
274 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800275 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700276 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800277 Collection<OFGroupStatsEntry> groupStats;
278 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700279 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800280
sangyun-han69ed4462016-07-27 12:10:12 +0900281 OpenFlowSwitch sw = this.getSwitch(dpid);
282
tom7ef8ff92014-09-17 13:08:06 -0700283 switch (msg.getType()) {
284 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700285 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700286 l.portChanged(dpid, (OFPortStatus) msg);
287 }
288 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700289 case FEATURES_REPLY:
290 for (OpenFlowSwitchListener l : ofSwitchListener) {
291 l.switchChanged(dpid);
292 }
293 break;
tom7ef8ff92014-09-17 13:08:06 -0700294 case PACKET_IN:
sangyun-han69ed4462016-07-27 12:10:12 +0900295 if (sw == null) {
296 log.error("Switch {} is not found", dpid);
297 break;
298 }
tom7ef8ff92014-09-17 13:08:06 -0700299 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
sangyun-han69ed4462016-07-27 12:10:12 +0900300 .packetContextFromPacketIn(sw, (OFPacketIn) msg);
tom7ef8ff92014-09-17 13:08:06 -0700301 for (PacketListener p : ofPacketListener.values()) {
302 p.handlePacket(pktCtx);
303 }
304 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800305 // TODO: Consider using separate threadpool for sensitive messages.
306 // ie. Back to back error could cause us to starve.
307 case FLOW_REMOVED:
Andrea Campanelladda93562016-03-02 11:08:12 -0800308 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800309 break;
Prince Pereirae7798032016-07-08 16:31:58 +0530310 case ERROR:
311 log.debug("Received error message from {}: {}", dpid, msg);
312 errorMsgs.putIfAbsent(msg.getXid(), true);
313 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
314 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700315 case STATS_REPLY:
316 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800317 switch (reply.getStatsType()) {
318 case PORT_DESC:
319 for (OpenFlowSwitchListener l : ofSwitchListener) {
320 l.switchChanged(dpid);
321 }
322 break;
323 case FLOW:
324 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
325 if (flowStats != null) {
326 OFFlowStatsReply.Builder rep =
327 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
328 rep.setEntries(Lists.newLinkedList(flowStats));
ssyoon9030fbcd92015-08-17 10:42:07 +0900329 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800330 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800331 }
332 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700333 case TABLE:
334 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
335 if (tableStats != null) {
336 OFTableStatsReply.Builder rep =
337 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
338 rep.setEntries(Lists.newLinkedList(tableStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800339 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700340 }
341 break;
sangho6a0bb172015-02-05 12:24:48 -0800342 case GROUP:
343 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
344 if (groupStats != null) {
345 OFGroupStatsReply.Builder rep =
346 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
347 rep.setEntries(Lists.newLinkedList(groupStats));
348 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800349 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800350 }
351 break;
352 case GROUP_DESC:
353 groupDescStats = publishGroupDescStats(dpid,
354 (OFGroupDescStatsReply) reply);
355 if (groupDescStats != null) {
356 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700357 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800358 rep.setEntries(Lists.newLinkedList(groupDescStats));
359 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800360 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800361 }
362 break;
sangho538108b2015-04-08 14:29:20 -0700363 case PORT:
Andrea Campanelladda93562016-03-02 11:08:12 -0800364 executorMsgs.execute(new OFMessageHandler(dpid, reply));
sangho538108b2015-04-08 14:29:20 -0700365 break;
alshabib5eb79392015-08-19 18:09:55 -0700366 case METER:
Andrea Campanelladda93562016-03-02 11:08:12 -0800367 executorMsgs.execute(new OFMessageHandler(dpid, reply));
alshabib5eb79392015-08-19 18:09:55 -0700368 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700369 case EXPERIMENTER:
370 if (reply instanceof OFCalientFlowStatsReply) {
371 // Convert Calient flow statistics to regular flow stats
372 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
sangyun-han69ed4462016-07-27 12:10:12 +0900373 if (sw == null) {
374 log.error("Switch {} is not found", dpid);
375 break;
376 }
377 OFFlowStatsReply.Builder fsr = sw.factory().buildFlowStatsReply();
Marc De Leenheerb9311372015-07-09 11:36:49 -0700378 List<OFFlowStatsEntry> entries = new LinkedList<>();
379 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
380
381 // Single instruction, i.e., output to port
382 OFActionOutput action = OFFactories
383 .getFactory(msg.getVersion())
384 .actions()
385 .buildOutput()
386 .setPort(entry.getOutPort())
387 .build();
388 OFInstruction instruction = OFFactories
389 .getFactory(msg.getVersion())
390 .instructions()
391 .applyActions(Collections.singletonList(action));
sangyun-han69ed4462016-07-27 12:10:12 +0900392 OFFlowStatsEntry fs = sw.factory().buildFlowStatsEntry()
Marc De Leenheerb9311372015-07-09 11:36:49 -0700393 .setMatch(entry.getMatch())
394 .setTableId(entry.getTableId())
395 .setDurationSec(entry.getDurationSec())
396 .setDurationNsec(entry.getDurationNsec())
397 .setPriority(entry.getPriority())
398 .setIdleTimeout(entry.getIdleTimeout())
399 .setHardTimeout(entry.getHardTimeout())
400 .setFlags(entry.getFlags())
401 .setCookie(entry.getCookie())
402 .setInstructions(Collections.singletonList(instruction))
403 .build();
404 entries.add(fs);
405 }
406 fsr.setEntries(entries);
407
408 flowStats = publishFlowStats(dpid, fsr.build());
409 if (flowStats != null) {
410 OFFlowStatsReply.Builder rep =
411 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
412 rep.setEntries(Lists.newLinkedList(flowStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800413 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700414 }
415 } else {
Andrea Campanelladda93562016-03-02 11:08:12 -0800416 executorMsgs.execute(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700417 }
418 break;
sangho6a0bb172015-02-05 12:24:48 -0800419 default:
alshabib5eb79392015-08-19 18:09:55 -0700420 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700421 break;
alshabib64def642014-12-02 23:27:37 -0800422 }
423 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700424 case BARRIER_REPLY:
Prince Pereirae7798032016-07-08 16:31:58 +0530425 if (errorMsgs.containsKey(msg.getXid())) {
426 //To make oferror msg handling and corresponding barrier reply serialized,
427 // executorErrorMsgs is used for both transaction
428 errorMsgs.remove(msg.getXid());
429 executorErrorMsgs.execute(new OFMessageHandler(dpid, msg));
430 } else {
431 executorBarrier.execute(new OFMessageHandler(dpid, msg));
432 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700433 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700434 case EXPERIMENTER:
sangyun-han69ed4462016-07-27 12:10:12 +0900435 if (sw == null) {
436 log.error("Switch {} is not found", dpid);
437 break;
438 }
Marc De Leenheerb9311372015-07-09 11:36:49 -0700439 long experimenter = ((OFExperimenter) msg).getExperimenter();
440 if (experimenter == 0x748771) {
441 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700442 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
sangyun-han69ed4462016-07-27 12:10:12 +0900443 OFPortStatus.Builder portStatus = sw.factory().buildPortStatus();
444 OFPortDesc.Builder portDesc = sw.factory().buildPortDesc();
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700445 portDesc.setPortNo(circuitPortStatus.getPortNo())
446 .setHwAddr(circuitPortStatus.getHwAddr())
447 .setName(circuitPortStatus.getName())
448 .setConfig(circuitPortStatus.getConfig())
449 .setState(circuitPortStatus.getState());
450 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
451 for (OpenFlowSwitchListener l : ofSwitchListener) {
452 l.portChanged(dpid, portStatus.build());
453 }
454 } else {
455 log.warn("Handling experimenter type {} not yet implemented",
456 ((OFExperimenter) msg).getExperimenter(), msg);
457 }
458 break;
tom7ef8ff92014-09-17 13:08:06 -0700459 default:
460 log.warn("Handling message type {} not yet implemented {}",
461 msg.getType(), msg);
462 }
463 }
464
sangho6a0bb172015-02-05 12:24:48 -0800465 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
466 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800467 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800468 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800469 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800470 return fullFlowStats.removeAll(dpid);
471 }
472 return null;
473 }
474
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700475 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
476 OFTableStatsReply reply) {
477 //TODO: Get rid of synchronized
478 fullTableStats.putAll(dpid, reply.getEntries());
479 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
480 return fullTableStats.removeAll(dpid);
481 }
482 return null;
483 }
484
sangho6a0bb172015-02-05 12:24:48 -0800485 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
486 OFGroupStatsReply reply) {
487 //TODO: Get rid of synchronized
488 fullGroupStats.putAll(dpid, reply.getEntries());
489 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
490 return fullGroupStats.removeAll(dpid);
491 }
492 return null;
493 }
494
495 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
496 OFGroupDescStatsReply reply) {
497 //TODO: Get rid of synchronized
498 fullGroupDescStats.putAll(dpid, reply.getEntries());
499 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
500 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800501 }
502 return null;
503 }
504
sangho538108b2015-04-08 14:29:20 -0700505 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
506 OFPortStatsReply reply) {
507 fullPortStats.putAll(dpid, reply.getEntries());
508 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
509 return fullPortStats.removeAll(dpid);
510 }
511 return null;
512 }
513
tom7ef8ff92014-09-17 13:08:06 -0700514 @Override
515 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700516 final OpenFlowSwitch sw = getSwitch(dpid);
517 if (sw == null) {
518 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
519 return;
520 }
521 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700522 }
523
524 /**
525 * Implementation of an OpenFlow Agent which is responsible for
526 * keeping track of connected switches and the state in which
527 * they are.
528 */
529 public class OpenFlowSwitchAgent implements OpenFlowAgent {
530
531 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
532 private final Lock switchLock = new ReentrantLock();
533
534 @Override
535 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700536
tom7ef8ff92014-09-17 13:08:06 -0700537 if (connectedSwitches.get(dpid) != null) {
538 log.error("Trying to add connectedSwitch but found a previous "
539 + "value for dpid: {}", dpid);
540 return false;
541 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700542 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700543 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700544 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700545 l.switchAdded(dpid);
546 }
547 return true;
548 }
549 }
550
551 @Override
552 public boolean validActivation(Dpid dpid) {
553 if (connectedSwitches.get(dpid) == null) {
554 log.error("Trying to activate switch but is not in "
555 + "connected switches: dpid {}. Aborting ..",
556 dpid);
557 return false;
558 }
559 if (activeMasterSwitches.get(dpid) != null ||
560 activeEqualSwitches.get(dpid) != null) {
561 log.error("Trying to activate switch but it is already "
562 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800563 + "Found in activeEqual: {}. Aborting ..",
564 dpid,
565 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
566 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700567 return false;
568 }
569 return true;
570 }
571
572
573 @Override
574 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
575 switchLock.lock();
576 try {
577 if (!validActivation(dpid)) {
578 return false;
579 }
580 activeMasterSwitches.put(dpid, sw);
581 return true;
582 } finally {
583 switchLock.unlock();
584 }
585 }
586
587 @Override
588 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
589 switchLock.lock();
590 try {
591 if (!validActivation(dpid)) {
592 return false;
593 }
594 activeEqualSwitches.put(dpid, sw);
595 log.info("Added Activated EQUAL Switch {}", dpid);
596 return true;
597 } finally {
598 switchLock.unlock();
599 }
600 }
601
602 @Override
603 public void transitionToMasterSwitch(Dpid dpid) {
604 switchLock.lock();
605 try {
606 if (activeMasterSwitches.containsKey(dpid)) {
607 return;
608 }
609 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
610 if (sw == null) {
611 sw = getSwitch(dpid);
612 if (sw == null) {
613 log.error("Transition to master called on sw {}, but switch "
614 + "was not found in controller-cache", dpid);
615 return;
616 }
617 }
618 log.info("Transitioned switch {} to MASTER", dpid);
619 activeMasterSwitches.put(dpid, sw);
620 } finally {
621 switchLock.unlock();
622 }
623 }
624
625
626 @Override
627 public void transitionToEqualSwitch(Dpid dpid) {
628 switchLock.lock();
629 try {
630 if (activeEqualSwitches.containsKey(dpid)) {
631 return;
632 }
633 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
634 if (sw == null) {
635 sw = getSwitch(dpid);
636 if (sw == null) {
637 log.error("Transition to equal called on sw {}, but switch "
638 + "was not found in controller-cache", dpid);
639 return;
640 }
641 }
642 log.info("Transitioned switch {} to EQUAL", dpid);
643 activeEqualSwitches.put(dpid, sw);
644 } finally {
645 switchLock.unlock();
646 }
647
648 }
649
650 @Override
651 public void removeConnectedSwitch(Dpid dpid) {
652 connectedSwitches.remove(dpid);
653 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
654 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700655 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700656 sw = activeEqualSwitches.remove(dpid);
657 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700658 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700659 l.switchRemoved(dpid);
660 }
661 }
662
663 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700664 public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
665 for (OpenFlowMessageListener listener : ofMessageListener) {
666 listener.handleOutgoingMessage(dpid, m);
667 }
668 }
669
670
671 @Override
tom7ef8ff92014-09-17 13:08:06 -0700672 public void processMessage(Dpid dpid, OFMessage m) {
673 processPacket(dpid, m);
Jian Lia78cdb22016-04-21 13:03:58 -0700674
675 for (OpenFlowMessageListener listener : ofMessageListener) {
676 listener.handleIncomingMessage(dpid, m);
677 }
tom7ef8ff92014-09-17 13:08:06 -0700678 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700679
680 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700681 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700682 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700683 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700684 }
685 }
tom7ef8ff92014-09-17 13:08:06 -0700686 }
687
Jian Li152b8852015-12-07 14:47:25 -0800688 /**
Jian Li2266bff2016-04-21 11:01:25 -0700689 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800690 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800691 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700692
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800693 protected final OFMessage msg;
694 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700695
696 public OFMessageHandler(Dpid dpid, OFMessage msg) {
697 this.msg = msg;
698 this.dpid = dpid;
699 }
700
701 @Override
702 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700703 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700704 listener.handleMessage(dpid, msg);
705 }
706 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700707 }
tom7ef8ff92014-09-17 13:08:06 -0700708}