blob: 9ef3077ab4588e7099995c029131e7fb3bfc3cac [file] [log] [blame]
tom9c94c5b2014-09-17 13:14:42 -07001package org.onlab.onos.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -07002
alshabib8f1cf4a2014-09-17 14:44:48 -07003import static org.onlab.util.Tools.namedThreads;
4
tom7ef8ff92014-09-17 13:08:06 -07005import java.util.HashSet;
6import java.util.Set;
7import java.util.concurrent.ConcurrentHashMap;
alshabib8f1cf4a2014-09-17 14:44:48 -07008import java.util.concurrent.ExecutorService;
9import java.util.concurrent.Executors;
tom7ef8ff92014-09-17 13:08:06 -070010import java.util.concurrent.locks.Lock;
11import java.util.concurrent.locks.ReentrantLock;
12
13import org.apache.felix.scr.annotations.Activate;
14import org.apache.felix.scr.annotations.Component;
15import org.apache.felix.scr.annotations.Deactivate;
16import org.apache.felix.scr.annotations.Service;
tom9c94c5b2014-09-17 13:14:42 -070017import org.onlab.onos.openflow.controller.DefaultOpenFlowPacketContext;
18import org.onlab.onos.openflow.controller.Dpid;
19import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070020import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070021import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
22import org.onlab.onos.openflow.controller.OpenFlowSwitch;
23import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
24import org.onlab.onos.openflow.controller.PacketListener;
25import org.onlab.onos.openflow.controller.RoleState;
26import org.onlab.onos.openflow.controller.driver.OpenFlowAgent;
tom7ef8ff92014-09-17 13:08:06 -070027import org.projectfloodlight.openflow.protocol.OFMessage;
28import org.projectfloodlight.openflow.protocol.OFPacketIn;
29import org.projectfloodlight.openflow.protocol.OFPortStatus;
Ayaka Koshibe38594c22014-10-22 13:36:12 -070030import org.projectfloodlight.openflow.protocol.OFStatsReply;
31import org.projectfloodlight.openflow.protocol.OFStatsType;
tom7ef8ff92014-09-17 13:08:06 -070032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
35import com.google.common.collect.ArrayListMultimap;
36import com.google.common.collect.Multimap;
alshabibeec3a062014-09-17 18:01:26 -070037import com.google.common.collect.Sets;
tom7ef8ff92014-09-17 13:08:06 -070038
39@Component(immediate = true)
40@Service
41public class OpenFlowControllerImpl implements OpenFlowController {
42
43 private static final Logger log =
44 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
45
alshabib8f1cf4a2014-09-17 14:44:48 -070046 private final ExecutorService executor = Executors.newFixedThreadPool(16,
alshabibeec3a062014-09-17 18:01:26 -070047 namedThreads("of-event-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -070048
tom7ef8ff92014-09-17 13:08:06 -070049 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
50 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
51 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
52 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
53 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
54 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
55
56 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
alshabib8f1cf4a2014-09-17 14:44:48 -070057 protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
tom7ef8ff92014-09-17 13:08:06 -070058
59 protected Multimap<Integer, PacketListener> ofPacketListener =
60 ArrayListMultimap.create();
61
alshabibeec3a062014-09-17 18:01:26 -070062 protected Set<OpenFlowEventListener> ofEventListener = Sets.newHashSet();
tom7ef8ff92014-09-17 13:08:06 -070063
64 private final Controller ctrl = new Controller();
65
66 @Activate
67 public void activate() {
68 ctrl.start(agent);
69 }
70
71 @Deactivate
72 public void deactivate() {
73 ctrl.stop();
74 }
75
76 @Override
77 public Iterable<OpenFlowSwitch> getSwitches() {
78 return connectedSwitches.values();
79 }
80
81 @Override
82 public Iterable<OpenFlowSwitch> getMasterSwitches() {
83 return activeMasterSwitches.values();
84 }
85
86 @Override
87 public Iterable<OpenFlowSwitch> getEqualSwitches() {
88 return activeEqualSwitches.values();
89 }
90
91 @Override
92 public OpenFlowSwitch getSwitch(Dpid dpid) {
93 return connectedSwitches.get(dpid);
94 }
95
96 @Override
97 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
98 return activeMasterSwitches.get(dpid);
99 }
100
101 @Override
102 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
103 return activeEqualSwitches.get(dpid);
104 }
105
106 @Override
107 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700108 if (!ofSwitchListener.contains(listener)) {
109 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700110 }
111 }
112
113 @Override
114 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700115 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700116 }
117
118 @Override
119 public void addPacketListener(int priority, PacketListener listener) {
120 ofPacketListener.put(priority, listener);
121 }
122
123 @Override
124 public void removePacketListener(PacketListener listener) {
125 ofPacketListener.values().remove(listener);
126 }
127
128 @Override
alshabibeec3a062014-09-17 18:01:26 -0700129 public void addEventListener(OpenFlowEventListener listener) {
130 ofEventListener.add(listener);
131 }
132
133 @Override
134 public void removeEventListener(OpenFlowEventListener listener) {
135 ofEventListener.remove(listener);
136 }
137
138 @Override
tom7ef8ff92014-09-17 13:08:06 -0700139 public void write(Dpid dpid, OFMessage msg) {
140 this.getSwitch(dpid).sendMsg(msg);
141 }
142
143 @Override
144 public void processPacket(Dpid dpid, OFMessage msg) {
145 switch (msg.getType()) {
146 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700147 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700148 l.portChanged(dpid, (OFPortStatus) msg);
149 }
150 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700151 case FEATURES_REPLY:
152 for (OpenFlowSwitchListener l : ofSwitchListener) {
153 l.switchChanged(dpid);
154 }
155 break;
tom7ef8ff92014-09-17 13:08:06 -0700156 case PACKET_IN:
157 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
158 .packetContextFromPacketIn(this.getSwitch(dpid),
159 (OFPacketIn) msg);
160 for (PacketListener p : ofPacketListener.values()) {
161 p.handlePacket(pktCtx);
162 }
163 break;
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700164 case STATS_REPLY:
165 OFStatsReply reply = (OFStatsReply) msg;
166 if (reply.getStatsType().equals(OFStatsType.PORT_DESC)) {
167 for (OpenFlowSwitchListener l : ofSwitchListener) {
168 l.switchChanged(dpid);
169 }
170 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700171 case FLOW_REMOVED:
172 case ERROR:
alshabib8f1cf4a2014-09-17 14:44:48 -0700173 case BARRIER_REPLY:
174 executor.submit(new OFMessageHandler(dpid, msg));
175 break;
tom7ef8ff92014-09-17 13:08:06 -0700176 default:
177 log.warn("Handling message type {} not yet implemented {}",
178 msg.getType(), msg);
179 }
180 }
181
182 @Override
183 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700184 final OpenFlowSwitch sw = getSwitch(dpid);
185 if (sw == null) {
186 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
187 return;
188 }
189 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700190 }
191
192 /**
193 * Implementation of an OpenFlow Agent which is responsible for
194 * keeping track of connected switches and the state in which
195 * they are.
196 */
197 public class OpenFlowSwitchAgent implements OpenFlowAgent {
198
199 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
200 private final Lock switchLock = new ReentrantLock();
201
202 @Override
203 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700204
tom7ef8ff92014-09-17 13:08:06 -0700205 if (connectedSwitches.get(dpid) != null) {
206 log.error("Trying to add connectedSwitch but found a previous "
207 + "value for dpid: {}", dpid);
208 return false;
209 } else {
Yuta HIGUCHIeb3f30b2014-10-22 11:34:49 -0700210 log.info("Added switch {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700211 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700212 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700213 l.switchAdded(dpid);
214 }
215 return true;
216 }
217 }
218
219 @Override
220 public boolean validActivation(Dpid dpid) {
221 if (connectedSwitches.get(dpid) == null) {
222 log.error("Trying to activate switch but is not in "
223 + "connected switches: dpid {}. Aborting ..",
224 dpid);
225 return false;
226 }
227 if (activeMasterSwitches.get(dpid) != null ||
228 activeEqualSwitches.get(dpid) != null) {
229 log.error("Trying to activate switch but it is already "
230 + "activated: dpid {}. Found in activeMaster: {} "
231 + "Found in activeEqual: {}. Aborting ..", new Object[]{
232 dpid,
233 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
234 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
235 return false;
236 }
237 return true;
238 }
239
240
241 @Override
242 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
243 switchLock.lock();
244 try {
245 if (!validActivation(dpid)) {
246 return false;
247 }
248 activeMasterSwitches.put(dpid, sw);
249 return true;
250 } finally {
251 switchLock.unlock();
252 }
253 }
254
255 @Override
256 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
257 switchLock.lock();
258 try {
259 if (!validActivation(dpid)) {
260 return false;
261 }
262 activeEqualSwitches.put(dpid, sw);
263 log.info("Added Activated EQUAL Switch {}", dpid);
264 return true;
265 } finally {
266 switchLock.unlock();
267 }
268 }
269
270 @Override
271 public void transitionToMasterSwitch(Dpid dpid) {
272 switchLock.lock();
273 try {
274 if (activeMasterSwitches.containsKey(dpid)) {
275 return;
276 }
277 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
278 if (sw == null) {
279 sw = getSwitch(dpid);
280 if (sw == null) {
281 log.error("Transition to master called on sw {}, but switch "
282 + "was not found in controller-cache", dpid);
283 return;
284 }
285 }
286 log.info("Transitioned switch {} to MASTER", dpid);
287 activeMasterSwitches.put(dpid, sw);
288 } finally {
289 switchLock.unlock();
290 }
291 }
292
293
294 @Override
295 public void transitionToEqualSwitch(Dpid dpid) {
296 switchLock.lock();
297 try {
298 if (activeEqualSwitches.containsKey(dpid)) {
299 return;
300 }
301 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
302 if (sw == null) {
303 sw = getSwitch(dpid);
304 if (sw == null) {
305 log.error("Transition to equal called on sw {}, but switch "
306 + "was not found in controller-cache", dpid);
307 return;
308 }
309 }
310 log.info("Transitioned switch {} to EQUAL", dpid);
311 activeEqualSwitches.put(dpid, sw);
312 } finally {
313 switchLock.unlock();
314 }
315
316 }
317
318 @Override
319 public void removeConnectedSwitch(Dpid dpid) {
320 connectedSwitches.remove(dpid);
321 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
322 if (sw == null) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700323 log.warn("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700324 sw = activeEqualSwitches.remove(dpid);
325 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700326 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700327 log.warn("removal for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700328 l.switchRemoved(dpid);
329 }
330 }
331
332 @Override
333 public void processMessage(Dpid dpid, OFMessage m) {
334 processPacket(dpid, m);
335 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700336
337 @Override
338 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
339 for (OpenFlowSwitchListener l : ofSwitchListener) {
340 l.roleAssertFailed(dpid, role);
341 }
342 }
tom7ef8ff92014-09-17 13:08:06 -0700343 }
344
alshabib8f1cf4a2014-09-17 14:44:48 -0700345 private final class OFMessageHandler implements Runnable {
346
347 private final OFMessage msg;
348 private final Dpid dpid;
349
350 public OFMessageHandler(Dpid dpid, OFMessage msg) {
351 this.msg = msg;
352 this.dpid = dpid;
353 }
354
355 @Override
356 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700357 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700358 listener.handleMessage(dpid, msg);
359 }
360 }
361
362 }
363
tom7ef8ff92014-09-17 13:08:06 -0700364}