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 | +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.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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/DebugCounter.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/IDebugCounter.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/debugcounter/NullDebugCounter.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
0 → 100644
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 | } | ... | ... |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
0 → 100644
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 | +//}; |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/ControllerRegistryEntry.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/IControllerRegistry.java
deleted
100644 → 0
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 | - |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/registry/RegistryException.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/DummySwitchForTesting.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/IterableIterator.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/LinkedHashSetWrapper.java
deleted
100644 → 0
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 | -} |
of/ctl/src/main/java/org/onlab/onos/of/controller/impl/util/OrderedCollection.java
deleted
100644 → 0
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 | -} |
of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/ControllerTest.java
deleted
100644 → 0
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 | -} |
of/ctl/src/test/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandlerTest.java
deleted
100644 → 0
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 | -} |
-
Please register or login to post a comment