tom

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 37 changed files with 1540 additions and 6105 deletions
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
63 <configuration> 63 <configuration>
64 <instructions> 64 <instructions>
65 <Export-Package> 65 <Export-Package>
66 - org.projectfloodlight.openflow.* 66 + org.onlab.onos.of.*,org.projectfloodlight.openflow.*
67 </Export-Package> 67 </Export-Package>
68 </instructions> 68 </instructions>
69 </configuration> 69 </configuration>
......
1 -package org.onlab.onos.of.controller;
2 -
3 -/**
4 - * Created by tom on 8/21/14.
5 - */
6 -public interface DeleteMe {
7 -}
1 -package org.onlab.onos.of.controller.impl.util; 1 +package org.onlab.onos.of.controller;
2 2
3 import org.projectfloodlight.openflow.util.HexString; 3 import org.projectfloodlight.openflow.util.HexString;
4 4
......
1 +package org.onlab.onos.of.controller;
2 +
3 +import org.projectfloodlight.openflow.protocol.OFMessage;
4 +
5 +/**
6 + * Abstraction of an OpenFlow controller. Serves as a one stop
7 + * shop for obtaining OpenFlow devices and (un)register listeners
8 + * on OpenFlow events
9 + */
10 +public interface OpenFlowController {
11 +
12 + /**
13 + * Returns all switches known to this OF controller.
14 + * @return Iterable of dpid elements
15 + */
16 + public Iterable<OpenFlowSwitch> getSwitches();
17 +
18 + /**
19 + * Returns all master switches known to this OF controller.
20 + * @return Iterable of dpid elements
21 + */
22 + public Iterable<OpenFlowSwitch> getMasterSwitches();
23 +
24 + /**
25 + * Returns all equal switches known to this OF controller.
26 + * @return Iterable of dpid elements
27 + */
28 + public Iterable<OpenFlowSwitch> getEqualSwitches();
29 +
30 +
31 + /**
32 + * Returns the actual switch for the given Dpid.
33 + * @param dpid the switch to fetch
34 + * @return the interface to this switch
35 + */
36 + public OpenFlowSwitch getSwitch(Dpid dpid);
37 +
38 + /**
39 + * Returns the actual master switch for the given Dpid, if one exists.
40 + * @param dpid the switch to fetch
41 + * @return the interface to this switch
42 + */
43 + public OpenFlowSwitch getMasterSwitch(Dpid dpid);
44 +
45 + /**
46 + * Returns the actual equal switch for the given Dpid, if one exists.
47 + * @param dpid the switch to fetch
48 + * @return the interface to this switch
49 + */
50 + public OpenFlowSwitch getEqualSwitch(Dpid dpid);
51 +
52 + /**
53 + * Register a listener for meta events that occur to OF
54 + * devices.
55 + * @param listener the listener to notify
56 + */
57 + public void addListener(OpenFlowSwitchListener listener);
58 +
59 + /**
60 + * Unregister a listener.
61 + *
62 + * @param listener the listener to unregister
63 + */
64 + public void removeListener(OpenFlowSwitchListener listener);
65 +
66 + /**
67 + * Register a listener for packet events.
68 + * @param priority the importance of this listener, lower values are more important
69 + * @param listener the listener to notify
70 + */
71 + public void addPacketListener(int priority, PacketListener listener);
72 +
73 + /**
74 + * Unregister a listener.
75 + *
76 + * @param listener the listener to unregister
77 + */
78 + public void removePacketListener(PacketListener listener);
79 +
80 + /**
81 + * Send a message to a particular switch.
82 + * @param dpid the switch to send to.
83 + * @param msg the message to send
84 + */
85 + public void write(Dpid dpid, OFMessage msg);
86 +
87 + /**
88 + * Process a message and notify the appropriate listeners.
89 + *
90 + * @param msg the message to process.
91 + */
92 + public void processPacket(OFMessage msg);
93 +
94 + /**
95 + * Sets the role for a given switch.
96 + * @param role the desired role
97 + * @param dpid the switch to set the role for.
98 + */
99 + public void setRole(Dpid dpid, RoleState role);
100 +}
1 +package org.onlab.onos.of.controller;
2 +
3 +import org.projectfloodlight.openflow.protocol.OFMessage;
4 +
5 +/**
6 + * Abstract model of an OpenFlow Switch.
7 + *
8 + */
9 +public interface OpenFlowSwitch {
10 +
11 + /**
12 + * Writes the message to this switch.
13 + *
14 + * @param msg the message to write
15 + */
16 + public void write(OFMessage msg);
17 +
18 + /**
19 + * Handle a message from the switch.
20 + * @param fromSwitch the message to handle
21 + */
22 + public void handleMessage(OFMessage fromSwitch);
23 +}
1 +package org.onlab.onos.of.controller;
2 +
3 +/**
4 + * Meta events that can happen at a switch.
5 + *
6 + */
7 +public enum OpenFlowSwitchEvent {
8 + /**
9 + * The switch connected.
10 + */
11 + SWITCH_CONNECTED,
12 +
13 + /**
14 + * The switch disconnected.
15 + */
16 + SWITCH_DISCONNECTED
17 +}
1 +package org.onlab.onos.of.controller;
2 +
3 +/**
4 + * Allows for providers interested in Switch events to be notified.
5 + */
6 +public interface OpenFlowSwitchListener {
7 +
8 + /**
9 + * Notify that the switch was added.
10 + * @param dpid the switch where the event occurred
11 + */
12 + public void switchAdded(Dpid dpid);
13 +
14 + /**
15 + * Notify that the switch was removed.
16 + * @param dpid the switch where the event occurred.
17 + */
18 + public void switchRemoved(Dpid dpid);
19 +
20 +}
1 +package org.onlab.onos.of.controller;
2 +
3 +import org.projectfloodlight.openflow.types.OFPort;
4 +
5 +/**
6 + * A representation of a packet context which allows any provider
7 + * to view the packet in event but may block the response to the
8 + * event if blocked has been called.
9 + */
10 +public interface PacketContext {
11 +
12 + //TODO: may want to support sending packet out other switches than
13 + // the one it came in on.
14 + /**
15 + * Blocks further responses (ie. send() calls) on this
16 + * packet in event.
17 + */
18 + public void block();
19 +
20 + /**
21 + * Provided build has been called send the packet
22 + * out the switch it came in on.
23 + */
24 + public void send();
25 +
26 + /**
27 + * Build the packet out in response to this packet in event.
28 + * @param outPort the out port to send to packet out of.
29 + */
30 + public void build(OFPort outPort);
31 +
32 + /**
33 + * Build the packet out in response to this packet in event.
34 + * @param ethFrame the actual packet to send out.
35 + * @param outPort the out port to send to packet out of.
36 + */
37 + public void build(Object ethFrame, OFPort outPort);
38 +
39 + /**
40 + * Provided a handle onto the parsed payload.
41 + * @return the parsed form of the payload.
42 + */
43 + public Object parsed();
44 +
45 + /**
46 + * Provide the dpid of the switch where the packet in arrived.
47 + * @return the dpid of the switch.
48 + */
49 + public Dpid dpid();
50 +}
1 +package org.onlab.onos.of.controller;
2 +
3 +/**
4 + * Notifies providers about Packet in events.
5 + */
6 +public interface PacketListener {
7 +
8 + /**
9 + * Handle the packet.
10 + * @param pktCtx the packet context ({@link }
11 + */
12 + public void handlePacket(PacketContext pktCtx);
13 +}
1 -package org.onlab.onos.of.controller.impl; 1 +package org.onlab.onos.of.controller;
2 2
3 import org.projectfloodlight.openflow.protocol.OFControllerRole; 3 import org.projectfloodlight.openflow.protocol.OFControllerRole;
4 4
...@@ -10,27 +10,14 @@ import org.projectfloodlight.openflow.protocol.OFControllerRole; ...@@ -10,27 +10,14 @@ import org.projectfloodlight.openflow.protocol.OFControllerRole;
10 * to the OF1.3 enum, before role messages are sent to the switch. 10 * to the OF1.3 enum, before role messages are sent to the switch.
11 * See sendRoleRequestMessage method in OFSwitchImpl 11 * See sendRoleRequestMessage method in OFSwitchImpl
12 */ 12 */
13 -public enum Role { 13 +public enum RoleState {
14 EQUAL(OFControllerRole.ROLE_EQUAL), 14 EQUAL(OFControllerRole.ROLE_EQUAL),
15 MASTER(OFControllerRole.ROLE_MASTER), 15 MASTER(OFControllerRole.ROLE_MASTER),
16 SLAVE(OFControllerRole.ROLE_SLAVE); 16 SLAVE(OFControllerRole.ROLE_SLAVE);
17 17
18 - private Role(OFControllerRole nxRole) { 18 + private RoleState(OFControllerRole nxRole) {
19 nxRole.ordinal(); 19 nxRole.ordinal();
20 } 20 }
21 - /* 21 +
22 - private static Map<Integer,Role> nxRoleToEnum
23 - = new HashMap<Integer,Role>();
24 - static {
25 - for(Role r: Role.values())
26 - nxRoleToEnum.put(r.toNxRole(), r);
27 - }
28 - public int toNxRole() {
29 - return nxRole;
30 - }
31 - // Return the enum representing the given nxRole or null if no
32 - // such role exists
33 - public static Role fromNxRole(int nxRole) {
34 - return nxRoleToEnum.get(nxRole);
35 - }*/
36 } 22 }
23 +
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
38 </properties> 38 </properties>
39 39
40 <dependencies> 40 <dependencies>
41 + <dependency>
42 + <groupId>org.onlab.onos</groupId>
43 + <artifactId>onos-of-api</artifactId>
44 + </dependency>
41 <!-- ONOS's direct dependencies --> 45 <!-- ONOS's direct dependencies -->
42 <dependency> 46 <dependency>
43 <groupId>org.apache.felix</groupId> 47 <groupId>org.apache.felix</groupId>
......
1 -/**
2 - * Copyright 2011, Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl;
19 -
20 -import java.io.IOException;
21 -import java.util.Collection;
22 -import java.util.Date;
23 -import java.util.List;
24 -import java.util.Map;
25 -import java.util.Set;
26 -import java.util.concurrent.Future;
27 -
28 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
29 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
30 -import org.onlab.onos.of.controller.impl.util.OrderedCollection;
31 -
32 -import org.jboss.netty.channel.Channel;
33 -import org.projectfloodlight.openflow.protocol.OFActionType;
34 -import org.projectfloodlight.openflow.protocol.OFCapabilities;
35 -import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36 -import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
37 -import org.projectfloodlight.openflow.protocol.OFMessage;
38 -import org.projectfloodlight.openflow.protocol.OFPortDesc;
39 -import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
40 -import org.projectfloodlight.openflow.protocol.OFPortStatus;
41 -import org.projectfloodlight.openflow.protocol.OFStatsReply;
42 -import org.projectfloodlight.openflow.protocol.OFStatsRequest;
43 -import org.projectfloodlight.openflow.protocol.OFVersion;
44 -import org.projectfloodlight.openflow.types.U64;
45 -
46 -
47 -public interface IOFSwitch {
48 -
49 - /**
50 - * OF1.3 switches should support role-request messages as in the 1.3 spec.
51 - * OF1.0 switches may or may not support the Nicira role request extensions.
52 - * To indicate the support, this property should be set by the associated
53 - * OF1.0 switch driver in the net.onrc.onos.core.drivermanager package.
54 - * The property will be ignored for OF1.3 switches.
55 - */
56 - public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole";
57 -
58 -
59 - //************************
60 - // Channel related
61 - //************************
62 -
63 - /**
64 - * Disconnects the switch by closing the TCP connection. Results in a call
65 - * to the channel handler's channelDisconnected method for cleanup
66 - * @throws IOException
67 - */
68 - public void disconnectSwitch();
69 -
70 - /**
71 - * Writes to the OFMessage to the output stream.
72 - *
73 - * @param m
74 - * @throws IOException
75 - */
76 - public void write(OFMessage m) throws IOException;
77 -
78 - /**
79 - * Writes the list of messages to the output stream.
80 - *
81 - * @param msglist
82 - * @throws IOException
83 - */
84 - public void write(List<OFMessage> msglist) throws IOException;
85 -
86 - /**
87 - * Gets the date the switch connected to this controller.
88 - *
89 - * @return the date
90 - */
91 - public Date getConnectedSince();
92 -
93 - /**
94 - * Gets the next available transaction id.
95 - *
96 - * @return the next transaction ID
97 - */
98 - public int getNextTransactionId();
99 -
100 - /**
101 - * Checks if the switch is still connected.
102 - * Only call while holding processMessageLock
103 - *
104 - * @return whether the switch is still disconnected
105 - */
106 - public boolean isConnected();
107 -
108 - /**
109 - * Sets whether the switch is connected.
110 - * Only call while holding modifySwitchLock
111 - *
112 - * @param connected whether the switch is connected
113 - */
114 - public void setConnected(boolean connected);
115 -
116 - /**
117 - * Flushes all flows queued for this switch in the current thread.
118 - * NOTE: The contract is limited to the current thread
119 - */
120 - public void flush();
121 -
122 - /**
123 - * Sets the Netty Channel this switch instance is associated with.
124 - * <p>
125 - * Called immediately after instantiation
126 - *
127 - * @param channel the channel
128 - */
129 - public void setChannel(Channel channel);
130 -
131 - //************************
132 - // Switch features related
133 - //************************
134 -
135 - /**
136 - * Gets the datapathId of the switch.
137 - *
138 - * @return the switch buffers
139 - */
140 - public long getId();
141 -
142 - /**
143 - * Gets a string version of the ID for this switch.
144 - *
145 - * @return string version of the ID
146 - */
147 - public String getStringId();
148 -
149 - /**
150 - * Gets the number of buffers.
151 - *
152 - * @return the number of buffers
153 - */
154 - public int getNumBuffers();
155 -
156 - public Set<OFCapabilities> getCapabilities();
157 -
158 - public byte getNumTables();
159 -
160 - /**
161 - * Returns an OFDescStatsReply message object. Use the methods contained
162 - * to retrieve switch descriptions for Manufacturer, Hw/Sw version etc.
163 - */
164 - public OFDescStatsReply getSwitchDescription();
165 -
166 - /**
167 - * Cancel features reply with a specific transaction ID.
168 - * @param transactionId the transaction ID
169 - */
170 - public void cancelFeaturesReply(int transactionId);
171 -
172 - /**
173 - * Gets the OFActionType set.
174 - * <p>
175 - * getActions has relevance only for an OpenFlow 1.0 switch.
176 - * For OF1.3, each table can support different actions
177 - *
178 - * @return the action set
179 - */
180 - public Set<OFActionType> getActions();
181 -
182 - public void setOFVersion(OFVersion ofv);
183 -
184 - public OFVersion getOFVersion();
185 -
186 -
187 - //************************
188 - // Switch port related
189 - //************************
190 -
191 - /**
192 - * the type of change that happened to an open flow port.
193 - */
194 - public enum PortChangeType {
195 - /** Either a new port has been added by the switch, or we are
196 - * adding a port we just deleted (via a prior notification) due to
197 - * a change in the portNumber-portName mapping.
198 - */
199 - ADD,
200 - /** some other feature of the port has changed (eg. speed)*/
201 - OTHER_UPDATE,
202 - /** Either a port has been deleted by the switch, or we are deleting
203 - * a port whose portNumber-portName mapping has changed. Note that in
204 - * the latter case, a subsequent notification will be sent out to add a
205 - * port with the new portNumber-portName mapping.
206 - */
207 - DELETE,
208 - /** Port is up (i.e. enabled). Presumably an earlier notification had
209 - * indicated that it was down. To be UP implies that the port is
210 - * administratively considered UP (see ofp_port_config) AND the port
211 - * link is up AND the port is no longer blocked (see ofp_port_state).
212 - */
213 - UP,
214 - /** Port is down (i.e. disabled). Presumably an earlier notification had
215 - * indicated that it was up, or the port was always up.
216 - * To be DOWN implies that the port has been either
217 - * administratively brought down (see ofp_port_config) OR the port
218 - * link is down OR the port is blocked (see ofp_port_state).
219 - */
220 - DOWN,
221 - }
222 -
223 - /**
224 - * Describes a change of an open flow port.
225 - */
226 - public static class PortChangeEvent {
227 - public final OFPortDesc port;
228 - public final PortChangeType type;
229 - /**
230 - * @param port
231 - * @param type
232 - */
233 - public PortChangeEvent(OFPortDesc port,
234 - PortChangeType type) {
235 - this.port = port;
236 - this.type = type;
237 - }
238 - /* (non-Javadoc)
239 - * @see java.lang.Object#hashCode()
240 - */
241 - @Override
242 - public int hashCode() {
243 - final int prime = 31;
244 - int result = 1;
245 - result = prime * result + ((port == null) ? 0 : port.hashCode());
246 - result = prime * result + ((type == null) ? 0 : type.hashCode());
247 - return result;
248 - }
249 - /* (non-Javadoc)
250 - * @see java.lang.Object#equals(java.lang.Object)
251 - */
252 - @Override
253 - public boolean equals(Object obj) {
254 - if (this == obj) {
255 - return true;
256 - }
257 - if (obj == null) {
258 - return false;
259 - }
260 - if (getClass() != obj.getClass()) {
261 - return false;
262 - }
263 - PortChangeEvent other = (PortChangeEvent) obj;
264 - if (port == null) {
265 - if (other.port != null) {
266 - return false;
267 - }
268 - } else if (!port.equals(other.port)) {
269 - return false;
270 - }
271 - if (type != other.type) {
272 - return false;
273 - }
274 - return true;
275 - }
276 - /* (non-Javadoc)
277 - * @see java.lang.Object#toString()
278 - */
279 - @Override
280 - public String toString() {
281 - return "[" + type + " " + port.toString() + "]";
282 - }
283 - }
284 -
285 -
286 - /**
287 - * Get list of all enabled ports. This will typically be different from
288 - * the list of ports in the OFFeaturesReply, since that one is a static
289 - * snapshot of the ports at the time the switch connected to the controller
290 - * whereas this port list also reflects the port status messages that have
291 - * been received.
292 - *
293 - * @return Unmodifiable list of ports not backed by the underlying collection
294 - */
295 - public Collection<OFPortDesc> getEnabledPorts();
296 -
297 - /**
298 - * Get list of the port numbers of all enabled ports. This will typically
299 - * be different from the list of ports in the OFFeaturesReply, since that
300 - * one is a static snapshot of the ports at the time the switch connected
301 - * to the controller whereas this port list also reflects the port status
302 - * messages that have been received.
303 - *
304 - * @return Unmodifiable list of ports not backed by the underlying collection
305 - */
306 - public Collection<Integer> getEnabledPortNumbers();
307 -
308 - /**
309 - * Retrieve the port object by the port number. The port object
310 - * is the one that reflects the port status updates that have been
311 - * received, not the one from the features reply.
312 - *
313 - * @param portNumber
314 - * @return port object
315 - */
316 - public OFPortDesc getPort(int portNumber);
317 -
318 - /**
319 - * Retrieve the port object by the port name. The port object
320 - * is the one that reflects the port status updates that have been
321 - * received, not the one from the features reply.
322 - *
323 - * @param portName
324 - * @return port object
325 - */
326 - public OFPortDesc getPort(String portName);
327 -
328 - /**
329 - * Add or modify a switch port. This is called by the core controller
330 - * code in response to a OFPortStatus message.
331 - *
332 - * OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
333 - * spec is not clear on whether portNames are portNumbers are considered
334 - * authoritative identifiers. We treat portNames <-> portNumber mappings
335 - * as fixed. If they change, we delete all previous conflicting ports and
336 - * add all new ports.
337 - *
338 - * @param ps the port status message
339 - * @return the ordered Collection of changes "applied" to the old ports
340 - * of the switch according to the PortStatus message. A single PortStatus
341 - * message can result in multiple changes.
342 - * If portName <-> portNumber mappings have
343 - * changed, the iteration order ensures that delete events for old
344 - * conflicting appear before before events adding new ports
345 - */
346 - public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
347 -
348 - /**
349 - * Get list of all ports. This will typically be different from
350 - * the list of ports in the OFFeaturesReply, since that one is a static
351 - * snapshot of the ports at the time the switch connected to the controller
352 - * whereas this port list also reflects the port status messages that have
353 - * been received.
354 - *
355 - * @return Unmodifiable list of ports
356 - */
357 - public Collection<OFPortDesc> getPorts();
358 -
359 - /**
360 - * @param portName
361 - * @return Whether a port is enabled per latest port status message
362 - * (not configured down nor link down nor in spanning tree blocking state)
363 - */
364 - public boolean portEnabled(int portName);
365 -
366 - /**
367 - * @param portName
368 - * @return Whether a port is enabled per latest port status message
369 - * (not configured down nor link down nor in spanning tree blocking state)
370 - */
371 - public boolean portEnabled(String portName);
372 -
373 - /**
374 - * Compute the changes that would be required to replace the old ports
375 - * of this switch with the new ports.
376 - * @param ports new ports to set
377 - * @return the ordered collection of changes "applied" to the old ports
378 - * of the switch in order to set them to the new set.
379 - * If portName <-> portNumber mappings have
380 - * changed, the iteration order ensures that delete events for old
381 - * conflicting appear before before events adding new ports
382 - */
383 - public OrderedCollection<PortChangeEvent>
384 - comparePorts(Collection<OFPortDesc> ports);
385 -
386 - /**
387 - * Replace the ports of this switch with the given ports.
388 - * @param ports new ports to set
389 - * @return the ordered collection of changes "applied" to the old ports
390 - * of the switch in order to set them to the new set.
391 - * If portName <-> portNumber mappings have
392 - * changed, the iteration order ensures that delete events for old
393 - * conflicting appear before before events adding new ports
394 - */
395 - public OrderedCollection<PortChangeEvent>
396 - setPorts(Collection<OFPortDesc> ports);
397 -
398 - //*******************************************
399 - // IOFSwitch object attributes
400 - //************************
401 -
402 - /**
403 - * Gets attributes of this switch.
404 - *
405 - * @return attributes of the switch
406 - */
407 - public Map<Object, Object> getAttributes();
408 -
409 - /**
410 - * Checks if a specific switch property exists for this switch.
411 - *
412 - * @param name name of property
413 - * @return value for name
414 - */
415 - boolean hasAttribute(String name);
416 -
417 - /**
418 - * Gets properties for switch specific behavior.
419 - *
420 - * @param name name of property
421 - * @return 'value' for 'name', or null if no entry for 'name' exists
422 - */
423 - Object getAttribute(String name);
424 -
425 - /**
426 - * Sets properties for switch specific behavior.
427 - *
428 - * @param name name of property
429 - * @param value value for name
430 - */
431 - void setAttribute(String name, Object value);
432 -
433 - /**
434 - * Removes properties for switch specific behavior.
435 - *
436 - * @param name name of property
437 - * @return current value for name or null (if not present)
438 - */
439 - Object removeAttribute(String name);
440 -
441 - //************************
442 - // Switch statistics
443 - //************************
444 -
445 - /**
446 - * Delivers the statistics future reply.
447 - *
448 - * @param reply the reply to deliver
449 - */
450 - public void deliverStatisticsReply(OFMessage reply);
451 -
452 - /**
453 - * Cancels the statistics reply with the given transaction ID.
454 - *
455 - * @param transactionId the transaction ID
456 - */
457 - public void cancelStatisticsReply(int transactionId);
458 -
459 - /**
460 - * Cancels all statistics replies.
461 - */
462 - public void cancelAllStatisticsReplies();
463 -
464 - /**
465 - * Gets a Future object that can be used to retrieve the asynchronous.
466 - * OFStatisticsReply when it is available.
467 - *
468 - * @param request statistics request
469 - * @return Future object wrapping OFStatisticsReply
470 - * @throws IOException
471 - */
472 - public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
473 - throws IOException;
474 -
475 - //************************
476 - // Switch other utilities
477 - //************************
478 -
479 - /**
480 - * Clears all flowmods on this switch.
481 - */
482 - public void clearAllFlowMods();
483 -
484 - /**
485 - * Gets the current role of this controller for this IOFSwitch.
486 - */
487 - public Role getRole();
488 -
489 - /**
490 - * Sets this controller's Role for this IOFSwitch to role.
491 - *
492 - * @param role
493 - */
494 - public void setRole(Role role);
495 -
496 - /**
497 - * Gets the next generation ID.
498 - * <p>
499 - * Note: relevant for role request messages in OF1.3
500 - *
501 - * @return next generation ID
502 - */
503 - public U64 getNextGenerationId();
504 -
505 -
506 - /**
507 - * Set debug counter service for per-switch counters.
508 - * Called immediately after instantiation.
509 - * @param debugCounter
510 - * @throws CounterException
511 - */
512 - public void setDebugCounterService(IDebugCounterService debugCounter)
513 - throws CounterException;
514 -
515 - /**
516 - * Start this switch driver's sub handshake. This might be a no-op but
517 - * this method must be called at least once for the switch to be become
518 - * ready.
519 - * This method must only be called from the I/O thread
520 - * @throws IOException
521 - * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted
522 - * if the sub-handshake has
523 - * already been started
524 - */
525 - public void startDriverHandshake() throws IOException;
526 -
527 - /**
528 - * Check if the sub-handshake for this switch driver has been completed.
529 - * This method can only be called after startDriverHandshake()
530 - *
531 - * This methods must only be called from the I/O thread
532 - * @return true if the sub-handshake has been completed. False otherwise
533 - * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
534 - * if startDriverHandshake() has
535 - * not been called yet.
536 - */
537 - public boolean isDriverHandshakeComplete();
538 -
539 - /**
540 - * Pass the given OFMessage to the driver as part of this driver's
541 - * sub-handshake. Must not be called after the handshake has been completed
542 - * This methods must only be called from the I/O thread
543 - * @param m The message that the driver should process
544 - * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted
545 - * if isDriverHandshake() returns
546 - * false before this method call
547 - * @throws org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted
548 - * if startDriverHandshake() has
549 - * not been called yet.
550 - */
551 - public void processDriverHandshakeMessage(OFMessage m);
552 -
553 - /**
554 - * Set the flow table full flag in the switch.
555 - * XXX S Rethink this for multiple tables
556 - */
557 - public void setTableFull(boolean isFull);
558 -
559 - /**
560 - * Save the features reply for this switch.
561 - *
562 - * @param featuresReply
563 - */
564 - public void setFeaturesReply(OFFeaturesReply featuresReply);
565 -
566 - /**
567 - * Save the portset for this switch.
568 - *
569 - * @param portDescReply
570 - */
571 - public void setPortDescReply(OFPortDescStatsReply portDescReply);
572 -
573 - //************************
574 - // Message handling
575 - //************************
576 - /**
577 - * Handle the message coming from the dataplane.
578 - *
579 - * @param m the actual message
580 - */
581 - public void handleMessage(OFMessage m);
582 -
583 -
584 -}
1 -package org.onlab.onos.of.controller.impl.debugcounter;
2 -
3 -import java.util.ArrayList;
4 -import java.util.Arrays;
5 -import java.util.Collections;
6 -import java.util.HashSet;
7 -import java.util.List;
8 -import java.util.Map;
9 -import java.util.Set;
10 -import java.util.concurrent.ConcurrentHashMap;
11 -import java.util.concurrent.atomic.AtomicInteger;
12 -import java.util.concurrent.atomic.AtomicLong;
13 -
14 -import org.slf4j.Logger;
15 -import org.slf4j.LoggerFactory;
16 -
17 -
18 -import com.google.common.collect.Sets;
19 -
20 -
21 -
22 -/**
23 - * This class implements a central store for all counters used for debugging the
24 - * system. For counters based on traffic-type, see ICounterStoreService.
25 - *
26 - */
27 -//CHECKSTYLE:OFF
28 -public class DebugCounter implements IDebugCounterService {
29 - protected static final Logger log = LoggerFactory.getLogger(DebugCounter.class);
30 -
31 - /**
32 - * registered counters need a counter id.
33 - */
34 - protected AtomicInteger counterIdCounter = new AtomicInteger();
35 -
36 - /**
37 - * The counter value.
38 - */
39 - protected static class MutableLong {
40 - long value = 0;
41 - public void increment() { value += 1; }
42 - public void increment(long incr) { value += incr; }
43 - public long get() { return value; }
44 - public void set(long val) { value = val; }
45 - }
46 -
47 - /**
48 - * protected class to store counter information.
49 - */
50 - public static class CounterInfo {
51 - String moduleCounterHierarchy;
52 - String counterDesc;
53 - CounterType ctype;
54 - String moduleName;
55 - String counterHierarchy;
56 - int counterId;
57 - boolean enabled;
58 - String[] metaData;
59 -
60 - public CounterInfo(int counterId, boolean enabled,
61 - String moduleName, String counterHierarchy,
62 - String desc, CounterType ctype, String... metaData) {
63 - this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy;
64 - this.moduleName = moduleName;
65 - this.counterHierarchy = counterHierarchy;
66 - this.counterDesc = desc;
67 - this.ctype = ctype;
68 - this.counterId = counterId;
69 - this.enabled = enabled;
70 - this.metaData = metaData;
71 - }
72 -
73 - public String getModuleCounterHierarchy() { return moduleCounterHierarchy; }
74 - public String getCounterDesc() { return counterDesc; }
75 - public CounterType getCtype() { return ctype; }
76 - public String getModuleName() { return moduleName; }
77 - public String getCounterHierarchy() { return counterHierarchy; }
78 - public int getCounterId() { return counterId; }
79 - public boolean isEnabled() { return enabled; }
80 - public String[] getMetaData() { return this.metaData.clone(); }
81 - }
82 -
83 - //******************
84 - // Global stores
85 - //******************
86 -
87 - /**
88 - * Counter info for a debug counter.
89 - */
90 - public static class DebugCounterInfo {
91 - CounterInfo cinfo;
92 - AtomicLong cvalue;
93 -
94 - public DebugCounterInfo(CounterInfo cinfo) {
95 - this.cinfo = cinfo;
96 - this.cvalue = new AtomicLong();
97 - }
98 - public CounterInfo getCounterInfo() {
99 - return cinfo;
100 - }
101 - public Long getCounterValue() {
102 - return cvalue.get();
103 - }
104 - }
105 -
106 - /**
107 - * Global debug-counter storage across all threads. These are
108 - * updated from the local per thread counters by the flush counters method.
109 - */
110 - private static final DebugCounterInfo[] ALLCOUNTERS =
111 - new DebugCounterInfo[MAX_COUNTERS];
112 -
113 -
114 - /**
115 - * per module counters, indexed by the module name and storing three levels
116 - * of Counter information in the form of CounterIndexStore.
117 - */
118 - protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>>
119 - moduleCounters = new ConcurrentHashMap<String,
120 - ConcurrentHashMap<String,
121 - CounterIndexStore>>();
122 -
123 - protected static class CounterIndexStore {
124 - int index;
125 - Map<String, CounterIndexStore> nextLevel;
126 -
127 - public CounterIndexStore(int index, Map<String, CounterIndexStore> cis) {
128 - this.index = index;
129 - this.nextLevel = cis;
130 - }
131 - }
132 -
133 - /**
134 - * fast global cache for counter ids that are currently active.
135 - */
136 - protected Set<Integer> currentCounters = Collections.newSetFromMap(
137 - new ConcurrentHashMap<Integer, Boolean>());
138 -
139 - //******************
140 - // Thread local stores
141 - //******************
142 -
143 - /**
144 - * Thread local storage of counter info.
145 - */
146 - protected static class LocalCounterInfo {
147 - boolean enabled;
148 - MutableLong cvalue;
149 -
150 - public LocalCounterInfo(boolean enabled) {
151 - this.enabled = enabled;
152 - this.cvalue = new MutableLong();
153 - }
154 - }
155 -
156 - /**
157 - * Thread local debug counters used for maintaining counters local to a thread.
158 - */
159 - protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters =
160 - new ThreadLocal<LocalCounterInfo[]>() {
161 - @Override
162 - protected LocalCounterInfo[] initialValue() {
163 - return new LocalCounterInfo[MAX_COUNTERS];
164 - }
165 - };
166 -
167 - /**
168 - * Thread local cache for counter ids that are currently active.
169 - */
170 - protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters =
171 - new ThreadLocal<Set<Integer>>() {
172 - @Override
173 - protected Set<Integer> initialValue() {
174 - return new HashSet<Integer>();
175 - }
176 - };
177 -
178 - //*******************************
179 - // IDebugCounter
180 - //*******************************
181 -
182 - protected class CounterImpl implements IDebugCounter {
183 - private final int counterId;
184 -
185 - public CounterImpl(int counterId) {
186 - this.counterId = counterId;
187 - }
188 -
189 - @Override
190 - public void updateCounterWithFlush() {
191 - if (!validCounterId()) {
192 - return;
193 - }
194 - updateCounter(counterId, 1, true);
195 - }
196 -
197 - @Override
198 - public void updateCounterNoFlush() {
199 - if (!validCounterId()) {
200 - return;
201 - }
202 - updateCounter(counterId, 1, false);
203 - }
204 -
205 - @Override
206 - public void updateCounterWithFlush(int incr) {
207 - if (!validCounterId()) {
208 - return;
209 - }
210 - updateCounter(counterId, incr, true);
211 - }
212 -
213 - @Override
214 - public void updateCounterNoFlush(int incr) {
215 - if (!validCounterId()) {
216 - return;
217 - }
218 - updateCounter(counterId, incr, false);
219 - }
220 -
221 - @Override
222 - public long getCounterValue() {
223 - if (!validCounterId()) {
224 - return -1;
225 - }
226 - return ALLCOUNTERS[counterId].cvalue.get();
227 - }
228 -
229 - /**
230 - * Checks if this is a valid counter.
231 - * @return true if the counter id is valid
232 - */
233 - private boolean validCounterId() {
234 - if (counterId < 0 || counterId >= MAX_COUNTERS) {
235 - log.error("Invalid counterId invoked");
236 - return false;
237 - }
238 - return true;
239 - }
240 -
241 - }
242 -
243 - //*******************************
244 - // IDebugCounterService
245 - //*******************************
246 -
247 - @Override
248 - public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
249 - String counterDescription, CounterType counterType,
250 - String... metaData)
251 - throws CounterException {
252 - // check if counter already exists
253 - if (!moduleCounters.containsKey(moduleName)) {
254 - moduleCounters.putIfAbsent(moduleName,
255 - new ConcurrentHashMap<String, CounterIndexStore>());
256 - }
257 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
258 - if (rci.allLevelsFound) {
259 - // counter exists
260 - log.info("Counter exists for {}/{} -- resetting counters", moduleName,
261 - counterHierarchy);
262 - resetCounterHierarchy(moduleName, counterHierarchy);
263 - return new CounterImpl(rci.ctrIds[rci.foundUptoLevel - 1]);
264 - }
265 - // check for validity of counter
266 - if (rci.levels.length > MAX_HIERARCHY) {
267 - String err = "Registry of counterHierarchy " + counterHierarchy +
268 - " exceeds max hierachy " + MAX_HIERARCHY + ".. aborting";
269 - throw new MaxHierarchyRegistered(err);
270 - }
271 - if (rci.foundUptoLevel < rci.levels.length - 1) {
272 - StringBuilder sb = new StringBuilder();
273 - for (int i = 0; i <= rci.foundUptoLevel; i++) {
274 - sb.append(rci.levels[i]);
275 - }
276 - String needToRegister = sb.toString();
277 - String err = "Attempting to register hierarchical counterHierarchy " +
278 - counterHierarchy + " but parts of hierarchy missing. " +
279 - "Please register " + needToRegister + " first";
280 - throw new MissingHierarchicalLevel(err);
281 - }
282 -
283 - // get a new counter id
284 - int counterId = counterIdCounter.getAndIncrement();
285 - if (counterId >= MAX_COUNTERS) {
286 - throw new MaxCountersRegistered("max counters reached");
287 - }
288 - // create storage for counter
289 - boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false;
290 - CounterInfo ci = new CounterInfo(counterId, enabled, moduleName,
291 - counterHierarchy, counterDescription,
292 - counterType, metaData);
293 - ALLCOUNTERS[counterId] = new DebugCounterInfo(ci);
294 -
295 - // account for the new counter in the module counter hierarchy
296 - addToModuleCounterHierarchy(moduleName, counterId, rci);
297 -
298 - // finally add to active counters
299 - if (enabled) {
300 - currentCounters.add(counterId);
301 - }
302 - return new CounterImpl(counterId);
303 - }
304 -
305 - private void updateCounter(int counterId, int incr, boolean flushNow) {
306 - if (counterId < 0 || counterId >= MAX_COUNTERS) {
307 - return;
308 - }
309 -
310 - LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
311 - if (thiscounters[counterId] == null) {
312 - // seeing this counter for the first time in this thread - create local
313 - // store by consulting global store
314 - DebugCounterInfo dc = ALLCOUNTERS[counterId];
315 - if (dc != null) {
316 - thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled);
317 - if (dc.cinfo.enabled) {
318 - Set<Integer> thisset = this.threadlocalCurrentCounters.get();
319 - thisset.add(counterId);
320 - }
321 - } else {
322 - log.error("updateCounter seen locally for counter {} but no global"
323 - + "storage exists for it yet .. not updating", counterId);
324 - return;
325 - }
326 - }
327 -
328 - // update local store if enabled locally for updating
329 - LocalCounterInfo lc = thiscounters[counterId];
330 - if (lc.enabled) {
331 - lc.cvalue.increment(incr);
332 - if (flushNow) {
333 - DebugCounterInfo dc = ALLCOUNTERS[counterId];
334 - if (dc.cinfo.enabled) {
335 - // globally enabled - flush now
336 - dc.cvalue.addAndGet(lc.cvalue.get());
337 - lc.cvalue.set(0);
338 - } else {
339 - // global counter is disabled - don't flush, disable locally
340 - lc.enabled = false;
341 - Set<Integer> thisset = this.threadlocalCurrentCounters.get();
342 - thisset.remove(counterId);
343 - }
344 - }
345 - }
346 - }
347 -
348 - @Override
349 - public void flushCounters() {
350 - LocalCounterInfo[] thiscounters = this.threadlocalCounters.get();
351 - Set<Integer> thisset = this.threadlocalCurrentCounters.get();
352 - ArrayList<Integer> temp = new ArrayList<Integer>();
353 -
354 - for (int counterId : thisset) {
355 - LocalCounterInfo lc = thiscounters[counterId];
356 - if (lc.cvalue.get() > 0) {
357 - DebugCounterInfo dc = ALLCOUNTERS[counterId];
358 - if (dc.cinfo.enabled) {
359 - // globally enabled - flush now
360 - dc.cvalue.addAndGet(lc.cvalue.get());
361 - lc.cvalue.set(0);
362 - } else {
363 - // global counter is disabled - don't flush, disable locally
364 - lc.enabled = false;
365 - temp.add(counterId);
366 - }
367 - }
368 - }
369 - for (int cId : temp) {
370 - thisset.remove(cId);
371 - }
372 -
373 - // At this point it is possible that the thread-local set does not
374 - // include a counter that has been enabled and is present in the global set.
375 - // We need to sync thread-local currently enabled set of counterIds with
376 - // the global set.
377 - Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset);
378 - for (int counterId : sv) {
379 - if (thiscounters[counterId] != null) {
380 - thiscounters[counterId].enabled = true;
381 - thisset.add(counterId);
382 - }
383 - }
384 - }
385 -
386 - @Override
387 - public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
388 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
389 - if (!rci.allLevelsFound) {
390 - String missing = rci.levels[rci.foundUptoLevel];
391 - log.error("Cannot reset counter hierarchy - missing counter {}", missing);
392 - return;
393 - }
394 - // reset at this level
395 - ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]].cvalue.set(0);
396 - // reset all levels below
397 - ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
398 - for (int index : resetIds) {
399 - ALLCOUNTERS[index].cvalue.set(0);
400 - }
401 - }
402 -
403 - @Override
404 - public void resetAllCounters() {
405 - RetCtrInfo rci = new RetCtrInfo();
406 - rci.levels = "".split("/");
407 - for (String moduleName : moduleCounters.keySet()) {
408 - ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
409 - for (int index : resetIds) {
410 - ALLCOUNTERS[index].cvalue.set(0);
411 - }
412 - }
413 - }
414 -
415 - @Override
416 - public void resetAllModuleCounters(String moduleName) {
417 - Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
418 - RetCtrInfo rci = new RetCtrInfo();
419 - rci.levels = "".split("/");
420 -
421 - if (target != null) {
422 - ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
423 - for (int index : resetIds) {
424 - ALLCOUNTERS[index].cvalue.set(0);
425 - }
426 - } else {
427 - if (log.isDebugEnabled()) {
428 - log.debug("No module found with name {}", moduleName);
429 - }
430 - }
431 - }
432 -
433 - @Override
434 - public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
435 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
436 - if (!rci.allLevelsFound) {
437 - String missing = rci.levels[rci.foundUptoLevel];
438 - log.error("Cannot enable counter - counter not found {}", missing);
439 - return;
440 - }
441 - // enable specific counter
442 - DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
443 - dc.cinfo.enabled = true;
444 - currentCounters.add(dc.cinfo.counterId);
445 - }
446 -
447 - @Override
448 - public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
449 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
450 - if (!rci.allLevelsFound) {
451 - String missing = rci.levels[rci.foundUptoLevel];
452 - log.error("Cannot disable counter - counter not found {}", missing);
453 - return;
454 - }
455 - // disable specific counter
456 - DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
457 - if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) {
458 - dc.cinfo.enabled = false;
459 - dc.cvalue.set(0);
460 - currentCounters.remove(dc.cinfo.counterId);
461 - }
462 - }
463 -
464 - @Override
465 - public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
466 - String counterHierarchy) {
467 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
468 - if (!rci.allLevelsFound) {
469 - String missing = rci.levels[rci.foundUptoLevel];
470 - log.error("Cannot fetch counter - counter not found {}", missing);
471 - return Collections.emptyList();
472 - }
473 - ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
474 - // get counter and all below it
475 - DebugCounterInfo dc = ALLCOUNTERS[rci.ctrIds[rci.foundUptoLevel - 1]];
476 - dcilist.add(dc);
477 - ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci);
478 - for (int index : belowIds) {
479 - dcilist.add(ALLCOUNTERS[index]);
480 - }
481 - return dcilist;
482 - }
483 -
484 - @Override
485 - public List<DebugCounterInfo> getAllCounterValues() {
486 - List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
487 - RetCtrInfo rci = new RetCtrInfo();
488 - rci.levels = "".split("/");
489 -
490 - for (String moduleName : moduleCounters.keySet()) {
491 - ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
492 - for (int index : resetIds) {
493 - dcilist.add(ALLCOUNTERS[index]);
494 - }
495 - }
496 - return dcilist;
497 - }
498 -
499 - @Override
500 - public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
501 - List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
502 - RetCtrInfo rci = new RetCtrInfo();
503 - rci.levels = "".split("/");
504 -
505 - if (moduleCounters.containsKey(moduleName)) {
506 - ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
507 - for (int index : resetIds) {
508 - dcilist.add(ALLCOUNTERS[index]);
509 - }
510 - }
511 - return dcilist;
512 - }
513 -
514 - @Override
515 - public boolean containsModuleCounterHierarchy(String moduleName,
516 - String counterHierarchy) {
517 - if (!moduleCounters.containsKey(moduleName)) {
518 - return false;
519 - }
520 - RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
521 - return rci.allLevelsFound;
522 - }
523 -
524 - @Override
525 - public boolean containsModuleName(String moduleName) {
526 - return (moduleCounters.containsKey(moduleName)) ? true : false;
527 - }
528 -
529 - @Override
530 - public List<String> getModuleList() {
531 - List<String> retval = new ArrayList<String>();
532 - retval.addAll(moduleCounters.keySet());
533 - return retval;
534 - }
535 -
536 - @Override
537 - public List<String> getModuleCounterList(String moduleName) {
538 - if (!moduleCounters.containsKey(moduleName)) {
539 - return Collections.emptyList();
540 - }
541 -
542 - List<String> retval = new ArrayList<String>();
543 - RetCtrInfo rci = new RetCtrInfo();
544 - rci.levels = "".split("/");
545 -
546 - ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci);
547 - for (int index : cids) {
548 - retval.add(ALLCOUNTERS[index].cinfo.counterHierarchy);
549 - }
550 - return retval;
551 - }
552 -
553 - //*******************************
554 - // Internal Methods
555 - //*******************************
556 -
557 - protected class RetCtrInfo {
558 - boolean allLevelsFound; // counter indices found all the way down the hierarchy
559 - boolean hierarchical; // true if counterHierarchy is hierarchical
560 - int foundUptoLevel;
561 - int[] ctrIds;
562 - String[] levels;
563 -
564 - public RetCtrInfo() {
565 - ctrIds = new int[MAX_HIERARCHY];
566 - for (int i = 0; i < MAX_HIERARCHY; i++) {
567 - ctrIds[i] = -1;
568 - }
569 - }
570 -
571 - @Override
572 - public int hashCode() {
573 - final int prime = 31;
574 - int result = 1;
575 - result = prime * result + getOuterType().hashCode();
576 - result = prime * result + (allLevelsFound ? 1231 : 1237);
577 - result = prime * result + Arrays.hashCode(ctrIds);
578 - result = prime * result + foundUptoLevel;
579 - result = prime * result + (hierarchical ? 1231 : 1237);
580 - result = prime * result + Arrays.hashCode(levels);
581 - return result;
582 - }
583 -
584 - @Override
585 - public boolean equals(Object oth) {
586 - if (!(oth instanceof RetCtrInfo)) {
587 - return false;
588 - }
589 - RetCtrInfo other = (RetCtrInfo) oth;
590 - if (other.allLevelsFound != this.allLevelsFound) {
591 - return false;
592 - }
593 - if (other.hierarchical != this.hierarchical) {
594 - return false;
595 - }
596 - if (other.foundUptoLevel != this.foundUptoLevel) {
597 - return false;
598 - }
599 - if (!Arrays.equals(other.ctrIds, this.ctrIds)) {
600 - return false;
601 - }
602 - if (!Arrays.equals(other.levels, this.levels)) {
603 - return false;
604 - }
605 - return true;
606 - }
607 -
608 - private DebugCounter getOuterType() {
609 - return DebugCounter.this;
610 - }
611 -
612 -
613 -
614 - }
615 -
616 - protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) {
617 - RetCtrInfo rci = new RetCtrInfo();
618 - Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName);
619 - rci.levels = counterHierarchy.split("/");
620 - if (rci.levels.length > 1) {
621 - rci.hierarchical = true;
622 - }
623 - if (templevel == null) {
624 - log.error("moduleName {} does not exist in debugCounters", moduleName);
625 - return rci;
626 - }
627 -
628 - /*
629 - if (rci.levels.length > MAX_HIERARCHY) {
630 - // chop off all array elems greater that MAX_HIERARCHY
631 - String[] temp = new String[MAX_HIERARCHY];
632 - System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY);
633 - rci.levels = temp;
634 - }
635 - */
636 - for (int i = 0; i < rci.levels.length; i++) {
637 - if (templevel != null) {
638 - CounterIndexStore cis = templevel.get(rci.levels[i]);
639 - if (cis == null) {
640 - // could not find counterHierarchy part at this level
641 - break;
642 - } else {
643 - rci.ctrIds[i] = cis.index;
644 - templevel = cis.nextLevel;
645 - rci.foundUptoLevel++;
646 - if (i == rci.levels.length - 1) {
647 - rci.allLevelsFound = true;
648 - }
649 - }
650 - } else {
651 - // there are no more levels, which means that some part of the
652 - // counterHierarchy has no corresponding map
653 - break;
654 - }
655 - }
656 - return rci;
657 - }
658 -
659 - protected void addToModuleCounterHierarchy(String moduleName, int counterId,
660 - RetCtrInfo rci) {
661 - Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
662 - if (target == null) {
663 - return;
664 - }
665 - CounterIndexStore cis = null;
666 -
667 - for (int i = 0; i < rci.foundUptoLevel; i++) {
668 - cis = target.get(rci.levels[i]);
669 - target = cis.nextLevel;
670 - }
671 - if (cis != null) {
672 - if (cis.nextLevel == null) {
673 - cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>();
674 - }
675 - cis.nextLevel.put(rci.levels[rci.foundUptoLevel],
676 - new CounterIndexStore(counterId, null));
677 - } else {
678 - target.put(rci.levels[rci.foundUptoLevel],
679 - new CounterIndexStore(counterId, null));
680 - }
681 - }
682 -
683 - // given a partial hierarchical counter, return the rest of the hierarchy
684 - protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) {
685 - Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
686 - CounterIndexStore cis = null;
687 - ArrayList<Integer> retval = new ArrayList<Integer>();
688 - if (target == null) {
689 - return retval;
690 - }
691 -
692 - // get to the level given
693 - for (int i = 0; i < rci.foundUptoLevel; i++) {
694 - cis = target.get(rci.levels[i]);
695 - target = cis.nextLevel;
696 - }
697 -
698 - if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) {
699 - // no more levels
700 - return retval;
701 - } else {
702 - // recursively get all ids
703 - getIdsAtLevel(target, retval, rci.foundUptoLevel + 1);
704 - }
705 -
706 - return retval;
707 - }
708 -
709 - protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy,
710 - ArrayList<Integer> retval, int level) {
711 - if (level > MAX_HIERARCHY) {
712 - return;
713 - }
714 - if (hcy == null || retval == null) {
715 - return;
716 - }
717 -
718 - // Can return the counter names as well but for now ids are enough.
719 - for (CounterIndexStore cistemp : hcy.values()) {
720 - retval.add(cistemp.index); // value at this level
721 - if (cistemp.nextLevel != null) {
722 - getIdsAtLevel(cistemp.nextLevel, retval, level + 1);
723 - }
724 - }
725 - }
726 -
727 -}
1 -package org.onlab.onos.of.controller.impl.debugcounter;
2 -
3 -public interface IDebugCounter {
4 - /**
5 - * Increments the counter by 1 thread-locally, and immediately flushes to
6 - * the global counter storage. This method should be used for counters that
7 - * are updated outside the OF message processing pipeline.
8 - */
9 - void updateCounterWithFlush();
10 -
11 - /**
12 - * Increments the counter by 1 thread-locally. Flushing to the global
13 - * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
14 - * resulting in higher performance. This method should be used for counters
15 - * updated in the OF message processing pipeline.
16 - */
17 - void updateCounterNoFlush();
18 -
19 - /**
20 - * Increments the counter thread-locally by the 'incr' specified, and immediately
21 - * flushes to the global counter storage. This method should be used for counters
22 - * that are updated outside the OF message processing pipeline.
23 - */
24 - void updateCounterWithFlush(int incr);
25 -
26 - /**
27 - * Increments the counter thread-locally by the 'incr' specified. Flushing to the global
28 - * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
29 - * resulting in higher performance. This method should be used for counters
30 - * updated in the OF message processing pipeline.
31 - */
32 - void updateCounterNoFlush(int incr);
33 -
34 - /**
35 - * Retrieve the value of the counter from the global counter store.
36 - */
37 - long getCounterValue();
38 -}
1 -package org.onlab.onos.of.controller.impl.debugcounter;
2 -
3 -
4 -
5 -import java.util.List;
6 -
7 -import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter.DebugCounterInfo;
8 -
9 -//CHECKSTYLE:OFF
10 -public interface IDebugCounterService {
11 -
12 - /**
13 - * Different counter types. Counters that are meant to be counted-on-demand
14 - * need to be separately enabled/disabled.
15 - */
16 - public enum CounterType {
17 - ALWAYS_COUNT,
18 - COUNT_ON_DEMAND
19 - }
20 -
21 - /**
22 - * Debug Counter Qualifiers.
23 - */
24 - public static final String CTR_MDATA_WARN = "warn";
25 - public static final String CTR_MDATA_ERROR = "error";
26 - public static final String CTR_MDATA_DROP = "drop";
27 -
28 - /**
29 - * A limit on the maximum number of counters that can be created.
30 - */
31 - public static final int MAX_COUNTERS = 5000;
32 -
33 - /**
34 - * Exception thrown when MAX_COUNTERS have been registered.
35 - */
36 - public class MaxCountersRegistered extends CounterException {
37 - private static final long serialVersionUID = 3173747663719376745L;
38 - String errormsg;
39 - public MaxCountersRegistered(String errormsg) {
40 - this.errormsg = errormsg;
41 - }
42 - @Override
43 - public String getMessage() {
44 - return this.errormsg;
45 - }
46 - }
47 - /**
48 - * Exception thrown when MAX_HIERARCHY has been reached.
49 - */
50 - public class MaxHierarchyRegistered extends CounterException {
51 - private static final long serialVersionUID = 967431358683523871L;
52 - private String errormsg;
53 - public MaxHierarchyRegistered(String errormsg) {
54 - this.errormsg = errormsg;
55 - }
56 - @Override
57 - public String getMessage() {
58 - return this.errormsg;
59 - }
60 - }
61 - /**
62 - * Exception thrown when attempting to register a hierarchical counter
63 - * where higher levels of the hierarchy have not been pre-registered.
64 - */
65 - public class MissingHierarchicalLevel extends CounterException {
66 - private static final long serialVersionUID = 517315311533995739L;
67 - private String errormsg;
68 - public MissingHierarchicalLevel(String errormsg) {
69 - this.errormsg = errormsg;
70 - }
71 - @Override
72 - public String getMessage() {
73 - return this.errormsg;
74 - }
75 - }
76 -
77 - public class CounterException extends Exception {
78 - private static final long serialVersionUID = 2219781500857866035L;
79 - }
80 -
81 - /**
82 - * maximum levels of hierarchy.
83 - * Example of moduleName/counterHierarchy:
84 - * switch/00:00:00:00:01:02:03:04/pktin/drops where
85 - * moduleName ==> "switch" and
86 - * counterHierarchy of 3 ==> "00:00:00:00:01:02:03:04/pktin/drops"
87 - */
88 - public static final int MAX_HIERARCHY = 3;
89 -
90 - /**
91 - * All modules that wish to have the DebugCounterService count for them, must
92 - * register their counters by making this call (typically from that module's
93 - * 'startUp' method). The counter can then be updated, displayed, reset etc.
94 - * using the registered moduleName and counterHierarchy.
95 - *
96 - * @param moduleName the name of the module which is registering the
97 - * counter eg. linkdiscovery or controller or switch
98 - * @param counterHierarchy the hierarchical counter name specifying all
99 - * the hierarchical levels that come above it.
100 - * For example: to register a drop counter for
101 - * packet-ins from a switch, the counterHierarchy
102 - * can be "00:00:00:00:01:02:03:04/pktin/drops"
103 - * It is necessary that counters in hierarchical levels
104 - * above have already been pre-registered - in this
105 - * example: "00:00:00:00:01:02:03:04/pktin" and
106 - * "00:00:00:00:01:02:03:04"
107 - * @param counterDescription a descriptive string that gives more information
108 - * of what the counter is measuring. For example,
109 - * "Measures the number of incoming packets seen by
110 - * this module".
111 - * @param counterType One of CounterType. On-demand counter types
112 - * need to be explicitly enabled/disabled using other
113 - * methods in this API -- i.e. registering them is
114 - * not enough to start counting.
115 - * @param metaData variable arguments that qualify a counter
116 - * eg. warn, error etc.
117 - * @return IDebugCounter with update methods that can be
118 - * used to update a counter.
119 - * @throws MaxCountersRegistered
120 - * @throws MaxHierarchyRegistered
121 - * @throws MissingHierarchicalLevel
122 - */
123 - public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
124 - String counterDescription, CounterType counterType,
125 - String... metaData)
126 - throws CounterException;
127 -
128 - /**
129 - * Flush all thread-local counter values (from the current thread)
130 - * to the global counter store. This method is not intended for use by any
131 - * module. It's typical usage is from core and it is meant
132 - * to flush those counters that are updated in the packet-processing pipeline,
133 - * typically with the 'updateCounterNoFlush" methods in IDebugCounter.
134 - */
135 - public void flushCounters();
136 -
137 - /**
138 - * Resets the value of counters in the hierarchy to zero. Note that the reset
139 - * applies to the level of counter hierarchy specified AND ALL LEVELS BELOW it
140 - * in the hierarchy.
141 - * For example: If a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops"
142 - * specifying a reset hierarchy: "00:00:00:00:01:02:03:04"
143 - * will reset all counters for the switch dpid specified;
144 - * while specifying a reset hierarchy: ""00:00:00:00:01:02:03:04/pktin"
145 - * will reset the pktin counter and all levels below it (like drops)
146 - * for the switch dpid specified.
147 - */
148 - void resetCounterHierarchy(String moduleName, String counterHierarchy);
149 -
150 - /**
151 - * Resets the values of all counters in the system.
152 - */
153 - public void resetAllCounters();
154 -
155 - /**
156 - * Resets the values of all counters belonging
157 - * to a module with the given 'moduleName'.
158 - */
159 - public void resetAllModuleCounters(String moduleName);
160 -
161 - /**
162 - * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
163 - * enable counting on the counter. Note that this step is necessary to start
164 - * counting for these counter types - merely registering the counter is not
165 - * enough (as is the case for CounterType.ALWAYS_COUNT). Newly
166 - * enabled counters start from an initial value of zero.
167 - *
168 - * Enabling a counter in a counterHierarchy enables only THAT counter. It
169 - * does not enable any other part of the counterHierarchy. For example, if
170 - * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
171 - * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then enabling
172 - * the 'pktin' counter by specifying the counterHierarchy as
173 - * "00:00:00:00:01:02:03:04/pktin" does NOT enable the 'drops' counter.
174 - */
175 - public void enableCtrOnDemand(String moduleName, String counterHierarchy);
176 -
177 - /**
178 - * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
179 - * enable counting on the counter. Note that disabling a counter results in a loss
180 - * of the counter value. When re-enabled the counter will restart from zero.
181 - *
182 - * Disabling a counter in a counterHierarchy disables only THAT counter. It
183 - * does not disable any other part of the counterHierarchy. For example, if
184 - * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
185 - * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then disabling
186 - * the 'pktin' counter by specifying the counterHierarchy as
187 - * "00:00:00:00:01:02:03:04/pktin" does NOT disable the 'drops' counter.
188 - */
189 - public void disableCtrOnDemand(String moduleName, String counterHierarchy);
190 -
191 - /**
192 - * Get counter value and associated information for the specified counterHierarchy.
193 - * Note that information on the level of counter hierarchy specified
194 - * AND ALL LEVELS BELOW it in the hierarchy will be returned.
195 - *
196 - * For example,
197 - * if a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", then
198 - * specifying a counterHierarchy of "00:00:00:00:01:02:03:04/pktin" in the
199 - * get call will return information on the 'pktin' as well as the 'drops'
200 - * counters for the switch dpid specified.
201 - *
202 - * @return A list of DebugCounterInfo or an empty list if the counter
203 - * could not be found
204 - */
205 - public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
206 - String counterHierarchy);
207 -
208 - /**
209 - * Get counter values and associated information for all counters in the
210 - * system.
211 - *
212 - * @return the list of values/info or an empty list
213 - */
214 - public List<DebugCounterInfo> getAllCounterValues();
215 -
216 - /**
217 - * Get counter values and associated information for all counters associated
218 - * with a module.
219 - *
220 - * @param moduleName
221 - * @return the list of values/info or an empty list
222 - */
223 - public List<DebugCounterInfo> getModuleCounterValues(String moduleName);
224 -
225 - /**
226 - * Convenience method to figure out if the the given 'counterHierarchy' corresponds
227 - * to a registered counterHierarchy for 'moduleName'. Note that the counter may or
228 - * may not be enabled for counting, but if it is registered the method will
229 - * return true.
230 - *
231 - * @param moduleName
232 - * @param counterHierarchy
233 - * @return false if moduleCounterHierarchy is not a registered counter
234 - */
235 - public boolean containsModuleCounterHierarchy(String moduleName,
236 - String counterHierarchy);
237 -
238 - /**
239 - * Convenience method to figure out if the the given 'moduleName' corresponds
240 - * to a registered moduleName or not. Note that the module may or may not have
241 - * a counter enabled for counting, but if it is registered the method will
242 - * return true.
243 - *
244 - * @param moduleName
245 - * @return false if moduleName is not a registered counter
246 - */
247 - public boolean containsModuleName(String moduleName);
248 -
249 - /**
250 - * Returns a list of moduleNames registered for debug counters or an empty
251 - * list if no counters have been registered in the system.
252 - */
253 - public List<String> getModuleList();
254 -
255 - /**
256 - * Returns a list of all counters registered for a specific moduleName
257 - * or a empty list.
258 - */
259 - public List<String> getModuleCounterList(String moduleName);
260 -
261 -
262 -}
1 -package org.onlab.onos.of.controller.impl.debugcounter;
2 -
3 -import java.util.Collections;
4 -import java.util.List;
5 -
6 -import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter.DebugCounterInfo;
7 -
8 -//CHECKSTYLE:OFF
9 -public class NullDebugCounter implements IDebugCounterService {
10 -
11 - @Override
12 - public void flushCounters() {
13 -
14 - }
15 -
16 - @Override
17 - public void resetAllCounters() {
18 -
19 - }
20 -
21 - @Override
22 - public void resetAllModuleCounters(String moduleName) {
23 -
24 - }
25 -
26 -
27 - @Override
28 - public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
29 -
30 - }
31 -
32 - @Override
33 - public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
34 -
35 - }
36 -
37 - @Override
38 - public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
39 -
40 - }
41 -
42 - @Override
43 - public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
44 - String counterHierarchy) {
45 - return Collections.emptyList();
46 - }
47 -
48 - @Override
49 - public List<DebugCounterInfo> getAllCounterValues() {
50 - return Collections.emptyList();
51 - }
52 -
53 - @Override
54 - public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
55 - return Collections.emptyList();
56 - }
57 -
58 - @Override
59 - public boolean containsModuleCounterHierarchy(String moduleName,
60 - String counterHierarchy) {
61 - return false;
62 - }
63 -
64 - @Override
65 - public boolean containsModuleName(String moduleName) {
66 - return false;
67 - }
68 -
69 - @Override
70 - public
71 - IDebugCounter
72 - registerCounter(String moduleName, String counterHierarchy,
73 - String counterDescription,
74 - CounterType counterType, String... metaData)
75 - throws MaxCountersRegistered {
76 - return new NullCounterImpl();
77 - }
78 -
79 - @Override
80 - public List<String> getModuleList() {
81 - return Collections.emptyList();
82 - }
83 -
84 - @Override
85 - public List<String> getModuleCounterList(String moduleName) {
86 - return Collections.emptyList();
87 - }
88 -
89 - public static class NullCounterImpl implements IDebugCounter {
90 -
91 - @Override
92 - public void updateCounterWithFlush() {
93 -
94 - }
95 -
96 - @Override
97 - public void updateCounterNoFlush() {
98 -
99 - }
100 -
101 - @Override
102 - public void updateCounterWithFlush(int incr) {
103 - }
104 -
105 - @Override
106 - public void updateCounterNoFlush(int incr) {
107 -
108 - }
109 -
110 - @Override
111 - public long getCounterValue() {
112 - return -1;
113 - }
114 -
115 - }
116 -
117 -}
1 +/**
2 + * Copyright 2011, Big Switch Networks, Inc.
3 + * Originally created by David Erickson, Stanford University
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 + * not use this file except in compliance with the License. You may obtain
7 + * a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 + * License for the specific language governing permissions and limitations
15 + * under the License.
16 + **/
17 +
18 +package org.onlab.onos.of.controller.impl.internal;
19 +
20 +import java.io.IOException;
21 +import java.util.List;
22 +
23 +import org.jboss.netty.channel.Channel;
24 +import org.onlab.onos.of.controller.Dpid;
25 +import org.onlab.onos.of.controller.OpenFlowSwitch;
26 +import org.onlab.onos.of.controller.RoleState;
27 +import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
28 +import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus;
29 +import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo;
30 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
31 +import org.projectfloodlight.openflow.protocol.OFExperimenter;
32 +import org.projectfloodlight.openflow.protocol.OFFactories;
33 +import org.projectfloodlight.openflow.protocol.OFFactory;
34 +import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
35 +import org.projectfloodlight.openflow.protocol.OFMessage;
36 +import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
37 +import org.projectfloodlight.openflow.protocol.OFRoleReply;
38 +import org.projectfloodlight.openflow.protocol.OFVersion;
39 +import org.slf4j.Logger;
40 +import org.slf4j.LoggerFactory;
41 +
42 +
43 +public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
44 +
45 + private static Logger log =
46 + LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
47 +
48 + private Channel channel;
49 + private boolean connected;
50 + private Dpid dpid;
51 + private OpenFlowSwitchAgent agent;
52 +
53 + private OFVersion ofVersion;
54 +
55 + protected OFPortDescStatsReply ports;
56 +
57 + protected boolean tableFull;
58 +
59 + private final RoleManager roleMan = new RoleManager(this);
60 +
61 + protected AbstractOpenFlowSwitch(long dpid) {
62 + this.dpid = new Dpid(dpid);
63 + }
64 +
65 + //************************
66 + // Channel related
67 + //************************
68 +
69 + /**
70 + * Disconnects the switch by closing the TCP connection. Results in a call
71 + * to the channel handler's channelDisconnected method for cleanup
72 + * @throws IOException
73 + */
74 + public final void disconnectSwitch() {
75 + this.channel.close();
76 + }
77 +
78 + /**
79 + * Writes to the OFMessage to the output stream.
80 + *
81 + * @param m the message to be written
82 + */
83 + public abstract void write(OFMessage m);
84 +
85 + /**
86 + * Writes to the OFMessage list to the output stream.
87 + *
88 + * @param msgs the messages to be written
89 + */
90 + public abstract void write(List<OFMessage> msgs);
91 +
92 +
93 + /**
94 + * Checks if the switch is still connected.
95 + * Only call while holding processMessageLock
96 + *
97 + * @return whether the switch is still disconnected
98 + */
99 + public final boolean isConnected() {
100 + return this.connected;
101 + }
102 +
103 + /**
104 + * Sets whether the switch is connected.
105 + * Only call while holding modifySwitchLock
106 + *
107 + * @param connected whether the switch is connected
108 + */
109 + final void setConnected(boolean connected) {
110 + this.connected = connected;
111 + };
112 +
113 + /**
114 + * Sets the Netty Channel this switch instance is associated with.
115 + * <p>
116 + * Called immediately after instantiation
117 + *
118 + * @param channel the channel
119 + */
120 + public final void setChannel(Channel channel) {
121 + this.channel = channel;
122 + };
123 +
124 + //************************
125 + // Switch features related
126 + //************************
127 +
128 + /**
129 + * Gets the datapathId of the switch.
130 + *
131 + * @return the switch buffers
132 + */
133 + public final long getId() {
134 + return this.dpid.value();
135 + };
136 +
137 + /**
138 + * Gets a string version of the ID for this switch.
139 + *
140 + * @return string version of the ID
141 + */
142 + public final String getStringId() {
143 + return this.dpid.toString();
144 + }
145 +
146 + public final void setOFVersion(OFVersion ofV) {
147 + this.ofVersion = ofV;
148 + }
149 +
150 + void setTableFull(boolean full) {
151 + this.tableFull = full;
152 + }
153 +
154 + public abstract void setFeaturesReply(OFFeaturesReply featuresReply);
155 +
156 + /**
157 + * Let peoeple know if you support Nicira style role requests.
158 + *
159 + * @return support Nicira roles or not.
160 + */
161 + public abstract Boolean supportNxRole();
162 +
163 + //************************
164 + // Message handling
165 + //************************
166 + /**
167 + * Handle the message coming from the dataplane.
168 + *
169 + * @param m the actual message
170 + */
171 + public final void handleMessage(OFMessage m) {
172 + this.agent.processMessage(m);
173 + }
174 +
175 + public abstract RoleState getRole();
176 +
177 + final boolean addConnectedSwitch() {
178 + return this.agent.addConnectedSwitch(this.getId(), this);
179 + }
180 +
181 + final boolean addActivatedMasterSwitch() {
182 + return this.agent.addActivatedMasterSwitch(this.getId(), this);
183 + }
184 +
185 + final boolean addActivatedEqualSwitch() {
186 + return this.agent.addActivatedEqualSwitch(this.getId(), this);
187 + }
188 +
189 + final void transitionToEqualSwitch() {
190 + this.agent.transitionToEqualSwitch(this.getId());
191 + }
192 +
193 + final void transitionToMasterSwitch() {
194 + this.agent.transitionToMasterSwitch(this.getId());
195 + }
196 +
197 + final void removeConnectedSwitch() {
198 + this.agent.removeConnectedSwitch(this.getId());
199 + }
200 +
201 + protected OFFactory factory() {
202 + return OFFactories.getFactory(ofVersion);
203 + }
204 +
205 + public void setPortDescReply(OFPortDescStatsReply portDescReply) {
206 + this.ports = portDescReply;
207 + }
208 +
209 + public abstract void startDriverHandshake();
210 +
211 + public abstract boolean isDriverHandshakeComplete();
212 +
213 + public abstract void processDriverHandshakeMessage(OFMessage m);
214 +
215 + public void setRole(RoleState role) {
216 + try {
217 + this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
218 + } catch (IOException e) {
219 + log.error("Unable to write to switch {}.", this.dpid);
220 + }
221 + }
222 +
223 + // Role Handling
224 +
225 + void handleRole(OFMessage m) throws SwitchStateException {
226 + RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
227 + RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
228 + if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
229 + if (rri.getRole() == RoleState.MASTER) {
230 + this.transitionToMasterSwitch();
231 + } else if (rri.getRole() == RoleState.EQUAL ||
232 + rri.getRole() == RoleState.MASTER) {
233 + this.transitionToEqualSwitch();
234 + }
235 + }
236 + }
237 +
238 + void handleNiciraRole(OFMessage m) throws SwitchStateException {
239 + RoleState role = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
240 + if (role == null) {
241 + // The message wasn't really a Nicira role reply. We just
242 + // dispatch it to the OFMessage listeners in this case.
243 + this.handleMessage(m);
244 + }
245 +
246 + RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
247 + new RoleReplyInfo(role, null, m.getXid()));
248 + if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
249 + if (role == RoleState.MASTER) {
250 + this.transitionToMasterSwitch();
251 + } else if (role == RoleState.EQUAL ||
252 + role == RoleState.SLAVE) {
253 + this.transitionToEqualSwitch();
254 + }
255 + }
256 + }
257 +
258 + boolean handleRoleError(OFErrorMsg error) {
259 + try {
260 + return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
261 + } catch (SwitchStateException e) {
262 + this.disconnectSwitch();
263 + }
264 + return true;
265 + }
266 +
267 + void reassertRole() {
268 + if (this.getRole() == RoleState.MASTER) {
269 + this.setRole(RoleState.MASTER);
270 + }
271 + }
272 +
273 + void setAgent(OpenFlowSwitchAgent ag) {
274 + this.agent = ag;
275 + }
276 +
277 +
278 +
279 +}
...@@ -20,47 +20,22 @@ package org.onlab.onos.of.controller.impl.internal; ...@@ -20,47 +20,22 @@ package org.onlab.onos.of.controller.impl.internal;
20 import java.lang.management.ManagementFactory; 20 import java.lang.management.ManagementFactory;
21 import java.lang.management.RuntimeMXBean; 21 import java.lang.management.RuntimeMXBean;
22 import java.net.InetSocketAddress; 22 import java.net.InetSocketAddress;
23 -import java.net.UnknownHostException;
24 -import java.util.Collections;
25 import java.util.HashMap; 23 import java.util.HashMap;
26 -import java.util.HashSet;
27 import java.util.Map; 24 import java.util.Map;
28 -import java.util.Set;
29 -import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.Executors; 25 import java.util.concurrent.Executors;
31 26
32 -import org.onlab.onos.of.controller.impl.IOFSwitchManager;
33 -import org.onlab.onos.of.controller.impl.Role;
34 -import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
35 -import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
36 -import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter;
37 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounter;
38 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
39 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
40 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterType;
41 -import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.RoleRecvStatus;
42 -import org.onlab.onos.of.controller.impl.registry.IControllerRegistry;
43 -import org.onlab.onos.of.controller.impl.registry.RegistryException;
44 -import org.onlab.onos.of.controller.impl.registry.IControllerRegistry.ControlChangeCallback;
45 -import org.onlab.onos.of.controller.impl.util.Dpid;
46 -import org.onlab.onos.of.controller.impl.util.DummySwitchForTesting;
47 -import org.onlab.onos.of.controller.impl.util.InstanceId;
48 -import org.onlab.onos.of.controller.impl.IOFSwitch;
49 -import org.onlab.onos.of.controller.impl.IOFSwitch.PortChangeType;
50 -
51 -import org.apache.felix.scr.annotations.Activate;
52 -import org.apache.felix.scr.annotations.Component;
53 import org.jboss.netty.bootstrap.ServerBootstrap; 27 import org.jboss.netty.bootstrap.ServerBootstrap;
54 import org.jboss.netty.channel.ChannelPipelineFactory; 28 import org.jboss.netty.channel.ChannelPipelineFactory;
55 import org.jboss.netty.channel.group.ChannelGroup; 29 import org.jboss.netty.channel.group.ChannelGroup;
56 import org.jboss.netty.channel.group.DefaultChannelGroup; 30 import org.jboss.netty.channel.group.DefaultChannelGroup;
57 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 31 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
32 +import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
33 +import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
34 +import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
58 import org.projectfloodlight.openflow.protocol.OFDescStatsReply; 35 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
59 import org.projectfloodlight.openflow.protocol.OFFactories; 36 import org.projectfloodlight.openflow.protocol.OFFactories;
60 import org.projectfloodlight.openflow.protocol.OFFactory; 37 import org.projectfloodlight.openflow.protocol.OFFactory;
61 -import org.projectfloodlight.openflow.protocol.OFPortDesc;
62 import org.projectfloodlight.openflow.protocol.OFVersion; 38 import org.projectfloodlight.openflow.protocol.OFVersion;
63 -import org.projectfloodlight.openflow.util.HexString;
64 import org.slf4j.Logger; 39 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory; 40 import org.slf4j.LoggerFactory;
66 41
...@@ -69,7 +44,6 @@ import org.slf4j.LoggerFactory; ...@@ -69,7 +44,6 @@ import org.slf4j.LoggerFactory;
69 * The main controller class. Handles all setup and network listeners 44 * The main controller class. Handles all setup and network listeners
70 * - Distributed ownership control of switch through IControllerRegistryService 45 * - Distributed ownership control of switch through IControllerRegistryService
71 */ 46 */
72 -@Component(immediate = true)
73 public class Controller { 47 public class Controller {
74 48
75 protected static final Logger log = LoggerFactory.getLogger(Controller.class); 49 protected static final Logger log = LoggerFactory.getLogger(Controller.class);
...@@ -78,189 +52,33 @@ public class Controller { ...@@ -78,189 +52,33 @@ public class Controller {
78 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13); 52 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
79 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10); 53 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
80 54
81 - // connectedSwitches cache contains all connected switch's channelHandlers 55 +
82 - // including ones where this controller is a master/equal/slave controller
83 - // as well as ones that have not been activated yet
84 - protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
85 - // These caches contains only those switches that are active
86 - protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
87 - protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
88 - // lock to synchronize on, when manipulating multiple caches above
89 - private Object multiCacheLock;
90 56
91 // The controllerNodeIPsCache maps Controller IDs to their IP address. 57 // The controllerNodeIPsCache maps Controller IDs to their IP address.
92 // It's only used by handleControllerNodeIPsChanged 58 // It's only used by handleControllerNodeIPsChanged
93 protected HashMap<String, String> controllerNodeIPsCache; 59 protected HashMap<String, String> controllerNodeIPsCache;
94 60
95 - // Module dependencies
96 -
97 - protected IControllerRegistry registryService;
98 - protected IDebugCounterService debugCounters;
99 -
100 61
101 private IOFSwitchManager switchManager; 62 private IOFSwitchManager switchManager;
102 63
64 + private ChannelGroup cg;
65 +
103 // Configuration options 66 // Configuration options
104 protected int openFlowPort = 6633; 67 protected int openFlowPort = 6633;
105 protected int workerThreads = 0; 68 protected int workerThreads = 0;
106 69
107 - // defined counters
108 - private Counters counters;
109 -
110 // Start time of the controller 70 // Start time of the controller
111 protected long systemStartTime; 71 protected long systemStartTime;
112 72
113 // Flag to always flush flow table on switch reconnect (HA or otherwise) 73 // Flag to always flush flow table on switch reconnect (HA or otherwise)
114 protected boolean alwaysClearFlowsOnSwAdd = false; 74 protected boolean alwaysClearFlowsOnSwAdd = false;
115 - private InstanceId instanceId; 75 + private OpenFlowSwitchAgent agent;
116 76
117 // Perf. related configuration 77 // Perf. related configuration
118 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024; 78 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
119 protected static final int BATCH_MAX_SIZE = 100; 79 protected static final int BATCH_MAX_SIZE = 100;
120 protected static final boolean ALWAYS_DECODE_ETH = true; 80 protected static final boolean ALWAYS_DECODE_ETH = true;
121 81
122 - protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
123 - if (connectedSwitches.get(dpid) != null) {
124 - log.error("Trying to add connectedSwitch but found a previous "
125 - + "value for dpid: {}", dpid);
126 - return false;
127 - } else {
128 - log.error("Added switch {}", dpid);
129 - connectedSwitches.put(dpid, h);
130 - return true;
131 - }
132 - }
133 -
134 - private boolean validActivation(long dpid) {
135 - if (connectedSwitches.get(dpid) == null) {
136 - log.error("Trying to activate switch but is not in "
137 - + "connected switches: dpid {}. Aborting ..",
138 - HexString.toHexString(dpid));
139 - return false;
140 - }
141 - if (activeMasterSwitches.get(dpid) != null ||
142 - activeEqualSwitches.get(dpid) != null) {
143 - log.error("Trying to activate switch but it is already "
144 - + "activated: dpid {}. Found in activeMaster: {} "
145 - + "Found in activeEqual: {}. Aborting ..", new Object[] {
146 - HexString.toHexString(dpid),
147 - (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
148 - (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
149 - counters.switchWithSameDpidActivated.updateCounterWithFlush();
150 - return false;
151 - }
152 - return true;
153 - }
154 -
155 - /**
156 - * Called when a switch is activated, with this controller's role as MASTER.
157 - */
158 - protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
159 - synchronized (multiCacheLock) {
160 - if (!validActivation(dpid)) {
161 - return false;
162 - }
163 - activeMasterSwitches.put(dpid, sw);
164 - }
165 - //update counters and events
166 - counters.switchActivated.updateCounterWithFlush();
167 -
168 - return true;
169 - }
170 -
171 - /**
172 - * Called when a switch is activated, with this controller's role as EQUAL.
173 - */
174 - protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
175 - synchronized (multiCacheLock) {
176 - if (!validActivation(dpid)) {
177 - return false;
178 - }
179 - activeEqualSwitches.put(dpid, sw);
180 - }
181 - //update counters and events
182 - counters.switchActivated.updateCounterWithFlush();
183 - return true;
184 - }
185 -
186 - /**
187 - * Called when this controller's role for a switch transitions from equal
188 - * to master. For 1.0 switches, we internally refer to the role 'slave' as
189 - * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
190 - */
191 - protected void transitionToMasterSwitch(long dpid) {
192 - synchronized (multiCacheLock) {
193 - IOFSwitch sw = activeEqualSwitches.remove(dpid);
194 - if (sw == null) {
195 - log.error("Transition to master called on sw {}, but switch "
196 - + "was not found in controller-cache", dpid);
197 - return;
198 - }
199 - activeMasterSwitches.put(dpid, sw);
200 - }
201 - }
202 -
203 -
204 - /**
205 - * Called when this controller's role for a switch transitions to equal.
206 - * For 1.0 switches, we internally refer to the role 'slave' as
207 - * 'equal'.
208 - */
209 - protected void transitionToEqualSwitch(long dpid) {
210 - synchronized (multiCacheLock) {
211 - IOFSwitch sw = activeMasterSwitches.remove(dpid);
212 - if (sw == null) {
213 - log.error("Transition to equal called on sw {}, but switch "
214 - + "was not found in controller-cache", dpid);
215 - return;
216 - }
217 - activeEqualSwitches.put(dpid, sw);
218 - }
219 -
220 - }
221 -
222 - /**
223 - * Clear all state in controller switch maps for a switch that has
224 - * disconnected from the local controller. Also release control for
225 - * that switch from the global repository. Notify switch listeners.
226 - */
227 - protected void removeConnectedSwitch(long dpid) {
228 - releaseRegistryControl(dpid);
229 - connectedSwitches.remove(dpid);
230 - IOFSwitch sw = activeMasterSwitches.remove(dpid);
231 - if (sw == null) {
232 - sw = activeEqualSwitches.remove(dpid);
233 - }
234 - if (sw != null) {
235 - sw.cancelAllStatisticsReplies();
236 - sw.setConnected(false); // do we need this?
237 - }
238 - counters.switchDisconnected.updateCounterWithFlush();
239 -
240 - }
241 -
242 - /**
243 - * Indicates that ports on the given switch have changed. Enqueue a
244 - * switch update.
245 - * @param dpid
246 - * @param port
247 - * @param changeType
248 - */
249 - protected void notifyPortChanged(long dpid, OFPortDesc port,
250 - PortChangeType changeType) {
251 - if (port == null || changeType == null) {
252 - String msg = String.format("Switch port or changetType must not "
253 - + "be null in port change notification");
254 - throw new NullPointerException(msg);
255 - }
256 - if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
257 - log.warn("Port change update on switch {} not connected or activated "
258 - + "... Aborting.", HexString.toHexString(dpid));
259 - return;
260 - }
261 -
262 - }
263 -
264 // *************** 82 // ***************
265 // Getters/Setters 83 // Getters/Setters
266 // *************** 84 // ***************
...@@ -268,180 +86,8 @@ public class Controller { ...@@ -268,180 +86,8 @@ public class Controller {
268 86
269 public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) { 87 public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) {
270 this.switchManager = swManager; 88 this.switchManager = swManager;
271 - this.registryService = swManager.getRegistry();
272 } 89 }
273 90
274 -
275 - public void setDebugCounter(IDebugCounterService dcs) {
276 - this.debugCounters = dcs;
277 - }
278 -
279 - IDebugCounterService getDebugCounter() {
280 - return this.debugCounters;
281 - }
282 -
283 - // **********************
284 - // Role Handling
285 - // **********************
286 -
287 - /**
288 - * created by ONOS - works with registry service.
289 - */
290 - protected class RoleChangeCallback implements ControlChangeCallback {
291 - @Override
292 - public void controlChanged(long dpidLong, boolean hasControl) {
293 - Dpid dpid = new Dpid(dpidLong);
294 - log.info("Role change callback for switch {}, hasControl {}",
295 - dpid, hasControl);
296 -
297 - Role role = null;
298 -
299 - /*
300 - * issue #229
301 - * Cannot rely on sw.getRole() as it can be behind due to pending
302 - * role changes in the queue. Just submit it and late the
303 - * RoleChanger handle duplicates.
304 - */
305 -
306 - if (hasControl) {
307 - role = Role.MASTER;
308 - } else {
309 - role = Role.EQUAL; // treat the same as Role.SLAVE
310 - }
311 -
312 - OFChannelHandler swCh = connectedSwitches.get(dpid.value());
313 - if (swCh == null) {
314 - log.warn("Switch {} not found in connected switches", dpid);
315 - return;
316 - }
317 -
318 - log.debug("Sending role request {} msg to {}", role, dpid);
319 - swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
320 - }
321 - }
322 -
323 - /**
324 - * Submit request to the registry service for mastership of the
325 - * switch.
326 - * @param dpid this datapath to get role for
327 - */
328 - public synchronized void submitRegistryRequest(long dpid) {
329 - if (registryService == null) {
330 - /*
331 - * If we have no registry then simply assign
332 - * mastership to this controller.
333 - */
334 - new RoleChangeCallback().controlChanged(dpid, true);
335 - return;
336 - }
337 - OFChannelHandler h = connectedSwitches.get(dpid);
338 - if (h == null) {
339 - log.error("Trying to request registry control for switch {} "
340 - + "not in connected switches. Aborting.. ",
341 - HexString.toHexString(dpid));
342 - connectedSwitches.get(dpid).disconnectSwitch();
343 - return;
344 - }
345 - //Request control of the switch from the global registry
346 - try {
347 - h.controlRequested = Boolean.TRUE;
348 - registryService.requestControl(dpid, new RoleChangeCallback());
349 - } catch (RegistryException e) {
350 - log.debug("Registry error: {}", e.getMessage());
351 - h.controlRequested = Boolean.FALSE;
352 - }
353 - if (!h.controlRequested) { // XXX what is being attempted here?
354 - // yield to allow other thread(s) to release control
355 - // TODO AAS: this is awful and needs to be fixed
356 - Thread.yield();
357 - // safer to bounce the switch to reconnect here than proceeding further
358 - // XXX S why? can't we just try again a little later?
359 - log.debug("Closing sw:{} because we weren't able to request control " +
360 - "successfully" + dpid);
361 - connectedSwitches.get(dpid).disconnectSwitch();
362 - }
363 - }
364 -
365 - /**
366 - * Relinquish role for the switch.
367 - * @param dpidLong the controlled datapath
368 - */
369 - public synchronized void releaseRegistryControl(long dpidLong) {
370 - OFChannelHandler h = connectedSwitches.get(dpidLong);
371 - if (h == null) {
372 - log.error("Trying to release registry control for switch {} "
373 - + "not in connected switches. Aborting.. ",
374 - HexString.toHexString(dpidLong));
375 - return;
376 - }
377 - if (registryService != null && h.controlRequested) {
378 - //TODO the above is not good for testing need to change controlrequest to method call.
379 - registryService.releaseControl(dpidLong);
380 - }
381 - }
382 -
383 -
384 - // FIXME: remove this method
385 - public Map<Long, IOFSwitch> getSwitches() {
386 - return getMasterSwitches();
387 - }
388 -
389 - // FIXME: remove this method
390 - public Map<Long, IOFSwitch> getMasterSwitches() {
391 - return Collections.unmodifiableMap(activeMasterSwitches);
392 - }
393 -
394 -
395 -
396 - public Set<Long> getAllSwitchDpids() {
397 - Set<Long> dpids = new HashSet<Long>();
398 - dpids.addAll(activeMasterSwitches.keySet());
399 - dpids.addAll(activeEqualSwitches.keySet());
400 - return dpids;
401 - }
402 -
403 -
404 - public Set<Long> getAllMasterSwitchDpids() {
405 - Set<Long> dpids = new HashSet<Long>();
406 - dpids.addAll(activeMasterSwitches.keySet());
407 - return dpids;
408 - }
409 -
410 -
411 - public Set<Long> getAllEqualSwitchDpids() {
412 - Set<Long> dpids = new HashSet<Long>();
413 - dpids.addAll(activeEqualSwitches.keySet());
414 - return dpids;
415 - }
416 -
417 -
418 - public IOFSwitch getSwitch(long dpid) {
419 - IOFSwitch sw = null;
420 - sw = activeMasterSwitches.get(dpid);
421 - if (sw != null) {
422 - return sw;
423 - }
424 - sw = activeEqualSwitches.get(dpid);
425 - if (sw != null) {
426 - return sw;
427 - }
428 - return sw;
429 - }
430 -
431 -
432 - public IOFSwitch getMasterSwitch(long dpid) {
433 - return activeMasterSwitches.get(dpid);
434 - }
435 -
436 -
437 - public IOFSwitch getEqualSwitch(long dpid) {
438 - return activeEqualSwitches.get(dpid);
439 - }
440 -
441 -
442 -
443 -
444 -
445 public OFFactory getOFMessageFactory10() { 91 public OFFactory getOFMessageFactory10() {
446 return FACTORY10; 92 return FACTORY10;
447 } 93 }
...@@ -469,12 +115,6 @@ public class Controller { ...@@ -469,12 +115,6 @@ public class Controller {
469 return (this.systemStartTime); 115 return (this.systemStartTime);
470 } 116 }
471 117
472 -
473 - public InstanceId getInstanceId() {
474 - return instanceId;
475 - }
476 -
477 -
478 // ************** 118 // **************
479 // Initialization 119 // Initialization
480 // ************** 120 // **************
...@@ -509,7 +149,7 @@ public class Controller { ...@@ -509,7 +149,7 @@ public class Controller {
509 new OpenflowPipelineFactory(this, null); 149 new OpenflowPipelineFactory(this, null);
510 bootstrap.setPipelineFactory(pfact); 150 bootstrap.setPipelineFactory(pfact);
511 InetSocketAddress sa = new InetSocketAddress(openFlowPort); 151 InetSocketAddress sa = new InetSocketAddress(openFlowPort);
512 - final ChannelGroup cg = new DefaultChannelGroup(); 152 + cg = new DefaultChannelGroup();
513 cg.add(bootstrap.bind(sa)); 153 cg.add(bootstrap.bind(sa));
514 154
515 log.info("Listening for switch connections on {}", sa); 155 log.info("Listening for switch connections on {}", sa);
...@@ -544,20 +184,6 @@ public class Controller { ...@@ -544,20 +184,6 @@ public class Controller {
544 this.workerThreads = Integer.parseInt(threads); 184 this.workerThreads = Integer.parseInt(threads);
545 } 185 }
546 log.debug("Number of worker threads set to {}", this.workerThreads); 186 log.debug("Number of worker threads set to {}", this.workerThreads);
547 - String controllerId = configParams.get("controllerid");
548 - if (controllerId != null) {
549 - this.instanceId = new InstanceId(controllerId);
550 - } else {
551 - //Try to get the hostname of the machine and use that for controller ID
552 - try {
553 - String hostname = java.net.InetAddress.getLocalHost().getHostName();
554 - this.instanceId = new InstanceId(hostname);
555 - } catch (UnknownHostException e) {
556 - log.warn("Can't get hostname, using the default");
557 - }
558 - }
559 -
560 - log.debug("ControllerId set to {}", this.instanceId);
561 } 187 }
562 188
563 189
...@@ -567,16 +193,11 @@ public class Controller { ...@@ -567,16 +193,11 @@ public class Controller {
567 public void init(Map<String, String> configParams) { 193 public void init(Map<String, String> configParams) {
568 // These data structures are initialized here because other 194 // These data structures are initialized here because other
569 // module's startUp() might be called before ours 195 // module's startUp() might be called before ours
570 - this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
571 - this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
572 - this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
573 this.controllerNodeIPsCache = new HashMap<String, String>(); 196 this.controllerNodeIPsCache = new HashMap<String, String>();
574 197
575 setConfigParams(configParams); 198 setConfigParams(configParams);
576 this.systemStartTime = System.currentTimeMillis(); 199 this.systemStartTime = System.currentTimeMillis();
577 - this.setDebugCounter(new DebugCounter()); 200 +
578 - this.counters = new Counters();
579 - this.multiCacheLock = new Object();
580 201
581 } 202 }
582 203
...@@ -589,215 +210,10 @@ public class Controller { ...@@ -589,215 +210,10 @@ public class Controller {
589 "that the system database has failed to start. " + 210 "that the system database has failed to start. " +
590 LogMessageDoc.CHECK_CONTROLLER) 211 LogMessageDoc.CHECK_CONTROLLER)
591 public synchronized void startupComponents() { 212 public synchronized void startupComponents() {
592 - try { 213 + //TODO do something maybe
593 - if (registryService != null) {
594 - registryService.registerController(instanceId.toString());
595 - }
596 - } catch (RegistryException e) {
597 - log.warn("Registry service error: {}", e.getMessage());
598 - }
599 -
600 - // register counters and events
601 - try {
602 - this.counters.createCounters(debugCounters);
603 - } catch (CounterException e) {
604 - log.warn("Counters unavailable: {}", e.getMessage());
605 - }
606 } 214 }
607 215
608 // ************** 216 // **************
609 - // debugCounter registrations
610 - // **************
611 -
612 - public static class Counters {
613 - public static final String PREFIX = "controller";
614 - public IDebugCounter switchActivated;
615 - public IDebugCounter switchWithSameDpidActivated; // warn
616 - public IDebugCounter switchDisconnected;
617 - public IDebugCounter messageReceived;
618 - public IDebugCounter switchDisconnectReadTimeout;
619 - public IDebugCounter switchDisconnectHandshakeTimeout;
620 - public IDebugCounter switchDisconnectIOError;
621 - public IDebugCounter switchDisconnectParseError;
622 - public IDebugCounter switchDisconnectSwitchStateException;
623 - public IDebugCounter rejectedExecutionException;
624 - public IDebugCounter switchDisconnectOtherException;
625 - public IDebugCounter switchConnected;
626 - public IDebugCounter unhandledMessage;
627 - public IDebugCounter packetInWhileSwitchIsSlave;
628 - public IDebugCounter epermErrorWhileSwitchIsMaster;
629 - public IDebugCounter roleReplyTimeout;
630 - public IDebugCounter roleReplyReceived; // expected RoleReply received
631 - public IDebugCounter roleReplyErrorUnsupported;
632 - public IDebugCounter switchCounterRegistrationFailed;
633 -
634 - void createCounters(IDebugCounterService debugCounters) throws CounterException {
635 -
636 - switchActivated =
637 - debugCounters.registerCounter(
638 - PREFIX, "switch-activated",
639 - "A switch connected to this controller is now " +
640 - "in MASTER role",
641 - CounterType.ALWAYS_COUNT);
642 -
643 - switchWithSameDpidActivated = // warn
644 - debugCounters.registerCounter(
645 - PREFIX, "switch-with-same-dpid-activated",
646 - "A switch with the same DPID as another switch " +
647 - "connected to the controller. This can be " +
648 - "caused by multiple switches configured with " +
649 - "the same DPID or by a switch reconnecting very " +
650 - "quickly.",
651 - CounterType.COUNT_ON_DEMAND,
652 - IDebugCounterService.CTR_MDATA_WARN);
653 -
654 - switchDisconnected =
655 - debugCounters.registerCounter(
656 - PREFIX, "switch-disconnected",
657 - "FIXME: switch has disconnected",
658 - CounterType.ALWAYS_COUNT);
659 -
660 - //------------------------
661 - // channel handler counters. Factor them out ??
662 - messageReceived =
663 - debugCounters.registerCounter(
664 - PREFIX, "message-received",
665 - "Number of OpenFlow messages received. Some of " +
666 - "these might be throttled",
667 - CounterType.ALWAYS_COUNT);
668 -
669 - switchDisconnectReadTimeout =
670 - debugCounters.registerCounter(
671 - PREFIX, "switch-disconnect-read-timeout",
672 - "Number of times a switch was disconnected due " +
673 - "due the switch failing to send OpenFlow " +
674 - "messages or responding to OpenFlow ECHOs",
675 - CounterType.ALWAYS_COUNT,
676 - IDebugCounterService.CTR_MDATA_ERROR);
677 - switchDisconnectHandshakeTimeout =
678 - debugCounters.registerCounter(
679 - PREFIX, "switch-disconnect-handshake-timeout",
680 - "Number of times a switch was disconnected " +
681 - "because it failed to complete the handshake " +
682 - "in time.",
683 - CounterType.ALWAYS_COUNT,
684 - IDebugCounterService.CTR_MDATA_ERROR);
685 - switchDisconnectIOError =
686 - debugCounters.registerCounter(
687 - PREFIX, "switch-disconnect-io-error",
688 - "Number of times a switch was disconnected " +
689 - "due to IO errors on the switch connection.",
690 - CounterType.ALWAYS_COUNT,
691 - IDebugCounterService.CTR_MDATA_ERROR);
692 - switchDisconnectParseError =
693 - debugCounters.registerCounter(
694 - PREFIX, "switch-disconnect-parse-error",
695 - "Number of times a switch was disconnected " +
696 - "because it sent an invalid packet that could " +
697 - "not be parsed",
698 - CounterType.ALWAYS_COUNT,
699 - IDebugCounterService.CTR_MDATA_ERROR);
700 -
701 - switchDisconnectSwitchStateException =
702 - debugCounters.registerCounter(
703 - PREFIX, "switch-disconnect-switch-state-exception",
704 - "Number of times a switch was disconnected " +
705 - "because it sent messages that were invalid " +
706 - "given the switch connection's state.",
707 - CounterType.ALWAYS_COUNT,
708 - IDebugCounterService.CTR_MDATA_ERROR);
709 - rejectedExecutionException =
710 - debugCounters.registerCounter(
711 - PREFIX, "rejected-execution-exception",
712 - "TODO",
713 - CounterType.ALWAYS_COUNT,
714 - IDebugCounterService.CTR_MDATA_ERROR);
715 -
716 - switchDisconnectOtherException =
717 - debugCounters.registerCounter(
718 - PREFIX, "switch-disconnect-other-exception",
719 - "Number of times a switch was disconnected " +
720 - "due to an exceptional situation not covered " +
721 - "by other counters",
722 - CounterType.ALWAYS_COUNT,
723 - IDebugCounterService.CTR_MDATA_ERROR);
724 -
725 - switchConnected =
726 - debugCounters.registerCounter(
727 - PREFIX, "switch-connected",
728 - "Number of times a new switch connection was " +
729 - "established",
730 - CounterType.ALWAYS_COUNT);
731 -
732 - unhandledMessage =
733 - debugCounters.registerCounter(
734 - PREFIX, "unhandled-message",
735 - "Number of times an OpenFlow message was " +
736 - "received that the controller ignored because " +
737 - "it was inapproriate given the switch " +
738 - "connection's state.",
739 - CounterType.ALWAYS_COUNT,
740 - IDebugCounterService.CTR_MDATA_WARN);
741 - // might be less than warning
742 -
743 - packetInWhileSwitchIsSlave =
744 - debugCounters.registerCounter(
745 - PREFIX, "packet-in-while-switch-is-slave",
746 - "Number of times a packet in was received " +
747 - "from a switch that was in SLAVE role. " +
748 - "Possibly inidicates inconsistent roles.",
749 - CounterType.ALWAYS_COUNT);
750 - epermErrorWhileSwitchIsMaster =
751 - debugCounters.registerCounter(
752 - PREFIX, "eperm-error-while-switch-is-master",
753 - "Number of times a permission error was " +
754 - "received while the switch was in MASTER role. " +
755 - "Possibly inidicates inconsistent roles.",
756 - CounterType.ALWAYS_COUNT,
757 - IDebugCounterService.CTR_MDATA_WARN);
758 -
759 - roleReplyTimeout =
760 - debugCounters.registerCounter(
761 - PREFIX, "role-reply-timeout",
762 - "Number of times a role request message did not " +
763 - "receive the expected reply from a switch",
764 - CounterType.ALWAYS_COUNT,
765 - IDebugCounterService.CTR_MDATA_WARN);
766 -
767 - roleReplyReceived = // expected RoleReply received
768 - debugCounters.registerCounter(
769 - PREFIX, "role-reply-received",
770 - "Number of times the controller received the " +
771 - "expected role reply message from a switch",
772 - CounterType.ALWAYS_COUNT);
773 -
774 - roleReplyErrorUnsupported =
775 - debugCounters.registerCounter(
776 - PREFIX, "role-reply-error-unsupported",
777 - "Number of times the controller received an " +
778 - "error from a switch in response to a role " +
779 - "request indicating that the switch does not " +
780 - "support roles.",
781 - CounterType.ALWAYS_COUNT);
782 -
783 - switchCounterRegistrationFailed =
784 - debugCounters.registerCounter(PREFIX,
785 - "switch-counter-registration-failed",
786 - "Number of times the controller failed to " +
787 - "register per-switch debug counters",
788 - CounterType.ALWAYS_COUNT,
789 - IDebugCounterService.CTR_MDATA_WARN);
790 -
791 -
792 - }
793 - }
794 -
795 - public Counters getCounters() {
796 - return this.counters;
797 - }
798 -
799 -
800 - // **************
801 // Utility methods 217 // Utility methods
802 // ************** 218 // **************
803 219
...@@ -820,20 +236,24 @@ public class Controller { ...@@ -820,20 +236,24 @@ public class Controller {
820 * @param desc 236 * @param desc
821 * @return switch instance 237 * @return switch instance
822 */ 238 */
823 - protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) { 239 + protected AbstractOpenFlowSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
824 - if (switchManager == null) { 240 + AbstractOpenFlowSwitch sw = switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
825 - return new DummySwitchForTesting();
826 - }
827 - return switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
828 desc.getSwDesc(), ofv); 241 desc.getSwDesc(), ofv);
242 + sw.setAgent(agent);
243 + return sw;
829 } 244 }
830 245
831 - @Activate 246 + public void start(OpenFlowSwitchAgent ag) {
832 - public void activate() {
833 log.info("Initialising OpenFlow Lib and IO"); 247 log.info("Initialising OpenFlow Lib and IO");
248 + this.agent = ag;
834 this.init(new HashMap<String, String>()); 249 this.init(new HashMap<String, String>());
835 this.startupComponents(); 250 this.startupComponents();
836 this.run(); 251 this.run();
837 } 252 }
838 253
254 +
255 + public void stop() {
256 + cg.close();
257 + }
258 +
839 } 259 }
......
1 -package org.onlab.onos.of.controller.impl; 1 +package org.onlab.onos.of.controller.impl.internal;
2 2
3 import org.projectfloodlight.openflow.protocol.OFVersion; 3 import org.projectfloodlight.openflow.protocol.OFVersion;
4 4
5 -import org.onlab.onos.of.controller.impl.registry.IControllerRegistry;
6 5
7 /** 6 /**
8 * Interface to passed to controller class in order to allow 7 * Interface to passed to controller class in order to allow
...@@ -22,12 +21,6 @@ public interface IOFSwitchManager { ...@@ -22,12 +21,6 @@ public interface IOFSwitchManager {
22 * @param ofv openflow version 21 * @param ofv openflow version
23 * @return A switch of type IOFSwitch. 22 * @return A switch of type IOFSwitch.
24 */ 23 */
25 - public IOFSwitch getSwitchImpl(String mfr, String hwDesc, String swDesc, OFVersion ofv); 24 + public AbstractOpenFlowSwitch getSwitchImpl(String mfr, String hwDesc, String swDesc, OFVersion ofv);
26 -
27 - /**
28 - * Returns the mastership registry used during controller-switch role election.
29 - * @return the registry
30 - */
31 - public IControllerRegistry getRegistry();
32 25
33 } 26 }
......
...@@ -4,21 +4,11 @@ package org.onlab.onos.of.controller.impl.internal; ...@@ -4,21 +4,11 @@ package org.onlab.onos.of.controller.impl.internal;
4 import java.io.IOException; 4 import java.io.IOException;
5 import java.nio.channels.ClosedChannelException; 5 import java.nio.channels.ClosedChannelException;
6 import java.util.ArrayList; 6 import java.util.ArrayList;
7 -import java.util.Collection;
8 import java.util.Collections; 7 import java.util.Collections;
9 import java.util.List; 8 import java.util.List;
10 import java.util.concurrent.CopyOnWriteArrayList; 9 import java.util.concurrent.CopyOnWriteArrayList;
11 import java.util.concurrent.RejectedExecutionException; 10 import java.util.concurrent.RejectedExecutionException;
12 11
13 -import org.onlab.onos.of.controller.impl.IOFSwitch;
14 -import org.onlab.onos.of.controller.impl.IOFSwitch.PortChangeEvent;
15 -import org.onlab.onos.of.controller.impl.Role;
16 -import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
17 -import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
18 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
19 -import org.onlab.onos.of.controller.impl.internal.Controller.Counters;
20 -import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.ChannelState.RoleReplyInfo;
21 -
22 import org.jboss.netty.channel.Channel; 12 import org.jboss.netty.channel.Channel;
23 import org.jboss.netty.channel.ChannelHandlerContext; 13 import org.jboss.netty.channel.ChannelHandlerContext;
24 import org.jboss.netty.channel.ChannelStateEvent; 14 import org.jboss.netty.channel.ChannelStateEvent;
...@@ -27,12 +17,14 @@ import org.jboss.netty.channel.MessageEvent; ...@@ -27,12 +17,14 @@ import org.jboss.netty.channel.MessageEvent;
27 import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler; 17 import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
28 import org.jboss.netty.handler.timeout.IdleStateEvent; 18 import org.jboss.netty.handler.timeout.IdleStateEvent;
29 import org.jboss.netty.handler.timeout.ReadTimeoutException; 19 import org.jboss.netty.handler.timeout.ReadTimeoutException;
20 +import org.onlab.onos.of.controller.RoleState;
21 +import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
22 +import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
30 import org.projectfloodlight.openflow.exceptions.OFParseError; 23 import org.projectfloodlight.openflow.exceptions.OFParseError;
31 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply; 24 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
32 import org.projectfloodlight.openflow.protocol.OFBadRequestCode; 25 import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
33 import org.projectfloodlight.openflow.protocol.OFBarrierReply; 26 import org.projectfloodlight.openflow.protocol.OFBarrierReply;
34 import org.projectfloodlight.openflow.protocol.OFBarrierRequest; 27 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
35 -import org.projectfloodlight.openflow.protocol.OFControllerRole;
36 import org.projectfloodlight.openflow.protocol.OFDescStatsReply; 28 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
37 import org.projectfloodlight.openflow.protocol.OFDescStatsRequest; 29 import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
38 import org.projectfloodlight.openflow.protocol.OFEchoReply; 30 import org.projectfloodlight.openflow.protocol.OFEchoReply;
...@@ -49,15 +41,12 @@ import org.projectfloodlight.openflow.protocol.OFGetConfigRequest; ...@@ -49,15 +41,12 @@ import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
49 import org.projectfloodlight.openflow.protocol.OFHello; 41 import org.projectfloodlight.openflow.protocol.OFHello;
50 import org.projectfloodlight.openflow.protocol.OFHelloElem; 42 import org.projectfloodlight.openflow.protocol.OFHelloElem;
51 import org.projectfloodlight.openflow.protocol.OFMessage; 43 import org.projectfloodlight.openflow.protocol.OFMessage;
52 -import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
53 -import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
54 import org.projectfloodlight.openflow.protocol.OFPacketIn; 44 import org.projectfloodlight.openflow.protocol.OFPacketIn;
55 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; 45 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
56 import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest; 46 import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
57 import org.projectfloodlight.openflow.protocol.OFPortStatus; 47 import org.projectfloodlight.openflow.protocol.OFPortStatus;
58 import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply; 48 import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
59 import org.projectfloodlight.openflow.protocol.OFRoleReply; 49 import org.projectfloodlight.openflow.protocol.OFRoleReply;
60 -import org.projectfloodlight.openflow.protocol.OFRoleRequest;
61 import org.projectfloodlight.openflow.protocol.OFSetConfig; 50 import org.projectfloodlight.openflow.protocol.OFSetConfig;
62 import org.projectfloodlight.openflow.protocol.OFStatsReply; 51 import org.projectfloodlight.openflow.protocol.OFStatsReply;
63 import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags; 52 import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
...@@ -66,11 +55,10 @@ import org.projectfloodlight.openflow.protocol.OFType; ...@@ -66,11 +55,10 @@ import org.projectfloodlight.openflow.protocol.OFType;
66 import org.projectfloodlight.openflow.protocol.OFVersion; 55 import org.projectfloodlight.openflow.protocol.OFVersion;
67 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; 56 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
68 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; 57 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
69 -import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
70 import org.projectfloodlight.openflow.types.U32; 58 import org.projectfloodlight.openflow.types.U32;
71 -import org.projectfloodlight.openflow.types.U64;
72 import org.slf4j.Logger; 59 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory; 60 import org.slf4j.LoggerFactory;
61 +
74 /** 62 /**
75 * Channel handler deals with the switch connection and dispatches 63 * Channel handler deals with the switch connection and dispatches
76 * switch messages to the appropriate locations. 64 * switch messages to the appropriate locations.
...@@ -79,18 +67,13 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -79,18 +67,13 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
79 private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class); 67 private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
80 private static final long DEFAULT_ROLE_TIMEOUT_MS = 2 * 1000; // 10 sec 68 private static final long DEFAULT_ROLE_TIMEOUT_MS = 2 * 1000; // 10 sec
81 private final Controller controller; 69 private final Controller controller;
82 - private final Counters counters; 70 + private AbstractOpenFlowSwitch sw;
83 - private IOFSwitch sw;
84 private long thisdpid; // channelHandler cached value of connected switch id 71 private long thisdpid; // channelHandler cached value of connected switch id
85 private Channel channel; 72 private Channel channel;
86 // State needs to be volatile because the HandshakeTimeoutHandler 73 // State needs to be volatile because the HandshakeTimeoutHandler
87 // needs to check if the handshake is complete 74 // needs to check if the handshake is complete
88 private volatile ChannelState state; 75 private volatile ChannelState state;
89 76
90 - // All role messaging is handled by the roleChanger. The channel state machine
91 - // coordinates between the roleChanger and the controller-global-registry-service
92 - // to determine controller roles per switch.
93 - private RoleChanger roleChanger;
94 // Used to coordinate between the controller and the cleanup thread(?) 77 // Used to coordinate between the controller and the cleanup thread(?)
95 // for access to the global registry on a per switch basis. 78 // for access to the global registry on a per switch basis.
96 volatile Boolean controlRequested; 79 volatile Boolean controlRequested;
...@@ -125,8 +108,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -125,8 +108,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
125 */ 108 */
126 OFChannelHandler(Controller controller) { 109 OFChannelHandler(Controller controller) {
127 this.controller = controller; 110 this.controller = controller;
128 - this.counters = controller.getCounters();
129 - this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
130 this.state = ChannelState.INIT; 111 this.state = ChannelState.INIT;
131 this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>(); 112 this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
132 factory13 = controller.getOFMessageFactory13(); 113 factory13 = controller.getOFMessageFactory13();
...@@ -135,392 +116,14 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -135,392 +116,14 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
135 duplicateDpidFound = Boolean.FALSE; 116 duplicateDpidFound = Boolean.FALSE;
136 } 117 }
137 118
138 - //*******************
139 - // Role Handling
140 - //*******************
141 119
142 - /**
143 - * When we remove a pending role request we use this enum to indicate how we
144 - * arrived at the decision. When we send a role request to the switch, we
145 - * also use this enum to indicate what we expect back from the switch, so the
146 - * role changer can match the reply to our expectation.
147 - */
148 - public enum RoleRecvStatus {
149 - /** The switch returned an error indicating that roles are not.
150 - * supported*/
151 - UNSUPPORTED,
152 - /** The request timed out. */
153 - NO_REPLY,
154 - /** The reply was old, there is a newer request pending. */
155 - OLD_REPLY,
156 - /**
157 - * The reply's role matched the role that this controller set in the
158 - * request message - invoked either initially at startup or to reassert
159 - * current role.
160 - */
161 - MATCHED_CURRENT_ROLE,
162 - /**
163 - * The reply's role matched the role that this controller set in the
164 - * request message - this is the result of a callback from the
165 - * global registry, followed by a role request sent to the switch.
166 - */
167 - MATCHED_SET_ROLE,
168 - /**
169 - * The reply's role was a response to the query made by this controller.
170 - */
171 - REPLY_QUERY,
172 - /** We received a role reply message from the switch
173 - * but the expectation was unclear, or there was no expectation.
174 - */
175 - OTHER_EXPECTATION,
176 - }
177 -
178 - /**
179 - * Forwards to RoleChanger. See there.
180 - * @param role
181 - */
182 - public void sendRoleRequest(Role role, RoleRecvStatus expectation) {
183 - try {
184 - roleChanger.sendRoleRequest(role, expectation);
185 - } catch (IOException e) {
186 - log.error("Disconnecting switch {} due to IO Error: {}",
187 - getSwitchInfoString(), e.getMessage());
188 - channel.close();
189 - }
190 - }
191 120
192 // XXX S consider if necessary 121 // XXX S consider if necessary
193 public void disconnectSwitch() { 122 public void disconnectSwitch() {
194 sw.disconnectSwitch(); 123 sw.disconnectSwitch();
195 } 124 }
196 125
197 - /**
198 - * A utility class to handle role requests and replies for this channel.
199 - * After a role request is submitted the role changer keeps track of the
200 - * pending request, collects the reply (if any) and times out the request
201 - * if necessary.
202 - *
203 - * To simplify role handling we only keep track of the /last/ pending
204 - * role reply send to the switch. If multiple requests are pending and
205 - * we receive replies for earlier requests we ignore them. However, this
206 - * way of handling pending requests implies that we could wait forever if
207 - * a new request is submitted before the timeout triggers. If necessary
208 - * we could work around that though.
209 - */
210 - private class RoleChanger {
211 - // indicates that a request is currently pending
212 - // needs to be volatile to allow correct double-check idiom
213 - private volatile boolean requestPending;
214 - // the transaction Id of the pending request
215 - private int pendingXid;
216 - // the role that's pending
217 - private Role pendingRole;
218 - // system time in MS when we send the request
219 - private long roleSubmitTime;
220 - // the timeout to use
221 - private final long roleTimeoutMs;
222 - // the expectation set by the caller for the returned role
223 - private RoleRecvStatus expectation;
224 -
225 - public RoleChanger(long roleTimeoutMs) {
226 - this.requestPending = false;
227 - this.roleSubmitTime = 0;
228 - this.pendingXid = -1;
229 - this.pendingRole = null;
230 - this.roleTimeoutMs = roleTimeoutMs;
231 - this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
232 - }
233 -
234 - /**
235 - * Send NX role request message to the switch requesting the specified
236 - * role.
237 - *
238 - * @param sw switch to send the role request message to
239 - * @param role role to request
240 - */
241 - private int sendNxRoleRequest(Role role) throws IOException {
242 - // Convert the role enum to the appropriate role to send
243 - OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
244 - switch (role) {
245 - case MASTER:
246 - roleToSend = OFNiciraControllerRole.ROLE_MASTER;
247 - break;
248 - case SLAVE:
249 - case EQUAL:
250 - default:
251 - // ensuring that the only two roles sent to 1.0 switches with
252 - // Nicira role support, are MASTER and SLAVE
253 - roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
254 - log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
255 - }
256 - int xid = sw.getNextTransactionId();
257 - OFExperimenter roleRequest = factory10
258 - .buildNiciraControllerRoleRequest()
259 - .setXid(xid)
260 - .setRole(roleToSend)
261 - .build();
262 - sw.write(Collections.<OFMessage>singletonList(roleRequest));
263 - return xid;
264 - }
265 -
266 - private int sendOF13RoleRequest(Role role) throws IOException {
267 - // Convert the role enum to the appropriate role to send
268 - OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
269 - switch (role) {
270 - case EQUAL:
271 - roleToSend = OFControllerRole.ROLE_EQUAL;
272 - break;
273 - case MASTER:
274 - roleToSend = OFControllerRole.ROLE_MASTER;
275 - break;
276 - case SLAVE:
277 - roleToSend = OFControllerRole.ROLE_SLAVE;
278 - break;
279 - default:
280 - log.warn("Sending default role.noChange to switch {}."
281 - + " Should only be used for queries.", sw);
282 - }
283 126
284 - int xid = sw.getNextTransactionId();
285 - OFRoleRequest rrm = factory13
286 - .buildRoleRequest()
287 - .setRole(roleToSend)
288 - .setXid(xid)
289 - .setGenerationId(sw.getNextGenerationId())
290 - .build();
291 - sw.write(rrm);
292 - return xid;
293 - }
294 -
295 - /**
296 - * Send a role request with the given role to the switch and update
297 - * the pending request and timestamp.
298 - * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
299 - * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
300 - * in the IOFSwitch driver. If not supported, this method sends nothing
301 - * and returns 'false'. The caller should take appropriate action.
302 - *
303 - * One other optimization we do here is that for OF1.0 switches with
304 - * Nicira role message support, we force the Role.EQUAL to become
305 - * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
306 - * We cannot expect it to behave like SLAVE. We don't have this problem with
307 - * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
308 - * SLAVE behavior by using ASYNC messages.
309 - *
310 - * @param role
311 - * @throws IOException
312 - * @returns false if and only if the switch does not support role-request
313 - * messages, according to the switch driver; true otherwise.
314 - */
315 - synchronized boolean sendRoleRequest(Role role, RoleRecvStatus exp)
316 - throws IOException {
317 - this.expectation = exp;
318 -
319 - if (ofVersion == OFVersion.OF_10) {
320 - Boolean supportsNxRole = (Boolean)
321 - sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
322 - if (!supportsNxRole) {
323 - log.debug("Switch driver indicates no support for Nicira "
324 - + "role request messages. Not sending ...");
325 - state.handleUnsentRoleMessage(OFChannelHandler.this, role,
326 - expectation);
327 - return false;
328 - }
329 - // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
330 - // make Role.EQUAL become Role.SLAVE
331 - role = (role == Role.EQUAL) ? Role.SLAVE : role;
332 - pendingXid = sendNxRoleRequest(role);
333 - pendingRole = role;
334 - roleSubmitTime = System.currentTimeMillis();
335 - requestPending = true;
336 - } else {
337 - // OF1.3 switch, use OFPT_ROLE_REQUEST message
338 - pendingXid = sendOF13RoleRequest(role);
339 - pendingRole = role;
340 - roleSubmitTime = System.currentTimeMillis();
341 - requestPending = true;
342 - }
343 - return true;
344 - }
345 -
346 - /**
347 - * Deliver a received role reply.
348 - *
349 - * Check if a request is pending and if the received reply matches the
350 - * the expected pending reply (we check both role and xid) we set
351 - * the role for the switch/channel.
352 - *
353 - * If a request is pending but doesn't match the reply we ignore it, and
354 - * return
355 - *
356 - * If no request is pending we disconnect with a SwitchStateException
357 - *
358 - * @param RoleReplyInfo information about role-reply in format that
359 - * controller can understand.
360 - * @throws SwitchStateException if no request is pending
361 - */
362 - synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
363 - throws SwitchStateException {
364 - if (!requestPending) {
365 - Role currentRole = (sw != null) ? sw.getRole() : null;
366 - if (currentRole != null) {
367 - if (currentRole == rri.getRole()) {
368 - // Don't disconnect if the role reply we received is
369 - // for the same role we are already in.
370 - log.debug("Received unexpected RoleReply from "
371 - + "Switch: {} in State: {}. "
372 - + "Role in reply is same as current role of this "
373 - + "controller for this sw. Ignoring ...",
374 - getSwitchInfoString(), state.toString());
375 - return RoleRecvStatus.OTHER_EXPECTATION;
376 - } else {
377 - String msg = String.format("Switch: [%s], State: [%s], "
378 - + "received unexpected RoleReply[%s]. "
379 - + "No roles are pending, and this controller's "
380 - + "current role:[%s] does not match reply. "
381 - + "Disconnecting switch ... ",
382 - OFChannelHandler.this.getSwitchInfoString(),
383 - OFChannelHandler.this.state.toString(),
384 - rri, currentRole);
385 - throw new SwitchStateException(msg);
386 - }
387 - }
388 - log.debug("Received unexpected RoleReply {} from "
389 - + "Switch: {} in State: {}. "
390 - + "This controller has no current role for this sw. "
391 - + "Ignoring ...", new Object[] {rri,
392 - getSwitchInfoString(), state});
393 - return RoleRecvStatus.OTHER_EXPECTATION;
394 - }
395 -
396 - int xid = (int) rri.getXid();
397 - Role role = rri.getRole();
398 - // XXX S should check generation id meaningfully and other cases of expectations
399 - // U64 genId = rri.getGenId();
400 -
401 - if (pendingXid != xid) {
402 - log.debug("Received older role reply from " +
403 - "switch {} ({}). Ignoring. " +
404 - "Waiting for {}, xid={}",
405 - new Object[] {getSwitchInfoString(), rri,
406 - pendingRole, pendingXid });
407 - return RoleRecvStatus.OLD_REPLY;
408 - }
409 -
410 - if (pendingRole == role) {
411 - log.debug("Received role reply message from {} that matched "
412 - + "expected role-reply {} with expectations {}",
413 - new Object[] {getSwitchInfoString(), role, expectation});
414 - counters.roleReplyReceived.updateCounterWithFlush();
415 - //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
416 - if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
417 - expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
418 - return expectation;
419 - } else {
420 - return RoleRecvStatus.OTHER_EXPECTATION;
421 - }
422 - }
423 -
424 - // if xids match but role's don't, perhaps its a query (OF1.3)
425 - if (expectation == RoleRecvStatus.REPLY_QUERY) {
426 - return expectation;
427 - }
428 -
429 - return RoleRecvStatus.OTHER_EXPECTATION;
430 - }
431 -
432 - /**
433 - * Called if we receive an error message. If the xid matches the
434 - * pending request we handle it otherwise we ignore it.
435 - *
436 - * Note: since we only keep the last pending request we might get
437 - * error messages for earlier role requests that we won't be able
438 - * to handle
439 - */
440 - synchronized RoleRecvStatus deliverError(OFErrorMsg error)
441 - throws SwitchStateException {
442 - if (!requestPending) {
443 - log.debug("Received an error msg from sw {}, but no pending "
444 - + "requests in role-changer; not handling ...",
445 - getSwitchInfoString());
446 - return RoleRecvStatus.OTHER_EXPECTATION;
447 - }
448 - if (pendingXid != error.getXid()) {
449 - if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
450 - log.debug("Received an error msg from sw {} for a role request,"
451 - + " but not for pending request in role-changer; "
452 - + " ignoring error {} ...",
453 - getSwitchInfoString(), error);
454 - }
455 - return RoleRecvStatus.OTHER_EXPECTATION;
456 - }
457 - // it is an error related to a currently pending role request message
458 - if (error.getErrType() == OFErrorType.BAD_REQUEST) {
459 - counters.roleReplyErrorUnsupported.updateCounterWithFlush();
460 - log.error("Received a error msg {} from sw {} in state {} for "
461 - + "pending role request {}. Switch driver indicates "
462 - + "role-messaging is supported. Possible issues in "
463 - + "switch driver configuration?", new Object[] {
464 - ((OFBadRequestErrorMsg) error).toString(),
465 - getSwitchInfoString(), state, pendingRole
466 - });
467 - return RoleRecvStatus.UNSUPPORTED;
468 - }
469 -
470 - if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
471 - OFRoleRequestFailedErrorMsg rrerr =
472 - (OFRoleRequestFailedErrorMsg) error;
473 - switch (rrerr.getCode()) {
474 - case BAD_ROLE:
475 - // switch says that current-role-req has bad role?
476 - // for now we disconnect
477 - // fall-thru
478 - case STALE:
479 - // switch says that current-role-req has stale gen-id?
480 - // for now we disconnect
481 - // fall-thru
482 - case UNSUP:
483 - // switch says that current-role-req has role that
484 - // cannot be supported? for now we disconnect
485 - String msgx = String.format("Switch: [%s], State: [%s], "
486 - + "received Error to for pending role request [%s]. "
487 - + "Error:[%s]. Disconnecting switch ... ",
488 - OFChannelHandler.this.getSwitchInfoString(),
489 - OFChannelHandler.this.state.toString(),
490 - pendingRole, rrerr);
491 - throw new SwitchStateException(msgx);
492 - default:
493 - break;
494 - }
495 - }
496 -
497 - // This error message was for a role request message but we dont know
498 - // how to handle errors for nicira role request messages
499 - return RoleRecvStatus.OTHER_EXPECTATION;
500 - }
501 -
502 - /**
503 - * Check if a pending role request has timed out.
504 - */
505 - void checkTimeout() {
506 - if (!requestPending) {
507 - return;
508 - }
509 - synchronized (this) {
510 - if (!requestPending) {
511 - return;
512 - }
513 - long now = System.currentTimeMillis();
514 - if (now - roleSubmitTime > roleTimeoutMs) {
515 - // timeout triggered.
516 - counters.roleReplyTimeout.updateCounterWithFlush();
517 - //setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
518 - // XXX S come back to this
519 - }
520 - }
521 - }
522 -
523 - }
524 127
525 //************************* 128 //*************************
526 // Channel State Machine 129 // Channel State Machine
...@@ -628,8 +231,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -628,8 +231,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
628 log.info("Received features reply for switch at {} with dpid {}", 231 log.info("Received features reply for switch at {} with dpid {}",
629 h.getSwitchInfoString(), h.thisdpid); 232 h.getSwitchInfoString(), h.thisdpid);
630 //update the controller about this connected switch 233 //update the controller about this connected switch
631 - boolean success = h.controller.addConnectedSwitch( 234 + boolean success = h.sw.addConnectedSwitch();
632 - h.thisdpid, h);
633 if (!success) { 235 if (!success) {
634 disconnectDuplicate(h); 236 disconnectDuplicate(h);
635 return; 237 return;
...@@ -825,41 +427,16 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -825,41 +427,16 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
825 h.sw.setConnected(true); 427 h.sw.setConnected(true);
826 h.sw.setChannel(h.channel); 428 h.sw.setChannel(h.channel);
827 429
828 - try {
829 - h.sw.setDebugCounterService(h.controller.getDebugCounter());
830 - } catch (CounterException e) {
831 - h.counters.switchCounterRegistrationFailed
832 - .updateCounterNoFlush();
833 - log.warn("Could not register counters for switch {} ",
834 - h.getSwitchInfoString(), e);
835 - }
836 430
837 log.info("Switch {} bound to class {}, description {}", 431 log.info("Switch {} bound to class {}, description {}",
838 new Object[] {h.sw, h.sw.getClass(), drep }); 432 new Object[] {h.sw, h.sw.getClass(), drep });
839 //Put switch in EQUAL mode until we hear back from the global registry 433 //Put switch in EQUAL mode until we hear back from the global registry
840 log.debug("Setting new switch {} to EQUAL and sending Role request", 434 log.debug("Setting new switch {} to EQUAL and sending Role request",
841 h.sw.getStringId()); 435 h.sw.getStringId());
842 - h.setSwitchRole(Role.EQUAL); 436 + h.setSwitchRole(RoleState.EQUAL);
843 - try { 437 + h.sw.startDriverHandshake();
844 - boolean supportsRRMsg = h.roleChanger.sendRoleRequest(Role.EQUAL, 438 + h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
845 - RoleRecvStatus.MATCHED_CURRENT_ROLE); 439 +
846 - if (!supportsRRMsg) {
847 - log.warn("Switch {} does not support role request messages "
848 - + "of any kind. No role messages were sent. "
849 - + "This controller instance SHOULD become MASTER "
850 - + "from the registry process. ",
851 - h.getSwitchInfoString());
852 - }
853 - h.setState(WAIT_INITIAL_ROLE);
854 - // request control of switch from global registry -
855 - // necessary even if this is the only controller the
856 - // switch is connected to.
857 - h.controller.submitRegistryRequest(h.sw.getId());
858 - } catch (IOException e) {
859 - log.error("Exception when sending role request: {} ",
860 - e.getMessage());
861 - // FIXME shouldn't we disconnect?
862 - }
863 } 440 }
864 441
865 @Override 442 @Override
...@@ -880,133 +457,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -880,133 +457,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
880 } 457 }
881 }, 458 },
882 459
883 - /**
884 - * We are waiting for a role reply message in response to a role request
885 - * sent after hearing back from the registry service -- OR -- we are
886 - * just waiting to hear back from the registry service in the case that
887 - * the switch does not support role messages. If completed successfully,
888 - * the controller's role for this switch will be set here.
889 - * Before we move to the state corresponding to the role, we allow the
890 - * switch specific driver to complete its configuration. This configuration
891 - * typically depends on the role the controller is playing for this switch.
892 - * And so we set the switch role (for 'this' controller) before we start
893 - * the driver-sub-handshake.
894 - * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
895 - */
896 - WAIT_INITIAL_ROLE(false) {
897 - @Override
898 - void processOFError(OFChannelHandler h, OFErrorMsg m)
899 - throws SwitchStateException {
900 - // role changer will ignore the error if it isn't for it
901 - RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
902 - if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
903 - logError(h, m);
904 - }
905 - }
906 -
907 - @Override
908 - void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
909 - throws IOException, SwitchStateException {
910 - Role role = extractNiciraRoleReply(h, m);
911 - // If role == null it means the vendor (experimenter) message
912 - // wasn't really a Nicira role reply. We ignore this case.
913 - if (role != null) {
914 - RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
915 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
916 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
917 - setRoleAndStartDriverHandshake(h, rri.getRole());
918 - } // else do nothing - wait for the correct expected reply
919 - } else {
920 - unhandledMessageReceived(h, m);
921 - }
922 - }
923 -
924 - @Override
925 - void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
926 - throws SwitchStateException, IOException {
927 - RoleReplyInfo rri = extractOFRoleReply(h, m);
928 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
929 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
930 - setRoleAndStartDriverHandshake(h, rri.getRole());
931 - } // else do nothing - wait for the correct expected reply
932 - }
933 -
934 - @Override
935 - void handleUnsentRoleMessage(OFChannelHandler h, Role role,
936 - RoleRecvStatus expectation) throws IOException {
937 - // typically this is triggered for a switch where role messages
938 - // are not supported - we confirm that the role being set is
939 - // master and move to the next state
940 - if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
941 - if (role == Role.MASTER) {
942 - setRoleAndStartDriverHandshake(h, role);
943 - } else {
944 - log.error("Expected MASTER role from registry for switch "
945 - + "which has no support for role-messages."
946 - + "Received {}. It is possible that this switch "
947 - + "is connected to other controllers, in which "
948 - + "case it should support role messages - not "
949 - + "moving forward.", role);
950 - }
951 - } // else do nothing - wait to hear back from registry
952 -
953 - }
954 -
955 - private void setRoleAndStartDriverHandshake(OFChannelHandler h,
956 - Role role) throws IOException {
957 - h.setSwitchRole(role);
958 - h.sw.startDriverHandshake();
959 - if (h.sw.isDriverHandshakeComplete()) {
960 - Role mySwitchRole = h.sw.getRole();
961 - if (mySwitchRole == Role.MASTER) {
962 - log.info("Switch-driver sub-handshake complete. "
963 - + "Activating switch {} with Role: MASTER",
964 - h.getSwitchInfoString());
965 - handlePendingPortStatusMessages(h); //before activation
966 - boolean success = h.controller.addActivatedMasterSwitch(
967 - h.sw.getId(), h.sw);
968 - if (!success) {
969 - disconnectDuplicate(h);
970 - return;
971 - }
972 - h.setState(MASTER);
973 - } else {
974 - log.info("Switch-driver sub-handshake complete. "
975 - + "Activating switch {} with Role: EQUAL",
976 - h.getSwitchInfoString());
977 - handlePendingPortStatusMessages(h); //before activation
978 - boolean success = h.controller.addActivatedEqualSwitch(
979 - h.sw.getId(), h.sw);
980 - if (!success) {
981 - disconnectDuplicate(h);
982 - return;
983 - }
984 - h.setState(EQUAL);
985 - }
986 - } else {
987 - h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
988 - }
989 - }
990 -
991 - @Override
992 - void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
993 - throws IOException, SwitchStateException {
994 - illegalMessageReceived(h, m);
995 - }
996 -
997 - @Override
998 - void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
999 - throws SwitchStateException {
1000 - illegalMessageReceived(h, m);
1001 - }
1002 -
1003 - @Override
1004 - void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1005 - throws IOException, SwitchStateException {
1006 - h.pendingPortStatusMsg.add(m);
1007 -
1008 - }
1009 - },
1010 460
1011 /** 461 /**
1012 * We are waiting for the respective switch driver to complete its 462 * We are waiting for the respective switch driver to complete its
...@@ -1026,39 +476,27 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1026,39 +476,27 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1026 476
1027 @Override 477 @Override
1028 void processOFMessage(OFChannelHandler h, OFMessage m) 478 void processOFMessage(OFChannelHandler h, OFMessage m)
1029 - throws IOException { 479 + throws IOException, SwitchStateException {
1030 if (m.getType() == OFType.ECHO_REQUEST) { 480 if (m.getType() == OFType.ECHO_REQUEST) {
1031 processOFEchoRequest(h, (OFEchoRequest) m); 481 processOFEchoRequest(h, (OFEchoRequest) m);
1032 - } else { 482 + } else if (m.getType() == OFType.ROLE_REPLY) {
1033 - // FIXME: other message to handle here? 483 + h.sw.handleRole(m);
484 + } else if (m.getType() == OFType.ERROR) {
485 + if (!h.sw.handleRoleError((OFErrorMsg)m)) {
1034 h.sw.processDriverHandshakeMessage(m); 486 h.sw.processDriverHandshakeMessage(m);
1035 if (h.sw.isDriverHandshakeComplete()) { 487 if (h.sw.isDriverHandshakeComplete()) {
1036 - // consult the h.sw role and goto that state 488 + h.setState(ACTIVE);
1037 - Role mySwitchRole = h.sw.getRole();
1038 - if (mySwitchRole == Role.MASTER) {
1039 - log.info("Switch-driver sub-handshake complete. "
1040 - + "Activating switch {} with Role: MASTER",
1041 - h.getSwitchInfoString());
1042 - handlePendingPortStatusMessages(h); //before activation
1043 - boolean success = h.controller.addActivatedMasterSwitch(
1044 - h.sw.getId(), h.sw);
1045 - if (!success) {
1046 - disconnectDuplicate(h);
1047 - return;
1048 } 489 }
1049 - h.setState(MASTER);
1050 - } else {
1051 - log.info("Switch-driver sub-handshake complete. "
1052 - + "Activating switch {} with Role: EQUAL",
1053 - h.getSwitchInfoString());
1054 - handlePendingPortStatusMessages(h); //before activation
1055 - boolean success = h.controller.addActivatedEqualSwitch(
1056 - h.sw.getId(), h.sw);
1057 - if (!success) {
1058 - disconnectDuplicate(h);
1059 - return;
1060 } 490 }
1061 - h.setState(EQUAL); 491 + } else {
492 + if (m.getType() == OFType.EXPERIMENTER &&
493 + ((OFExperimenter) m).getExperimenter() ==
494 + RoleManager.NICIRA_EXPERIMENTER) {
495 + h.sw.handleNiciraRole(m);
496 + } else {
497 + h.sw.processDriverHandshakeMessage(m);
498 + if (h.sw.isDriverHandshakeComplete()) {
499 + h.setState(ACTIVE);
1062 } 500 }
1063 } 501 }
1064 } 502 }
...@@ -1084,7 +522,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1084,7 +522,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1084 * if we send a role request for SLAVE /and/ receive the role reply for 522 * if we send a role request for SLAVE /and/ receive the role reply for
1085 * SLAVE. 523 * SLAVE.
1086 */ 524 */
1087 - MASTER(true) { 525 + ACTIVE(true) {
1088 @LogMessageDoc(level = "WARN", 526 @LogMessageDoc(level = "WARN",
1089 message = "Received permission error from switch {} while" 527 message = "Received permission error from switch {} while"
1090 + "being master. Reasserting master role.", 528 + "being master. Reasserting master role.",
...@@ -1097,13 +535,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1097,13 +535,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1097 @Override 535 @Override
1098 void processOFError(OFChannelHandler h, OFErrorMsg m) 536 void processOFError(OFChannelHandler h, OFErrorMsg m)
1099 throws IOException, SwitchStateException { 537 throws IOException, SwitchStateException {
1100 - // first check if the error msg is in response to a role-request message
1101 - RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
1102 - if (rrstatus != RoleRecvStatus.OTHER_EXPECTATION) {
1103 - // rolechanger has handled the error message - we are done
1104 - return;
1105 - }
1106 -
1107 // if we get here, then the error message is for something else 538 // if we get here, then the error message is for something else
1108 if (m.getErrType() == OFErrorType.BAD_REQUEST && 539 if (m.getErrType() == OFErrorType.BAD_REQUEST &&
1109 ((OFBadRequestErrorMsg) m).getCode() == 540 ((OFBadRequestErrorMsg) m).getCode() ==
...@@ -1116,13 +547,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1116,13 +547,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1116 // if two controllers are master (even if its only for 547 // if two controllers are master (even if its only for
1117 // a brief period). We might need to see if these errors 548 // a brief period). We might need to see if these errors
1118 // persist before we reassert 549 // persist before we reassert
1119 - h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
1120 log.warn("Received permission error from switch {} while" + 550 log.warn("Received permission error from switch {} while" +
1121 "being master. Reasserting master role.", 551 "being master. Reasserting master role.",
1122 h.getSwitchInfoString()); 552 h.getSwitchInfoString());
1123 - //h.controller.reassertRole(h, Role.MASTER); 553 + h.sw.reassertRole();
1124 - // XXX S reassert in role changer or reconsider if all this
1125 - // stuff is really needed
1126 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED && 554 } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
1127 ((OFFlowModFailedErrorMsg) m).getCode() == 555 ((OFFlowModFailedErrorMsg) m).getCode() ==
1128 OFFlowModFailedCode.ALL_TABLES_FULL) { 556 OFFlowModFailedCode.ALL_TABLES_FULL) {
...@@ -1136,35 +564,19 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1136,35 +564,19 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1136 @Override 564 @Override
1137 void processOFStatisticsReply(OFChannelHandler h, 565 void processOFStatisticsReply(OFChannelHandler h,
1138 OFStatsReply m) { 566 OFStatsReply m) {
1139 - h.sw.deliverStatisticsReply(m); 567 + h.sw.handleMessage(m);
1140 } 568 }
1141 569
1142 @Override 570 @Override
1143 void processOFExperimenter(OFChannelHandler h, OFExperimenter m) 571 void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1144 throws IOException, SwitchStateException { 572 throws IOException, SwitchStateException {
1145 - Role role = extractNiciraRoleReply(h, m); 573 + h.sw.handleNiciraRole(m);
1146 - if (role == null) {
1147 - // The message wasn't really a Nicira role reply. We just
1148 - // dispatch it to the OFMessage listeners in this case.
1149 - h.dispatchMessage(m);
1150 - return;
1151 - }
1152 -
1153 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
1154 - new RoleReplyInfo(role, null, m.getXid()));
1155 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1156 - checkAndSetRoleTransition(h, role);
1157 - }
1158 } 574 }
1159 575
1160 @Override 576 @Override
1161 void processOFRoleReply(OFChannelHandler h, OFRoleReply m) 577 void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1162 throws SwitchStateException, IOException { 578 throws SwitchStateException, IOException {
1163 - RoleReplyInfo rri = extractOFRoleReply(h, m); 579 + h.sw.handleRole(m);
1164 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
1165 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1166 - checkAndSetRoleTransition(h, rri.getRole());
1167 - }
1168 } 580 }
1169 581
1170 @Override 582 @Override
...@@ -1192,95 +604,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1192,95 +604,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1192 h.dispatchMessage(m); 604 h.dispatchMessage(m);
1193 } 605 }
1194 606
1195 - },
1196 -
1197 - /**
1198 - * This controller is in EQUAL role for this switch. We enter this state
1199 - * after some /other/ controller instance wins mastership-role over this
1200 - * switch. The EQUAL role can be considered the same as the SLAVE role
1201 - * if this controller does NOT send commands or packets to the switch.
1202 - * This should always be true for OF1.0 switches. XXX S need to enforce.
1203 - *
1204 - * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
1205 - * gives us the flexibility that if an app wants to send commands/packets
1206 - * to switches, it can, even thought it is running on a controller instance
1207 - * that is not in a MASTER role for this switch. Of course, it is the job
1208 - * of the app to ensure that commands/packets sent by this (EQUAL) controller
1209 - * instance does not clash/conflict with commands/packets sent by the MASTER
1210 - * controller for this switch. Neither the controller instances, nor the
1211 - * switch provides any kind of resolution mechanism should conflicts occur.
1212 - */
1213 - EQUAL(true) {
1214 - @Override
1215 - void processOFError(OFChannelHandler h, OFErrorMsg m)
1216 - throws IOException, SwitchStateException {
1217 - // role changer will ignore the error if it isn't for it
1218 - RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
1219 - if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
1220 - logError(h, m);
1221 - h.dispatchMessage(m);
1222 - }
1223 - }
1224 -
1225 - @Override
1226 - void processOFStatisticsReply(OFChannelHandler h,
1227 - OFStatsReply m) {
1228 - h.sw.deliverStatisticsReply(m);
1229 - }
1230 -
1231 - @Override
1232 - void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
1233 - throws IOException, SwitchStateException {
1234 - Role role = extractNiciraRoleReply(h, m);
1235 - // If role == null it means the message wasn't really a
1236 - // Nicira role reply. We ignore it in this state.
1237 - if (role != null) {
1238 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
1239 - new RoleReplyInfo(role, null, m.getXid()));
1240 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1241 - checkAndSetRoleTransition(h, role);
1242 - }
1243 - } else {
1244 - unhandledMessageReceived(h, m);
1245 - }
1246 - }
1247 -
1248 - @Override
1249 - void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
1250 - throws SwitchStateException, IOException {
1251 - RoleReplyInfo rri = extractOFRoleReply(h, m);
1252 - RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
1253 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
1254 - checkAndSetRoleTransition(h, rri.getRole());
1255 - }
1256 - }
1257 -
1258 - // XXX S needs more handlers for 1.3 switches in equal role
1259 -
1260 - @Override
1261 - void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
1262 - throws IOException, SwitchStateException {
1263 - handlePortStatusMessage(h, m, true);
1264 - }
1265 -
1266 - @Override
1267 - @LogMessageDoc(level = "WARN",
1268 - message = "Received PacketIn from switch {} while "
1269 - + "being slave. Reasserting slave role.",
1270 - explanation = "The switch has receive a PacketIn despite being "
1271 - + "in slave role indicating inconsistent controller roles",
1272 - recommendation = "This situation can occurs transiently during role"
1273 - + " changes. If, however, the condition persists or happens"
1274 - + " frequently this indicates a role inconsistency. "
1275 - + LogMessageDoc.CHECK_CONTROLLER)
1276 - void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
1277 - // we don't expect packetIn while slave, reassert we are slave
1278 - h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
1279 - log.warn("Received PacketIn from switch {} while" +
1280 - "being slave. Reasserting slave role.", h.sw);
1281 - //h.controller.reassertRole(h, Role.SLAVE);
1282 - // XXX reassert in role changer
1283 - }
1284 }; 607 };
1285 608
1286 private final boolean handshakeComplete; 609 private final boolean handshakeComplete;
...@@ -1345,7 +668,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1345,7 +668,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1345 */ 668 */
1346 protected void unhandledMessageReceived(OFChannelHandler h, 669 protected void unhandledMessageReceived(OFChannelHandler h,
1347 OFMessage m) { 670 OFMessage m) {
1348 - h.counters.unhandledMessage.updateCounterNoFlush();
1349 if (log.isDebugEnabled()) { 671 if (log.isDebugEnabled()) {
1350 String msg = getSwitchStateMessage(h, m, 672 String msg = getSwitchStateMessage(h, m,
1351 "Ignoring unexpected message"); 673 "Ignoring unexpected message");
...@@ -1398,108 +720,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1398,108 +720,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1398 h.channel.disconnect(); 720 h.channel.disconnect();
1399 } 721 }
1400 722
1401 - /**
1402 - * Extract the role from an OFVendor message.
1403 - *
1404 - * Extract the role from an OFVendor message if the message is a
1405 - * Nicira role reply. Otherwise return null.
1406 - *
1407 - * @param h The channel handler receiving the message
1408 - * @param vendorMessage The vendor message to parse.
1409 - * @return The role in the message if the message is a Nicira role
1410 - * reply, null otherwise.
1411 - * @throws SwitchStateException If the message is a Nicira role reply
1412 - * but the numeric role value is unknown.
1413 - */
1414 - protected Role extractNiciraRoleReply(OFChannelHandler h,
1415 - OFExperimenter experimenterMsg) throws SwitchStateException {
1416 - int vendor = (int) experimenterMsg.getExperimenter();
1417 - if (vendor != 0x2320) {
1418 - return null;
1419 - }
1420 - OFNiciraControllerRoleReply nrr =
1421 - (OFNiciraControllerRoleReply) experimenterMsg;
1422 -
1423 - Role role = null;
1424 - OFNiciraControllerRole ncr = nrr.getRole();
1425 - switch(ncr) {
1426 - case ROLE_MASTER:
1427 - role = Role.MASTER;
1428 - break;
1429 - case ROLE_OTHER:
1430 - role = Role.EQUAL;
1431 - break;
1432 - case ROLE_SLAVE:
1433 - role = Role.SLAVE;
1434 - break;
1435 - default: //handled below
1436 - }
1437 723
1438 - if (role == null) {
1439 - String msg = String.format("Switch: [%s], State: [%s], "
1440 - + "received NX_ROLE_REPLY with invalid role "
1441 - + "value %s",
1442 - h.getSwitchInfoString(),
1443 - this.toString(),
1444 - nrr.getRole());
1445 - throw new SwitchStateException(msg);
1446 - }
1447 - return role;
1448 - }
1449 -
1450 - /**
1451 - * Helper class returns role reply information in the format understood
1452 - * by the controller.
1453 - */
1454 - protected static class RoleReplyInfo {
1455 - private Role role;
1456 - private U64 genId;
1457 - private long xid;
1458 -
1459 - RoleReplyInfo(Role role, U64 genId, long xid) {
1460 - this.role = role;
1461 - this.genId = genId;
1462 - this.xid = xid;
1463 - }
1464 - public Role getRole() { return role; }
1465 - public U64 getGenId() { return genId; }
1466 - public long getXid() { return xid; }
1467 - @Override
1468 - public String toString() {
1469 - return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
1470 - }
1471 - }
1472 -
1473 - /**
1474 - * Extract the role information from an OF1.3 Role Reply Message.
1475 - * @param h
1476 - * @param rrmsg
1477 - * @return RoleReplyInfo object
1478 - * @throws SwitchStateException
1479 - */
1480 - protected RoleReplyInfo extractOFRoleReply(OFChannelHandler h,
1481 - OFRoleReply rrmsg) throws SwitchStateException {
1482 - OFControllerRole cr = rrmsg.getRole();
1483 - Role role = null;
1484 - switch(cr) {
1485 - case ROLE_EQUAL:
1486 - role = Role.EQUAL;
1487 - break;
1488 - case ROLE_MASTER:
1489 - role = Role.MASTER;
1490 - break;
1491 - case ROLE_SLAVE:
1492 - role = Role.SLAVE;
1493 - break;
1494 - case ROLE_NOCHANGE: // switch should send current role
1495 - default:
1496 - String msg = String.format("Unknown controller role %s "
1497 - + "received from switch %s", cr, h.sw);
1498 - throw new SwitchStateException(msg);
1499 - }
1500 -
1501 - return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
1502 - }
1503 724
1504 /** 725 /**
1505 * Handles all pending port status messages before a switch is declared 726 * Handles all pending port status messages before a switch is declared
...@@ -1567,52 +788,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1567,52 +788,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1567 throw new SwitchStateException(msg); 788 throw new SwitchStateException(msg);
1568 } 789 }
1569 790
1570 - Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m); 791 + h.sw.handleMessage(m);
1571 - if (doNotify) {
1572 - for (PortChangeEvent ev: changes) {
1573 - h.controller.notifyPortChanged(h.sw.getId(), ev.port, ev.type);
1574 - }
1575 - }
1576 - }
1577 -
1578 - /**
1579 - * Checks if the role received (from the role-reply msg) is different
1580 - * from the existing role in the IOFSwitch object for this controller.
1581 - * If so, it transitions the controller to the new role. Note that
1582 - * the caller should have already verified that the role-reply msg
1583 - * received was in response to a role-request msg sent out by this
1584 - * controller after hearing from the registry service.
1585 - *
1586 - * @param h the ChannelHandler that received the message
1587 - * @param role the role in the recieved role reply message
1588 - */
1589 - protected void checkAndSetRoleTransition(OFChannelHandler h, Role role) {
1590 - // we received a role-reply in response to a role message
1591 - // sent after hearing from the registry service. It is
1592 - // possible that the role of this controller instance for
1593 - // this switch has changed:
1594 - // for 1.0 switch: from MASTER to SLAVE
1595 - // for 1.3 switch: from MASTER to EQUAL
1596 - if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
1597 - (h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
1598 - // the mastership has changed
1599 - h.sw.setRole(role);
1600 - h.setState(EQUAL);
1601 - h.controller.transitionToEqualSwitch(h.sw.getId());
1602 - return;
1603 } 792 }
1604 793
1605 - // or for both 1.0 and 1.3 switches from EQUAL to MASTER.
1606 - // note that for 1.0, even though we mean SLAVE,
1607 - // internally we call the role EQUAL.
1608 - if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
1609 - // the mastership has changed
1610 - h.sw.setRole(role);
1611 - h.setState(MASTER);
1612 - h.controller.transitionToMasterSwitch(h.sw.getId());
1613 - return;
1614 - }
1615 - }
1616 794
1617 /** 795 /**
1618 * Process an OF message received on the channel and 796 * Process an OF message received on the channel and
...@@ -1635,7 +813,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1635,7 +813,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1635 */ 813 */
1636 void processOFMessage(OFChannelHandler h, OFMessage m) 814 void processOFMessage(OFChannelHandler h, OFMessage m)
1637 throws IOException, SwitchStateException { 815 throws IOException, SwitchStateException {
1638 - h.roleChanger.checkTimeout();
1639 switch(m.getType()) { 816 switch(m.getType()) {
1640 case HELLO: 817 case HELLO:
1641 processOFHello(h, (OFHello) m); 818 processOFHello(h, (OFHello) m);
...@@ -1812,10 +989,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1812,10 +989,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1812 unhandledMessageReceived(h, m); 989 unhandledMessageReceived(h, m);
1813 } 990 }
1814 991
1815 - void handleUnsentRoleMessage(OFChannelHandler h, Role role,
1816 - RoleRecvStatus expectation) throws IOException {
1817 - // do nothing in most states
1818 - }
1819 } 992 }
1820 993
1821 994
...@@ -1830,7 +1003,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1830,7 +1003,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1830 + "specified IP address") 1003 + "specified IP address")
1831 public void channelConnected(ChannelHandlerContext ctx, 1004 public void channelConnected(ChannelHandlerContext ctx,
1832 ChannelStateEvent e) throws Exception { 1005 ChannelStateEvent e) throws Exception {
1833 - counters.switchConnected.updateCounterWithFlush();
1834 channel = e.getChannel(); 1006 channel = e.getChannel();
1835 log.info("New switch connection from {}", 1007 log.info("New switch connection from {}",
1836 channel.getRemoteAddress()); 1008 channel.getRemoteAddress());
...@@ -1853,7 +1025,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1853,7 +1025,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1853 // switch was a duplicate-dpid, calling the method below would clear 1025 // switch was a duplicate-dpid, calling the method below would clear
1854 // all state for the original switch (with the same dpid), 1026 // all state for the original switch (with the same dpid),
1855 // which we obviously don't want. 1027 // which we obviously don't want.
1856 - controller.removeConnectedSwitch(thisdpid); 1028 + sw.removeConnectedSwitch();
1857 } else { 1029 } else {
1858 // A duplicate was disconnected on this ChannelHandler, 1030 // A duplicate was disconnected on this ChannelHandler,
1859 // this is the same switch reconnecting, but the original state was 1031 // this is the same switch reconnecting, but the original state was
...@@ -1914,12 +1086,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1914,12 +1086,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1914 // switch timeout 1086 // switch timeout
1915 log.error("Disconnecting switch {} due to read timeout", 1087 log.error("Disconnecting switch {} due to read timeout",
1916 getSwitchInfoString()); 1088 getSwitchInfoString());
1917 - counters.switchDisconnectReadTimeout.updateCounterWithFlush();
1918 ctx.getChannel().close(); 1089 ctx.getChannel().close();
1919 } else if (e.getCause() instanceof HandshakeTimeoutException) { 1090 } else if (e.getCause() instanceof HandshakeTimeoutException) {
1920 log.error("Disconnecting switch {}: failed to complete handshake", 1091 log.error("Disconnecting switch {}: failed to complete handshake",
1921 getSwitchInfoString()); 1092 getSwitchInfoString());
1922 - counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
1923 ctx.getChannel().close(); 1093 ctx.getChannel().close();
1924 } else if (e.getCause() instanceof ClosedChannelException) { 1094 } else if (e.getCause() instanceof ClosedChannelException) {
1925 log.debug("Channel for sw {} already closed", getSwitchInfoString()); 1095 log.debug("Channel for sw {} already closed", getSwitchInfoString());
...@@ -1930,7 +1100,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1930,7 +1100,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1930 // still print stack trace if debug is enabled 1100 // still print stack trace if debug is enabled
1931 log.debug("StackTrace for previous Exception: ", e.getCause()); 1101 log.debug("StackTrace for previous Exception: ", e.getCause());
1932 } 1102 }
1933 - counters.switchDisconnectIOError.updateCounterWithFlush();
1934 ctx.getChannel().close(); 1103 ctx.getChannel().close();
1935 } else if (e.getCause() instanceof SwitchStateException) { 1104 } else if (e.getCause() instanceof SwitchStateException) {
1936 log.error("Disconnecting switch {} due to switch state error: {}", 1105 log.error("Disconnecting switch {} due to switch state error: {}",
...@@ -1939,23 +1108,19 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1939,23 +1108,19 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1939 // still print stack trace if debug is enabled 1108 // still print stack trace if debug is enabled
1940 log.debug("StackTrace for previous Exception: ", e.getCause()); 1109 log.debug("StackTrace for previous Exception: ", e.getCause());
1941 } 1110 }
1942 - counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
1943 ctx.getChannel().close(); 1111 ctx.getChannel().close();
1944 } else if (e.getCause() instanceof OFParseError) { 1112 } else if (e.getCause() instanceof OFParseError) {
1945 log.error("Disconnecting switch " 1113 log.error("Disconnecting switch "
1946 + getSwitchInfoString() + 1114 + getSwitchInfoString() +
1947 " due to message parse failure", 1115 " due to message parse failure",
1948 e.getCause()); 1116 e.getCause());
1949 - counters.switchDisconnectParseError.updateCounterWithFlush();
1950 ctx.getChannel().close(); 1117 ctx.getChannel().close();
1951 } else if (e.getCause() instanceof RejectedExecutionException) { 1118 } else if (e.getCause() instanceof RejectedExecutionException) {
1952 log.warn("Could not process message: queue full"); 1119 log.warn("Could not process message: queue full");
1953 - counters.rejectedExecutionException.updateCounterWithFlush();
1954 } else { 1120 } else {
1955 log.error("Error while processing message from switch " 1121 log.error("Error while processing message from switch "
1956 + getSwitchInfoString() 1122 + getSwitchInfoString()
1957 + "state " + this.state, e.getCause()); 1123 + "state " + this.state, e.getCause());
1958 - counters.switchDisconnectOtherException.updateCounterWithFlush();
1959 ctx.getChannel().close(); 1124 ctx.getChannel().close();
1960 } 1125 }
1961 } 1126 }
...@@ -1986,12 +1151,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -1986,12 +1151,10 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
1986 1151
1987 1152
1988 for (OFMessage ofm : msglist) { 1153 for (OFMessage ofm : msglist) {
1989 - counters.messageReceived.updateCounterNoFlush();
1990 // Do the actual packet processing 1154 // Do the actual packet processing
1991 state.processOFMessage(this, ofm); 1155 state.processOFMessage(this, ofm);
1992 } 1156 }
1993 } else { 1157 } else {
1994 - counters.messageReceived.updateCounterNoFlush();
1995 state.processOFMessage(this, (OFMessage) e.getMessage()); 1158 state.processOFMessage(this, (OFMessage) e.getMessage());
1996 } 1159 }
1997 } 1160 }
...@@ -2080,7 +1243,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -2080,7 +1243,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
2080 channel.write(Collections.singletonList(m)); 1243 channel.write(Collections.singletonList(m));
2081 } 1244 }
2082 1245
2083 - private void setSwitchRole(Role role) { 1246 + private void setSwitchRole(RoleState role) {
2084 sw.setRole(role); 1247 sw.setRole(role);
2085 } 1248 }
2086 1249
...@@ -2146,9 +1309,4 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -2146,9 +1309,4 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
2146 return state; 1309 return state;
2147 } 1310 }
2148 1311
2149 - void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
2150 - roleChanger = new RoleChanger(roleTimeoutMs);
2151 - }
2152 -
2153 -
2154 } 1312 }
......
1 +package org.onlab.onos.of.controller.impl.internal;
2 +
3 +import java.util.ArrayList;
4 +import java.util.concurrent.ConcurrentHashMap;
5 +import java.util.concurrent.locks.Lock;
6 +import java.util.concurrent.locks.ReentrantLock;
7 +
8 +import org.apache.felix.scr.annotations.Activate;
9 +import org.apache.felix.scr.annotations.Component;
10 +import org.apache.felix.scr.annotations.Deactivate;
11 +import org.apache.felix.scr.annotations.Service;
12 +import org.onlab.onos.of.controller.Dpid;
13 +import org.onlab.onos.of.controller.OpenFlowController;
14 +import org.onlab.onos.of.controller.OpenFlowSwitch;
15 +import org.onlab.onos.of.controller.OpenFlowSwitchListener;
16 +import org.onlab.onos.of.controller.PacketListener;
17 +import org.onlab.onos.of.controller.RoleState;
18 +import org.projectfloodlight.openflow.protocol.OFMessage;
19 +import org.projectfloodlight.openflow.util.HexString;
20 +import org.slf4j.Logger;
21 +import org.slf4j.LoggerFactory;
22 +
23 +@Component(immediate = true)
24 +@Service
25 +public class OpenFlowControllerImpl implements OpenFlowController {
26 +
27 + protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches;
28 + protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches;
29 + protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches;
30 +
31 + protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
32 + protected ArrayList<OpenFlowSwitchListener> ofEventListener;
33 +
34 + private final Controller ctrl = new Controller();
35 +
36 + @Activate
37 + public void activate() {
38 + ctrl.start(agent);
39 + }
40 +
41 + @Deactivate
42 + public void deactivate() {
43 + ctrl.stop();
44 + }
45 +
46 + @Override
47 + public Iterable<OpenFlowSwitch> getSwitches() {
48 + return connectedSwitches.values();
49 + }
50 +
51 + @Override
52 + public Iterable<OpenFlowSwitch> getMasterSwitches() {
53 + return activeMasterSwitches.values();
54 + }
55 +
56 + @Override
57 + public Iterable<OpenFlowSwitch> getEqualSwitches() {
58 + return activeEqualSwitches.values();
59 + }
60 +
61 + @Override
62 + public OpenFlowSwitch getSwitch(Dpid dpid) {
63 + return connectedSwitches.get(dpid.value());
64 + }
65 +
66 + @Override
67 + public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
68 + return activeMasterSwitches.get(dpid.value());
69 + }
70 +
71 + @Override
72 + public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
73 + return activeEqualSwitches.get(dpid.value()); }
74 +
75 + @Override
76 + public void addListener(OpenFlowSwitchListener listener) {
77 + if (!ofEventListener.contains(listener)) {
78 + this.ofEventListener.add(listener);
79 + }
80 + }
81 +
82 + @Override
83 + public void removeListener(OpenFlowSwitchListener listener) {
84 + this.ofEventListener.remove(listener);
85 + }
86 +
87 + @Override
88 + public void addPacketListener(int priority, PacketListener listener) {
89 + // TODO Auto-generated method stub
90 +
91 + }
92 +
93 + @Override
94 + public void removePacketListener(PacketListener listener) {
95 + // TODO Auto-generated method stub
96 +
97 + }
98 +
99 + @Override
100 + public void write(Dpid dpid, OFMessage msg) {
101 + this.getSwitch(dpid).write(msg);
102 + }
103 +
104 + @Override
105 + public void processPacket(OFMessage msg) {
106 + }
107 +
108 + @Override
109 + public void setRole(Dpid dpid, RoleState role) {
110 + switch (role) {
111 + case MASTER:
112 + agent.transitionToMasterSwitch(dpid.value());
113 + break;
114 + case EQUAL:
115 + agent.transitionToEqualSwitch(dpid.value());
116 + break;
117 + case SLAVE:
118 + //agent.transitionToSlaveSwitch(dpid.value());
119 + break;
120 + default:
121 + //WTF role is this?
122 + }
123 +
124 + }
125 +
126 + public class OpenFlowSwitchAgent {
127 +
128 + private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
129 + private Lock switchLock = new ReentrantLock();
130 +
131 + public boolean addConnectedSwitch(long dpid, AbstractOpenFlowSwitch sw) {
132 + if (connectedSwitches.get(dpid) != null) {
133 + log.error("Trying to add connectedSwitch but found a previous "
134 + + "value for dpid: {}", dpid);
135 + return false;
136 + } else {
137 + log.error("Added switch {}", dpid);
138 + connectedSwitches.put(dpid, sw);
139 + for (OpenFlowSwitchListener l : ofEventListener) {
140 + l.switchAdded(new Dpid(dpid));
141 + }
142 + return true;
143 + }
144 + }
145 +
146 + private boolean validActivation(long dpid) {
147 + if (connectedSwitches.get(dpid) == null) {
148 + log.error("Trying to activate switch but is not in "
149 + + "connected switches: dpid {}. Aborting ..",
150 + HexString.toHexString(dpid));
151 + return false;
152 + }
153 + if (activeMasterSwitches.get(dpid) != null ||
154 + activeEqualSwitches.get(dpid) != null) {
155 + log.error("Trying to activate switch but it is already "
156 + + "activated: dpid {}. Found in activeMaster: {} "
157 + + "Found in activeEqual: {}. Aborting ..", new Object[] {
158 + HexString.toHexString(dpid),
159 + (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
160 + (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
161 + return false;
162 + }
163 + return true;
164 + }
165 +
166 + /**
167 + * Called when a switch is activated, with this controller's role as MASTER.
168 + */
169 + protected boolean addActivatedMasterSwitch(long dpid, AbstractOpenFlowSwitch sw) {
170 + switchLock.lock();
171 + try {
172 + if (!validActivation(dpid)) {
173 + return false;
174 + }
175 + activeMasterSwitches.put(dpid, sw);
176 + return true;
177 + } finally {
178 + switchLock.unlock();
179 + }
180 + }
181 +
182 + /**
183 + * Called when a switch is activated, with this controller's role as EQUAL.
184 + */
185 + protected boolean addActivatedEqualSwitch(long dpid, AbstractOpenFlowSwitch sw) {
186 + switchLock.lock();
187 + try {
188 + if (!validActivation(dpid)) {
189 + return false;
190 + }
191 + activeEqualSwitches.put(dpid, sw);
192 + return true;
193 + } finally {
194 + switchLock.unlock();
195 + }
196 + }
197 +
198 + /**
199 + * Called when this controller's role for a switch transitions from equal
200 + * to master. For 1.0 switches, we internally refer to the role 'slave' as
201 + * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
202 + */
203 + protected void transitionToMasterSwitch(long dpid) {
204 + switchLock.lock();
205 + try {
206 + OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
207 + if (sw == null) {
208 + log.error("Transition to master called on sw {}, but switch "
209 + + "was not found in controller-cache", dpid);
210 + return;
211 + }
212 + activeMasterSwitches.put(dpid, sw);
213 + } finally {
214 + switchLock.unlock();
215 + }
216 + }
217 +
218 +
219 + /**
220 + * Called when this controller's role for a switch transitions to equal.
221 + * For 1.0 switches, we internally refer to the role 'slave' as
222 + * 'equal'.
223 + */
224 + protected void transitionToEqualSwitch(long dpid) {
225 + switchLock.lock();
226 + try {
227 + OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
228 + if (sw == null) {
229 + log.error("Transition to equal called on sw {}, but switch "
230 + + "was not found in controller-cache", dpid);
231 + return;
232 + }
233 + activeEqualSwitches.put(dpid, sw);
234 + } finally {
235 + switchLock.unlock();
236 + }
237 +
238 + }
239 +
240 + /**
241 + * Clear all state in controller switch maps for a switch that has
242 + * disconnected from the local controller. Also release control for
243 + * that switch from the global repository. Notify switch listeners.
244 + */
245 + public void removeConnectedSwitch(long dpid) {
246 + connectedSwitches.remove(dpid);
247 + OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
248 + if (sw == null) {
249 + sw = activeEqualSwitches.remove(dpid);
250 + }
251 + for (OpenFlowSwitchListener l : ofEventListener) {
252 + l.switchRemoved(new Dpid(dpid));
253 + }
254 + }
255 +
256 + public void processMessage(OFMessage m) {
257 + processPacket(m);
258 + }
259 + }
260 +
261 +
262 +
263 +}
1 +package org.onlab.onos.of.controller.impl.internal;
2 +
3 +import java.io.IOException;
4 +import java.util.Collections;
5 +import java.util.concurrent.atomic.AtomicInteger;
6 +
7 +import org.onlab.onos.of.controller.RoleState;
8 +import org.projectfloodlight.openflow.protocol.OFControllerRole;
9 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
10 +import org.projectfloodlight.openflow.protocol.OFErrorType;
11 +import org.projectfloodlight.openflow.protocol.OFExperimenter;
12 +import org.projectfloodlight.openflow.protocol.OFFactories;
13 +import org.projectfloodlight.openflow.protocol.OFMessage;
14 +import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
15 +import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
16 +import org.projectfloodlight.openflow.protocol.OFRoleReply;
17 +import org.projectfloodlight.openflow.protocol.OFRoleRequest;
18 +import org.projectfloodlight.openflow.protocol.OFVersion;
19 +import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
20 +import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
21 +import org.projectfloodlight.openflow.types.U64;
22 +import org.slf4j.Logger;
23 +import org.slf4j.LoggerFactory;
24 +
25 +
26 +/**
27 + * A utility class to handle role requests and replies for this channel.
28 + * After a role request is submitted the role changer keeps track of the
29 + * pending request, collects the reply (if any) and times out the request
30 + * if necessary.
31 + *
32 + * To simplify role handling we only keep track of the /last/ pending
33 + * role reply send to the switch. If multiple requests are pending and
34 + * we receive replies for earlier requests we ignore them. However, this
35 + * way of handling pending requests implies that we could wait forever if
36 + * a new request is submitted before the timeout triggers. If necessary
37 + * we could work around that though.
38 + */
39 +class RoleManager {
40 + protected static final long NICIRA_EXPERIMENTER = 0x2320;
41 +
42 + private static Logger log = LoggerFactory.getLogger(RoleManager.class);
43 + // indicates that a request is currently pending
44 + // needs to be volatile to allow correct double-check idiom
45 + private volatile boolean requestPending;
46 + // the transaction Id of the pending request
47 + private int pendingXid;
48 + // the role that's pending
49 + private RoleState pendingRole;
50 +
51 + // the expectation set by the caller for the returned role
52 + private RoleRecvStatus expectation;
53 + private AtomicInteger xidCounter;
54 + private AbstractOpenFlowSwitch sw;
55 +
56 +
57 + public RoleManager(AbstractOpenFlowSwitch sw) {
58 + this.requestPending = false;
59 + this.pendingXid = -1;
60 + this.pendingRole = null;
61 + this.xidCounter = new AtomicInteger(0);
62 + this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
63 + this.sw = sw;
64 + }
65 +
66 + /**
67 + * Send NX role request message to the switch requesting the specified
68 + * role.
69 + *
70 + * @param sw switch to send the role request message to
71 + * @param role role to request
72 + */
73 + private int sendNxRoleRequest(RoleState role) throws IOException {
74 + // Convert the role enum to the appropriate role to send
75 + OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
76 + switch (role) {
77 + case MASTER:
78 + roleToSend = OFNiciraControllerRole.ROLE_MASTER;
79 + break;
80 + case SLAVE:
81 + case EQUAL:
82 + default:
83 + // ensuring that the only two roles sent to 1.0 switches with
84 + // Nicira role support, are MASTER and SLAVE
85 + roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
86 + log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
87 + }
88 + int xid = xidCounter.getAndIncrement();
89 + OFExperimenter roleRequest = OFFactories.getFactory(OFVersion.OF_10)
90 + .buildNiciraControllerRoleRequest()
91 + .setXid(xid)
92 + .setRole(roleToSend)
93 + .build();
94 + sw.write(Collections.<OFMessage>singletonList(roleRequest));
95 + return xid;
96 + }
97 +
98 + private int sendOF13RoleRequest(RoleState role) throws IOException {
99 + // Convert the role enum to the appropriate role to send
100 + OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
101 + switch (role) {
102 + case EQUAL:
103 + roleToSend = OFControllerRole.ROLE_EQUAL;
104 + break;
105 + case MASTER:
106 + roleToSend = OFControllerRole.ROLE_MASTER;
107 + break;
108 + case SLAVE:
109 + roleToSend = OFControllerRole.ROLE_SLAVE;
110 + break;
111 + default:
112 + log.warn("Sending default role.noChange to switch {}."
113 + + " Should only be used for queries.", sw);
114 + }
115 +
116 + int xid = xidCounter.getAndIncrement();
117 + OFRoleRequest rrm = OFFactories.getFactory(OFVersion.OF_13)
118 + .buildRoleRequest()
119 + .setRole(roleToSend)
120 + .setXid(xid)
121 + //FIXME fix below when we actually use generation ids
122 + .setGenerationId(U64.ZERO)
123 + .build();
124 + sw.write(rrm);
125 + return xid;
126 + }
127 +
128 + /**
129 + * Send a role request with the given role to the switch and update
130 + * the pending request and timestamp.
131 + * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
132 + * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
133 + * in the IOFSwitch driver. If not supported, this method sends nothing
134 + * and returns 'false'. The caller should take appropriate action.
135 + *
136 + * One other optimization we do here is that for OF1.0 switches with
137 + * Nicira role message support, we force the Role.EQUAL to become
138 + * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
139 + * We cannot expect it to behave like SLAVE. We don't have this problem with
140 + * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
141 + * SLAVE behavior by using ASYNC messages.
142 + *
143 + * @param role
144 + * @throws IOException
145 + * @returns false if and only if the switch does not support role-request
146 + * messages, according to the switch driver; true otherwise.
147 + */
148 + synchronized boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
149 + throws IOException {
150 + this.expectation = exp;
151 +
152 + if (sw.factory().getVersion() == OFVersion.OF_10) {
153 + Boolean supportsNxRole = (Boolean)
154 + sw.supportNxRole();
155 + if (!supportsNxRole) {
156 + log.debug("Switch driver indicates no support for Nicira "
157 + + "role request messages. Not sending ...");
158 + handleUnsentRoleMessage(role,
159 + expectation);
160 + return false;
161 + }
162 + // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
163 + // make Role.EQUAL become Role.SLAVE
164 + role = (role == RoleState.EQUAL) ? RoleState.SLAVE : role;
165 + pendingXid = sendNxRoleRequest(role);
166 + pendingRole = role;
167 + requestPending = true;
168 + } else {
169 + // OF1.3 switch, use OFPT_ROLE_REQUEST message
170 + pendingXid = sendOF13RoleRequest(role);
171 + pendingRole = role;
172 + requestPending = true;
173 + }
174 + return true;
175 + }
176 +
177 + private void handleUnsentRoleMessage(RoleState role,
178 + RoleRecvStatus exp) throws IOException {
179 + // typically this is triggered for a switch where role messages
180 + // are not supported - we confirm that the role being set is
181 + // master
182 + if (exp != RoleRecvStatus.MATCHED_SET_ROLE) {
183 +
184 + log.error("Expected MASTER role from registry for switch "
185 + + "which has no support for role-messages."
186 + + "Received {}. It is possible that this switch "
187 + + "is connected to other controllers, in which "
188 + + "case it should support role messages - not "
189 + + "moving forward.", role);
190 +
191 + }
192 +
193 + }
194 +
195 + /**
196 + * Deliver a received role reply.
197 + *
198 + * Check if a request is pending and if the received reply matches the
199 + * the expected pending reply (we check both role and xid) we set
200 + * the role for the switch/channel.
201 + *
202 + * If a request is pending but doesn't match the reply we ignore it, and
203 + * return
204 + *
205 + * If no request is pending we disconnect with a SwitchStateException
206 + *
207 + * @param RoleReplyInfo information about role-reply in format that
208 + * controller can understand.
209 + * @throws SwitchStateException if no request is pending
210 + */
211 + synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
212 + throws SwitchStateException {
213 + if (!requestPending) {
214 + RoleState currentRole = (sw != null) ? sw.getRole() : null;
215 + if (currentRole != null) {
216 + if (currentRole == rri.getRole()) {
217 + // Don't disconnect if the role reply we received is
218 + // for the same role we are already in.
219 + log.debug("Received unexpected RoleReply from "
220 + + "Switch: {}. "
221 + + "Role in reply is same as current role of this "
222 + + "controller for this sw. Ignoring ...",
223 + sw.getStringId());
224 + return RoleRecvStatus.OTHER_EXPECTATION;
225 + } else {
226 + String msg = String.format("Switch: [%s], "
227 + + "received unexpected RoleReply[%s]. "
228 + + "No roles are pending, and this controller's "
229 + + "current role:[%s] does not match reply. "
230 + + "Disconnecting switch ... ",
231 + sw.getStringId(),
232 + rri, currentRole);
233 + throw new SwitchStateException(msg);
234 + }
235 + }
236 + log.debug("Received unexpected RoleReply {} from "
237 + + "Switch: {}. "
238 + + "This controller has no current role for this sw. "
239 + + "Ignoring ...", new Object[] {rri,
240 + sw.getStringId(), });
241 + return RoleRecvStatus.OTHER_EXPECTATION;
242 + }
243 +
244 + int xid = (int) rri.getXid();
245 + RoleState role = rri.getRole();
246 + // XXX S should check generation id meaningfully and other cases of expectations
247 + // U64 genId = rri.getGenId();
248 +
249 + if (pendingXid != xid) {
250 + log.debug("Received older role reply from " +
251 + "switch {} ({}). Ignoring. " +
252 + "Waiting for {}, xid={}",
253 + new Object[] {sw.getStringId(), rri,
254 + pendingRole, pendingXid });
255 + return RoleRecvStatus.OLD_REPLY;
256 + }
257 +
258 + if (pendingRole == role) {
259 + log.debug("Received role reply message from {} that matched "
260 + + "expected role-reply {} with expectations {}",
261 + new Object[] {sw.getStringId(), role, expectation});
262 +
263 + //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
264 + if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
265 + expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
266 + return expectation;
267 + } else {
268 + return RoleRecvStatus.OTHER_EXPECTATION;
269 + }
270 + }
271 +
272 + // if xids match but role's don't, perhaps its a query (OF1.3)
273 + if (expectation == RoleRecvStatus.REPLY_QUERY) {
274 + return expectation;
275 + }
276 +
277 + return RoleRecvStatus.OTHER_EXPECTATION;
278 + }
279 +
280 + /**
281 + * Called if we receive an error message. If the xid matches the
282 + * pending request we handle it otherwise we ignore it.
283 + *
284 + * Note: since we only keep the last pending request we might get
285 + * error messages for earlier role requests that we won't be able
286 + * to handle
287 + */
288 + synchronized RoleRecvStatus deliverError(OFErrorMsg error)
289 + throws SwitchStateException {
290 + if (!requestPending) {
291 + log.debug("Received an error msg from sw {}, but no pending "
292 + + "requests in role-changer; not handling ...",
293 + sw.getStringId());
294 + return RoleRecvStatus.OTHER_EXPECTATION;
295 + }
296 + if (pendingXid != error.getXid()) {
297 + if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
298 + log.debug("Received an error msg from sw {} for a role request,"
299 + + " but not for pending request in role-changer; "
300 + + " ignoring error {} ...",
301 + sw.getStringId(), error);
302 + }
303 + return RoleRecvStatus.OTHER_EXPECTATION;
304 + }
305 + // it is an error related to a currently pending role request message
306 + if (error.getErrType() == OFErrorType.BAD_REQUEST) {
307 + log.error("Received a error msg {} from sw {} for "
308 + + "pending role request {}. Switch driver indicates "
309 + + "role-messaging is supported. Possible issues in "
310 + + "switch driver configuration?", new Object[] {
311 + ((OFBadRequestErrorMsg) error).toString(),
312 + sw.getStringId(), pendingRole
313 + });
314 + return RoleRecvStatus.UNSUPPORTED;
315 + }
316 +
317 + if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
318 + OFRoleRequestFailedErrorMsg rrerr =
319 + (OFRoleRequestFailedErrorMsg) error;
320 + switch (rrerr.getCode()) {
321 + case BAD_ROLE:
322 + // switch says that current-role-req has bad role?
323 + // for now we disconnect
324 + // fall-thru
325 + case STALE:
326 + // switch says that current-role-req has stale gen-id?
327 + // for now we disconnect
328 + // fall-thru
329 + case UNSUP:
330 + // switch says that current-role-req has role that
331 + // cannot be supported? for now we disconnect
332 + String msgx = String.format("Switch: [%s], "
333 + + "received Error to for pending role request [%s]. "
334 + + "Error:[%s]. Disconnecting switch ... ",
335 + sw.getStringId(),
336 + pendingRole, rrerr);
337 + throw new SwitchStateException(msgx);
338 + default:
339 + break;
340 + }
341 + }
342 +
343 + // This error message was for a role request message but we dont know
344 + // how to handle errors for nicira role request messages
345 + return RoleRecvStatus.OTHER_EXPECTATION;
346 + }
347 +
348 + /**
349 + * Extract the role from an OFVendor message.
350 + *
351 + * Extract the role from an OFVendor message if the message is a
352 + * Nicira role reply. Otherwise return null.
353 + *
354 + * @param h The channel handler receiving the message
355 + * @param vendorMessage The vendor message to parse.
356 + * @return The role in the message if the message is a Nicira role
357 + * reply, null otherwise.
358 + * @throws SwitchStateException If the message is a Nicira role reply
359 + * but the numeric role value is unknown.
360 + */
361 + protected RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
362 + throws SwitchStateException {
363 + int vendor = (int) experimenterMsg.getExperimenter();
364 + if (vendor != 0x2320) {
365 + return null;
366 + }
367 + OFNiciraControllerRoleReply nrr =
368 + (OFNiciraControllerRoleReply) experimenterMsg;
369 +
370 + RoleState role = null;
371 + OFNiciraControllerRole ncr = nrr.getRole();
372 + switch(ncr) {
373 + case ROLE_MASTER:
374 + role = RoleState.MASTER;
375 + break;
376 + case ROLE_OTHER:
377 + role = RoleState.EQUAL;
378 + break;
379 + case ROLE_SLAVE:
380 + role = RoleState.SLAVE;
381 + break;
382 + default: //handled below
383 + }
384 +
385 + if (role == null) {
386 + String msg = String.format("Switch: [%s], "
387 + + "received NX_ROLE_REPLY with invalid role "
388 + + "value %s",
389 + sw.getStringId(),
390 + nrr.getRole());
391 + throw new SwitchStateException(msg);
392 + }
393 + return role;
394 + }
395 +
396 + /**
397 + * When we remove a pending role request we use this enum to indicate how we
398 + * arrived at the decision. When we send a role request to the switch, we
399 + * also use this enum to indicate what we expect back from the switch, so the
400 + * role changer can match the reply to our expectation.
401 + */
402 + public enum RoleRecvStatus {
403 + /** The switch returned an error indicating that roles are not.
404 + * supported*/
405 + UNSUPPORTED,
406 + /** The request timed out. */
407 + NO_REPLY,
408 + /** The reply was old, there is a newer request pending. */
409 + OLD_REPLY,
410 + /**
411 + * The reply's role matched the role that this controller set in the
412 + * request message - invoked either initially at startup or to reassert
413 + * current role.
414 + */
415 + MATCHED_CURRENT_ROLE,
416 + /**
417 + * The reply's role matched the role that this controller set in the
418 + * request message - this is the result of a callback from the
419 + * global registry, followed by a role request sent to the switch.
420 + */
421 + MATCHED_SET_ROLE,
422 + /**
423 + * The reply's role was a response to the query made by this controller.
424 + */
425 + REPLY_QUERY,
426 + /** We received a role reply message from the switch
427 + * but the expectation was unclear, or there was no expectation.
428 + */
429 + OTHER_EXPECTATION,
430 + }
431 +
432 + /**
433 + * Helper class returns role reply information in the format understood
434 + * by the controller.
435 + */
436 + protected static class RoleReplyInfo {
437 + private RoleState role;
438 + private U64 genId;
439 + private long xid;
440 +
441 + RoleReplyInfo(RoleState role, U64 genId, long xid) {
442 + this.role = role;
443 + this.genId = genId;
444 + this.xid = xid;
445 + }
446 + public RoleState getRole() { return role; }
447 + public U64 getGenId() { return genId; }
448 + public long getXid() { return xid; }
449 + @Override
450 + public String toString() {
451 + return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
452 + }
453 + }
454 +
455 + /**
456 + * Extract the role information from an OF1.3 Role Reply Message.
457 + * @param h
458 + * @param rrmsg
459 + * @return RoleReplyInfo object
460 + * @throws SwitchStateException
461 + */
462 + protected RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
463 + throws SwitchStateException {
464 + OFControllerRole cr = rrmsg.getRole();
465 + RoleState role = null;
466 + switch(cr) {
467 + case ROLE_EQUAL:
468 + role = RoleState.EQUAL;
469 + break;
470 + case ROLE_MASTER:
471 + role = RoleState.MASTER;
472 + break;
473 + case ROLE_SLAVE:
474 + role = RoleState.SLAVE;
475 + break;
476 + case ROLE_NOCHANGE: // switch should send current role
477 + default:
478 + String msg = String.format("Unknown controller role %s "
479 + + "received from switch %s", cr, sw);
480 + throw new SwitchStateException(msg);
481 + }
482 +
483 + return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
484 + }
485 +
486 +}
487 +
488 +
489 +///**
490 +// * We are waiting for a role reply message in response to a role request
491 +// * sent after hearing back from the registry service -- OR -- we are
492 +// * just waiting to hear back from the registry service in the case that
493 +// * the switch does not support role messages. If completed successfully,
494 +// * the controller's role for this switch will be set here.
495 +// * Before we move to the state corresponding to the role, we allow the
496 +// * switch specific driver to complete its configuration. This configuration
497 +// * typically depends on the role the controller is playing for this switch.
498 +// * And so we set the switch role (for 'this' controller) before we start
499 +// * the driver-sub-handshake.
500 +// * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
501 +// */
502 +//WAIT_INITIAL_ROLE(false) {
503 +// @Override
504 +// void processOFError(OFChannelHandler h, OFErrorMsg m)
505 +// throws SwitchStateException {
506 +// // role changer will ignore the error if it isn't for it
507 +// RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
508 +// if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
509 +// logError(h, m);
510 +// }
511 +// }
512 +//
513 +// @Override
514 +// void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
515 +// throws IOException, SwitchStateException {
516 +// Role role = extractNiciraRoleReply(h, m);
517 +// // If role == null it means the vendor (experimenter) message
518 +// // wasn't really a Nicira role reply. We ignore this case.
519 +// if (role != null) {
520 +// RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
521 +// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
522 +// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
523 +// setRoleAndStartDriverHandshake(h, rri.getRole());
524 +// } // else do nothing - wait for the correct expected reply
525 +// } else {
526 +// unhandledMessageReceived(h, m);
527 +// }
528 +// }
529 +//
530 +// @Override
531 +// void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
532 +// throws SwitchStateException, IOException {
533 +// RoleReplyInfo rri = extractOFRoleReply(h, m);
534 +// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
535 +// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
536 +// setRoleAndStartDriverHandshake(h, rri.getRole());
537 +// } // else do nothing - wait for the correct expected reply
538 +// }
539 +//
540 +// @Override
541 +// void handleUnsentRoleMessage(OFChannelHandler h, Role role,
542 +// RoleRecvStatus expectation) throws IOException {
543 +// // typically this is triggered for a switch where role messages
544 +// // are not supported - we confirm that the role being set is
545 +// // master and move to the next state
546 +// if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
547 +// if (role == Role.MASTER) {
548 +// setRoleAndStartDriverHandshake(h, role);
549 +// } else {
550 +// log.error("Expected MASTER role from registry for switch "
551 +// + "which has no support for role-messages."
552 +// + "Received {}. It is possible that this switch "
553 +// + "is connected to other controllers, in which "
554 +// + "case it should support role messages - not "
555 +// + "moving forward.", role);
556 +// }
557 +// } // else do nothing - wait to hear back from registry
558 +//
559 +// }
560 +//
561 +// private void setRoleAndStartDriverHandshake(OFChannelHandler h,
562 +// Role role) throws IOException {
563 +// h.setSwitchRole(role);
564 +// h.sw.startDriverHandshake();
565 +// if (h.sw.isDriverHandshakeComplete()) {
566 +// Role mySwitchRole = h.sw.getRole();
567 +// if (mySwitchRole == Role.MASTER) {
568 +// log.info("Switch-driver sub-handshake complete. "
569 +// + "Activating switch {} with Role: MASTER",
570 +// h.sw.getStringId());
571 +// handlePendingPortStatusMessages(h); //before activation
572 +// boolean success = h.sw.addActivatedMasterSwitch();
573 +// if (!success) {
574 +// disconnectDuplicate(h);
575 +// return;
576 +// }
577 +// h.setState(MASTER);
578 +// } else {
579 +// log.info("Switch-driver sub-handshake complete. "
580 +// + "Activating switch {} with Role: EQUAL",
581 +// h.sw.getStringId());
582 +// handlePendingPortStatusMessages(h); //before activation
583 +// boolean success = h.sw.addActivatedEqualSwitch();
584 +// if (!success) {
585 +// disconnectDuplicate(h);
586 +// return;
587 +// }
588 +// h.setState(EQUAL);
589 +// }
590 +// } else {
591 +// h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
592 +// }
593 +// }
594 +//
595 +// @Override
596 +// void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m)
597 +// throws IOException, SwitchStateException {
598 +// illegalMessageReceived(h, m);
599 +// }
600 +//
601 +// @Override
602 +// void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
603 +// throws SwitchStateException {
604 +// illegalMessageReceived(h, m);
605 +// }
606 +//
607 +// @Override
608 +// void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
609 +// throws IOException, SwitchStateException {
610 +// h.pendingPortStatusMsg.add(m);
611 +//
612 +// }
613 +//},
614 +
615 +
616 +
617 +
618 +
619 +
620 +
621 +///**
622 +// * This controller is in EQUAL role for this switch. We enter this state
623 +// * after some /other/ controller instance wins mastership-role over this
624 +// * switch. The EQUAL role can be considered the same as the SLAVE role
625 +// * if this controller does NOT send commands or packets to the switch.
626 +// * This should always be true for OF1.0 switches. XXX S need to enforce.
627 +// *
628 +// * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
629 +// * gives us the flexibility that if an app wants to send commands/packets
630 +// * to switches, it can, even thought it is running on a controller instance
631 +// * that is not in a MASTER role for this switch. Of course, it is the job
632 +// * of the app to ensure that commands/packets sent by this (EQUAL) controller
633 +// * instance does not clash/conflict with commands/packets sent by the MASTER
634 +// * controller for this switch. Neither the controller instances, nor the
635 +// * switch provides any kind of resolution mechanism should conflicts occur.
636 +// */
637 +//EQUAL(true) {
638 +// @Override
639 +// void processOFError(OFChannelHandler h, OFErrorMsg m)
640 +// throws IOException, SwitchStateException {
641 +// // role changer will ignore the error if it isn't for it
642 +// RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
643 +// if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
644 +// logError(h, m);
645 +// h.dispatchMessage(m);
646 +// }
647 +// }
648 +//
649 +// @Override
650 +// void processOFStatisticsReply(OFChannelHandler h,
651 +// OFStatsReply m) {
652 +// h.sw.handleMessage(m);
653 +// }
654 +//
655 +// @Override
656 +// void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
657 +// throws IOException, SwitchStateException {
658 +// Role role = extractNiciraRoleReply(h, m);
659 +// // If role == null it means the message wasn't really a
660 +// // Nicira role reply. We ignore it in this state.
661 +// if (role != null) {
662 +// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
663 +// new RoleReplyInfo(role, null, m.getXid()));
664 +// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
665 +// checkAndSetRoleTransition(h, role);
666 +// }
667 +// } else {
668 +// unhandledMessageReceived(h, m);
669 +// }
670 +// }
671 +//
672 +// @Override
673 +// void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
674 +// throws SwitchStateException, IOException {
675 +// RoleReplyInfo rri = extractOFRoleReply(h, m);
676 +// RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
677 +// if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
678 +// checkAndSetRoleTransition(h, rri.getRole());
679 +// }
680 +// }
681 +//
682 +// // XXX S needs more handlers for 1.3 switches in equal role
683 +//
684 +// @Override
685 +// void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
686 +// throws IOException, SwitchStateException {
687 +// handlePortStatusMessage(h, m, true);
688 +// }
689 +//
690 +// @Override
691 +// @LogMessageDoc(level = "WARN",
692 +// message = "Received PacketIn from switch {} while "
693 +// + "being slave. Reasserting slave role.",
694 +// explanation = "The switch has receive a PacketIn despite being "
695 +// + "in slave role indicating inconsistent controller roles",
696 +// recommendation = "This situation can occurs transiently during role"
697 +// + " changes. If, however, the condition persists or happens"
698 +// + " frequently this indicates a role inconsistency. "
699 +// + LogMessageDoc.CHECK_CONTROLLER)
700 +// void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
701 +// // we don't expect packetIn while slave, reassert we are slave
702 +// h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
703 +// log.warn("Received PacketIn from switch {} while" +
704 +// "being slave. Reasserting slave role.", h.sw);
705 +// //h.controller.reassertRole(h, Role.SLAVE);
706 +// // XXX reassert in role changer
707 +// }
708 +//};
1 -package org.onlab.onos.of.controller.impl.registry;
2 -
3 -
4 -
5 -public class ControllerRegistryEntry implements Comparable<ControllerRegistryEntry> {
6 - //
7 - // TODO: Refactor the implementation and decide whether controllerId
8 - // is needed. If "yes", we might need to consider it inside the
9 - // compareTo(), equals() and hashCode() implementations.
10 - //
11 - private final String controllerId;
12 - private final int sequenceNumber;
13 -
14 - public ControllerRegistryEntry(String controllerId, int sequenceNumber) {
15 - this.controllerId = controllerId;
16 - this.sequenceNumber = sequenceNumber;
17 - }
18 -
19 - public String getControllerId() {
20 - return controllerId;
21 - }
22 -
23 - /**
24 - * Compares this object with the specified object for order.
25 - * NOTE: the test is based on ControllerRegistryEntry sequence numbers,
26 - * and doesn't include the controllerId.
27 - *
28 - * @param o the object to be compared.
29 - * @return a negative integer, zero, or a positive integer as this object
30 - * is less than, equal to, or greater than the specified object.
31 - */
32 - @Override
33 - public int compareTo(ControllerRegistryEntry o) {
34 - return this.sequenceNumber - o.sequenceNumber;
35 - }
36 -
37 - /**
38 - * Test whether some other object is "equal to" this one.
39 - * NOTE: the test is based on ControllerRegistryEntry sequence numbers,
40 - * and doesn't include the controllerId.
41 - *
42 - * @param obj the reference object with which to compare.
43 - * @return true if this object is the same as the obj argument; false
44 - * otherwise.
45 - */
46 - @Override
47 - public boolean equals(Object obj) {
48 - if (obj instanceof ControllerRegistryEntry) {
49 - ControllerRegistryEntry other = (ControllerRegistryEntry) obj;
50 - return this.sequenceNumber == other.sequenceNumber;
51 - }
52 - return false;
53 - }
54 -
55 - /**
56 - * Get the hash code for the object.
57 - * NOTE: the computation is based on ControllerRegistryEntry sequence
58 - * numbers, and doesn't include the controller ID.
59 - *
60 - * @return a hash code value for this object.
61 - */
62 - @Override
63 - public int hashCode() {
64 - return Integer.valueOf(this.sequenceNumber).hashCode();
65 - }
66 -}
1 -package org.onlab.onos.of.controller.impl.registry;
2 -
3 -import java.util.Collection;
4 -import java.util.List;
5 -import java.util.Map;
6 -
7 -import org.onlab.onos.of.controller.impl.util.InstanceId;
8 -
9 -/**
10 - * A registry service that allows ONOS to register controllers and switches in a
11 - * way that is global to the entire ONOS cluster. The registry is the arbiter
12 - * for allowing controllers to control switches.
13 - * <p/>
14 - * The OVS/OF1.{2,3} fault tolerance model is a switch connects to multiple
15 - * controllers, and the controllers send role requests to tell the switch their
16 - * role in controlling the switch.
17 - * <p/>
18 - * The ONOS fault tolerance model allows only a single controller to have
19 - * control of a switch (MASTER role) at once. Controllers therefore need a
20 - * mechanism that enables them to decide who should control a each switch. The
21 - * registry service provides this mechanism.
22 - */
23 -public interface IControllerRegistry {
24 -
25 - /**
26 - * Callback interface for control change events.
27 - */
28 - public interface ControlChangeCallback {
29 - /**
30 - * Called whenever the control changes from the point of view of the
31 - * registry. The callee can check whether they have control or not using
32 - * the hasControl parameter.
33 - *
34 - * @param dpid The switch that control has changed for
35 - * @param hasControl Whether the listener now has control or not
36 - */
37 - void controlChanged(long dpid, boolean hasControl);
38 - }
39 -
40 - /**
41 - * Request for control of a switch. This method does not block. When control
42 - * for a switch changes, the controlChanged method on the callback object
43 - * will be called. This happens any time the control changes while the
44 - * request is still active (until releaseControl is called)
45 - *
46 - * @param dpid Switch to request control for
47 - * @param cb Callback that will be used to notify caller of control changes
48 - * @throws RegistryException Errors contacting the registry service
49 - */
50 - public void requestControl(long dpid, ControlChangeCallback cb)
51 - throws RegistryException;
52 -
53 - /**
54 - * Stop trying to take control of a switch. This removes the entry for this
55 - * controller requesting this switch in the registry. If the controller had
56 - * control when this is called, another controller will now gain control of
57 - * the switch. This call doesn't block.
58 - *
59 - * @param dpid Switch to release control of
60 - */
61 - public void releaseControl(long dpid);
62 -
63 - /**
64 - * Check whether the controller has control of the switch This call doesn't
65 - * block.
66 - *
67 - * @param dpid Switch to check control of
68 - * @return true if controller has control of the switch.
69 - */
70 - public boolean hasControl(long dpid);
71 -
72 - /**
73 - * Check whether this instance is the leader for the cluster. This call
74 - * doesn't block.
75 - *
76 - * @return true if the instance is the leader for the cluster, otherwise
77 - * false.
78 - */
79 - public boolean isClusterLeader();
80 -
81 - /**
82 - * Gets the unique ID used to identify this ONOS instance in the cluster.
83 - *
84 - * @return Instance ID.
85 - */
86 - public InstanceId getOnosInstanceId();
87 -
88 - /**
89 - * Register a controller to the ONOS cluster. Must be called before the
90 - * registry can be used to take control of any switches.
91 - *
92 - * @param controllerId A unique string ID identifying this controller in the
93 - * cluster
94 - * @throws RegistryException for errors connecting to registry service,
95 - * controllerId already registered
96 - */
97 - public void registerController(String controllerId)
98 - throws RegistryException;
99 -
100 - /**
101 - * Get all controllers in the cluster.
102 - *
103 - * @return Collection of controller IDs
104 - * @throws RegistryException on error
105 - */
106 - public Collection<String> getAllControllers() throws RegistryException;
107 -
108 - /**
109 - * Get all switches in the cluster, along with which controller is in
110 - * control of them (if any) and any other controllers that have requested
111 - * control.
112 - *
113 - * @return Map of all switches.
114 - */
115 - public Map<String, List<ControllerRegistryEntry>> getAllSwitches();
116 -
117 - /**
118 - * Get the controller that has control of a given switch.
119 - *
120 - * @param dpid Switch to find controller for
121 - * @return controller ID
122 - * @throws RegistryException Errors contacting registry service
123 - */
124 - public String getControllerForSwitch(long dpid) throws RegistryException;
125 -
126 - /**
127 - * Get all switches controlled by a given controller.
128 - *
129 - * @param controllerId ID of the controller
130 - * @return Collection of dpids
131 - */
132 - public Collection<Long> getSwitchesControlledByController(String controllerId);
133 -
134 - /**
135 - * Get a unique Id Block.
136 - *
137 - * @return Id Block.
138 - */
139 - public IdBlock allocateUniqueIdBlock();
140 -
141 - /**
142 - * Get next unique id and retrieve a new range of ids if needed.
143 - *
144 - * @param range range to use for the identifier
145 - * @return Id Block.
146 - */
147 - public IdBlock allocateUniqueIdBlock(long range);
148 -
149 - /**
150 - * Get a globally unique ID.
151 - *
152 - * @return a globally unique ID.
153 - */
154 - public long getNextUniqueId();
155 -}
1 -package org.onlab.onos.of.controller.impl.registry;
2 -
3 -public class IdBlock {
4 - private final long start;
5 - private final long end;
6 - private final long size;
7 -
8 - public IdBlock(long start, long end, long size) {
9 - this.start = start;
10 - this.end = end;
11 - this.size = size;
12 - }
13 -
14 - public long getStart() {
15 - return start;
16 - }
17 -
18 - public long getEnd() {
19 - return end;
20 - }
21 -
22 - public long getSize() {
23 - return size;
24 - }
25 -
26 - @Override
27 - public String toString() {
28 - return "IdBlock [start=" + start + ", end=" + end + ", size=" + size
29 - + "]";
30 - }
31 -}
32 -
1 -package org.onlab.onos.of.controller.impl.registry;
2 -
3 -public class RegistryException extends Exception {
4 -
5 - private static final long serialVersionUID = -8276300722010217913L;
6 -
7 - public RegistryException(String message) {
8 - super(message);
9 - }
10 -
11 - public RegistryException(String message, Throwable cause) {
12 - super(message, cause);
13 - }
14 -
15 -}
1 -package org.onlab.onos.of.controller.impl.util;
2 -
3 -import java.io.IOException;
4 -import java.util.Collection;
5 -import java.util.Date;
6 -import java.util.List;
7 -import java.util.Map;
8 -import java.util.Set;
9 -import java.util.concurrent.Future;
10 -
11 -import org.jboss.netty.channel.Channel;
12 -import org.projectfloodlight.openflow.protocol.OFActionType;
13 -import org.projectfloodlight.openflow.protocol.OFCapabilities;
14 -import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
15 -import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
16 -import org.projectfloodlight.openflow.protocol.OFMessage;
17 -import org.projectfloodlight.openflow.protocol.OFPortDesc;
18 -import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
19 -import org.projectfloodlight.openflow.protocol.OFPortStatus;
20 -import org.projectfloodlight.openflow.protocol.OFStatsReply;
21 -import org.projectfloodlight.openflow.protocol.OFStatsRequest;
22 -import org.projectfloodlight.openflow.protocol.OFVersion;
23 -import org.projectfloodlight.openflow.types.DatapathId;
24 -import org.projectfloodlight.openflow.types.U64;
25 -import org.slf4j.Logger;
26 -import org.slf4j.LoggerFactory;
27 -
28 -import org.onlab.onos.of.controller.impl.IOFSwitch;
29 -import org.onlab.onos.of.controller.impl.Role;
30 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
31 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
32 -
33 -public class DummySwitchForTesting implements IOFSwitch {
34 -
35 - protected static final Logger log = LoggerFactory.getLogger(DummySwitchForTesting.class);
36 -
37 - private Channel channel;
38 - private boolean connected = false;
39 - private OFVersion ofv = OFVersion.OF_10;
40 -
41 - private Collection<OFPortDesc> ports;
42 -
43 - private DatapathId datapathId;
44 -
45 - private Set<OFCapabilities> capabilities;
46 -
47 - private int buffers;
48 -
49 - private byte tables;
50 -
51 - private String stringId;
52 -
53 - private Role role;
54 -
55 - @Override
56 - public void disconnectSwitch() {
57 - this.channel.close();
58 - }
59 -
60 - @Override
61 - public void write(OFMessage m) throws IOException {
62 - this.channel.write(m);
63 -
64 - }
65 -
66 - @Override
67 - public void write(List<OFMessage> msglist) throws IOException {
68 - for (OFMessage m : msglist) {
69 - this.channel.write(m);
70 - }
71 -
72 - }
73 -
74 - @Override
75 - public Date getConnectedSince() {
76 - // TODO Auto-generated method stub
77 - return null;
78 - }
79 -
80 - @Override
81 - public int getNextTransactionId() {
82 - return 0;
83 - }
84 -
85 - @Override
86 - public boolean isConnected() {
87 - return this.connected;
88 - }
89 -
90 - @Override
91 - public void setConnected(boolean connected) {
92 - this.connected = connected;
93 -
94 - }
95 -
96 - @Override
97 - public void flush() {
98 - // TODO Auto-generated method stub
99 -
100 - }
101 -
102 - @Override
103 - public void setChannel(Channel channel) {
104 - this.channel = channel;
105 -
106 - }
107 -
108 - @Override
109 - public long getId() {
110 - if (this.stringId == null) {
111 - throw new RuntimeException("Features reply has not yet been set");
112 - }
113 - return this.datapathId.getLong();
114 - }
115 -
116 - @Override
117 - public String getStringId() {
118 - // TODO Auto-generated method stub
119 - return "DummySwitch";
120 - }
121 -
122 - @Override
123 - public int getNumBuffers() {
124 - // TODO Auto-generated method stub
125 - return 0;
126 - }
127 -
128 - @Override
129 - public Set<OFCapabilities> getCapabilities() {
130 - // TODO Auto-generated method stub
131 - return null;
132 - }
133 -
134 - @Override
135 - public byte getNumTables() {
136 - // TODO Auto-generated method stub
137 - return 0;
138 - }
139 -
140 - @Override
141 - public OFDescStatsReply getSwitchDescription() {
142 - // TODO Auto-generated method stub
143 - return null;
144 - }
145 -
146 - @Override
147 - public void cancelFeaturesReply(int transactionId) {
148 - // TODO Auto-generated method stub
149 -
150 - }
151 -
152 - @Override
153 - public Set<OFActionType> getActions() {
154 - // TODO Auto-generated method stub
155 - return null;
156 - }
157 -
158 - @Override
159 - public void setOFVersion(OFVersion version) {
160 - // TODO Auto-generated method stub
161 -
162 - }
163 -
164 - @Override
165 - public OFVersion getOFVersion() {
166 - return this.ofv;
167 - }
168 -
169 - @Override
170 - public Collection<OFPortDesc> getEnabledPorts() {
171 - // TODO Auto-generated method stub
172 - return null;
173 - }
174 -
175 - @Override
176 - public Collection<Integer> getEnabledPortNumbers() {
177 - // TODO Auto-generated method stub
178 - return null;
179 - }
180 -
181 - @Override
182 - public OFPortDesc getPort(int portNumber) {
183 - // TODO Auto-generated method stub
184 - return null;
185 - }
186 -
187 - @Override
188 - public OFPortDesc getPort(String portName) {
189 - // TODO Auto-generated method stub
190 - return null;
191 - }
192 -
193 - @Override
194 - public OrderedCollection<PortChangeEvent> processOFPortStatus(
195 - OFPortStatus ps) {
196 - // TODO Auto-generated method stub
197 - return null;
198 - }
199 -
200 - @Override
201 - public Collection<OFPortDesc> getPorts() {
202 - return ports;
203 - }
204 -
205 - @Override
206 - public boolean portEnabled(int portName) {
207 - // TODO Auto-generated method stub
208 - return false;
209 - }
210 -
211 - @Override
212 - public OrderedCollection<PortChangeEvent> setPorts(
213 - Collection<OFPortDesc> p) {
214 - this.ports = p;
215 - return null;
216 - }
217 -
218 - @Override
219 - public Map<Object, Object> getAttributes() {
220 - return null;
221 - }
222 -
223 - @Override
224 - public boolean hasAttribute(String name) {
225 - // TODO Auto-generated method stub
226 - return false;
227 - }
228 -
229 - @Override
230 - public Object getAttribute(String name) {
231 - return Boolean.FALSE;
232 - }
233 -
234 - @Override
235 - public void setAttribute(String name, Object value) {
236 - // TODO Auto-generated method stub
237 -
238 - }
239 -
240 - @Override
241 - public Object removeAttribute(String name) {
242 - // TODO Auto-generated method stub
243 - return null;
244 - }
245 -
246 - @Override
247 - public void deliverStatisticsReply(OFMessage reply) {
248 - // TODO Auto-generated method stub
249 -
250 - }
251 -
252 - @Override
253 - public void cancelStatisticsReply(int transactionId) {
254 - // TODO Auto-generated method stub
255 -
256 - }
257 -
258 - @Override
259 - public void cancelAllStatisticsReplies() {
260 - // TODO Auto-generated method stub
261 -
262 - }
263 -
264 - @Override
265 - public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
266 - throws IOException {
267 - // TODO Auto-generated method stub
268 - return null;
269 - }
270 -
271 - @Override
272 - public void clearAllFlowMods() {
273 - // TODO Auto-generated method stub
274 -
275 - }
276 -
277 - @Override
278 - public Role getRole() {
279 - return this.role;
280 - }
281 -
282 - @Override
283 - public void setRole(Role role) {
284 - this.role = role;
285 - }
286 -
287 - @Override
288 - public U64 getNextGenerationId() {
289 - // TODO Auto-generated method stub
290 - return null;
291 - }
292 -
293 - @Override
294 - public void setDebugCounterService(IDebugCounterService debugCounter)
295 - throws CounterException {
296 - // TODO Auto-generated method stub
297 -
298 - }
299 -
300 - @Override
301 - public void startDriverHandshake() throws IOException {
302 - // TODO Auto-generated method stub
303 -
304 - }
305 -
306 - @Override
307 - public boolean isDriverHandshakeComplete() {
308 - return true;
309 - }
310 -
311 - @Override
312 - public void processDriverHandshakeMessage(OFMessage m) {
313 -
314 - }
315 -
316 - @Override
317 - public void setTableFull(boolean isFull) {
318 - // TODO Auto-generated method stub
319 -
320 - }
321 -
322 - @Override
323 - public void setFeaturesReply(OFFeaturesReply featuresReply) {
324 - if (featuresReply == null) {
325 - log.error("Error setting featuresReply for switch: {}", getStringId());
326 - return;
327 - }
328 - this.datapathId = featuresReply.getDatapathId();
329 - this.capabilities = featuresReply.getCapabilities();
330 - this.buffers = (int) featuresReply.getNBuffers();
331 - this.tables = (byte) featuresReply.getNTables();
332 - this.stringId = this.datapathId.toString();
333 -
334 - }
335 -
336 - @Override
337 - public void setPortDescReply(OFPortDescStatsReply portDescReply) {
338 - // TODO Auto-generated method stub
339 -
340 - }
341 -
342 - @Override
343 - public void handleMessage(OFMessage m) {
344 - log.info("Got packet {} but I am dumb so I don't know what to do.", m);
345 - }
346 -
347 - @Override
348 - public boolean portEnabled(String portName) {
349 - // TODO Auto-generated method stub
350 - return false;
351 - }
352 -
353 - @Override
354 - public OrderedCollection<PortChangeEvent> comparePorts(
355 - Collection<OFPortDesc> p) {
356 - // TODO Auto-generated method stub
357 - return null;
358 - }
359 -
360 -}
1 -package org.onlab.onos.of.controller.impl.util;
2 -
3 -import java.util.EnumSet;
4 -import java.util.Set;
5 -
6 -/**
7 - * A utility class to convert between integer based bitmaps for (OpenFlow)
8 - * flags and Enum and EnumSet based representations.
9 - *
10 - * The enum used to represent individual flags needs to implement the
11 - * BitmapableEnum interface.
12 - *
13 - * Example:
14 - * {@code
15 - * int bitmap = 0x11; // OFPPC_PORT_DOWN | OFPPC_NO_STP
16 - * EnumSet<OFPortConfig> s = toEnumSet(OFPortConfig.class, bitmap);
17 - * // s will contain OFPPC_PORT_DOWN and OFPPC_NO_STP
18 - * }
19 - *
20 - * {@code
21 - * EnumSet<OFPortConfig> s = EnumSet.of(OFPPC_NO_STP, OFPPC_PORT_DOWN);
22 - * int bitmap = toBitmap(s); // returns 0x11
23 - * }
24 - *
25 - */
26 -public final class EnumBitmaps {
27 -
28 -
29 - private EnumBitmaps() { }
30 -
31 - /**
32 - * Enums used to represent individual flags needs to implement this
33 - * interface.
34 - */
35 - public interface BitmapableEnum {
36 - /** Return the value in the bitmap that the enum constant represents.
37 - * The returned value must have only a single bit set. E.g.,1 << 3
38 - */
39 - int getValue();
40 - }
41 -
42 -
43 - /**
44 - * Convert an integer bitmap to an EnumSet.
45 - *
46 - * See class description for example
47 - * @param type The Enum class to use. Must implement BitmapableEnum
48 - * @param bitmap The integer bitmap
49 - * @return A newly allocated EnumSet representing the bits set in the
50 - * bitmap
51 - * @throws NullPointerException if type is null
52 - * @throws IllegalArgumentException if any enum constant from type has
53 - * more than one bit set.
54 - * @throws IllegalArgumentException if the bitmap has any bits set not
55 - * represented by an enum constant.
56 - */
57 - public static <E extends Enum<E> & BitmapableEnum>
58 - EnumSet<E> toEnumSet(Class<E> type, int bitmap) {
59 - if (type == null) {
60 - throw new NullPointerException("Given enum type must not be null");
61 - }
62 - EnumSet<E> s = EnumSet.noneOf(type);
63 - // allSetBitmap will eventually have all valid bits for the given
64 - // type set.
65 - int allSetBitmap = 0;
66 - for (E element: type.getEnumConstants()) {
67 - if (Integer.bitCount(element.getValue()) != 1) {
68 - String msg = String.format("The %s (%x) constant of the " +
69 - "enum %s is supposed to represent a bitmap entry but " +
70 - "has more than one bit set.",
71 - element.toString(), element.getValue(), type.getName());
72 - throw new IllegalArgumentException(msg);
73 - }
74 - allSetBitmap |= element.getValue();
75 - if ((bitmap & element.getValue()) != 0) {
76 - s.add(element);
77 - }
78 - }
79 - if (((~allSetBitmap) & bitmap) != 0) {
80 - // check if only valid flags are set in the given bitmap
81 - String msg = String.format("The bitmap %x for enum %s has " +
82 - "bits set that are presented by any enum constant",
83 - bitmap, type.getName());
84 - throw new IllegalArgumentException(msg);
85 - }
86 - return s;
87 - }
88 -
89 - /**
90 - * Return the bitmap mask with all possible bits set. E.g., If a bitmap
91 - * has the individual flags 0x1, 0x2, and 0x8 (note the missing 0x4) then
92 - * the mask will be 0xb (1011 binary)
93 - *
94 - * @param type The Enum class to use. Must implement BitmapableEnum
95 - * @throws NullPointerException if type is null
96 - * @throws IllegalArgumentException if any enum constant from type has
97 - * more than one bit set
98 - * @return an integer with all possible bits for the given bitmap enum
99 - * type set.
100 - */
101 - public static <E extends Enum<E> & BitmapableEnum>
102 - int getMask(Class<E> type) {
103 - if (type == null) {
104 - throw new NullPointerException("Given enum type must not be null");
105 - }
106 - // allSetBitmap will eventually have all valid bits for the given
107 - // type set.
108 - int allSetBitmap = 0;
109 - for (E element: type.getEnumConstants()) {
110 - if (Integer.bitCount(element.getValue()) != 1) {
111 - String msg = String.format("The %s (%x) constant of the " +
112 - "enum %s is supposed to represent a bitmap entry but " +
113 - "has more than one bit set.",
114 - element.toString(), element.getValue(), type.getName());
115 - throw new IllegalArgumentException(msg);
116 - }
117 - allSetBitmap |= element.getValue();
118 - }
119 - return allSetBitmap;
120 - }
121 -
122 - /**
123 - * Convert the given EnumSet to the integer bitmap representation.
124 - * @param set The EnumSet to convert. The enum must implement
125 - * BitmapableEnum
126 - * @return the integer bitmap
127 - * @throws IllegalArgumentException if an enum constant from the set (!) has
128 - * more than one bit set
129 - * @throws NullPointerException if the set is null
130 - */
131 - public static <E extends Enum<E> & BitmapableEnum>
132 - int toBitmap(Set<E> set) {
133 - if (set == null) {
134 - throw new NullPointerException("Given set must not be null");
135 - }
136 - int bitmap = 0;
137 - for (E element: set) {
138 - if (Integer.bitCount(element.getValue()) != 1) {
139 - String msg = String.format("The %s (%x) constant in the set " +
140 - "is supposed to represent a bitmap entry but " +
141 - "has more than one bit set.",
142 - element.toString(), element.getValue());
143 - throw new IllegalArgumentException(msg);
144 - }
145 - bitmap |= element.getValue();
146 - }
147 - return bitmap;
148 - }
149 -}
1 -/**
2 - * Copyright 2012, Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl.util;
19 -
20 -import java.util.Iterator;
21 -import java.util.NoSuchElementException;
22 -
23 -/**
24 - * An iterator that will filter values from an iterator and return only
25 - * those values that match the predicate.
26 - */
27 -public abstract class FilterIterator<T> implements Iterator<T> {
28 - protected Iterator<T> subIterator;
29 - protected T next;
30 -
31 - /**
32 - * Construct a filter iterator from the given sub iterator.
33 - *
34 - * @param subIterator the sub iterator over which we'll filter
35 - */
36 - public FilterIterator(Iterator<T> subIterator) {
37 - super();
38 - this.subIterator = subIterator;
39 - }
40 -
41 - /**
42 - * Check whether the given value should be returned by the
43 - * filter.
44 - *
45 - * @param value the value to check
46 - * @return true if the value should be included
47 - */
48 - protected abstract boolean matches(T value);
49 -
50 - // ***********
51 - // Iterator<T>
52 - // ***********
53 -
54 - @Override
55 - public boolean hasNext() {
56 - if (next != null) {
57 - return true;
58 - }
59 -
60 - while (subIterator.hasNext()) {
61 - next = subIterator.next();
62 - if (matches(next)) {
63 - return true;
64 - }
65 - }
66 - next = null;
67 - return false;
68 - }
69 -
70 - @Override
71 - public T next() {
72 - if (hasNext()) {
73 - T cur = next;
74 - next = null;
75 - return cur;
76 - }
77 - throw new NoSuchElementException();
78 - }
79 -
80 - @Override
81 - public void remove() {
82 - throw new UnsupportedOperationException();
83 - }
84 -
85 -}
1 -package org.onlab.onos.of.controller.impl.util;
2 -
3 -import static com.google.common.base.Preconditions.checkNotNull;
4 -import static com.google.common.base.Preconditions.checkArgument;
5 -
6 -/**
7 - * The class representing an ONOS Instance ID.
8 - *
9 - * This class is immutable.
10 - */
11 -public final class InstanceId {
12 - private final String id;
13 -
14 - /**
15 - * Constructor from a string value.
16 - *
17 - * @param id the value to use.
18 - */
19 - public InstanceId(String id) {
20 - this.id = checkNotNull(id);
21 - checkArgument(!id.isEmpty(), "Empty ONOS Instance ID");
22 - }
23 -
24 - @Override
25 - public int hashCode() {
26 - return id.hashCode();
27 - }
28 -
29 - @Override
30 - public boolean equals(Object obj) {
31 - if (obj == this) {
32 - return true;
33 - }
34 -
35 - if (!(obj instanceof InstanceId)) {
36 - return false;
37 - }
38 -
39 - InstanceId that = (InstanceId) obj;
40 - return this.id.equals(that.id);
41 - }
42 -
43 - @Override
44 - public String toString() {
45 - return id;
46 - }
47 -}
1 -/**
2 - * Copyright 2012 Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl.util;
19 -
20 -import java.util.Iterator;
21 -import java.util.NoSuchElementException;
22 -
23 -/**
24 - * Iterator over all values in an iterator of iterators.
25 - *
26 - * @param <T> the type of elements returned by this iterator
27 - */
28 -public class IterableIterator<T> implements Iterator<T> {
29 - Iterator<? extends Iterable<T>> subIterator;
30 - Iterator<T> current = null;
31 -
32 - public IterableIterator(Iterator<? extends Iterable<T>> subIterator) {
33 - super();
34 - this.subIterator = subIterator;
35 - }
36 -
37 - @Override
38 - public boolean hasNext() {
39 - if (current == null) {
40 - if (subIterator.hasNext()) {
41 - current = subIterator.next().iterator();
42 - } else {
43 - return false;
44 - }
45 - }
46 - while (!current.hasNext() && subIterator.hasNext()) {
47 - current = subIterator.next().iterator();
48 - }
49 -
50 - return current.hasNext();
51 - }
52 -
53 - @Override
54 - public T next() {
55 - if (hasNext()) {
56 - return current.next();
57 - }
58 - throw new NoSuchElementException();
59 - }
60 -
61 - @Override
62 - public void remove() {
63 - if (hasNext()) {
64 - current.remove();
65 - }
66 - throw new NoSuchElementException();
67 - }
68 -}
1 -/**
2 - * Copyright 2011, Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl.util;
19 -
20 -import java.util.LinkedHashMap;
21 -import java.util.Map;
22 -
23 -public class LRUHashMap<K, V> extends LinkedHashMap<K, V> {
24 -
25 - private static final long serialVersionUID = 1L;
26 -
27 - private final int capacity;
28 -
29 - public LRUHashMap(int capacity) {
30 - super(capacity + 1, 0.75f, true);
31 - this.capacity = capacity;
32 - }
33 -
34 - protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
35 - return size() > capacity;
36 - }
37 -
38 -}
1 -package org.onlab.onos.of.controller.impl.util;
2 -
3 -import java.util.Collection;
4 -import java.util.LinkedHashSet;
5 -
6 -import com.google.common.collect.ForwardingCollection;
7 -
8 -/**
9 - * A simple wrapper / forwarder that forwards all calls to a LinkedHashSet.
10 - * This wrappers sole reason for existence is to implement the
11 - * OrderedCollection marker interface.
12 - *
13 - */
14 -public class LinkedHashSetWrapper<E>
15 - extends ForwardingCollection<E> implements OrderedCollection<E> {
16 - private final Collection<E> delegate;
17 -
18 - public LinkedHashSetWrapper() {
19 - super();
20 - this.delegate = new LinkedHashSet<E>();
21 - }
22 -
23 - public LinkedHashSetWrapper(Collection<? extends E> c) {
24 - super();
25 - this.delegate = new LinkedHashSet<E>(c);
26 - }
27 -
28 - @Override
29 - protected Collection<E> delegate() {
30 - return this.delegate;
31 - }
32 -}
1 -/**
2 - * Copyright 2012 Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl.util;
19 -
20 -import java.util.Iterator;
21 -import java.util.NoSuchElementException;
22 -
23 -/**
24 - * Iterator over all values in an iterator of iterators.
25 - *
26 - * @param <T> the type of elements returned by this iterator
27 - */
28 -public class MultiIterator<T> implements Iterator<T> {
29 - Iterator<Iterator<T>> subIterator;
30 - Iterator<T> current = null;
31 -
32 - public MultiIterator(Iterator<Iterator<T>> subIterator) {
33 - super();
34 - this.subIterator = subIterator;
35 - }
36 -
37 - @Override
38 - public boolean hasNext() {
39 - if (current == null) {
40 - if (subIterator.hasNext()) {
41 - current = subIterator.next();
42 - } else {
43 - return false;
44 - }
45 - }
46 - while (!current.hasNext() && subIterator.hasNext()) {
47 - current = subIterator.next();
48 - }
49 -
50 - return current.hasNext();
51 - }
52 -
53 - @Override
54 - public T next() {
55 - if (hasNext()) {
56 - return current.next();
57 - }
58 - throw new NoSuchElementException();
59 - }
60 -
61 - @Override
62 - public void remove() {
63 - if (hasNext()) {
64 - current.remove();
65 - }
66 - throw new NoSuchElementException();
67 - }
68 -}
1 -package org.onlab.onos.of.controller.impl.util;
2 -
3 -import java.util.Collection;
4 -
5 -/**
6 - * A marker interface indicating that this Collection defines a particular
7 - * iteration order. The details about the iteration order are specified by
8 - * the concrete implementation.
9 - *
10 - * @param <E>
11 - */
12 -public interface OrderedCollection<E> extends Collection<E> {
13 -
14 -}
1 -/**
2 - * Copyright 2011, Big Switch Networks, Inc.
3 - * Originally created by David Erickson, Stanford University
4 - *
5 - * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 - * not use this file except in compliance with the License. You may obtain
7 - * a copy of the License at
8 - *
9 - * http://www.apache.org/licenses/LICENSE-2.0
10 - *
11 - * Unless required by applicable law or agreed to in writing, software
12 - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 - * License for the specific language governing permissions and limitations
15 - * under the License.
16 - **/
17 -
18 -package org.onlab.onos.of.controller.impl.internal;
19 -
20 -import junit.framework.TestCase;
21 -import org.onlab.onos.of.controller.impl.IOFSwitch;
22 -
23 -import org.easymock.EasyMock;
24 -import org.junit.After;
25 -import org.junit.Before;
26 -import org.junit.Test;
27 -
28 -
29 -public class ControllerTest extends TestCase {
30 -
31 - private Controller controller;
32 - private IOFSwitch sw;
33 - private OFChannelHandler h;
34 -
35 - @Override
36 - @Before
37 - public void setUp() throws Exception {
38 - super.setUp();
39 - sw = EasyMock.createMock(IOFSwitch.class);
40 - h = EasyMock.createMock(OFChannelHandler.class);
41 - controller = new Controller();
42 - ControllerRunThread t = new ControllerRunThread();
43 - t.start();
44 - /*
45 - * Making sure the thread is properly started before making calls
46 - * to controller class.
47 - */
48 - Thread.sleep(200);
49 - }
50 -
51 - /**
52 - * Starts the base mocks used in these tests.
53 - */
54 - private void startMocks() {
55 - EasyMock.replay(sw, h);
56 - }
57 -
58 - /**
59 - * Reset the mocks to a known state.
60 - * Automatically called after tests.
61 - */
62 - @After
63 - private void resetMocks() {
64 - EasyMock.reset(sw);
65 - }
66 -
67 - /**
68 - * Fetches the controller instance.
69 - * @return the controller
70 - */
71 - public Controller getController() {
72 - return controller;
73 - }
74 -
75 - /**
76 - * Run the controller's main loop so that updates are processed.
77 - */
78 - protected class ControllerRunThread extends Thread {
79 - @Override
80 - public void run() {
81 - controller.openFlowPort = 0; // Don't listen
82 - controller.activate();
83 - }
84 - }
85 -
86 - /**
87 - * Verify that we are able to add a switch that just connected.
88 - * If it already exists then this should fail
89 - *
90 - * @throws Exception error
91 - */
92 - @Test
93 - public void testAddConnectedSwitches() throws Exception {
94 - startMocks();
95 - assertTrue(controller.addConnectedSwitch(0, h));
96 - assertFalse(controller.addConnectedSwitch(0, h));
97 - }
98 -
99 - /**
100 - * Add active master but cannot re-add active master.
101 - * @throws Exception an error occurred.
102 - */
103 - @Test
104 - public void testAddActivatedMasterSwitch() throws Exception {
105 - startMocks();
106 - controller.addConnectedSwitch(0, h);
107 - assertTrue(controller.addActivatedMasterSwitch(0, sw));
108 - assertFalse(controller.addActivatedMasterSwitch(0, sw));
109 - }
110 -
111 - /**
112 - * Tests that an activated switch can be added but cannot be re-added.
113 - *
114 - * @throws Exception an error occurred
115 - */
116 - @Test
117 - public void testAddActivatedEqualSwitch() throws Exception {
118 - startMocks();
119 - controller.addConnectedSwitch(0, h);
120 - assertTrue(controller.addActivatedEqualSwitch(0, sw));
121 - assertFalse(controller.addActivatedEqualSwitch(0, sw));
122 - }
123 -
124 - /**
125 - * Move an equal switch to master.
126 - * @throws Exception an error occurred
127 - */
128 - @Test
129 - public void testTranstitionToMaster() throws Exception {
130 - startMocks();
131 - controller.addConnectedSwitch(0, h);
132 - controller.addActivatedEqualSwitch(0, sw);
133 - controller.transitionToMasterSwitch(0);
134 - assertNotNull(controller.getMasterSwitch(0));
135 - }
136 -
137 - /**
138 - * Transition a master switch to equal state.
139 - * @throws Exception an error occurred
140 - */
141 - @Test
142 - public void testTranstitionToEqual() throws Exception {
143 - startMocks();
144 - controller.addConnectedSwitch(0, h);
145 - controller.addActivatedMasterSwitch(0, sw);
146 - controller.transitionToEqualSwitch(0);
147 - assertNotNull(controller.getEqualSwitch(0));
148 - }
149 -
150 - /**
151 - * Remove the switch from the controller instance.
152 - * @throws Exception an error occurred
153 - */
154 - @Test
155 - public void testRemoveSwitch() throws Exception {
156 - sw.cancelAllStatisticsReplies();
157 - EasyMock.expectLastCall().once();
158 - sw.setConnected(false);
159 - EasyMock.expectLastCall().once();
160 - startMocks();
161 - controller.addConnectedSwitch(0, h);
162 - controller.addActivatedMasterSwitch(0, sw);
163 - controller.removeConnectedSwitch(0);
164 - assertNull(controller.getSwitch(0));
165 - EasyMock.verify(sw, h);
166 - }
167 -}
1 -package org.onlab.onos.of.controller.impl.internal;
2 -
3 -import static org.easymock.EasyMock.capture;
4 -import static org.easymock.EasyMock.createMock;
5 -import static org.easymock.EasyMock.expect;
6 -import static org.easymock.EasyMock.expectLastCall;
7 -import static org.easymock.EasyMock.replay;
8 -import static org.easymock.EasyMock.reset;
9 -import static org.easymock.EasyMock.verify;
10 -import static org.junit.Assert.assertEquals;
11 -import static org.junit.Assert.assertFalse;
12 -import static org.junit.Assert.assertTrue;
13 -
14 -import java.io.IOException;
15 -import java.util.ArrayList;
16 -import java.util.Collections;
17 -import java.util.HashSet;
18 -import java.util.List;
19 -import java.util.Set;
20 -
21 -import org.onlab.onos.of.controller.impl.IOFSwitch;
22 -import org.onlab.onos.of.controller.impl.Role;
23 -import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter;
24 -import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
25 -import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.RoleRecvStatus;
26 -
27 -import org.easymock.Capture;
28 -import org.easymock.CaptureType;
29 -import org.jboss.netty.channel.Channel;
30 -import org.jboss.netty.channel.ChannelHandlerContext;
31 -import org.jboss.netty.channel.ChannelPipeline;
32 -import org.jboss.netty.channel.ChannelStateEvent;
33 -import org.jboss.netty.channel.ExceptionEvent;
34 -import org.jboss.netty.channel.MessageEvent;
35 -import org.junit.After;
36 -import org.junit.Before;
37 -import org.junit.Test;
38 -import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
39 -import org.projectfloodlight.openflow.protocol.OFExperimenter;
40 -import org.projectfloodlight.openflow.protocol.OFFactories;
41 -import org.projectfloodlight.openflow.protocol.OFFactory;
42 -import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
43 -import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
44 -import org.projectfloodlight.openflow.protocol.OFHelloElem;
45 -import org.projectfloodlight.openflow.protocol.OFMessage;
46 -import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
47 -import org.projectfloodlight.openflow.protocol.OFPacketIn;
48 -import org.projectfloodlight.openflow.protocol.OFPacketInReason;
49 -import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
50 -import org.projectfloodlight.openflow.protocol.OFSetConfig;
51 -import org.projectfloodlight.openflow.protocol.OFStatsReply;
52 -import org.projectfloodlight.openflow.protocol.OFStatsRequest;
53 -import org.projectfloodlight.openflow.protocol.OFStatsType;
54 -import org.projectfloodlight.openflow.protocol.OFType;
55 -import org.projectfloodlight.openflow.protocol.OFVersion;
56 -import org.projectfloodlight.openflow.types.DatapathId;
57 -import org.projectfloodlight.openflow.types.U32;
58 -
59 -/**
60 - * Channel handler deals with the switch connection and dispatches
61 - * switch messages to the appropriate locations. These Unit Testing cases
62 - * test the channeler state machine and role changer. In the first release,
63 - * we will focus on OF version 1.0. we will add the testing case for
64 - * version 1.3 later.
65 - */
66 -public class OFChannelHandlerTest {
67 - private Controller controller;
68 - private IDebugCounterService debugCounterService;
69 - private OFChannelHandler handler;
70 - private Channel channel;
71 - private ChannelHandlerContext ctx;
72 - private MessageEvent messageEvent;
73 - private ChannelStateEvent channelStateEvent;
74 - private ChannelPipeline pipeline;
75 - private Capture<ExceptionEvent> exceptionEventCapture;
76 - private Capture<List<OFMessage>> writeCapture;
77 - private OFFeaturesReply featuresReply;
78 - private Set<Integer> seenXids = null;
79 - private IOFSwitch swImplBase;
80 - private OFVersion ofVersion = OFVersion.OF_10;
81 - private OFFactory factory13;
82 - private OFFactory factory10;
83 - private OFFactory factory;
84 -
85 - @Before
86 - public void setUp() throws Exception {
87 - controller = createMock(Controller.class);
88 - ctx = createMock(ChannelHandlerContext.class);
89 - channelStateEvent = createMock(ChannelStateEvent.class);
90 - channel = createMock(Channel.class);
91 - messageEvent = createMock(MessageEvent.class);
92 - exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
93 - pipeline = createMock(ChannelPipeline.class);
94 - writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
95 - swImplBase = createMock(IOFSwitch.class);
96 - seenXids = null;
97 - factory13 = OFFactories.getFactory(OFVersion.OF_13);
98 - factory10 = OFFactories.getFactory(OFVersion.OF_10);
99 - factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
100 -
101 - // TODO: should mock IDebugCounterService and make sure
102 - // the expected counters are updated.
103 - debugCounterService = new DebugCounter();
104 - Controller.Counters counters =
105 - new Controller.Counters();
106 - counters.createCounters(debugCounterService);
107 - expect(controller.getCounters()).andReturn(counters).anyTimes();
108 - expect(controller.getOFMessageFactory10()).andReturn(factory10)
109 - .anyTimes();
110 - expect(controller.getOFMessageFactory13()).andReturn(factory13)
111 - .anyTimes();
112 - expect(controller.addConnectedSwitch(2000, handler)).andReturn(true)
113 - .anyTimes();
114 - replay(controller);
115 - handler = new OFChannelHandler(controller);
116 - verify(controller);
117 - reset(controller);
118 -
119 - resetChannel();
120 -
121 - // replay controller. Reset it if you need more specific behavior
122 - replay(controller);
123 -
124 - // replay switch. Reset it if you need more specific behavior
125 - replay(swImplBase);
126 -
127 - // Mock ctx and channelStateEvent
128 - expect(ctx.getChannel()).andReturn(channel).anyTimes();
129 - expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
130 - replay(ctx, channelStateEvent);
131 -
132 - /* Setup an exception event capture on the channel. Right now
133 - * we only expect exception events to be send up the channel.
134 - * However, it's easy to extend to other events if we need it
135 - */
136 - pipeline.sendUpstream(capture(exceptionEventCapture));
137 - expectLastCall().anyTimes();
138 - replay(pipeline);
139 - featuresReply = (OFFeaturesReply) buildOFMessage(OFType.FEATURES_REPLY);
140 - }
141 -
142 - @After
143 - public void tearDown() {
144 - /* ensure no exception was thrown */
145 - if (exceptionEventCapture.hasCaptured()) {
146 - Throwable ex = exceptionEventCapture.getValue().getCause();
147 - throw new AssertionError("Unexpected exception: " +
148 - ex.getClass().getName() + "(" + ex + ")");
149 - }
150 - assertFalse("Unexpected messages have been captured",
151 - writeCapture.hasCaptured());
152 - // verify all mocks.
153 - verify(channel);
154 - verify(messageEvent);
155 - verify(controller);
156 - verify(ctx);
157 - verify(channelStateEvent);
158 - verify(pipeline);
159 - verify(swImplBase);
160 -
161 - }
162 -
163 - /**
164 - * Reset the channel mock and set basic method call expectations.
165 - *
166 - **/
167 - void resetChannel() {
168 - reset(channel);
169 - expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
170 - expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
171 - }
172 -
173 - /**
174 - * reset, setup, and replay the messageEvent mock for the given
175 - * messages.
176 - */
177 - void setupMessageEvent(List<OFMessage> messages) {
178 - reset(messageEvent);
179 - expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
180 - replay(messageEvent);
181 - }
182 -
183 - /**
184 - * reset, setup, and replay the messageEvent mock for the given
185 - * messages, mock controller send message to channel handler.
186 - *
187 - * This method will reset, start replay on controller, and then verify
188 - */
189 - void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
190 - throws Exception {
191 - verify(controller);
192 - reset(controller);
193 -
194 - sendMessageToHandlerNoControllerReset(messages);
195 - }
196 -
197 - /**
198 - * reset, setup, and replay the messageEvent mock for the given
199 - * messages, mock controller send message to channel handler.
200 - *
201 - * This method will start replay on controller, and then verify
202 - */
203 - void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
204 - throws Exception {
205 - setupMessageEvent(messages);
206 -
207 - expect(controller.addConnectedSwitch(1000, handler))
208 - .andReturn(true).anyTimes();
209 - replay(controller);
210 -
211 - handler.messageReceived(ctx, messageEvent);
212 - verify(controller);
213 - }
214 -
215 - /**
216 - * Extract the list of OFMessages that was captured by the Channel.write()
217 - * capture. Will check that something was actually captured first. We'll
218 - * collapse the messages from multiple writes into a single list of
219 - * OFMessages.
220 - * Resets the channelWriteCapture.
221 - */
222 - List<OFMessage> getMessagesFromCapture() {
223 - List<OFMessage> msgs = new ArrayList<OFMessage>();
224 -
225 - assertTrue("No write on channel was captured",
226 - writeCapture.hasCaptured());
227 - List<List<OFMessage>> capturedVals = writeCapture.getValues();
228 -
229 - for (List<OFMessage> oneWriteList: capturedVals) {
230 - msgs.addAll(oneWriteList);
231 - }
232 - writeCapture.reset();
233 - return msgs;
234 - }
235 -
236 -
237 - /**
238 - * Verify that the given exception event capture (as returned by
239 - * getAndInitExceptionCapture) has thrown an exception of the given
240 - * expectedExceptionClass.
241 - * Resets the capture
242 - */
243 - void verifyExceptionCaptured(
244 - Class<? extends Throwable> expectedExceptionClass) {
245 - assertTrue("Excpected exception not thrown",
246 - exceptionEventCapture.hasCaptured());
247 - Throwable caughtEx = exceptionEventCapture.getValue().getCause();
248 - assertEquals(expectedExceptionClass, caughtEx.getClass());
249 - exceptionEventCapture.reset();
250 - }
251 -
252 - /**
253 - * Make sure that the transaction ids in the given messages are
254 - * not 0 and differ between each other.
255 - * While it's not a defect per se if the xids are we want to ensure
256 - * we use different ones for each message we send.
257 - */
258 - void verifyUniqueXids(List<OFMessage> msgs) {
259 - if (seenXids == null) {
260 - seenXids = new HashSet<Integer>();
261 - }
262 - for (OFMessage m: msgs) {
263 - int xid = (int) m.getXid();
264 - assertTrue("Xid in messags is 0", xid != 0);
265 - assertFalse("Xid " + xid + " has already been used",
266 - seenXids.contains(xid));
267 - seenXids.add(xid);
268 - }
269 - }
270 -
271 -
272 -
273 - public void testInitState() throws Exception {
274 - OFMessage m = buildOFMessage(OFType.HELLO);
275 -
276 - expect(messageEvent.getMessage()).andReturn(null);
277 - replay(channel, messageEvent);
278 -
279 - // We don't expect to receive /any/ messages in init state since
280 - // channelConnected moves us to a different state
281 - sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
282 -
283 - verifyExceptionCaptured(SwitchStateException.class);
284 - assertEquals(OFChannelHandler.ChannelState.INIT,
285 - handler.getStateForTesting());
286 - }
287 -
288 - /**
289 - * move the channel from scratch to WAIT_HELLO state.
290 - *
291 - */
292 - @Test
293 - public void moveToWaitHello() throws Exception {
294 - resetChannel();
295 - channel.write(capture(writeCapture));
296 - expectLastCall().andReturn(null).once();
297 - replay(channel);
298 - // replay unused mocks
299 - replay(messageEvent);
300 -
301 - handler.channelConnected(ctx, channelStateEvent);
302 -
303 - List<OFMessage> msgs = getMessagesFromCapture();
304 - assertEquals(1, msgs.size());
305 - assertEquals(OFType.HELLO, msgs.get(0).getType());
306 - assertEquals(OFChannelHandler.ChannelState.WAIT_HELLO,
307 - handler.getStateForTesting());
308 - //Should verify that the Hello received from the controller
309 - //is ALWAYS OF1.3 hello regardless of the switch version
310 - assertEquals(OFVersion.OF_13, msgs.get(0).getVersion());
311 - verifyUniqueXids(msgs);
312 - }
313 -
314 -
315 - /**
316 - * Move the channel from scratch to WAIT_FEATURES_REPLY state.
317 - * Builds on moveToWaitHello().
318 - * adds testing for WAIT_HELLO state.
319 - */
320 - @Test
321 - public void moveToWaitFeaturesReply() throws Exception {
322 - moveToWaitHello();
323 - resetChannel();
324 - channel.write(capture(writeCapture));
325 - expectLastCall().andReturn(null).atLeastOnce();
326 - replay(channel);
327 -
328 - OFMessage hello = buildOFMessage(OFType.HELLO);
329 - sendMessageToHandlerWithControllerReset(Collections.singletonList(hello));
330 -
331 - List<OFMessage> msgs = getMessagesFromCapture();
332 - assertEquals(1, msgs.size());
333 - assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
334 - if (ofVersion == OFVersion.OF_10) {
335 - assertEquals(OFVersion.OF_10, msgs.get(0).getVersion());
336 - }
337 - verifyUniqueXids(msgs);
338 -
339 - assertEquals(OFChannelHandler.ChannelState.WAIT_FEATURES_REPLY,
340 - handler.getStateForTesting());
341 - }
342 -
343 - /**
344 - * Move the channel from scratch to WAIT_CONFIG_REPLY state.
345 - * Builds on moveToWaitFeaturesReply.
346 - * adds testing for WAIT_FEATURES_REPLY state.
347 - */
348 - @Test
349 - public void moveToWaitConfigReply() throws Exception {
350 - moveToWaitFeaturesReply();
351 -
352 - resetChannel();
353 - channel.write(capture(writeCapture));
354 - expectLastCall().andReturn(null).atLeastOnce();
355 - replay(channel);
356 -
357 - sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));
358 - List<OFMessage> msgs = getMessagesFromCapture();
359 - assertEquals(3, msgs.size());
360 - assertEquals(OFType.SET_CONFIG, msgs.get(0).getType());
361 - OFSetConfig sc = (OFSetConfig) msgs.get(0);
362 - assertEquals((short) 0xffff, sc.getMissSendLen());
363 - assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType());
364 - assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType());
365 - verifyUniqueXids(msgs);
366 - assertEquals(OFChannelHandler.ChannelState.WAIT_CONFIG_REPLY,
367 - handler.getStateForTesting());
368 - }
369 -
370 - /**
371 - * Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state.
372 - * Builds on moveToWaitConfigReply().
373 - * adds testing for WAIT_CONFIG_REPLY state.
374 - */
375 - @Test
376 - public void moveToWaitDescriptionStatReply() throws Exception {
377 - moveToWaitConfigReply();
378 - resetChannel();
379 - channel.write(capture(writeCapture));
380 - expectLastCall().andReturn(null).atLeastOnce();
381 - replay(channel);
382 -
383 - OFGetConfigReply cr = (OFGetConfigReply) buildOFMessage(OFType.GET_CONFIG_REPLY);
384 -
385 - sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(cr));
386 -
387 - List<OFMessage> msgs = getMessagesFromCapture();
388 - assertEquals(1, msgs.size());
389 - assertEquals(OFType.STATS_REQUEST, msgs.get(0).getType());
390 - OFStatsRequest<?> sr = (OFStatsRequest<?>) msgs.get(0);
391 - assertEquals(OFStatsType.DESC, sr.getStatsType());
392 - verifyUniqueXids(msgs);
393 - assertEquals(OFChannelHandler.ChannelState.WAIT_DESCRIPTION_STAT_REPLY,
394 - handler.getStateForTesting());
395 - }
396 -
397 -
398 - private OFStatsReply createDescriptionStatsReply() throws IOException {
399 - OFStatsReply sr = (OFStatsReply) buildOFMessage(OFType.STATS_REPLY);
400 - return sr;
401 - }
402 -
403 - /**
404 - * Move the channel from scratch to WAIT_INITIAL_ROLE state.
405 - * for a switch that does not have a sub-handshake.
406 - * Builds on moveToWaitDescriptionStatReply().
407 - * adds testing for WAIT_DESCRIPTION_STAT_REPLY state.
408 - *
409 - */
410 - @Test
411 - public void moveToWaitInitialRole()
412 - throws Exception {
413 - moveToWaitDescriptionStatReply();
414 -
415 - long xid = 2000;
416 -
417 - // build the stats reply
418 - OFStatsReply sr = createDescriptionStatsReply();
419 -
420 - resetChannel();
421 - replay(channel);
422 -
423 - setupMessageEvent(Collections.<OFMessage>singletonList(sr));
424 -
425 - // mock controller
426 - reset(controller);
427 - reset(swImplBase);
428 -
429 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
430 - .andReturn(swImplBase).anyTimes();
431 - expect(controller.getDebugCounter())
432 - .andReturn(debugCounterService).anyTimes();
433 - controller.submitRegistryRequest(1000);
434 - expectLastCall().once();
435 - replay(controller);
436 -
437 - //TODO: With the description stats message you are sending in the test,
438 - //you will end up with an OFSwitchImplBase object
439 - //which by default does NOT support the nicira role messages.
440 - //If you wish to test the case where Nicira role messages are supported,
441 - //then make a comment here that states that this is different
442 - //from the default behavior of switchImplbase /or/
443 - //send the right desc-stats (for example send what is expected from OVS 1.0)
444 -
445 - if (ofVersion == OFVersion.OF_10) {
446 - expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
447 - .andReturn(true).once();
448 -
449 - swImplBase.write(capture(writeCapture));
450 - expectLastCall().anyTimes();
451 - }
452 -
453 - swImplBase.setOFVersion(ofVersion);
454 - expectLastCall().once();
455 - swImplBase.setConnected(true);
456 - expectLastCall().once();
457 - swImplBase.setChannel(channel);
458 - expectLastCall().once();
459 - swImplBase.setDebugCounterService(controller.getDebugCounter());
460 - expectLastCall().once();
461 - expect(swImplBase.getStringId())
462 - .andReturn(null).anyTimes();
463 - swImplBase.setRole(Role.EQUAL);
464 - expectLastCall().once();
465 -
466 - expect(swImplBase.getNextTransactionId())
467 - .andReturn((int) xid).anyTimes();
468 - expect(swImplBase.getId())
469 - .andReturn(1000L).once();
470 -
471 - swImplBase.setFeaturesReply(featuresReply);
472 - expectLastCall().once();
473 - swImplBase.setPortDescReply((OFPortDescStatsReply) null);
474 - replay(swImplBase);
475 -
476 - // send the description stats reply
477 - handler.messageReceived(ctx, messageEvent);
478 -
479 - List<OFMessage> msgs = getMessagesFromCapture();
480 - assertEquals(1, msgs.size());
481 - assertEquals(OFType.EXPERIMENTER, msgs.get(0).getType());
482 - verifyNiciraMessage((OFExperimenter) msgs.get(0));
483 -
484 - verify(controller);
485 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
486 - handler.getStateForTesting());
487 - }
488 -
489 - /**
490 - * Move the channel from scratch to.
491 - * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
492 - * Builds on moveToWaitInitialRole().
493 - */
494 - @Test
495 - public void moveToWaitSubHandshake()
496 - throws Exception {
497 - moveToWaitInitialRole();
498 -
499 - int xid = 2000;
500 - resetChannel();
501 - replay(channel);
502 -
503 - reset(swImplBase);
504 - // Set the role
505 - setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);
506 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
507 - handler.getStateForTesting());
508 -
509 - // build the stats reply
510 - OFStatsReply sr = createDescriptionStatsReply();
511 - OFMessage rr = getRoleReply(xid, Role.SLAVE);
512 - setupMessageEvent(Collections.<OFMessage>singletonList(rr));
513 -
514 - // mock controller
515 - reset(controller);
516 - reset(swImplBase);
517 -
518 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
519 - .andReturn(swImplBase).anyTimes();
520 - expect(controller.getDebugCounter())
521 - .andReturn(debugCounterService).anyTimes();
522 -
523 - replay(controller);
524 -
525 - expect(swImplBase.getStringId())
526 - .andReturn(null).anyTimes();
527 - swImplBase.setRole(Role.SLAVE);
528 - expectLastCall().once();
529 - expect(swImplBase.getNextTransactionId())
530 - .andReturn(xid).anyTimes();
531 - swImplBase.startDriverHandshake();
532 - expectLastCall().once();
533 -
534 - //when this flag is false, state machine will move to
535 - //WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state
536 - expect(swImplBase.isDriverHandshakeComplete())
537 - .andReturn(false).once();
538 -
539 - replay(swImplBase);
540 -
541 - // send the description stats reply
542 - handler.messageReceived(ctx, messageEvent);
543 -
544 - assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
545 - handler.getStateForTesting());
546 - }
547 -
548 - /**
549 - * Move the channel from scratch to WAIT_INITIAL_ROLE state,
550 - * then move the channel to EQUAL state based on the switch Role.
551 - * This test basically test the switch with role support.
552 - * Builds on moveToWaitInitialRole().
553 - *
554 - * In WAIT_INITIAL_ROLE state, when any messages (except ECHO_REQUEST
555 - * and PORT_STATUS), state machine will transit to MASTER or
556 - * EQUAL state based on the switch role.
557 - */
558 - @Test
559 - public void moveToSlaveWithHandshakeComplete()
560 - throws Exception {
561 -
562 - moveToWaitInitialRole();
563 -
564 - int xid = 2000;
565 - resetChannel();
566 - replay(channel);
567 -
568 - reset(swImplBase);
569 - // Set the role
570 - setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);
571 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
572 - handler.getStateForTesting());
573 -
574 - // build the stats reply
575 - OFStatsReply sr = createDescriptionStatsReply();
576 - OFMessage rr = getRoleReply(xid, Role.SLAVE);
577 - setupMessageEvent(Collections.<OFMessage>singletonList(rr));
578 -
579 - // mock controller
580 - reset(controller);
581 - reset(swImplBase);
582 -
583 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
584 - .andReturn(swImplBase).anyTimes();
585 -
586 - expect(controller.getDebugCounter())
587 - .andReturn(debugCounterService).anyTimes();
588 -
589 - expect(controller.addActivatedEqualSwitch(1000, swImplBase))
590 - .andReturn(true).once();
591 - replay(controller);
592 -
593 - expect(swImplBase.getStringId())
594 - .andReturn(null).anyTimes();
595 - //consult the role in sw to determine the next state.
596 - //in this testing case, we are testing that channel handler
597 - // will move to EQUAL state when switch role is in SLAVE.
598 - expect(swImplBase.getRole()).andReturn(Role.SLAVE).once();
599 - swImplBase.setRole(Role.SLAVE);
600 - expectLastCall().once();
601 -
602 - expect(swImplBase.getNextTransactionId())
603 - .andReturn(xid).anyTimes();
604 - expect(swImplBase.getId())
605 - .andReturn(1000L).once();
606 - swImplBase.startDriverHandshake();
607 - expectLastCall().once();
608 -
609 - //when this flag is true, don't need to move interim state
610 - //WAIT_SWITCH_DRIVER_SUB_HANDSHAKE. channel handler will
611 - //move to corresponding state after consulting the role in sw
612 - //This is essentially the same test as the one above,
613 - //except for this line
614 - expect(swImplBase.isDriverHandshakeComplete())
615 - .andReturn(true).once();
616 -
617 - replay(swImplBase);
618 -
619 - // send the description stats reply
620 - handler.messageReceived(ctx, messageEvent);
621 -
622 - assertEquals(OFChannelHandler.ChannelState.EQUAL,
623 - handler.getStateForTesting());
624 - }
625 -
626 - /**
627 - * Move the channel from scratch to WAIT_INITIAL_ROLE state,
628 - * then to MASTERL state based on the switch Role.
629 - * This test basically test the switch with role support.
630 - * Builds on moveToWaitInitialRole().
631 - *
632 - * In WAIT_INITIAL_ROLE state, when any messages (except ECHO_REQUEST
633 - * and PORT_STATUS), state machine will transit to MASTER or
634 - * EQUAL state based on the switch role.
635 - */
636 - @Test
637 - public void moveToMasterWithHandshakeComplete()
638 - throws Exception {
639 -
640 - moveToWaitInitialRole();
641 -
642 - int xid = 2000;
643 - resetChannel();
644 - replay(channel);
645 -
646 - reset(swImplBase);
647 - // Set the role
648 - setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
649 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
650 - handler.getStateForTesting());
651 -
652 - // build the stats reply
653 - OFStatsReply sr = createDescriptionStatsReply();
654 - OFMessage rr = getRoleReply(xid, Role.MASTER);
655 - setupMessageEvent(Collections.<OFMessage>singletonList(rr));
656 -
657 - // mock controller
658 - reset(controller);
659 - reset(swImplBase);
660 -
661 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
662 - .andReturn(swImplBase).anyTimes();
663 -
664 - expect(controller.getDebugCounter())
665 - .andReturn(debugCounterService).anyTimes();
666 -
667 - expect(controller.addActivatedMasterSwitch(1000, swImplBase))
668 - .andReturn(true).once();
669 - replay(controller);
670 -
671 - expect(swImplBase.getStringId())
672 - .andReturn(null).anyTimes();
673 - expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
674 - swImplBase.setRole(Role.MASTER);
675 - expectLastCall().once();
676 -
677 - expect(swImplBase.getNextTransactionId())
678 - .andReturn(xid).anyTimes();
679 - expect(swImplBase.getId())
680 - .andReturn(1000L).once();
681 - swImplBase.startDriverHandshake();
682 - expectLastCall().once();
683 - expect(swImplBase.isDriverHandshakeComplete())
684 - .andReturn(true).once();
685 -
686 - replay(swImplBase);
687 -
688 -
689 - // send the description stats reply
690 - handler.messageReceived(ctx, messageEvent);
691 -
692 - assertEquals(OFChannelHandler.ChannelState.MASTER,
693 - handler.getStateForTesting());
694 - }
695 -
696 - /**
697 - * Move the channel from scratch to
698 - * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
699 - * Builds on moveToWaitSubHandshake().
700 - */
701 - @Test
702 - public void moveToEqualViaWaitSubHandshake()
703 - throws Exception {
704 - moveToWaitSubHandshake();
705 -
706 - long xid = 2000;
707 - resetChannel();
708 - replay(channel);
709 -
710 - // build the stats reply
711 - OFStatsReply sr = createDescriptionStatsReply();
712 -
713 - setupMessageEvent(Collections.<OFMessage>singletonList(sr));
714 -
715 - // mock controller
716 - reset(controller);
717 - reset(swImplBase);
718 -
719 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
720 - .andReturn(swImplBase).anyTimes();
721 - expect(controller.getDebugCounter())
722 - .andReturn(debugCounterService).anyTimes();
723 -
724 - expect(controller.addActivatedEqualSwitch(1000, swImplBase))
725 - .andReturn(true).once();
726 - replay(controller);
727 -
728 - expect(swImplBase.getStringId())
729 - .andReturn(null).anyTimes();
730 - expect(swImplBase.getRole()).andReturn(Role.SLAVE).once();
731 - expect(swImplBase.getNextTransactionId())
732 - .andReturn((int) xid).anyTimes();
733 - expect(swImplBase.getId())
734 - .andReturn(1000L).once();
735 -
736 - swImplBase.processDriverHandshakeMessage(sr);
737 - expectLastCall().once();
738 - expect(swImplBase.isDriverHandshakeComplete())
739 - .andReturn(true).once();
740 -
741 - replay(swImplBase);
742 -
743 - // send the description stats reply
744 - handler.messageReceived(ctx, messageEvent);
745 -
746 - assertEquals(OFChannelHandler.ChannelState.EQUAL,
747 - handler.getStateForTesting());
748 - }
749 -
750 - /**
751 - * Move the channel from scratch to
752 - * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
753 - * Builds on moveToWaitSubHandshake().
754 - */
755 - @Test
756 - public void moveToMasterViaWaitSubHandshake()
757 - throws Exception {
758 - moveToWaitSubHandshake();
759 -
760 - long xid = 2000;
761 - resetChannel();
762 - replay(channel);
763 -
764 - // In this state, any messages except echo request, port status and
765 - // error go to the switch sub driver handshake. Once the switch reports
766 - // that its sub driver handshake is complete (#isDriverHandshakeComplete
767 - // return true) then the channel handle consults the switch role and
768 - // moves the state machine to the appropriate state (MASTER or EQUALS).
769 - // In this test we expect the state machine to end up in MASTER state.
770 - OFStatsReply sr = createDescriptionStatsReply();
771 -
772 - setupMessageEvent(Collections.<OFMessage>singletonList(sr));
773 -
774 - // mock controller
775 - reset(controller);
776 - reset(swImplBase);
777 -
778 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
779 - .andReturn(swImplBase).anyTimes();
780 -
781 - expect(controller.getDebugCounter())
782 - .andReturn(debugCounterService).anyTimes();
783 - expect(controller.addActivatedMasterSwitch(1000, swImplBase))
784 - .andReturn(true).once();
785 - replay(controller);
786 -
787 - expect(swImplBase.getStringId())
788 - .andReturn(null).anyTimes();
789 - expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
790 - expect(swImplBase.getNextTransactionId())
791 - .andReturn((int) xid).anyTimes();
792 - expect(swImplBase.getId())
793 - .andReturn(1000L).once();
794 -
795 - swImplBase.processDriverHandshakeMessage(sr);
796 - expectLastCall().once();
797 - expect(swImplBase.isDriverHandshakeComplete())
798 - .andReturn(true).once();
799 -
800 - replay(swImplBase);
801 -
802 - // send the description stats reply
803 - handler.messageReceived(ctx, messageEvent);
804 - verify(controller);
805 - assertEquals(OFChannelHandler.ChannelState.MASTER,
806 - handler.getStateForTesting());
807 - }
808 -
809 - /**
810 - * Test the behavior in WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state.
811 - * ECHO_REQUEST message received case.
812 - */
813 - @Test
814 - public void testWaitSwitchDriverSubhandshake() throws Exception {
815 - moveToWaitSubHandshake();
816 -
817 - long xid = 2000;
818 - resetChannel();
819 - channel.write(capture(writeCapture));
820 - expectLastCall().andReturn(null).atLeastOnce();
821 - replay(channel);
822 -
823 - OFMessage er = buildOFMessage(OFType.ECHO_REQUEST);
824 -
825 - setupMessageEvent(Collections.<OFMessage>singletonList(er));
826 -
827 - // mock controller
828 - reset(controller);
829 - reset(swImplBase);
830 -
831 - expect(controller.getOFMessageFactory10()).andReturn(factory10);
832 - expect(controller.getDebugCounter())
833 - .andReturn(debugCounterService).anyTimes();
834 -
835 - replay(controller);
836 -
837 - expect(swImplBase.getStringId())
838 - .andReturn(null).anyTimes();
839 - expect(swImplBase.getNextTransactionId())
840 - .andReturn((int) xid).anyTimes();
841 -
842 - replay(swImplBase);
843 -
844 - handler.messageReceived(ctx, messageEvent);
845 -
846 - List<OFMessage> msgs = getMessagesFromCapture();
847 - assertEquals(1, msgs.size());
848 - assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
849 - verifyUniqueXids(msgs);
850 - assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
851 - handler.getStateForTesting());
852 - }
853 -
854 - /**
855 - * Helper.
856 - * Verify that the given OFMessage is a correct Nicira RoleRequest message.
857 - */
858 - private void verifyNiciraMessage(OFExperimenter ofMessage) {
859 -
860 - int vendor = (int) ofMessage.getExperimenter();
861 - assertEquals(vendor, 0x2320); // magic number representing nicira
862 - }
863 -
864 - /**
865 - * Setup the mock switch and write capture for a role request, set the
866 - * role and verify mocks.
867 - * @param supportsNxRole whether the switch supports role request messages
868 - * to setup the attribute. This must be null (don't yet know if roles
869 - * supported: send to check) or true.
870 - * @param xid The xid to use in the role request
871 - * @param role The role to send
872 - * @throws IOException
873 - */
874 - private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole,
875 - int xid,
876 - Role role) throws IOException {
877 -
878 - RoleRecvStatus expectation = RoleRecvStatus.MATCHED_SET_ROLE;
879 -
880 - expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
881 - .andReturn(supportsNxRole).atLeastOnce();
882 -
883 - if (supportsNxRole != null && supportsNxRole) {
884 - expect(swImplBase.getNextTransactionId()).andReturn(xid).once();
885 - swImplBase.write(capture(writeCapture));
886 - expectLastCall().anyTimes();
887 - }
888 - replay(swImplBase);
889 -
890 - handler.sendRoleRequest(role, expectation);
891 -
892 - if (supportsNxRole != null && supportsNxRole) {
893 - List<OFMessage> msgs = getMessagesFromCapture();
894 - assertEquals(1, msgs.size());
895 - verifyNiciraMessage((OFExperimenter) msgs.get(0));
896 - }
897 - }
898 -
899 - /**
900 - * Setup the mock switch for a role change request where the switch
901 - * does not support roles.
902 - *
903 - * Needs to verify and reset the controller since we need to set
904 - * an expectation
905 - */
906 - private void setupSwitchRoleChangeUnsupported(int xid,
907 - Role role) {
908 - boolean supportsNxRole = false;
909 - RoleRecvStatus expectation = RoleRecvStatus.NO_REPLY;
910 - reset(swImplBase);
911 - expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
912 - .andReturn(supportsNxRole).atLeastOnce();
913 - // TODO: hmmm. While it's not incorrect that we set the attribute
914 - // again it looks odd. Maybe change
915 - swImplBase.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole);
916 - expectLastCall().anyTimes();
917 -
918 - replay(swImplBase);
919 -
920 - handler.sendRoleRequest(role, expectation);
921 -
922 - verify(swImplBase);
923 - }
924 -
925 - /*
926 - * Return a Nicira RoleReply message for the given role.
927 - */
928 - private OFMessage getRoleReply(long xid, Role role) {
929 -
930 - OFNiciraControllerRole nr = null;
931 -
932 - switch(role) {
933 - case MASTER:
934 - nr = OFNiciraControllerRole.ROLE_MASTER;
935 - break;
936 - case EQUAL:
937 - nr = OFNiciraControllerRole.ROLE_SLAVE;
938 - break;
939 - case SLAVE:
940 - nr = OFNiciraControllerRole.ROLE_SLAVE;
941 - break;
942 - default: //handled below
943 - }
944 - OFMessage m = factory10.buildNiciraControllerRoleReply()
945 - .setRole(nr)
946 - .setXid(xid)
947 - .build();
948 - return m;
949 - }
950 -
951 - /**
952 - * Move the channel from scratch to MASTER state.
953 - * Builds on moveToWaitInitialRole().
954 - * adds testing for WAIT_INITAL_ROLE state.
955 - *
956 - * This method tests the case that the switch does NOT support roles.
957 - * In ONOS if the switch-driver says that nicira-role messages are not
958 - * supported, then ONOS does NOT send role-request messages
959 - * (see handleUnsentRoleMessage())
960 - */
961 - @Test
962 - public void testInitialMoveToMasterNoRole() throws Exception {
963 - int xid = 43;
964 - // first, move us to WAIT_INITIAL_ROLE_STATE
965 -
966 - moveToWaitInitialRole();
967 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
968 - handler.getStateForTesting());
969 -
970 - OFStatsReply sr = createDescriptionStatsReply();
971 -
972 - reset(controller);
973 - reset(swImplBase);
974 -
975 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
976 - .andReturn(swImplBase).anyTimes();
977 -
978 - expect(controller.getDebugCounter())
979 - .andReturn(debugCounterService).anyTimes();
980 -
981 - expect(controller.addActivatedMasterSwitch(1000, swImplBase))
982 - .andReturn(true).once();
983 - replay(controller);
984 -
985 - reset(swImplBase);
986 - swImplBase.setRole(Role.MASTER);
987 - expectLastCall().once();
988 - swImplBase.startDriverHandshake();
989 - expectLastCall().once();
990 - expect(swImplBase.isDriverHandshakeComplete())
991 - .andReturn(true).once();
992 - expect(swImplBase.getStringId())
993 - .andReturn(null).anyTimes();
994 - expect(swImplBase.getRole()).andReturn(Role.MASTER).once();
995 -
996 - expect(swImplBase.getId())
997 - .andReturn(1000L).once();
998 - // Set the role
999 - setupSwitchSendRoleRequestAndVerify(false, xid, Role.MASTER);
1000 -
1001 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1002 - handler.getStateForTesting());
1003 - }
1004 -
1005 - /**
1006 - * Move the channel from scratch to WAIT_INITIAL_ROLE state.
1007 - * Builds on moveToWaitInitialRole().
1008 - * adds testing for WAIT_INITAL_ROLE state
1009 - *
1010 - * We let the initial role request time out. Role support should be
1011 - * disabled but the switch should be activated.
1012 - */
1013 - /* TBD
1014 - @Test
1015 - public void testInitialMoveToMasterTimeout() throws Exception {
1016 - int timeout = 50;
1017 - handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
1018 - int xid = 4343;
1019 -
1020 - // first, move us to WAIT_INITIAL_ROLE_STATE
1021 -
1022 - moveToWaitInitialRole();
1023 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1024 - handler.getStateForTesting());
1025 -
1026 - // prepare mocks and inject the role reply message
1027 - reset(swImplBase);
1028 - // Set the role
1029 - swImplBase.setRole(Role.MASTER);
1030 - expectLastCall().once();
1031 - swImplBase.startDriverHandshake();
1032 - expectLastCall().once();
1033 - expect(swImplBase.isDriverHandshakeComplete())
1034 - .andReturn(false).once();
1035 - if (ofVersion == OFVersion.OF_10) {
1036 - expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
1037 - .andReturn(true).once();
1038 -
1039 - swImplBase.write(capture(writeCapture),
1040 - EasyMock.<FloodlightContext>anyObject());
1041 - expectLastCall().anyTimes();
1042 - }
1043 - expect(swImplBase.getNextTransactionId()).andReturn(xid).once();
1044 -
1045 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1046 - handler.getStateForTesting());
1047 -
1048 - // Set the role
1049 - setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
1050 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1051 - handler.getStateForTesting());
1052 -
1053 - OFMessage m = buildOFMessage(OFType.ECHO_REPLY);
1054 -
1055 - setupMessageEvent(Collections.<OFMessage>singletonList(m));
1056 -
1057 - Thread.sleep(timeout+5);
1058 -
1059 - verify(controller);
1060 - reset(controller);
1061 -
1062 - expect(controller.addActivatedMasterSwitch(1000, swImplBase))
1063 - .andReturn(true).once();
1064 - controller.flushAll();
1065 - expectLastCall().once();
1066 -
1067 - replay(controller);
1068 -
1069 - handler.messageReceived(ctx, messageEvent);
1070 -
1071 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1072 - handler.getStateForTesting());
1073 -
1074 - }
1075 -
1076 - */
1077 - /**
1078 - * Move the channel from scratch to SLAVE state.
1079 - * Builds on doMoveToWaitInitialRole().
1080 - * adds testing for WAIT_INITAL_ROLE state
1081 - *
1082 - * This method tests the case that the switch does NOT support roles.
1083 - * The channel handler still needs to send the initial request to find
1084 - * out that whether the switch supports roles.
1085 - *
1086 - */
1087 - @Test
1088 - public void testInitialMoveToSlaveNoRole() throws Exception {
1089 - int xid = 44;
1090 - // first, move us to WAIT_INITIAL_ROLE_STATE
1091 - moveToWaitInitialRole();
1092 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1093 - handler.getStateForTesting());
1094 -
1095 - reset(swImplBase);
1096 - // Set the role
1097 - setupSwitchSendRoleRequestAndVerify(false, xid, Role.SLAVE);
1098 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1099 - handler.getStateForTesting());
1100 -
1101 - }
1102 -
1103 - /**
1104 - * Move the channel from scratch to SLAVE state.
1105 - * Builds on doMoveToWaitInitialRole().
1106 - * adds testing for WAIT_INITAL_ROLE state
1107 - *
1108 - * We let the initial role request time out. The switch should be
1109 - * disconnected
1110 - */
1111 - /* TBD
1112 - @Test
1113 - public void testInitialMoveToSlaveTimeout() throws Exception {
1114 - int timeout = 50;
1115 - handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
1116 - int xid = 4444;
1117 -
1118 - // first, move us to WAIT_INITIAL_ROLE_STATE
1119 - moveToWaitInitialRole();
1120 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1121 - handler.getStateForTesting());
1122 -
1123 - // Set the role
1124 - setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
1125 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1126 - handler.getStateForTesting());
1127 -
1128 - // prepare mocks and inject the role reply message
1129 - reset(sw);
1130 - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
1131 - expectLastCall().once();
1132 - sw.setRole(Role.SLAVE);
1133 - expectLastCall().once();
1134 - sw.disconnectSwitch(); // Make sure we disconnect
1135 - expectLastCall().once();
1136 - replay(sw);
1137 -
1138 - OFMessage m = buildOFMessage(OFType.ECHO_REPLY);
1139 -
1140 - Thread.sleep(timeout+5);
1141 -
1142 - sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
1143 - }
1144 -
1145 - */
1146 - /**
1147 - * Move channel from scratch to WAIT_INITIAL_STATE, then MASTER,
1148 - * then SLAVE for cases where the switch does not support roles.
1149 - * I.e., the final SLAVE transition should disconnect the switch.
1150 - */
1151 - @Test
1152 - public void testNoRoleInitialToMasterToSlave() throws Exception {
1153 - int xid = 46;
1154 - reset(swImplBase);
1155 - replay(swImplBase);
1156 -
1157 - reset(controller);
1158 - replay(controller);
1159 -
1160 - // First, lets move the state to MASTER without role support
1161 - testInitialMoveToMasterNoRole();
1162 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1163 - handler.getStateForTesting());
1164 -
1165 - // try to set master role again. should be a no-op
1166 - setupSwitchRoleChangeUnsupported(xid, Role.MASTER);
1167 -
1168 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1169 - handler.getStateForTesting());
1170 -
1171 - setupSwitchRoleChangeUnsupported(xid, Role.SLAVE);
1172 - //switch does not support role message. there is no role set
1173 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1174 - handler.getStateForTesting());
1175 -
1176 - }
1177 -
1178 - /**
1179 - * Move the channel to MASTER state.
1180 - * Expects that the channel is in MASTER or SLAVE state.
1181 - *
1182 - */
1183 - public void changeRoleToMasterWithRequest() throws Exception {
1184 - int xid = 4242;
1185 -
1186 - assertTrue("This method can only be called when handler is in " +
1187 - "MASTER or SLAVE role", handler.isHandshakeComplete());
1188 -
1189 - reset(swImplBase);
1190 - reset(controller);
1191 - // Set the role
1192 - setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
1193 -
1194 - // prepare mocks and inject the role reply message
1195 -
1196 - reset(controller);
1197 - expect(controller.addActivatedMasterSwitch(1000, swImplBase))
1198 - .andReturn(true).once();
1199 - OFMessage reply = getRoleReply(xid, Role.MASTER);
1200 -
1201 - // sendMessageToHandler will verify and rest controller mock
1202 -
1203 - OFStatsReply sr = createDescriptionStatsReply();
1204 - setupMessageEvent(Collections.<OFMessage>singletonList(reply));
1205 -
1206 - // mock controller
1207 - reset(controller);
1208 - reset(swImplBase);
1209 -
1210 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
1211 - .andReturn(swImplBase).anyTimes();
1212 -
1213 - expect(controller.getDebugCounter())
1214 - .andReturn(debugCounterService).anyTimes();
1215 - controller.transitionToMasterSwitch(1000);
1216 - expectLastCall().once();
1217 -
1218 - replay(controller);
1219 -
1220 - expect(swImplBase.getStringId())
1221 - .andReturn(null).anyTimes();
1222 - expect(swImplBase.getRole()).andReturn(Role.EQUAL).atLeastOnce();
1223 - expect(swImplBase.getNextTransactionId())
1224 - .andReturn(xid).anyTimes();
1225 - expect(swImplBase.getId())
1226 - .andReturn(1000L).once();
1227 -
1228 - swImplBase.setRole(Role.MASTER);
1229 - expectLastCall().once();
1230 - replay(swImplBase);
1231 -
1232 - // send the description stats reply
1233 - handler.messageReceived(ctx, messageEvent);
1234 -
1235 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1236 - handler.getStateForTesting());
1237 - }
1238 -
1239 - /**
1240 - * Move the channel to SLAVE state.
1241 - * Expects that the channel is in MASTER or SLAVE state.
1242 - *
1243 - */
1244 - public void changeRoleToSlaveWithRequest() throws Exception {
1245 - int xid = 2323;
1246 -
1247 - assertTrue("This method can only be called when handler is in " +
1248 - "MASTER or SLAVE role", handler.isHandshakeComplete());
1249 -
1250 - // Set the role
1251 - reset(controller);
1252 - reset(swImplBase);
1253 -
1254 - swImplBase.write(capture(writeCapture));
1255 - expectLastCall().anyTimes();
1256 -
1257 - expect(swImplBase.getNextTransactionId())
1258 - .andReturn(xid).anyTimes();
1259 -
1260 -
1261 - if (ofVersion == OFVersion.OF_10) {
1262 - expect(swImplBase.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
1263 - .andReturn(true).once();
1264 -
1265 - swImplBase.write(capture(writeCapture));
1266 - expectLastCall().anyTimes();
1267 - }
1268 - replay(swImplBase);
1269 -
1270 - handler.sendRoleRequest(Role.SLAVE, RoleRecvStatus.MATCHED_SET_ROLE);
1271 -
1272 - List<OFMessage> msgs = getMessagesFromCapture();
1273 - assertEquals(1, msgs.size());
1274 - verifyNiciraMessage((OFExperimenter) msgs.get(0));
1275 -
1276 -
1277 - OFMessage reply = getRoleReply(xid, Role.SLAVE);
1278 - OFStatsReply sr = createDescriptionStatsReply();
1279 - setupMessageEvent(Collections.<OFMessage>singletonList(reply));
1280 -
1281 - // mock controller
1282 - reset(controller);
1283 - reset(swImplBase);
1284 -
1285 - controller.transitionToEqualSwitch(1000);
1286 - expectLastCall().once();
1287 - expect(controller.getOFSwitchInstance((OFDescStatsReply) sr, ofVersion))
1288 - .andReturn(swImplBase).anyTimes();
1289 -
1290 - expect(controller.getDebugCounter())
1291 - .andReturn(debugCounterService).anyTimes();
1292 -
1293 - replay(controller);
1294 -
1295 - expect(swImplBase.getStringId())
1296 - .andReturn(null).anyTimes();
1297 - expect(swImplBase.getRole()).andReturn(Role.MASTER).atLeastOnce();
1298 - expect(swImplBase.getNextTransactionId())
1299 - .andReturn(xid).anyTimes();
1300 -
1301 - // prepare mocks and inject the role reply message
1302 - swImplBase.setRole(Role.SLAVE);
1303 - expectLastCall().once();
1304 - expect(swImplBase.getId())
1305 - .andReturn(1000L).once();
1306 - replay(swImplBase);
1307 -
1308 - handler.messageReceived(ctx, messageEvent);
1309 -
1310 - assertEquals(OFChannelHandler.ChannelState.EQUAL,
1311 - handler.getStateForTesting());
1312 - }
1313 -
1314 - @Test
1315 - public void testMultiRoleChange1() throws Exception {
1316 - moveToMasterWithHandshakeComplete();
1317 - changeRoleToMasterWithRequest();
1318 - changeRoleToSlaveWithRequest();
1319 - changeRoleToSlaveWithRequest();
1320 - changeRoleToMasterWithRequest();
1321 - changeRoleToSlaveWithRequest();
1322 - }
1323 -
1324 - @Test
1325 - public void testMultiRoleChange2() throws Exception {
1326 - moveToSlaveWithHandshakeComplete();
1327 - changeRoleToMasterWithRequest();
1328 - changeRoleToSlaveWithRequest();
1329 - changeRoleToSlaveWithRequest();
1330 - changeRoleToMasterWithRequest();
1331 - changeRoleToSlaveWithRequest();
1332 - }
1333 -
1334 - /**
1335 - * Start from scratch and reply with an unexpected error to the role
1336 - * change request.
1337 - * Builds on doMoveToWaitInitialRole()
1338 - * adds testing for WAIT_INITAL_ROLE state
1339 - */
1340 - /* TBD
1341 - @Test
1342 - public void testInitialRoleChangeOtherError() throws Exception {
1343 - int xid = 4343;
1344 - // first, move us to WAIT_INITIAL_ROLE_STATE
1345 - moveToWaitInitialRole();
1346 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1347 - handler.getStateForTesting());
1348 -
1349 - reset(swImplBase);
1350 - // Set the role
1351 - setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
1352 - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
1353 - handler.getStateForTesting());
1354 -
1355 -
1356 - // FIXME: shouldn't use ordinal(), but OFError is broken
1357 -
1358 - OFMessage err = factory.errorMsgs().buildBadActionErrorMsg()
1359 - .setCode(OFBadActionCode.BAD_LEN)
1360 - .setXid(2000)
1361 - .build();
1362 - verify(swImplBase);
1363 - reset(swImplBase);
1364 - replay(swImplBase);
1365 - sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
1366 -
1367 - verifyExceptionCaptured(SwitchStateException.class);
1368 - }
1369 - */
1370 - /**
1371 - * Test dispatch of messages while in MASTER role.
1372 - */
1373 - @Test
1374 - public void testMessageDispatchMaster() throws Exception {
1375 -
1376 - moveToMasterWithHandshakeComplete();
1377 -
1378 - // Send packet in. expect dispatch
1379 - OFPacketIn pi = (OFPacketIn)
1380 - buildOFMessage(OFType.PACKET_IN);
1381 - setupMessageEvent(Collections.<OFMessage>singletonList(pi));
1382 -
1383 - reset(swImplBase);
1384 - swImplBase.handleMessage(pi);
1385 - expectLastCall().once();
1386 - replay(swImplBase);
1387 - // send the description stats reply
1388 - handler.messageReceived(ctx, messageEvent);
1389 -
1390 - assertEquals(OFChannelHandler.ChannelState.MASTER,
1391 - handler.getStateForTesting());
1392 -
1393 - verify(controller);
1394 - // TODO: many more to go
1395 - }
1396 -
1397 - /**
1398 - * Test port status message handling while MASTER.
1399 - *
1400 - */
1401 - /* Patrick: TBD
1402 - @Test
1403 - public void testPortStatusMessageMaster() throws Exception {
1404 - long dpid = featuresReply.getDatapathId().getLong();
1405 - testInitialMoveToMasterWithRole();
1406 - List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
1407 - // A dummy port.
1408 - OFPortDesc p = factory.buildPortDesc()
1409 - .setName("Eth1")
1410 - .setPortNo(OFPort.ofInt(1))
1411 - .build();
1412 - ports.add(p);
1413 -
1414 - p.setName("Port1");
1415 - p.setPortNumber((short)1);
1416 -
1417 - OFPortStatus ps = (OFPortStatus)buildOFMessage(OFType.PORT_STATUS);
1418 - ps.setDesc(p);
1419 -
1420 - // The events we expect sw.handlePortStatus to return
1421 - // We'll just use the same list for all valid OFPortReasons and add
1422 - // arbitrary events for arbitrary ports that are not necessarily
1423 - // related to the port status message. Our goal
1424 - // here is not to return the correct set of events but the make sure
1425 - // that a) sw.handlePortStatus is called
1426 - // b) the list of events sw.handlePortStatus returns is sent
1427 - // as IOFSwitchListener notifications.
1428 - OrderedCollection<PortChangeEvent> events =
1429 - new LinkedHashSetWrapper<PortChangeEvent>();
1430 - ImmutablePort p1 = ImmutablePort.create("eth1", (short)1);
1431 - ImmutablePort p2 = ImmutablePort.create("eth2", (short)2);
1432 - ImmutablePort p3 = ImmutablePort.create("eth3", (short)3);
1433 - ImmutablePort p4 = ImmutablePort.create("eth4", (short)4);
1434 - ImmutablePort p5 = ImmutablePort.create("eth5", (short)5);
1435 - events.add(new PortChangeEvent(p1, PortChangeType.ADD));
1436 - events.add(new PortChangeEvent(p2, PortChangeType.DELETE));
1437 - events.add(new PortChangeEvent(p3, PortChangeType.UP));
1438 - events.add(new PortChangeEvent(p4, PortChangeType.DOWN));
1439 - events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE));
1440 -
1441 -
1442 - for (OFPortReason reason: OFPortReason.values()) {
1443 - ps.setReason(reason.getReasonCode());
1444 -
1445 - reset(sw);
1446 - expect(sw.getId()).andReturn(dpid).anyTimes();
1447 -
1448 - expect(sw.processOFPortStatus(ps)).andReturn(events).once();
1449 - replay(sw);
1450 -
1451 - reset(controller);
1452 - controller.notifyPortChanged(sw, p1, PortChangeType.ADD);
1453 - controller.notifyPortChanged(sw, p2, PortChangeType.DELETE);
1454 - controller.notifyPortChanged(sw, p3, PortChangeType.UP);
1455 - controller.notifyPortChanged(sw, p4, PortChangeType.DOWN);
1456 - controller.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE);
1457 - sendMessageToHandlerNoControllerReset(
1458 - Collections.<OFMessage>singletonList(ps));
1459 - verify(sw);
1460 - verify(controller);
1461 - }
1462 - }
1463 -
1464 - */
1465 - /**
1466 - * Build an OF message.
1467 - * @throws IOException
1468 - */
1469 - private OFMessage buildOFMessage(OFType t) throws IOException {
1470 - OFMessage m = null;
1471 - switch (t) {
1472 -
1473 - case HELLO:
1474 - // The OF protocol requires us to start things off by sending the highest
1475 - // version of the protocol supported.
1476 -
1477 - // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
1478 - // see Sec. 7.5.1 of the OF1.3.4 spec
1479 - if (ofVersion == OFVersion.OF_13) {
1480 - U32 bitmap = U32.ofRaw(0x00000012);
1481 - OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
1482 - .setBitmaps(Collections.singletonList(bitmap))
1483 - .build();
1484 - m = factory13.buildHello()
1485 - .setXid(2000)
1486 - .setElements(Collections.singletonList(hem))
1487 - .build();
1488 - } else {
1489 - m = factory10.buildHello()
1490 - .setXid(2000)
1491 - .build();
1492 - }
1493 - break;
1494 - case FEATURES_REQUEST:
1495 - m = factory.buildFeaturesRequest()
1496 - .setXid(2000)
1497 - .build();
1498 - break;
1499 - case FEATURES_REPLY:
1500 -
1501 - m = factory.buildFeaturesReply()
1502 - .setDatapathId(DatapathId.of(1000L))
1503 - .setXid(2000)
1504 - .build();
1505 - break;
1506 - case SET_CONFIG:
1507 - m = factory.buildSetConfig()
1508 - .setMissSendLen((short) 0xffff)
1509 - .setXid(2000)
1510 - .build();
1511 - break;
1512 - case BARRIER_REQUEST:
1513 - m = factory.buildBarrierRequest()
1514 - .setXid(2000)
1515 - .build();
1516 - break;
1517 - case GET_CONFIG_REQUEST:
1518 - m = factory.buildGetConfigRequest()
1519 - .setXid(2000)
1520 - .build();
1521 - break;
1522 - case GET_CONFIG_REPLY:
1523 - m = factory.buildGetConfigReply()
1524 - .setMissSendLen((short) 0xffff)
1525 - .setXid(2000)
1526 - .build();
1527 - break;
1528 - case STATS_REQUEST:
1529 - break;
1530 - case STATS_REPLY:
1531 - m = factory.buildDescStatsReply()
1532 - .setDpDesc("Datapath Description")
1533 - .setHwDesc("Hardware Secription")
1534 - .setMfrDesc("Manufacturer Desctiption")
1535 - .setSerialNum("Serial Number")
1536 - .setSwDesc("Software Desription")
1537 - .build();
1538 - break;
1539 - case ECHO_REQUEST:
1540 - m = factory.buildEchoRequest()
1541 - .setXid(2000)
1542 - .build();
1543 - break;
1544 - case FLOW_REMOVED:
1545 - break;
1546 -
1547 - case PACKET_IN:
1548 - m = factory.buildPacketIn()
1549 - .setReason(OFPacketInReason.NO_MATCH)
1550 - .setTotalLen(1500)
1551 - .setXid(2000)
1552 - .build();
1553 - break;
1554 - case PORT_STATUS:
1555 - m = factory.buildPortStatus()
1556 - .setXid(2000)
1557 - .build();
1558 - break;
1559 -
1560 - default:
1561 - m = factory.buildFeaturesRequest()
1562 - .setXid(2000)
1563 - .build();
1564 - break;
1565 - }
1566 -
1567 - return (m);
1568 - }
1569 -}