blob: e8ebcd1bbea883eb334df04c75814428a80e2f89 [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) {
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) {
192 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) {
310 sw = activeEqualSwitches.remove(dpid);
311 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700312 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700313 l.switchRemoved(dpid);
314 }
315 }
316
317 @Override
318 public void processMessage(Dpid dpid, OFMessage m) {
319 processPacket(dpid, m);
320 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700321
322 @Override
323 public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
324 for (OpenFlowSwitchListener l : ofSwitchListener) {
325 l.roleAssertFailed(dpid, role);
326 }
327 }
tom7ef8ff92014-09-17 13:08:06 -0700328 }
329
alshabib8f1cf4a2014-09-17 14:44:48 -0700330 private final class OFMessageHandler implements Runnable {
331
332 private final OFMessage msg;
333 private final Dpid dpid;
334
335 public OFMessageHandler(Dpid dpid, OFMessage msg) {
336 this.msg = msg;
337 this.dpid = dpid;
338 }
339
340 @Override
341 public void run() {
alshabibeec3a062014-09-17 18:01:26 -0700342 for (OpenFlowEventListener listener : ofEventListener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700343 listener.handleMessage(dpid, msg);
344 }
345 }
346
347 }
348
tom7ef8ff92014-09-17 13:08:06 -0700349}