blob: 43b91fd80153b8c011416b73ce7df6d4ce255510 [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";
Charles Chan3b00e1b2015-08-26 23:12:52 +080091 private static final int DEFAULT_WORKER_THREADS = 16;
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,
114 label = "Number of controller worker threads; default is 16")
115 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
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800123 protected ConcurrentMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700124 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800125 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700126 new ConcurrentHashMap<>();
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800127 protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700128 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700129
130 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700131 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700132
133 protected Multimap<Integer, PacketListener> ofPacketListener =
134 ArrayListMultimap.create();
135
Jonathan Hart6d44d192015-05-11 18:01:19 -0700136 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700137
Jian Lia78cdb22016-04-21 13:03:58 -0700138 protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
Jian Li28247b52016-01-07 17:24:15 -0800139
sangho6a0bb172015-02-05 12:24:48 -0800140 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
141 ArrayListMultimap.create();
142
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700143 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
144 ArrayListMultimap.create();
145
sangho6a0bb172015-02-05 12:24:48 -0800146 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
147 ArrayListMultimap.create();
148
149 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800150 ArrayListMultimap.create();
151
sangho538108b2015-04-08 14:29:20 -0700152 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
153 ArrayListMultimap.create();
154
tom7ef8ff92014-09-17 13:08:06 -0700155 private final Controller ctrl = new Controller();
156
157 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800158 public void activate(ComponentContext context) {
Andrea Campanella3556f362016-04-28 15:18:10 -0700159 coreService.registerApplication(APP_ID, this::cleanup);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800160 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700161 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700162 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700163 }
164
Andrea Campanella3556f362016-04-28 15:18:10 -0700165 private void cleanup() {
166 // Close listening channel and all OF channels. Clean information about switches
167 // before deactivating
Charles Chanecfdfb72015-11-24 19:05:50 -0800168 ctrl.stop();
169 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
Andrea Campanella3556f362016-04-28 15:18:10 -0700170 connectedSwitches.clear();
171 activeMasterSwitches.clear();
172 activeEqualSwitches.clear();
Charles Chanecfdfb72015-11-24 19:05:50 -0800173 }
174
tom7ef8ff92014-09-17 13:08:06 -0700175 @Deactivate
176 public void deactivate() {
Andrea Campanella3556f362016-04-28 15:18:10 -0700177 if (!connectedSwitches.isEmpty()) {
178 cleanup();
179 }
Charles Chan3b00e1b2015-08-26 23:12:52 +0800180 cfgService.unregisterProperties(getClass(), false);
tom7ef8ff92014-09-17 13:08:06 -0700181 }
182
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800183 @Modified
184 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800185 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700186 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800187 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800188 }
189
tom7ef8ff92014-09-17 13:08:06 -0700190 @Override
191 public Iterable<OpenFlowSwitch> getSwitches() {
192 return connectedSwitches.values();
193 }
194
195 @Override
196 public Iterable<OpenFlowSwitch> getMasterSwitches() {
197 return activeMasterSwitches.values();
198 }
199
200 @Override
201 public Iterable<OpenFlowSwitch> getEqualSwitches() {
202 return activeEqualSwitches.values();
203 }
204
205 @Override
206 public OpenFlowSwitch getSwitch(Dpid dpid) {
207 return connectedSwitches.get(dpid);
208 }
209
210 @Override
211 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
212 return activeMasterSwitches.get(dpid);
213 }
214
215 @Override
216 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
217 return activeEqualSwitches.get(dpid);
218 }
219
220 @Override
221 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700222 if (!ofSwitchListener.contains(listener)) {
223 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700224 }
225 }
226
227 @Override
228 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700229 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700230 }
231
232 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700233 public void addMessageListener(OpenFlowMessageListener listener) {
234 ofMessageListener.add(listener);
235 }
236
237 @Override
238 public void removeMessageListener(OpenFlowMessageListener listener) {
239 ofMessageListener.remove(listener);
240 }
241
242 @Override
tom7ef8ff92014-09-17 13:08:06 -0700243 public void addPacketListener(int priority, PacketListener listener) {
244 ofPacketListener.put(priority, listener);
245 }
246
247 @Override
248 public void removePacketListener(PacketListener listener) {
249 ofPacketListener.values().remove(listener);
250 }
251
252 @Override
alshabibeec3a062014-09-17 18:01:26 -0700253 public void addEventListener(OpenFlowEventListener listener) {
254 ofEventListener.add(listener);
255 }
256
257 @Override
258 public void removeEventListener(OpenFlowEventListener listener) {
259 ofEventListener.remove(listener);
260 }
261
262 @Override
tom7ef8ff92014-09-17 13:08:06 -0700263 public void write(Dpid dpid, OFMessage msg) {
264 this.getSwitch(dpid).sendMsg(msg);
265 }
266
267 @Override
268 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800269 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700270 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800271 Collection<OFGroupStatsEntry> groupStats;
272 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700273 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800274
tom7ef8ff92014-09-17 13:08:06 -0700275 switch (msg.getType()) {
276 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700277 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700278 l.portChanged(dpid, (OFPortStatus) msg);
279 }
280 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700281 case FEATURES_REPLY:
282 for (OpenFlowSwitchListener l : ofSwitchListener) {
283 l.switchChanged(dpid);
284 }
285 break;
tom7ef8ff92014-09-17 13:08:06 -0700286 case PACKET_IN:
287 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
288 .packetContextFromPacketIn(this.getSwitch(dpid),
289 (OFPacketIn) msg);
290 for (PacketListener p : ofPacketListener.values()) {
291 p.handlePacket(pktCtx);
292 }
293 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800294 // TODO: Consider using separate threadpool for sensitive messages.
295 // ie. Back to back error could cause us to starve.
296 case FLOW_REMOVED:
297 case ERROR:
Andrea Campanelladda93562016-03-02 11:08:12 -0800298 executorMsgs.execute(new OFMessageHandler(dpid, msg));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800299 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700300 case STATS_REPLY:
301 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800302 switch (reply.getStatsType()) {
303 case PORT_DESC:
304 for (OpenFlowSwitchListener l : ofSwitchListener) {
305 l.switchChanged(dpid);
306 }
307 break;
308 case FLOW:
309 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
310 if (flowStats != null) {
311 OFFlowStatsReply.Builder rep =
312 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
313 rep.setEntries(Lists.newLinkedList(flowStats));
ssyoon9030fbcd92015-08-17 10:42:07 +0900314 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800315 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800316 }
317 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700318 case TABLE:
319 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
320 if (tableStats != null) {
321 OFTableStatsReply.Builder rep =
322 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
323 rep.setEntries(Lists.newLinkedList(tableStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800324 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700325 }
326 break;
sangho6a0bb172015-02-05 12:24:48 -0800327 case GROUP:
328 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
329 if (groupStats != null) {
330 OFGroupStatsReply.Builder rep =
331 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
332 rep.setEntries(Lists.newLinkedList(groupStats));
333 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800334 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800335 }
336 break;
337 case GROUP_DESC:
338 groupDescStats = publishGroupDescStats(dpid,
339 (OFGroupDescStatsReply) reply);
340 if (groupDescStats != null) {
341 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700342 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800343 rep.setEntries(Lists.newLinkedList(groupDescStats));
344 rep.setXid(reply.getXid());
Andrea Campanelladda93562016-03-02 11:08:12 -0800345 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
sangho6a0bb172015-02-05 12:24:48 -0800346 }
347 break;
sangho538108b2015-04-08 14:29:20 -0700348 case PORT:
Andrea Campanelladda93562016-03-02 11:08:12 -0800349 executorMsgs.execute(new OFMessageHandler(dpid, reply));
sangho538108b2015-04-08 14:29:20 -0700350 break;
alshabib5eb79392015-08-19 18:09:55 -0700351 case METER:
Andrea Campanelladda93562016-03-02 11:08:12 -0800352 executorMsgs.execute(new OFMessageHandler(dpid, reply));
alshabib5eb79392015-08-19 18:09:55 -0700353 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700354 case EXPERIMENTER:
355 if (reply instanceof OFCalientFlowStatsReply) {
356 // Convert Calient flow statistics to regular flow stats
357 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
358 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
359 List<OFFlowStatsEntry> entries = new LinkedList<>();
360 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
361
362 // Single instruction, i.e., output to port
363 OFActionOutput action = OFFactories
364 .getFactory(msg.getVersion())
365 .actions()
366 .buildOutput()
367 .setPort(entry.getOutPort())
368 .build();
369 OFInstruction instruction = OFFactories
370 .getFactory(msg.getVersion())
371 .instructions()
372 .applyActions(Collections.singletonList(action));
373 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
374 .setMatch(entry.getMatch())
375 .setTableId(entry.getTableId())
376 .setDurationSec(entry.getDurationSec())
377 .setDurationNsec(entry.getDurationNsec())
378 .setPriority(entry.getPriority())
379 .setIdleTimeout(entry.getIdleTimeout())
380 .setHardTimeout(entry.getHardTimeout())
381 .setFlags(entry.getFlags())
382 .setCookie(entry.getCookie())
383 .setInstructions(Collections.singletonList(instruction))
384 .build();
385 entries.add(fs);
386 }
387 fsr.setEntries(entries);
388
389 flowStats = publishFlowStats(dpid, fsr.build());
390 if (flowStats != null) {
391 OFFlowStatsReply.Builder rep =
392 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
393 rep.setEntries(Lists.newLinkedList(flowStats));
Andrea Campanelladda93562016-03-02 11:08:12 -0800394 executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700395 }
396 } else {
Andrea Campanelladda93562016-03-02 11:08:12 -0800397 executorMsgs.execute(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700398 }
399 break;
sangho6a0bb172015-02-05 12:24:48 -0800400 default:
alshabib5eb79392015-08-19 18:09:55 -0700401 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700402 break;
alshabib64def642014-12-02 23:27:37 -0800403 }
404 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700405 case BARRIER_REPLY:
Andrea Campanelladda93562016-03-02 11:08:12 -0800406 executorBarrier.execute(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700407 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700408 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700409 long experimenter = ((OFExperimenter) msg).getExperimenter();
410 if (experimenter == 0x748771) {
411 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700412 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
413 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
414 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
415 portDesc.setPortNo(circuitPortStatus.getPortNo())
416 .setHwAddr(circuitPortStatus.getHwAddr())
417 .setName(circuitPortStatus.getName())
418 .setConfig(circuitPortStatus.getConfig())
419 .setState(circuitPortStatus.getState());
420 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
421 for (OpenFlowSwitchListener l : ofSwitchListener) {
422 l.portChanged(dpid, portStatus.build());
423 }
424 } else {
425 log.warn("Handling experimenter type {} not yet implemented",
426 ((OFExperimenter) msg).getExperimenter(), msg);
427 }
428 break;
tom7ef8ff92014-09-17 13:08:06 -0700429 default:
430 log.warn("Handling message type {} not yet implemented {}",
431 msg.getType(), msg);
432 }
433 }
434
sangho6a0bb172015-02-05 12:24:48 -0800435 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
436 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800437 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800438 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800439 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800440 return fullFlowStats.removeAll(dpid);
441 }
442 return null;
443 }
444
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700445 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
446 OFTableStatsReply reply) {
447 //TODO: Get rid of synchronized
448 fullTableStats.putAll(dpid, reply.getEntries());
449 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
450 return fullTableStats.removeAll(dpid);
451 }
452 return null;
453 }
454
sangho6a0bb172015-02-05 12:24:48 -0800455 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
456 OFGroupStatsReply reply) {
457 //TODO: Get rid of synchronized
458 fullGroupStats.putAll(dpid, reply.getEntries());
459 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
460 return fullGroupStats.removeAll(dpid);
461 }
462 return null;
463 }
464
465 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
466 OFGroupDescStatsReply reply) {
467 //TODO: Get rid of synchronized
468 fullGroupDescStats.putAll(dpid, reply.getEntries());
469 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
470 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800471 }
472 return null;
473 }
474
sangho538108b2015-04-08 14:29:20 -0700475 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
476 OFPortStatsReply reply) {
477 fullPortStats.putAll(dpid, reply.getEntries());
478 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
479 return fullPortStats.removeAll(dpid);
480 }
481 return null;
482 }
483
tom7ef8ff92014-09-17 13:08:06 -0700484 @Override
485 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700486 final OpenFlowSwitch sw = getSwitch(dpid);
487 if (sw == null) {
488 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
489 return;
490 }
491 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700492 }
493
494 /**
495 * Implementation of an OpenFlow Agent which is responsible for
496 * keeping track of connected switches and the state in which
497 * they are.
498 */
499 public class OpenFlowSwitchAgent implements OpenFlowAgent {
500
501 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
502 private final Lock switchLock = new ReentrantLock();
503
504 @Override
505 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700506
tom7ef8ff92014-09-17 13:08:06 -0700507 if (connectedSwitches.get(dpid) != null) {
508 log.error("Trying to add connectedSwitch but found a previous "
509 + "value for dpid: {}", dpid);
510 return false;
511 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700512 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700513 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700514 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700515 l.switchAdded(dpid);
516 }
517 return true;
518 }
519 }
520
521 @Override
522 public boolean validActivation(Dpid dpid) {
523 if (connectedSwitches.get(dpid) == null) {
524 log.error("Trying to activate switch but is not in "
525 + "connected switches: dpid {}. Aborting ..",
526 dpid);
527 return false;
528 }
529 if (activeMasterSwitches.get(dpid) != null ||
530 activeEqualSwitches.get(dpid) != null) {
531 log.error("Trying to activate switch but it is already "
532 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800533 + "Found in activeEqual: {}. Aborting ..",
534 dpid,
535 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
536 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700537 return false;
538 }
539 return true;
540 }
541
542
543 @Override
544 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
545 switchLock.lock();
546 try {
547 if (!validActivation(dpid)) {
548 return false;
549 }
550 activeMasterSwitches.put(dpid, sw);
551 return true;
552 } finally {
553 switchLock.unlock();
554 }
555 }
556
557 @Override
558 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
559 switchLock.lock();
560 try {
561 if (!validActivation(dpid)) {
562 return false;
563 }
564 activeEqualSwitches.put(dpid, sw);
565 log.info("Added Activated EQUAL Switch {}", dpid);
566 return true;
567 } finally {
568 switchLock.unlock();
569 }
570 }
571
572 @Override
573 public void transitionToMasterSwitch(Dpid dpid) {
574 switchLock.lock();
575 try {
576 if (activeMasterSwitches.containsKey(dpid)) {
577 return;
578 }
579 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
580 if (sw == null) {
581 sw = getSwitch(dpid);
582 if (sw == null) {
583 log.error("Transition to master called on sw {}, but switch "
584 + "was not found in controller-cache", dpid);
585 return;
586 }
587 }
588 log.info("Transitioned switch {} to MASTER", dpid);
589 activeMasterSwitches.put(dpid, sw);
590 } finally {
591 switchLock.unlock();
592 }
593 }
594
595
596 @Override
597 public void transitionToEqualSwitch(Dpid dpid) {
598 switchLock.lock();
599 try {
600 if (activeEqualSwitches.containsKey(dpid)) {
601 return;
602 }
603 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
604 if (sw == null) {
605 sw = getSwitch(dpid);
606 if (sw == null) {
607 log.error("Transition to equal called on sw {}, but switch "
608 + "was not found in controller-cache", dpid);
609 return;
610 }
611 }
612 log.info("Transitioned switch {} to EQUAL", dpid);
613 activeEqualSwitches.put(dpid, sw);
614 } finally {
615 switchLock.unlock();
616 }
617
618 }
619
620 @Override
621 public void removeConnectedSwitch(Dpid dpid) {
622 connectedSwitches.remove(dpid);
623 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
624 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700625 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700626 sw = activeEqualSwitches.remove(dpid);
627 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700628 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700629 l.switchRemoved(dpid);
630 }
631 }
632
633 @Override
Jian Lia78cdb22016-04-21 13:03:58 -0700634 public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
635 for (OpenFlowMessageListener listener : ofMessageListener) {
636 listener.handleOutgoingMessage(dpid, m);
637 }
638 }
639
640
641 @Override
tom7ef8ff92014-09-17 13:08:06 -0700642 public void processMessage(Dpid dpid, OFMessage m) {
643 processPacket(dpid, m);
Jian Lia78cdb22016-04-21 13:03:58 -0700644
645 for (OpenFlowMessageListener listener : ofMessageListener) {
646 listener.handleIncomingMessage(dpid, m);
647 }
tom7ef8ff92014-09-17 13:08:06 -0700648 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700649
650 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700651 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700652 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700653 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700654 }
655 }
tom7ef8ff92014-09-17 13:08:06 -0700656 }
657
Jian Li152b8852015-12-07 14:47:25 -0800658 /**
Jian Li2266bff2016-04-21 11:01:25 -0700659 * OpenFlow message handler.
Jian Li152b8852015-12-07 14:47:25 -0800660 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800661 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700662
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800663 protected final OFMessage msg;
664 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700665
666 public OFMessageHandler(Dpid dpid, OFMessage msg) {
667 this.msg = msg;
668 this.dpid = dpid;
669 }
670
671 @Override
672 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700673 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700674 listener.handleMessage(dpid, msg);
675 }
676 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700677 }
tom7ef8ff92014-09-17 13:08:06 -0700678}