blob: 565ccb9f26239bd056afe81344a70052aeaed4d0 [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) {
alshabib9eab22f2014-10-20 17:17:31 -0700191
tom7ef8ff92014-09-17 13:08:06 -0700192 if (connectedSwitches.get(dpid) != null) {
193 log.error("Trying to add connectedSwitch but found a previous "
194 + "value for dpid: {}", dpid);
195 return false;
196 } else {
197 log.error("Added switch {}", dpid);
198 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700199 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700200 l.switchAdded(dpid);
201 }
202 return true;
203 }
204 }
205
206 @Override
207 public boolean validActivation(Dpid dpid) {
208 if (connectedSwitches.get(dpid) == null) {
209 log.error("Trying to activate switch but is not in "
210 + "connected switches: dpid {}. Aborting ..",
211 dpid);
212 return false;
213 }
214 if (activeMasterSwitches.get(dpid) != null ||
215 activeEqualSwitches.get(dpid) != null) {
216 log.error("Trying to activate switch but it is already "
217 + "activated: dpid {}. Found in activeMaster: {} "
218 + "Found in activeEqual: {}. Aborting ..", new Object[]{
219 dpid,
220 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
221 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
222 return false;
223 }
224 return true;
225 }
226
227
228 @Override
229 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
230 switchLock.lock();
231 try {
232 if (!validActivation(dpid)) {
233 return false;
234 }
235 activeMasterSwitches.put(dpid, sw);
236 return true;
237 } finally {
238 switchLock.unlock();
239 }
240 }
241
242 @Override
243 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
244 switchLock.lock();
245 try {
246 if (!validActivation(dpid)) {
247 return false;
248 }
249 activeEqualSwitches.put(dpid, sw);
250 log.info("Added Activated EQUAL Switch {}", dpid);
251 return true;
252 } finally {
253 switchLock.unlock();
254 }
255 }
256
257 @Override
258 public void transitionToMasterSwitch(Dpid dpid) {
259 switchLock.lock();
260 try {
261 if (activeMasterSwitches.containsKey(dpid)) {
262 return;
263 }
264 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
265 if (sw == null) {
266 sw = getSwitch(dpid);
267 if (sw == null) {
268 log.error("Transition to master called on sw {}, but switch "
269 + "was not found in controller-cache", dpid);
270 return;
271 }
272 }
273 log.info("Transitioned switch {} to MASTER", dpid);
274 activeMasterSwitches.put(dpid, sw);
275 } finally {
276 switchLock.unlock();
277 }
278 }
279
280
281 @Override
282 public void transitionToEqualSwitch(Dpid dpid) {
283 switchLock.lock();
284 try {
285 if (activeEqualSwitches.containsKey(dpid)) {
286 return;
287 }
288 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
289 if (sw == null) {
290 sw = getSwitch(dpid);
291 if (sw == null) {
292 log.error("Transition to equal called on sw {}, but switch "
293 + "was not found in controller-cache", dpid);
294 return;
295 }
296 }
297 log.info("Transitioned switch {} to EQUAL", dpid);
298 activeEqualSwitches.put(dpid, sw);
299 } finally {
300 switchLock.unlock();
301 }
302
303 }
304
305 @Override
306 public void removeConnectedSwitch(Dpid dpid) {
307 connectedSwitches.remove(dpid);
308 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
309 if (sw == null) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700310 log.warn("sw was null for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700311 sw = activeEqualSwitches.remove(dpid);
312 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700313 for (OpenFlowSwitchListener l : ofSwitchListener) {
Ayaka Koshibec4047702014-10-07 14:43:52 -0700314 log.warn("removal for {}", dpid);
tom7ef8ff92014-09-17 13:08:06 -0700315 l.switchRemoved(dpid);
316 }
317 }
318
319 @Override
320 public void processMessage(Dpid dpid, OFMessage m) {
321 processPacket(dpid, m);
322 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700323
324 @Override
325 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
326 for (OpenFlowSwitchListener l : ofSwitchListener) {
327 l.roleAssertFailed(dpid, role);
328 }
329 }
tom7ef8ff92014-09-17 13:08:06 -0700330 }
331
alshabib8f1cf4a2014-09-17 14:44:48 -0700332 private final class OFMessageHandler implements Runnable {
333
334 private final OFMessage msg;
335 private final Dpid dpid;
336
337 public OFMessageHandler(Dpid dpid, OFMessage msg) {
338 this.msg = msg;
339 this.dpid = dpid;
340 }
341
342 @Override
343 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700344 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700345 listener.handleMessage(dpid, msg);
346 }
347 }
348
349 }
350
tom7ef8ff92014-09-17 13:08:06 -0700351}