blob: bd5547e9950e1d21bf9bcda6cbae4f761ea065fa [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.Ip4Address;
28import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.openflow.controller.Dpid;
30import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070031import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
32import org.projectfloodlight.openflow.protocol.OFErrorMsg;
33import org.projectfloodlight.openflow.protocol.OFExperimenter;
34import org.projectfloodlight.openflow.protocol.OFFactories;
35import org.projectfloodlight.openflow.protocol.OFFactory;
36import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
37import org.projectfloodlight.openflow.protocol.OFMessage;
38import org.projectfloodlight.openflow.protocol.OFPortDesc;
39import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Thomas Vachuska39274462014-12-02 13:23:50 -080040import org.projectfloodlight.openflow.protocol.OFPortStatus;
tom7ef8ff92014-09-17 13:08:06 -070041import org.projectfloodlight.openflow.protocol.OFRoleReply;
42import org.projectfloodlight.openflow.protocol.OFVersion;
43import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46/**
47 * An abstract representation of an OpenFlow switch. Can be extended by others
48 * to serve as a base for their vendor specific representation of a switch.
49 */
50public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
51
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070052 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070053
54 protected Channel channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080055 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070056
57 private boolean connected;
58 protected boolean startDriverHandshakeCalled = false;
59 private final Dpid dpid;
60 private OpenFlowAgent agent;
61 private final AtomicInteger xidCounter = new AtomicInteger(0);
62
63 private OFVersion ofVersion;
64
65 protected OFPortDescStatsReply ports;
66
67 protected boolean tableFull;
68
69 private RoleHandler roleMan;
70
71 protected RoleState role;
72
73 protected OFFeaturesReply features;
74 protected OFDescStatsReply desc;
75
76 /**
77 * Given a dpid build this switch.
78 * @param dp the dpid
79 */
80 protected AbstractOpenFlowSwitch(Dpid dp) {
81 this.dpid = dp;
82 }
83
84 public AbstractOpenFlowSwitch(Dpid dpid, OFDescStatsReply desc) {
85 this.dpid = dpid;
86 this.desc = desc;
87 }
88
89 //************************
90 // Channel related
91 //************************
92
93 @Override
94 public final void disconnectSwitch() {
95 this.channel.close();
96 }
97
98 @Override
99 public final void sendMsg(OFMessage m) {
alshabib339a3d92014-09-26 17:54:32 -0700100 if (role == RoleState.MASTER) {
101 this.write(m);
102 }
tom7ef8ff92014-09-17 13:08:06 -0700103 }
104
105 @Override
106 public final void sendMsg(List<OFMessage> msgs) {
alshabib339a3d92014-09-26 17:54:32 -0700107 if (role == RoleState.MASTER) {
108 this.write(msgs);
109 }
tom7ef8ff92014-09-17 13:08:06 -0700110 }
111
112 @Override
113 public abstract void write(OFMessage msg);
114
115 @Override
116 public abstract void write(List<OFMessage> msgs);
117
118 @Override
119 public final boolean isConnected() {
120 return this.connected;
121 }
122
123 @Override
124 public final void setConnected(boolean connected) {
125 this.connected = connected;
126 };
127
128 @Override
129 public final void setChannel(Channel channel) {
130 this.channel = channel;
Ray Milkeye53f1712015-01-16 09:17:16 -0800131 final SocketAddress address = channel.getRemoteAddress();
132 if (address instanceof InetSocketAddress) {
133 final InetSocketAddress inetAddress = (InetSocketAddress) address;
134 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
135 if (ipAddress.version() == Ip4Address.VERSION) {
136 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
137 } else {
138 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
139 }
140 }
tom7ef8ff92014-09-17 13:08:06 -0700141 };
142
Ray Milkeye53f1712015-01-16 09:17:16 -0800143 @Override
144 public String channelId() {
145 return channelId;
146 }
147
148
tom7ef8ff92014-09-17 13:08:06 -0700149 //************************
150 // Switch features related
151 //************************
152
153 @Override
154 public final long getId() {
155 return this.dpid.value();
156 };
157
158 @Override
159 public final String getStringId() {
160 return this.dpid.toString();
161 }
162
163 @Override
164 public final void setOFVersion(OFVersion ofV) {
165 this.ofVersion = ofV;
166 }
167
168 @Override
169 public void setTableFull(boolean full) {
170 this.tableFull = full;
171 }
172
173 @Override
174 public void setFeaturesReply(OFFeaturesReply featuresReply) {
175 this.features = featuresReply;
176 }
177
178 @Override
179 public abstract Boolean supportNxRole();
180
181 //************************
182 // Message handling
183 //************************
184 /**
185 * Handle the message coming from the dataplane.
186 *
187 * @param m the actual message
188 */
189 @Override
190 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800191 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
alshabib339a3d92014-09-26 17:54:32 -0700192 this.agent.processMessage(dpid, m);
193 }
tom7ef8ff92014-09-17 13:08:06 -0700194 }
195
196 @Override
197 public RoleState getRole() {
198 return role;
199 };
200
201 @Override
202 public final boolean connectSwitch() {
203 return this.agent.addConnectedSwitch(dpid, this);
204 }
205
206 @Override
207 public final boolean activateMasterSwitch() {
208 return this.agent.addActivatedMasterSwitch(dpid, this);
209 }
210
211 @Override
212 public final boolean activateEqualSwitch() {
213 return this.agent.addActivatedEqualSwitch(dpid, this);
214 }
215
216 @Override
217 public final void transitionToEqualSwitch() {
218 this.agent.transitionToEqualSwitch(dpid);
219 }
220
221 @Override
222 public final void transitionToMasterSwitch() {
223 this.agent.transitionToMasterSwitch(dpid);
224 }
225
226 @Override
227 public final void removeConnectedSwitch() {
228 this.agent.removeConnectedSwitch(dpid);
229 }
230
231 @Override
232 public OFFactory factory() {
233 return OFFactories.getFactory(ofVersion);
234 }
235
236 @Override
237 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
238 this.ports = portDescReply;
239 }
240
241 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700242 public void returnRoleReply(RoleState requested, RoleState response) {
243 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700244 }
245
246 @Override
tom7ef8ff92014-09-17 13:08:06 -0700247 public abstract void startDriverHandshake();
248
249 @Override
250 public abstract boolean isDriverHandshakeComplete();
251
252 @Override
253 public abstract void processDriverHandshakeMessage(OFMessage m);
254
alshabib339a3d92014-09-26 17:54:32 -0700255
256 // Role Handling
257
tom7ef8ff92014-09-17 13:08:06 -0700258 @Override
259 public void setRole(RoleState role) {
260 try {
tom7ef8ff92014-09-17 13:08:06 -0700261 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
alshabib339a3d92014-09-26 17:54:32 -0700262 log.info("Sending role {} to switch {}", role, getStringId());
263 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
264 this.role = role;
265 }
alshabib7814e9f2014-09-30 11:52:12 -0700266 } else {
267 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700268 }
269 } catch (IOException e) {
270 log.error("Unable to write to switch {}.", this.dpid);
271 }
272 }
273
alshabib339a3d92014-09-26 17:54:32 -0700274 @Override
275 public void reassertRole() {
276 if (this.getRole() == RoleState.MASTER) {
277 log.warn("Received permission error from switch {} while " +
278 "being master. Reasserting master role.",
279 this.getStringId());
280 this.setRole(RoleState.MASTER);
281 }
282 }
283
284
tom7ef8ff92014-09-17 13:08:06 -0700285
286 @Override
287 public void handleRole(OFMessage m) throws SwitchStateException {
288 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
289 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
290 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
291 if (rri.getRole() == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700292 this.role = rri.getRole();
tom7ef8ff92014-09-17 13:08:06 -0700293 this.transitionToMasterSwitch();
294 } else if (rri.getRole() == RoleState.EQUAL ||
alshabib339a3d92014-09-26 17:54:32 -0700295 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700296 this.transitionToEqualSwitch();
297 }
alshabib339a3d92014-09-26 17:54:32 -0700298 } else {
alshabib4785eec2014-12-04 16:45:45 -0800299 log.warn("Failed to set role for {}", this.getStringId());
alshabib339a3d92014-09-26 17:54:32 -0700300 return;
tom7ef8ff92014-09-17 13:08:06 -0700301 }
302 }
303
304 @Override
305 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
306 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
307 if (r == null) {
308 // The message wasn't really a Nicira role reply. We just
309 // dispatch it to the OFMessage listeners in this case.
310 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700311 return;
tom7ef8ff92014-09-17 13:08:06 -0700312 }
313
314 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
315 new RoleReplyInfo(r, null, m.getXid()));
316 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
317 if (r == RoleState.MASTER) {
alshabib339a3d92014-09-26 17:54:32 -0700318 this.role = r;
tom7ef8ff92014-09-17 13:08:06 -0700319 this.transitionToMasterSwitch();
320 } else if (r == RoleState.EQUAL ||
321 r == RoleState.SLAVE) {
322 this.transitionToEqualSwitch();
323 }
alshabib339a3d92014-09-26 17:54:32 -0700324 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700325 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700326 }
327 }
328
329 @Override
330 public boolean handleRoleError(OFErrorMsg error) {
331 try {
332 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
333 } catch (SwitchStateException e) {
334 this.disconnectSwitch();
335 }
336 return true;
337 }
338
alshabib339a3d92014-09-26 17:54:32 -0700339
tom7ef8ff92014-09-17 13:08:06 -0700340
341 @Override
342 public final void setAgent(OpenFlowAgent ag) {
343 if (this.agent == null) {
344 this.agent = ag;
345 }
346 }
347
348 @Override
349 public final void setRoleHandler(RoleHandler roleHandler) {
350 if (this.roleMan == null) {
351 this.roleMan = roleHandler;
352 }
353 }
354
355 @Override
356 public void setSwitchDescription(OFDescStatsReply d) {
357 this.desc = d;
358 }
359
360 @Override
361 public int getNextTransactionId() {
362 return this.xidCounter.getAndIncrement();
363 }
364
365 @Override
366 public List<OFPortDesc> getPorts() {
367 return Collections.unmodifiableList(ports.getEntries());
368 }
369
370 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800371 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700372 return this.desc.getMfrDesc();
373 }
374
375
376 @Override
377 public String datapathDescription() {
378 return this.desc.getDpDesc();
379 }
380
381
382 @Override
383 public String hardwareDescription() {
384 return this.desc.getHwDesc();
385 }
386
387 @Override
388 public String softwareDescription() {
389 return this.desc.getSwDesc();
390 }
391
392 @Override
393 public String serialNumber() {
394 return this.desc.getSerialNum();
395 }
396
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700397 @Override
398 public boolean isOptical() {
399 return false;
400 }
401
tom7ef8ff92014-09-17 13:08:06 -0700402}