Committed by
Gerrit Code Review
Sketching out what link-state addition would look like; quite easy until we get …
…to the distributed store. Added unit tests to provide durable-nondurable transitions. FIxed issue where link could be accidentally activated. Renamed parameter. Change-Id: I8aa19a6583ec50dbf28769995f0a8ea9be9a4daa
Showing
16 changed files
with
292 additions
and
73 deletions
... | @@ -25,6 +25,17 @@ public final class AnnotationKeys { | ... | @@ -25,6 +25,17 @@ public final class AnnotationKeys { |
25 | private AnnotationKeys() {} | 25 | private AnnotationKeys() {} |
26 | 26 | ||
27 | /** | 27 | /** |
28 | + * Annotation key for durable links. | ||
29 | + */ | ||
30 | + public static final String DURABLE = "durable"; | ||
31 | + | ||
32 | + /** | ||
33 | + * Annotation key for active/inactive links. Links are implicitly | ||
34 | + * considered active unless explicitly marked otherwise. | ||
35 | + */ | ||
36 | + public static final String INACTIVE = "inactive"; | ||
37 | + | ||
38 | + /** | ||
28 | * Annotation key for latency. | 39 | * Annotation key for latency. |
29 | */ | 40 | */ |
30 | public static final String LATENCY = "latency"; | 41 | public static final String LATENCY = "latency"; | ... | ... |
... | @@ -20,6 +20,7 @@ import org.onlab.onos.net.provider.ProviderId; | ... | @@ -20,6 +20,7 @@ import org.onlab.onos.net.provider.ProviderId; |
20 | import java.util.Objects; | 20 | import java.util.Objects; |
21 | 21 | ||
22 | import static com.google.common.base.MoreObjects.toStringHelper; | 22 | import static com.google.common.base.MoreObjects.toStringHelper; |
23 | +import static org.onlab.onos.net.Link.State.ACTIVE; | ||
23 | 24 | ||
24 | /** | 25 | /** |
25 | * Default infrastructure link model implementation. | 26 | * Default infrastructure link model implementation. |
... | @@ -29,9 +30,11 @@ public class DefaultLink extends AbstractModel implements Link { | ... | @@ -29,9 +30,11 @@ public class DefaultLink extends AbstractModel implements Link { |
29 | private final ConnectPoint src; | 30 | private final ConnectPoint src; |
30 | private final ConnectPoint dst; | 31 | private final ConnectPoint dst; |
31 | private final Type type; | 32 | private final Type type; |
33 | + private final State state; | ||
34 | + private final boolean isDurable; | ||
32 | 35 | ||
33 | /** | 36 | /** |
34 | - * Creates an infrastructure link using the supplied information. | 37 | + * Creates an active infrastructure link using the supplied information. |
35 | * | 38 | * |
36 | * @param providerId provider identity | 39 | * @param providerId provider identity |
37 | * @param src link source | 40 | * @param src link source |
... | @@ -41,10 +44,31 @@ public class DefaultLink extends AbstractModel implements Link { | ... | @@ -41,10 +44,31 @@ public class DefaultLink extends AbstractModel implements Link { |
41 | */ | 44 | */ |
42 | public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst, | 45 | public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst, |
43 | Type type, Annotations... annotations) { | 46 | Type type, Annotations... annotations) { |
47 | + this(providerId, src, dst, type, ACTIVE, false, annotations); | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Creates an infrastructure link using the supplied information. | ||
52 | + * Links marked as durable will remain in the inventory when a vanish | ||
53 | + * message is received and instead will be marked as inactive. | ||
54 | + * | ||
55 | + * @param providerId provider identity | ||
56 | + * @param src link source | ||
57 | + * @param dst link destination | ||
58 | + * @param type link type | ||
59 | + * @param state link state | ||
60 | + * @param isDurable indicates if the link is to be considered durable | ||
61 | + * @param annotations optional key/value annotations | ||
62 | + */ | ||
63 | + public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst, | ||
64 | + Type type, State state, | ||
65 | + boolean isDurable, Annotations... annotations) { | ||
44 | super(providerId, annotations); | 66 | super(providerId, annotations); |
45 | this.src = src; | 67 | this.src = src; |
46 | this.dst = dst; | 68 | this.dst = dst; |
47 | this.type = type; | 69 | this.type = type; |
70 | + this.state = state; | ||
71 | + this.isDurable = isDurable; | ||
48 | } | 72 | } |
49 | 73 | ||
50 | @Override | 74 | @Override |
... | @@ -63,6 +87,18 @@ public class DefaultLink extends AbstractModel implements Link { | ... | @@ -63,6 +87,18 @@ public class DefaultLink extends AbstractModel implements Link { |
63 | } | 87 | } |
64 | 88 | ||
65 | @Override | 89 | @Override |
90 | + public State state() { | ||
91 | + return state; | ||
92 | + } | ||
93 | + | ||
94 | + @Override | ||
95 | + public boolean isDurable() { | ||
96 | + return isDurable; | ||
97 | + } | ||
98 | + | ||
99 | + // Note: Durability & state are purposefully omitted form equality & hashCode. | ||
100 | + | ||
101 | + @Override | ||
66 | public int hashCode() { | 102 | public int hashCode() { |
67 | return Objects.hash(src, dst, type); | 103 | return Objects.hash(src, dst, type); |
68 | } | 104 | } |
... | @@ -87,6 +123,8 @@ public class DefaultLink extends AbstractModel implements Link { | ... | @@ -87,6 +123,8 @@ public class DefaultLink extends AbstractModel implements Link { |
87 | .add("src", src) | 123 | .add("src", src) |
88 | .add("dst", dst) | 124 | .add("dst", dst) |
89 | .add("type", type) | 125 | .add("type", type) |
126 | + .add("state", state) | ||
127 | + .add("durable", isDurable) | ||
90 | .toString(); | 128 | .toString(); |
91 | } | 129 | } |
92 | 130 | ... | ... |
... | @@ -55,6 +55,23 @@ public interface Link extends Annotated, Provided, NetworkResource { | ... | @@ -55,6 +55,23 @@ public interface Link extends Annotated, Provided, NetworkResource { |
55 | } | 55 | } |
56 | 56 | ||
57 | /** | 57 | /** |
58 | + * Representation of the link state, which applies primarily only to | ||
59 | + * configured durable links, i.e. those that need to remain present, | ||
60 | + * but instead be marked as inactive. | ||
61 | + */ | ||
62 | + public enum State { | ||
63 | + /** | ||
64 | + * Signifies that a link is currently active. | ||
65 | + */ | ||
66 | + ACTIVE, | ||
67 | + | ||
68 | + /** | ||
69 | + * Signifies that a link is currently active. | ||
70 | + */ | ||
71 | + INACTIVE | ||
72 | + } | ||
73 | + | ||
74 | + /** | ||
58 | * Returns the link source connection point. | 75 | * Returns the link source connection point. |
59 | * | 76 | * |
60 | * @return link source connection point | 77 | * @return link source connection point |
... | @@ -75,4 +92,16 @@ public interface Link extends Annotated, Provided, NetworkResource { | ... | @@ -75,4 +92,16 @@ public interface Link extends Annotated, Provided, NetworkResource { |
75 | */ | 92 | */ |
76 | Type type(); | 93 | Type type(); |
77 | 94 | ||
95 | + /** | ||
96 | + * Returns the link state. | ||
97 | + */ | ||
98 | + State state(); | ||
99 | + | ||
100 | + /** | ||
101 | + * Indicates if the link is to be considered durable. | ||
102 | + * | ||
103 | + * @return link state | ||
104 | + */ | ||
105 | + boolean isDurable(); | ||
106 | + | ||
78 | } | 107 | } | ... | ... |
... | @@ -64,7 +64,8 @@ public class DefaultLinkDescription extends AbstractDescription | ... | @@ -64,7 +64,8 @@ public class DefaultLinkDescription extends AbstractDescription |
64 | 64 | ||
65 | @Override | 65 | @Override |
66 | public String toString() { | 66 | public String toString() { |
67 | - return MoreObjects.toStringHelper("Link").add("src", src()) | 67 | + return MoreObjects.toStringHelper(this) |
68 | + .add("src", src()) | ||
68 | .add("dst", dst()) | 69 | .add("dst", dst()) |
69 | .add("type", type()).toString(); | 70 | .add("type", type()).toString(); |
70 | } | 71 | } | ... | ... |
... | @@ -45,6 +45,5 @@ public interface LinkDescription extends Description { | ... | @@ -45,6 +45,5 @@ public interface LinkDescription extends Description { |
45 | */ | 45 | */ |
46 | Link.Type type(); | 46 | Link.Type type(); |
47 | 47 | ||
48 | - | ||
49 | // Add further link attributes | 48 | // Add further link attributes |
50 | } | 49 | } | ... | ... |
... | @@ -33,7 +33,7 @@ public class LinkEvent extends AbstractEvent<LinkEvent.Type, Link> { | ... | @@ -33,7 +33,7 @@ public class LinkEvent extends AbstractEvent<LinkEvent.Type, Link> { |
33 | LINK_ADDED, | 33 | LINK_ADDED, |
34 | 34 | ||
35 | /** | 35 | /** |
36 | - * Signifies that a link has been updated. | 36 | + * Signifies that a link has been updated or changed state. |
37 | */ | 37 | */ |
38 | LINK_UPDATED, | 38 | LINK_UPDATED, |
39 | 39 | ... | ... |
... | @@ -95,6 +95,16 @@ public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> { | ... | @@ -95,6 +95,16 @@ public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> { |
95 | LinkDescription linkDescription); | 95 | LinkDescription linkDescription); |
96 | 96 | ||
97 | /** | 97 | /** |
98 | + * Removes the link, or marks it as inactive if the link is durable, | ||
99 | + * based on the specified information. | ||
100 | + * | ||
101 | + * @param src link source | ||
102 | + * @param dst link destination | ||
103 | + * @return remove or update link event, or null if no change resulted | ||
104 | + */ | ||
105 | + LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst); | ||
106 | + | ||
107 | + /** | ||
98 | * Removes the link based on the specified information. | 108 | * Removes the link based on the specified information. |
99 | * | 109 | * |
100 | * @param src link source | 110 | * @param src link source |
... | @@ -103,4 +113,5 @@ public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> { | ... | @@ -103,4 +113,5 @@ public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> { |
103 | */ | 113 | */ |
104 | LinkEvent removeLink(ConnectPoint src, ConnectPoint dst); | 114 | LinkEvent removeLink(ConnectPoint src, ConnectPoint dst); |
105 | 115 | ||
116 | + | ||
106 | } | 117 | } | ... | ... |
... | @@ -78,5 +78,4 @@ public class LinkServiceAdapter implements LinkService { | ... | @@ -78,5 +78,4 @@ public class LinkServiceAdapter implements LinkService { |
78 | public void removeListener(LinkListener listener) { | 78 | public void removeListener(LinkListener listener) { |
79 | } | 79 | } |
80 | 80 | ||
81 | - | ||
82 | } | 81 | } | ... | ... |
... | @@ -158,7 +158,7 @@ public class LinkManager | ... | @@ -158,7 +158,7 @@ public class LinkManager |
158 | if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) { | 158 | if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) { |
159 | return; | 159 | return; |
160 | } | 160 | } |
161 | - removeLinks(getLinks(connectPoint)); | 161 | + removeLinks(getLinks(connectPoint), false); |
162 | } | 162 | } |
163 | 163 | ||
164 | @Override | 164 | @Override |
... | @@ -166,7 +166,7 @@ public class LinkManager | ... | @@ -166,7 +166,7 @@ public class LinkManager |
166 | if (deviceService.getRole(deviceId) != MastershipRole.MASTER) { | 166 | if (deviceService.getRole(deviceId) != MastershipRole.MASTER) { |
167 | return; | 167 | return; |
168 | } | 168 | } |
169 | - removeLinks(getDeviceLinks(deviceId)); | 169 | + removeLinks(getDeviceLinks(deviceId), false); |
170 | } | 170 | } |
171 | 171 | ||
172 | @Override | 172 | @Override |
... | @@ -228,7 +228,7 @@ public class LinkManager | ... | @@ -228,7 +228,7 @@ public class LinkManager |
228 | ConnectPoint src = linkDescription.src(); | 228 | ConnectPoint src = linkDescription.src(); |
229 | ConnectPoint dst = linkDescription.dst(); | 229 | ConnectPoint dst = linkDescription.dst(); |
230 | 230 | ||
231 | - LinkEvent event = store.removeLink(src, dst); | 231 | + LinkEvent event = store.removeOrDownLink(src, dst); |
232 | if (event != null) { | 232 | if (event != null) { |
233 | log.info("Link {} vanished", linkDescription); | 233 | log.info("Link {} vanished", linkDescription); |
234 | post(event); | 234 | post(event); |
... | @@ -242,7 +242,7 @@ public class LinkManager | ... | @@ -242,7 +242,7 @@ public class LinkManager |
242 | 242 | ||
243 | log.info("Links for connection point {} vanished", connectPoint); | 243 | log.info("Links for connection point {} vanished", connectPoint); |
244 | // FIXME: This will remove links registered by other providers | 244 | // FIXME: This will remove links registered by other providers |
245 | - removeLinks(getLinks(connectPoint)); | 245 | + removeLinks(getLinks(connectPoint), true); |
246 | } | 246 | } |
247 | 247 | ||
248 | @Override | 248 | @Override |
... | @@ -251,14 +251,16 @@ public class LinkManager | ... | @@ -251,14 +251,16 @@ public class LinkManager |
251 | checkValidity(); | 251 | checkValidity(); |
252 | 252 | ||
253 | log.info("Links for device {} vanished", deviceId); | 253 | log.info("Links for device {} vanished", deviceId); |
254 | - removeLinks(getDeviceLinks(deviceId)); | 254 | + removeLinks(getDeviceLinks(deviceId), true); |
255 | } | 255 | } |
256 | } | 256 | } |
257 | 257 | ||
258 | // Removes all links in the specified set and emits appropriate events. | 258 | // Removes all links in the specified set and emits appropriate events. |
259 | - private void removeLinks(Set<Link> links) { | 259 | + private void removeLinks(Set<Link> links, boolean isSoftRemove) { |
260 | for (Link link : links) { | 260 | for (Link link : links) { |
261 | - LinkEvent event = store.removeLink(link.src(), link.dst()); | 261 | + LinkEvent event = isSoftRemove ? |
262 | + store.removeOrDownLink(link.src(), link.dst()) : | ||
263 | + store.removeLink(link.src(), link.dst()); | ||
262 | post(event); | 264 | post(event); |
263 | } | 265 | } |
264 | } | 266 | } | ... | ... |
... | @@ -21,7 +21,6 @@ import com.google.common.collect.HashMultimap; | ... | @@ -21,7 +21,6 @@ import com.google.common.collect.HashMultimap; |
21 | import com.google.common.collect.ImmutableList; | 21 | import com.google.common.collect.ImmutableList; |
22 | import com.google.common.collect.Maps; | 22 | import com.google.common.collect.Maps; |
23 | import com.google.common.collect.SetMultimap; | 23 | import com.google.common.collect.SetMultimap; |
24 | - | ||
25 | import org.apache.commons.lang3.RandomUtils; | 24 | import org.apache.commons.lang3.RandomUtils; |
26 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
27 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
... | @@ -32,6 +31,7 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -32,6 +31,7 @@ import org.apache.felix.scr.annotations.Service; |
32 | import org.onlab.onos.cluster.ClusterService; | 31 | import org.onlab.onos.cluster.ClusterService; |
33 | import org.onlab.onos.cluster.ControllerNode; | 32 | import org.onlab.onos.cluster.ControllerNode; |
34 | import org.onlab.onos.cluster.NodeId; | 33 | import org.onlab.onos.cluster.NodeId; |
34 | +import org.onlab.onos.net.AnnotationKeys; | ||
35 | import org.onlab.onos.net.AnnotationsUtil; | 35 | import org.onlab.onos.net.AnnotationsUtil; |
36 | import org.onlab.onos.net.ConnectPoint; | 36 | import org.onlab.onos.net.ConnectPoint; |
37 | import org.onlab.onos.net.DefaultAnnotations; | 37 | import org.onlab.onos.net.DefaultAnnotations; |
... | @@ -65,28 +65,30 @@ import java.util.Collections; | ... | @@ -65,28 +65,30 @@ import java.util.Collections; |
65 | import java.util.HashMap; | 65 | import java.util.HashMap; |
66 | import java.util.HashSet; | 66 | import java.util.HashSet; |
67 | import java.util.Map; | 67 | import java.util.Map; |
68 | +import java.util.Map.Entry; | ||
68 | import java.util.Objects; | 69 | import java.util.Objects; |
69 | import java.util.Set; | 70 | import java.util.Set; |
70 | -import java.util.Map.Entry; | ||
71 | import java.util.concurrent.ConcurrentHashMap; | 71 | import java.util.concurrent.ConcurrentHashMap; |
72 | import java.util.concurrent.ConcurrentMap; | 72 | import java.util.concurrent.ConcurrentMap; |
73 | import java.util.concurrent.ScheduledExecutorService; | 73 | import java.util.concurrent.ScheduledExecutorService; |
74 | import java.util.concurrent.TimeUnit; | 74 | import java.util.concurrent.TimeUnit; |
75 | 75 | ||
76 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
77 | +import static com.google.common.base.Predicates.notNull; | ||
78 | +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
76 | import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | 79 | import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; |
77 | import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; | 80 | import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; |
78 | -import static org.onlab.onos.net.DefaultAnnotations.union; | ||
79 | import static org.onlab.onos.net.DefaultAnnotations.merge; | 81 | import static org.onlab.onos.net.DefaultAnnotations.merge; |
82 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
83 | +import static org.onlab.onos.net.Link.State.ACTIVE; | ||
84 | +import static org.onlab.onos.net.Link.State.INACTIVE; | ||
80 | import static org.onlab.onos.net.Link.Type.DIRECT; | 85 | import static org.onlab.onos.net.Link.Type.DIRECT; |
81 | import static org.onlab.onos.net.Link.Type.INDIRECT; | 86 | import static org.onlab.onos.net.Link.Type.INDIRECT; |
82 | import static org.onlab.onos.net.LinkKey.linkKey; | 87 | import static org.onlab.onos.net.LinkKey.linkKey; |
83 | import static org.onlab.onos.net.link.LinkEvent.Type.*; | 88 | import static org.onlab.onos.net.link.LinkEvent.Type.*; |
89 | +import static org.onlab.onos.store.link.impl.GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT; | ||
84 | import static org.onlab.util.Tools.namedThreads; | 90 | import static org.onlab.util.Tools.namedThreads; |
85 | import static org.slf4j.LoggerFactory.getLogger; | 91 | import static org.slf4j.LoggerFactory.getLogger; |
86 | -import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
87 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
88 | -import static com.google.common.base.Predicates.notNull; | ||
89 | -import static org.onlab.onos.store.link.impl.GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT; | ||
90 | 92 | ||
91 | /** | 93 | /** |
92 | * Manages inventory of infrastructure links in distributed data store | 94 | * Manages inventory of infrastructure links in distributed data store |
... | @@ -261,8 +263,6 @@ public class GossipLinkStore | ... | @@ -261,8 +263,6 @@ public class GossipLinkStore |
261 | mergedDesc = map.get(providerId); | 263 | mergedDesc = map.get(providerId); |
262 | } | 264 | } |
263 | 265 | ||
264 | - | ||
265 | - | ||
266 | if (event != null) { | 266 | if (event != null) { |
267 | log.info("Notifying peers of a link update topology event from providerId: " | 267 | log.info("Notifying peers of a link update topology event from providerId: " |
268 | + "{} between src: {} and dst: {}", | 268 | + "{} between src: {} and dst: {}", |
... | @@ -278,6 +278,26 @@ public class GossipLinkStore | ... | @@ -278,6 +278,26 @@ public class GossipLinkStore |
278 | return event; | 278 | return event; |
279 | } | 279 | } |
280 | 280 | ||
281 | + @Override | ||
282 | + public LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst) { | ||
283 | + Link link = getLink(src, dst); | ||
284 | + if (link == null) { | ||
285 | + return null; | ||
286 | + } | ||
287 | + | ||
288 | + if (link.isDurable()) { | ||
289 | + // FIXME: this is not the right thing to call for the gossip store; will not sync link state!!! | ||
290 | + return link.state() == INACTIVE ? null : | ||
291 | + updateLink(linkKey(link.src(), link.dst()), link, | ||
292 | + new DefaultLink(link.providerId(), | ||
293 | + link.src(), link.dst(), | ||
294 | + link.type(), INACTIVE, | ||
295 | + link.isDurable(), | ||
296 | + link.annotations())); | ||
297 | + } | ||
298 | + return removeLink(src, dst); | ||
299 | + } | ||
300 | + | ||
281 | private LinkEvent createOrUpdateLinkInternal( | 301 | private LinkEvent createOrUpdateLinkInternal( |
282 | ProviderId providerId, | 302 | ProviderId providerId, |
283 | Timestamped<LinkDescription> linkDescription) { | 303 | Timestamped<LinkDescription> linkDescription) { |
... | @@ -333,7 +353,7 @@ public class GossipLinkStore | ... | @@ -333,7 +353,7 @@ public class GossipLinkStore |
333 | } | 353 | } |
334 | SparseAnnotations merged = union(existingLinkDescription.value().annotations(), | 354 | SparseAnnotations merged = union(existingLinkDescription.value().annotations(), |
335 | linkDescription.value().annotations()); | 355 | linkDescription.value().annotations()); |
336 | - newLinkDescription = new Timestamped<LinkDescription>( | 356 | + newLinkDescription = new Timestamped<>( |
337 | new DefaultLinkDescription( | 357 | new DefaultLinkDescription( |
338 | linkDescription.value().src(), | 358 | linkDescription.value().src(), |
339 | linkDescription.value().dst(), | 359 | linkDescription.value().dst(), |
... | @@ -357,7 +377,8 @@ public class GossipLinkStore | ... | @@ -357,7 +377,8 @@ public class GossipLinkStore |
357 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { | 377 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { |
358 | // Note: INDIRECT -> DIRECT transition only | 378 | // Note: INDIRECT -> DIRECT transition only |
359 | // so that BDDP discovered Link will not overwrite LDDP Link | 379 | // so that BDDP discovered Link will not overwrite LDDP Link |
360 | - if ((oldLink.type() == INDIRECT && newLink.type() == DIRECT) || | 380 | + if (oldLink.state() != newLink.state() || |
381 | + (oldLink.type() == INDIRECT && newLink.type() == DIRECT) || | ||
361 | !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { | 382 | !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { |
362 | 383 | ||
363 | links.put(key, newLink); | 384 | links.put(key, newLink); |
... | @@ -449,12 +470,8 @@ public class GossipLinkStore | ... | @@ -449,12 +470,8 @@ public class GossipLinkStore |
449 | // outdated remove request, ignore | 470 | // outdated remove request, ignore |
450 | return null; | 471 | return null; |
451 | } | 472 | } |
452 | - Link link = links.get(key); | ||
453 | - if (isDurable(link)) { | ||
454 | - return null; | ||
455 | - } | ||
456 | removedLinks.put(key, timestamp); | 473 | removedLinks.put(key, timestamp); |
457 | - links.remove(key); | 474 | + Link link = links.remove(key); |
458 | linkDescriptions.clear(); | 475 | linkDescriptions.clear(); |
459 | if (link != null) { | 476 | if (link != null) { |
460 | srcLinks.remove(link.src().deviceId(), key); | 477 | srcLinks.remove(link.src().deviceId(), key); |
... | @@ -465,11 +482,6 @@ public class GossipLinkStore | ... | @@ -465,11 +482,6 @@ public class GossipLinkStore |
465 | } | 482 | } |
466 | } | 483 | } |
467 | 484 | ||
468 | - // Indicates if the link has been marked as durable via annotations. | ||
469 | - private boolean isDurable(Link link) { | ||
470 | - return link != null && Objects.equals(link.annotations().value("durable"), "true"); | ||
471 | - } | ||
472 | - | ||
473 | private static <K, V> SetMultimap<K, V> createSynchronizedHashMultiMap() { | 485 | private static <K, V> SetMultimap<K, V> createSynchronizedHashMultiMap() { |
474 | return synchronizedSetMultimap(HashMultimap.<K, V>create()); | 486 | return synchronizedSetMultimap(HashMultimap.<K, V>create()); |
475 | } | 487 | } |
... | @@ -518,7 +530,10 @@ public class GossipLinkStore | ... | @@ -518,7 +530,10 @@ public class GossipLinkStore |
518 | annotations = merge(annotations, e.getValue().value().annotations()); | 530 | annotations = merge(annotations, e.getValue().value().annotations()); |
519 | } | 531 | } |
520 | 532 | ||
521 | - return new DefaultLink(baseProviderId, src, dst, type, annotations); | 533 | + boolean isDurable = Objects.equals(annotations.value(AnnotationKeys.DURABLE), "true"); |
534 | + boolean isActive = !Objects.equals(annotations.value(AnnotationKeys.INACTIVE), "true"); | ||
535 | + return new DefaultLink(baseProviderId, src, dst, type, | ||
536 | + isActive ? ACTIVE : INACTIVE, isDurable, annotations); | ||
522 | } | 537 | } |
523 | 538 | ||
524 | private Map<ProviderId, Timestamped<LinkDescription>> getOrCreateLinkDescriptions(LinkKey key) { | 539 | private Map<ProviderId, Timestamped<LinkDescription>> getOrCreateLinkDescriptions(LinkKey key) { |
... | @@ -538,9 +553,11 @@ public class GossipLinkStore | ... | @@ -538,9 +553,11 @@ public class GossipLinkStore |
538 | } | 553 | } |
539 | 554 | ||
540 | private final Function<LinkKey, Link> lookupLink = new LookupLink(); | 555 | private final Function<LinkKey, Link> lookupLink = new LookupLink(); |
556 | + | ||
541 | /** | 557 | /** |
542 | * Returns a Function to lookup Link instance using LinkKey from cache. | 558 | * Returns a Function to lookup Link instance using LinkKey from cache. |
543 | - * @return | 559 | + * |
560 | + * @return lookup link function | ||
544 | */ | 561 | */ |
545 | private Function<LinkKey, Link> lookupLink() { | 562 | private Function<LinkKey, Link> lookupLink() { |
546 | return lookupLink; | 563 | return lookupLink; | ... | ... |
... | @@ -49,6 +49,8 @@ import static com.google.common.collect.ImmutableSetMultimap.Builder; | ... | @@ -49,6 +49,8 @@ import static com.google.common.collect.ImmutableSetMultimap.Builder; |
49 | import static org.onlab.graph.GraphPathSearch.Result; | 49 | import static org.onlab.graph.GraphPathSearch.Result; |
50 | import static org.onlab.graph.TarjanGraphSearch.SCCResult; | 50 | import static org.onlab.graph.TarjanGraphSearch.SCCResult; |
51 | import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID; | 51 | import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID; |
52 | +import static org.onlab.onos.net.Link.State.ACTIVE; | ||
53 | +import static org.onlab.onos.net.Link.State.INACTIVE; | ||
52 | import static org.onlab.onos.net.Link.Type.INDIRECT; | 54 | import static org.onlab.onos.net.Link.Type.INDIRECT; |
53 | 55 | ||
54 | /** | 56 | /** |
... | @@ -434,7 +436,8 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -434,7 +436,8 @@ public class DefaultTopology extends AbstractModel implements Topology { |
434 | public double weight(TopologyEdge edge) { | 436 | public double weight(TopologyEdge edge) { |
435 | // To force preference to use direct paths first, make indirect | 437 | // To force preference to use direct paths first, make indirect |
436 | // links as expensive as the linear vertex traversal. | 438 | // links as expensive as the linear vertex traversal. |
437 | - return edge.link().type() == INDIRECT ? indirectLinkCost : 1; | 439 | + return edge.link().state() == ACTIVE ? |
440 | + (edge.link().type() == INDIRECT ? indirectLinkCost : 1) : -1; | ||
438 | } | 441 | } |
439 | } | 442 | } |
440 | 443 | ||
... | @@ -442,7 +445,7 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -442,7 +445,7 @@ public class DefaultTopology extends AbstractModel implements Topology { |
442 | private static class NoIndirectLinksWeight implements LinkWeight { | 445 | private static class NoIndirectLinksWeight implements LinkWeight { |
443 | @Override | 446 | @Override |
444 | public double weight(TopologyEdge edge) { | 447 | public double weight(TopologyEdge edge) { |
445 | - return edge.link().type() == INDIRECT ? -1 : 1; | 448 | + return edge.link().state() == INACTIVE || edge.link().type() == INDIRECT ? -1 : 1; |
446 | } | 449 | } |
447 | } | 450 | } |
448 | 451 | ... | ... |
... | @@ -15,15 +15,15 @@ | ... | @@ -15,15 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.store.serializers; | 16 | package org.onlab.onos.store.serializers; |
17 | 17 | ||
18 | -import org.onlab.onos.net.ConnectPoint; | ||
19 | -import org.onlab.onos.net.DefaultLink; | ||
20 | -import org.onlab.onos.net.Link.Type; | ||
21 | -import org.onlab.onos.net.provider.ProviderId; | ||
22 | - | ||
23 | import com.esotericsoftware.kryo.Kryo; | 18 | import com.esotericsoftware.kryo.Kryo; |
24 | import com.esotericsoftware.kryo.Serializer; | 19 | import com.esotericsoftware.kryo.Serializer; |
25 | import com.esotericsoftware.kryo.io.Input; | 20 | import com.esotericsoftware.kryo.io.Input; |
26 | import com.esotericsoftware.kryo.io.Output; | 21 | import com.esotericsoftware.kryo.io.Output; |
22 | +import org.onlab.onos.net.ConnectPoint; | ||
23 | +import org.onlab.onos.net.DefaultLink; | ||
24 | +import org.onlab.onos.net.Link.State; | ||
25 | +import org.onlab.onos.net.Link.Type; | ||
26 | +import org.onlab.onos.net.provider.ProviderId; | ||
27 | 27 | ||
28 | /** | 28 | /** |
29 | * Kryo Serializer for {@link DefaultLink}. | 29 | * Kryo Serializer for {@link DefaultLink}. |
... | @@ -44,6 +44,8 @@ public class DefaultLinkSerializer extends Serializer<DefaultLink> { | ... | @@ -44,6 +44,8 @@ public class DefaultLinkSerializer extends Serializer<DefaultLink> { |
44 | kryo.writeClassAndObject(output, object.src()); | 44 | kryo.writeClassAndObject(output, object.src()); |
45 | kryo.writeClassAndObject(output, object.dst()); | 45 | kryo.writeClassAndObject(output, object.dst()); |
46 | kryo.writeClassAndObject(output, object.type()); | 46 | kryo.writeClassAndObject(output, object.type()); |
47 | + kryo.writeClassAndObject(output, object.state()); | ||
48 | + kryo.writeClassAndObject(output, object.isDurable()); | ||
47 | } | 49 | } |
48 | 50 | ||
49 | @Override | 51 | @Override |
... | @@ -52,6 +54,8 @@ public class DefaultLinkSerializer extends Serializer<DefaultLink> { | ... | @@ -52,6 +54,8 @@ public class DefaultLinkSerializer extends Serializer<DefaultLink> { |
52 | ConnectPoint src = (ConnectPoint) kryo.readClassAndObject(input); | 54 | ConnectPoint src = (ConnectPoint) kryo.readClassAndObject(input); |
53 | ConnectPoint dst = (ConnectPoint) kryo.readClassAndObject(input); | 55 | ConnectPoint dst = (ConnectPoint) kryo.readClassAndObject(input); |
54 | Type linkType = (Type) kryo.readClassAndObject(input); | 56 | Type linkType = (Type) kryo.readClassAndObject(input); |
55 | - return new DefaultLink(providerId, src, dst, linkType); | 57 | + State state = (State) kryo.readClassAndObject(input); |
58 | + boolean isDurable = (boolean) kryo.readClassAndObject(input); | ||
59 | + return new DefaultLink(providerId, src, dst, linkType, state, isDurable); | ||
56 | } | 60 | } |
57 | } | 61 | } | ... | ... |
... | @@ -164,6 +164,7 @@ public final class KryoNamespaces { | ... | @@ -164,6 +164,7 @@ public final class KryoNamespaces { |
164 | DefaultPortDescription.class, | 164 | DefaultPortDescription.class, |
165 | Element.class, | 165 | Element.class, |
166 | Link.Type.class, | 166 | Link.Type.class, |
167 | + Link.State.class, | ||
167 | Timestamp.class, | 168 | Timestamp.class, |
168 | HostId.class, | 169 | HostId.class, |
169 | HostDescription.class, | 170 | HostDescription.class, | ... | ... |
... | @@ -49,6 +49,8 @@ import static com.google.common.collect.ImmutableSetMultimap.Builder; | ... | @@ -49,6 +49,8 @@ import static com.google.common.collect.ImmutableSetMultimap.Builder; |
49 | import static org.onlab.graph.GraphPathSearch.Result; | 49 | import static org.onlab.graph.GraphPathSearch.Result; |
50 | import static org.onlab.graph.TarjanGraphSearch.SCCResult; | 50 | import static org.onlab.graph.TarjanGraphSearch.SCCResult; |
51 | import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID; | 51 | import static org.onlab.onos.core.CoreService.CORE_PROVIDER_ID; |
52 | +import static org.onlab.onos.net.Link.State.ACTIVE; | ||
53 | +import static org.onlab.onos.net.Link.State.INACTIVE; | ||
52 | import static org.onlab.onos.net.Link.Type.INDIRECT; | 54 | import static org.onlab.onos.net.Link.Type.INDIRECT; |
53 | 55 | ||
54 | /** | 56 | /** |
... | @@ -434,7 +436,8 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -434,7 +436,8 @@ public class DefaultTopology extends AbstractModel implements Topology { |
434 | public double weight(TopologyEdge edge) { | 436 | public double weight(TopologyEdge edge) { |
435 | // To force preference to use direct paths first, make indirect | 437 | // To force preference to use direct paths first, make indirect |
436 | // links as expensive as the linear vertex traversal. | 438 | // links as expensive as the linear vertex traversal. |
437 | - return edge.link().type() == INDIRECT ? indirectLinkCost : 1; | 439 | + return edge.link().state() == ACTIVE ? |
440 | + (edge.link().type() == INDIRECT ? indirectLinkCost : 1) : -1; | ||
438 | } | 441 | } |
439 | } | 442 | } |
440 | 443 | ||
... | @@ -442,7 +445,7 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -442,7 +445,7 @@ public class DefaultTopology extends AbstractModel implements Topology { |
442 | private static class NoIndirectLinksWeight implements LinkWeight { | 445 | private static class NoIndirectLinksWeight implements LinkWeight { |
443 | @Override | 446 | @Override |
444 | public double weight(TopologyEdge edge) { | 447 | public double weight(TopologyEdge edge) { |
445 | - return edge.link().type() == INDIRECT ? -1 : 1; | 448 | + return edge.link().state() == INACTIVE || edge.link().type() == INDIRECT ? -1 : 1; |
446 | } | 449 | } |
447 | } | 450 | } |
448 | 451 | ... | ... |
... | @@ -19,20 +19,20 @@ import com.google.common.base.Function; | ... | @@ -19,20 +19,20 @@ import com.google.common.base.Function; |
19 | import com.google.common.collect.FluentIterable; | 19 | import com.google.common.collect.FluentIterable; |
20 | import com.google.common.collect.HashMultimap; | 20 | import com.google.common.collect.HashMultimap; |
21 | import com.google.common.collect.SetMultimap; | 21 | import com.google.common.collect.SetMultimap; |
22 | - | ||
23 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
24 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
25 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
26 | import org.apache.felix.scr.annotations.Service; | 25 | import org.apache.felix.scr.annotations.Service; |
26 | +import org.onlab.onos.net.AnnotationKeys; | ||
27 | import org.onlab.onos.net.AnnotationsUtil; | 27 | import org.onlab.onos.net.AnnotationsUtil; |
28 | import org.onlab.onos.net.ConnectPoint; | 28 | import org.onlab.onos.net.ConnectPoint; |
29 | import org.onlab.onos.net.DefaultAnnotations; | 29 | import org.onlab.onos.net.DefaultAnnotations; |
30 | import org.onlab.onos.net.DefaultLink; | 30 | import org.onlab.onos.net.DefaultLink; |
31 | import org.onlab.onos.net.DeviceId; | 31 | import org.onlab.onos.net.DeviceId; |
32 | import org.onlab.onos.net.Link; | 32 | import org.onlab.onos.net.Link; |
33 | -import org.onlab.onos.net.SparseAnnotations; | ||
34 | import org.onlab.onos.net.Link.Type; | 33 | import org.onlab.onos.net.Link.Type; |
35 | import org.onlab.onos.net.LinkKey; | 34 | import org.onlab.onos.net.LinkKey; |
35 | +import org.onlab.onos.net.SparseAnnotations; | ||
36 | import org.onlab.onos.net.link.DefaultLinkDescription; | 36 | import org.onlab.onos.net.link.DefaultLinkDescription; |
37 | import org.onlab.onos.net.link.LinkDescription; | 37 | import org.onlab.onos.net.link.LinkDescription; |
38 | import org.onlab.onos.net.link.LinkEvent; | 38 | import org.onlab.onos.net.link.LinkEvent; |
... | @@ -46,22 +46,24 @@ import java.util.Collections; | ... | @@ -46,22 +46,24 @@ import java.util.Collections; |
46 | import java.util.HashMap; | 46 | import java.util.HashMap; |
47 | import java.util.HashSet; | 47 | import java.util.HashSet; |
48 | import java.util.Map; | 48 | import java.util.Map; |
49 | +import java.util.Map.Entry; | ||
49 | import java.util.Objects; | 50 | import java.util.Objects; |
50 | import java.util.Set; | 51 | import java.util.Set; |
51 | -import java.util.Map.Entry; | ||
52 | import java.util.concurrent.ConcurrentHashMap; | 52 | import java.util.concurrent.ConcurrentHashMap; |
53 | import java.util.concurrent.ConcurrentMap; | 53 | import java.util.concurrent.ConcurrentMap; |
54 | 54 | ||
55 | -import static org.onlab.onos.net.DefaultAnnotations.union; | 55 | +import static com.google.common.base.Predicates.notNull; |
56 | +import static com.google.common.base.Verify.verifyNotNull; | ||
57 | +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
56 | import static org.onlab.onos.net.DefaultAnnotations.merge; | 58 | import static org.onlab.onos.net.DefaultAnnotations.merge; |
59 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
60 | +import static org.onlab.onos.net.Link.State.ACTIVE; | ||
61 | +import static org.onlab.onos.net.Link.State.INACTIVE; | ||
57 | import static org.onlab.onos.net.Link.Type.DIRECT; | 62 | import static org.onlab.onos.net.Link.Type.DIRECT; |
58 | import static org.onlab.onos.net.Link.Type.INDIRECT; | 63 | import static org.onlab.onos.net.Link.Type.INDIRECT; |
59 | import static org.onlab.onos.net.LinkKey.linkKey; | 64 | import static org.onlab.onos.net.LinkKey.linkKey; |
60 | import static org.onlab.onos.net.link.LinkEvent.Type.*; | 65 | import static org.onlab.onos.net.link.LinkEvent.Type.*; |
61 | import static org.slf4j.LoggerFactory.getLogger; | 66 | import static org.slf4j.LoggerFactory.getLogger; |
62 | -import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
63 | -import static com.google.common.base.Predicates.notNull; | ||
64 | -import static com.google.common.base.Verify.verifyNotNull; | ||
65 | 67 | ||
66 | /** | 68 | /** |
67 | * Manages inventory of infrastructure links using trivial in-memory structures | 69 | * Manages inventory of infrastructure links using trivial in-memory structures |
... | @@ -178,6 +180,25 @@ public class SimpleLinkStore | ... | @@ -178,6 +180,25 @@ public class SimpleLinkStore |
178 | } | 180 | } |
179 | } | 181 | } |
180 | 182 | ||
183 | + @Override | ||
184 | + public LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst) { | ||
185 | + Link link = getLink(src, dst); | ||
186 | + if (link == null) { | ||
187 | + return null; | ||
188 | + } | ||
189 | + | ||
190 | + if (link.isDurable()) { | ||
191 | + return link.state() == INACTIVE ? null : | ||
192 | + updateLink(linkKey(link.src(), link.dst()), link, | ||
193 | + new DefaultLink(link.providerId(), | ||
194 | + link.src(), link.dst(), | ||
195 | + link.type(), INACTIVE, | ||
196 | + link.isDurable(), | ||
197 | + link.annotations())); | ||
198 | + } | ||
199 | + return removeLink(src, dst); | ||
200 | + } | ||
201 | + | ||
181 | // Guarded by linkDescs value (=locking each Link) | 202 | // Guarded by linkDescs value (=locking each Link) |
182 | private LinkDescription createOrUpdateLinkDescription( | 203 | private LinkDescription createOrUpdateLinkDescription( |
183 | Map<ProviderId, LinkDescription> descs, | 204 | Map<ProviderId, LinkDescription> descs, |
... | @@ -197,8 +218,7 @@ public class SimpleLinkStore | ... | @@ -197,8 +218,7 @@ public class SimpleLinkStore |
197 | } | 218 | } |
198 | SparseAnnotations merged = union(oldDesc.annotations(), | 219 | SparseAnnotations merged = union(oldDesc.annotations(), |
199 | linkDescription.annotations()); | 220 | linkDescription.annotations()); |
200 | - newDesc = new DefaultLinkDescription( | 221 | + newDesc = new DefaultLinkDescription(linkDescription.src(), |
201 | - linkDescription.src(), | ||
202 | linkDescription.dst(), | 222 | linkDescription.dst(), |
203 | newType, merged); | 223 | newType, merged); |
204 | } | 224 | } |
... | @@ -217,7 +237,8 @@ public class SimpleLinkStore | ... | @@ -217,7 +237,8 @@ public class SimpleLinkStore |
217 | // Updates, if necessary the specified link and returns the appropriate event. | 237 | // Updates, if necessary the specified link and returns the appropriate event. |
218 | // Guarded by linkDescs value (=locking each Link) | 238 | // Guarded by linkDescs value (=locking each Link) |
219 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { | 239 | private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { |
220 | - if ((oldLink.type() == INDIRECT && newLink.type() == DIRECT) || | 240 | + if (oldLink.state() != newLink.state() || |
241 | + (oldLink.type() == INDIRECT && newLink.type() == DIRECT) || | ||
221 | !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { | 242 | !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { |
222 | 243 | ||
223 | links.put(key, newLink); | 244 | links.put(key, newLink); |
... | @@ -234,11 +255,7 @@ public class SimpleLinkStore | ... | @@ -234,11 +255,7 @@ public class SimpleLinkStore |
234 | final LinkKey key = linkKey(src, dst); | 255 | final LinkKey key = linkKey(src, dst); |
235 | Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key); | 256 | Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key); |
236 | synchronized (descs) { | 257 | synchronized (descs) { |
237 | - Link link = links.get(key); | 258 | + Link link = links.remove(key); |
238 | - if (isDurable(link)) { | ||
239 | - return null; | ||
240 | - } | ||
241 | - links.remove(key); | ||
242 | descs.clear(); | 259 | descs.clear(); |
243 | if (link != null) { | 260 | if (link != null) { |
244 | srcLinks.remove(link.src().deviceId(), key); | 261 | srcLinks.remove(link.src().deviceId(), key); |
... | @@ -249,11 +266,6 @@ public class SimpleLinkStore | ... | @@ -249,11 +266,6 @@ public class SimpleLinkStore |
249 | } | 266 | } |
250 | } | 267 | } |
251 | 268 | ||
252 | - // Indicates if the link has been marked as durable via annotations. | ||
253 | - private boolean isDurable(Link link) { | ||
254 | - return link != null && Objects.equals(link.annotations().value("durable"), "true"); | ||
255 | - } | ||
256 | - | ||
257 | private static <K, V> SetMultimap<K, V> createSynchronizedHashMultiMap() { | 269 | private static <K, V> SetMultimap<K, V> createSynchronizedHashMultiMap() { |
258 | return synchronizedSetMultimap(HashMultimap.<K, V>create()); | 270 | return synchronizedSetMultimap(HashMultimap.<K, V>create()); |
259 | } | 271 | } |
... | @@ -301,7 +313,10 @@ public class SimpleLinkStore | ... | @@ -301,7 +313,10 @@ public class SimpleLinkStore |
301 | annotations = merge(annotations, e.getValue().annotations()); | 313 | annotations = merge(annotations, e.getValue().annotations()); |
302 | } | 314 | } |
303 | 315 | ||
304 | - return new DefaultLink(primary , src, dst, type, annotations); | 316 | + boolean isDurable = Objects.equals(annotations.value(AnnotationKeys.DURABLE), "true"); |
317 | + boolean isActive = !Objects.equals(annotations.value(AnnotationKeys.INACTIVE), "true"); | ||
318 | + return new DefaultLink(primary, src, dst, type, | ||
319 | + isActive ? ACTIVE : INACTIVE, isDurable, annotations); | ||
305 | } | 320 | } |
306 | 321 | ||
307 | private Map<ProviderId, LinkDescription> getOrCreateLinkDescriptions(LinkKey key) { | 322 | private Map<ProviderId, LinkDescription> getOrCreateLinkDescriptions(LinkKey key) { |
... | @@ -321,6 +336,7 @@ public class SimpleLinkStore | ... | @@ -321,6 +336,7 @@ public class SimpleLinkStore |
321 | } | 336 | } |
322 | 337 | ||
323 | private final Function<LinkKey, Link> lookupLink = new LookupLink(); | 338 | private final Function<LinkKey, Link> lookupLink = new LookupLink(); |
339 | + | ||
324 | private Function<LinkKey, Link> lookupLink() { | 340 | private Function<LinkKey, Link> lookupLink() { |
325 | return lookupLink; | 341 | return lookupLink; |
326 | } | 342 | } | ... | ... |
... | @@ -23,6 +23,7 @@ import org.junit.Before; | ... | @@ -23,6 +23,7 @@ import org.junit.Before; |
23 | import org.junit.BeforeClass; | 23 | import org.junit.BeforeClass; |
24 | import org.junit.Ignore; | 24 | import org.junit.Ignore; |
25 | import org.junit.Test; | 25 | import org.junit.Test; |
26 | +import org.onlab.onos.net.AnnotationKeys; | ||
26 | import org.onlab.onos.net.ConnectPoint; | 27 | import org.onlab.onos.net.ConnectPoint; |
27 | import org.onlab.onos.net.DefaultAnnotations; | 28 | import org.onlab.onos.net.DefaultAnnotations; |
28 | import org.onlab.onos.net.DeviceId; | 29 | import org.onlab.onos.net.DeviceId; |
... | @@ -80,6 +81,23 @@ public class SimpleLinkStoreTest { | ... | @@ -80,6 +81,23 @@ public class SimpleLinkStoreTest { |
80 | .set("B4", "b4") | 81 | .set("B4", "b4") |
81 | .build(); | 82 | .build(); |
82 | 83 | ||
84 | + private static final SparseAnnotations DA1 = DefaultAnnotations.builder() | ||
85 | + .set("A1", "a1") | ||
86 | + .set("B1", "b1") | ||
87 | + .set(AnnotationKeys.DURABLE, "true") | ||
88 | + .build(); | ||
89 | + private static final SparseAnnotations DA2 = DefaultAnnotations.builder() | ||
90 | + .set("A2", "a2") | ||
91 | + .set("B2", "b2") | ||
92 | + .set(AnnotationKeys.DURABLE, "true") | ||
93 | + .build(); | ||
94 | + private static final SparseAnnotations NDA1 = DefaultAnnotations.builder() | ||
95 | + .set("A1", "a1") | ||
96 | + .set("B1", "b1") | ||
97 | + .remove(AnnotationKeys.DURABLE) | ||
98 | + .build(); | ||
99 | + | ||
100 | + | ||
83 | 101 | ||
84 | private SimpleLinkStore simpleLinkStore; | 102 | private SimpleLinkStore simpleLinkStore; |
85 | private LinkStore linkStore; | 103 | private LinkStore linkStore; |
... | @@ -105,17 +123,19 @@ public class SimpleLinkStoreTest { | ... | @@ -105,17 +123,19 @@ public class SimpleLinkStoreTest { |
105 | } | 123 | } |
106 | 124 | ||
107 | private void putLink(DeviceId srcId, PortNumber srcNum, | 125 | private void putLink(DeviceId srcId, PortNumber srcNum, |
108 | - DeviceId dstId, PortNumber dstNum, Type type, | 126 | + DeviceId dstId, PortNumber dstNum, |
127 | + Type type, boolean isDurable, | ||
109 | SparseAnnotations... annotations) { | 128 | SparseAnnotations... annotations) { |
110 | ConnectPoint src = new ConnectPoint(srcId, srcNum); | 129 | ConnectPoint src = new ConnectPoint(srcId, srcNum); |
111 | ConnectPoint dst = new ConnectPoint(dstId, dstNum); | 130 | ConnectPoint dst = new ConnectPoint(dstId, dstNum); |
112 | - linkStore.createOrUpdateLink(PID, new DefaultLinkDescription(src, dst, type, annotations)); | 131 | + linkStore.createOrUpdateLink(PID, new DefaultLinkDescription(src, dst, type, |
132 | + annotations)); | ||
113 | } | 133 | } |
114 | 134 | ||
115 | private void putLink(LinkKey key, Type type, SparseAnnotations... annotations) { | 135 | private void putLink(LinkKey key, Type type, SparseAnnotations... annotations) { |
116 | putLink(key.src().deviceId(), key.src().port(), | 136 | putLink(key.src().deviceId(), key.src().port(), |
117 | key.dst().deviceId(), key.dst().port(), | 137 | key.dst().deviceId(), key.dst().port(), |
118 | - type, annotations); | 138 | + type, false, annotations); |
119 | } | 139 | } |
120 | 140 | ||
121 | private static void assertLink(DeviceId srcId, PortNumber srcNum, | 141 | private static void assertLink(DeviceId srcId, PortNumber srcNum, |
... | @@ -138,9 +158,9 @@ public class SimpleLinkStoreTest { | ... | @@ -138,9 +158,9 @@ public class SimpleLinkStoreTest { |
138 | public final void testGetLinkCount() { | 158 | public final void testGetLinkCount() { |
139 | assertEquals("initialy empty", 0, linkStore.getLinkCount()); | 159 | assertEquals("initialy empty", 0, linkStore.getLinkCount()); |
140 | 160 | ||
141 | - putLink(DID1, P1, DID2, P2, DIRECT); | 161 | + putLink(DID1, P1, DID2, P2, DIRECT, false); |
142 | - putLink(DID2, P2, DID1, P1, DIRECT); | 162 | + putLink(DID2, P2, DID1, P1, DIRECT, false); |
143 | - putLink(DID1, P1, DID2, P2, DIRECT); | 163 | + putLink(DID1, P1, DID2, P2, DIRECT, false); |
144 | 164 | ||
145 | assertEquals("expecting 2 unique link", 2, linkStore.getLinkCount()); | 165 | assertEquals("expecting 2 unique link", 2, linkStore.getLinkCount()); |
146 | } | 166 | } |
... | @@ -360,6 +380,47 @@ public class SimpleLinkStoreTest { | ... | @@ -360,6 +380,47 @@ public class SimpleLinkStoreTest { |
360 | 380 | ||
361 | 381 | ||
362 | @Test | 382 | @Test |
383 | + public final void testRemoveOrDownLink() { | ||
384 | + removeOrDownLink(false); | ||
385 | + } | ||
386 | + | ||
387 | + @Test | ||
388 | + public final void testRemoveOrDownLinkDurable() { | ||
389 | + removeOrDownLink(true); | ||
390 | + } | ||
391 | + | ||
392 | + private void removeOrDownLink(boolean isDurable) { | ||
393 | + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); | ||
394 | + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); | ||
395 | + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); | ||
396 | + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1); | ||
397 | + | ||
398 | + putLink(linkId1, DIRECT, isDurable ? DA1 : A1); | ||
399 | + putLink(linkId2, DIRECT, isDurable ? DA2 : A2); | ||
400 | + | ||
401 | + // DID1,P1 => DID2,P2 | ||
402 | + // DID2,P2 => DID1,P1 | ||
403 | + // DID1,P2 => DID2,P3 | ||
404 | + | ||
405 | + LinkEvent event = linkStore.removeOrDownLink(d1P1, d2P2); | ||
406 | + assertEquals(isDurable ? LINK_UPDATED : LINK_REMOVED, event.type()); | ||
407 | + assertAnnotationsEquals(event.subject().annotations(), isDurable ? DA1 : A1); | ||
408 | + LinkEvent event2 = linkStore.removeOrDownLink(d1P1, d2P2); | ||
409 | + assertNull(event2); | ||
410 | + | ||
411 | + assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1)); | ||
412 | + assertAnnotationsEquals(linkStore.getLink(d2P2, d1P1).annotations(), | ||
413 | + isDurable ? DA2 : A2); | ||
414 | + | ||
415 | + // annotations, etc. should not survive remove | ||
416 | + if (!isDurable) { | ||
417 | + putLink(linkId1, DIRECT); | ||
418 | + assertLink(linkId1, DIRECT, linkStore.getLink(d1P1, d2P2)); | ||
419 | + assertAnnotationsEquals(linkStore.getLink(d1P1, d2P2).annotations()); | ||
420 | + } | ||
421 | + } | ||
422 | + | ||
423 | + @Test | ||
363 | public final void testRemoveLink() { | 424 | public final void testRemoveLink() { |
364 | final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); | 425 | final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); |
365 | final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); | 426 | final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); |
... | @@ -402,6 +463,30 @@ public class SimpleLinkStoreTest { | ... | @@ -402,6 +463,30 @@ public class SimpleLinkStoreTest { |
402 | assertNotNull(linkStore.getLink(src, dst)); | 463 | assertNotNull(linkStore.getLink(src, dst)); |
403 | } | 464 | } |
404 | 465 | ||
466 | + @Test | ||
467 | + public void testDurableToNonDurable() { | ||
468 | + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); | ||
469 | + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); | ||
470 | + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); | ||
471 | + | ||
472 | + putLink(linkId1, DIRECT, DA1); | ||
473 | + assertTrue("should be be durable", linkStore.getLink(d1P1, d2P2).isDurable()); | ||
474 | + putLink(linkId1, DIRECT, NDA1); | ||
475 | + assertFalse("should not be durable", linkStore.getLink(d1P1, d2P2).isDurable()); | ||
476 | + } | ||
477 | + | ||
478 | + @Test | ||
479 | + public void testNonDurableToDurable() { | ||
480 | + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); | ||
481 | + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); | ||
482 | + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); | ||
483 | + | ||
484 | + putLink(linkId1, DIRECT, A1); | ||
485 | + assertFalse("should not be durable", linkStore.getLink(d1P1, d2P2).isDurable()); | ||
486 | + putLink(linkId1, DIRECT, DA1); | ||
487 | + assertTrue("should be durable", linkStore.getLink(d1P1, d2P2).isDurable()); | ||
488 | + } | ||
489 | + | ||
405 | // If Delegates should be called only on remote events, | 490 | // If Delegates should be called only on remote events, |
406 | // then Simple* should never call them, thus not test required. | 491 | // then Simple* should never call them, thus not test required. |
407 | @Ignore("Ignore until Delegate spec. is clear.") | 492 | @Ignore("Ignore until Delegate spec. is clear.") |
... | @@ -451,7 +536,7 @@ public class SimpleLinkStoreTest { | ... | @@ -451,7 +536,7 @@ public class SimpleLinkStoreTest { |
451 | 536 | ||
452 | linkStore.unsetDelegate(checkUpdate); | 537 | linkStore.unsetDelegate(checkUpdate); |
453 | linkStore.setDelegate(checkRemove); | 538 | linkStore.setDelegate(checkRemove); |
454 | - linkStore.removeLink(d1P1, d2P2); | 539 | + linkStore.removeOrDownLink(d1P1, d2P2); |
455 | assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); | 540 | assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); |
456 | } | 541 | } |
457 | } | 542 | } | ... | ... |
-
Please register or login to post a comment