Marc De Leenheer
Committed by Gerrit Code Review

Injecting topology through JSON ConfigProvider works for multi-instance (ONOS-490).

Change-Id: Ib977f4cf9a59ddec360072891fd803c6f9ee84f1

Injecting optical device annotations and ports works for multi-instance (ONOS-870).

Change-Id: Icdde16ef72fc4e47eec7213250b04902083f0537
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
15 */ 15 */
16 package org.onosproject.event; 16 package org.onosproject.event;
17 17
18 -import static com.google.common.base.MoreObjects.toStringHelper;
19 -
20 import org.joda.time.LocalDateTime; 18 import org.joda.time.LocalDateTime;
21 19
20 +import static com.google.common.base.MoreObjects.toStringHelper;
21 +
22 /** 22 /**
23 * Base event implementation. 23 * Base event implementation.
24 */ 24 */
...@@ -75,5 +75,4 @@ public class AbstractEvent<T extends Enum, S> implements Event<T, S> { ...@@ -75,5 +75,4 @@ public class AbstractEvent<T extends Enum, S> implements Event<T, S> {
75 .add("subject", subject()) 75 .add("subject", subject())
76 .toString(); 76 .toString();
77 } 77 }
78 -
79 } 78 }
......
...@@ -47,7 +47,7 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -47,7 +47,7 @@ public class DefaultDeviceDescription extends AbstractDescription
47 * @param hwVersion device HW version 47 * @param hwVersion device HW version
48 * @param swVersion device SW version 48 * @param swVersion device SW version
49 * @param serialNumber device serial number 49 * @param serialNumber device serial number
50 - * @param chassis chasis id 50 + * @param chassis chassis id
51 * @param annotations optional key/value annotations map 51 * @param annotations optional key/value annotations map
52 */ 52 */
53 public DefaultDeviceDescription(URI uri, Type type, String manufacturer, 53 public DefaultDeviceDescription(URI uri, Type type, String manufacturer,
......
...@@ -306,18 +306,16 @@ public class DeviceManager ...@@ -306,18 +306,16 @@ public class DeviceManager
306 // TODO: Do we need to explicitly tell the Provider that 306 // TODO: Do we need to explicitly tell the Provider that
307 // this instance is not the MASTER 307 // this instance is not the MASTER
308 applyRole(deviceId, MastershipRole.STANDBY); 308 applyRole(deviceId, MastershipRole.STANDBY);
309 - return; 309 + } else {
310 - }
311 log.info("Role of this node is MASTER for {}", deviceId); 310 log.info("Role of this node is MASTER for {}", deviceId);
312 -
313 // tell clock provider if this instance is the master 311 // tell clock provider if this instance is the master
314 deviceClockProviderService.setMastershipTerm(deviceId, term); 312 deviceClockProviderService.setMastershipTerm(deviceId, term);
313 + applyRole(deviceId, MastershipRole.MASTER);
314 + }
315 315
316 DeviceEvent event = store.createOrUpdateDevice(provider().id(), 316 DeviceEvent event = store.createOrUpdateDevice(provider().id(),
317 deviceId, deviceDescription); 317 deviceId, deviceDescription);
318 318
319 - applyRole(deviceId, MastershipRole.MASTER);
320 -
321 // If there was a change of any kind, tell the provider 319 // If there was a change of any kind, tell the provider
322 // that this instance is the master. 320 // that this instance is the master.
323 if (event != null) { 321 if (event != null) {
......
1 +package org.onosproject.store.device.impl;
2 +
3 +import com.google.common.base.MoreObjects;
4 +import org.onosproject.net.DeviceId;
5 +import org.onosproject.net.device.DeviceDescription;
6 +import org.onosproject.net.provider.ProviderId;
7 +
8 +public class DeviceInjectedEvent {
9 + private final ProviderId providerId;
10 + private final DeviceId deviceId;
11 + private final DeviceDescription deviceDescription;
12 +
13 + protected DeviceInjectedEvent(
14 + ProviderId providerId,
15 + DeviceId deviceId,
16 + DeviceDescription deviceDescription) {
17 + this.providerId = providerId;
18 + this.deviceId = deviceId;
19 + this.deviceDescription = deviceDescription;
20 + }
21 +
22 + public DeviceId deviceId() {
23 + return deviceId;
24 + }
25 +
26 + public ProviderId providerId() {
27 + return providerId;
28 + }
29 +
30 + public DeviceDescription deviceDescription() {
31 + return deviceDescription;
32 + }
33 +
34 + @Override
35 + public String toString() {
36 + return MoreObjects.toStringHelper(getClass())
37 + .add("providerId", providerId)
38 + .add("deviceId", deviceId)
39 + .add("deviceDescription", deviceDescription)
40 + .toString();
41 + }
42 +
43 + // for serializer
44 + protected DeviceInjectedEvent() {
45 + this.providerId = null;
46 + this.deviceId = null;
47 + this.deviceDescription = null;
48 + }
49 +}
...@@ -34,4 +34,8 @@ public final class GossipDeviceStoreMessageSubjects { ...@@ -34,4 +34,8 @@ public final class GossipDeviceStoreMessageSubjects {
34 public static final MessageSubject DEVICE_ADVERTISE = new MessageSubject("peer-device-advertisements"); 34 public static final MessageSubject DEVICE_ADVERTISE = new MessageSubject("peer-device-advertisements");
35 // to be used with 3-way anti-entropy process 35 // to be used with 3-way anti-entropy process
36 public static final MessageSubject DEVICE_REQUEST = new MessageSubject("peer-device-request"); 36 public static final MessageSubject DEVICE_REQUEST = new MessageSubject("peer-device-request");
37 +
38 + // Network elements injected (not discovered) by ConfigProvider
39 + public static final MessageSubject DEVICE_INJECTED = new MessageSubject("peer-device-injected");
40 + public static final MessageSubject PORT_INJECTED = new MessageSubject("peer-port-injected");
37 } 41 }
......
1 +package org.onosproject.store.device.impl;
2 +
3 +import com.google.common.base.MoreObjects;
4 +import org.onosproject.net.DeviceId;
5 +import org.onosproject.net.device.PortDescription;
6 +import org.onosproject.net.provider.ProviderId;
7 +
8 +import java.util.List;
9 +
10 +public class PortInjectedEvent {
11 +
12 + private ProviderId providerId;
13 + private DeviceId deviceId;
14 + private List<PortDescription> portDescriptions;
15 +
16 + protected PortInjectedEvent(ProviderId providerId, DeviceId deviceId, List<PortDescription> portDescriptions) {
17 + this.providerId = providerId;
18 + this.deviceId = deviceId;
19 + this.portDescriptions = portDescriptions;
20 + }
21 +
22 + public DeviceId deviceId() {
23 + return deviceId;
24 + }
25 +
26 + public ProviderId providerId() {
27 + return providerId;
28 + }
29 +
30 + public List<PortDescription> portDescriptions() {
31 + return portDescriptions;
32 + }
33 +
34 + @Override
35 + public String toString() {
36 + return MoreObjects.toStringHelper(getClass())
37 + .add("providerId", providerId)
38 + .add("deviceId", deviceId)
39 + .add("portDescriptions", portDescriptions)
40 + .toString();
41 + }
42 +
43 + // for serializer
44 + protected PortInjectedEvent() {
45 + this.providerId = null;
46 + this.deviceId = null;
47 + this.portDescriptions = null;
48 + }
49 +
50 +}
...@@ -32,6 +32,7 @@ import org.onlab.util.KryoNamespace; ...@@ -32,6 +32,7 @@ import org.onlab.util.KryoNamespace;
32 import org.onosproject.cluster.ClusterService; 32 import org.onosproject.cluster.ClusterService;
33 import org.onosproject.cluster.ControllerNode; 33 import org.onosproject.cluster.ControllerNode;
34 import org.onosproject.cluster.NodeId; 34 import org.onosproject.cluster.NodeId;
35 +import org.onosproject.mastership.MastershipService;
35 import org.onosproject.net.AnnotationKeys; 36 import org.onosproject.net.AnnotationKeys;
36 import org.onosproject.net.AnnotationsUtil; 37 import org.onosproject.net.AnnotationsUtil;
37 import org.onosproject.net.ConnectPoint; 38 import org.onosproject.net.ConnectPoint;
...@@ -90,9 +91,7 @@ import static org.onosproject.net.Link.State.INACTIVE; ...@@ -90,9 +91,7 @@ import static org.onosproject.net.Link.State.INACTIVE;
90 import static org.onosproject.net.Link.Type.DIRECT; 91 import static org.onosproject.net.Link.Type.DIRECT;
91 import static org.onosproject.net.Link.Type.INDIRECT; 92 import static org.onosproject.net.Link.Type.INDIRECT;
92 import static org.onosproject.net.LinkKey.linkKey; 93 import static org.onosproject.net.LinkKey.linkKey;
93 -import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; 94 +import static org.onosproject.net.link.LinkEvent.Type.*;
94 -import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
95 -import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED;
96 import static org.onosproject.store.link.impl.GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT; 95 import static org.onosproject.store.link.impl.GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT;
97 import static org.slf4j.LoggerFactory.getLogger; 96 import static org.slf4j.LoggerFactory.getLogger;
98 97
...@@ -106,6 +105,9 @@ public class GossipLinkStore ...@@ -106,6 +105,9 @@ public class GossipLinkStore
106 extends AbstractStore<LinkEvent, LinkStoreDelegate> 105 extends AbstractStore<LinkEvent, LinkStoreDelegate>
107 implements LinkStore { 106 implements LinkStore {
108 107
108 + // Timeout in milliseconds to process links on remote master node
109 + private static final int REMOTE_MASTER_TIMEOUT = 1000;
110 +
109 private final Logger log = getLogger(getClass()); 111 private final Logger log = getLogger(getClass());
110 112
111 // Link inventory 113 // Link inventory
...@@ -131,6 +133,9 @@ public class GossipLinkStore ...@@ -131,6 +133,9 @@ public class GossipLinkStore
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected ClusterService clusterService; 134 protected ClusterService clusterService;
133 135
136 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 + protected MastershipService mastershipService;
138 +
134 protected static final KryoSerializer SERIALIZER = new KryoSerializer() { 139 protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
135 @Override 140 @Override
136 protected void setupKryoPool() { 141 protected void setupKryoPool() {
...@@ -141,6 +146,7 @@ public class GossipLinkStore ...@@ -141,6 +146,7 @@ public class GossipLinkStore
141 .register(InternalLinkRemovedEvent.class) 146 .register(InternalLinkRemovedEvent.class)
142 .register(LinkAntiEntropyAdvertisement.class) 147 .register(LinkAntiEntropyAdvertisement.class)
143 .register(LinkFragmentId.class) 148 .register(LinkFragmentId.class)
149 + .register(LinkInjectedEvent.class)
144 .build(); 150 .build();
145 } 151 }
146 }; 152 };
...@@ -161,6 +167,9 @@ public class GossipLinkStore ...@@ -161,6 +167,9 @@ public class GossipLinkStore
161 clusterCommunicator.addSubscriber( 167 clusterCommunicator.addSubscriber(
162 GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT, 168 GossipLinkStoreMessageSubjects.LINK_ANTI_ENTROPY_ADVERTISEMENT,
163 new InternalLinkAntiEntropyAdvertisementListener()); 169 new InternalLinkAntiEntropyAdvertisementListener());
170 + clusterCommunicator.addSubscriber(
171 + GossipLinkStoreMessageSubjects.LINK_INJECTED,
172 + new LinkInjectedEventListener());
164 173
165 executor = Executors.newCachedThreadPool(namedThreads("onos-link-fg-%d")); 174 executor = Executors.newCachedThreadPool(namedThreads("onos-link-fg-%d"));
166 175
...@@ -270,27 +279,52 @@ public class GossipLinkStore ...@@ -270,27 +279,52 @@ public class GossipLinkStore
270 public LinkEvent createOrUpdateLink(ProviderId providerId, 279 public LinkEvent createOrUpdateLink(ProviderId providerId,
271 LinkDescription linkDescription) { 280 LinkDescription linkDescription) {
272 281
273 - DeviceId dstDeviceId = linkDescription.dst().deviceId(); 282 + final DeviceId dstDeviceId = linkDescription.dst().deviceId();
283 + final NodeId localNode = clusterService.getLocalNode().id();
284 + final NodeId dstNode = mastershipService.getMasterFor(dstDeviceId);
285 +
286 + // Process link update only if we're the master of the destination node,
287 + // otherwise signal the actual master.
288 + LinkEvent linkEvent = null;
289 + if (localNode.equals(dstNode)) {
290 +
274 Timestamp newTimestamp = deviceClockService.getTimestamp(dstDeviceId); 291 Timestamp newTimestamp = deviceClockService.getTimestamp(dstDeviceId);
275 292
276 final Timestamped<LinkDescription> deltaDesc = new Timestamped<>(linkDescription, newTimestamp); 293 final Timestamped<LinkDescription> deltaDesc = new Timestamped<>(linkDescription, newTimestamp);
277 294
278 LinkKey key = linkKey(linkDescription.src(), linkDescription.dst()); 295 LinkKey key = linkKey(linkDescription.src(), linkDescription.dst());
279 - final LinkEvent event;
280 final Timestamped<LinkDescription> mergedDesc; 296 final Timestamped<LinkDescription> mergedDesc;
281 Map<ProviderId, Timestamped<LinkDescription>> map = getOrCreateLinkDescriptions(key); 297 Map<ProviderId, Timestamped<LinkDescription>> map = getOrCreateLinkDescriptions(key);
298 +
282 synchronized (map) { 299 synchronized (map) {
283 - event = createOrUpdateLinkInternal(providerId, deltaDesc); 300 + linkEvent = createOrUpdateLinkInternal(providerId, deltaDesc);
284 mergedDesc = map.get(providerId); 301 mergedDesc = map.get(providerId);
285 } 302 }
286 303
287 - if (event != null) { 304 + if (linkEvent != null) {
288 log.info("Notifying peers of a link update topology event from providerId: " 305 log.info("Notifying peers of a link update topology event from providerId: "
289 + "{} between src: {} and dst: {}", 306 + "{} between src: {} and dst: {}",
290 providerId, linkDescription.src(), linkDescription.dst()); 307 providerId, linkDescription.src(), linkDescription.dst());
291 notifyPeers(new InternalLinkEvent(providerId, mergedDesc)); 308 notifyPeers(new InternalLinkEvent(providerId, mergedDesc));
292 } 309 }
293 - return event; 310 +
311 + } else {
312 +
313 + LinkInjectedEvent linkInjectedEvent = new LinkInjectedEvent(providerId, linkDescription);
314 + ClusterMessage linkInjectedMessage = new ClusterMessage(localNode,
315 + GossipLinkStoreMessageSubjects.LINK_INJECTED, SERIALIZER.encode(linkInjectedEvent));
316 +
317 + try {
318 + clusterCommunicator.unicast(linkInjectedMessage, dstNode);
319 + } catch (IOException e) {
320 + log.warn("Failed to process link update between src: {} and dst: {} " +
321 + "(cluster messaging failed: {})",
322 + linkDescription.src(), linkDescription.dst(), e);
323 + }
324 +
325 + }
326 +
327 + return linkEvent;
294 } 328 }
295 329
296 @Override 330 @Override
...@@ -397,7 +431,7 @@ public class GossipLinkStore ...@@ -397,7 +431,7 @@ public class GossipLinkStore
397 !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { 431 !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) {
398 432
399 links.put(key, newLink); 433 links.put(key, newLink);
400 - // strictly speaking following can be ommitted 434 + // strictly speaking following can be omitted
401 srcLinks.put(oldLink.src().deviceId(), key); 435 srcLinks.put(oldLink.src().deviceId(), key);
402 dstLinks.put(oldLink.dst().deviceId(), key); 436 dstLinks.put(oldLink.dst().deviceId(), key);
403 return new LinkEvent(LINK_UPDATED, newLink); 437 return new LinkEvent(LINK_UPDATED, newLink);
...@@ -848,4 +882,25 @@ public class GossipLinkStore ...@@ -848,4 +882,25 @@ public class GossipLinkStore
848 }); 882 });
849 } 883 }
850 } 884 }
885 +
886 + private final class LinkInjectedEventListener
887 + implements ClusterMessageHandler {
888 + @Override
889 + public void handle(ClusterMessage message) {
890 +
891 + log.trace("Received injected link event from peer: {}", message.sender());
892 + LinkInjectedEvent linkInjectedEvent = SERIALIZER.decode(message.payload());
893 +
894 + ProviderId providerId = linkInjectedEvent.providerId();
895 + LinkDescription linkDescription = linkInjectedEvent.linkDescription();
896 +
897 + executor.submit(new Runnable() {
898 +
899 + @Override
900 + public void run() {
901 + createOrUpdateLink(providerId, linkDescription);
902 + }
903 + });
904 + }
905 + }
851 } 906 }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
15 */ 15 */
16 package org.onosproject.store.link.impl; 16 package org.onosproject.store.link.impl;
17 17
18 -import org.onosproject.store.cluster.messaging.MessageSubject; 18 + import org.onosproject.store.cluster.messaging.MessageSubject;
19 19
20 /** 20 /**
21 * MessageSubjects used by GossipLinkStore peer-peer communication. 21 * MessageSubjects used by GossipLinkStore peer-peer communication.
...@@ -30,4 +30,6 @@ public final class GossipLinkStoreMessageSubjects { ...@@ -30,4 +30,6 @@ public final class GossipLinkStoreMessageSubjects {
30 new MessageSubject("peer-link-removed"); 30 new MessageSubject("peer-link-removed");
31 public static final MessageSubject LINK_ANTI_ENTROPY_ADVERTISEMENT = 31 public static final MessageSubject LINK_ANTI_ENTROPY_ADVERTISEMENT =
32 new MessageSubject("link-enti-entropy-advertisement"); 32 new MessageSubject("link-enti-entropy-advertisement");
33 + public static final MessageSubject LINK_INJECTED =
34 + new MessageSubject("peer-link-injected");
33 } 35 }
......
1 +package org.onosproject.store.link.impl;
2 +
3 +import com.google.common.base.MoreObjects;
4 +import org.onosproject.net.link.LinkDescription;
5 +import org.onosproject.net.provider.ProviderId;
6 +
7 +public class LinkInjectedEvent {
8 +
9 + ProviderId providerId;
10 + LinkDescription linkDescription;
11 +
12 + public LinkInjectedEvent(ProviderId providerId, LinkDescription linkDescription) {
13 + this.providerId = providerId;
14 + this.linkDescription = linkDescription;
15 + }
16 +
17 + public ProviderId providerId() {
18 + return providerId;
19 + }
20 +
21 + public LinkDescription linkDescription() {
22 + return linkDescription;
23 + }
24 +
25 + @Override
26 + public String toString() {
27 + return MoreObjects.toStringHelper(getClass())
28 + .add("providerId", providerId)
29 + .add("linkDescription", linkDescription)
30 + .toString();
31 + }
32 +
33 + // for serializer
34 + protected LinkInjectedEvent() {
35 + this.providerId = null;
36 + this.linkDescription = null;
37 + }
38 +}
...@@ -27,6 +27,8 @@ import org.onlab.packet.IpAddress; ...@@ -27,6 +27,8 @@ import org.onlab.packet.IpAddress;
27 import org.onosproject.cluster.ControllerNode; 27 import org.onosproject.cluster.ControllerNode;
28 import org.onosproject.cluster.DefaultControllerNode; 28 import org.onosproject.cluster.DefaultControllerNode;
29 import org.onosproject.cluster.NodeId; 29 import org.onosproject.cluster.NodeId;
30 +import org.onosproject.mastership.MastershipService;
31 +import org.onosproject.mastership.MastershipServiceAdapter;
30 import org.onosproject.mastership.MastershipTerm; 32 import org.onosproject.mastership.MastershipTerm;
31 import org.onosproject.net.ConnectPoint; 33 import org.onosproject.net.ConnectPoint;
32 import org.onosproject.net.DefaultAnnotations; 34 import org.onosproject.net.DefaultAnnotations;
...@@ -115,7 +117,7 @@ public class GossipLinkStoreTest { ...@@ -115,7 +117,7 @@ public class GossipLinkStoreTest {
115 private DeviceClockManager deviceClockManager; 117 private DeviceClockManager deviceClockManager;
116 private DeviceClockService deviceClockService; 118 private DeviceClockService deviceClockService;
117 private ClusterCommunicationService clusterCommunicator; 119 private ClusterCommunicationService clusterCommunicator;
118 - 120 + private MastershipService mastershipService;
119 121
120 @BeforeClass 122 @BeforeClass
121 public static void setUpBeforeClass() throws Exception { 123 public static void setUpBeforeClass() throws Exception {
...@@ -146,11 +148,13 @@ public class GossipLinkStoreTest { ...@@ -146,11 +148,13 @@ public class GossipLinkStoreTest {
146 linkStoreImpl.deviceClockService = deviceClockService; 148 linkStoreImpl.deviceClockService = deviceClockService;
147 linkStoreImpl.clusterCommunicator = clusterCommunicator; 149 linkStoreImpl.clusterCommunicator = clusterCommunicator;
148 linkStoreImpl.clusterService = new TestClusterService(); 150 linkStoreImpl.clusterService = new TestClusterService();
151 + linkStoreImpl.mastershipService = new TestMastershipService();
149 linkStoreImpl.activate(); 152 linkStoreImpl.activate();
150 linkStore = linkStoreImpl; 153 linkStore = linkStoreImpl;
151 154
152 verify(clusterCommunicator); 155 verify(clusterCommunicator);
153 reset(clusterCommunicator); 156 reset(clusterCommunicator);
157 +
154 } 158 }
155 159
156 @After 160 @After
...@@ -602,4 +606,11 @@ public class GossipLinkStoreTest { ...@@ -602,4 +606,11 @@ public class GossipLinkStoreTest {
602 nodeStates.put(NID2, ACTIVE); 606 nodeStates.put(NID2, ACTIVE);
603 } 607 }
604 } 608 }
609 +
610 + private final class TestMastershipService extends MastershipServiceAdapter {
611 + @Override
612 + public NodeId getMasterFor(DeviceId deviceId) {
613 + return NID1;
614 + }
615 + }
605 } 616 }
......