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