alshabib

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

Showing 19 changed files with 956 additions and 41 deletions
...@@ -56,6 +56,13 @@ public interface MastershipService { ...@@ -56,6 +56,13 @@ public interface MastershipService {
56 Set<DeviceId> getDevicesOf(NodeId nodeId); 56 Set<DeviceId> getDevicesOf(NodeId nodeId);
57 57
58 /** 58 /**
59 + * Returns the mastership term service for getting term information.
60 + *
61 + * @return the MastershipTermService for this mastership manager
62 + */
63 + MastershipTermService requestTermService();
64 +
65 + /**
59 * Adds the specified mastership change listener. 66 * Adds the specified mastership change listener.
60 * 67 *
61 * @param listener the mastership listener 68 * @param listener the mastership listener
......
...@@ -55,4 +55,13 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD ...@@ -55,4 +55,13 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD
55 * @return a mastership event 55 * @return a mastership event
56 */ 56 */
57 MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId); 57 MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId);
58 +
59 + /**
60 + * Returns the current master and number of past mastership hand-offs
61 + * (terms) for a device.
62 + *
63 + * @param deviceId the device identifier
64 + * @return the current master's ID and the term value for device, or null
65 + */
66 + MastershipTerm getTermFor(DeviceId deviceId);
58 } 67 }
......
1 package org.onlab.onos.cluster; 1 package org.onlab.onos.cluster;
2 2
3 -public class MastershipTerm { 3 +import java.util.Objects;
4 - private final NodeId master = null; 4 +
5 +public final class MastershipTerm {
6 +
7 + private final NodeId master;
5 private int termNumber; 8 private int termNumber;
9 +
10 + private MastershipTerm(NodeId master, int term) {
11 + this.master = master;
12 + this.termNumber = term;
13 + }
14 +
15 + public static MastershipTerm of(NodeId master, int term) {
16 + return new MastershipTerm(master, term);
17 + }
18 +
19 + public NodeId master() {
20 + return master;
21 + }
22 +
23 + public int termNumber() {
24 + return termNumber;
25 + }
26 +
27 + @Override
28 + public int hashCode() {
29 + return Objects.hash(master, termNumber);
30 + }
31 +
32 + @Override
33 + public boolean equals(Object other) {
34 + if (this == other) {
35 + return true;
36 + }
37 + if (other instanceof MastershipTerm) {
38 + MastershipTerm that = (MastershipTerm) other;
39 + if (!this.master.equals(that.master)) {
40 + return false;
41 + }
42 + if (this.termNumber != that.termNumber) {
43 + return false;
44 + }
45 + return true;
46 + }
47 + return false;
48 + }
6 } 49 }
......
1 +package org.onlab.onos.net;
2 +
3 +import java.util.Objects;
4 +
5 +import com.google.common.base.MoreObjects;
6 +
7 +// TODO Consider renaming.
8 +// it's an identifier for a Link, but it's not ElementId, so not using LinkId.
9 +/**
10 + * Immutable representation of a link identity.
11 + */
12 +public class LinkKey {
13 +
14 + private final ConnectPoint src;
15 + private final ConnectPoint dst;
16 +
17 + /**
18 + * Returns source connection point.
19 + *
20 + * @return source connection point
21 + */
22 + public ConnectPoint src() {
23 + return src;
24 + }
25 +
26 + /**
27 + * Returns destination connection point.
28 + *
29 + * @return destination connection point
30 + */
31 + public ConnectPoint dst() {
32 + return dst;
33 + }
34 +
35 + /**
36 + * Creates a link identifier with source and destination connection point.
37 + *
38 + * @param src source connection point
39 + * @param dst destination connection point
40 + */
41 + public LinkKey(ConnectPoint src, ConnectPoint dst) {
42 + this.src = src;
43 + this.dst = dst;
44 + }
45 +
46 + @Override
47 + public int hashCode() {
48 + return Objects.hash(src(), dst);
49 + }
50 +
51 + @Override
52 + public boolean equals(Object obj) {
53 + if (this == obj) {
54 + return true;
55 + }
56 + if (obj instanceof LinkKey) {
57 + final LinkKey other = (LinkKey) obj;
58 + return Objects.equals(this.src(), other.src()) &&
59 + Objects.equals(this.dst, other.dst);
60 + }
61 + return false;
62 + }
63 +
64 + @Override
65 + public String toString() {
66 + return MoreObjects.toStringHelper(getClass())
67 + .add("src", src())
68 + .add("dst", dst)
69 + .toString();
70 + }
71 +}
...@@ -40,4 +40,9 @@ public class MastershipServiceAdapter implements MastershipService { ...@@ -40,4 +40,9 @@ public class MastershipServiceAdapter implements MastershipService {
40 @Override 40 @Override
41 public void removeListener(MastershipListener listener) { 41 public void removeListener(MastershipListener listener) {
42 } 42 }
43 +
44 + @Override
45 + public MastershipTermService requestTermService() {
46 + return null;
47 + }
43 } 48 }
......
...@@ -12,6 +12,8 @@ import org.onlab.onos.cluster.MastershipEvent; ...@@ -12,6 +12,8 @@ import org.onlab.onos.cluster.MastershipEvent;
12 import org.onlab.onos.cluster.MastershipListener; 12 import org.onlab.onos.cluster.MastershipListener;
13 import org.onlab.onos.cluster.MastershipService; 13 import org.onlab.onos.cluster.MastershipService;
14 import org.onlab.onos.cluster.MastershipStore; 14 import org.onlab.onos.cluster.MastershipStore;
15 +import org.onlab.onos.cluster.MastershipTerm;
16 +import org.onlab.onos.cluster.MastershipTermService;
15 import org.onlab.onos.cluster.NodeId; 17 import org.onlab.onos.cluster.NodeId;
16 import org.onlab.onos.event.AbstractListenerRegistry; 18 import org.onlab.onos.event.AbstractListenerRegistry;
17 import org.onlab.onos.event.EventDeliveryService; 19 import org.onlab.onos.event.EventDeliveryService;
...@@ -103,6 +105,12 @@ public class MastershipManager ...@@ -103,6 +105,12 @@ public class MastershipManager
103 return store.getDevices(nodeId); 105 return store.getDevices(nodeId);
104 } 106 }
105 107
108 +
109 + @Override
110 + public MastershipTermService requestTermService() {
111 + return new InternalMastershipTermService();
112 + }
113 +
106 @Override 114 @Override
107 public void addListener(MastershipListener listener) { 115 public void addListener(MastershipListener listener) {
108 checkNotNull(listener); 116 checkNotNull(listener);
...@@ -124,4 +132,13 @@ public class MastershipManager ...@@ -124,4 +132,13 @@ public class MastershipManager
124 } 132 }
125 } 133 }
126 134
135 + private class InternalMastershipTermService implements MastershipTermService {
136 +
137 + @Override
138 + public MastershipTerm getMastershipTerm(DeviceId deviceId) {
139 + return store.getTermFor(deviceId);
140 + }
141 +
142 + }
143 +
127 } 144 }
......
...@@ -11,6 +11,7 @@ import org.onlab.onos.cluster.ControllerNode; ...@@ -11,6 +11,7 @@ import org.onlab.onos.cluster.ControllerNode;
11 import org.onlab.onos.cluster.ControllerNode.State; 11 import org.onlab.onos.cluster.ControllerNode.State;
12 import org.onlab.onos.cluster.DefaultControllerNode; 12 import org.onlab.onos.cluster.DefaultControllerNode;
13 import org.onlab.onos.cluster.MastershipService; 13 import org.onlab.onos.cluster.MastershipService;
14 +import org.onlab.onos.cluster.MastershipTermService;
14 import org.onlab.onos.cluster.NodeId; 15 import org.onlab.onos.cluster.NodeId;
15 import org.onlab.onos.event.impl.TestEventDispatcher; 16 import org.onlab.onos.event.impl.TestEventDispatcher;
16 import org.onlab.onos.net.DeviceId; 17 import org.onlab.onos.net.DeviceId;
...@@ -100,6 +101,20 @@ public class MastershipManagerTest { ...@@ -100,6 +101,20 @@ public class MastershipManagerTest {
100 assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); 101 assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size());
101 } 102 }
102 103
104 + @Test
105 + public void termService() {
106 + MastershipTermService ts = mgr.requestTermService();
107 +
108 + //term = 0 for both
109 + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
110 + assertEquals("inconsistent term: ", 0, ts.getMastershipTerm(DEV_MASTER).termNumber());
111 +
112 + //hand devices to NID_LOCAL and back: term = 2
113 + mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
114 + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
115 + assertEquals("inconsistent terms: ", 2, ts.getMastershipTerm(DEV_MASTER).termNumber());
116 + }
117 +
103 private final class TestClusterService implements ClusterService { 118 private final class TestClusterService implements ClusterService {
104 119
105 ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST); 120 ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
......
...@@ -15,6 +15,7 @@ import org.onlab.onos.cluster.ClusterService; ...@@ -15,6 +15,7 @@ import org.onlab.onos.cluster.ClusterService;
15 import org.onlab.onos.cluster.MastershipEvent; 15 import org.onlab.onos.cluster.MastershipEvent;
16 import org.onlab.onos.cluster.MastershipStore; 16 import org.onlab.onos.cluster.MastershipStore;
17 import org.onlab.onos.cluster.MastershipStoreDelegate; 17 import org.onlab.onos.cluster.MastershipStoreDelegate;
18 +import org.onlab.onos.cluster.MastershipTerm;
18 import org.onlab.onos.cluster.NodeId; 19 import org.onlab.onos.cluster.NodeId;
19 import org.onlab.onos.net.DeviceId; 20 import org.onlab.onos.net.DeviceId;
20 import org.onlab.onos.net.MastershipRole; 21 import org.onlab.onos.net.MastershipRole;
...@@ -115,4 +116,10 @@ public class DistributedMastershipStore ...@@ -115,4 +116,10 @@ public class DistributedMastershipStore
115 return nodeId.equals(master) ? MastershipRole.MASTER : MastershipRole.STANDBY; 116 return nodeId.equals(master) ? MastershipRole.MASTER : MastershipRole.STANDBY;
116 } 117 }
117 118
119 + @Override
120 + public MastershipTerm getTermFor(DeviceId deviceId) {
121 + // TODO Auto-generated method stub
122 + return null;
123 + }
124 +
118 } 125 }
......
...@@ -369,7 +369,7 @@ public class DistributedDeviceStore ...@@ -369,7 +369,7 @@ public class DistributedDeviceStore
369 } 369 }
370 370
371 @Override 371 @Override
372 - protected void onUpdate(DeviceId deviceId, DefaultDevice device) { 372 + protected void onUpdate(DeviceId deviceId, DefaultDevice oldDevice, DefaultDevice device) {
373 notifyDelegate(new DeviceEvent(DEVICE_UPDATED, device)); 373 notifyDelegate(new DeviceEvent(DEVICE_UPDATED, device));
374 } 374 }
375 } 375 }
...@@ -390,7 +390,7 @@ public class DistributedDeviceStore ...@@ -390,7 +390,7 @@ public class DistributedDeviceStore
390 } 390 }
391 391
392 @Override 392 @Override
393 - protected void onUpdate(DeviceId deviceId, Map<PortNumber, Port> ports) { 393 + protected void onUpdate(DeviceId deviceId, Map<PortNumber, Port> oldPorts, Map<PortNumber, Port> ports) {
394 // notifyDelegate(new DeviceEvent(PORT_UPDATED, getDevice(deviceId))); 394 // notifyDelegate(new DeviceEvent(PORT_UPDATED, getDevice(deviceId)));
395 } 395 }
396 } 396 }
......
...@@ -101,7 +101,7 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -101,7 +101,7 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
101 V newVal = deserialize(event.getValue()); 101 V newVal = deserialize(event.getValue());
102 Optional<V> newValue = Optional.of(newVal); 102 Optional<V> newValue = Optional.of(newVal);
103 cache.asMap().replace(key, oldValue, newValue); 103 cache.asMap().replace(key, oldValue, newValue);
104 - onUpdate(key, newVal); 104 + onUpdate(key, oldVal, newVal);
105 } 105 }
106 106
107 @Override 107 @Override
...@@ -125,9 +125,10 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -125,9 +125,10 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
125 * Cache entry update hook. 125 * Cache entry update hook.
126 * 126 *
127 * @param key new key 127 * @param key new key
128 + * @param oldValue old value
128 * @param newVal new value 129 * @param newVal new value
129 */ 130 */
130 - protected void onUpdate(K key, V newVal) { 131 + protected void onUpdate(K key, V oldValue, V newVal) {
131 } 132 }
132 133
133 /** 134 /**
......
...@@ -14,19 +14,26 @@ import org.apache.felix.scr.annotations.Service; ...@@ -14,19 +14,26 @@ import org.apache.felix.scr.annotations.Service;
14 import org.onlab.onos.cluster.ControllerNode; 14 import org.onlab.onos.cluster.ControllerNode;
15 import org.onlab.onos.cluster.DefaultControllerNode; 15 import org.onlab.onos.cluster.DefaultControllerNode;
16 import org.onlab.onos.cluster.NodeId; 16 import org.onlab.onos.cluster.NodeId;
17 +import org.onlab.onos.net.ConnectPoint;
17 import org.onlab.onos.net.DefaultDevice; 18 import org.onlab.onos.net.DefaultDevice;
19 +import org.onlab.onos.net.DefaultLink;
18 import org.onlab.onos.net.DefaultPort; 20 import org.onlab.onos.net.DefaultPort;
19 import org.onlab.onos.net.Device; 21 import org.onlab.onos.net.Device;
20 import org.onlab.onos.net.DeviceId; 22 import org.onlab.onos.net.DeviceId;
21 import org.onlab.onos.net.Element; 23 import org.onlab.onos.net.Element;
24 +import org.onlab.onos.net.Link;
25 +import org.onlab.onos.net.LinkKey;
22 import org.onlab.onos.net.MastershipRole; 26 import org.onlab.onos.net.MastershipRole;
23 import org.onlab.onos.net.Port; 27 import org.onlab.onos.net.Port;
24 import org.onlab.onos.net.PortNumber; 28 import org.onlab.onos.net.PortNumber;
25 import org.onlab.onos.net.provider.ProviderId; 29 import org.onlab.onos.net.provider.ProviderId;
26 import org.onlab.onos.store.common.StoreService; 30 import org.onlab.onos.store.common.StoreService;
31 +import org.onlab.onos.store.serializers.ConnectPointSerializer;
32 +import org.onlab.onos.store.serializers.DefaultLinkSerializer;
27 import org.onlab.onos.store.serializers.DefaultPortSerializer; 33 import org.onlab.onos.store.serializers.DefaultPortSerializer;
28 import org.onlab.onos.store.serializers.DeviceIdSerializer; 34 import org.onlab.onos.store.serializers.DeviceIdSerializer;
29 import org.onlab.onos.store.serializers.IpPrefixSerializer; 35 import org.onlab.onos.store.serializers.IpPrefixSerializer;
36 +import org.onlab.onos.store.serializers.LinkKeySerializer;
30 import org.onlab.onos.store.serializers.NodeIdSerializer; 37 import org.onlab.onos.store.serializers.NodeIdSerializer;
31 import org.onlab.onos.store.serializers.OnosTimestampSerializer; 38 import org.onlab.onos.store.serializers.OnosTimestampSerializer;
32 import org.onlab.onos.store.serializers.PortNumberSerializer; 39 import org.onlab.onos.store.serializers.PortNumberSerializer;
...@@ -84,7 +91,9 @@ public class StoreManager implements StoreService { ...@@ -84,7 +91,9 @@ public class StoreManager implements StoreService {
84 DefaultDevice.class, 91 DefaultDevice.class,
85 MastershipRole.class, 92 MastershipRole.class,
86 Port.class, 93 Port.class,
87 - Element.class 94 + Element.class,
95 +
96 + Link.Type.class
88 ) 97 )
89 .register(IpPrefix.class, new IpPrefixSerializer()) 98 .register(IpPrefix.class, new IpPrefixSerializer())
90 .register(URI.class, new URISerializer()) 99 .register(URI.class, new URISerializer())
...@@ -94,6 +103,9 @@ public class StoreManager implements StoreService { ...@@ -94,6 +103,9 @@ public class StoreManager implements StoreService {
94 .register(PortNumber.class, new PortNumberSerializer()) 103 .register(PortNumber.class, new PortNumberSerializer())
95 .register(DefaultPort.class, new DefaultPortSerializer()) 104 .register(DefaultPort.class, new DefaultPortSerializer())
96 .register(OnosTimestamp.class, new OnosTimestampSerializer()) 105 .register(OnosTimestamp.class, new OnosTimestampSerializer())
106 + .register(LinkKey.class, new LinkKeySerializer())
107 + .register(ConnectPoint.class, new ConnectPointSerializer())
108 + .register(DefaultLink.class, new DefaultLinkSerializer())
97 .build() 109 .build()
98 .populate(10); 110 .populate(10);
99 } 111 }
......
1 +package org.onlab.onos.store.link.impl;
2 +
3 +import static com.google.common.cache.CacheBuilder.newBuilder;
4 +import static org.onlab.onos.net.Link.Type.DIRECT;
5 +import static org.onlab.onos.net.Link.Type.INDIRECT;
6 +import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
7 +import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
8 +import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED;
9 +import static org.slf4j.LoggerFactory.getLogger;
10 +
11 +import java.util.HashSet;
12 +import java.util.Set;
13 +import org.apache.felix.scr.annotations.Activate;
14 +import org.apache.felix.scr.annotations.Component;
15 +import org.apache.felix.scr.annotations.Deactivate;
16 +import org.apache.felix.scr.annotations.Service;
17 +import org.onlab.onos.net.ConnectPoint;
18 +import org.onlab.onos.net.DefaultLink;
19 +import org.onlab.onos.net.DeviceId;
20 +import org.onlab.onos.net.Link;
21 +import org.onlab.onos.net.LinkKey;
22 +import org.onlab.onos.net.link.LinkDescription;
23 +import org.onlab.onos.net.link.LinkEvent;
24 +import org.onlab.onos.net.link.LinkStore;
25 +import org.onlab.onos.net.link.LinkStoreDelegate;
26 +import org.onlab.onos.net.provider.ProviderId;
27 +import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache;
28 +import org.onlab.onos.store.impl.AbstractDistributedStore;
29 +import org.onlab.onos.store.impl.OptionalCacheLoader;
30 +import org.slf4j.Logger;
31 +
32 +import com.google.common.base.Optional;
33 +import com.google.common.cache.LoadingCache;
34 +import com.google.common.collect.HashMultimap;
35 +import com.google.common.collect.ImmutableSet;
36 +import com.google.common.collect.Multimap;
37 +import com.google.common.collect.ImmutableSet.Builder;
38 +import com.hazelcast.core.IMap;
39 +
40 +/**
41 + * Manages inventory of infrastructure links using Hazelcast-backed map.
42 + */
43 +@Component(immediate = true)
44 +@Service
45 +public class DistributedLinkStore
46 + extends AbstractDistributedStore<LinkEvent, LinkStoreDelegate>
47 + implements LinkStore {
48 +
49 + private final Logger log = getLogger(getClass());
50 +
51 + // Link inventory
52 + private IMap<byte[], byte[]> rawLinks;
53 + private LoadingCache<LinkKey, Optional<DefaultLink>> links;
54 +
55 + // TODO synchronize?
56 + // Egress and ingress link sets
57 + private final Multimap<DeviceId, Link> srcLinks = HashMultimap.create();
58 + private final Multimap<DeviceId, Link> dstLinks = HashMultimap.create();
59 +
60 + @Override
61 + @Activate
62 + public void activate() {
63 + super.activate();
64 +
65 + boolean includeValue = true;
66 +
67 + // TODO decide on Map name scheme to avoid collision
68 + rawLinks = theInstance.getMap("links");
69 + final OptionalCacheLoader<LinkKey, DefaultLink> linkLoader
70 + = new OptionalCacheLoader<>(storeService, rawLinks);
71 + links = new AbsentInvalidatingLoadingCache<>(newBuilder().build(linkLoader));
72 + // refresh/populate cache based on notification from other instance
73 + rawLinks.addEntryListener(new RemoteLinkEventHandler(links), includeValue);
74 +
75 + loadLinkCache();
76 +
77 + log.info("Started");
78 + }
79 +
80 + @Deactivate
81 + public void deactivate() {
82 + super.activate();
83 + log.info("Stopped");
84 + }
85 +
86 + private void loadLinkCache() {
87 + for (byte[] keyBytes : rawLinks.keySet()) {
88 + final LinkKey id = deserialize(keyBytes);
89 + links.refresh(id);
90 + }
91 + }
92 +
93 + @Override
94 + public int getLinkCount() {
95 + return links.asMap().size();
96 + }
97 +
98 + @Override
99 + public Iterable<Link> getLinks() {
100 + Builder<Link> builder = ImmutableSet.builder();
101 + for (Optional<DefaultLink> e : links.asMap().values()) {
102 + if (e.isPresent()) {
103 + builder.add(e.get());
104 + }
105 + }
106 + return builder.build();
107 + }
108 +
109 + @Override
110 + public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
111 + return ImmutableSet.copyOf(srcLinks.get(deviceId));
112 + }
113 +
114 + @Override
115 + public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
116 + return ImmutableSet.copyOf(dstLinks.get(deviceId));
117 + }
118 +
119 + @Override
120 + public Link getLink(ConnectPoint src, ConnectPoint dst) {
121 + return links.getUnchecked(new LinkKey(src, dst)).orNull();
122 + }
123 +
124 + @Override
125 + public Set<Link> getEgressLinks(ConnectPoint src) {
126 + Set<Link> egress = new HashSet<>();
127 + for (Link link : srcLinks.get(src.deviceId())) {
128 + if (link.src().equals(src)) {
129 + egress.add(link);
130 + }
131 + }
132 + return egress;
133 + }
134 +
135 + @Override
136 + public Set<Link> getIngressLinks(ConnectPoint dst) {
137 + Set<Link> ingress = new HashSet<>();
138 + for (Link link : dstLinks.get(dst.deviceId())) {
139 + if (link.dst().equals(dst)) {
140 + ingress.add(link);
141 + }
142 + }
143 + return ingress;
144 + }
145 +
146 + @Override
147 + public LinkEvent createOrUpdateLink(ProviderId providerId,
148 + LinkDescription linkDescription) {
149 + LinkKey key = new LinkKey(linkDescription.src(), linkDescription.dst());
150 + Optional<DefaultLink> link = links.getUnchecked(key);
151 + if (!link.isPresent()) {
152 + return createLink(providerId, key, linkDescription);
153 + }
154 + return updateLink(providerId, link.get(), key, linkDescription);
155 + }
156 +
157 + // Creates and stores the link and returns the appropriate event.
158 + private LinkEvent createLink(ProviderId providerId, LinkKey key,
159 + LinkDescription linkDescription) {
160 + DefaultLink link = new DefaultLink(providerId, key.src(), key.dst(),
161 + linkDescription.type());
162 + synchronized (this) {
163 + final byte[] keyBytes = serialize(key);
164 + rawLinks.put(keyBytes, serialize(link));
165 + links.asMap().putIfAbsent(key, Optional.of(link));
166 +
167 + addNewLink(link);
168 + }
169 + return new LinkEvent(LINK_ADDED, link);
170 + }
171 +
172 + // update Egress and ingress link sets
173 + private void addNewLink(DefaultLink link) {
174 + synchronized (this) {
175 + srcLinks.put(link.src().deviceId(), link);
176 + dstLinks.put(link.dst().deviceId(), link);
177 + }
178 + }
179 +
180 + // Updates, if necessary the specified link and returns the appropriate event.
181 + private LinkEvent updateLink(ProviderId providerId, DefaultLink link,
182 + LinkKey key, LinkDescription linkDescription) {
183 + // FIXME confirm Link update condition is OK
184 + if (link.type() == INDIRECT && linkDescription.type() == DIRECT) {
185 + synchronized (this) {
186 +
187 + DefaultLink updated =
188 + new DefaultLink(providerId, link.src(), link.dst(),
189 + linkDescription.type());
190 + final byte[] keyBytes = serialize(key);
191 + rawLinks.put(keyBytes, serialize(updated));
192 + links.asMap().replace(key, Optional.of(link), Optional.of(updated));
193 +
194 + replaceLink(link, updated);
195 + return new LinkEvent(LINK_UPDATED, updated);
196 + }
197 + }
198 + return null;
199 + }
200 +
201 + // update Egress and ingress link sets
202 + private void replaceLink(DefaultLink link, DefaultLink updated) {
203 + synchronized (this) {
204 + srcLinks.remove(link.src().deviceId(), link);
205 + dstLinks.remove(link.dst().deviceId(), link);
206 +
207 + srcLinks.put(link.src().deviceId(), updated);
208 + dstLinks.put(link.dst().deviceId(), updated);
209 + }
210 + }
211 +
212 + @Override
213 + public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
214 + synchronized (this) {
215 + LinkKey key = new LinkKey(src, dst);
216 + byte[] keyBytes = serialize(key);
217 + Link link = deserialize(rawLinks.remove(keyBytes));
218 + links.invalidate(key);
219 + if (link != null) {
220 + removeLink(link);
221 + return new LinkEvent(LINK_REMOVED, link);
222 + }
223 + return null;
224 + }
225 + }
226 +
227 + // update Egress and ingress link sets
228 + private void removeLink(Link link) {
229 + synchronized (this) {
230 + srcLinks.remove(link.src().deviceId(), link);
231 + dstLinks.remove(link.dst().deviceId(), link);
232 + }
233 + }
234 +
235 + private class RemoteLinkEventHandler extends RemoteEventHandler<LinkKey, DefaultLink> {
236 + public RemoteLinkEventHandler(LoadingCache<LinkKey, Optional<DefaultLink>> cache) {
237 + super(cache);
238 + }
239 +
240 + @Override
241 + protected void onAdd(LinkKey key, DefaultLink newVal) {
242 + addNewLink(newVal);
243 + notifyDelegate(new LinkEvent(LINK_ADDED, newVal));
244 + }
245 +
246 + @Override
247 + protected void onUpdate(LinkKey key, DefaultLink oldVal, DefaultLink newVal) {
248 + replaceLink(oldVal, newVal);
249 + notifyDelegate(new LinkEvent(LINK_UPDATED, newVal));
250 + }
251 +
252 + @Override
253 + protected void onRemove(LinkKey key, DefaultLink val) {
254 + removeLink(val);
255 + notifyDelegate(new LinkEvent(LINK_REMOVED, val));
256 + }
257 + }
258 +}
1 +/**
2 + * Implementation of link store using Hazelcast distributed structures.
3 + */
4 +package org.onlab.onos.store.link.impl;
1 +package org.onlab.onos.store.serializers;
2 +
3 +import org.onlab.onos.net.ConnectPoint;
4 +import org.onlab.onos.net.ElementId;
5 +import org.onlab.onos.net.PortNumber;
6 +
7 +import com.esotericsoftware.kryo.Kryo;
8 +import com.esotericsoftware.kryo.Serializer;
9 +import com.esotericsoftware.kryo.io.Input;
10 +import com.esotericsoftware.kryo.io.Output;
11 +
12 +/**
13 + * Kryo Serializer for {@link ConnectPointSerializer}.
14 + */
15 +public class ConnectPointSerializer extends Serializer<ConnectPoint> {
16 +
17 + /**
18 + * Default constructor.
19 + */
20 + public ConnectPointSerializer() {
21 + // non-null, immutable
22 + super(false, true);
23 + }
24 +
25 + @Override
26 + public void write(Kryo kryo, Output output, ConnectPoint object) {
27 + kryo.writeClassAndObject(output, object.elementId());
28 + kryo.writeClassAndObject(output, object.port());
29 + }
30 +
31 + @Override
32 + public ConnectPoint read(Kryo kryo, Input input, Class<ConnectPoint> type) {
33 + ElementId elementId = (ElementId) kryo.readClassAndObject(input);
34 + PortNumber portNumber = (PortNumber) kryo.readClassAndObject(input);
35 + return new ConnectPoint(elementId, portNumber);
36 + }
37 +}
1 +package org.onlab.onos.store.serializers;
2 +
3 +import org.onlab.onos.net.ConnectPoint;
4 +import org.onlab.onos.net.DefaultLink;
5 +import org.onlab.onos.net.Link.Type;
6 +import org.onlab.onos.net.provider.ProviderId;
7 +
8 +import com.esotericsoftware.kryo.Kryo;
9 +import com.esotericsoftware.kryo.Serializer;
10 +import com.esotericsoftware.kryo.io.Input;
11 +import com.esotericsoftware.kryo.io.Output;
12 +
13 +/**
14 + * Kryo Serializer for {@link DefaultLink}.
15 + */
16 +public class DefaultLinkSerializer extends Serializer<DefaultLink> {
17 +
18 + /**
19 + * Default constructor.
20 + */
21 + public DefaultLinkSerializer() {
22 + // non-null, immutable
23 + super(false, true);
24 + }
25 +
26 + @Override
27 + public void write(Kryo kryo, Output output, DefaultLink object) {
28 + kryo.writeClassAndObject(output, object.providerId());
29 + kryo.writeClassAndObject(output, object.src());
30 + kryo.writeClassAndObject(output, object.dst());
31 + kryo.writeClassAndObject(output, object.type());
32 + }
33 +
34 + @Override
35 + public DefaultLink read(Kryo kryo, Input input, Class<DefaultLink> type) {
36 + ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
37 + ConnectPoint src = (ConnectPoint) kryo.readClassAndObject(input);
38 + ConnectPoint dst = (ConnectPoint) kryo.readClassAndObject(input);
39 + Type linkType = (Type) kryo.readClassAndObject(input);
40 + return new DefaultLink(providerId, src, dst, linkType);
41 + }
42 +}
1 +package org.onlab.onos.store.serializers;
2 +
3 +import org.onlab.onos.net.ConnectPoint;
4 +import org.onlab.onos.net.LinkKey;
5 +import com.esotericsoftware.kryo.Kryo;
6 +import com.esotericsoftware.kryo.Serializer;
7 +import com.esotericsoftware.kryo.io.Input;
8 +import com.esotericsoftware.kryo.io.Output;
9 +
10 +/**
11 + * Kryo Serializer for {@link LinkKey}.
12 + */
13 +public class LinkKeySerializer extends Serializer<LinkKey> {
14 +
15 + /**
16 + * Default constructor.
17 + */
18 + public LinkKeySerializer() {
19 + // non-null, immutable
20 + super(false, true);
21 + }
22 +
23 + @Override
24 + public void write(Kryo kryo, Output output, LinkKey object) {
25 + kryo.writeClassAndObject(output, object.src());
26 + kryo.writeClassAndObject(output, object.dst());
27 + }
28 +
29 + @Override
30 + public LinkKey read(Kryo kryo, Input input, Class<LinkKey> type) {
31 + ConnectPoint src = (ConnectPoint) kryo.readClassAndObject(input);
32 + ConnectPoint dst = (ConnectPoint) kryo.readClassAndObject(input);
33 + return new LinkKey(src, dst);
34 + }
35 +}
1 +package org.onlab.onos.store.link.impl;
2 +
3 +import static org.junit.Assert.*;
4 +import static org.onlab.onos.net.DeviceId.deviceId;
5 +import static org.onlab.onos.net.Link.Type.*;
6 +import static org.onlab.onos.net.link.LinkEvent.Type.*;
7 +
8 +import java.util.HashMap;
9 +import java.util.Map;
10 +import java.util.Set;
11 +import java.util.concurrent.CountDownLatch;
12 +import java.util.concurrent.TimeUnit;
13 +
14 +import org.junit.After;
15 +import org.junit.AfterClass;
16 +import org.junit.Before;
17 +import org.junit.BeforeClass;
18 +import org.junit.Test;
19 +import org.onlab.onos.net.ConnectPoint;
20 +import org.onlab.onos.net.DeviceId;
21 +import org.onlab.onos.net.Link;
22 +import org.onlab.onos.net.LinkKey;
23 +import org.onlab.onos.net.PortNumber;
24 +import org.onlab.onos.net.Link.Type;
25 +import org.onlab.onos.net.link.DefaultLinkDescription;
26 +import org.onlab.onos.net.link.LinkEvent;
27 +import org.onlab.onos.net.link.LinkStoreDelegate;
28 +import org.onlab.onos.net.provider.ProviderId;
29 +import org.onlab.onos.store.common.StoreService;
30 +import org.onlab.onos.store.impl.StoreManager;
31 +import org.onlab.onos.store.impl.TestStoreManager;
32 +
33 +import com.google.common.collect.Iterables;
34 +import com.hazelcast.config.Config;
35 +import com.hazelcast.core.Hazelcast;
36 +
37 +public class DistributedLinkStoreTest {
38 +
39 + private static final ProviderId PID = new ProviderId("of", "foo");
40 + private static final DeviceId DID1 = deviceId("of:foo");
41 + private static final DeviceId DID2 = deviceId("of:bar");
42 +// private static final String MFR = "whitebox";
43 +// private static final String HW = "1.1.x";
44 +// private static final String SW1 = "3.8.1";
45 +// private static final String SW2 = "3.9.5";
46 +// private static final String SN = "43311-12345";
47 +
48 + private static final PortNumber P1 = PortNumber.portNumber(1);
49 + private static final PortNumber P2 = PortNumber.portNumber(2);
50 + private static final PortNumber P3 = PortNumber.portNumber(3);
51 +
52 + private StoreManager storeManager;
53 +
54 + private DistributedLinkStore linkStore;
55 +
56 + @BeforeClass
57 + public static void setUpBeforeClass() throws Exception {
58 + }
59 +
60 + @AfterClass
61 + public static void tearDownAfterClass() throws Exception {
62 + }
63 +
64 + @Before
65 + public void setUp() throws Exception {
66 + // TODO should find a way to clean Hazelcast instance without shutdown.
67 + Config config = TestStoreManager.getTestConfig();
68 +
69 + storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
70 + storeManager.activate();
71 +
72 + linkStore = new TestDistributedLinkStore(storeManager);
73 + linkStore.activate();
74 + }
75 +
76 + @After
77 + public void tearDown() throws Exception {
78 + linkStore.deactivate();
79 + storeManager.deactivate();
80 + }
81 +
82 + private void putLink(DeviceId srcId, PortNumber srcNum,
83 + DeviceId dstId, PortNumber dstNum, Type type) {
84 + ConnectPoint src = new ConnectPoint(srcId, srcNum);
85 + ConnectPoint dst = new ConnectPoint(dstId, dstNum);
86 + linkStore.createOrUpdateLink(PID, new DefaultLinkDescription(src, dst, type));
87 + }
88 +
89 + private void putLink(LinkKey key, Type type) {
90 + putLink(key.src().deviceId(), key.src().port(),
91 + key.dst().deviceId(), key.dst().port(),
92 + type);
93 + }
94 +
95 + private static void assertLink(DeviceId srcId, PortNumber srcNum,
96 + DeviceId dstId, PortNumber dstNum, Type type,
97 + Link link) {
98 + assertEquals(srcId, link.src().deviceId());
99 + assertEquals(srcNum, link.src().port());
100 + assertEquals(dstId, link.dst().deviceId());
101 + assertEquals(dstNum, link.dst().port());
102 + assertEquals(type, link.type());
103 + }
104 +
105 + private static void assertLink(LinkKey key, Type type, Link link) {
106 + assertLink(key.src().deviceId(), key.src().port(),
107 + key.dst().deviceId(), key.dst().port(),
108 + type, link);
109 + }
110 +
111 + @Test
112 + public final void testGetLinkCount() {
113 + assertEquals("initialy empty", 0, linkStore.getLinkCount());
114 +
115 + putLink(DID1, P1, DID2, P2, DIRECT);
116 + putLink(DID2, P2, DID1, P1, DIRECT);
117 + putLink(DID1, P1, DID2, P2, DIRECT);
118 +
119 + assertEquals("expecting 2 unique link", 2, linkStore.getLinkCount());
120 + }
121 +
122 + @Test
123 + public final void testGetLinks() {
124 + assertEquals("initialy empty", 0,
125 + Iterables.size(linkStore.getLinks()));
126 +
127 + LinkKey linkId1 = new LinkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
128 + LinkKey linkId2 = new LinkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
129 +
130 + putLink(linkId1, DIRECT);
131 + putLink(linkId2, DIRECT);
132 + putLink(linkId1, DIRECT);
133 +
134 + assertEquals("expecting 2 unique link", 2,
135 + Iterables.size(linkStore.getLinks()));
136 +
137 + Map<LinkKey, Link> links = new HashMap<>();
138 + for (Link link : linkStore.getLinks()) {
139 + links.put(new LinkKey(link.src(), link.dst()), link);
140 + }
141 +
142 + assertLink(linkId1, DIRECT, links.get(linkId1));
143 + assertLink(linkId2, DIRECT, links.get(linkId2));
144 + }
145 +
146 + @Test
147 + public final void testGetDeviceEgressLinks() {
148 + LinkKey linkId1 = new LinkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
149 + LinkKey linkId2 = new LinkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
150 + LinkKey linkId3 = new LinkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
151 +
152 + putLink(linkId1, DIRECT);
153 + putLink(linkId2, DIRECT);
154 + putLink(linkId3, DIRECT);
155 +
156 + // DID1,P1 => DID2,P2
157 + // DID2,P2 => DID1,P1
158 + // DID1,P2 => DID2,P3
159 +
160 + Set<Link> links1 = linkStore.getDeviceEgressLinks(DID1);
161 + assertEquals(2, links1.size());
162 + // check
163 +
164 + Set<Link> links2 = linkStore.getDeviceEgressLinks(DID2);
165 + assertEquals(1, links2.size());
166 + assertLink(linkId2, DIRECT, links2.iterator().next());
167 + }
168 +
169 + @Test
170 + public final void testGetDeviceIngressLinks() {
171 + LinkKey linkId1 = new LinkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2));
172 + LinkKey linkId2 = new LinkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1));
173 + LinkKey linkId3 = new LinkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
174 +
175 + putLink(linkId1, DIRECT);
176 + putLink(linkId2, DIRECT);
177 + putLink(linkId3, DIRECT);
178 +
179 + // DID1,P1 => DID2,P2
180 + // DID2,P2 => DID1,P1
181 + // DID1,P2 => DID2,P3
182 +
183 + Set<Link> links1 = linkStore.getDeviceIngressLinks(DID2);
184 + assertEquals(2, links1.size());
185 + // check
186 +
187 + Set<Link> links2 = linkStore.getDeviceIngressLinks(DID1);
188 + assertEquals(1, links2.size());
189 + assertLink(linkId2, DIRECT, links2.iterator().next());
190 + }
191 +
192 + @Test
193 + public final void testGetLink() {
194 + ConnectPoint src = new ConnectPoint(DID1, P1);
195 + ConnectPoint dst = new ConnectPoint(DID2, P2);
196 + LinkKey linkId1 = new LinkKey(src, dst);
197 +
198 + putLink(linkId1, DIRECT);
199 +
200 + Link link = linkStore.getLink(src, dst);
201 + assertLink(linkId1, DIRECT, link);
202 +
203 + assertNull("There shouldn't be reverese link",
204 + linkStore.getLink(dst, src));
205 + }
206 +
207 + @Test
208 + public final void testGetEgressLinks() {
209 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
210 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
211 + LinkKey linkId1 = new LinkKey(d1P1, d2P2);
212 + LinkKey linkId2 = new LinkKey(d2P2, d1P1);
213 + LinkKey linkId3 = new LinkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
214 +
215 + putLink(linkId1, DIRECT);
216 + putLink(linkId2, DIRECT);
217 + putLink(linkId3, DIRECT);
218 +
219 + // DID1,P1 => DID2,P2
220 + // DID2,P2 => DID1,P1
221 + // DID1,P2 => DID2,P3
222 +
223 + Set<Link> links1 = linkStore.getEgressLinks(d1P1);
224 + assertEquals(1, links1.size());
225 + assertLink(linkId1, DIRECT, links1.iterator().next());
226 +
227 + Set<Link> links2 = linkStore.getEgressLinks(d2P2);
228 + assertEquals(1, links2.size());
229 + assertLink(linkId2, DIRECT, links2.iterator().next());
230 + }
231 +
232 + @Test
233 + public final void testGetIngressLinks() {
234 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
235 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
236 + LinkKey linkId1 = new LinkKey(d1P1, d2P2);
237 + LinkKey linkId2 = new LinkKey(d2P2, d1P1);
238 + LinkKey linkId3 = new LinkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3));
239 +
240 + putLink(linkId1, DIRECT);
241 + putLink(linkId2, DIRECT);
242 + putLink(linkId3, DIRECT);
243 +
244 + // DID1,P1 => DID2,P2
245 + // DID2,P2 => DID1,P1
246 + // DID1,P2 => DID2,P3
247 +
248 + Set<Link> links1 = linkStore.getIngressLinks(d2P2);
249 + assertEquals(1, links1.size());
250 + assertLink(linkId1, DIRECT, links1.iterator().next());
251 +
252 + Set<Link> links2 = linkStore.getIngressLinks(d1P1);
253 + assertEquals(1, links2.size());
254 + assertLink(linkId2, DIRECT, links2.iterator().next());
255 + }
256 +
257 + @Test
258 + public final void testCreateOrUpdateLink() {
259 + ConnectPoint src = new ConnectPoint(DID1, P1);
260 + ConnectPoint dst = new ConnectPoint(DID2, P2);
261 +
262 + // add link
263 + LinkEvent event = linkStore.createOrUpdateLink(PID,
264 + new DefaultLinkDescription(src, dst, INDIRECT));
265 +
266 + assertLink(DID1, P1, DID2, P2, INDIRECT, event.subject());
267 + assertEquals(LINK_ADDED, event.type());
268 +
269 + // update link type
270 + LinkEvent event2 = linkStore.createOrUpdateLink(PID,
271 + new DefaultLinkDescription(src, dst, DIRECT));
272 +
273 + assertLink(DID1, P1, DID2, P2, DIRECT, event2.subject());
274 + assertEquals(LINK_UPDATED, event2.type());
275 +
276 + // no change
277 + LinkEvent event3 = linkStore.createOrUpdateLink(PID,
278 + new DefaultLinkDescription(src, dst, DIRECT));
279 +
280 + assertNull("No change event expected", event3);
281 + }
282 +
283 + @Test
284 + public final void testRemoveLink() {
285 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
286 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
287 + LinkKey linkId1 = new LinkKey(d1P1, d2P2);
288 + LinkKey linkId2 = new LinkKey(d2P2, d1P1);
289 +
290 + putLink(linkId1, DIRECT);
291 + putLink(linkId2, DIRECT);
292 +
293 + // DID1,P1 => DID2,P2
294 + // DID2,P2 => DID1,P1
295 + // DID1,P2 => DID2,P3
296 +
297 + LinkEvent event = linkStore.removeLink(d1P1, d2P2);
298 + assertEquals(LINK_REMOVED, event.type());
299 + LinkEvent event2 = linkStore.removeLink(d1P1, d2P2);
300 + assertNull(event2);
301 +
302 + assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1));
303 + }
304 +
305 + @Test
306 + public final void testEvents() throws InterruptedException {
307 +
308 + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1);
309 + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2);
310 + final LinkKey linkId1 = new LinkKey(d1P1, d2P2);
311 +
312 + final CountDownLatch addLatch = new CountDownLatch(1);
313 + LinkStoreDelegate checkAdd = new LinkStoreDelegate() {
314 + @Override
315 + public void notify(LinkEvent event) {
316 + assertEquals(LINK_ADDED, event.type());
317 + assertLink(linkId1, INDIRECT, event.subject());
318 + addLatch.countDown();
319 + }
320 + };
321 + final CountDownLatch updateLatch = new CountDownLatch(1);
322 + LinkStoreDelegate checkUpdate = new LinkStoreDelegate() {
323 + @Override
324 + public void notify(LinkEvent event) {
325 + assertEquals(LINK_UPDATED, event.type());
326 + assertLink(linkId1, DIRECT, event.subject());
327 + updateLatch.countDown();
328 + }
329 + };
330 + final CountDownLatch removeLatch = new CountDownLatch(1);
331 + LinkStoreDelegate checkRemove = new LinkStoreDelegate() {
332 + @Override
333 + public void notify(LinkEvent event) {
334 + assertEquals(LINK_REMOVED, event.type());
335 + assertLink(linkId1, DIRECT, event.subject());
336 + removeLatch.countDown();
337 + }
338 + };
339 +
340 + linkStore.setDelegate(checkAdd);
341 + putLink(linkId1, INDIRECT);
342 + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
343 +
344 + linkStore.unsetDelegate(checkAdd);
345 + linkStore.setDelegate(checkUpdate);
346 + putLink(linkId1, DIRECT);
347 + assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
348 +
349 + linkStore.unsetDelegate(checkUpdate);
350 + linkStore.setDelegate(checkRemove);
351 + linkStore.removeLink(d1P1, d2P2);
352 + assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
353 + }
354 +
355 +
356 + class TestDistributedLinkStore extends DistributedLinkStore {
357 + TestDistributedLinkStore(StoreService storeService) {
358 + this.storeService = storeService;
359 + }
360 + }
361 +}
...@@ -3,6 +3,7 @@ package org.onlab.onos.net.trivial.impl; ...@@ -3,6 +3,7 @@ package org.onlab.onos.net.trivial.impl;
3 import com.google.common.collect.HashMultimap; 3 import com.google.common.collect.HashMultimap;
4 import com.google.common.collect.ImmutableSet; 4 import com.google.common.collect.ImmutableSet;
5 import com.google.common.collect.Multimap; 5 import com.google.common.collect.Multimap;
6 +
6 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
7 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
8 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
...@@ -11,6 +12,7 @@ import org.onlab.onos.net.ConnectPoint; ...@@ -11,6 +12,7 @@ import org.onlab.onos.net.ConnectPoint;
11 import org.onlab.onos.net.DefaultLink; 12 import org.onlab.onos.net.DefaultLink;
12 import org.onlab.onos.net.DeviceId; 13 import org.onlab.onos.net.DeviceId;
13 import org.onlab.onos.net.Link; 14 import org.onlab.onos.net.Link;
15 +import org.onlab.onos.net.LinkKey;
14 import org.onlab.onos.net.link.LinkDescription; 16 import org.onlab.onos.net.link.LinkDescription;
15 import org.onlab.onos.net.link.LinkEvent; 17 import org.onlab.onos.net.link.LinkEvent;
16 import org.onlab.onos.net.link.LinkStore; 18 import org.onlab.onos.net.link.LinkStore;
...@@ -22,7 +24,6 @@ import org.slf4j.Logger; ...@@ -22,7 +24,6 @@ import org.slf4j.Logger;
22 import java.util.Collections; 24 import java.util.Collections;
23 import java.util.HashSet; 25 import java.util.HashSet;
24 import java.util.Map; 26 import java.util.Map;
25 -import java.util.Objects;
26 import java.util.Set; 27 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap; 28 import java.util.concurrent.ConcurrentHashMap;
28 29
...@@ -123,7 +124,7 @@ public class SimpleLinkStore ...@@ -123,7 +124,7 @@ public class SimpleLinkStore
123 // Creates and stores the link and returns the appropriate event. 124 // Creates and stores the link and returns the appropriate event.
124 private LinkEvent createLink(ProviderId providerId, LinkKey key, 125 private LinkEvent createLink(ProviderId providerId, LinkKey key,
125 LinkDescription linkDescription) { 126 LinkDescription linkDescription) {
126 - DefaultLink link = new DefaultLink(providerId, key.src, key.dst, 127 + DefaultLink link = new DefaultLink(providerId, key.src(), key.dst(),
127 linkDescription.type()); 128 linkDescription.type());
128 synchronized (this) { 129 synchronized (this) {
129 links.put(key, link); 130 links.put(key, link);
...@@ -165,33 +166,4 @@ public class SimpleLinkStore ...@@ -165,33 +166,4 @@ public class SimpleLinkStore
165 return null; 166 return null;
166 } 167 }
167 } 168 }
168 -
169 - // Auxiliary key to track links.
170 - private class LinkKey {
171 - final ConnectPoint src;
172 - final ConnectPoint dst;
173 -
174 - LinkKey(ConnectPoint src, ConnectPoint dst) {
175 - this.src = src;
176 - this.dst = dst;
177 - }
178 -
179 - @Override
180 - public int hashCode() {
181 - return Objects.hash(src, dst);
182 - }
183 -
184 - @Override
185 - public boolean equals(Object obj) {
186 - if (this == obj) {
187 - return true;
188 - }
189 - if (obj instanceof LinkKey) {
190 - final LinkKey other = (LinkKey) obj;
191 - return Objects.equals(this.src, other.src) &&
192 - Objects.equals(this.dst, other.dst);
193 - }
194 - return false;
195 - }
196 - }
197 } 169 }
......
...@@ -3,11 +3,13 @@ package org.onlab.onos.net.trivial.impl; ...@@ -3,11 +3,13 @@ package org.onlab.onos.net.trivial.impl;
3 import static org.slf4j.LoggerFactory.getLogger; 3 import static org.slf4j.LoggerFactory.getLogger;
4 4
5 import java.util.Collections; 5 import java.util.Collections;
6 +import java.util.HashMap;
6 import java.util.HashSet; 7 import java.util.HashSet;
7 import java.util.Map; 8 import java.util.Map;
8 import java.util.Set; 9 import java.util.Set;
9 import java.util.concurrent.ConcurrentHashMap; 10 import java.util.concurrent.ConcurrentHashMap;
10 import java.util.concurrent.ConcurrentMap; 11 import java.util.concurrent.ConcurrentMap;
12 +import java.util.concurrent.atomic.AtomicInteger;
11 13
12 import org.apache.felix.scr.annotations.Activate; 14 import org.apache.felix.scr.annotations.Activate;
13 import org.apache.felix.scr.annotations.Component; 15 import org.apache.felix.scr.annotations.Component;
...@@ -18,6 +20,7 @@ import org.onlab.onos.cluster.DefaultControllerNode; ...@@ -18,6 +20,7 @@ import org.onlab.onos.cluster.DefaultControllerNode;
18 import org.onlab.onos.cluster.MastershipEvent; 20 import org.onlab.onos.cluster.MastershipEvent;
19 import org.onlab.onos.cluster.MastershipStore; 21 import org.onlab.onos.cluster.MastershipStore;
20 import org.onlab.onos.cluster.MastershipStoreDelegate; 22 import org.onlab.onos.cluster.MastershipStoreDelegate;
23 +import org.onlab.onos.cluster.MastershipTerm;
21 import org.onlab.onos.cluster.NodeId; 24 import org.onlab.onos.cluster.NodeId;
22 import org.onlab.onos.net.DeviceId; 25 import org.onlab.onos.net.DeviceId;
23 import org.onlab.onos.net.MastershipRole; 26 import org.onlab.onos.net.MastershipRole;
...@@ -47,6 +50,7 @@ public class SimpleMastershipStore ...@@ -47,6 +50,7 @@ public class SimpleMastershipStore
47 //devices mapped to their masters, to emulate multiple nodes 50 //devices mapped to their masters, to emulate multiple nodes
48 protected final ConcurrentMap<DeviceId, NodeId> masterMap = 51 protected final ConcurrentMap<DeviceId, NodeId> masterMap =
49 new ConcurrentHashMap<>(); 52 new ConcurrentHashMap<>();
53 + protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>();
50 54
51 @Activate 55 @Activate
52 public void activate() { 56 public void activate() {
...@@ -63,15 +67,21 @@ public class SimpleMastershipStore ...@@ -63,15 +67,21 @@ public class SimpleMastershipStore
63 67
64 NodeId node = masterMap.get(deviceId); 68 NodeId node = masterMap.get(deviceId);
65 if (node == null) { 69 if (node == null) {
66 - masterMap.put(deviceId, nodeId); 70 + synchronized (this) {
71 + masterMap.put(deviceId, nodeId);
72 + termMap.put(deviceId, new AtomicInteger());
73 + }
67 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); 74 return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
68 } 75 }
69 76
70 if (node.equals(nodeId)) { 77 if (node.equals(nodeId)) {
71 return null; 78 return null;
72 } else { 79 } else {
73 - masterMap.put(deviceId, nodeId); 80 + synchronized (this) {
74 - return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); 81 + masterMap.put(deviceId, nodeId);
82 + termMap.get(deviceId).incrementAndGet();
83 + return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
84 + }
75 } 85 }
76 } 86 }
77 87
...@@ -114,4 +124,13 @@ public class SimpleMastershipStore ...@@ -114,4 +124,13 @@ public class SimpleMastershipStore
114 return role; 124 return role;
115 } 125 }
116 126
127 + @Override
128 + public MastershipTerm getTermFor(DeviceId deviceId) {
129 + if (masterMap.get(deviceId) == null) {
130 + return null;
131 + }
132 + return MastershipTerm.of(
133 + masterMap.get(deviceId), termMap.get(deviceId).get());
134 + }
135 +
117 } 136 }
......