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