2f6357bd209a3ddee208737bb9c867b3a9d39227
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 Open Networking Laboratory
3  *
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
7  *
8  *     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.
15  */
16
17 package org.onosproject.openflow.controller.driver;
18
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;
41
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;
50
51 /**
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  */
55 public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
56         implements OpenFlowSwitchDriver {
57
58     protected final Logger log = LoggerFactory.getLogger(getClass());
59
60     private Channel channel;
61     protected String channelId;
62
63     private boolean connected;
64     protected boolean startDriverHandshakeCalled = false;
65     private Dpid dpid;
66     private OpenFlowAgent agent;
67     private final AtomicInteger xidCounter = new AtomicInteger(0);
68
69     private OFVersion ofVersion;
70
71     protected List<OFPortDescStatsReply> ports = new ArrayList<>();
72
73     protected boolean tableFull;
74
75     private RoleHandler roleMan;
76
77     protected RoleState role;
78
79     protected OFFeaturesReply features;
80     protected OFDescStatsReply desc;
81
82     @Override
83     public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
84         this.dpid = dpid;
85         this.desc = desc;
86         this.ofVersion = ofv;
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 void sendMsg(OFMessage m) {
100         if (role == RoleState.MASTER && channel.isConnected()) {
101             channel.write(Collections.singletonList(m));
102         }
103     }
104
105     @Override
106     public final void sendMsg(List<OFMessage> msgs) {
107         if (role == RoleState.MASTER && channel.isConnected()) {
108             channel.write(msgs);
109         }
110     }
111
112     @Override
113     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     }
122
123     @Override
124     public final void sendHandshakeMessage(OFMessage message) {
125         if (!this.isDriverHandshakeComplete()) {
126             channel.write(Collections.singletonList(message));
127         }
128     }
129
130     @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;
138     }
139
140     @Override
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();
149             } else {
150                 channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
151             }
152         }
153     }
154
155     @Override
156     public String channelId() {
157         return channelId;
158     }
159
160     //************************
161     // Switch features related
162     //************************
163
164     @Override
165     public final long getId() {
166         return this.dpid.value();
167     }
168
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) {
202         if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
203             this.agent.processMessage(dpid, m);
204         }
205     }
206
207     @Override
208     public RoleState getRole() {
209         return role;
210     }
211
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) {
249         this.ports.add(portDescReply);
250     }
251
252     @Override
253     public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
254         this.ports.addAll(portDescReplies);
255     }
256
257     @Override
258     public void returnRoleReply(RoleState requested, RoleState response) {
259         this.agent.returnRoleReply(dpid, requested, response);
260     }
261
262     @Override
263     public abstract void startDriverHandshake();
264
265     @Override
266     public abstract boolean isDriverHandshakeComplete();
267
268     @Override
269     public abstract void processDriverHandshakeMessage(OFMessage m);
270
271
272     // Role Handling
273
274     @Override
275     public void setRole(RoleState role) {
276         try {
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) {
280                     this.role = role;
281                 }
282             } else {
283                 this.role = role;
284             }
285         } catch (IOException e) {
286             log.error("Unable to write to switch {}.", this.dpid);
287         }
288     }
289
290     @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
301
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) {
308                 this.role = rri.getRole();
309                 this.transitionToMasterSwitch();
310             } else if (rri.getRole() == RoleState.EQUAL ||
311                     rri.getRole() == RoleState.SLAVE) {
312                 this.transitionToEqualSwitch();
313             }
314         }  else {
315             log.warn("Failed to set role for {}", this.getStringId());
316         }
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);
326             return;
327         }
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) {
333                 this.role = r;
334                 this.transitionToMasterSwitch();
335             } else if (r == RoleState.EQUAL ||
336                     r == RoleState.SLAVE) {
337                 this.transitionToEqualSwitch();
338             }
339         } else {
340             this.disconnectSwitch();
341         }
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
354
355
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() {
382         return this.ports.stream()
383                   .flatMap((portReply) -> (portReply.getEntries().stream()))
384                   .collect(Collectors.toList());
385         //return Collections.unmodifiableList(ports.getEntries());
386     }
387
388     @Override
389     public String manufacturerDescription() {
390         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
415
416     @Override
417     public Device.Type deviceType() {
418         return Device.Type.SWITCH;
419     }
420
421
422     @Override
423     public String toString() {
424         return this.getClass().getName() + " [" + ((channel != null)
425                 ? channel.getRemoteAddress() : "?")
426                 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
427     }
428
429
430
431 }