blob: 433439521a8466a0de67a4efd414d49a0873ada9 [file] [log] [blame]
tom7ef8ff92014-09-17 13:08:06 -07001/**
2 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
17
tom9c94c5b2014-09-17 13:14:42 -070018package org.onlab.onos.openflow.controller.driver;
tom7ef8ff92014-09-17 13:08:06 -070019
20import java.io.IOException;
21import java.util.Collections;
22import java.util.List;
23import java.util.concurrent.atomic.AtomicInteger;
24
25import org.jboss.netty.channel.Channel;
tom9c94c5b2014-09-17 13:14:42 -070026import org.onlab.onos.openflow.controller.Dpid;
27import org.onlab.onos.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070028import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
29import org.projectfloodlight.openflow.protocol.OFErrorMsg;
30import org.projectfloodlight.openflow.protocol.OFExperimenter;
31import org.projectfloodlight.openflow.protocol.OFFactories;
32import org.projectfloodlight.openflow.protocol.OFFactory;
33import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
34import org.projectfloodlight.openflow.protocol.OFMessage;
35import org.projectfloodlight.openflow.protocol.OFPortDesc;
36import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
37import org.projectfloodlight.openflow.protocol.OFRoleReply;
38import org.projectfloodlight.openflow.protocol.OFVersion;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42/**
43 * An abstract representation of an OpenFlow switch. Can be extended by others
44 * to serve as a base for their vendor specific representation of a switch.
45 */
46public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
47
48 private static Logger log =
49 LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
50
51 protected Channel channel;
52
53 private boolean connected;
54 protected boolean startDriverHandshakeCalled = false;
55 private final Dpid dpid;
56 private OpenFlowAgent agent;
57 private final AtomicInteger xidCounter = new AtomicInteger(0);
58
59 private OFVersion ofVersion;
60
61 protected OFPortDescStatsReply ports;
62
63 protected boolean tableFull;
64
65 private RoleHandler roleMan;
66
67 protected RoleState role;
68
69 protected OFFeaturesReply features;
70 protected OFDescStatsReply desc;
71
72 /**
73 * Given a dpid build this switch.
74 * @param dp the dpid
75 */
76 protected AbstractOpenFlowSwitch(Dpid dp) {
77 this.dpid = dp;
78 }
79
80 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
81 this.dpid = dpid;
82 this.desc = desc;
83 }
84
85 //************************
86 // Channel related
87 //************************
88
89 @Override
90 public final void disconnectSwitch() {
91 this.channel.close();
92 }
93
94 @Override
95 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -070096 if (role == RoleState.MASTER) {
97 this.write(m);
98 }
tom7ef8ff92014-09-17 13:08:06 -070099 }
100
101 @Override
102 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700103 if (role == RoleState.MASTER) {
104 this.write(msgs);
105 }
tom7ef8ff92014-09-17 13:08:06 -0700106 }
107
108 @Override
109 public abstract void write(OFMessage msg);
110
111 @Override
112 public abstract void write(List<OFMessage> msgs);
113
114 @Override
115 public final boolean isConnected() {
116 return this.connected;
117 }
118
119 @Override
120 public final void setConnected(boolean connected) {
121 this.connected = connected;
122 };
123
124 @Override
125 public final void setChannel(Channel channel) {
126 this.channel = channel;
127 };
128
129 //************************
130 // Switch features related
131 //************************
132
133 @Override
134 public final long getId() {
135 return this.dpid.value();
136 };
137
138 @Override
139 public final String getStringId() {
140 return this.dpid.toString();
141 }
142
143 @Override
144 public final void setOFVersion(OFVersion ofV) {
145 this.ofVersion = ofV;
146 }
147
148 @Override
149 public void setTableFull(boolean full) {
150 this.tableFull = full;
151 }
152
153 @Override
154 public void setFeaturesReply(OFFeaturesReply featuresReply) {
155 this.features = featuresReply;
156 }
157
158 @Override
159 public abstract Boolean supportNxRole();
160
161 //************************
162 // Message handling
163 //************************
164 /**
165 * Handle the message coming from the dataplane.
166 *
167 * @param m the actual message
168 */
169 @Override
170 public final void handleMessage(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -0700171 if (this.role == RoleState.MASTER) {
172 this.agent.processMessage(dpid, m);
173 }
tom7ef8ff92014-09-17 13:08:06 -0700174 }
175
176 @Override
177 public RoleState getRole() {
178 return role;
179 };
180
181 @Override
182 public final boolean connectSwitch() {
183 return this.agent.addConnectedSwitch(dpid, this);
184 }
185
186 @Override
187 public final boolean activateMasterSwitch() {
188 return this.agent.addActivatedMasterSwitch(dpid, this);
189 }
190
191 @Override
192 public final boolean activateEqualSwitch() {
193 return this.agent.addActivatedEqualSwitch(dpid, this);
194 }
195
196 @Override
197 public final void transitionToEqualSwitch() {
198 this.agent.transitionToEqualSwitch(dpid);
199 }
200
201 @Override
202 public final void transitionToMasterSwitch() {
203 this.agent.transitionToMasterSwitch(dpid);
204 }
205
206 @Override
207 public final void removeConnectedSwitch() {
208 this.agent.removeConnectedSwitch(dpid);
209 }
210
211 @Override
212 public OFFactory factory() {
213 return OFFactories.getFactory(ofVersion);
214 }
215
216 @Override
217 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
218 this.ports = portDescReply;
219 }
220
221 @Override
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700222 public void returnRoleAssertFailure(RoleState role) {
223 this.agent.returnRoleAssertFailed(dpid, role);
224 }
225
226 @Override
tom7ef8ff92014-09-17 13:08:06 -0700227 public abstract void startDriverHandshake();
228
229 @Override
230 public abstract boolean isDriverHandshakeComplete();
231
232 @Override
233 public abstract void processDriverHandshakeMessage(OFMessage m);
234
alshabib339a3d92014-09-26 17:54:32 -0700235
236 // Role Handling
237
tom7ef8ff92014-09-17 13:08:06 -0700238 @Override
239 public void setRole(RoleState role) {
240 try {
tom7ef8ff92014-09-17 13:08:06 -0700241 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700242 log.info("Sending role {} to switch {}", role, getStringId());
243 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
244 this.role = role;
245 }
alshabib7814e9f2014-09-30 11:52:12 -0700246 } else {
247 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700248 }
249 } catch (IOException e) {
250 log.error("Unable to write to switch {}.", this.dpid);
251 }
252 }
253
alshabib339a3d92014-09-26 17:54:32 -0700254 @Override
255 public void reassertRole() {
256 if (this.getRole() == RoleState.MASTER) {
257 log.warn("Received permission error from switch {} while " +
258 "being master. Reasserting master role.",
259 this.getStringId());
260 this.setRole(RoleState.MASTER);
261 }
262 }
263
264
tom7ef8ff92014-09-17 13:08:06 -0700265
266 @Override
267 public void handleRole(OFMessage m) throws SwitchStateException {
268 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
269 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
270 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
271 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700272 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700273 this.transitionToMasterSwitch();
274 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700275 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700276 this.transitionToEqualSwitch();
277 }
alshabib339a3d92014-09-26 17:54:32 -0700278 } else {
279 return;
280 //TODO: tell people that we failed.
tom7ef8ff92014-09-17 13:08:06 -0700281 }
282 }
283
284 @Override
285 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
286 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
287 if (r == null) {
288 // The message wasn't really a Nicira role reply. We just
289 // dispatch it to the OFMessage listeners in this case.
290 this.handleMessage(m);
291 }
292
293 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
294 new RoleReplyInfo(r, null, m.getXid()));
295 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
296 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700297 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700298 this.transitionToMasterSwitch();
299 } else if (r == RoleState.EQUAL ||
300 r == RoleState.SLAVE) {
301 this.transitionToEqualSwitch();
302 }
alshabib339a3d92014-09-26 17:54:32 -0700303 } else {
304 return;
305 //TODO: tell people that we failed.
tom7ef8ff92014-09-17 13:08:06 -0700306 }
307 }
308
309 @Override
310 public boolean handleRoleError(OFErrorMsg error) {
311 try {
312 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
313 } catch (SwitchStateException e) {
314 this.disconnectSwitch();
315 }
316 return true;
317 }
318
alshabib339a3d92014-09-26 17:54:32 -0700319
tom7ef8ff92014-09-17 13:08:06 -0700320
321 @Override
322 public final void setAgent(OpenFlowAgent ag) {
323 if (this.agent == null) {
324 this.agent = ag;
325 }
326 }
327
328 @Override
329 public final void setRoleHandler(RoleHandler roleHandler) {
330 if (this.roleMan == null) {
331 this.roleMan = roleHandler;
332 }
333 }
334
335 @Override
336 public void setSwitchDescription(OFDescStatsReply d) {
337 this.desc = d;
338 }
339
340 @Override
341 public int getNextTransactionId() {
342 return this.xidCounter.getAndIncrement();
343 }
344
345 @Override
346 public List<OFPortDesc> getPorts() {
347 return Collections.unmodifiableList(ports.getEntries());
348 }
349
350 @Override
351 public String manfacturerDescription() {
352 return this.desc.getMfrDesc();
353 }
354
355
356 @Override
357 public String datapathDescription() {
358 return this.desc.getDpDesc();
359 }
360
361
362 @Override
363 public String hardwareDescription() {
364 return this.desc.getHwDesc();
365 }
366
367 @Override
368 public String softwareDescription() {
369 return this.desc.getSwDesc();
370 }
371
372 @Override
373 public String serialNumber() {
374 return this.desc.getSerialNum();
375 }
376
377}