blob: 3a19d140824aad4b0926045d50826bd257fbf8ab [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
tom7ef8ff92014-09-17 13:08:06 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
tom7ef8ff92014-09-17 13:08:06 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
tom7ef8ff92014-09-17 13:08:06 -070016
tom9c94c5b2014-09-17 13:14:42 -070017package org.onlab.onos.openflow.controller.driver;
tom7ef8ff92014-09-17 13:08:06 -070018
19import java.io.IOException;
20import java.util.Collections;
21import java.util.List;
22import java.util.concurrent.atomic.AtomicInteger;
23
24import org.jboss.netty.channel.Channel;
tom9c94c5b2014-09-17 13:14:42 -070025import org.onlab.onos.openflow.controller.Dpid;
26import org.onlab.onos.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070027import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
28import org.projectfloodlight.openflow.protocol.OFErrorMsg;
29import org.projectfloodlight.openflow.protocol.OFExperimenter;
30import org.projectfloodlight.openflow.protocol.OFFactories;
31import org.projectfloodlight.openflow.protocol.OFFactory;
32import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
33import org.projectfloodlight.openflow.protocol.OFMessage;
34import org.projectfloodlight.openflow.protocol.OFPortDesc;
35import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080036import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070037import 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
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070048 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070049
50 protected Channel channel;
51
52 private boolean connected;
53 protected boolean startDriverHandshakeCalled = false;
54 private final Dpid dpid;
55 private OpenFlowAgent agent;
56 private final AtomicInteger xidCounter = new AtomicInteger(0);
57
58 private OFVersion ofVersion;
59
60 protected OFPortDescStatsReply ports;
61
62 protected boolean tableFull;
63
64 private RoleHandler roleMan;
65
66 protected RoleState role;
67
68 protected OFFeaturesReply features;
69 protected OFDescStatsReply desc;
70
71 /**
72 * Given a dpid build this switch.
73 * @param dp the dpid
74 */
75 protected AbstractOpenFlowSwitch(Dpid dp) {
76 this.dpid = dp;
77 }
78
79 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
80 this.dpid = dpid;
81 this.desc = desc;
82 }
83
84 //************************
85 // Channel related
86 //************************
87
88 @Override
89 public final void disconnectSwitch() {
90 this.channel.close();
91 }
92
93 @Override
94 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -070095 if (role == RoleState.MASTER) {
96 this.write(m);
97 }
tom7ef8ff92014-09-17 13:08:06 -070098 }
99
100 @Override
101 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700102 if (role == RoleState.MASTER) {
103 this.write(msgs);
104 }
tom7ef8ff92014-09-17 13:08:06 -0700105 }
106
107 @Override
108 public abstract void write(OFMessage msg);
109
110 @Override
111 public abstract void write(List<OFMessage> msgs);
112
113 @Override
114 public final boolean isConnected() {
115 return this.connected;
116 }
117
118 @Override
119 public final void setConnected(boolean connected) {
120 this.connected = connected;
121 };
122
123 @Override
124 public final void setChannel(Channel channel) {
125 this.channel = channel;
126 };
127
128 //************************
129 // Switch features related
130 //************************
131
132 @Override
133 public final long getId() {
134 return this.dpid.value();
135 };
136
137 @Override
138 public final String getStringId() {
139 return this.dpid.toString();
140 }
141
142 @Override
143 public final void setOFVersion(OFVersion ofV) {
144 this.ofVersion = ofV;
145 }
146
147 @Override
148 public void setTableFull(boolean full) {
149 this.tableFull = full;
150 }
151
152 @Override
153 public void setFeaturesReply(OFFeaturesReply featuresReply) {
154 this.features = featuresReply;
155 }
156
157 @Override
158 public abstract Boolean supportNxRole();
159
160 //************************
161 // Message handling
162 //************************
163 /**
164 * Handle the message coming from the dataplane.
165 *
166 * @param m the actual message
167 */
168 @Override
169 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800170 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700171 this.agent.processMessage(dpid, m);
172 }
tom7ef8ff92014-09-17 13:08:06 -0700173 }
174
175 @Override
176 public RoleState getRole() {
177 return role;
178 };
179
180 @Override
181 public final boolean connectSwitch() {
182 return this.agent.addConnectedSwitch(dpid, this);
183 }
184
185 @Override
186 public final boolean activateMasterSwitch() {
187 return this.agent.addActivatedMasterSwitch(dpid, this);
188 }
189
190 @Override
191 public final boolean activateEqualSwitch() {
192 return this.agent.addActivatedEqualSwitch(dpid, this);
193 }
194
195 @Override
196 public final void transitionToEqualSwitch() {
197 this.agent.transitionToEqualSwitch(dpid);
198 }
199
200 @Override
201 public final void transitionToMasterSwitch() {
202 this.agent.transitionToMasterSwitch(dpid);
203 }
204
205 @Override
206 public final void removeConnectedSwitch() {
207 this.agent.removeConnectedSwitch(dpid);
208 }
209
210 @Override
211 public OFFactory factory() {
212 return OFFactories.getFactory(ofVersion);
213 }
214
215 @Override
216 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
217 this.ports = portDescReply;
218 }
219
220 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700221 public void returnRoleReply(RoleState requested, RoleState response) {
222 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700223 }
224
225 @Override
tom7ef8ff92014-09-17 13:08:06 -0700226 public abstract void startDriverHandshake();
227
228 @Override
229 public abstract boolean isDriverHandshakeComplete();
230
231 @Override
232 public abstract void processDriverHandshakeMessage(OFMessage m);
233
alshabib339a3d92014-09-26 17:54:32 -0700234
235 // Role Handling
236
tom7ef8ff92014-09-17 13:08:06 -0700237 @Override
238 public void setRole(RoleState role) {
239 try {
tom7ef8ff92014-09-17 13:08:06 -0700240 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700241 log.info("Sending role {} to switch {}", role, getStringId());
242 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
243 this.role = role;
244 }
alshabib7814e9f2014-09-30 11:52:12 -0700245 } else {
246 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700247 }
248 } catch (IOException e) {
249 log.error("Unable to write to switch {}.", this.dpid);
250 }
251 }
252
alshabib339a3d92014-09-26 17:54:32 -0700253 @Override
254 public void reassertRole() {
255 if (this.getRole() == RoleState.MASTER) {
256 log.warn("Received permission error from switch {} while " +
257 "being master. Reasserting master role.",
258 this.getStringId());
259 this.setRole(RoleState.MASTER);
260 }
261 }
262
263
tom7ef8ff92014-09-17 13:08:06 -0700264
265 @Override
266 public void handleRole(OFMessage m) throws SwitchStateException {
267 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
268 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
269 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
270 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700271 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700272 this.transitionToMasterSwitch();
273 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700274 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700275 this.transitionToEqualSwitch();
276 }
alshabib339a3d92014-09-26 17:54:32 -0700277 } else {
278 return;
279 //TODO: tell people that we failed.
tom7ef8ff92014-09-17 13:08:06 -0700280 }
281 }
282
283 @Override
284 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
285 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
286 if (r == null) {
287 // The message wasn't really a Nicira role reply. We just
288 // dispatch it to the OFMessage listeners in this case.
289 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700290 return;
tom7ef8ff92014-09-17 13:08:06 -0700291 }
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 {
alshabibdfc7afb2014-10-21 20:13:27 -0700304 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700305 }
306 }
307
308 @Override
309 public boolean handleRoleError(OFErrorMsg error) {
310 try {
311 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
312 } catch (SwitchStateException e) {
313 this.disconnectSwitch();
314 }
315 return true;
316 }
317
alshabib339a3d92014-09-26 17:54:32 -0700318
tom7ef8ff92014-09-17 13:08:06 -0700319
320 @Override
321 public final void setAgent(OpenFlowAgent ag) {
322 if (this.agent == null) {
323 this.agent = ag;
324 }
325 }
326
327 @Override
328 public final void setRoleHandler(RoleHandler roleHandler) {
329 if (this.roleMan == null) {
330 this.roleMan = roleHandler;
331 }
332 }
333
334 @Override
335 public void setSwitchDescription(OFDescStatsReply d) {
336 this.desc = d;
337 }
338
339 @Override
340 public int getNextTransactionId() {
341 return this.xidCounter.getAndIncrement();
342 }
343
344 @Override
345 public List<OFPortDesc> getPorts() {
346 return Collections.unmodifiableList(ports.getEntries());
347 }
348
349 @Override
350 public String manfacturerDescription() {
351 return this.desc.getMfrDesc();
352 }
353
354
355 @Override
356 public String datapathDescription() {
357 return this.desc.getDpDesc();
358 }
359
360
361 @Override
362 public String hardwareDescription() {
363 return this.desc.getHwDesc();
364 }
365
366 @Override
367 public String softwareDescription() {
368 return this.desc.getSwDesc();
369 }
370
371 @Override
372 public String serialNumber() {
373 return this.desc.getSerialNum();
374 }
375
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700376 @Override
377 public boolean isOptical() {
378 return false;
379 }
380
tom7ef8ff92014-09-17 13:08:06 -0700381}