blob: 685ee9c05a090decf0ed5ddf15073d49edd7f06c [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
tom7ef8ff92014-09-17 13:08:06 -070047 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
48 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
49 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
50 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
51 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
52 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
53
54 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
alshabib8f1cf4a2014-09-17 14:44:48 -070055 protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
tom7ef8ff92014-09-17 13:08:06 -070056
57 protected Multimap<Integer, PacketListener> ofPacketListener =
58 ArrayListMultimap.create();
59
alshabibeec3a062014-09-17 18:01:26 -070060 protected Set<OpenFlowEventListener> ofEventListener = Sets.newHashSet();
tom7ef8ff92014-09-17 13:08:06 -070061
62 private final Controller ctrl = new Controller();
63
64 @Activate
65 public void activate() {
66 ctrl.start(agent);
67 }
68
69 @Deactivate
70 public void deactivate() {
71 ctrl.stop();
72 }
73
74 @Override
75 public Iterable<OpenFlowSwitch> getSwitches() {
76 return connectedSwitches.values();
77 }
78
79 @Override
80 public Iterable<OpenFlowSwitch> getMasterSwitches() {
81 return activeMasterSwitches.values();
82 }
83
84 @Override
85 public Iterable<OpenFlowSwitch> getEqualSwitches() {
86 return activeEqualSwitches.values();
87 }
88
89 @Override
90 public OpenFlowSwitch getSwitch(Dpid dpid) {
91 return connectedSwitches.get(dpid);
92 }
93
94 @Override
95 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
96 return activeMasterSwitches.get(dpid);
97 }
98
99 @Override
100 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
101 return activeEqualSwitches.get(dpid);
102 }
103
104 @Override
105 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700106 if (!ofSwitchListener.contains(listener)) {
107 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700108 }
109 }
110
111 @Override
112 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700113 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700114 }
115
116 @Override
117 public void addPacketListener(int priority, PacketListener listener) {
118 ofPacketListener.put(priority, listener);
119 }
120
121 @Override
122 public void removePacketListener(PacketListener listener) {
123 ofPacketListener.values().remove(listener);
124 }
125
126 @Override
alshabibeec3a062014-09-17 18:01:26 -0700127 public void addEventListener(OpenFlowEventListener listener) {
128 ofEventListener.add(listener);
129 }
130
131 @Override
132 public void removeEventListener(OpenFlowEventListener listener) {
133 ofEventListener.remove(listener);
134 }
135
136 @Override
tom7ef8ff92014-09-17 13:08:06 -0700137 public void write(Dpid dpid, OFMessage msg) {
138 this.getSwitch(dpid).sendMsg(msg);
139 }
140
141 @Override
142 public void processPacket(Dpid dpid, OFMessage msg) {
143 switch (msg.getType()) {
144 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700145 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700146 l.portChanged(dpid, (OFPortStatus) msg);
147 }
148 break;
149 case PACKET_IN:
150 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
151 .packetContextFromPacketIn(this.getSwitch(dpid),
152 (OFPacketIn) msg);
153 for (PacketListener p : ofPacketListener.values()) {
154 p.handlePacket(pktCtx);
155 }
156 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700157 case FLOW_REMOVED:
158 case ERROR:
159 case STATS_REPLY:
160 case BARRIER_REPLY:
161 executor.submit(new OFMessageHandler(dpid, msg));
162 break;
tom7ef8ff92014-09-17 13:08:06 -0700163 default:
164 log.warn("Handling message type {} not yet implemented {}",
165 msg.getType(), msg);
166 }
167 }
168
169 @Override
170 public void setRole(Dpid dpid, RoleState role) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700171 final OpenFlowSwitch sw = getSwitch(dpid);
172 if (sw == null) {
173 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
174 return;
175 }
176 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700177 }
178
179 /**
180 * Implementation of an OpenFlow Agent which is responsible for
181 * keeping track of connected switches and the state in which
182 * they are.
183 */
184 public class OpenFlowSwitchAgent implements OpenFlowAgent {
185
186 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
187 private final Lock switchLock = new ReentrantLock();
188
189 @Override
190 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
191 if (connectedSwitches.get(dpid) != null) {
192 log.error("Trying to add connectedSwitch but found a previous "
193 + "value for dpid: {}", dpid);
194 return false;
195 } else {
196 log.error("Added switch {}", dpid);
197 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700198 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700199 l.switchAdded(dpid);
200 }
201 return true;
202 }
203 }
204
205 @Override
206 public boolean validActivation(Dpid dpid) {
207 if (connectedSwitches.get(dpid) == null) {
208 log.error("Trying to activate switch but is not in "
209 + "connected switches: dpid {}. Aborting ..",
210 dpid);
211 return false;
212 }
213 if (activeMasterSwitches.get(dpid) != null ||
214 activeEqualSwitches.get(dpid) != null) {
215 log.error("Trying to activate switch but it is already "
216 + "activated: dpid {}. Found in activeMaster: {} "
217 + "Found in activeEqual: {}. Aborting ..", new Object[]{
218 dpid,
219 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
220 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
221 return false;
222 }
223 return true;
224 }
225
226
227 @Override
228 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
229 switchLock.lock();
230 try {
231 if (!validActivation(dpid)) {
232 return false;
233 }
234 activeMasterSwitches.put(dpid, sw);
235 return true;
236 } finally {
237 switchLock.unlock();
238 }
239 }
240
241 @Override
242 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
243 switchLock.lock();
244 try {
245 if (!validActivation(dpid)) {
246 return false;
247 }
248 activeEqualSwitches.put(dpid, sw);
249 log.info("Added Activated EQUAL Switch {}", dpid);
250 return true;
251 } finally {
252 switchLock.unlock();
253 }
254 }
255
256 @Override
257 public void transitionToMasterSwitch(Dpid dpid) {
258 switchLock.lock();
259 try {
260 if (activeMasterSwitches.containsKey(dpid)) {
261 return;
262 }
263 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
264 if (sw == null) {
265 sw = getSwitch(dpid);
266 if (sw == null) {
267 log.error("Transition to master called on sw {}, but switch "
268 + "was not found in controller-cache", dpid);
269 return;
270 }
271 }
272 log.info("Transitioned switch {} to MASTER", dpid);
273 activeMasterSwitches.put(dpid, sw);
274 } finally {
275 switchLock.unlock();
276 }
277 }
278
279
280 @Override
281 public void transitionToEqualSwitch(Dpid dpid) {
282 switchLock.lock();
283 try {
284 if (activeEqualSwitches.containsKey(dpid)) {
285 return;
286 }
287 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
288 if (sw == null) {
289 sw = getSwitch(dpid);
290 if (sw == null) {
291 log.error("Transition to equal called on sw {}, but switch "
292 + "was not found in controller-cache", dpid);
293 return;
294 }
295 }
296 log.info("Transitioned switch {} to EQUAL", dpid);
297 activeEqualSwitches.put(dpid, sw);
298 } finally {
299 switchLock.unlock();
300 }
301
302 }
303
304 @Override
305 public void removeConnectedSwitch(Dpid dpid) {
306 connectedSwitches.remove(dpid);
307 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
308 if (sw == null) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700309 log.warn("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700310 sw = activeEqualSwitches.remove(dpid);
311 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700312 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700313 log.warn("removal for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700314 l.switchRemoved(dpid);
315 }
316 }
317
318 @Override
319 public void processMessage(Dpid dpid, OFMessage m) {
320 processPacket(dpid, m);
321 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700322
323 @Override
324 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
325 for (OpenFlowSwitchListener l : ofSwitchListener) {
326 l.roleAssertFailed(dpid, role);
327 }
328 }
tom7ef8ff92014-09-17 13:08:06 -0700329 }
330
alshabib8f1cf4a2014-09-17 14:44:48 -0700331 private final class OFMessageHandler implements Runnable {
332
333 private final OFMessage msg;
334 private final Dpid dpid;
335
336 public OFMessageHandler(Dpid dpid, OFMessage msg) {
337 this.msg = msg;
338 this.dpid = dpid;
339 }
340
341 @Override
342 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700343 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700344 listener.handleMessage(dpid, msg);
345 }
346 }
347
348 }
349
tom7ef8ff92014-09-17 13:08:06 -0700350}