blob: d47c78f27e4d9166ce641547de0afbbe6bbb91d9 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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
Brian O'Connorabafb502014-12-02 22:26:20 -080017package org.onosproject.openflow.controller.driver;
tom7ef8ff92014-09-17 13:08:06 -070018
19import java.io.IOException;
Ray Milkeye53f1712015-01-16 09:17:16 -080020import java.net.InetSocketAddress;
21import java.net.SocketAddress;
tom7ef8ff92014-09-17 13:08:06 -070022import java.util.Collections;
23import java.util.List;
Thomas Vachuskaf15511b2015-03-24 12:17:57 -070024import java.util.concurrent.RejectedExecutionException;
tom7ef8ff92014-09-17 13:08:06 -070025import java.util.concurrent.atomic.AtomicInteger;
26
27import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080028import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.openflow.controller.Dpid;
30import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070031import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
32import org.projectfloodlight.openflow.protocol.OFErrorMsg;
33import org.projectfloodlight.openflow.protocol.OFExperimenter;
34import org.projectfloodlight.openflow.protocol.OFFactories;
35import org.projectfloodlight.openflow.protocol.OFFactory;
36import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
37import org.projectfloodlight.openflow.protocol.OFMessage;
38import org.projectfloodlight.openflow.protocol.OFPortDesc;
39import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080040import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070041import org.projectfloodlight.openflow.protocol.OFRoleReply;
42import org.projectfloodlight.openflow.protocol.OFVersion;
43import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46/**
47 * An abstract representation of an OpenFlow switch. Can be extended by others
48 * to serve as a base for their vendor specific representation of a switch.
49 */
50public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
51
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070052 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070053
Thomas Vachuskaf15511b2015-03-24 12:17:57 -070054 private static final String SHUTDOWN_MSG = "Worker has already been shutdown";
55
tom7ef8ff92014-09-17 13:08:06 -070056 protected Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080057 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070058
59 private boolean connected;
60 protected boolean startDriverHandshakeCalled = false;
61 private final Dpid dpid;
62 private OpenFlowAgent agent;
63 private final AtomicInteger xidCounter = new AtomicInteger(0);
64
65 private OFVersion ofVersion;
66
67 protected OFPortDescStatsReply ports;
68
69 protected boolean tableFull;
70
71 private RoleHandler roleMan;
72
73 protected RoleState role;
74
75 protected OFFeaturesReply features;
76 protected OFDescStatsReply desc;
77
78 /**
79 * Given a dpid build this switch.
80 * @param dp the dpid
81 */
82 protected AbstractOpenFlowSwitch(Dpid dp) {
83 this.dpid = dp;
84 }
85
86 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
87 this.dpid = dpid;
88 this.desc = desc;
89 }
90
91 //************************
92 // Channel related
93 //************************
94
95 @Override
96 public final void disconnectSwitch() {
97 this.channel.close();
98 }
99
100 @Override
101 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -0700102 if (role == RoleState.MASTER) {
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700103 try {
104 this.write(m);
105 } catch (RejectedExecutionException e) {
Thomas Vachuska152f9fd2015-04-02 16:28:13 -0700106 log.warn(e.getMessage());
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700107 if (!e.getMessage().contains(SHUTDOWN_MSG)) {
108 throw e;
109 }
110 }
alshabib339a3d92014-09-26 17:54:32 -0700111 }
tom7ef8ff92014-09-17 13:08:06 -0700112 }
113
114 @Override
115 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700116 if (role == RoleState.MASTER) {
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700117 try {
118 this.write(msgs);
119 } catch (RejectedExecutionException e) {
Thomas Vachuska152f9fd2015-04-02 16:28:13 -0700120 log.warn(e.getMessage());
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700121 if (!e.getMessage().contains(SHUTDOWN_MSG)) {
122 throw e;
123 }
124 }
alshabib339a3d92014-09-26 17:54:32 -0700125 }
tom7ef8ff92014-09-17 13:08:06 -0700126 }
127
128 @Override
129 public abstract void write(OFMessage msg);
130
131 @Override
132 public abstract void write(List<OFMessage> msgs);
133
134 @Override
135 public final boolean isConnected() {
136 return this.connected;
137 }
138
139 @Override
140 public final void setConnected(boolean connected) {
141 this.connected = connected;
142 };
143
144 @Override
145 public final void setChannel(Channel channel) {
146 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800147 final SocketAddress address = channel.getRemoteAddress();
148 if (address instanceof InetSocketAddress) {
149 final InetSocketAddress inetAddress = (InetSocketAddress) address;
150 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700151 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800152 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
153 } else {
154 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
155 }
156 }
tom7ef8ff92014-09-17 13:08:06 -0700157 };
158
Ray Milkeye53f1712015-01-16 09:17:16 -0800159 @Override
160 public String channelId() {
161 return channelId;
162 }
163
164
tom7ef8ff92014-09-17 13:08:06 -0700165 //************************
166 // Switch features related
167 //************************
168
169 @Override
170 public final long getId() {
171 return this.dpid.value();
172 };
173
174 @Override
175 public final String getStringId() {
176 return this.dpid.toString();
177 }
178
179 @Override
180 public final void setOFVersion(OFVersion ofV) {
181 this.ofVersion = ofV;
182 }
183
184 @Override
185 public void setTableFull(boolean full) {
186 this.tableFull = full;
187 }
188
189 @Override
190 public void setFeaturesReply(OFFeaturesReply featuresReply) {
191 this.features = featuresReply;
192 }
193
194 @Override
195 public abstract Boolean supportNxRole();
196
197 //************************
198 // Message handling
199 //************************
200 /**
201 * Handle the message coming from the dataplane.
202 *
203 * @param m the actual message
204 */
205 @Override
206 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800207 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700208 this.agent.processMessage(dpid, m);
209 }
tom7ef8ff92014-09-17 13:08:06 -0700210 }
211
212 @Override
213 public RoleState getRole() {
214 return role;
215 };
216
217 @Override
218 public final boolean connectSwitch() {
219 return this.agent.addConnectedSwitch(dpid, this);
220 }
221
222 @Override
223 public final boolean activateMasterSwitch() {
224 return this.agent.addActivatedMasterSwitch(dpid, this);
225 }
226
227 @Override
228 public final boolean activateEqualSwitch() {
229 return this.agent.addActivatedEqualSwitch(dpid, this);
230 }
231
232 @Override
233 public final void transitionToEqualSwitch() {
234 this.agent.transitionToEqualSwitch(dpid);
235 }
236
237 @Override
238 public final void transitionToMasterSwitch() {
239 this.agent.transitionToMasterSwitch(dpid);
240 }
241
242 @Override
243 public final void removeConnectedSwitch() {
244 this.agent.removeConnectedSwitch(dpid);
245 }
246
247 @Override
248 public OFFactory factory() {
249 return OFFactories.getFactory(ofVersion);
250 }
251
252 @Override
253 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
254 this.ports = portDescReply;
255 }
256
257 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700258 public void returnRoleReply(RoleState requested, RoleState response) {
259 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700260 }
261
262 @Override
tom7ef8ff92014-09-17 13:08:06 -0700263 public abstract void startDriverHandshake();
264
265 @Override
266 public abstract boolean isDriverHandshakeComplete();
267
268 @Override
269 public abstract void processDriverHandshakeMessage(OFMessage m);
270
alshabib339a3d92014-09-26 17:54:32 -0700271
272 // Role Handling
273
tom7ef8ff92014-09-17 13:08:06 -0700274 @Override
275 public void setRole(RoleState role) {
276 try {
tom7ef8ff92014-09-17 13:08:06 -0700277 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700278 log.info("Sending role {} to switch {}", role, getStringId());
279 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
280 this.role = role;
281 }
alshabib7814e9f2014-09-30 11:52:12 -0700282 } else {
283 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700284 }
285 } catch (IOException e) {
286 log.error("Unable to write to switch {}.", this.dpid);
287 }
288 }
289
alshabib339a3d92014-09-26 17:54:32 -0700290 @Override
291 public void reassertRole() {
292 if (this.getRole() == RoleState.MASTER) {
293 log.warn("Received permission error from switch {} while " +
294 "being master. Reasserting master role.",
295 this.getStringId());
296 this.setRole(RoleState.MASTER);
297 }
298 }
299
300
tom7ef8ff92014-09-17 13:08:06 -0700301
302 @Override
303 public void handleRole(OFMessage m) throws SwitchStateException {
304 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
305 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
306 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
307 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700308 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700309 this.transitionToMasterSwitch();
310 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700311 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700312 this.transitionToEqualSwitch();
313 }
alshabib339a3d92014-09-26 17:54:32 -0700314 } else {
alshabib4785eec2014-12-04 16:45:45 -0800315 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700316 }
317 }
318
319 @Override
320 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
321 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
322 if (r == null) {
323 // The message wasn't really a Nicira role reply. We just
324 // dispatch it to the OFMessage listeners in this case.
325 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700326 return;
tom7ef8ff92014-09-17 13:08:06 -0700327 }
328
329 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
330 new RoleReplyInfo(r, null, m.getXid()));
331 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
332 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700333 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700334 this.transitionToMasterSwitch();
335 } else if (r == RoleState.EQUAL ||
336 r == RoleState.SLAVE) {
337 this.transitionToEqualSwitch();
338 }
alshabib339a3d92014-09-26 17:54:32 -0700339 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700340 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700341 }
342 }
343
344 @Override
345 public boolean handleRoleError(OFErrorMsg error) {
346 try {
347 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
348 } catch (SwitchStateException e) {
349 this.disconnectSwitch();
350 }
351 return true;
352 }
353
alshabib339a3d92014-09-26 17:54:32 -0700354
tom7ef8ff92014-09-17 13:08:06 -0700355
356 @Override
357 public final void setAgent(OpenFlowAgent ag) {
358 if (this.agent == null) {
359 this.agent = ag;
360 }
361 }
362
363 @Override
364 public final void setRoleHandler(RoleHandler roleHandler) {
365 if (this.roleMan == null) {
366 this.roleMan = roleHandler;
367 }
368 }
369
370 @Override
371 public void setSwitchDescription(OFDescStatsReply d) {
372 this.desc = d;
373 }
374
375 @Override
376 public int getNextTransactionId() {
377 return this.xidCounter.getAndIncrement();
378 }
379
380 @Override
381 public List<OFPortDesc> getPorts() {
382 return Collections.unmodifiableList(ports.getEntries());
383 }
384
385 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800386 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700387 return this.desc.getMfrDesc();
388 }
389
390
391 @Override
392 public String datapathDescription() {
393 return this.desc.getDpDesc();
394 }
395
396
397 @Override
398 public String hardwareDescription() {
399 return this.desc.getHwDesc();
400 }
401
402 @Override
403 public String softwareDescription() {
404 return this.desc.getSwDesc();
405 }
406
407 @Override
408 public String serialNumber() {
409 return this.desc.getSerialNum();
410 }
411
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700412 @Override
413 public boolean isOptical() {
414 return false;
415 }
416
alshabib9af70072015-02-09 14:34:16 -0800417
418
tom7ef8ff92014-09-17 13:08:06 -0700419}