blob: 2f6357bd209a3ddee208737bb9c867b3a9d39227 [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
tom7ef8ff92014-09-17 13:08:06 -070019import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080020import org.onlab.packet.IpAddress;
Marc De Leenheerb9311372015-07-09 11:36:49 -070021import org.onosproject.net.Device;
alshabibb452fd72015-04-22 20:46:20 -070022import org.onosproject.net.driver.AbstractHandlerBehaviour;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.openflow.controller.Dpid;
24import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070025import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
26import org.projectfloodlight.openflow.protocol.OFErrorMsg;
27import org.projectfloodlight.openflow.protocol.OFExperimenter;
28import org.projectfloodlight.openflow.protocol.OFFactories;
29import org.projectfloodlight.openflow.protocol.OFFactory;
30import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
31import org.projectfloodlight.openflow.protocol.OFMessage;
alshabibb452fd72015-04-22 20:46:20 -070032import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
tom7ef8ff92014-09-17 13:08:06 -070033import org.projectfloodlight.openflow.protocol.OFPortDesc;
34import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080035import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070036import org.projectfloodlight.openflow.protocol.OFRoleReply;
alshabibb452fd72015-04-22 20:46:20 -070037import org.projectfloodlight.openflow.protocol.OFRoleRequest;
tom7ef8ff92014-09-17 13:08:06 -070038import org.projectfloodlight.openflow.protocol.OFVersion;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
Thomas Vachuska1c681d72015-05-18 14:58:53 -070042import java.io.IOException;
43import java.net.InetSocketAddress;
44import java.net.SocketAddress;
45import java.util.ArrayList;
46import java.util.Collections;
47import java.util.List;
48import java.util.concurrent.atomic.AtomicInteger;
49import java.util.stream.Collectors;
50
tom7ef8ff92014-09-17 13:08:06 -070051/**
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
alshabibb452fd72015-04-22 20:46:20 -070060 private Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080061 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070062
63 private boolean connected;
64 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070065 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070066 private OpenFlowAgent agent;
67 private final AtomicInteger xidCounter = new AtomicInteger(0);
68
69 private OFVersion ofVersion;
70
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070071 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
tom7ef8ff92014-09-17 13:08:06 -070072
73 protected boolean tableFull;
74
75 private RoleHandler roleMan;
76
77 protected RoleState role;
78
79 protected OFFeaturesReply features;
80 protected OFDescStatsReply desc;
81
alshabibb452fd72015-04-22 20:46:20 -070082 @Override
83 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -070084 this.dpid = dpid;
85 this.desc = desc;
alshabibb452fd72015-04-22 20:46:20 -070086 this.ofVersion = ofv;
tom7ef8ff92014-09-17 13:08:06 -070087 }
88
89 //************************
90 // Channel related
91 //************************
92
93 @Override
94 public final void disconnectSwitch() {
95 this.channel.close();
96 }
97
98 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -070099 public void sendMsg(OFMessage m) {
Jonathan Hart9f1600a2015-07-28 13:58:31 -0700100 if (role == RoleState.MASTER && channel.isConnected()) {
Marc De Leenheerd24420f2015-05-27 09:40:59 -0700101 channel.write(Collections.singletonList(m));
alshabib339a3d92014-09-26 17:54:32 -0700102 }
tom7ef8ff92014-09-17 13:08:06 -0700103 }
104
105 @Override
106 public final void sendMsg(List<OFMessage> msgs) {
Jonathan Hart9f1600a2015-07-28 13:58:31 -0700107 if (role == RoleState.MASTER && channel.isConnected()) {
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700108 channel.write(msgs);
alshabib339a3d92014-09-26 17:54:32 -0700109 }
tom7ef8ff92014-09-17 13:08:06 -0700110 }
111
112 @Override
alshabibb452fd72015-04-22 20:46:20 -0700113 public final void sendRoleRequest(OFMessage msg) {
114 if (msg instanceof OFRoleRequest ||
115 msg instanceof OFNiciraControllerRoleRequest) {
116 channel.write(Collections.singletonList(msg));
117 return;
118 }
119 throw new IllegalArgumentException("Someone is trying to send " +
120 "a non role request message");
121 }
tom7ef8ff92014-09-17 13:08:06 -0700122
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700123 @Override
alshabiba2df7b2a2015-05-06 13:57:10 -0700124 public final void sendHandshakeMessage(OFMessage message) {
125 if (!this.isDriverHandshakeComplete()) {
126 channel.write(Collections.singletonList(message));
127 }
128 }
129
tom7ef8ff92014-09-17 13:08:06 -0700130 @Override
131 public final boolean isConnected() {
132 return this.connected;
133 }
134
135 @Override
136 public final void setConnected(boolean connected) {
137 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700138 }
tom7ef8ff92014-09-17 13:08:06 -0700139
140 @Override
141 public final void setChannel(Channel channel) {
142 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800143 final SocketAddress address = channel.getRemoteAddress();
144 if (address instanceof InetSocketAddress) {
145 final InetSocketAddress inetAddress = (InetSocketAddress) address;
146 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700147 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800148 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
149 } else {
150 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
151 }
152 }
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700153 }
tom7ef8ff92014-09-17 13:08:06 -0700154
Ray Milkeye53f1712015-01-16 09:17:16 -0800155 @Override
156 public String channelId() {
157 return channelId;
158 }
159
tom7ef8ff92014-09-17 13:08:06 -0700160 //************************
161 // Switch features related
162 //************************
163
164 @Override
165 public final long getId() {
166 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700167 }
tom7ef8ff92014-09-17 13:08:06 -0700168
169 @Override
170 public final String getStringId() {
171 return this.dpid.toString();
172 }
173
174 @Override
175 public final void setOFVersion(OFVersion ofV) {
176 this.ofVersion = ofV;
177 }
178
179 @Override
180 public void setTableFull(boolean full) {
181 this.tableFull = full;
182 }
183
184 @Override
185 public void setFeaturesReply(OFFeaturesReply featuresReply) {
186 this.features = featuresReply;
187 }
188
189 @Override
190 public abstract Boolean supportNxRole();
191
192 //************************
193 // Message handling
194 //************************
195 /**
196 * Handle the message coming from the dataplane.
197 *
198 * @param m the actual message
199 */
200 @Override
201 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800202 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700203 this.agent.processMessage(dpid, m);
204 }
tom7ef8ff92014-09-17 13:08:06 -0700205 }
206
207 @Override
208 public RoleState getRole() {
209 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700210 }
tom7ef8ff92014-09-17 13:08:06 -0700211
212 @Override
213 public final boolean connectSwitch() {
214 return this.agent.addConnectedSwitch(dpid, this);
215 }
216
217 @Override
218 public final boolean activateMasterSwitch() {
219 return this.agent.addActivatedMasterSwitch(dpid, this);
220 }
221
222 @Override
223 public final boolean activateEqualSwitch() {
224 return this.agent.addActivatedEqualSwitch(dpid, this);
225 }
226
227 @Override
228 public final void transitionToEqualSwitch() {
229 this.agent.transitionToEqualSwitch(dpid);
230 }
231
232 @Override
233 public final void transitionToMasterSwitch() {
234 this.agent.transitionToMasterSwitch(dpid);
235 }
236
237 @Override
238 public final void removeConnectedSwitch() {
239 this.agent.removeConnectedSwitch(dpid);
240 }
241
242 @Override
243 public OFFactory factory() {
244 return OFFactories.getFactory(ofVersion);
245 }
246
247 @Override
248 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700249 this.ports.add(portDescReply);
250 }
251
252 @Override
253 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
254 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700255 }
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)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700278 log.debug("Sending role {} to switch {}", role, getStringId());
alshabib339a3d92014-09-26 17:54:32 -0700279 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() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700382 return this.ports.stream()
383 .flatMap((portReply) -> (portReply.getEntries().stream()))
384 .collect(Collectors.toList());
385 //return Collections.unmodifiableList(ports.getEntries());
tom7ef8ff92014-09-17 13:08:06 -0700386 }
387
388 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800389 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700390 return this.desc.getMfrDesc();
391 }
392
393
394 @Override
395 public String datapathDescription() {
396 return this.desc.getDpDesc();
397 }
398
399
400 @Override
401 public String hardwareDescription() {
402 return this.desc.getHwDesc();
403 }
404
405 @Override
406 public String softwareDescription() {
407 return this.desc.getSwDesc();
408 }
409
410 @Override
411 public String serialNumber() {
412 return this.desc.getSerialNum();
413 }
414
alshabibb452fd72015-04-22 20:46:20 -0700415
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700416 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700417 public Device.Type deviceType() {
418 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700419 }
420
alshabib9af70072015-02-09 14:34:16 -0800421
alshabibb452fd72015-04-22 20:46:20 -0700422 @Override
423 public String toString() {
424 return this.getClass().getName() + " [" + ((channel != null)
425 ? channel.getRemoteAddress() : "?")
426 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
427 }
428
429
alshabib9af70072015-02-09 14:34:16 -0800430
tom7ef8ff92014-09-17 13:08:06 -0700431}