Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
12 changed files
with
191 additions
and
126 deletions
1 | package org.onlab.onos.mastership; | 1 | package org.onlab.onos.mastership; |
2 | 2 | ||
3 | -import org.onlab.onos.cluster.NodeId; | ||
4 | import org.onlab.onos.cluster.RoleInfo; | 3 | import org.onlab.onos.cluster.RoleInfo; |
5 | import org.onlab.onos.event.AbstractEvent; | 4 | import org.onlab.onos.event.AbstractEvent; |
6 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
... | @@ -56,19 +55,6 @@ public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceI | ... | @@ -56,19 +55,6 @@ public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceI |
56 | } | 55 | } |
57 | 56 | ||
58 | /** | 57 | /** |
59 | - * Returns the NodeID of the node associated with the event. | ||
60 | - * For MASTER_CHANGED this is the newly elected master, and for | ||
61 | - * BACKUPS_CHANGED, this is the node that was newly added, removed, or | ||
62 | - * whose position was changed in the list. | ||
63 | - * | ||
64 | - * @return node ID as a subject | ||
65 | - */ | ||
66 | - //XXX to-be removed - or keep for convenience? | ||
67 | - public NodeId node() { | ||
68 | - return roleInfo.master(); | ||
69 | - } | ||
70 | - | ||
71 | - /** | ||
72 | * Returns the current role state for the subject. | 58 | * Returns the current role state for the subject. |
73 | * | 59 | * |
74 | * @return RoleInfo associated with Device ID subject | 60 | * @return RoleInfo associated with Device ID subject | ... | ... |
1 | package org.onlab.onos.store.cluster.messaging; | 1 | package org.onlab.onos.store.cluster.messaging; |
2 | 2 | ||
3 | +import java.util.concurrent.Future; | ||
3 | import java.util.concurrent.TimeUnit; | 4 | import java.util.concurrent.TimeUnit; |
4 | import java.util.concurrent.TimeoutException; | 5 | import java.util.concurrent.TimeoutException; |
5 | 6 | ||
6 | import org.onlab.onos.cluster.NodeId; | 7 | import org.onlab.onos.cluster.NodeId; |
7 | 8 | ||
8 | -public interface ClusterMessageResponse { | 9 | +public interface ClusterMessageResponse extends Future<byte[]> { |
10 | + | ||
9 | public NodeId sender(); | 11 | public NodeId sender(); |
10 | - public byte[] get(long timeout, TimeUnit timeunit) throws TimeoutException; | 12 | + |
11 | - public byte[] get(long timeout) throws InterruptedException; | 13 | + // TODO InterruptedException, ExecutionException removed from original |
14 | + // Future declaration. Revisit if we ever need those. | ||
15 | + @Override | ||
16 | + public byte[] get(long timeout, TimeUnit unit) throws TimeoutException; | ||
17 | + | ||
12 | } | 18 | } | ... | ... |
... | @@ -227,10 +227,14 @@ implements MastershipService, MastershipAdminService { | ... | @@ -227,10 +227,14 @@ implements MastershipService, MastershipAdminService { |
227 | if (clusterService.getNodes().size() > (clusterSize.intValue() / 2)) { | 227 | if (clusterService.getNodes().size() > (clusterSize.intValue() / 2)) { |
228 | return true; | 228 | return true; |
229 | } | 229 | } |
230 | - //else { | 230 | +// else { |
231 | //FIXME: break tie for equal-sized clusters, by number of | 231 | //FIXME: break tie for equal-sized clusters, by number of |
232 | // connected switches, then masters, then nodeId hash | 232 | // connected switches, then masters, then nodeId hash |
233 | - // } | 233 | + // problem is, how do we get at channel info cleanly here? |
234 | + // Also, what's the time hit for a distributed store look-up | ||
235 | + // versus channel re-negotiation? bet on the latter being worse. | ||
236 | + | ||
237 | +// } | ||
234 | return false; | 238 | return false; |
235 | } | 239 | } |
236 | 240 | ... | ... |
... | @@ -4,9 +4,9 @@ import static com.google.common.base.Preconditions.checkArgument; | ... | @@ -4,9 +4,9 @@ import static com.google.common.base.Preconditions.checkArgument; |
4 | 4 | ||
5 | import java.io.IOException; | 5 | import java.io.IOException; |
6 | import java.util.Set; | 6 | import java.util.Set; |
7 | +import java.util.concurrent.ExecutionException; | ||
7 | import java.util.concurrent.TimeUnit; | 8 | import java.util.concurrent.TimeUnit; |
8 | import java.util.concurrent.TimeoutException; | 9 | import java.util.concurrent.TimeoutException; |
9 | - | ||
10 | import org.apache.felix.scr.annotations.Activate; | 10 | import org.apache.felix.scr.annotations.Activate; |
11 | import org.apache.felix.scr.annotations.Component; | 11 | import org.apache.felix.scr.annotations.Component; |
12 | import org.apache.felix.scr.annotations.Deactivate; | 12 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -181,10 +181,13 @@ public class ClusterCommunicationManager | ... | @@ -181,10 +181,13 @@ public class ClusterCommunicationManager |
181 | } | 181 | } |
182 | } | 182 | } |
183 | 183 | ||
184 | - private static final class InternalClusterMessageResponse implements ClusterMessageResponse { | 184 | + private static final class InternalClusterMessageResponse |
185 | + implements ClusterMessageResponse { | ||
185 | 186 | ||
186 | private final NodeId sender; | 187 | private final NodeId sender; |
187 | private final Response responseFuture; | 188 | private final Response responseFuture; |
189 | + private volatile boolean isCancelled = false; | ||
190 | + private volatile boolean isDone = false; | ||
188 | 191 | ||
189 | public InternalClusterMessageResponse(NodeId sender, Response responseFuture) { | 192 | public InternalClusterMessageResponse(NodeId sender, Response responseFuture) { |
190 | this.sender = sender; | 193 | this.sender = sender; |
... | @@ -198,12 +201,39 @@ public class ClusterCommunicationManager | ... | @@ -198,12 +201,39 @@ public class ClusterCommunicationManager |
198 | @Override | 201 | @Override |
199 | public byte[] get(long timeout, TimeUnit timeunit) | 202 | public byte[] get(long timeout, TimeUnit timeunit) |
200 | throws TimeoutException { | 203 | throws TimeoutException { |
201 | - return responseFuture.get(timeout, timeunit); | 204 | + final byte[] result = responseFuture.get(timeout, timeunit); |
205 | + isDone = true; | ||
206 | + return result; | ||
207 | + } | ||
208 | + | ||
209 | + @Override | ||
210 | + public boolean cancel(boolean mayInterruptIfRunning) { | ||
211 | + if (isDone()) { | ||
212 | + return false; | ||
213 | + } | ||
214 | + // doing nothing for now | ||
215 | + // when onlab.netty Response support cancel, call them. | ||
216 | + isCancelled = true; | ||
217 | + return true; | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public boolean isCancelled() { | ||
222 | + return isCancelled; | ||
223 | + } | ||
224 | + | ||
225 | + @Override | ||
226 | + public boolean isDone() { | ||
227 | + return this.isDone || isCancelled(); | ||
202 | } | 228 | } |
203 | 229 | ||
204 | @Override | 230 | @Override |
205 | - public byte[] get(long timeout) throws InterruptedException { | 231 | + public byte[] get() throws InterruptedException, ExecutionException { |
206 | - return responseFuture.get(); | 232 | + // TODO: consider forbidding this call and force the use of timed get |
233 | + // to enforce handling of remote peer failure scenario | ||
234 | + final byte[] result = responseFuture.get(); | ||
235 | + isDone = true; | ||
236 | + return result; | ||
207 | } | 237 | } |
208 | } | 238 | } |
209 | } | 239 | } | ... | ... |
... | @@ -86,7 +86,7 @@ public class ReplicaInfoManager implements ReplicaInfoService { | ... | @@ -86,7 +86,7 @@ public class ReplicaInfoManager implements ReplicaInfoService { |
86 | final List<NodeId> standbyList = Collections.<NodeId>emptyList(); | 86 | final List<NodeId> standbyList = Collections.<NodeId>emptyList(); |
87 | eventDispatcher.post(new ReplicaInfoEvent(MASTER_CHANGED, | 87 | eventDispatcher.post(new ReplicaInfoEvent(MASTER_CHANGED, |
88 | event.subject(), | 88 | event.subject(), |
89 | - new ReplicaInfo(event.node(), standbyList))); | 89 | + new ReplicaInfo(event.roleInfo().master(), standbyList))); |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ... | ... |
... | @@ -4,6 +4,7 @@ import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects. | ... | @@ -4,6 +4,7 @@ import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects. |
4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
5 | 5 | ||
6 | import com.google.common.collect.ImmutableSet; | 6 | import com.google.common.collect.ImmutableSet; |
7 | + | ||
7 | import org.apache.felix.scr.annotations.Activate; | 8 | import org.apache.felix.scr.annotations.Activate; |
8 | import org.apache.felix.scr.annotations.Component; | 9 | import org.apache.felix.scr.annotations.Component; |
9 | import org.apache.felix.scr.annotations.Deactivate; | 10 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -26,9 +27,9 @@ import org.onlab.onos.store.flow.ReplicaInfo; | ... | @@ -26,9 +27,9 @@ import org.onlab.onos.store.flow.ReplicaInfo; |
26 | import org.onlab.onos.store.flow.ReplicaInfoService; | 27 | import org.onlab.onos.store.flow.ReplicaInfoService; |
27 | import org.onlab.onos.store.serializers.KryoNamespaces; | 28 | import org.onlab.onos.store.serializers.KryoNamespaces; |
28 | import org.onlab.onos.store.serializers.KryoSerializer; | 29 | import org.onlab.onos.store.serializers.KryoSerializer; |
30 | +import org.onlab.util.KryoNamespace; | ||
29 | import org.slf4j.Logger; | 31 | import org.slf4j.Logger; |
30 | 32 | ||
31 | - | ||
32 | import java.io.IOException; | 33 | import java.io.IOException; |
33 | import java.util.HashSet; | 34 | import java.util.HashSet; |
34 | import java.util.Map; | 35 | import java.util.Map; |
... | @@ -70,7 +71,9 @@ public class DistributedStatisticStore implements StatisticStore { | ... | @@ -70,7 +71,9 @@ public class DistributedStatisticStore implements StatisticStore { |
70 | protected static final KryoSerializer SERIALIZER = new KryoSerializer() { | 71 | protected static final KryoSerializer SERIALIZER = new KryoSerializer() { |
71 | @Override | 72 | @Override |
72 | protected void setupKryoPool() { | 73 | protected void setupKryoPool() { |
73 | - serializerPool = KryoNamespaces.API.newBuilder() | 74 | + serializerPool = KryoNamespace.newBuilder() |
75 | + .register(KryoNamespaces.API) | ||
76 | + // register this store specific classes here | ||
74 | .build() | 77 | .build() |
75 | .populate(1); | 78 | .populate(1); |
76 | } | 79 | } | ... | ... |
... | @@ -91,23 +91,14 @@ implements MastershipStore { | ... | @@ -91,23 +91,14 @@ implements MastershipStore { |
91 | 91 | ||
92 | @Override | 92 | @Override |
93 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 93 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
94 | - NodeId current = getNode(MASTER, deviceId); | 94 | + final RoleValue roleInfo = getRoleValue(deviceId); |
95 | - if (current == null) { | 95 | + if (roleInfo.contains(MASTER, nodeId)) { |
96 | - if (isRole(STANDBY, nodeId, deviceId)) { | 96 | + return MASTER; |
97 | - //was previously standby, or set to standby from master | 97 | + } |
98 | - return MastershipRole.STANDBY; | 98 | + if (roleInfo.contains(STANDBY, nodeId)) { |
99 | - } else { | 99 | + return STANDBY; |
100 | - return MastershipRole.NONE; | ||
101 | - } | ||
102 | - } else { | ||
103 | - if (current.equals(nodeId)) { | ||
104 | - //*should* be in unusable, not always | ||
105 | - return MastershipRole.MASTER; | ||
106 | - } else { | ||
107 | - //may be in backups or unusable from earlier retirement | ||
108 | - return MastershipRole.STANDBY; | ||
109 | - } | ||
110 | } | 100 | } |
101 | + return NONE; | ||
111 | } | 102 | } |
112 | 103 | ||
113 | @Override | 104 | @Override |
... | @@ -124,10 +115,11 @@ implements MastershipStore { | ... | @@ -124,10 +115,11 @@ implements MastershipStore { |
124 | roleMap.put(deviceId, rv); | 115 | roleMap.put(deviceId, rv); |
125 | return null; | 116 | return null; |
126 | case STANDBY: | 117 | case STANDBY: |
118 | + case NONE: | ||
127 | NodeId current = rv.get(MASTER); | 119 | NodeId current = rv.get(MASTER); |
128 | if (current != null) { | 120 | if (current != null) { |
129 | //backup and replace current master | 121 | //backup and replace current master |
130 | - rv.reassign(nodeId, NONE, STANDBY); | 122 | + rv.reassign(current, NONE, STANDBY); |
131 | rv.replace(current, nodeId, MASTER); | 123 | rv.replace(current, nodeId, MASTER); |
132 | } else { | 124 | } else { |
133 | //no master before so just add. | 125 | //no master before so just add. |
... | @@ -137,12 +129,6 @@ implements MastershipStore { | ... | @@ -137,12 +129,6 @@ implements MastershipStore { |
137 | roleMap.put(deviceId, rv); | 129 | roleMap.put(deviceId, rv); |
138 | updateTerm(deviceId); | 130 | updateTerm(deviceId); |
139 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | 131 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); |
140 | - case NONE: | ||
141 | - rv.add(MASTER, nodeId); | ||
142 | - rv.reassign(nodeId, STANDBY, NONE); | ||
143 | - roleMap.put(deviceId, rv); | ||
144 | - updateTerm(deviceId); | ||
145 | - return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | ||
146 | default: | 132 | default: |
147 | log.warn("unknown Mastership Role {}", role); | 133 | log.warn("unknown Mastership Role {}", role); |
148 | return null; | 134 | return null; |
... | @@ -193,21 +179,28 @@ implements MastershipStore { | ... | @@ -193,21 +179,28 @@ implements MastershipStore { |
193 | switch (role) { | 179 | switch (role) { |
194 | case MASTER: | 180 | case MASTER: |
195 | rv.reassign(local, STANDBY, NONE); | 181 | rv.reassign(local, STANDBY, NONE); |
182 | + terms.putIfAbsent(deviceId, INIT); | ||
196 | roleMap.put(deviceId, rv); | 183 | roleMap.put(deviceId, rv); |
197 | break; | 184 | break; |
198 | case STANDBY: | 185 | case STANDBY: |
199 | rv.reassign(local, NONE, STANDBY); | 186 | rv.reassign(local, NONE, STANDBY); |
200 | roleMap.put(deviceId, rv); | 187 | roleMap.put(deviceId, rv); |
201 | terms.putIfAbsent(deviceId, INIT); | 188 | terms.putIfAbsent(deviceId, INIT); |
202 | - | ||
203 | break; | 189 | break; |
204 | case NONE: | 190 | case NONE: |
205 | - //claim mastership | 191 | + //either we're the first standby, or first to device. |
206 | - rv.add(MASTER, local); | 192 | + //for latter, claim mastership. |
207 | - rv.reassign(local, STANDBY, NONE); | 193 | + if (rv.get(MASTER) == null) { |
194 | + rv.add(MASTER, local); | ||
195 | + rv.reassign(local, STANDBY, NONE); | ||
196 | + updateTerm(deviceId); | ||
197 | + role = MastershipRole.MASTER; | ||
198 | + } else { | ||
199 | + rv.add(STANDBY, local); | ||
200 | + rv.reassign(local, NONE, STANDBY); | ||
201 | + role = MastershipRole.STANDBY; | ||
202 | + } | ||
208 | roleMap.put(deviceId, rv); | 203 | roleMap.put(deviceId, rv); |
209 | - updateTerm(deviceId); | ||
210 | - role = MastershipRole.MASTER; | ||
211 | break; | 204 | break; |
212 | default: | 205 | default: |
213 | log.warn("unknown Mastership Role {}", role); | 206 | log.warn("unknown Mastership Role {}", role); |
... | @@ -315,7 +308,10 @@ implements MastershipStore { | ... | @@ -315,7 +308,10 @@ implements MastershipStore { |
315 | RoleValue value = roleMap.get(deviceId); | 308 | RoleValue value = roleMap.get(deviceId); |
316 | if (value == null) { | 309 | if (value == null) { |
317 | value = new RoleValue(); | 310 | value = new RoleValue(); |
318 | - roleMap.put(deviceId, value); | 311 | + RoleValue concurrentlyAdded = roleMap.putIfAbsent(deviceId, value); |
312 | + if (concurrentlyAdded != null) { | ||
313 | + return concurrentlyAdded; | ||
314 | + } | ||
319 | } | 315 | } |
320 | return value; | 316 | return value; |
321 | } | 317 | } |
... | @@ -329,16 +325,6 @@ implements MastershipStore { | ... | @@ -329,16 +325,6 @@ implements MastershipStore { |
329 | return null; | 325 | return null; |
330 | } | 326 | } |
331 | 327 | ||
332 | - //check if node is a certain role given a device | ||
333 | - private boolean isRole( | ||
334 | - MastershipRole role, NodeId nodeId, DeviceId deviceId) { | ||
335 | - RoleValue value = roleMap.get(deviceId); | ||
336 | - if (value != null) { | ||
337 | - return value.contains(role, nodeId); | ||
338 | - } | ||
339 | - return false; | ||
340 | - } | ||
341 | - | ||
342 | //adds or updates term information. | 328 | //adds or updates term information. |
343 | private void updateTerm(DeviceId deviceId) { | 329 | private void updateTerm(DeviceId deviceId) { |
344 | terms.lock(deviceId); | 330 | terms.lock(deviceId); | ... | ... |
... | @@ -97,6 +97,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -97,6 +97,7 @@ public class DistributedMastershipStoreTest { |
97 | assertEquals("wrong role:", NONE, dms.getRole(N1, DID1)); | 97 | assertEquals("wrong role:", NONE, dms.getRole(N1, DID1)); |
98 | testStore.put(DID1, N1, true, false, true); | 98 | testStore.put(DID1, N1, true, false, true); |
99 | assertEquals("wrong role:", MASTER, dms.getRole(N1, DID1)); | 99 | assertEquals("wrong role:", MASTER, dms.getRole(N1, DID1)); |
100 | + testStore.put(DID1, N2, false, true, false); | ||
100 | assertEquals("wrong role:", STANDBY, dms.getRole(N2, DID1)); | 101 | assertEquals("wrong role:", STANDBY, dms.getRole(N2, DID1)); |
101 | } | 102 | } |
102 | 103 | ||
... | @@ -155,6 +156,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -155,6 +156,7 @@ public class DistributedMastershipStoreTest { |
155 | 156 | ||
156 | //switch over to N2 | 157 | //switch over to N2 |
157 | assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID1).type()); | 158 | assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID1).type()); |
159 | + System.out.println(dms.getTermFor(DID1).master() + ":" + dms.getTermFor(DID1).termNumber()); | ||
158 | assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID1)); | 160 | assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID1)); |
159 | 161 | ||
160 | //orphan switch - should be rare case | 162 | //orphan switch - should be rare case |
... | @@ -182,14 +184,9 @@ public class DistributedMastershipStoreTest { | ... | @@ -182,14 +184,9 @@ public class DistributedMastershipStoreTest { |
182 | assertEquals("wrong event:", Type.MASTER_CHANGED, dms.relinquishRole(N1, DID1).type()); | 184 | assertEquals("wrong event:", Type.MASTER_CHANGED, dms.relinquishRole(N1, DID1).type()); |
183 | assertEquals("wrong master", N2, dms.getMaster(DID1)); | 185 | assertEquals("wrong master", N2, dms.getMaster(DID1)); |
184 | 186 | ||
185 | - //STANDBY - nothing here, either | ||
186 | - assertNull("wrong event:", dms.relinquishRole(N1, DID1)); | ||
187 | - assertEquals("wrong role for node:", STANDBY, dms.getRole(N1, DID1)); | ||
188 | - | ||
189 | //all nodes "give up" on device, which goes back to NONE. | 187 | //all nodes "give up" on device, which goes back to NONE. |
190 | assertNull("wrong event:", dms.relinquishRole(N2, DID1)); | 188 | assertNull("wrong event:", dms.relinquishRole(N2, DID1)); |
191 | assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1)); | 189 | assertEquals("wrong role for node:", NONE, dms.getRole(N2, DID1)); |
192 | - assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1)); | ||
193 | 190 | ||
194 | assertEquals("wrong number of retired nodes", 2, | 191 | assertEquals("wrong number of retired nodes", 2, |
195 | dms.roleMap.get(DID1).nodesOfRole(NONE).size()); | 192 | dms.roleMap.get(DID1).nodesOfRole(NONE).size()); |
... | @@ -201,6 +198,10 @@ public class DistributedMastershipStoreTest { | ... | @@ -201,6 +198,10 @@ public class DistributedMastershipStoreTest { |
201 | assertEquals("wrong number of backup nodes", 1, | 198 | assertEquals("wrong number of backup nodes", 1, |
202 | dms.roleMap.get(DID1).nodesOfRole(STANDBY).size()); | 199 | dms.roleMap.get(DID1).nodesOfRole(STANDBY).size()); |
203 | 200 | ||
201 | + //If STANDBY, should drop to NONE | ||
202 | + assertNull("wrong event:", dms.relinquishRole(N1, DID1)); | ||
203 | + assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID1)); | ||
204 | + | ||
204 | //NONE - nothing happens | 205 | //NONE - nothing happens |
205 | assertNull("wrong event:", dms.relinquishRole(N1, DID2)); | 206 | assertNull("wrong event:", dms.relinquishRole(N1, DID2)); |
206 | assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID2)); | 207 | assertEquals("wrong role for node:", NONE, dms.getRole(N1, DID2)); |
... | @@ -218,7 +219,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -218,7 +219,7 @@ public class DistributedMastershipStoreTest { |
218 | public void notify(MastershipEvent event) { | 219 | public void notify(MastershipEvent event) { |
219 | assertEquals("wrong event:", Type.MASTER_CHANGED, event.type()); | 220 | assertEquals("wrong event:", Type.MASTER_CHANGED, event.type()); |
220 | assertEquals("wrong subject", DID1, event.subject()); | 221 | assertEquals("wrong subject", DID1, event.subject()); |
221 | - assertEquals("wrong subject", N1, event.node()); | 222 | + assertEquals("wrong subject", N1, event.roleInfo().master()); |
222 | addLatch.countDown(); | 223 | addLatch.countDown(); |
223 | } | 224 | } |
224 | }; | 225 | }; | ... | ... |
... | @@ -207,7 +207,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -207,7 +207,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
207 | + "value for dpid: {}", dpid); | 207 | + "value for dpid: {}", dpid); |
208 | return false; | 208 | return false; |
209 | } else { | 209 | } else { |
210 | - log.error("Added switch {}", dpid); | 210 | + log.info("Added switch {}", dpid); |
211 | connectedSwitches.put(dpid, sw); | 211 | connectedSwitches.put(dpid, sw); |
212 | for (OpenFlowSwitchListener l : ofSwitchListener) { | 212 | for (OpenFlowSwitchListener l : ofSwitchListener) { |
213 | l.switchAdded(dpid); | 213 | l.switchAdded(dpid); | ... | ... |
... | @@ -16,58 +16,95 @@ from functools import partial | ... | @@ -16,58 +16,95 @@ from functools import partial |
16 | import time | 16 | import time |
17 | from sys import argv | 17 | from sys import argv |
18 | from time import sleep | 18 | from time import sleep |
19 | +from sets import Set | ||
19 | 20 | ||
20 | class ONOS( Controller ): | 21 | class ONOS( Controller ): |
21 | - #def __init__( self, name, command='/opt/onos/bin/onos-service', **kwargs ): | 22 | + "TODO" |
22 | - # Controller.__init__( self, name, command=command, inNamespace=True, **kwargs ) | 23 | + |
23 | - #def __init__( self, name, inNamespace=False, command='controller', | 24 | + onosDir = '/opt/onos/' |
24 | - # cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1", | 25 | + |
25 | - # port=6633, protocol='tcp', **params ): | 26 | + def __init__( self, name, onosDir=onosDir, |
26 | - #self.command = command | 27 | + reactive=True, features=[ 'onos-app-tvue' ], |
27 | - #self.cargs = cargs | 28 | + **kwargs ): |
28 | - #self.cdir = cdir | 29 | + '''TODO''' |
29 | - #self.ip = ip | 30 | + |
30 | - #self.port = port | 31 | + Controller.__init__( self, name, **kwargs ) |
31 | - #self.protocol = protocol | 32 | + # the following have been done for us: |
32 | - #Node.__init__( self, name, inNamespace=inNamespace, | 33 | + #self.ip = ip ('127.0.0.1') |
33 | - # ip=ip, **params ) | 34 | + #self.port = port (6633) |
34 | - #self.checkListening() | 35 | + #self.protocol = protocol ('tcp') |
35 | - | 36 | + #self.checkListening() |
36 | - ONOS_DIR = '/opt/onos/' | 37 | + |
37 | - KARAF_DIR = ONOS_DIR + 'apache-karaf-3.0.1/' | 38 | + self.onosDir = onosDir |
38 | - reactive = True | 39 | + self.karafDir = onosDir + 'apache-karaf-3.0.1/' |
40 | + self.instanceDir = self.karafDir | ||
41 | + | ||
42 | + # add default modules | ||
43 | + # TODO: consider an ordered set | ||
44 | + self.features = Set([ 'webconsole', | ||
45 | + 'onos-api', | ||
46 | + 'onos-cli', | ||
47 | + 'onos-openflow' ]) | ||
48 | + self.features.update( features ) | ||
49 | + # add reactive forwarding modules | ||
50 | + if reactive: | ||
51 | + self.features.update( ['onos-app-fwd', | ||
52 | + 'onos-app-proxyarp', | ||
53 | + 'onos-app-mobility' ] ) | ||
54 | + # add the distributed core if we are in a namespace with no trivial core | ||
55 | + if self.inNamespace and 'onos-core-trivial' not in self.features: | ||
56 | + self.features.add( 'onos-core' ) | ||
57 | + # if there is no core, add the trivial one | ||
58 | + if 'onos-core' not in self.features: | ||
59 | + self.features.add( 'onos-core-trivial' ) | ||
60 | + print self.features | ||
39 | 61 | ||
40 | def start( self ): | 62 | def start( self ): |
41 | - # switch to the non-root user because karaf gets upset otherwise | ||
42 | - # TODO we should look into why.... | ||
43 | - self.sendCmd( 'sudo su - %s' % self.findUser() ) | ||
44 | - self.waiting = False | ||
45 | - | ||
46 | if self.inNamespace: | 63 | if self.inNamespace: |
47 | - self.cmd( self.KARAF_DIR + 'bin/instance create %s' % self.name ) | 64 | + instanceOpts = ( '-furl mvn:org.onlab.onos/onos-features/1.0.0-SNAPSHOT/xml/features ' |
48 | - src = self.KARAF_DIR + 'etc/org.apache.karaf.features.cfg' | 65 | + '-s 8101' ) |
49 | - dst = self.KARAF_DIR + 'instances/%s/etc/org.apache.karaf.features.cfg' % self.name | 66 | + self.userCmd( self.karafDir + 'bin/instance create %s %s' % ( instanceOpts, self.name ) ) |
50 | - self.cmd( 'cp %s %s' % (src, dst) ) | 67 | + self.instanceDir = self.karafDir + 'instances/%s/' % self.name |
51 | - self.updateProperties( dst ) | ||
52 | - self.cmd( self.KARAF_DIR + 'bin/instance start %s' % self.name ) | ||
53 | else: | 68 | else: |
54 | # we are running in the root namespace, so let's use the root instance | 69 | # we are running in the root namespace, so let's use the root instance |
55 | - self.cmd( 'rm -rf '+ self.KARAF_DIR + 'data/' ) | 70 | + # clean up the data directory |
56 | - filename = self.KARAF_DIR + 'etc/org.apache.karaf.features.cfg' | 71 | + #self.userCmd( 'rm -rf '+ self.karafDir + 'data/' ) |
57 | - self.updateProperties( filename ) | 72 | + pass |
58 | - self.cmd( self.KARAF_DIR + 'bin/start' ) | 73 | + |
74 | + self.userCmd( 'rm -rf '+ self.instanceDir + 'data/' ) | ||
75 | + | ||
76 | + # Update etc/org.apache.karaf.features.cfg | ||
77 | + self.updateFeatures() | ||
59 | 78 | ||
79 | + # TODO 2. Update etc/hazelcast.xml : interface lines | ||
80 | + #cp etc/hazelcast.xml instances/c1/etc/ | ||
81 | + self.updateHazelcast() | ||
82 | + | ||
83 | + # TODO 3. Update etc/system.properties : onos.ip | ||
84 | + # TODO 4. Update config/cluster.json : with all nodes | ||
85 | + | ||
86 | + # start onos | ||
87 | + self.userCmd( self.instanceDir + 'bin/start' ) | ||
60 | #TODO we should wait for startup... | 88 | #TODO we should wait for startup... |
61 | 89 | ||
62 | def stop( self ): | 90 | def stop( self ): |
63 | - if self.inNamespace: | 91 | + self.userCmd( self.instanceDir + 'bin/stop' ) |
64 | - self.cmd( '/opt/onos/apache-karaf-3.0.1/bin/instance stop %s' % self.name ) | 92 | + #if self.inNamespace: |
65 | - self.cmd( '/opt/onos/apache-karaf-3.0.1/bin/instance destroy %s' % self.name ) | 93 | + # self.userCmd( self.karafDir + 'bin/instance destroy %s' % self.name ) |
66 | - else: | ||
67 | - self.cmd( self.ONOS_DIR + 'apache-karaf-3.0.1/bin/stop' ) | ||
68 | self.terminate() | 94 | self.terminate() |
69 | 95 | ||
70 | - def updateProperties( self, filename ): | 96 | + def updateHazelcast( self ): |
97 | + readfile = self.karafDir + 'etc/hazelcast.xml' | ||
98 | + writefile = self.instanceDir + 'etc/hazelcast.xml' | ||
99 | + with open( readfile, 'r' ) as r: | ||
100 | + with open( writefile, 'w' ) as w: | ||
101 | + for line in r.readlines(): | ||
102 | + if '<interface>' in line: | ||
103 | + line = '<interface>' + '192.168.123.*' + '</interface>\n' | ||
104 | + w.write( line ) | ||
105 | + | ||
106 | + def updateFeatures( self ): | ||
107 | + filename = self.instanceDir + 'etc/org.apache.karaf.features.cfg' | ||
71 | with open( filename, 'r+' ) as f: | 108 | with open( filename, 'r+' ) as f: |
72 | lines = f.readlines() | 109 | lines = f.readlines() |
73 | f.seek(0) | 110 | f.seek(0) |
... | @@ -75,17 +112,25 @@ class ONOS( Controller ): | ... | @@ -75,17 +112,25 @@ class ONOS( Controller ): |
75 | for line in lines: | 112 | for line in lines: |
76 | #print '?', line, | 113 | #print '?', line, |
77 | if 'featuresBoot=' in line: | 114 | if 'featuresBoot=' in line: |
78 | - line = line.rstrip() | 115 | + # parse the features from the line |
79 | - #print ord(line[-1]), ord(line[-2]), ord(line[-3]) | 116 | + features = line.rstrip().split('=')[1].split(',') |
80 | - if self.reactive: | 117 | + # add the features to our features set |
81 | - line += ',onos-app-fwd' | 118 | + self.features.update( features ) |
82 | - line += '\n' | 119 | + # generate the new features line |
120 | + line = 'featuresBoot=' + ','.join( self.features ) + '\n' | ||
83 | #print '!', line, | 121 | #print '!', line, |
84 | f.write( line ) | 122 | f.write( line ) |
85 | 123 | ||
124 | + | ||
86 | @classmethod | 125 | @classmethod |
87 | def isAvailable( self ): | 126 | def isAvailable( self ): |
88 | - return quietRun( 'ls /opt/onos' ) | 127 | + return quietRun( 'ls %s' % self.onosDir ) |
128 | + | ||
129 | + def userCmd( self, cmd ): | ||
130 | + # switch to the non-root user because karaf gets upset otherwise | ||
131 | + # because the .m2repo is not stored with root | ||
132 | + cmd = 'sudo -u %s %s' % ( self.findUser(), cmd ) | ||
133 | + return self.cmd( cmd ) | ||
89 | 134 | ||
90 | @staticmethod | 135 | @staticmethod |
91 | def findUser(): | 136 | def findUser(): |
... | @@ -111,7 +156,7 @@ class ControlNetwork( Topo ): | ... | @@ -111,7 +156,7 @@ class ControlNetwork( Topo ): |
111 | # Connect everything to a single switch | 156 | # Connect everything to a single switch |
112 | cs0 = self.addSwitch( 'cs0' ) | 157 | cs0 = self.addSwitch( 'cs0' ) |
113 | # Add hosts which will serve as data network controllers | 158 | # Add hosts which will serve as data network controllers |
114 | - for i in range( 0, n ): | 159 | + for i in range( 1, n+1 ): |
115 | c = self.addHost( 'c%s' % i, cls=dataController, | 160 | c = self.addHost( 'c%s' % i, cls=dataController, |
116 | inNamespace=True ) | 161 | inNamespace=True ) |
117 | self.addLink( c, cs0 ) | 162 | self.addLink( c, cs0 ) |
... | @@ -122,7 +167,7 @@ class ControlNetwork( Topo ): | ... | @@ -122,7 +167,7 @@ class ControlNetwork( Topo ): |
122 | 167 | ||
123 | class ONOSCluster( Controller ): | 168 | class ONOSCluster( Controller ): |
124 | # TODO | 169 | # TODO |
125 | - n = 4 | 170 | + n = 3 |
126 | 171 | ||
127 | def start( self ): | 172 | def start( self ): |
128 | ctopo = ControlNetwork( n=self.n, dataController=ONOS ) | 173 | ctopo = ControlNetwork( n=self.n, dataController=ONOS ) |
... | @@ -137,6 +182,9 @@ class ONOSCluster( Controller ): | ... | @@ -137,6 +182,9 @@ class ONOSCluster( Controller ): |
137 | host.start() | 182 | host.start() |
138 | 183 | ||
139 | def stop( self ): | 184 | def stop( self ): |
185 | + for host in self.cnet.hosts: | ||
186 | + if isinstance( host, Controller ): | ||
187 | + host.stop() | ||
140 | self.cnet.stop() | 188 | self.cnet.stop() |
141 | 189 | ||
142 | def clist( self ): | 190 | def clist( self ): |
... | @@ -158,10 +206,11 @@ switches = { 'ovso': OVSSwitchONOS } | ... | @@ -158,10 +206,11 @@ switches = { 'ovso': OVSSwitchONOS } |
158 | 206 | ||
159 | if __name__ == '__main__': | 207 | if __name__ == '__main__': |
160 | # Simple test for ONOS() controller class | 208 | # Simple test for ONOS() controller class |
161 | - setLogLevel( 'info' ) | 209 | + setLogLevel( 'info' ) #TODO info |
162 | size = 2 if len( argv ) != 2 else int( argv[ 1 ] ) | 210 | size = 2 if len( argv ) != 2 else int( argv[ 1 ] ) |
163 | net = Mininet( topo=LinearTopo( size ), | 211 | net = Mininet( topo=LinearTopo( size ), |
164 | - controller=partial( ONOSCluster, n=4 ), | 212 | + #controller=ONOS, |
213 | + controller=partial( ONOSCluster, n=3 ), #TODO | ||
165 | switch=OVSSwitchONOS ) | 214 | switch=OVSSwitchONOS ) |
166 | net.start() | 215 | net.start() |
167 | #waitConnected( net.switches ) | 216 | #waitConnected( net.switches ) | ... | ... |
... | @@ -26,7 +26,6 @@ | ... | @@ -26,7 +26,6 @@ |
26 | <dependency> | 26 | <dependency> |
27 | <groupId>com.google.guava</groupId> | 27 | <groupId>com.google.guava</groupId> |
28 | <artifactId>guava</artifactId> | 28 | <artifactId>guava</artifactId> |
29 | - <version>17.0</version> | ||
30 | <scope>test</scope> | 29 | <scope>test</scope> |
31 | </dependency> | 30 | </dependency> |
32 | 31 | ... | ... |
-
Please register or login to post a comment