blob: f20a3f9e6c7b7656583a68df386487e5004c6900 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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;
24import java.util.concurrent.atomic.AtomicInteger;
25
26import org.jboss.netty.channel.Channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080027import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.openflow.controller.Dpid;
29import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070030import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
31import org.projectfloodlight.openflow.protocol.OFErrorMsg;
32import org.projectfloodlight.openflow.protocol.OFExperimenter;
33import org.projectfloodlight.openflow.protocol.OFFactories;
34import org.projectfloodlight.openflow.protocol.OFFactory;
35import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
36import org.projectfloodlight.openflow.protocol.OFMessage;
37import org.projectfloodlight.openflow.protocol.OFPortDesc;
38import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080039import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070040import org.projectfloodlight.openflow.protocol.OFRoleReply;
41import org.projectfloodlight.openflow.protocol.OFVersion;
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45/**
46 * An abstract representation of an OpenFlow switch. Can be extended by others
47 * to serve as a base for their vendor specific representation of a switch.
48 */
49public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
50
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070051 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070052
53 protected Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080054 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070055
56 private boolean connected;
57 protected boolean startDriverHandshakeCalled = false;
58 private final Dpid dpid;
59 private OpenFlowAgent agent;
60 private final AtomicInteger xidCounter = new AtomicInteger(0);
61
62 private OFVersion ofVersion;
63
64 protected OFPortDescStatsReply ports;
65
66 protected boolean tableFull;
67
68 private RoleHandler roleMan;
69
70 protected RoleState role;
71
72 protected OFFeaturesReply features;
73 protected OFDescStatsReply desc;
74
75 /**
76 * Given a dpid build this switch.
77 * @param dp the dpid
78 */
79 protected AbstractOpenFlowSwitch(Dpid dp) {
80 this.dpid = dp;
81 }
82
83 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
84 this.dpid = dpid;
85 this.desc = desc;
86 }
87
88 //************************
89 // Channel related
90 //************************
91
92 @Override
93 public final void disconnectSwitch() {
94 this.channel.close();
95 }
96
97 @Override
98 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -070099 if (role == RoleState.MASTER) {
100 this.write(m);
101 }
tom7ef8ff92014-09-17 13:08:06 -0700102 }
103
104 @Override
105 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700106 if (role == RoleState.MASTER) {
107 this.write(msgs);
108 }
tom7ef8ff92014-09-17 13:08:06 -0700109 }
110
111 @Override
112 public abstract void write(OFMessage msg);
113
114 @Override
115 public abstract void write(List<OFMessage> msgs);
116
117 @Override
118 public final boolean isConnected() {
119 return this.connected;
120 }
121
122 @Override
123 public final void setConnected(boolean connected) {
124 this.connected = connected;
125 };
126
127 @Override
128 public final void setChannel(Channel channel) {
129 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800130 final SocketAddress address = channel.getRemoteAddress();
131 if (address instanceof InetSocketAddress) {
132 final InetSocketAddress inetAddress = (InetSocketAddress) address;
133 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700134 if (ipAddress.isIp4()) {
Ray Milkeye53f1712015-01-16 09:17:16 -0800135 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
136 } else {
137 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
138 }
139 }
tom7ef8ff92014-09-17 13:08:06 -0700140 };
141
Ray Milkeye53f1712015-01-16 09:17:16 -0800142 @Override
143 public String channelId() {
144 return channelId;
145 }
146
147
tom7ef8ff92014-09-17 13:08:06 -0700148 //************************
149 // Switch features related
150 //************************
151
152 @Override
153 public final long getId() {
154 return this.dpid.value();
155 };
156
157 @Override
158 public final String getStringId() {
159 return this.dpid.toString();
160 }
161
162 @Override
163 public final void setOFVersion(OFVersion ofV) {
164 this.ofVersion = ofV;
165 }
166
167 @Override
168 public void setTableFull(boolean full) {
169 this.tableFull = full;
170 }
171
172 @Override
173 public void setFeaturesReply(OFFeaturesReply featuresReply) {
174 this.features = featuresReply;
175 }
176
177 @Override
178 public abstract Boolean supportNxRole();
179
180 //************************
181 // Message handling
182 //************************
183 /**
184 * Handle the message coming from the dataplane.
185 *
186 * @param m the actual message
187 */
188 @Override
189 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800190 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700191 this.agent.processMessage(dpid, m);
192 }
tom7ef8ff92014-09-17 13:08:06 -0700193 }
194
195 @Override
196 public RoleState getRole() {
197 return role;
198 };
199
200 @Override
201 public final boolean connectSwitch() {
202 return this.agent.addConnectedSwitch(dpid, this);
203 }
204
205 @Override
206 public final boolean activateMasterSwitch() {
207 return this.agent.addActivatedMasterSwitch(dpid, this);
208 }
209
210 @Override
211 public final boolean activateEqualSwitch() {
212 return this.agent.addActivatedEqualSwitch(dpid, this);
213 }
214
215 @Override
216 public final void transitionToEqualSwitch() {
217 this.agent.transitionToEqualSwitch(dpid);
218 }
219
220 @Override
221 public final void transitionToMasterSwitch() {
222 this.agent.transitionToMasterSwitch(dpid);
223 }
224
225 @Override
226 public final void removeConnectedSwitch() {
227 this.agent.removeConnectedSwitch(dpid);
228 }
229
230 @Override
231 public OFFactory factory() {
232 return OFFactories.getFactory(ofVersion);
233 }
234
235 @Override
236 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
237 this.ports = portDescReply;
238 }
239
240 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700241 public void returnRoleReply(RoleState requested, RoleState response) {
242 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700243 }
244
245 @Override
tom7ef8ff92014-09-17 13:08:06 -0700246 public abstract void startDriverHandshake();
247
248 @Override
249 public abstract boolean isDriverHandshakeComplete();
250
251 @Override
252 public abstract void processDriverHandshakeMessage(OFMessage m);
253
alshabib339a3d92014-09-26 17:54:32 -0700254
255 // Role Handling
256
tom7ef8ff92014-09-17 13:08:06 -0700257 @Override
258 public void setRole(RoleState role) {
259 try {
tom7ef8ff92014-09-17 13:08:06 -0700260 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700261 log.info("Sending role {} to switch {}", role, getStringId());
262 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
263 this.role = role;
264 }
alshabib7814e9f2014-09-30 11:52:12 -0700265 } else {
266 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700267 }
268 } catch (IOException e) {
269 log.error("Unable to write to switch {}.", this.dpid);
270 }
271 }
272
alshabib339a3d92014-09-26 17:54:32 -0700273 @Override
274 public void reassertRole() {
275 if (this.getRole() == RoleState.MASTER) {
276 log.warn("Received permission error from switch {} while " +
277 "being master. Reasserting master role.",
278 this.getStringId());
279 this.setRole(RoleState.MASTER);
280 }
281 }
282
283
tom7ef8ff92014-09-17 13:08:06 -0700284
285 @Override
286 public void handleRole(OFMessage m) throws SwitchStateException {
287 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
288 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
289 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
290 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700291 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700292 this.transitionToMasterSwitch();
293 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700294 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700295 this.transitionToEqualSwitch();
296 }
alshabib339a3d92014-09-26 17:54:32 -0700297 } else {
alshabib4785eec2014-12-04 16:45:45 -0800298 log.warn("Failed to set role for {}", this.getStringId());
alshabib339a3d92014-09-26 17:54:32 -0700299 return;
tom7ef8ff92014-09-17 13:08:06 -0700300 }
301 }
302
303 @Override
304 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
305 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
306 if (r == null) {
307 // The message wasn't really a Nicira role reply. We just
308 // dispatch it to the OFMessage listeners in this case.
309 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700310 return;
tom7ef8ff92014-09-17 13:08:06 -0700311 }
312
313 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
314 new RoleReplyInfo(r, null, m.getXid()));
315 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
316 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700317 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700318 this.transitionToMasterSwitch();
319 } else if (r == RoleState.EQUAL ||
320 r == RoleState.SLAVE) {
321 this.transitionToEqualSwitch();
322 }
alshabib339a3d92014-09-26 17:54:32 -0700323 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700324 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700325 }
326 }
327
328 @Override
329 public boolean handleRoleError(OFErrorMsg error) {
330 try {
331 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
332 } catch (SwitchStateException e) {
333 this.disconnectSwitch();
334 }
335 return true;
336 }
337
alshabib339a3d92014-09-26 17:54:32 -0700338
tom7ef8ff92014-09-17 13:08:06 -0700339
340 @Override
341 public final void setAgent(OpenFlowAgent ag) {
342 if (this.agent == null) {
343 this.agent = ag;
344 }
345 }
346
347 @Override
348 public final void setRoleHandler(RoleHandler roleHandler) {
349 if (this.roleMan == null) {
350 this.roleMan = roleHandler;
351 }
352 }
353
354 @Override
355 public void setSwitchDescription(OFDescStatsReply d) {
356 this.desc = d;
357 }
358
359 @Override
360 public int getNextTransactionId() {
361 return this.xidCounter.getAndIncrement();
362 }
363
364 @Override
365 public List<OFPortDesc> getPorts() {
366 return Collections.unmodifiableList(ports.getEntries());
367 }
368
369 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800370 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700371 return this.desc.getMfrDesc();
372 }
373
374
375 @Override
376 public String datapathDescription() {
377 return this.desc.getDpDesc();
378 }
379
380
381 @Override
382 public String hardwareDescription() {
383 return this.desc.getHwDesc();
384 }
385
386 @Override
387 public String softwareDescription() {
388 return this.desc.getSwDesc();
389 }
390
391 @Override
392 public String serialNumber() {
393 return this.desc.getSerialNum();
394 }
395
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700396 @Override
397 public boolean isOptical() {
398 return false;
399 }
400
alshabib9af70072015-02-09 14:34:16 -0800401
402
tom7ef8ff92014-09-17 13:08:06 -0700403}