blob: a8b06735675c112bd09b963e46ef09b1c8d253ad [file] [log] [blame]
tom7ef8ff92014-09-17 13:08:06 -07001package org.onlab.onos.of.controller.impl;
2
3import java.util.HashSet;
4import java.util.Set;
5import java.util.concurrent.ConcurrentHashMap;
6import java.util.concurrent.locks.Lock;
7import java.util.concurrent.locks.ReentrantLock;
8
9import org.apache.felix.scr.annotations.Activate;
10import org.apache.felix.scr.annotations.Component;
11import org.apache.felix.scr.annotations.Deactivate;
12import org.apache.felix.scr.annotations.Service;
13import org.onlab.onos.of.controller.DefaultOpenFlowPacketContext;
14import org.onlab.onos.of.controller.Dpid;
15import org.onlab.onos.of.controller.OpenFlowController;
16import org.onlab.onos.of.controller.OpenFlowPacketContext;
17import org.onlab.onos.of.controller.OpenFlowSwitch;
18import org.onlab.onos.of.controller.OpenFlowSwitchListener;
19import org.onlab.onos.of.controller.PacketListener;
20import org.onlab.onos.of.controller.RoleState;
21import org.onlab.onos.of.controller.driver.OpenFlowAgent;
22import org.projectfloodlight.openflow.protocol.OFMessage;
23import org.projectfloodlight.openflow.protocol.OFPacketIn;
24import org.projectfloodlight.openflow.protocol.OFPortStatus;
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
28import com.google.common.collect.ArrayListMultimap;
29import com.google.common.collect.Multimap;
30
31@Component(immediate = true)
32@Service
33public class OpenFlowControllerImpl implements OpenFlowController {
34
35 private static final Logger log =
36 LoggerFactory.getLogger(OpenFlowControllerImpl.class);
37
38 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
39 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
40 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
41 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
42 protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
43 new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
44
45 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
46 protected Set<OpenFlowSwitchListener> ofEventListener = new HashSet<>();
47
48 protected Multimap<Integer, PacketListener> ofPacketListener =
49 ArrayListMultimap.create();
50
51
52 private final Controller ctrl = new Controller();
53
54 @Activate
55 public void activate() {
56 ctrl.start(agent);
57 }
58
59 @Deactivate
60 public void deactivate() {
61 ctrl.stop();
62 }
63
64 @Override
65 public Iterable<OpenFlowSwitch> getSwitches() {
66 return connectedSwitches.values();
67 }
68
69 @Override
70 public Iterable<OpenFlowSwitch> getMasterSwitches() {
71 return activeMasterSwitches.values();
72 }
73
74 @Override
75 public Iterable<OpenFlowSwitch> getEqualSwitches() {
76 return activeEqualSwitches.values();
77 }
78
79 @Override
80 public OpenFlowSwitch getSwitch(Dpid dpid) {
81 return connectedSwitches.get(dpid);
82 }
83
84 @Override
85 public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
86 return activeMasterSwitches.get(dpid);
87 }
88
89 @Override
90 public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
91 return activeEqualSwitches.get(dpid);
92 }
93
94 @Override
95 public void addListener(OpenFlowSwitchListener listener) {
96 if (!ofEventListener.contains(listener)) {
97 this.ofEventListener.add(listener);
98 }
99 }
100
101 @Override
102 public void removeListener(OpenFlowSwitchListener listener) {
103 this.ofEventListener.remove(listener);
104 }
105
106 @Override
107 public void addPacketListener(int priority, PacketListener listener) {
108 ofPacketListener.put(priority, listener);
109 }
110
111 @Override
112 public void removePacketListener(PacketListener listener) {
113 ofPacketListener.values().remove(listener);
114 }
115
116 @Override
117 public void write(Dpid dpid, OFMessage msg) {
118 this.getSwitch(dpid).sendMsg(msg);
119 }
120
121 @Override
122 public void processPacket(Dpid dpid, OFMessage msg) {
123 switch (msg.getType()) {
124 case PORT_STATUS:
125 for (OpenFlowSwitchListener l : ofEventListener) {
126 l.portChanged(dpid, (OFPortStatus) msg);
127 }
128 break;
129 case PACKET_IN:
130 OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
131 .packetContextFromPacketIn(this.getSwitch(dpid),
132 (OFPacketIn) msg);
133 for (PacketListener p : ofPacketListener.values()) {
134 p.handlePacket(pktCtx);
135 }
136 break;
137 default:
138 log.warn("Handling message type {} not yet implemented {}",
139 msg.getType(), msg);
140 }
141 }
142
143 @Override
144 public void setRole(Dpid dpid, RoleState role) {
145 getSwitch(dpid).setRole(role);
146 }
147
148 /**
149 * Implementation of an OpenFlow Agent which is responsible for
150 * keeping track of connected switches and the state in which
151 * they are.
152 */
153 public class OpenFlowSwitchAgent implements OpenFlowAgent {
154
155 private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
156 private final Lock switchLock = new ReentrantLock();
157
158 @Override
159 public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
160 if (connectedSwitches.get(dpid) != null) {
161 log.error("Trying to add connectedSwitch but found a previous "
162 + "value for dpid: {}", dpid);
163 return false;
164 } else {
165 log.error("Added switch {}", dpid);
166 connectedSwitches.put(dpid, sw);
167 for (OpenFlowSwitchListener l : ofEventListener) {
168 l.switchAdded(dpid);
169 }
170 return true;
171 }
172 }
173
174 @Override
175 public boolean validActivation(Dpid dpid) {
176 if (connectedSwitches.get(dpid) == null) {
177 log.error("Trying to activate switch but is not in "
178 + "connected switches: dpid {}. Aborting ..",
179 dpid);
180 return false;
181 }
182 if (activeMasterSwitches.get(dpid) != null ||
183 activeEqualSwitches.get(dpid) != null) {
184 log.error("Trying to activate switch but it is already "
185 + "activated: dpid {}. Found in activeMaster: {} "
186 + "Found in activeEqual: {}. Aborting ..", new Object[]{
187 dpid,
188 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
189 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
190 return false;
191 }
192 return true;
193 }
194
195
196 @Override
197 public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
198 switchLock.lock();
199 try {
200 if (!validActivation(dpid)) {
201 return false;
202 }
203 activeMasterSwitches.put(dpid, sw);
204 return true;
205 } finally {
206 switchLock.unlock();
207 }
208 }
209
210 @Override
211 public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
212 switchLock.lock();
213 try {
214 if (!validActivation(dpid)) {
215 return false;
216 }
217 activeEqualSwitches.put(dpid, sw);
218 log.info("Added Activated EQUAL Switch {}", dpid);
219 return true;
220 } finally {
221 switchLock.unlock();
222 }
223 }
224
225 @Override
226 public void transitionToMasterSwitch(Dpid dpid) {
227 switchLock.lock();
228 try {
229 if (activeMasterSwitches.containsKey(dpid)) {
230 return;
231 }
232 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
233 if (sw == null) {
234 sw = getSwitch(dpid);
235 if (sw == null) {
236 log.error("Transition to master called on sw {}, but switch "
237 + "was not found in controller-cache", dpid);
238 return;
239 }
240 }
241 log.info("Transitioned switch {} to MASTER", dpid);
242 activeMasterSwitches.put(dpid, sw);
243 } finally {
244 switchLock.unlock();
245 }
246 }
247
248
249 @Override
250 public void transitionToEqualSwitch(Dpid dpid) {
251 switchLock.lock();
252 try {
253 if (activeEqualSwitches.containsKey(dpid)) {
254 return;
255 }
256 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
257 if (sw == null) {
258 sw = getSwitch(dpid);
259 if (sw == null) {
260 log.error("Transition to equal called on sw {}, but switch "
261 + "was not found in controller-cache", dpid);
262 return;
263 }
264 }
265 log.info("Transitioned switch {} to EQUAL", dpid);
266 activeEqualSwitches.put(dpid, sw);
267 } finally {
268 switchLock.unlock();
269 }
270
271 }
272
273 @Override
274 public void removeConnectedSwitch(Dpid dpid) {
275 connectedSwitches.remove(dpid);
276 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
277 if (sw == null) {
278 sw = activeEqualSwitches.remove(dpid);
279 }
280 for (OpenFlowSwitchListener l : ofEventListener) {
281 l.switchRemoved(dpid);
282 }
283 }
284
285 @Override
286 public void processMessage(Dpid dpid, OFMessage m) {
287 processPacket(dpid, m);
288 }
289 }
290
291
292}