blob: 49943b82891ae25b183c95c5914d0f01fced2bd9 [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 Koshibe3ef2b0d2014-10-31 13:58:27 -0700220 public void returnRoleReply(RoleState requested, RoleState response) {
221 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700222 }
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 {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700303 log.warn(">>> mismatch with expected role - got {} - Disconnecting", r);
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}