blob: ebfa635a9c0c390bb89fe1d1e706f8fe35715856 [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;
tom7ef8ff92014-09-17 13:08:06 -070023import 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;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070026import java.util.stream.Collectors;
tom7ef8ff92014-09-17 13:08:06 -070027
28import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080029import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.openflow.controller.Dpid;
31import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070032import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
33import org.projectfloodlight.openflow.protocol.OFErrorMsg;
34import org.projectfloodlight.openflow.protocol.OFExperimenter;
35import org.projectfloodlight.openflow.protocol.OFFactories;
36import org.projectfloodlight.openflow.protocol.OFFactory;
37import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
38import org.projectfloodlight.openflow.protocol.OFMessage;
39import org.projectfloodlight.openflow.protocol.OFPortDesc;
40import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080041import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070042import org.projectfloodlight.openflow.protocol.OFRoleReply;
43import org.projectfloodlight.openflow.protocol.OFVersion;
44import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
47/**
48 * An abstract representation of an OpenFlow switch. Can be extended by others
49 * to serve as a base for their vendor specific representation of a switch.
50 */
51public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
52
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070053 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070054
Thomas Vachuskaf15511b2015-03-24 12:17:57 -070055 private static final String SHUTDOWN_MSG = "Worker has already been shutdown";
56
tom7ef8ff92014-09-17 13:08:06 -070057 protected Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080058 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070059
60 private boolean connected;
61 protected boolean startDriverHandshakeCalled = false;
62 private final Dpid dpid;
63 private OpenFlowAgent agent;
64 private final AtomicInteger xidCounter = new AtomicInteger(0);
65
66 private OFVersion ofVersion;
67
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070068 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070069
70 protected boolean tableFull;
71
72 private RoleHandler roleMan;
73
74 protected RoleState role;
75
76 protected OFFeaturesReply features;
77 protected OFDescStatsReply desc;
78
79 /**
80 * Given a dpid build this switch.
81 * @param dp the dpid
82 */
83 protected AbstractOpenFlowSwitch(Dpid dp) {
84 this.dpid = dp;
85 }
86
87 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
88 this.dpid = dpid;
89 this.desc = desc;
90 }
91
92 //************************
93 // Channel related
94 //************************
95
96 @Override
97 public final void disconnectSwitch() {
98 this.channel.close();
99 }
100
101 @Override
102 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -0700103 if (role == RoleState.MASTER) {
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700104 try {
105 this.write(m);
106 } catch (RejectedExecutionException e) {
Thomas Vachuska152f9fd2015-04-02 16:28:13 -0700107 log.warn(e.getMessage());
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700108 if (!e.getMessage().contains(SHUTDOWN_MSG)) {
109 throw e;
110 }
111 }
alshabib339a3d92014-09-26 17:54:32 -0700112 }
tom7ef8ff92014-09-17 13:08:06 -0700113 }
114
115 @Override
116 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700117 if (role == RoleState.MASTER) {
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700118 try {
119 this.write(msgs);
120 } catch (RejectedExecutionException e) {
Thomas Vachuska152f9fd2015-04-02 16:28:13 -0700121 log.warn(e.getMessage());
Thomas Vachuskaf15511b2015-03-24 12:17:57 -0700122 if (!e.getMessage().contains(SHUTDOWN_MSG)) {
123 throw e;
124 }
125 }
alshabib339a3d92014-09-26 17:54:32 -0700126 }
tom7ef8ff92014-09-17 13:08:06 -0700127 }
128
129 @Override
130 public abstract void write(OFMessage msg);
131
132 @Override
133 public abstract void write(List<OFMessage> msgs);
134
135 @Override
136 public final boolean isConnected() {
137 return this.connected;
138 }
139
140 @Override
141 public final void setConnected(boolean connected) {
142 this.connected = connected;
143 };
144
145 @Override
146 public final void setChannel(Channel channel) {
147 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800148 final SocketAddress address = channel.getRemoteAddress();
149 if (address instanceof InetSocketAddress) {
150 final InetSocketAddress inetAddress = (InetSocketAddress) address;
151 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700152 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800153 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
154 } else {
155 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
156 }
157 }
tom7ef8ff92014-09-17 13:08:06 -0700158 };
159
Ray Milkeye53f1712015-01-16 09:17:16 -0800160 @Override
161 public String channelId() {
162 return channelId;
163 }
164
165
tom7ef8ff92014-09-17 13:08:06 -0700166 //************************
167 // Switch features related
168 //************************
169
170 @Override
171 public final long getId() {
172 return this.dpid.value();
173 };
174
175 @Override
176 public final String getStringId() {
177 return this.dpid.toString();
178 }
179
180 @Override
181 public final void setOFVersion(OFVersion ofV) {
182 this.ofVersion = ofV;
183 }
184
185 @Override
186 public void setTableFull(boolean full) {
187 this.tableFull = full;
188 }
189
190 @Override
191 public void setFeaturesReply(OFFeaturesReply featuresReply) {
192 this.features = featuresReply;
193 }
194
195 @Override
196 public abstract Boolean supportNxRole();
197
198 //************************
199 // Message handling
200 //************************
201 /**
202 * Handle the message coming from the dataplane.
203 *
204 * @param m the actual message
205 */
206 @Override
207 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800208 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700209 this.agent.processMessage(dpid, m);
210 }
tom7ef8ff92014-09-17 13:08:06 -0700211 }
212
213 @Override
214 public RoleState getRole() {
215 return role;
216 };
217
218 @Override
219 public final boolean connectSwitch() {
220 return this.agent.addConnectedSwitch(dpid, this);
221 }
222
223 @Override
224 public final boolean activateMasterSwitch() {
225 return this.agent.addActivatedMasterSwitch(dpid, this);
226 }
227
228 @Override
229 public final boolean activateEqualSwitch() {
230 return this.agent.addActivatedEqualSwitch(dpid, this);
231 }
232
233 @Override
234 public final void transitionToEqualSwitch() {
235 this.agent.transitionToEqualSwitch(dpid);
236 }
237
238 @Override
239 public final void transitionToMasterSwitch() {
240 this.agent.transitionToMasterSwitch(dpid);
241 }
242
243 @Override
244 public final void removeConnectedSwitch() {
245 this.agent.removeConnectedSwitch(dpid);
246 }
247
248 @Override
249 public OFFactory factory() {
250 return OFFactories.getFactory(ofVersion);
251 }
252
253 @Override
254 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700255 this.ports.add(portDescReply);
256 }
257
258 @Override
259 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
260 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700261 }
262
263 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700264 public void returnRoleReply(RoleState requested, RoleState response) {
265 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700266 }
267
268 @Override
tom7ef8ff92014-09-17 13:08:06 -0700269 public abstract void startDriverHandshake();
270
271 @Override
272 public abstract boolean isDriverHandshakeComplete();
273
274 @Override
275 public abstract void processDriverHandshakeMessage(OFMessage m);
276
alshabib339a3d92014-09-26 17:54:32 -0700277
278 // Role Handling
279
tom7ef8ff92014-09-17 13:08:06 -0700280 @Override
281 public void setRole(RoleState role) {
282 try {
tom7ef8ff92014-09-17 13:08:06 -0700283 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700284 log.info("Sending role {} to switch {}", role, getStringId());
285 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
286 this.role = role;
287 }
alshabib7814e9f2014-09-30 11:52:12 -0700288 } else {
289 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700290 }
291 } catch (IOException e) {
292 log.error("Unable to write to switch {}.", this.dpid);
293 }
294 }
295
alshabib339a3d92014-09-26 17:54:32 -0700296 @Override
297 public void reassertRole() {
298 if (this.getRole() == RoleState.MASTER) {
299 log.warn("Received permission error from switch {} while " +
300 "being master. Reasserting master role.",
301 this.getStringId());
302 this.setRole(RoleState.MASTER);
303 }
304 }
305
306
tom7ef8ff92014-09-17 13:08:06 -0700307
308 @Override
309 public void handleRole(OFMessage m) throws SwitchStateException {
310 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
311 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
312 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
313 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700314 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700315 this.transitionToMasterSwitch();
316 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700317 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700318 this.transitionToEqualSwitch();
319 }
alshabib339a3d92014-09-26 17:54:32 -0700320 } else {
alshabib4785eec2014-12-04 16:45:45 -0800321 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700322 }
323 }
324
325 @Override
326 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
327 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
328 if (r == null) {
329 // The message wasn't really a Nicira role reply. We just
330 // dispatch it to the OFMessage listeners in this case.
331 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700332 return;
tom7ef8ff92014-09-17 13:08:06 -0700333 }
334
335 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
336 new RoleReplyInfo(r, null, m.getXid()));
337 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
338 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700339 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700340 this.transitionToMasterSwitch();
341 } else if (r == RoleState.EQUAL ||
342 r == RoleState.SLAVE) {
343 this.transitionToEqualSwitch();
344 }
alshabib339a3d92014-09-26 17:54:32 -0700345 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700346 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700347 }
348 }
349
350 @Override
351 public boolean handleRoleError(OFErrorMsg error) {
352 try {
353 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
354 } catch (SwitchStateException e) {
355 this.disconnectSwitch();
356 }
357 return true;
358 }
359
alshabib339a3d92014-09-26 17:54:32 -0700360
tom7ef8ff92014-09-17 13:08:06 -0700361
362 @Override
363 public final void setAgent(OpenFlowAgent ag) {
364 if (this.agent == null) {
365 this.agent = ag;
366 }
367 }
368
369 @Override
370 public final void setRoleHandler(RoleHandler roleHandler) {
371 if (this.roleMan == null) {
372 this.roleMan = roleHandler;
373 }
374 }
375
376 @Override
377 public void setSwitchDescription(OFDescStatsReply d) {
378 this.desc = d;
379 }
380
381 @Override
382 public int getNextTransactionId() {
383 return this.xidCounter.getAndIncrement();
384 }
385
386 @Override
387 public List<OFPortDesc> getPorts() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700388 return this.ports.stream()
389 .flatMap((portReply) -> (portReply.getEntries().stream()))
390 .collect(Collectors.toList());
391 //return Collections.unmodifiableList(ports.getEntries());
tom7ef8ff92014-09-17 13:08:06 -0700392 }
393
394 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800395 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700396 return this.desc.getMfrDesc();
397 }
398
399
400 @Override
401 public String datapathDescription() {
402 return this.desc.getDpDesc();
403 }
404
405
406 @Override
407 public String hardwareDescription() {
408 return this.desc.getHwDesc();
409 }
410
411 @Override
412 public String softwareDescription() {
413 return this.desc.getSwDesc();
414 }
415
416 @Override
417 public String serialNumber() {
418 return this.desc.getSerialNum();
419 }
420
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700421 @Override
422 public boolean isOptical() {
423 return false;
424 }
425
alshabib9af70072015-02-09 14:34:16 -0800426
427
tom7ef8ff92014-09-17 13:08:06 -0700428}