blob: 46b8be62267f1d8ad6e782aaaed2775a3c4b403a [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:
Ayaka Koshibee8708e32014-10-22 13:40:18 -0700145 case FEATURES_REPLY:
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) {
Yuta HIGUCHI79cbd1c2014-10-02 16:57:57 -0700172 final OpenFlowSwitch sw = getSwitch(dpid);
173 if (sw == null) {
174 log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role);
175 return;
176 }
177 sw.setRole(role);
tom7ef8ff92014-09-17 13:08:06 -0700178 }
179
180 /**
181 * Implementation of an OpenFlow Agent which is responsible for
182 * keeping track of connected switches and the state in which
183 * they are.
184 */
185 public class OpenFlowSwitchAgent implements OpenFlowAgent {
186
187 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
188 private final Lock switchLock = new ReentrantLock();
189
190 @Override
191 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
alshabib9eab22f2014-10-20 17:17:31 -0700192
tom7ef8ff92014-09-17 13:08:06 -0700193 if (connectedSwitches.get(dpid) != null) {
194 log.error("Trying to add connectedSwitch but found a previous "
195 + "value for dpid: {}", dpid);
196 return false;
197 } else {
198 log.error("Added switch {}", dpid);
199 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700200 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700201 l.switchAdded(dpid);
202 }
203 return true;
204 }
205 }
206
207 @Override
208 public boolean validActivation(Dpid dpid) {
209 if (connectedSwitches.get(dpid) == null) {
210 log.error("Trying to activate switch but is not in "
211 + "connected switches: dpid {}. Aborting ..",
212 dpid);
213 return false;
214 }
215 if (activeMasterSwitches.get(dpid) != null ||
216 activeEqualSwitches.get(dpid) != null) {
217 log.error("Trying to activate switch but it is already "
218 + "activated: dpid {}. Found in activeMaster: {} "
219 + "Found in activeEqual: {}. Aborting ..", new Object[]{
220 dpid,
221 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
222 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
223 return false;
224 }
225 return true;
226 }
227
228
229 @Override
230 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
231 switchLock.lock();
232 try {
233 if (!validActivation(dpid)) {
234 return false;
235 }
236 activeMasterSwitches.put(dpid, sw);
237 return true;
238 } finally {
239 switchLock.unlock();
240 }
241 }
242
243 @Override
244 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
245 switchLock.lock();
246 try {
247 if (!validActivation(dpid)) {
248 return false;
249 }
250 activeEqualSwitches.put(dpid, sw);
251 log.info("Added Activated EQUAL Switch {}", dpid);
252 return true;
253 } finally {
254 switchLock.unlock();
255 }
256 }
257
258 @Override
259 public void transitionToMasterSwitch(Dpid dpid) {
260 switchLock.lock();
261 try {
262 if (activeMasterSwitches.containsKey(dpid)) {
263 return;
264 }
265 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
266 if (sw == null) {
267 sw = getSwitch(dpid);
268 if (sw == null) {
269 log.error("Transition to master called on sw {}, but switch "
270 + "was not found in controller-cache", dpid);
271 return;
272 }
273 }
274 log.info("Transitioned switch {} to MASTER", dpid);
275 activeMasterSwitches.put(dpid, sw);
276 } finally {
277 switchLock.unlock();
278 }
279 }
280
281
282 @Override
283 public void transitionToEqualSwitch(Dpid dpid) {
284 switchLock.lock();
285 try {
286 if (activeEqualSwitches.containsKey(dpid)) {
287 return;
288 }
289 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
290 if (sw == null) {
291 sw = getSwitch(dpid);
292 if (sw == null) {
293 log.error("Transition to equal called on sw {}, but switch "
294 + "was not found in controller-cache", dpid);
295 return;
296 }
297 }
298 log.info("Transitioned switch {} to EQUAL", dpid);
299 activeEqualSwitches.put(dpid, sw);
300 } finally {
301 switchLock.unlock();
302 }
303
304 }
305
306 @Override
307 public void removeConnectedSwitch(Dpid dpid) {
308 connectedSwitches.remove(dpid);
309 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
310 if (sw == null) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700311 log.warn("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700312 sw = activeEqualSwitches.remove(dpid);
313 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700314 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700315 log.warn("removal for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700316 l.switchRemoved(dpid);
317 }
318 }
319
320 @Override
321 public void processMessage(Dpid dpid, OFMessage m) {
322 processPacket(dpid, m);
323 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700324
325 @Override
326 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
327 for (OpenFlowSwitchListener l : ofSwitchListener) {
328 l.roleAssertFailed(dpid, role);
329 }
330 }
tom7ef8ff92014-09-17 13:08:06 -0700331 }
332
alshabib8f1cf4a2014-09-17 14:44:48 -0700333 private final class OFMessageHandler implements Runnable {
334
335 private final OFMessage msg;
336 private final Dpid dpid;
337
338 public OFMessageHandler(Dpid dpid, OFMessage msg) {
339 this.msg = msg;
340 this.dpid = dpid;
341 }
342
343 @Override
344 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700345 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700346 listener.handleMessage(dpid, msg);
347 }
348 }
349
350 }
351
tom7ef8ff92014-09-17 13:08:06 -0700352}