blob: ba3eab5231aecc95aab98d8842cbf25e1e82daa0 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -070017
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080018import com.google.common.collect.ArrayListMultimap;
alshabib64def642014-12-02 23:27:37 -080019import com.google.common.collect.Lists;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080020import com.google.common.collect.Multimap;
tom7ef8ff92014-09-17 13:08:06 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080024import org.apache.felix.scr.annotations.Modified;
Charles Chan3b00e1b2015-08-26 23:12:52 +080025import org.apache.felix.scr.annotations.Property;
alshabibb452fd72015-04-22 20:46:20 -070026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
tom7ef8ff92014-09-17 13:08:06 -070028import org.apache.felix.scr.annotations.Service;
Charles Chan3b00e1b2015-08-26 23:12:52 +080029import org.onosproject.cfg.ComponentConfigService;
Charles Chanecfdfb72015-11-24 19:05:50 -080030import org.onosproject.core.CoreService;
Thomas Vachuska3358af22015-05-19 18:40:34 -070031import org.onosproject.net.driver.DefaultDriverProviderService;
alshabibb452fd72015-04-22 20:46:20 -070032import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.openflow.controller.DefaultOpenFlowPacketContext;
34import org.onosproject.openflow.controller.Dpid;
35import org.onosproject.openflow.controller.OpenFlowController;
36import org.onosproject.openflow.controller.OpenFlowEventListener;
37import org.onosproject.openflow.controller.OpenFlowPacketContext;
38import org.onosproject.openflow.controller.OpenFlowSwitch;
39import org.onosproject.openflow.controller.OpenFlowSwitchListener;
40import org.onosproject.openflow.controller.PacketListener;
41import org.onosproject.openflow.controller.RoleState;
42import org.onosproject.openflow.controller.driver.OpenFlowAgent;
Jonathan Hartbbd91d42015-02-27 11:18:04 -080043import org.osgi.service.component.ComponentContext;
Marc De Leenheerb9311372015-07-09 11:36:49 -070044import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsEntry;
45import org.projectfloodlight.openflow.protocol.OFCalientFlowStatsReply;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070046import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
47import org.projectfloodlight.openflow.protocol.OFExperimenter;
alshabib64def642014-12-02 23:27:37 -080048import org.projectfloodlight.openflow.protocol.OFFactories;
49import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
50import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080051import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
52import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
53import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
54import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070055import org.projectfloodlight.openflow.protocol.OFMessage;
56import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070057import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070058import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
59import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070060import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070061import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080062import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
Jian Li2266bff2016-04-21 11:01:25 -070063import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
64import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Marc De Leenheerb9311372015-07-09 11:36:49 -070065import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
66import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
tom7ef8ff92014-09-17 13:08:06 -070067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080070import java.util.Collection;
Marc De Leenheerb9311372015-07-09 11:36:49 -070071import java.util.Collections;
Marc De Leenheerb9311372015-07-09 11:36:49 -070072import java.util.LinkedList;
73import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080074import java.util.Set;
75import java.util.concurrent.ConcurrentHashMap;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080076import java.util.concurrent.ConcurrentMap;
Jonathan Hart6d44d192015-05-11 18:01:19 -070077import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080078import java.util.concurrent.ExecutorService;
79import java.util.concurrent.Executors;
80import java.util.concurrent.locks.Lock;
81import java.util.concurrent.locks.ReentrantLock;
Jian Li2266bff2016-04-21 11:01:25 -070082
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080083import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070084
85@Component(immediate = true)
86@Service
87public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -080088 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -070089 private static final String DEFAULT_OFPORT = "6633,6653";
Charles Chan3b00e1b2015-08-26 23:12:52 +080090 private static final int DEFAULT_WORKER_THREADS = 16;
tom7ef8ff92014-09-17 13:08:06 -070091
92 private static final Logger log =
93 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
94
alshabibb452fd72015-04-22 20:46:20 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -080096 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -070099 protected DriverService driverService;
100
Thomas Vachuska3358af22015-05-19 18:40:34 -0700101 // References exists merely for sequencing purpose to assure drivers are loaded
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected DefaultDriverProviderService defaultDriverProviderService;
104
Charles Chan3b00e1b2015-08-26 23:12:52 +0800105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected ComponentConfigService cfgService;
107
Brian O'Connore2a399e2015-09-22 15:32:50 -0700108 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
109 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
110 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800111
112 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
113 label = "Number of controller worker threads; default is 16")
114 private int workerThreads = DEFAULT_WORKER_THREADS;
115
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800116 protected ExecutorService executorMsgs =
Andrea Campanelladda93562016-03-02 11:08:12 -0800117 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d", log));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800118
119 private final ExecutorService executorBarrier =
Andrea Campanelladda93562016-03-02 11:08:12 -0800120 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d", log));
alshabib8f1cf4a2014-09-17 14:44:48 -0700121
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800122 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700123 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800124 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700125 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800126 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700127 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700128
129 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700130 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700131
132 protected Multimap<Integer, PacketListener> ofPacketListener =
133 ArrayListMultimap.create();
134
Jonathan Hart6d44d192015-05-11 18:01:19 -0700135 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700136
Jian Li28247b52016-01-07 17:24:15 -0800137 protected boolean monitorAllEvents = false;
138
sangho6a0bb172015-02-05 12:24:48 -0800139 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
140 ArrayListMultimap.create();
141
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700142 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
143 ArrayListMultimap.create();
144
sangho6a0bb172015-02-05 12:24:48 -0800145 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
146 ArrayListMultimap.create();
147
148 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800149 ArrayListMultimap.create();
150
sangho538108b2015-04-08 14:29:20 -0700151 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
152 ArrayListMultimap.create();
153
tom7ef8ff92014-09-17 13:08:06 -0700154 private final Controller ctrl = new Controller();
155
156 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800157 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700158 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800159 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700160 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700161 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700162 }
163
Andrea Campanella3556f362016-04-28 15:18:10 -0700164 private void cleanup() {
165 // Close listening channel and all OF channels. Clean information about switches
166 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800167 ctrl.stop();
168 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700169 connectedSwitches.clear();
170 activeMasterSwitches.clear();
171 activeEqualSwitches.clear();
Charles Chanecfdfb72015-11-24 19:05:50 -0800172 }
173
tom7ef8ff92014-09-17 13:08:06 -0700174 @Deactivate
175 public void deactivate() {
Andrea Campanella3556f362016-04-28 15:18:10 -0700176 if (!connectedSwitches.isEmpty()) {
177 cleanup();
178 }
Charles Chan3b00e1b2015-08-26 23:12:52 +0800179 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700180 }
181
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800182 @Modified
183 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800184 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700185 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800186 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800187 }
188
tom7ef8ff92014-09-17 13:08:06 -0700189 @Override
190 public Iterable<OpenFlowSwitch> getSwitches() {
191 return connectedSwitches.values();
192 }
193
194 @Override
195 public Iterable<OpenFlowSwitch> getMasterSwitches() {
196 return activeMasterSwitches.values();
197 }
198
199 @Override
200 public Iterable<OpenFlowSwitch> getEqualSwitches() {
201 return activeEqualSwitches.values();
202 }
203
204 @Override
205 public OpenFlowSwitch getSwitch(Dpid dpid) {
206 return connectedSwitches.get(dpid);
207 }
208
209 @Override
210 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
211 return activeMasterSwitches.get(dpid);
212 }
213
214 @Override
215 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
216 return activeEqualSwitches.get(dpid);
217 }
218
219 @Override
Jian Li28247b52016-01-07 17:24:15 -0800220 public void monitorAllEvents(boolean monitor) {
221 this.monitorAllEvents = monitor;
222 }
223
224 @Override
tom7ef8ff92014-09-17 13:08:06 -0700225 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700226 if (!ofSwitchListener.contains(listener)) {
227 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700228 }
229 }
230
231 @Override
232 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700233 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700234 }
235
236 @Override
237 public void addPacketListener(int priority, PacketListener listener) {
238 ofPacketListener.put(priority, listener);
239 }
240
241 @Override
242 public void removePacketListener(PacketListener listener) {
243 ofPacketListener.values().remove(listener);
244 }
245
246 @Override
alshabibeec3a062014-09-17 18:01:26 -0700247 public void addEventListener(OpenFlowEventListener listener) {
248 ofEventListener.add(listener);
249 }
250
251 @Override
252 public void removeEventListener(OpenFlowEventListener listener) {
253 ofEventListener.remove(listener);
254 }
255
256 @Override
tom7ef8ff92014-09-17 13:08:06 -0700257 public void write(Dpid dpid, OFMessage msg) {
258 this.getSwitch(dpid).sendMsg(msg);
259 }
260
261 @Override
262 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800263 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700264 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800265 Collection<OFGroupStatsEntry> groupStats;
266 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700267 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800268
tom7ef8ff92014-09-17 13:08:06 -0700269 switch (msg.getType()) {
270 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700271 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700272 l.portChanged(dpid, (OFPortStatus) msg);
273 }
274 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700275 case FEATURES_REPLY:
276 for (OpenFlowSwitchListener l : ofSwitchListener) {
277 l.switchChanged(dpid);
278 }
279 break;
tom7ef8ff92014-09-17 13:08:06 -0700280 case PACKET_IN:
281 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
282 .packetContextFromPacketIn(this.getSwitch(dpid),
283 (OFPacketIn) msg);
284 for (PacketListener p : ofPacketListener.values()) {
285 p.handlePacket(pktCtx);
286 }
287 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800288 // TODO: Consider using separate threadpool for sensitive messages.
289 // ie. Back to back error could cause us to starve.
290 case FLOW_REMOVED:
291 case ERROR:
Andrea Campanelladda93562016-03-02 11:08:12 -0800292 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800293 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700294 case STATS_REPLY:
295 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800296 switch (reply.getStatsType()) {
297 case PORT_DESC:
298 for (OpenFlowSwitchListener l : ofSwitchListener) {
299 l.switchChanged(dpid);
300 }
301 break;
302 case FLOW:
303 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
304 if (flowStats != null) {
305 OFFlowStatsReply.Builder rep =
306 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
307 rep.setEntries(Lists.newLinkedList(flowStats));
ssyoon9030fbcd92015-08-17 10:42:07 +0900308 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800309 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800310 }
311 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700312 case TABLE:
313 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
314 if (tableStats != null) {
315 OFTableStatsReply.Builder rep =
316 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
317 rep.setEntries(Lists.newLinkedList(tableStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800318 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700319 }
320 break;
sangho6a0bb172015-02-05 12:24:48 -0800321 case GROUP:
322 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
323 if (groupStats != null) {
324 OFGroupStatsReply.Builder rep =
325 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
326 rep.setEntries(Lists.newLinkedList(groupStats));
327 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800328 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800329 }
330 break;
331 case GROUP_DESC:
332 groupDescStats = publishGroupDescStats(dpid,
333 (OFGroupDescStatsReply) reply);
334 if (groupDescStats != null) {
335 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700336 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800337 rep.setEntries(Lists.newLinkedList(groupDescStats));
338 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800339 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800340 }
341 break;
sangho538108b2015-04-08 14:29:20 -0700342 case PORT:
Andrea Campanelladda93562016-03-02 11:08:12 -0800343 executorMsgs.execute(new OFMessageHandler(dpid, reply));
sangho538108b2015-04-08 14:29:20 -0700344 break;
alshabib5eb79392015-08-19 18:09:55 -0700345 case METER:
Andrea Campanelladda93562016-03-02 11:08:12 -0800346 executorMsgs.execute(new OFMessageHandler(dpid, reply));
alshabib5eb79392015-08-19 18:09:55 -0700347 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700348 case EXPERIMENTER:
349 if (reply instanceof OFCalientFlowStatsReply) {
350 // Convert Calient flow statistics to regular flow stats
351 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
352 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
353 List<OFFlowStatsEntry> entries = new LinkedList<>();
354 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
355
356 // Single instruction, i.e., output to port
357 OFActionOutput action = OFFactories
358 .getFactory(msg.getVersion())
359 .actions()
360 .buildOutput()
361 .setPort(entry.getOutPort())
362 .build();
363 OFInstruction instruction = OFFactories
364 .getFactory(msg.getVersion())
365 .instructions()
366 .applyActions(Collections.singletonList(action));
367 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
368 .setMatch(entry.getMatch())
369 .setTableId(entry.getTableId())
370 .setDurationSec(entry.getDurationSec())
371 .setDurationNsec(entry.getDurationNsec())
372 .setPriority(entry.getPriority())
373 .setIdleTimeout(entry.getIdleTimeout())
374 .setHardTimeout(entry.getHardTimeout())
375 .setFlags(entry.getFlags())
376 .setCookie(entry.getCookie())
377 .setInstructions(Collections.singletonList(instruction))
378 .build();
379 entries.add(fs);
380 }
381 fsr.setEntries(entries);
382
383 flowStats = publishFlowStats(dpid, fsr.build());
384 if (flowStats != null) {
385 OFFlowStatsReply.Builder rep =
386 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
387 rep.setEntries(Lists.newLinkedList(flowStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800388 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700389 }
390 } else {
Andrea Campanelladda93562016-03-02 11:08:12 -0800391 executorMsgs.execute(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700392 }
393 break;
sangho6a0bb172015-02-05 12:24:48 -0800394 default:
alshabib5eb79392015-08-19 18:09:55 -0700395 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700396 break;
alshabib64def642014-12-02 23:27:37 -0800397 }
398 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700399 case BARRIER_REPLY:
Andrea Campanelladda93562016-03-02 11:08:12 -0800400 executorBarrier.execute(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700401 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700402 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700403 long experimenter = ((OFExperimenter) msg).getExperimenter();
404 if (experimenter == 0x748771) {
405 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700406 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
407 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
408 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
409 portDesc.setPortNo(circuitPortStatus.getPortNo())
410 .setHwAddr(circuitPortStatus.getHwAddr())
411 .setName(circuitPortStatus.getName())
412 .setConfig(circuitPortStatus.getConfig())
413 .setState(circuitPortStatus.getState());
414 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
415 for (OpenFlowSwitchListener l : ofSwitchListener) {
416 l.portChanged(dpid, portStatus.build());
417 }
418 } else {
419 log.warn("Handling experimenter type {} not yet implemented",
420 ((OFExperimenter) msg).getExperimenter(), msg);
421 }
422 break;
tom7ef8ff92014-09-17 13:08:06 -0700423 default:
424 log.warn("Handling message type {} not yet implemented {}",
425 msg.getType(), msg);
426 }
427 }
428
sangho6a0bb172015-02-05 12:24:48 -0800429 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
430 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800431 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800432 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800433 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800434 return fullFlowStats.removeAll(dpid);
435 }
436 return null;
437 }
438
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700439 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
440 OFTableStatsReply reply) {
441 //TODO: Get rid of synchronized
442 fullTableStats.putAll(dpid, reply.getEntries());
443 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
444 return fullTableStats.removeAll(dpid);
445 }
446 return null;
447 }
448
sangho6a0bb172015-02-05 12:24:48 -0800449 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
450 OFGroupStatsReply reply) {
451 //TODO: Get rid of synchronized
452 fullGroupStats.putAll(dpid, reply.getEntries());
453 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
454 return fullGroupStats.removeAll(dpid);
455 }
456 return null;
457 }
458
459 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
460 OFGroupDescStatsReply reply) {
461 //TODO: Get rid of synchronized
462 fullGroupDescStats.putAll(dpid, reply.getEntries());
463 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
464 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800465 }
466 return null;
467 }
468
sangho538108b2015-04-08 14:29:20 -0700469 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
470 OFPortStatsReply reply) {
471 fullPortStats.putAll(dpid, reply.getEntries());
472 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
473 return fullPortStats.removeAll(dpid);
474 }
475 return null;
476 }
477
tom7ef8ff92014-09-17 13:08:06 -0700478 @Override
479 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700480 final OpenFlowSwitch sw = getSwitch(dpid);
481 if (sw == null) {
482 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
483 return;
484 }
485 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700486 }
487
488 /**
489 * Implementation of an OpenFlow Agent which is responsible for
490 * keeping track of connected switches and the state in which
491 * they are.
492 */
493 public class OpenFlowSwitchAgent implements OpenFlowAgent {
494
495 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
496 private final Lock switchLock = new ReentrantLock();
497
498 @Override
499 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700500
tom7ef8ff92014-09-17 13:08:06 -0700501 if (connectedSwitches.get(dpid) != null) {
502 log.error("Trying to add connectedSwitch but found a previous "
503 + "value for dpid: {}", dpid);
504 return false;
505 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700506 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700507 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700508 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700509 l.switchAdded(dpid);
510 }
511 return true;
512 }
513 }
514
515 @Override
516 public boolean validActivation(Dpid dpid) {
517 if (connectedSwitches.get(dpid) == null) {
518 log.error("Trying to activate switch but is not in "
519 + "connected switches: dpid {}. Aborting ..",
520 dpid);
521 return false;
522 }
523 if (activeMasterSwitches.get(dpid) != null ||
524 activeEqualSwitches.get(dpid) != null) {
525 log.error("Trying to activate switch but it is already "
526 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800527 + "Found in activeEqual: {}. Aborting ..",
528 dpid,
529 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
530 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700531 return false;
532 }
533 return true;
534 }
535
536
537 @Override
538 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
539 switchLock.lock();
540 try {
541 if (!validActivation(dpid)) {
542 return false;
543 }
544 activeMasterSwitches.put(dpid, sw);
545 return true;
546 } finally {
547 switchLock.unlock();
548 }
549 }
550
551 @Override
552 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
553 switchLock.lock();
554 try {
555 if (!validActivation(dpid)) {
556 return false;
557 }
558 activeEqualSwitches.put(dpid, sw);
559 log.info("Added Activated EQUAL Switch {}", dpid);
560 return true;
561 } finally {
562 switchLock.unlock();
563 }
564 }
565
566 @Override
567 public void transitionToMasterSwitch(Dpid dpid) {
568 switchLock.lock();
569 try {
570 if (activeMasterSwitches.containsKey(dpid)) {
571 return;
572 }
573 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
574 if (sw == null) {
575 sw = getSwitch(dpid);
576 if (sw == null) {
577 log.error("Transition to master called on sw {}, but switch "
578 + "was not found in controller-cache", dpid);
579 return;
580 }
581 }
582 log.info("Transitioned switch {} to MASTER", dpid);
583 activeMasterSwitches.put(dpid, sw);
584 } finally {
585 switchLock.unlock();
586 }
587 }
588
589
590 @Override
591 public void transitionToEqualSwitch(Dpid dpid) {
592 switchLock.lock();
593 try {
594 if (activeEqualSwitches.containsKey(dpid)) {
595 return;
596 }
597 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
598 if (sw == null) {
599 sw = getSwitch(dpid);
600 if (sw == null) {
601 log.error("Transition to equal called on sw {}, but switch "
602 + "was not found in controller-cache", dpid);
603 return;
604 }
605 }
606 log.info("Transitioned switch {} to EQUAL", dpid);
607 activeEqualSwitches.put(dpid, sw);
608 } finally {
609 switchLock.unlock();
610 }
611
612 }
613
614 @Override
615 public void removeConnectedSwitch(Dpid dpid) {
616 connectedSwitches.remove(dpid);
617 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
618 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700619 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700620 sw = activeEqualSwitches.remove(dpid);
621 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700622 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700623 l.switchRemoved(dpid);
624 }
625 }
626
627 @Override
628 public void processMessage(Dpid dpid, OFMessage m) {
629 processPacket(dpid, m);
630 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700631
632 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700633 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700634 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700635 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700636 }
637 }
tom7ef8ff92014-09-17 13:08:06 -0700638 }
639
Jian Li152b8852015-12-07 14:47:25 -0800640 /**
Jian Li2266bff2016-04-21 11:01:25 -0700641 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800642 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800643 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700644
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800645 protected final OFMessage msg;
646 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700647
648 public OFMessageHandler(Dpid dpid, OFMessage msg) {
649 this.msg = msg;
650 this.dpid = dpid;
651 }
652
653 @Override
654 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700655 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700656 listener.handleMessage(dpid, msg);
657 }
658 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700659 }
tom7ef8ff92014-09-17 13:08:06 -0700660}