blob: 586deab128cadc3bbe3145d3ad3b46206492511b [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;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070022import java.util.ArrayList;
alshabibb452fd72015-04-22 20:46:20 -070023import java.util.Collections;
tom7ef8ff92014-09-17 13:08:06 -070024import java.util.List;
Thomas Vachuskaf15511b2015-03-24 12:17:57 -070025import java.util.concurrent.RejectedExecutionException;
tom7ef8ff92014-09-17 13:08:06 -070026import java.util.concurrent.atomic.AtomicInteger;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070027import java.util.stream.Collectors;
tom7ef8ff92014-09-17 13:08:06 -070028
29import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080030import org.onlab.packet.IpAddress;
alshabibb452fd72015-04-22 20:46:20 -070031import org.onosproject.net.driver.AbstractHandlerBehaviour;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.openflow.controller.Dpid;
33import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070034import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
35import org.projectfloodlight.openflow.protocol.OFErrorMsg;
36import org.projectfloodlight.openflow.protocol.OFExperimenter;
37import org.projectfloodlight.openflow.protocol.OFFactories;
38import org.projectfloodlight.openflow.protocol.OFFactory;
39import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
40import org.projectfloodlight.openflow.protocol.OFMessage;
alshabibb452fd72015-04-22 20:46:20 -070041import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
tom7ef8ff92014-09-17 13:08:06 -070042import org.projectfloodlight.openflow.protocol.OFPortDesc;
43import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080044import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070045import org.projectfloodlight.openflow.protocol.OFRoleReply;
alshabibb452fd72015-04-22 20:46:20 -070046import org.projectfloodlight.openflow.protocol.OFRoleRequest;
tom7ef8ff92014-09-17 13:08:06 -070047import org.projectfloodlight.openflow.protocol.OFVersion;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
51/**
52 * An abstract representation of an OpenFlow switch. Can be extended by others
53 * to serve as a base for their vendor specific representation of a switch.
54 */
alshabibb452fd72015-04-22 20:46:20 -070055public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
56 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070057
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070058 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070059
Thomas Vachuskaf15511b2015-03-24 12:17:57 -070060 private static final String SHUTDOWN_MSG = "Worker has already been shutdown";
61
alshabibb452fd72015-04-22 20:46:20 -070062 private Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080063 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070064
65 private boolean connected;
66 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070067 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070068 private OpenFlowAgent agent;
69 private final AtomicInteger xidCounter = new AtomicInteger(0);
70
71 private OFVersion ofVersion;
72
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070073 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070074
75 protected boolean tableFull;
76
77 private RoleHandler roleMan;
78
79 protected RoleState role;
80
81 protected OFFeaturesReply features;
82 protected OFDescStatsReply desc;
83
alshabibb452fd72015-04-22 20:46:20 -070084 @Override
85 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -070086 this.dpid = dpid;
87 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -070088 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -070089 }
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 {
alshabibb452fd72015-04-22 20:46:20 -0700104 channel.write(Collections.singletonList(m));
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700105 } 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 {
alshabibb452fd72015-04-22 20:46:20 -0700118 channel.write(msgs);
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700119 } 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
alshabibb452fd72015-04-22 20:46:20 -0700129 public final void sendRoleRequest(OFMessage msg) {
130 if (msg instanceof OFRoleRequest ||
131 msg instanceof OFNiciraControllerRoleRequest) {
132 channel.write(Collections.singletonList(msg));
133 return;
134 }
135 throw new IllegalArgumentException("Someone is trying to send " +
136 "a non role request message");
137 }
tom7ef8ff92014-09-17 13:08:06 -0700138
alshabiba2df7b2a2015-05-06 13:57:10 -0700139 public final void sendHandshakeMessage(OFMessage message) {
140 if (!this.isDriverHandshakeComplete()) {
141 channel.write(Collections.singletonList(message));
142 }
143 }
144
tom7ef8ff92014-09-17 13:08:06 -0700145 @Override
146 public final boolean isConnected() {
147 return this.connected;
148 }
149
150 @Override
151 public final void setConnected(boolean connected) {
152 this.connected = connected;
153 };
154
155 @Override
156 public final void setChannel(Channel channel) {
157 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800158 final SocketAddress address = channel.getRemoteAddress();
159 if (address instanceof InetSocketAddress) {
160 final InetSocketAddress inetAddress = (InetSocketAddress) address;
161 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700162 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800163 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
164 } else {
165 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
166 }
167 }
tom7ef8ff92014-09-17 13:08:06 -0700168 };
169
Ray Milkeye53f1712015-01-16 09:17:16 -0800170 @Override
171 public String channelId() {
172 return channelId;
173 }
174
175
tom7ef8ff92014-09-17 13:08:06 -0700176 //************************
177 // Switch features related
178 //************************
179
180 @Override
181 public final long getId() {
182 return this.dpid.value();
183 };
184
185 @Override
186 public final String getStringId() {
187 return this.dpid.toString();
188 }
189
190 @Override
191 public final void setOFVersion(OFVersion ofV) {
192 this.ofVersion = ofV;
193 }
194
195 @Override
196 public void setTableFull(boolean full) {
197 this.tableFull = full;
198 }
199
200 @Override
201 public void setFeaturesReply(OFFeaturesReply featuresReply) {
202 this.features = featuresReply;
203 }
204
205 @Override
206 public abstract Boolean supportNxRole();
207
208 //************************
209 // Message handling
210 //************************
211 /**
212 * Handle the message coming from the dataplane.
213 *
214 * @param m the actual message
215 */
216 @Override
217 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800218 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700219 this.agent.processMessage(dpid, m);
220 }
tom7ef8ff92014-09-17 13:08:06 -0700221 }
222
223 @Override
224 public RoleState getRole() {
225 return role;
226 };
227
228 @Override
229 public final boolean connectSwitch() {
230 return this.agent.addConnectedSwitch(dpid, this);
231 }
232
233 @Override
234 public final boolean activateMasterSwitch() {
235 return this.agent.addActivatedMasterSwitch(dpid, this);
236 }
237
238 @Override
239 public final boolean activateEqualSwitch() {
240 return this.agent.addActivatedEqualSwitch(dpid, this);
241 }
242
243 @Override
244 public final void transitionToEqualSwitch() {
245 this.agent.transitionToEqualSwitch(dpid);
246 }
247
248 @Override
249 public final void transitionToMasterSwitch() {
250 this.agent.transitionToMasterSwitch(dpid);
251 }
252
253 @Override
254 public final void removeConnectedSwitch() {
255 this.agent.removeConnectedSwitch(dpid);
256 }
257
258 @Override
259 public OFFactory factory() {
260 return OFFactories.getFactory(ofVersion);
261 }
262
263 @Override
264 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700265 this.ports.add(portDescReply);
266 }
267
268 @Override
269 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
270 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700271 }
272
273 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700274 public void returnRoleReply(RoleState requested, RoleState response) {
275 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700276 }
277
278 @Override
tom7ef8ff92014-09-17 13:08:06 -0700279 public abstract void startDriverHandshake();
280
281 @Override
282 public abstract boolean isDriverHandshakeComplete();
283
284 @Override
285 public abstract void processDriverHandshakeMessage(OFMessage m);
286
alshabib339a3d92014-09-26 17:54:32 -0700287
288 // Role Handling
289
tom7ef8ff92014-09-17 13:08:06 -0700290 @Override
291 public void setRole(RoleState role) {
292 try {
tom7ef8ff92014-09-17 13:08:06 -0700293 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700294 log.info("Sending role {} to switch {}", role, getStringId());
295 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
296 this.role = role;
297 }
alshabib7814e9f2014-09-30 11:52:12 -0700298 } else {
299 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700300 }
301 } catch (IOException e) {
302 log.error("Unable to write to switch {}.", this.dpid);
303 }
304 }
305
alshabib339a3d92014-09-26 17:54:32 -0700306 @Override
307 public void reassertRole() {
308 if (this.getRole() == RoleState.MASTER) {
309 log.warn("Received permission error from switch {} while " +
310 "being master. Reasserting master role.",
311 this.getStringId());
312 this.setRole(RoleState.MASTER);
313 }
314 }
315
316
tom7ef8ff92014-09-17 13:08:06 -0700317
318 @Override
319 public void handleRole(OFMessage m) throws SwitchStateException {
320 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
321 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
322 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
323 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700324 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700325 this.transitionToMasterSwitch();
326 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700327 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700328 this.transitionToEqualSwitch();
329 }
alshabib339a3d92014-09-26 17:54:32 -0700330 } else {
alshabib4785eec2014-12-04 16:45:45 -0800331 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700332 }
333 }
334
335 @Override
336 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
337 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
338 if (r == null) {
339 // The message wasn't really a Nicira role reply. We just
340 // dispatch it to the OFMessage listeners in this case.
341 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700342 return;
tom7ef8ff92014-09-17 13:08:06 -0700343 }
344
345 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
346 new RoleReplyInfo(r, null, m.getXid()));
347 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
348 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700349 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700350 this.transitionToMasterSwitch();
351 } else if (r == RoleState.EQUAL ||
352 r == RoleState.SLAVE) {
353 this.transitionToEqualSwitch();
354 }
alshabib339a3d92014-09-26 17:54:32 -0700355 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700356 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700357 }
358 }
359
360 @Override
361 public boolean handleRoleError(OFErrorMsg error) {
362 try {
363 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
364 } catch (SwitchStateException e) {
365 this.disconnectSwitch();
366 }
367 return true;
368 }
369
alshabib339a3d92014-09-26 17:54:32 -0700370
tom7ef8ff92014-09-17 13:08:06 -0700371
372 @Override
373 public final void setAgent(OpenFlowAgent ag) {
374 if (this.agent == null) {
375 this.agent = ag;
376 }
377 }
378
379 @Override
380 public final void setRoleHandler(RoleHandler roleHandler) {
381 if (this.roleMan == null) {
382 this.roleMan = roleHandler;
383 }
384 }
385
386 @Override
387 public void setSwitchDescription(OFDescStatsReply d) {
388 this.desc = d;
389 }
390
391 @Override
392 public int getNextTransactionId() {
393 return this.xidCounter.getAndIncrement();
394 }
395
396 @Override
397 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700398 return this.ports.stream()
399 .flatMap((portReply) -> (portReply.getEntries().stream()))
400 .collect(Collectors.toList());
401 //return Collections.unmodifiableList(ports.getEntries());
tom7ef8ff92014-09-17 13:08:06 -0700402 }
403
404 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800405 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700406 return this.desc.getMfrDesc();
407 }
408
409
410 @Override
411 public String datapathDescription() {
412 return this.desc.getDpDesc();
413 }
414
415
416 @Override
417 public String hardwareDescription() {
418 return this.desc.getHwDesc();
419 }
420
421 @Override
422 public String softwareDescription() {
423 return this.desc.getSwDesc();
424 }
425
426 @Override
427 public String serialNumber() {
428 return this.desc.getSerialNum();
429 }
430
alshabibb452fd72015-04-22 20:46:20 -0700431
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700432 @Override
433 public boolean isOptical() {
434 return false;
435 }
436
alshabib9af70072015-02-09 14:34:16 -0800437
alshabibb452fd72015-04-22 20:46:20 -0700438 @Override
439 public String toString() {
440 return this.getClass().getName() + " [" + ((channel != null)
441 ? channel.getRemoteAddress() : "?")
442 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
443 }
444
445
alshabib9af70072015-02-09 14:34:16 -0800446
tom7ef8ff92014-09-17 13:08:06 -0700447}