blob: a119be3a3f18e4bc9406948a902f8c542bb52302 [file] [log] [blame]
tom7ef8ff92014-09-17 13:08:06 -07001package org.onlab.onos.of.controller.impl;
2
alshabib8f1cf4a2014-09-17 14:44:48 -07003import static org.onlab.util.Tools.namedThreads;
4
tom7ef8ff92014-09-17 13:08:06 -07005import java.util.HashSet;
alshabib8f1cf4a2014-09-17 14:44:48 -07006import java.util.List;
7import java.util.Map;
tom7ef8ff92014-09-17 13:08:06 -07008import java.util.Set;
9import java.util.concurrent.ConcurrentHashMap;
alshabib8f1cf4a2014-09-17 14:44:48 -070010import java.util.concurrent.ExecutorService;
11import java.util.concurrent.Executors;
tom7ef8ff92014-09-17 13:08:06 -070012import java.util.concurrent.locks.Lock;
13import java.util.concurrent.locks.ReentrantLock;
14
15import org.apache.felix.scr.annotations.Activate;
16import org.apache.felix.scr.annotations.Component;
17import org.apache.felix.scr.annotations.Deactivate;
18import org.apache.felix.scr.annotations.Service;
19import org.onlab.onos.of.controller.DefaultOpenFlowPacketContext;
20import org.onlab.onos.of.controller.Dpid;
21import org.onlab.onos.of.controller.OpenFlowController;
alshabib8f1cf4a2014-09-17 14:44:48 -070022import org.onlab.onos.of.controller.OpenFlowEventListener;
tom7ef8ff92014-09-17 13:08:06 -070023import org.onlab.onos.of.controller.OpenFlowPacketContext;
24import org.onlab.onos.of.controller.OpenFlowSwitch;
25import org.onlab.onos.of.controller.OpenFlowSwitchListener;
26import org.onlab.onos.of.controller.PacketListener;
27import org.onlab.onos.of.controller.RoleState;
28import org.onlab.onos.of.controller.driver.OpenFlowAgent;
29import org.projectfloodlight.openflow.protocol.OFMessage;
30import org.projectfloodlight.openflow.protocol.OFPacketIn;
31import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib8f1cf4a2014-09-17 14:44:48 -070032import org.projectfloodlight.openflow.protocol.OFType;
tom7ef8ff92014-09-17 13:08:06 -070033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import com.google.common.collect.ArrayListMultimap;
alshabib8f1cf4a2014-09-17 14:44:48 -070037import com.google.common.collect.Maps;
tom7ef8ff92014-09-17 13:08:06 -070038import com.google.common.collect.Multimap;
39
40@Component(immediate = true)
41@Service
42public class OpenFlowControllerImpl implements OpenFlowController {
43
44 private static final Logger log =
45 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
46
alshabib8f1cf4a2014-09-17 14:44:48 -070047 private final ExecutorService executor = Executors.newFixedThreadPool(16,
48 namedThreads("of-event-dispatch-%d"));
49
50
tom7ef8ff92014-09-17 13:08:06 -070051 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
52 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
53 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
54 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
55 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
56 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
57
58 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
alshabib8f1cf4a2014-09-17 14:44:48 -070059 protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
tom7ef8ff92014-09-17 13:08:06 -070060
61 protected Multimap<Integer, PacketListener> ofPacketListener =
62 ArrayListMultimap.create();
63
alshabib8f1cf4a2014-09-17 14:44:48 -070064 protected Map<OFType, List<OpenFlowEventListener>> ofEventListener = Maps.newHashMap();
tom7ef8ff92014-09-17 13:08:06 -070065
66 private final Controller ctrl = new Controller();
67
68 @Activate
69 public void activate() {
70 ctrl.start(agent);
71 }
72
73 @Deactivate
74 public void deactivate() {
75 ctrl.stop();
76 }
77
78 @Override
79 public Iterable<OpenFlowSwitch> getSwitches() {
80 return connectedSwitches.values();
81 }
82
83 @Override
84 public Iterable<OpenFlowSwitch> getMasterSwitches() {
85 return activeMasterSwitches.values();
86 }
87
88 @Override
89 public Iterable<OpenFlowSwitch> getEqualSwitches() {
90 return activeEqualSwitches.values();
91 }
92
93 @Override
94 public OpenFlowSwitch getSwitch(Dpid dpid) {
95 return connectedSwitches.get(dpid);
96 }
97
98 @Override
99 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
100 return activeMasterSwitches.get(dpid);
101 }
102
103 @Override
104 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
105 return activeEqualSwitches.get(dpid);
106 }
107
108 @Override
109 public void addListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700110 if (!ofSwitchListener.contains(listener)) {
111 this.ofSwitchListener.add(listener);
tom7ef8ff92014-09-17 13:08:06 -0700112 }
113 }
114
115 @Override
116 public void removeListener(OpenFlowSwitchListener listener) {
alshabib8f1cf4a2014-09-17 14:44:48 -0700117 this.ofSwitchListener.remove(listener);
tom7ef8ff92014-09-17 13:08:06 -0700118 }
119
120 @Override
121 public void addPacketListener(int priority, PacketListener listener) {
122 ofPacketListener.put(priority, listener);
123 }
124
125 @Override
126 public void removePacketListener(PacketListener listener) {
127 ofPacketListener.values().remove(listener);
128 }
129
130 @Override
131 public void write(Dpid dpid, OFMessage msg) {
132 this.getSwitch(dpid).sendMsg(msg);
133 }
134
135 @Override
136 public void processPacket(Dpid dpid, OFMessage msg) {
137 switch (msg.getType()) {
138 case PORT_STATUS:
alshabib8f1cf4a2014-09-17 14:44:48 -0700139 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700140 l.portChanged(dpid, (OFPortStatus) msg);
141 }
142 break;
143 case PACKET_IN:
144 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
145 .packetContextFromPacketIn(this.getSwitch(dpid),
146 (OFPacketIn) msg);
147 for (PacketListener p : ofPacketListener.values()) {
148 p.handlePacket(pktCtx);
149 }
150 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700151 case FLOW_REMOVED:
152 case ERROR:
153 case STATS_REPLY:
154 case BARRIER_REPLY:
155 executor.submit(new OFMessageHandler(dpid, msg));
156 break;
tom7ef8ff92014-09-17 13:08:06 -0700157 default:
158 log.warn("Handling message type {} not yet implemented {}",
159 msg.getType(), msg);
160 }
161 }
162
163 @Override
164 public void setRole(Dpid dpid, RoleState role) {
165 getSwitch(dpid).setRole(role);
166 }
167
168 /**
169 * Implementation of an OpenFlow Agent which is responsible for
170 * keeping track of connected switches and the state in which
171 * they are.
172 */
173 public class OpenFlowSwitchAgent implements OpenFlowAgent {
174
175 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
176 private final Lock switchLock = new ReentrantLock();
177
178 @Override
179 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
180 if (connectedSwitches.get(dpid) != null) {
181 log.error("Trying to add connectedSwitch but found a previous "
182 + "value for dpid: {}", dpid);
183 return false;
184 } else {
185 log.error("Added switch {}", dpid);
186 connectedSwitches.put(dpid, sw);
alshabib8f1cf4a2014-09-17 14:44:48 -0700187 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700188 l.switchAdded(dpid);
189 }
190 return true;
191 }
192 }
193
194 @Override
195 public boolean validActivation(Dpid dpid) {
196 if (connectedSwitches.get(dpid) == null) {
197 log.error("Trying to activate switch but is not in "
198 + "connected switches: dpid {}. Aborting ..",
199 dpid);
200 return false;
201 }
202 if (activeMasterSwitches.get(dpid) != null ||
203 activeEqualSwitches.get(dpid) != null) {
204 log.error("Trying to activate switch but it is already "
205 + "activated: dpid {}. Found in activeMaster: {} "
206 + "Found in activeEqual: {}. Aborting ..", new Object[]{
207 dpid,
208 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
209 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
210 return false;
211 }
212 return true;
213 }
214
215
216 @Override
217 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
218 switchLock.lock();
219 try {
220 if (!validActivation(dpid)) {
221 return false;
222 }
223 activeMasterSwitches.put(dpid, sw);
224 return true;
225 } finally {
226 switchLock.unlock();
227 }
228 }
229
230 @Override
231 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
232 switchLock.lock();
233 try {
234 if (!validActivation(dpid)) {
235 return false;
236 }
237 activeEqualSwitches.put(dpid, sw);
238 log.info("Added Activated EQUAL Switch {}", dpid);
239 return true;
240 } finally {
241 switchLock.unlock();
242 }
243 }
244
245 @Override
246 public void transitionToMasterSwitch(Dpid dpid) {
247 switchLock.lock();
248 try {
249 if (activeMasterSwitches.containsKey(dpid)) {
250 return;
251 }
252 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
253 if (sw == null) {
254 sw = getSwitch(dpid);
255 if (sw == null) {
256 log.error("Transition to master called on sw {}, but switch "
257 + "was not found in controller-cache", dpid);
258 return;
259 }
260 }
261 log.info("Transitioned switch {} to MASTER", dpid);
262 activeMasterSwitches.put(dpid, sw);
263 } finally {
264 switchLock.unlock();
265 }
266 }
267
268
269 @Override
270 public void transitionToEqualSwitch(Dpid dpid) {
271 switchLock.lock();
272 try {
273 if (activeEqualSwitches.containsKey(dpid)) {
274 return;
275 }
276 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
277 if (sw == null) {
278 sw = getSwitch(dpid);
279 if (sw == null) {
280 log.error("Transition to equal called on sw {}, but switch "
281 + "was not found in controller-cache", dpid);
282 return;
283 }
284 }
285 log.info("Transitioned switch {} to EQUAL", dpid);
286 activeEqualSwitches.put(dpid, sw);
287 } finally {
288 switchLock.unlock();
289 }
290
291 }
292
293 @Override
294 public void removeConnectedSwitch(Dpid dpid) {
295 connectedSwitches.remove(dpid);
296 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
297 if (sw == null) {
298 sw = activeEqualSwitches.remove(dpid);
299 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700300 for (OpenFlowSwitchListener l : ofSwitchListener) {
tom7ef8ff92014-09-17 13:08:06 -0700301 l.switchRemoved(dpid);
302 }
303 }
304
305 @Override
306 public void processMessage(Dpid dpid, OFMessage m) {
307 processPacket(dpid, m);
308 }
309 }
310
alshabib8f1cf4a2014-09-17 14:44:48 -0700311 private final class OFMessageHandler implements Runnable {
312
313 private final OFMessage msg;
314 private final Dpid dpid;
315
316 public OFMessageHandler(Dpid dpid, OFMessage msg) {
317 this.msg = msg;
318 this.dpid = dpid;
319 }
320
321 @Override
322 public void run() {
323 List<OpenFlowEventListener> listeners =
324 ofEventListener.get(OFType.FLOW_REMOVED);
325 for (OpenFlowEventListener listener : listeners) {
326 listener.handleMessage(dpid, msg);
327 }
328 }
329
330 }
331
tom7ef8ff92014-09-17 13:08:06 -0700332
333}