blob: 995051563de6bcb01ff5e3f31d7e2427fbc5cfd3 [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;
36import org.projectfloodlight.openflow.protocol.OFRoleReply;
37import org.projectfloodlight.openflow.protocol.OFVersion;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41/**
42 * An abstract representation of an OpenFlow switch. Can be extended by others
43 * to serve as a base for their vendor specific representation of a switch.
44 */
45public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
46
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070047 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070048
49 protected Channel channel;
50
51 private boolean connected;
52 protected boolean startDriverHandshakeCalled = false;
53 private final Dpid dpid;
54 private OpenFlowAgent agent;
55 private final AtomicInteger xidCounter = new AtomicInteger(0);
56
57 private OFVersion ofVersion;
58
59 protected OFPortDescStatsReply ports;
60
61 protected boolean tableFull;
62
63 private RoleHandler roleMan;
64
65 protected RoleState role;
66
67 protected OFFeaturesReply features;
68 protected OFDescStatsReply desc;
69
70 /**
71 * Given a dpid build this switch.
72 * @param dp the dpid
73 */
74 protected AbstractOpenFlowSwitch(Dpid dp) {
75 this.dpid = dp;
76 }
77
78 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
79 this.dpid = dpid;
80 this.desc = desc;
81 }
82
83 //************************
84 // Channel related
85 //************************
86
87 @Override
88 public final void disconnectSwitch() {
89 this.channel.close();
90 }
91
92 @Override
93 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -070094 if (role == RoleState.MASTER) {
95 this.write(m);
96 }
tom7ef8ff92014-09-17 13:08:06 -070097 }
98
99 @Override
100 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700101 if (role == RoleState.MASTER) {
102 this.write(msgs);
103 }
tom7ef8ff92014-09-17 13:08:06 -0700104 }
105
106 @Override
107 public abstract void write(OFMessage msg);
108
109 @Override
110 public abstract void write(List<OFMessage> msgs);
111
112 @Override
113 public final boolean isConnected() {
114 return this.connected;
115 }
116
117 @Override
118 public final void setConnected(boolean connected) {
119 this.connected = connected;
120 };
121
122 @Override
123 public final void setChannel(Channel channel) {
124 this.channel = channel;
125 };
126
127 //************************
128 // Switch features related
129 //************************
130
131 @Override
132 public final long getId() {
133 return this.dpid.value();
134 };
135
136 @Override
137 public final String getStringId() {
138 return this.dpid.toString();
139 }
140
141 @Override
142 public final void setOFVersion(OFVersion ofV) {
143 this.ofVersion = ofV;
144 }
145
146 @Override
147 public void setTableFull(boolean full) {
148 this.tableFull = full;
149 }
150
151 @Override
152 public void setFeaturesReply(OFFeaturesReply featuresReply) {
153 this.features = featuresReply;
154 }
155
156 @Override
157 public abstract Boolean supportNxRole();
158
159 //************************
160 // Message handling
161 //************************
162 /**
163 * Handle the message coming from the dataplane.
164 *
165 * @param m the actual message
166 */
167 @Override
168 public final void handleMessage(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -0700169 if (this.role == RoleState.MASTER) {
170 this.agent.processMessage(dpid, m);
171 }
tom7ef8ff92014-09-17 13:08:06 -0700172 }
173
174 @Override
175 public RoleState getRole() {
176 return role;
177 };
178
179 @Override
180 public final boolean connectSwitch() {
181 return this.agent.addConnectedSwitch(dpid, this);
182 }
183
184 @Override
185 public final boolean activateMasterSwitch() {
186 return this.agent.addActivatedMasterSwitch(dpid, this);
187 }
188
189 @Override
190 public final boolean activateEqualSwitch() {
191 return this.agent.addActivatedEqualSwitch(dpid, this);
192 }
193
194 @Override
195 public final void transitionToEqualSwitch() {
196 this.agent.transitionToEqualSwitch(dpid);
197 }
198
199 @Override
200 public final void transitionToMasterSwitch() {
201 this.agent.transitionToMasterSwitch(dpid);
202 }
203
204 @Override
205 public final void removeConnectedSwitch() {
206 this.agent.removeConnectedSwitch(dpid);
207 }
208
209 @Override
210 public OFFactory factory() {
211 return OFFactories.getFactory(ofVersion);
212 }
213
214 @Override
215 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
216 this.ports = portDescReply;
217 }
218
219 @Override
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700220 public void returnRoleAssertFailure(RoleState role) {
221 this.agent.returnRoleAssertFailed(dpid, role);
222 }
223
224 @Override
tom7ef8ff92014-09-17 13:08:06 -0700225 public abstract void startDriverHandshake();
226
227 @Override
228 public abstract boolean isDriverHandshakeComplete();
229
230 @Override
231 public abstract void processDriverHandshakeMessage(OFMessage m);
232
alshabib339a3d92014-09-26 17:54:32 -0700233
234 // Role Handling
235
tom7ef8ff92014-09-17 13:08:06 -0700236 @Override
237 public void setRole(RoleState role) {
238 try {
tom7ef8ff92014-09-17 13:08:06 -0700239 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700240 log.info("Sending role {} to switch {}", role, getStringId());
241 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
242 this.role = role;
243 }
alshabib7814e9f2014-09-30 11:52:12 -0700244 } else {
245 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700246 }
247 } catch (IOException e) {
248 log.error("Unable to write to switch {}.", this.dpid);
249 }
250 }
251
alshabib339a3d92014-09-26 17:54:32 -0700252 @Override
253 public void reassertRole() {
254 if (this.getRole() == RoleState.MASTER) {
255 log.warn("Received permission error from switch {} while " +
256 "being master. Reasserting master role.",
257 this.getStringId());
258 this.setRole(RoleState.MASTER);
259 }
260 }
261
262
tom7ef8ff92014-09-17 13:08:06 -0700263
264 @Override
265 public void handleRole(OFMessage m) throws SwitchStateException {
266 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
267 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
268 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
269 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700270 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700271 this.transitionToMasterSwitch();
272 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700273 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700274 this.transitionToEqualSwitch();
275 }
alshabib339a3d92014-09-26 17:54:32 -0700276 } else {
277 return;
278 //TODO: tell people that we failed.
tom7ef8ff92014-09-17 13:08:06 -0700279 }
280 }
281
282 @Override
283 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
284 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
285 if (r == null) {
286 // The message wasn't really a Nicira role reply. We just
287 // dispatch it to the OFMessage listeners in this case.
288 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700289 return;
tom7ef8ff92014-09-17 13:08:06 -0700290 }
291
292 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
293 new RoleReplyInfo(r, null, m.getXid()));
294 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
295 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700296 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700297 this.transitionToMasterSwitch();
298 } else if (r == RoleState.EQUAL ||
299 r == RoleState.SLAVE) {
300 this.transitionToEqualSwitch();
301 }
alshabib339a3d92014-09-26 17:54:32 -0700302 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700303 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700304 }
305 }
306
307 @Override
308 public boolean handleRoleError(OFErrorMsg error) {
309 try {
310 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
311 } catch (SwitchStateException e) {
312 this.disconnectSwitch();
313 }
314 return true;
315 }
316
alshabib339a3d92014-09-26 17:54:32 -0700317
tom7ef8ff92014-09-17 13:08:06 -0700318
319 @Override
320 public final void setAgent(OpenFlowAgent ag) {
321 if (this.agent == null) {
322 this.agent = ag;
323 }
324 }
325
326 @Override
327 public final void setRoleHandler(RoleHandler roleHandler) {
328 if (this.roleMan == null) {
329 this.roleMan = roleHandler;
330 }
331 }
332
333 @Override
334 public void setSwitchDescription(OFDescStatsReply d) {
335 this.desc = d;
336 }
337
338 @Override
339 public int getNextTransactionId() {
340 return this.xidCounter.getAndIncrement();
341 }
342
343 @Override
344 public List<OFPortDesc> getPorts() {
345 return Collections.unmodifiableList(ports.getEntries());
346 }
347
348 @Override
349 public String manfacturerDescription() {
350 return this.desc.getMfrDesc();
351 }
352
353
354 @Override
355 public String datapathDescription() {
356 return this.desc.getDpDesc();
357 }
358
359
360 @Override
361 public String hardwareDescription() {
362 return this.desc.getHwDesc();
363 }
364
365 @Override
366 public String softwareDescription() {
367 return this.desc.getSwDesc();
368 }
369
370 @Override
371 public String serialNumber() {
372 return this.desc.getSerialNum();
373 }
374
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700375 @Override
376 public boolean isOptical() {
377 return false;
378 }
379
tom7ef8ff92014-09-17 13:08:06 -0700380}