blob: f9a6059f54fad3d61b8045ee119fe959c69f04c7 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070051import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
52import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
sangho6a0bb172015-02-05 12:24:48 -080053import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
54import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
55import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
56import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070057import org.projectfloodlight.openflow.protocol.OFMessage;
58import org.projectfloodlight.openflow.protocol.OFPacketIn;
Marc De Leenheer631ffce2014-10-28 16:29:07 -070059import org.projectfloodlight.openflow.protocol.OFPortDesc;
sangho538108b2015-04-08 14:29:20 -070060import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
61import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
tom7ef8ff92014-09-17 13:08:06 -070062import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070063import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib64def642014-12-02 23:27:37 -080064import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
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;
Jonathan Hart6d44d192015-05-11 18:01:19 -070076import java.util.concurrent.CopyOnWriteArraySet;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080077import java.util.concurrent.ExecutorService;
78import java.util.concurrent.Executors;
79import java.util.concurrent.locks.Lock;
80import java.util.concurrent.locks.ReentrantLock;
81
82import static org.onlab.util.Tools.groupedThreads;
tom7ef8ff92014-09-17 13:08:06 -070083
84@Component(immediate = true)
85@Service
86public class OpenFlowControllerImpl implements OpenFlowController {
Charles Chanecfdfb72015-11-24 19:05:50 -080087 private static final String APP_ID = "org.onosproject.openflow-base";
Brian O'Connorff278502015-09-22 14:49:52 -070088 private static final String DEFAULT_OFPORT = "6633,6653";
Charles Chan3b00e1b2015-08-26 23:12:52 +080089 private static final int DEFAULT_WORKER_THREADS = 16;
tom7ef8ff92014-09-17 13:08:06 -070090
91 private static final Logger log =
92 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
93
alshabibb452fd72015-04-22 20:46:20 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanecfdfb72015-11-24 19:05:50 -080095 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb452fd72015-04-22 20:46:20 -070098 protected DriverService driverService;
99
Thomas Vachuska3358af22015-05-19 18:40:34 -0700100 // References exists merely for sequencing purpose to assure drivers are loaded
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DefaultDriverProviderService defaultDriverProviderService;
103
Charles Chan3b00e1b2015-08-26 23:12:52 +0800104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected ComponentConfigService cfgService;
106
Brian O'Connore2a399e2015-09-22 15:32:50 -0700107 @Property(name = "openflowPorts", value = DEFAULT_OFPORT,
108 label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653")
109 private String openflowPorts = DEFAULT_OFPORT;
Charles Chan3b00e1b2015-08-26 23:12:52 +0800110
111 @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS,
112 label = "Number of controller worker threads; default is 16")
113 private int workerThreads = DEFAULT_WORKER_THREADS;
114
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800115 protected ExecutorService executorMsgs =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800116 Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d"));
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800117
118 private final ExecutorService executorBarrier =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800119 Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -0700120
tom7ef8ff92014-09-17 13:08:06 -0700121 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700122 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700123 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700124 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700125 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
Jonathan Hart6d44d192015-05-11 18:01:19 -0700126 new ConcurrentHashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700127
128 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
Jonathan Hart6d44d192015-05-11 18:01:19 -0700129 protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700130
131 protected Multimap<Integer, PacketListener> ofPacketListener =
132 ArrayListMultimap.create();
133
Jonathan Hart6d44d192015-05-11 18:01:19 -0700134 protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
tom7ef8ff92014-09-17 13:08:06 -0700135
sangho6a0bb172015-02-05 12:24:48 -0800136 protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
137 ArrayListMultimap.create();
138
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700139 protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
140 ArrayListMultimap.create();
141
sangho6a0bb172015-02-05 12:24:48 -0800142 protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats =
143 ArrayListMultimap.create();
144
145 protected Multimap<Dpid, OFGroupDescStatsEntry> fullGroupDescStats =
alshabib64def642014-12-02 23:27:37 -0800146 ArrayListMultimap.create();
147
sangho538108b2015-04-08 14:29:20 -0700148 protected Multimap<Dpid, OFPortStatsEntry> fullPortStats =
149 ArrayListMultimap.create();
150
tom7ef8ff92014-09-17 13:08:06 -0700151 private final Controller ctrl = new Controller();
152
153 @Activate
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800154 public void activate(ComponentContext context) {
Charles Chanecfdfb72015-11-24 19:05:50 -0800155 coreService.registerApplication(APP_ID, this::preDeactivate);
Charles Chan3b00e1b2015-08-26 23:12:52 +0800156 cfgService.registerProperties(getClass());
Brian O'Connorff278502015-09-22 14:49:52 -0700157 ctrl.setConfigParams(context.getProperties());
alshabibb452fd72015-04-22 20:46:20 -0700158 ctrl.start(agent, driverService);
tom7ef8ff92014-09-17 13:08:06 -0700159 }
160
Charles Chanecfdfb72015-11-24 19:05:50 -0800161 private void preDeactivate() {
162 // Close listening channel and all OF channels before deactivating
163 ctrl.stop();
164 connectedSwitches.values().forEach(OpenFlowSwitch::disconnectSwitch);
165 }
166
tom7ef8ff92014-09-17 13:08:06 -0700167 @Deactivate
168 public void deactivate() {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800169 cfgService.unregisterProperties(getClass(), false);
Charles Chanecfdfb72015-11-24 19:05:50 -0800170 connectedSwitches.clear();
171 activeMasterSwitches.clear();
172 activeEqualSwitches.clear();
tom7ef8ff92014-09-17 13:08:06 -0700173 }
174
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800175 @Modified
176 public void modified(ComponentContext context) {
Charles Chan3b00e1b2015-08-26 23:12:52 +0800177 ctrl.stop();
Brian O'Connorff278502015-09-22 14:49:52 -0700178 ctrl.setConfigParams(context.getProperties());
Charles Chan3b00e1b2015-08-26 23:12:52 +0800179 ctrl.start(agent, driverService);
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800180 }
181
tom7ef8ff92014-09-17 13:08:06 -0700182 @Override
183 public Iterable<OpenFlowSwitch> getSwitches() {
184 return connectedSwitches.values();
185 }
186
187 @Override
188 public Iterable<OpenFlowSwitch> getMasterSwitches() {
189 return activeMasterSwitches.values();
190 }
191
192 @Override
193 public Iterable<OpenFlowSwitch> getEqualSwitches() {
194 return activeEqualSwitches.values();
195 }
196
197 @Override
198 public OpenFlowSwitch getSwitch(Dpid dpid) {
199 return connectedSwitches.get(dpid);
200 }
201
202 @Override
203 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
204 return activeMasterSwitches.get(dpid);
205 }
206
207 @Override
208 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
209 return activeEqualSwitches.get(dpid);
210 }
211
212 @Override
213 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700214 if (!ofSwitchListener.contains(listener)) {
215 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700216 }
217 }
218
219 @Override
220 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700221 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700222 }
223
224 @Override
225 public void addPacketListener(int priority, PacketListener listener) {
226 ofPacketListener.put(priority, listener);
227 }
228
229 @Override
230 public void removePacketListener(PacketListener listener) {
231 ofPacketListener.values().remove(listener);
232 }
233
234 @Override
alshabibeec3a062014-09-17 18:01:26 -0700235 public void addEventListener(OpenFlowEventListener listener) {
236 ofEventListener.add(listener);
237 }
238
239 @Override
240 public void removeEventListener(OpenFlowEventListener listener) {
241 ofEventListener.remove(listener);
242 }
243
244 @Override
tom7ef8ff92014-09-17 13:08:06 -0700245 public void write(Dpid dpid, OFMessage msg) {
246 this.getSwitch(dpid).sendMsg(msg);
247 }
248
249 @Override
250 public void processPacket(Dpid dpid, OFMessage msg) {
sangho6a0bb172015-02-05 12:24:48 -0800251 Collection<OFFlowStatsEntry> flowStats;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700252 Collection<OFTableStatsEntry> tableStats;
sangho6a0bb172015-02-05 12:24:48 -0800253 Collection<OFGroupStatsEntry> groupStats;
254 Collection<OFGroupDescStatsEntry> groupDescStats;
sangho538108b2015-04-08 14:29:20 -0700255 Collection<OFPortStatsEntry> portStats;
sangho6a0bb172015-02-05 12:24:48 -0800256
tom7ef8ff92014-09-17 13:08:06 -0700257 switch (msg.getType()) {
258 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700259 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700260 l.portChanged(dpid, (OFPortStatus) msg);
261 }
262 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700263 case FEATURES_REPLY:
264 for (OpenFlowSwitchListener l : ofSwitchListener) {
265 l.switchChanged(dpid);
266 }
267 break;
tom7ef8ff92014-09-17 13:08:06 -0700268 case PACKET_IN:
269 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
270 .packetContextFromPacketIn(this.getSwitch(dpid),
271 (OFPacketIn) msg);
272 for (PacketListener p : ofPacketListener.values()) {
273 p.handlePacket(pktCtx);
274 }
Jian Li152b8852015-12-07 14:47:25 -0800275 executorMsgs.submit(new OFMessageHandler(dpid, msg));
tom7ef8ff92014-09-17 13:08:06 -0700276 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800277 // TODO: Consider using separate threadpool for sensitive messages.
278 // ie. Back to back error could cause us to starve.
279 case FLOW_REMOVED:
Jian Li152b8852015-12-07 14:47:25 -0800280 executorMsgs.submit(new OFMessageHandler(dpid, msg));
281 break;
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800282 case ERROR:
283 executorMsgs.submit(new OFMessageHandler(dpid, msg));
284 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700285 case STATS_REPLY:
286 OFStatsReply reply = (OFStatsReply) msg;
sangho6a0bb172015-02-05 12:24:48 -0800287 switch (reply.getStatsType()) {
288 case PORT_DESC:
289 for (OpenFlowSwitchListener l : ofSwitchListener) {
290 l.switchChanged(dpid);
291 }
292 break;
293 case FLOW:
294 flowStats = publishFlowStats(dpid, (OFFlowStatsReply) reply);
295 if (flowStats != null) {
296 OFFlowStatsReply.Builder rep =
297 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
298 rep.setEntries(Lists.newLinkedList(flowStats));
ssyoon9030fbcd92015-08-17 10:42:07 +0900299 rep.setXid(reply.getXid());
sangho6a0bb172015-02-05 12:24:48 -0800300 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
301 }
302 break;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700303 case TABLE:
304 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
305 if (tableStats != null) {
306 OFTableStatsReply.Builder rep =
307 OFFactories.getFactory(msg.getVersion()).buildTableStatsReply();
308 rep.setEntries(Lists.newLinkedList(tableStats));
309 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
310 }
311 break;
sangho6a0bb172015-02-05 12:24:48 -0800312 case GROUP:
313 groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply);
314 if (groupStats != null) {
315 OFGroupStatsReply.Builder rep =
316 OFFactories.getFactory(msg.getVersion()).buildGroupStatsReply();
317 rep.setEntries(Lists.newLinkedList(groupStats));
318 rep.setXid(reply.getXid());
319 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
320 }
321 break;
322 case GROUP_DESC:
323 groupDescStats = publishGroupDescStats(dpid,
324 (OFGroupDescStatsReply) reply);
325 if (groupDescStats != null) {
326 OFGroupDescStatsReply.Builder rep =
Marc De Leenheerb9311372015-07-09 11:36:49 -0700327 OFFactories.getFactory(msg.getVersion()).buildGroupDescStatsReply();
sangho6a0bb172015-02-05 12:24:48 -0800328 rep.setEntries(Lists.newLinkedList(groupDescStats));
329 rep.setXid(reply.getXid());
330 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
331 }
332 break;
sangho538108b2015-04-08 14:29:20 -0700333 case PORT:
334 executorMsgs.submit(new OFMessageHandler(dpid, reply));
335 break;
alshabib5eb79392015-08-19 18:09:55 -0700336 case METER:
337 executorMsgs.submit(new OFMessageHandler(dpid, reply));
338 break;
Marc De Leenheerb9311372015-07-09 11:36:49 -0700339 case EXPERIMENTER:
340 if (reply instanceof OFCalientFlowStatsReply) {
341 // Convert Calient flow statistics to regular flow stats
342 // TODO: parse remaining fields such as power levels etc. when we have proper monitoring API
343 OFFlowStatsReply.Builder fsr = getSwitch(dpid).factory().buildFlowStatsReply();
344 List<OFFlowStatsEntry> entries = new LinkedList<>();
345 for (OFCalientFlowStatsEntry entry : ((OFCalientFlowStatsReply) msg).getEntries()) {
346
347 // Single instruction, i.e., output to port
348 OFActionOutput action = OFFactories
349 .getFactory(msg.getVersion())
350 .actions()
351 .buildOutput()
352 .setPort(entry.getOutPort())
353 .build();
354 OFInstruction instruction = OFFactories
355 .getFactory(msg.getVersion())
356 .instructions()
357 .applyActions(Collections.singletonList(action));
358 OFFlowStatsEntry fs = getSwitch(dpid).factory().buildFlowStatsEntry()
359 .setMatch(entry.getMatch())
360 .setTableId(entry.getTableId())
361 .setDurationSec(entry.getDurationSec())
362 .setDurationNsec(entry.getDurationNsec())
363 .setPriority(entry.getPriority())
364 .setIdleTimeout(entry.getIdleTimeout())
365 .setHardTimeout(entry.getHardTimeout())
366 .setFlags(entry.getFlags())
367 .setCookie(entry.getCookie())
368 .setInstructions(Collections.singletonList(instruction))
369 .build();
370 entries.add(fs);
371 }
372 fsr.setEntries(entries);
373
374 flowStats = publishFlowStats(dpid, fsr.build());
375 if (flowStats != null) {
376 OFFlowStatsReply.Builder rep =
377 OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply();
378 rep.setEntries(Lists.newLinkedList(flowStats));
379 executorMsgs.submit(new OFMessageHandler(dpid, rep.build()));
380 }
381 } else {
Michael Bunimovich1b45e1f2015-08-27 07:49:25 -0400382 executorMsgs.submit(new OFMessageHandler(dpid, reply));
Marc De Leenheerb9311372015-07-09 11:36:49 -0700383 }
384 break;
sangho6a0bb172015-02-05 12:24:48 -0800385 default:
alshabib5eb79392015-08-19 18:09:55 -0700386 log.warn("Discarding unknown stats reply type {}", reply.getStatsType());
Marc De Leenheerb9311372015-07-09 11:36:49 -0700387 break;
alshabib64def642014-12-02 23:27:37 -0800388 }
389 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700390 case BARRIER_REPLY:
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800391 executorBarrier.submit(new OFMessageHandler(dpid, msg));
alshabib8f1cf4a2014-09-17 14:44:48 -0700392 break;
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700393 case EXPERIMENTER:
Marc De Leenheerb9311372015-07-09 11:36:49 -0700394 long experimenter = ((OFExperimenter) msg).getExperimenter();
395 if (experimenter == 0x748771) {
396 // LINC-OE port stats
Marc De Leenheer631ffce2014-10-28 16:29:07 -0700397 OFCircuitPortStatus circuitPortStatus = (OFCircuitPortStatus) msg;
398 OFPortStatus.Builder portStatus = this.getSwitch(dpid).factory().buildPortStatus();
399 OFPortDesc.Builder portDesc = this.getSwitch(dpid).factory().buildPortDesc();
400 portDesc.setPortNo(circuitPortStatus.getPortNo())
401 .setHwAddr(circuitPortStatus.getHwAddr())
402 .setName(circuitPortStatus.getName())
403 .setConfig(circuitPortStatus.getConfig())
404 .setState(circuitPortStatus.getState());
405 portStatus.setReason(circuitPortStatus.getReason()).setDesc(portDesc.build());
406 for (OpenFlowSwitchListener l : ofSwitchListener) {
407 l.portChanged(dpid, portStatus.build());
408 }
409 } else {
410 log.warn("Handling experimenter type {} not yet implemented",
411 ((OFExperimenter) msg).getExperimenter(), msg);
412 }
413 break;
tom7ef8ff92014-09-17 13:08:06 -0700414 default:
415 log.warn("Handling message type {} not yet implemented {}",
416 msg.getType(), msg);
417 }
418 }
419
sangho6a0bb172015-02-05 12:24:48 -0800420 private synchronized Collection<OFFlowStatsEntry> publishFlowStats(Dpid dpid,
421 OFFlowStatsReply reply) {
alshabib64def642014-12-02 23:27:37 -0800422 //TODO: Get rid of synchronized
sangho6a0bb172015-02-05 12:24:48 -0800423 fullFlowStats.putAll(dpid, reply.getEntries());
alshabib64def642014-12-02 23:27:37 -0800424 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
sangho6a0bb172015-02-05 12:24:48 -0800425 return fullFlowStats.removeAll(dpid);
426 }
427 return null;
428 }
429
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700430 private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
431 OFTableStatsReply reply) {
432 //TODO: Get rid of synchronized
433 fullTableStats.putAll(dpid, reply.getEntries());
434 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
435 return fullTableStats.removeAll(dpid);
436 }
437 return null;
438 }
439
sangho6a0bb172015-02-05 12:24:48 -0800440 private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid,
441 OFGroupStatsReply reply) {
442 //TODO: Get rid of synchronized
443 fullGroupStats.putAll(dpid, reply.getEntries());
444 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
445 return fullGroupStats.removeAll(dpid);
446 }
447 return null;
448 }
449
450 private synchronized Collection<OFGroupDescStatsEntry> publishGroupDescStats(Dpid dpid,
451 OFGroupDescStatsReply reply) {
452 //TODO: Get rid of synchronized
453 fullGroupDescStats.putAll(dpid, reply.getEntries());
454 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
455 return fullGroupDescStats.removeAll(dpid);
alshabib64def642014-12-02 23:27:37 -0800456 }
457 return null;
458 }
459
sangho538108b2015-04-08 14:29:20 -0700460 private synchronized Collection<OFPortStatsEntry> publishPortStats(Dpid dpid,
461 OFPortStatsReply reply) {
462 fullPortStats.putAll(dpid, reply.getEntries());
463 if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
464 return fullPortStats.removeAll(dpid);
465 }
466 return null;
467 }
468
tom7ef8ff92014-09-17 13:08:06 -0700469 @Override
470 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700471 final OpenFlowSwitch sw = getSwitch(dpid);
472 if (sw == null) {
473 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
474 return;
475 }
476 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700477 }
478
479 /**
480 * Implementation of an OpenFlow Agent which is responsible for
481 * keeping track of connected switches and the state in which
482 * they are.
483 */
484 public class OpenFlowSwitchAgent implements OpenFlowAgent {
485
486 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
487 private final Lock switchLock = new ReentrantLock();
488
489 @Override
490 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700491
tom7ef8ff92014-09-17 13:08:06 -0700492 if (connectedSwitches.get(dpid) != null) {
493 log.error("Trying to add connectedSwitch but found a previous "
494 + "value for dpid: {}", dpid);
495 return false;
496 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700497 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700498 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700499 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700500 l.switchAdded(dpid);
501 }
502 return true;
503 }
504 }
505
506 @Override
507 public boolean validActivation(Dpid dpid) {
508 if (connectedSwitches.get(dpid) == null) {
509 log.error("Trying to activate switch but is not in "
510 + "connected switches: dpid {}. Aborting ..",
511 dpid);
512 return false;
513 }
514 if (activeMasterSwitches.get(dpid) != null ||
515 activeEqualSwitches.get(dpid) != null) {
516 log.error("Trying to activate switch but it is already "
517 + "activated: dpid {}. Found in activeMaster: {} "
Ray Milkey6bc43c22015-11-06 13:22:38 -0800518 + "Found in activeEqual: {}. Aborting ..",
519 dpid,
520 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
521 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y');
tom7ef8ff92014-09-17 13:08:06 -0700522 return false;
523 }
524 return true;
525 }
526
527
528 @Override
529 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
530 switchLock.lock();
531 try {
532 if (!validActivation(dpid)) {
533 return false;
534 }
535 activeMasterSwitches.put(dpid, sw);
536 return true;
537 } finally {
538 switchLock.unlock();
539 }
540 }
541
542 @Override
543 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
544 switchLock.lock();
545 try {
546 if (!validActivation(dpid)) {
547 return false;
548 }
549 activeEqualSwitches.put(dpid, sw);
550 log.info("Added Activated EQUAL Switch {}", dpid);
551 return true;
552 } finally {
553 switchLock.unlock();
554 }
555 }
556
557 @Override
558 public void transitionToMasterSwitch(Dpid dpid) {
559 switchLock.lock();
560 try {
561 if (activeMasterSwitches.containsKey(dpid)) {
562 return;
563 }
564 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
565 if (sw == null) {
566 sw = getSwitch(dpid);
567 if (sw == null) {
568 log.error("Transition to master called on sw {}, but switch "
569 + "was not found in controller-cache", dpid);
570 return;
571 }
572 }
573 log.info("Transitioned switch {} to MASTER", dpid);
574 activeMasterSwitches.put(dpid, sw);
575 } finally {
576 switchLock.unlock();
577 }
578 }
579
580
581 @Override
582 public void transitionToEqualSwitch(Dpid dpid) {
583 switchLock.lock();
584 try {
585 if (activeEqualSwitches.containsKey(dpid)) {
586 return;
587 }
588 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
589 if (sw == null) {
590 sw = getSwitch(dpid);
591 if (sw == null) {
592 log.error("Transition to equal called on sw {}, but switch "
593 + "was not found in controller-cache", dpid);
594 return;
595 }
596 }
597 log.info("Transitioned switch {} to EQUAL", dpid);
598 activeEqualSwitches.put(dpid, sw);
599 } finally {
600 switchLock.unlock();
601 }
602
603 }
604
605 @Override
606 public void removeConnectedSwitch(Dpid dpid) {
607 connectedSwitches.remove(dpid);
608 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
609 if (sw == null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700610 log.debug("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700611 sw = activeEqualSwitches.remove(dpid);
612 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700613 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700614 l.switchRemoved(dpid);
615 }
616 }
617
618 @Override
619 public void processMessage(Dpid dpid, OFMessage m) {
620 processPacket(dpid, m);
621 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700622
623 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700624 public void returnRoleReply(Dpid dpid, RoleState requested, RoleState response) {
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700625 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700626 l.receivedRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700627 }
628 }
tom7ef8ff92014-09-17 13:08:06 -0700629 }
630
Jian Li152b8852015-12-07 14:47:25 -0800631 /**
632 * OpenFlow message handler for incoming control messages.
633 */
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800634 protected final class OFMessageHandler implements Runnable {
alshabib8f1cf4a2014-09-17 14:44:48 -0700635
Ray Milkey7ec0d1b2015-11-13 08:51:35 -0800636 protected final OFMessage msg;
637 protected final Dpid dpid;
alshabib8f1cf4a2014-09-17 14:44:48 -0700638
639 public OFMessageHandler(Dpid dpid, OFMessage msg) {
640 this.msg = msg;
641 this.dpid = dpid;
642 }
643
644 @Override
645 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700646 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700647 listener.handleMessage(dpid, msg);
648 }
649 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700650 }
tom7ef8ff92014-09-17 13:08:06 -0700651}