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;
83 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
89 //************************
91 //************************
94 public final void disconnectSwitch() {
99 public void sendMsg(OFMessage m) {
100 if (role == RoleState.MASTER && channel.isConnected()) {
101 channel.write(Collections.singletonList(m));
106 public final void sendMsg(List<OFMessage> msgs) {
107 if (role == RoleState.MASTER && channel.isConnected()) {
113 public final void sendRoleRequest(OFMessage msg) {
114 if (msg instanceof OFRoleRequest ||
115 msg instanceof OFNiciraControllerRoleRequest) {
116 channel.write(Collections.singletonList(msg));
119 throw new IllegalArgumentException("Someone is trying to send " +
120 "a non role request message");
124 public final void sendHandshakeMessage(OFMessage message) {
125 if (!this.isDriverHandshakeComplete()) {
126 channel.write(Collections.singletonList(message));
131 public final boolean isConnected() {
132 return this.connected;
136 public final void setConnected(boolean connected) {
137 this.connected = connected;
141 public final void setChannel(Channel channel) {
142 this.channel = channel;
143 final SocketAddress address = channel.getRemoteAddress();
144 if (address instanceof InetSocketAddress) {
145 final InetSocketAddress inetAddress = (InetSocketAddress) address;
146 final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
147 if (ipAddress.isIp4()) {
148 channelId = ipAddress.toString() + ':' + inetAddress.getPort();
150 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
156 public String channelId() {
160 //************************
161 // Switch features related
162 //************************
165 public final long getId() {
166 return this.dpid.value();
170 public final String getStringId() {
171 return this.dpid.toString();
175 public final void setOFVersion(OFVersion ofV) {
176 this.ofVersion = ofV;
180 public void setTableFull(boolean full) {
181 this.tableFull = full;
185 public void setFeaturesReply(OFFeaturesReply featuresReply) {
186 this.features = featuresReply;
190 public abstract Boolean supportNxRole();
192 //************************
194 //************************
196 * Handle the message coming from the dataplane.
198 * @param m the actual message
201 public final void handleMessage(OFMessage m) {
202 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
203 this.agent.processMessage(dpid, m);
208 public RoleState getRole() {
213 public final boolean connectSwitch() {
214 return this.agent.addConnectedSwitch(dpid, this);
218 public final boolean activateMasterSwitch() {
219 return this.agent.addActivatedMasterSwitch(dpid, this);
223 public final boolean activateEqualSwitch() {
224 return this.agent.addActivatedEqualSwitch(dpid, this);
228 public final void transitionToEqualSwitch() {
229 this.agent.transitionToEqualSwitch(dpid);
233 public final void transitionToMasterSwitch() {
234 this.agent.transitionToMasterSwitch(dpid);
238 public final void removeConnectedSwitch() {
239 this.agent.removeConnectedSwitch(dpid);
243 public OFFactory factory() {
244 return OFFactories.getFactory(ofVersion);
248 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
249 this.ports.add(portDescReply);
253 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
254 this.ports.addAll(portDescReplies);
258 public void returnRoleReply(RoleState requested, RoleState response) {
259 this.agent.returnRoleReply(dpid, requested, response);
263 public abstract void startDriverHandshake();
266 public abstract boolean isDriverHandshakeComplete();
269 public abstract void processDriverHandshakeMessage(OFMessage m);
275 public void setRole(RoleState role) {
277 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
278 log.debug("Sending role {} to switch {}", role, getStringId());
279 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
285 } catch (IOException e) {
286 log.error("Unable to write to switch {}.", this.dpid);
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.",
296 this.setRole(RoleState.MASTER);
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) {
308 this.role = rri.getRole();
309 this.transitionToMasterSwitch();
310 } else if (rri.getRole() == RoleState.EQUAL ||
311 rri.getRole() == RoleState.SLAVE) {
312 this.transitionToEqualSwitch();
315 log.warn("Failed to set role for {}", this.getStringId());
320 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
321 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
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);
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) {
334 this.transitionToMasterSwitch();
335 } else if (r == RoleState.EQUAL ||
336 r == RoleState.SLAVE) {
337 this.transitionToEqualSwitch();
340 this.disconnectSwitch();
345 public boolean handleRoleError(OFErrorMsg error) {
347 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
348 } catch (SwitchStateException e) {
349 this.disconnectSwitch();
357 public final void setAgent(OpenFlowAgent ag) {
358 if (this.agent == null) {
364 public final void setRoleHandler(RoleHandler roleHandler) {
365 if (this.roleMan == null) {
366 this.roleMan = roleHandler;
371 public void setSwitchDescription(OFDescStatsReply d) {
376 public int getNextTransactionId() {
377 return this.xidCounter.getAndIncrement();
381 public List<OFPortDesc> getPorts() {
382 return this.ports.stream()
383 .flatMap((portReply) -> (portReply.getEntries().stream()))
384 .collect(Collectors.toList());
385 //return Collections.unmodifiableList(ports.getEntries());
389 public String manufacturerDescription() {
390 return this.desc.getMfrDesc();
395 public String datapathDescription() {
396 return this.desc.getDpDesc();
401 public String hardwareDescription() {
402 return this.desc.getHwDesc();
406 public String softwareDescription() {
407 return this.desc.getSwDesc();
411 public String serialNumber() {
412 return this.desc.getSerialNum();
417 public Device.Type deviceType() {
418 return Device.Type.SWITCH;
423 public String toString() {
424 return this.getClass().getName() + " [" + ((channel != null)
425 ? channel.getRemoteAddress() : "?")
426 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";