blob: eb122865c25adfaf6a1b10bf46b034f32591895c [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;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33import com.google.common.collect.ArrayListMultimap;
34import com.google.common.collect.Multimap;
alshabibeec3a062014-09-17 18:01:26 -070035import com.google.common.collect.Sets;
tom7ef8ff92014-09-17 13:08:06 -070036
37@Component(immediate = true)
38@Service
39public class OpenFlowControllerImpl implements OpenFlowController {
40
41 private static final Logger log =
42 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
43
alshabib8f1cf4a2014-09-17 14:44:48 -070044 private final ExecutorService executor = Executors.newFixedThreadPool(16,
alshabibeec3a062014-09-17 18:01:26 -070045 namedThreads("of-event-%d"));
alshabib8f1cf4a2014-09-17 14:44:48 -070046
47
tom7ef8ff92014-09-17 13:08:06 -070048 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
49 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
50 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
51 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
52 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
53 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
54
55 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
alshabib8f1cf4a2014-09-17 14:44:48 -070056 protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
tom7ef8ff92014-09-17 13:08:06 -070057
58 protected Multimap<Integer, PacketListener> ofPacketListener =
59 ArrayListMultimap.create();
60
alshabibeec3a062014-09-17 18:01:26 -070061 protected Set<OpenFlowEventListener> ofEventListener = Sets.newHashSet();
tom7ef8ff92014-09-17 13:08:06 -070062
63 private final Controller ctrl = new Controller();
64
65 @Activate
66 public void activate() {
67 ctrl.start(agent);
68 }
69
70 @Deactivate
71 public void deactivate() {
72 ctrl.stop();
73 }
74
75 @Override
76 public Iterable<OpenFlowSwitch> getSwitches() {
77 return connectedSwitches.values();
78 }
79
80 @Override
81 public Iterable<OpenFlowSwitch> getMasterSwitches() {
82 return activeMasterSwitches.values();
83 }
84
85 @Override
86 public Iterable<OpenFlowSwitch> getEqualSwitches() {
87 return activeEqualSwitches.values();
88 }
89
90 @Override
91 public OpenFlowSwitch getSwitch(Dpid dpid) {
92 return connectedSwitches.get(dpid);
93 }
94
95 @Override
96 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
97 return activeMasterSwitches.get(dpid);
98 }
99
100 @Override
101 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
102 return activeEqualSwitches.get(dpid);
103 }
104
105 @Override
106 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700107 if (!ofSwitchListener.contains(listener)) {
108 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700109 }
110 }
111
112 @Override
113 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700114 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700115 }
116
117 @Override
118 public void addPacketListener(int priority, PacketListener listener) {
119 ofPacketListener.put(priority, listener);
120 }
121
122 @Override
123 public void removePacketListener(PacketListener listener) {
124 ofPacketListener.values().remove(listener);
125 }
126
127 @Override
alshabibeec3a062014-09-17 18:01:26 -0700128 public void addEventListener(OpenFlowEventListener listener) {
129 ofEventListener.add(listener);
130 }
131
132 @Override
133 public void removeEventListener(OpenFlowEventListener listener) {
134 ofEventListener.remove(listener);
135 }
136
137 @Override
tom7ef8ff92014-09-17 13:08:06 -0700138 public void write(Dpid dpid, OFMessage msg) {
139 this.getSwitch(dpid).sendMsg(msg);
140 }
141
142 @Override
143 public void processPacket(Dpid dpid, OFMessage msg) {
144 switch (msg.getType()) {
145 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700146 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700147 l.portChanged(dpid, (OFPortStatus) msg);
148 }
149 break;
150 case PACKET_IN:
151 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
152 .packetContextFromPacketIn(this.getSwitch(dpid),
153 (OFPacketIn) msg);
154 for (PacketListener p : ofPacketListener.values()) {
155 p.handlePacket(pktCtx);
156 }
157 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700158 case FLOW_REMOVED:
159 case ERROR:
160 case STATS_REPLY:
161 case BARRIER_REPLY:
162 executor.submit(new OFMessageHandler(dpid, msg));
163 break;
tom7ef8ff92014-09-17 13:08:06 -0700164 default:
165 log.warn("Handling message type {} not yet implemented {}",
166 msg.getType(), msg);
167 }
168 }
169
170 @Override
171 public void setRole(Dpid dpid, RoleState role) {
172 getSwitch(dpid).setRole(role);
173 }
174
175 /**
176 * Implementation of an OpenFlow Agent which is responsible for
177 * keeping track of connected switches and the state in which
178 * they are.
179 */
180 public class OpenFlowSwitchAgent implements OpenFlowAgent {
181
182 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
183 private final Lock switchLock = new ReentrantLock();
184
185 @Override
186 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
187 if (connectedSwitches.get(dpid) != null) {
188 log.error("Trying to add connectedSwitch but found a previous "
189 + "value for dpid: {}", dpid);
190 return false;
191 } else {
192 log.error("Added switch {}", dpid);
193 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700194 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700195 l.switchAdded(dpid);
196 }
197 return true;
198 }
199 }
200
201 @Override
202 public boolean validActivation(Dpid dpid) {
203 if (connectedSwitches.get(dpid) == null) {
204 log.error("Trying to activate switch but is not in "
205 + "connected switches: dpid {}. Aborting ..",
206 dpid);
207 return false;
208 }
209 if (activeMasterSwitches.get(dpid) != null ||
210 activeEqualSwitches.get(dpid) != null) {
211 log.error("Trying to activate switch but it is already "
212 + "activated: dpid {}. Found in activeMaster: {} "
213 + "Found in activeEqual: {}. Aborting ..", new Object[]{
214 dpid,
215 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
216 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
217 return false;
218 }
219 return true;
220 }
221
222
223 @Override
224 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
225 switchLock.lock();
226 try {
227 if (!validActivation(dpid)) {
228 return false;
229 }
230 activeMasterSwitches.put(dpid, sw);
231 return true;
232 } finally {
233 switchLock.unlock();
234 }
235 }
236
237 @Override
238 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
239 switchLock.lock();
240 try {
241 if (!validActivation(dpid)) {
242 return false;
243 }
244 activeEqualSwitches.put(dpid, sw);
245 log.info("Added Activated EQUAL Switch {}", dpid);
246 return true;
247 } finally {
248 switchLock.unlock();
249 }
250 }
251
252 @Override
253 public void transitionToMasterSwitch(Dpid dpid) {
254 switchLock.lock();
255 try {
256 if (activeMasterSwitches.containsKey(dpid)) {
257 return;
258 }
259 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
260 if (sw == null) {
261 sw = getSwitch(dpid);
262 if (sw == null) {
263 log.error("Transition to master called on sw {}, but switch "
264 + "was not found in controller-cache", dpid);
265 return;
266 }
267 }
268 log.info("Transitioned switch {} to MASTER", dpid);
269 activeMasterSwitches.put(dpid, sw);
270 } finally {
271 switchLock.unlock();
272 }
273 }
274
275
276 @Override
277 public void transitionToEqualSwitch(Dpid dpid) {
278 switchLock.lock();
279 try {
280 if (activeEqualSwitches.containsKey(dpid)) {
281 return;
282 }
283 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
284 if (sw == null) {
285 sw = getSwitch(dpid);
286 if (sw == null) {
287 log.error("Transition to equal called on sw {}, but switch "
288 + "was not found in controller-cache", dpid);
289 return;
290 }
291 }
292 log.info("Transitioned switch {} to EQUAL", dpid);
293 activeEqualSwitches.put(dpid, sw);
294 } finally {
295 switchLock.unlock();
296 }
297
298 }
299
300 @Override
301 public void removeConnectedSwitch(Dpid dpid) {
302 connectedSwitches.remove(dpid);
303 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
304 if (sw == null) {
305 sw = activeEqualSwitches.remove(dpid);
306 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700307 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700308 l.switchRemoved(dpid);
309 }
310 }
311
312 @Override
313 public void processMessage(Dpid dpid, OFMessage m) {
314 processPacket(dpid, m);
315 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700316
317 @Override
318 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
319 for (OpenFlowSwitchListener l : ofSwitchListener) {
320 l.roleAssertFailed(dpid, role);
321 }
322 }
tom7ef8ff92014-09-17 13:08:06 -0700323 }
324
alshabib8f1cf4a2014-09-17 14:44:48 -0700325 private final class OFMessageHandler implements Runnable {
326
327 private final OFMessage msg;
328 private final Dpid dpid;
329
330 public OFMessageHandler(Dpid dpid, OFMessage msg) {
331 this.msg = msg;
332 this.dpid = dpid;
333 }
334
335 @Override
336 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700337 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700338 listener.handleMessage(dpid, msg);
339 }
340 }
341
342 }
343
tom7ef8ff92014-09-17 13:08:06 -0700344}