2 * Copyright 2014-2015 Open Networking Laboratory
4 * 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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onosproject.openflow.controller.driver;
19 import org.jboss.netty.channel.Channel;
20 import org.onlab.packet.IpAddress;
21 import org.onosproject.net.Device;
22 import org.onosproject.net.driver.AbstractHandlerBehaviour;
23 import org.onosproject.openflow.controller.Dpid;
24 import org.onosproject.openflow.controller.RoleState;
25 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
26 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
27 import org.projectfloodlight.openflow.protocol.OFExperimenter;
28 import org.projectfloodlight.openflow.protocol.OFFactories;
29 import org.projectfloodlight.openflow.protocol.OFFactory;
30 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
31 import org.projectfloodlight.openflow.protocol.OFMessage;
32 import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
33 import org.projectfloodlight.openflow.protocol.OFPortDesc;
34 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
35 import org.projectfloodlight.openflow.protocol.OFPortStatus;
36 import org.projectfloodlight.openflow.protocol.OFRoleReply;
37 import org.projectfloodlight.openflow.protocol.OFRoleRequest;
38 import org.projectfloodlight.openflow.protocol.OFVersion;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import java.io.IOException;
43 import java.net.InetSocketAddress;
44 import java.net.SocketAddress;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.concurrent.atomic.AtomicInteger;
49 import java.util.stream.Collectors;
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.
55 public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
56 implements OpenFlowSwitchDriver {
58 protected final Logger log = LoggerFactory.getLogger(getClass());
60 private Channel channel;
61 protected String channelId;
63 private boolean connected;
64 protected boolean startDriverHandshakeCalled = false;
66 private OpenFlowAgent agent;
67 private final AtomicInteger xidCounter = new AtomicInteger(0);
69 private OFVersion ofVersion;
71 protected List<OFPortDescStatsReply> ports = new ArrayList<>();
73 protected boolean tableFull;
75 private RoleHandler roleMan;
77 protected RoleState role;
79 protected OFFeaturesReply features;
80 protected OFDescStatsReply desc;
82 List<OFMessage> messagesPendingMastership;
85 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
91 //************************
93 //************************
96 public final void disconnectSwitch() {
101 public void sendMsg(OFMessage msg) {
102 this.sendMsg(Collections.singletonList(msg));
106 public final void sendMsg(List<OFMessage> msgs) {
107 if (role == RoleState.MASTER && channel.isConnected()) {
109 } else if (messagesPendingMastership != null) {
110 messagesPendingMastership.addAll(msgs);
111 log.debug("Enqueue message for switch {}. queue size after is {}",
112 dpid, messagesPendingMastership.size());
114 log.warn("Dropping message for switch {} (role: {}, connected: {}): {}",
115 dpid, role, channel.isConnected(), msgs);
120 public final void sendRoleRequest(OFMessage msg) {
121 if (msg instanceof OFRoleRequest ||
122 msg instanceof OFNiciraControllerRoleRequest) {
123 channel.write(Collections.singletonList(msg));
126 throw new IllegalArgumentException("Someone is trying to send " +
127 "a non role request message");
131 public final void sendHandshakeMessage(OFMessage message) {
132 if (!this.isDriverHandshakeComplete()) {
133 channel.write(Collections.singletonList(message));
138 public final boolean isConnected() {
139 return this.connected;
143 public final void setConnected(boolean connected) {
144 this.connected = connected;
148 public final void setChannel(Channel channel) {
149 this.channel = channel;
150 final SocketAddress address = channel.getRemoteAddress();
151 if (address instanceof InetSocketAddress) {
152 final InetSocketAddress inetAddress = (InetSocketAddress) address;
153 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
154 if (ipAddress.isIp4()) {
155 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
157 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
163 public String channelId() {
167 //************************
168 // Switch features related
169 //************************
172 public final long getId() {
173 return this.dpid.value();
177 public final String getStringId() {
178 return this.dpid.toString();
182 public final void setOFVersion(OFVersion ofV) {
183 this.ofVersion = ofV;
187 public void setTableFull(boolean full) {
188 this.tableFull = full;
192 public void setFeaturesReply(OFFeaturesReply featuresReply) {
193 this.features = featuresReply;
197 public abstract Boolean supportNxRole();
199 //************************
201 //************************
203 * Handle the message coming from the dataplane.
205 * @param m the actual message
208 public final void handleMessage(OFMessage m) {
209 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
210 this.agent.processMessage(dpid, m);
215 public RoleState getRole() {
220 public final boolean connectSwitch() {
221 return this.agent.addConnectedSwitch(dpid, this);
225 public final boolean activateMasterSwitch() {
226 return this.agent.addActivatedMasterSwitch(dpid, this);
230 public final boolean activateEqualSwitch() {
231 return this.agent.addActivatedEqualSwitch(dpid, this);
235 public final void transitionToEqualSwitch() {
236 this.agent.transitionToEqualSwitch(dpid);
240 public final void transitionToMasterSwitch() {
241 this.agent.transitionToMasterSwitch(dpid);
242 if (messagesPendingMastership != null) {
243 this.sendMsg(messagesPendingMastership);
244 log.debug("Sending {} pending messages to switch {}",
245 messagesPendingMastership.size(), dpid);
246 messagesPendingMastership = null;
251 public final void removeConnectedSwitch() {
252 this.agent.removeConnectedSwitch(dpid);
256 public OFFactory factory() {
257 return OFFactories.getFactory(ofVersion);
261 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
262 this.ports.add(portDescReply);
266 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
267 this.ports.addAll(portDescReplies);
271 public void returnRoleReply(RoleState requested, RoleState response) {
272 this.agent.returnRoleReply(dpid, requested, response);
276 public abstract void startDriverHandshake();
279 public abstract boolean isDriverHandshakeComplete();
282 public abstract void processDriverHandshakeMessage(OFMessage m);
288 public void setRole(RoleState role) {
290 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
291 log.debug("Sending role {} to switch {}", role, getStringId());
292 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
295 if (messagesPendingMastership == null) {
296 log.debug("Initializing new queue for switch {}", dpid);
297 messagesPendingMastership = new ArrayList<>();
303 } catch (IOException e) {
304 log.error("Unable to write to switch {}.", this.dpid);
309 public void reassertRole() {
310 if (this.getRole() == RoleState.MASTER) {
311 log.warn("Received permission error from switch {} while " +
312 "being master. Reasserting master role.",
314 this.setRole(RoleState.MASTER);
321 public void handleRole(OFMessage m) throws SwitchStateException {
322 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
323 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
324 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
325 if (rri.getRole() == RoleState.MASTER) {
326 this.role = rri.getRole();
327 this.transitionToMasterSwitch();
328 } else if (rri.getRole() == RoleState.EQUAL ||
329 rri.getRole() == RoleState.SLAVE) {
330 this.transitionToEqualSwitch();
333 log.warn("Failed to set role for {}", this.getStringId());
338 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
339 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
341 // The message wasn't really a Nicira role reply. We just
342 // dispatch it to the OFMessage listeners in this case.
343 this.handleMessage(m);
347 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
348 new RoleReplyInfo(r, null, m.getXid()));
349 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
350 if (r == RoleState.MASTER) {
352 this.transitionToMasterSwitch();
353 } else if (r == RoleState.EQUAL ||
354 r == RoleState.SLAVE) {
355 this.transitionToEqualSwitch();
358 this.disconnectSwitch();
363 public boolean handleRoleError(OFErrorMsg error) {
365 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
366 } catch (SwitchStateException e) {
367 this.disconnectSwitch();
375 public final void setAgent(OpenFlowAgent ag) {
376 if (this.agent == null) {
382 public final void setRoleHandler(RoleHandler roleHandler) {
383 if (this.roleMan == null) {
384 this.roleMan = roleHandler;
389 public void setSwitchDescription(OFDescStatsReply d) {
394 public int getNextTransactionId() {
395 return this.xidCounter.getAndIncrement();
399 public List<OFPortDesc> getPorts() {
400 return this.ports.stream()
401 .flatMap((portReply) -> (portReply.getEntries().stream()))
402 .collect(Collectors.toList());
403 //return Collections.unmodifiableList(ports.getEntries());
407 public String manufacturerDescription() {
408 return this.desc.getMfrDesc();
413 public String datapathDescription() {
414 return this.desc.getDpDesc();
419 public String hardwareDescription() {
420 return this.desc.getHwDesc();
424 public String softwareDescription() {
425 return this.desc.getSwDesc();
429 public String serialNumber() {
430 return this.desc.getSerialNum();
435 public Device.Type deviceType() {
436 return Device.Type.SWITCH;
441 public String toString() {
442 return this.getClass().getName() + " [" + ((channel != null)
443 ? channel.getRemoteAddress() : "?")
444 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";