blob: 56d88b52f316b82ad7006c5155226f17c079f66c [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
139 @Override
140 public final boolean isConnected() {
141 return this.connected;
142 }
143
144 @Override
145 public final void setConnected(boolean connected) {
146 this.connected = connected;
147 };
148
149 @Override
150 public final void setChannel(Channel channel) {
151 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800152 final SocketAddress address = channel.getRemoteAddress();
153 if (address instanceof InetSocketAddress) {
154 final InetSocketAddress inetAddress = (InetSocketAddress) address;
155 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700156 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800157 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
158 } else {
159 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
160 }
161 }
tom7ef8ff92014-09-17 13:08:06 -0700162 };
163
Ray Milkeye53f1712015-01-16 09:17:16 -0800164 @Override
165 public String channelId() {
166 return channelId;
167 }
168
169
tom7ef8ff92014-09-17 13:08:06 -0700170 //************************
171 // Switch features related
172 //************************
173
174 @Override
175 public final long getId() {
176 return this.dpid.value();
177 };
178
179 @Override
180 public final String getStringId() {
181 return this.dpid.toString();
182 }
183
184 @Override
185 public final void setOFVersion(OFVersion ofV) {
186 this.ofVersion = ofV;
187 }
188
189 @Override
190 public void setTableFull(boolean full) {
191 this.tableFull = full;
192 }
193
194 @Override
195 public void setFeaturesReply(OFFeaturesReply featuresReply) {
196 this.features = featuresReply;
197 }
198
199 @Override
200 public abstract Boolean supportNxRole();
201
202 //************************
203 // Message handling
204 //************************
205 /**
206 * Handle the message coming from the dataplane.
207 *
208 * @param m the actual message
209 */
210 @Override
211 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800212 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700213 this.agent.processMessage(dpid, m);
214 }
tom7ef8ff92014-09-17 13:08:06 -0700215 }
216
217 @Override
218 public RoleState getRole() {
219 return role;
220 };
221
222 @Override
223 public final boolean connectSwitch() {
224 return this.agent.addConnectedSwitch(dpid, this);
225 }
226
227 @Override
228 public final boolean activateMasterSwitch() {
229 return this.agent.addActivatedMasterSwitch(dpid, this);
230 }
231
232 @Override
233 public final boolean activateEqualSwitch() {
234 return this.agent.addActivatedEqualSwitch(dpid, this);
235 }
236
237 @Override
238 public final void transitionToEqualSwitch() {
239 this.agent.transitionToEqualSwitch(dpid);
240 }
241
242 @Override
243 public final void transitionToMasterSwitch() {
244 this.agent.transitionToMasterSwitch(dpid);
245 }
246
247 @Override
248 public final void removeConnectedSwitch() {
249 this.agent.removeConnectedSwitch(dpid);
250 }
251
252 @Override
253 public OFFactory factory() {
254 return OFFactories.getFactory(ofVersion);
255 }
256
257 @Override
258 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700259 this.ports.add(portDescReply);
260 }
261
262 @Override
263 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
264 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700265 }
266
267 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700268 public void returnRoleReply(RoleState requested, RoleState response) {
269 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700270 }
271
272 @Override
tom7ef8ff92014-09-17 13:08:06 -0700273 public abstract void startDriverHandshake();
274
275 @Override
276 public abstract boolean isDriverHandshakeComplete();
277
278 @Override
279 public abstract void processDriverHandshakeMessage(OFMessage m);
280
alshabib339a3d92014-09-26 17:54:32 -0700281
282 // Role Handling
283
tom7ef8ff92014-09-17 13:08:06 -0700284 @Override
285 public void setRole(RoleState role) {
286 try {
tom7ef8ff92014-09-17 13:08:06 -0700287 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700288 log.info("Sending role {} to switch {}", role, getStringId());
289 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
290 this.role = role;
291 }
alshabib7814e9f2014-09-30 11:52:12 -0700292 } else {
293 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700294 }
295 } catch (IOException e) {
296 log.error("Unable to write to switch {}.", this.dpid);
297 }
298 }
299
alshabib339a3d92014-09-26 17:54:32 -0700300 @Override
301 public void reassertRole() {
302 if (this.getRole() == RoleState.MASTER) {
303 log.warn("Received permission error from switch {} while " +
304 "being master. Reasserting master role.",
305 this.getStringId());
306 this.setRole(RoleState.MASTER);
307 }
308 }
309
310
tom7ef8ff92014-09-17 13:08:06 -0700311
312 @Override
313 public void handleRole(OFMessage m) throws SwitchStateException {
314 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
315 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
316 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
317 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700318 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700319 this.transitionToMasterSwitch();
320 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700321 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700322 this.transitionToEqualSwitch();
323 }
alshabib339a3d92014-09-26 17:54:32 -0700324 } else {
alshabib4785eec2014-12-04 16:45:45 -0800325 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700326 }
327 }
328
329 @Override
330 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
331 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
332 if (r == null) {
333 // The message wasn't really a Nicira role reply. We just
334 // dispatch it to the OFMessage listeners in this case.
335 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700336 return;
tom7ef8ff92014-09-17 13:08:06 -0700337 }
338
339 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
340 new RoleReplyInfo(r, null, m.getXid()));
341 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
342 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700343 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700344 this.transitionToMasterSwitch();
345 } else if (r == RoleState.EQUAL ||
346 r == RoleState.SLAVE) {
347 this.transitionToEqualSwitch();
348 }
alshabib339a3d92014-09-26 17:54:32 -0700349 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700350 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700351 }
352 }
353
354 @Override
355 public boolean handleRoleError(OFErrorMsg error) {
356 try {
357 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
358 } catch (SwitchStateException e) {
359 this.disconnectSwitch();
360 }
361 return true;
362 }
363
alshabib339a3d92014-09-26 17:54:32 -0700364
tom7ef8ff92014-09-17 13:08:06 -0700365
366 @Override
367 public final void setAgent(OpenFlowAgent ag) {
368 if (this.agent == null) {
369 this.agent = ag;
370 }
371 }
372
373 @Override
374 public final void setRoleHandler(RoleHandler roleHandler) {
375 if (this.roleMan == null) {
376 this.roleMan = roleHandler;
377 }
378 }
379
380 @Override
381 public void setSwitchDescription(OFDescStatsReply d) {
382 this.desc = d;
383 }
384
385 @Override
386 public int getNextTransactionId() {
387 return this.xidCounter.getAndIncrement();
388 }
389
390 @Override
391 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700392 return this.ports.stream()
393 .flatMap((portReply) -> (portReply.getEntries().stream()))
394 .collect(Collectors.toList());
395 //return Collections.unmodifiableList(ports.getEntries());
tom7ef8ff92014-09-17 13:08:06 -0700396 }
397
398 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800399 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700400 return this.desc.getMfrDesc();
401 }
402
403
404 @Override
405 public String datapathDescription() {
406 return this.desc.getDpDesc();
407 }
408
409
410 @Override
411 public String hardwareDescription() {
412 return this.desc.getHwDesc();
413 }
414
415 @Override
416 public String softwareDescription() {
417 return this.desc.getSwDesc();
418 }
419
420 @Override
421 public String serialNumber() {
422 return this.desc.getSerialNum();
423 }
424
alshabibb452fd72015-04-22 20:46:20 -0700425
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700426 @Override
427 public boolean isOptical() {
428 return false;
429 }
430
alshabib9af70072015-02-09 14:34:16 -0800431
alshabibb452fd72015-04-22 20:46:20 -0700432 @Override
433 public String toString() {
434 return this.getClass().getName() + " [" + ((channel != null)
435 ? channel.getRemoteAddress() : "?")
436 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
437 }
438
439
alshabib9af70072015-02-09 14:34:16 -0800440
tom7ef8ff92014-09-17 13:08:06 -0700441}