blob: 2240eb4f5cb7e194fd4dac45f7ea9acf4132be65 [file] [log] [blame]
Madan Jampanibad538c2015-08-19 17:35:27 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Madan Jampanibad538c2015-08-19 17:35:27 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.link.impl;
17
Madan Jampanibad538c2015-08-19 17:35:27 -070018import java.util.Collection;
19import java.util.Map;
20import java.util.Objects;
21import java.util.Set;
22import java.util.concurrent.atomic.AtomicReference;
23import java.util.function.Predicate;
24import java.util.stream.Collectors;
25
26import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
29import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
31import org.apache.felix.scr.annotations.Service;
32import org.onlab.util.KryoNamespace;
33import org.onlab.util.SharedExecutors;
34import org.onosproject.cluster.ClusterService;
35import org.onosproject.cluster.NodeId;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
Madan Jampanibad538c2015-08-19 17:35:27 -070038import org.onosproject.mastership.MastershipService;
39import org.onosproject.net.AnnotationKeys;
40import org.onosproject.net.AnnotationsUtil;
41import org.onosproject.net.ConnectPoint;
42import org.onosproject.net.DefaultAnnotations;
43import org.onosproject.net.DefaultLink;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Link;
Madan Jampanibad538c2015-08-19 17:35:27 -070046import org.onosproject.net.Link.Type;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080047import org.onosproject.net.LinkKey;
48import org.onosproject.net.config.ConfigFactory;
49import org.onosproject.net.config.NetworkConfigEvent;
50import org.onosproject.net.config.NetworkConfigListener;
51import org.onosproject.net.config.NetworkConfigRegistry;
Madan Jampanibad538c2015-08-19 17:35:27 -070052import org.onosproject.net.device.DeviceClockService;
53import org.onosproject.net.link.DefaultLinkDescription;
54import org.onosproject.net.link.LinkDescription;
55import org.onosproject.net.link.LinkEvent;
56import org.onosproject.net.link.LinkStore;
57import org.onosproject.net.link.LinkStoreDelegate;
58import org.onosproject.net.provider.ProviderId;
59import org.onosproject.store.AbstractStore;
60import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
61import org.onosproject.store.cluster.messaging.MessageSubject;
62import org.onosproject.store.impl.MastershipBasedTimestamp;
63import org.onosproject.store.serializers.KryoNamespaces;
HIGUCHI Yutae7290652016-05-18 11:29:01 -070064import org.onosproject.store.serializers.StoreSerializer;
Madan Jampanibad538c2015-08-19 17:35:27 -070065import org.onosproject.store.serializers.custom.DistributedStoreSerializers;
66import org.onosproject.store.service.EventuallyConsistentMap;
67import org.onosproject.store.service.EventuallyConsistentMapEvent;
68import org.onosproject.store.service.EventuallyConsistentMapListener;
69import org.onosproject.store.service.StorageService;
70import org.slf4j.Logger;
71
72import com.google.common.collect.Iterables;
73import com.google.common.collect.Maps;
kircaali28d67682016-04-11 15:08:14 +000074import com.google.common.collect.Sets;
Madan Jampanibad538c2015-08-19 17:35:27 -070075import com.google.common.util.concurrent.Futures;
76
Ray Milkeyb7f0f642016-01-22 16:08:14 -080077import static org.onosproject.net.DefaultAnnotations.merge;
78import static org.onosproject.net.DefaultAnnotations.union;
79import static org.onosproject.net.Link.State.ACTIVE;
80import static org.onosproject.net.Link.State.INACTIVE;
81import static org.onosproject.net.Link.Type.DIRECT;
82import static org.onosproject.net.Link.Type.INDIRECT;
83import static org.onosproject.net.LinkKey.linkKey;
84import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
85import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
86import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
87import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED;
88import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
89import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
90import static org.slf4j.LoggerFactory.getLogger;
91
Madan Jampanibad538c2015-08-19 17:35:27 -070092/**
93 * Manages the inventory of links using a {@code EventuallyConsistentMap}.
94 */
Sho SHIMIZU5c396e32016-08-12 15:19:12 -070095@Component(immediate = true)
Madan Jampanibad538c2015-08-19 17:35:27 -070096@Service
97public class ECLinkStore
kircaali28d67682016-04-11 15:08:14 +000098 extends AbstractStore<LinkEvent, LinkStoreDelegate>
99 implements LinkStore {
Madan Jampanibad538c2015-08-19 17:35:27 -0700100
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800101 /**
102 * Modes for dealing with newly discovered links.
103 */
104 protected enum LinkDiscoveryMode {
105 /**
106 * Permissive mode - all newly discovered links are valid.
107 */
108 PERMISSIVE,
109
110 /**
111 * Strict mode - all newly discovered links must be defined in
112 * the network config.
113 */
114 STRICT
115 }
116
Madan Jampanibad538c2015-08-19 17:35:27 -0700117 private final Logger log = getLogger(getClass());
118
119 private final Map<LinkKey, Link> links = Maps.newConcurrentMap();
kircaali28d67682016-04-11 15:08:14 +0000120 private final Map<LinkKey, Set<ProviderId>> linkProviders = Maps.newConcurrentMap();
Madan Jampanibad538c2015-08-19 17:35:27 -0700121 private EventuallyConsistentMap<Provided<LinkKey>, LinkDescription> linkDescriptions;
122
kircaali28d67682016-04-11 15:08:14 +0000123
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800124 private ApplicationId appId;
125
Madan Jampanibad538c2015-08-19 17:35:27 -0700126 private static final MessageSubject LINK_INJECT_MESSAGE = new MessageSubject("inject-link-request");
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected StorageService storageService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected MastershipService mastershipService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected DeviceClockService deviceClockService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected ClusterCommunicationService clusterCommunicator;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected ClusterService clusterService;
142
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected NetworkConfigRegistry netCfgService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected CoreService coreService;
148
Madan Jampanibad538c2015-08-19 17:35:27 -0700149 private EventuallyConsistentMapListener<Provided<LinkKey>, LinkDescription> linkTracker =
150 new InternalLinkTracker();
151
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800152 // Listener for config changes
153 private final InternalConfigListener cfgListener = new InternalConfigListener();
154
155 protected LinkDiscoveryMode linkDiscoveryMode = LinkDiscoveryMode.STRICT;
156
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700157 protected static final StoreSerializer SERIALIZER = StoreSerializer.using(
158 KryoNamespace.newBuilder()
Madan Jampanibad538c2015-08-19 17:35:27 -0700159 .register(DistributedStoreSerializers.STORE_COMMON)
160 .nextId(DistributedStoreSerializers.STORE_CUSTOM_BEGIN)
161 .register(Provided.class)
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700162 .build("ECLink"));
Madan Jampanibad538c2015-08-19 17:35:27 -0700163
164 @Activate
165 public void activate() {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800166 appId = coreService.registerApplication("org.onosproject.core");
167 netCfgService.registerConfigFactory(factory);
168 netCfgService.addListener(cfgListener);
169
170 cfgListener.reconfigure(netCfgService.getConfig(appId, CoreConfig.class));
171
Madan Jampanibad538c2015-08-19 17:35:27 -0700172 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
173 .register(KryoNamespaces.API)
174 .register(MastershipBasedTimestamp.class)
175 .register(Provided.class);
176
177 linkDescriptions = storageService.<Provided<LinkKey>, LinkDescription>eventuallyConsistentMapBuilder()
178 .withName("onos-link-descriptions")
179 .withSerializer(serializer)
180 .withTimestampProvider((k, v) -> {
181 try {
182 return v == null ? null : deviceClockService.getTimestamp(v.dst().deviceId());
183 } catch (IllegalStateException e) {
184 return null;
185 }
186 }).build();
187
188 clusterCommunicator.addSubscriber(LINK_INJECT_MESSAGE,
kircaali28d67682016-04-11 15:08:14 +0000189 SERIALIZER::decode,
190 this::injectLink,
191 SERIALIZER::encode,
192 SharedExecutors.getPoolThreadExecutor());
Madan Jampanibad538c2015-08-19 17:35:27 -0700193
194 linkDescriptions.addListener(linkTracker);
195
196 log.info("Started");
197 }
198
199 @Deactivate
200 public void deactivate() {
201 linkDescriptions.removeListener(linkTracker);
202 linkDescriptions.destroy();
kircaali28d67682016-04-11 15:08:14 +0000203 linkProviders.clear();
Madan Jampanibad538c2015-08-19 17:35:27 -0700204 links.clear();
205 clusterCommunicator.removeSubscriber(LINK_INJECT_MESSAGE);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800206 netCfgService.removeListener(cfgListener);
207 netCfgService.unregisterConfigFactory(factory);
Madan Jampanibad538c2015-08-19 17:35:27 -0700208
209 log.info("Stopped");
210 }
211
212 @Override
213 public int getLinkCount() {
214 return links.size();
215 }
216
217 @Override
218 public Iterable<Link> getLinks() {
219 return links.values();
220 }
221
222 @Override
223 public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
224 return filter(links.values(), link -> deviceId.equals(link.src().deviceId()));
225 }
226
227 @Override
228 public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
229 return filter(links.values(), link -> deviceId.equals(link.dst().deviceId()));
230 }
231
232 @Override
233 public Link getLink(ConnectPoint src, ConnectPoint dst) {
234 return links.get(linkKey(src, dst));
235 }
236
237 @Override
238 public Set<Link> getEgressLinks(ConnectPoint src) {
239 return filter(links.values(), link -> src.equals(link.src()));
240 }
241
242 @Override
243 public Set<Link> getIngressLinks(ConnectPoint dst) {
244 return filter(links.values(), link -> dst.equals(link.dst()));
245 }
246
247 @Override
248 public LinkEvent createOrUpdateLink(ProviderId providerId,
249 LinkDescription linkDescription) {
250 final DeviceId dstDeviceId = linkDescription.dst().deviceId();
251 final NodeId dstNodeId = mastershipService.getMasterFor(dstDeviceId);
252
253 // Process link update only if we're the master of the destination node,
254 // otherwise signal the actual master.
255 if (clusterService.getLocalNode().id().equals(dstNodeId)) {
256 LinkKey linkKey = linkKey(linkDescription.src(), linkDescription.dst());
Ayaka Koshibe2c59acf2015-09-08 15:37:47 -0700257 Provided<LinkKey> internalLinkKey = getProvided(linkKey, providerId);
258 if (internalLinkKey == null) {
259 return null;
260 }
Jian Li68c4fc42016-01-11 16:07:03 -0800261 linkDescriptions.compute(internalLinkKey, (k, v) -> createOrUpdateLinkInternal(v, linkDescription));
Madan Jampanibad538c2015-08-19 17:35:27 -0700262 return refreshLinkCache(linkKey);
263 } else {
Thomas Vachuska1cf1fa42017-01-19 13:56:19 -0800264 // Only forward for ConfigProvider or NullProvider
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800265 // Forwarding was added as a workaround for ONOS-490
Thomas Vachuska1cf1fa42017-01-19 13:56:19 -0800266 if (!providerId.scheme().equals("cfg") && !providerId.scheme().equals("null")) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800267 return null;
268 }
269 // Temporary hack for NPE (ONOS-1171).
270 // Proper fix is to implement forwarding to master on ConfigProvider
Madan Jampanibad538c2015-08-19 17:35:27 -0700271 if (dstNodeId == null) {
272 return null;
273 }
274 return Futures.getUnchecked(clusterCommunicator.sendAndReceive(new Provided<>(linkDescription, providerId),
kircaali28d67682016-04-11 15:08:14 +0000275 LINK_INJECT_MESSAGE,
276 SERIALIZER::encode,
277 SERIALIZER::decode,
278 dstNodeId));
Madan Jampanibad538c2015-08-19 17:35:27 -0700279 }
280 }
281
Ayaka Koshibe2c59acf2015-09-08 15:37:47 -0700282 private Provided<LinkKey> getProvided(LinkKey linkKey, ProviderId provId) {
283 ProviderId bpid = getBaseProviderId(linkKey);
284 if (provId == null) {
285 // The LinkService didn't know who this LinkKey belongs to.
286 // A fix is to either modify the getProvider() in LinkService classes
287 // or expose the contents of linkDescriptions to the LinkService.
288 return (bpid == null) ? null : new Provided<>(linkKey, bpid);
289 } else {
290 return new Provided<>(linkKey, provId);
291 }
292 }
293
Madan Jampanibad538c2015-08-19 17:35:27 -0700294 private LinkDescription createOrUpdateLinkInternal(LinkDescription current, LinkDescription updated) {
295 if (current != null) {
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800296 Type type;
297 if (current.type() == DIRECT && updated.type() == Type.INDIRECT) {
298 // mask transition from DIRECT -> INDIRECT, likely to be triggered by BDDP
299 type = Type.DIRECT;
300 } else {
301 type = updated.type();
302 }
kircaali28d67682016-04-11 15:08:14 +0000303 return new DefaultLinkDescription(
304 current.src(),
305 current.dst(),
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800306 type,
kircaali28d67682016-04-11 15:08:14 +0000307 current.isExpected(),
308 union(current.annotations(), updated.annotations()));
Madan Jampanibad538c2015-08-19 17:35:27 -0700309 }
310 return updated;
311 }
312
kircaali28d67682016-04-11 15:08:14 +0000313 private Set<ProviderId> createOrUpdateLinkProviders(Set<ProviderId> current, ProviderId providerId) {
314 if (current == null) {
315 current = Sets.newConcurrentHashSet();
316 }
317 current.add(providerId);
318 return current;
319 }
320
Madan Jampanibad538c2015-08-19 17:35:27 -0700321 private LinkEvent refreshLinkCache(LinkKey linkKey) {
322 AtomicReference<LinkEvent.Type> eventType = new AtomicReference<>();
323 Link link = links.compute(linkKey, (key, existingLink) -> {
324 Link newLink = composeLink(linkKey);
Madan Jampani11591862016-06-27 13:58:07 -0700325 if (newLink == null) {
326 return null;
327 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700328 if (existingLink == null) {
329 eventType.set(LINK_ADDED);
330 return newLink;
331 } else if (existingLink.state() != newLink.state() ||
kircaali28d67682016-04-11 15:08:14 +0000332 existingLink.isExpected() != newLink.isExpected() ||
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800333 (existingLink.type() != newLink.type()) ||
kircaali28d67682016-04-11 15:08:14 +0000334 !AnnotationsUtil.isEqual(existingLink.annotations(), newLink.annotations())) {
335 eventType.set(LINK_UPDATED);
336 return newLink;
Madan Jampanibad538c2015-08-19 17:35:27 -0700337 } else {
338 return existingLink;
339 }
340 });
341 return eventType.get() != null ? new LinkEvent(eventType.get(), link) : null;
342 }
343
344 private Set<ProviderId> getAllProviders(LinkKey linkKey) {
kircaali28d67682016-04-11 15:08:14 +0000345 return linkProviders.getOrDefault(linkKey, Sets.newConcurrentHashSet());
Madan Jampanibad538c2015-08-19 17:35:27 -0700346 }
347
348 private ProviderId getBaseProviderId(LinkKey linkKey) {
349 Set<ProviderId> allProviders = getAllProviders(linkKey);
350 if (allProviders.size() > 0) {
351 return allProviders.stream()
kircaali28d67682016-04-11 15:08:14 +0000352 .filter(p -> !p.isAncillary())
353 .findFirst()
354 .orElse(Iterables.getFirst(allProviders, null));
Madan Jampanibad538c2015-08-19 17:35:27 -0700355 }
356 return null;
357 }
358
359 private Link composeLink(LinkKey linkKey) {
360
Ray Milkey1bce6fb2016-07-15 13:38:53 -0700361 ProviderId baseProviderId = getBaseProviderId(linkKey);
362 if (baseProviderId == null) {
363 // provider was not found, this means it was already removed by the
364 // parent component.
365 return null;
366 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700367 LinkDescription base = linkDescriptions.get(new Provided<>(linkKey, baseProviderId));
Madan Jampani11591862016-06-27 13:58:07 -0700368 // short circuit if link description no longer exists
369 if (base == null) {
370 return null;
371 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700372 ConnectPoint src = base.src();
373 ConnectPoint dst = base.dst();
374 Type type = base.type();
375 AtomicReference<DefaultAnnotations> annotations = new AtomicReference<>(DefaultAnnotations.builder().build());
376 annotations.set(merge(annotations.get(), base.annotations()));
377
378 getAllProviders(linkKey).stream()
kircaali28d67682016-04-11 15:08:14 +0000379 .map(p -> new Provided<>(linkKey, p))
380 .forEach(key -> {
381 LinkDescription linkDescription = linkDescriptions.get(key);
382 if (linkDescription != null) {
383 annotations.set(merge(annotations.get(),
384 linkDescription.annotations()));
385 }
386 });
Madan Jampanibad538c2015-08-19 17:35:27 -0700387
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800388 Link.State initialLinkState;
389
390 boolean isExpected;
391 if (linkDiscoveryMode == LinkDiscoveryMode.PERMISSIVE) {
392 initialLinkState = ACTIVE;
393 isExpected =
394 Objects.equals(annotations.get().value(AnnotationKeys.DURABLE), "true");
395 } else {
396 initialLinkState = base.isExpected() ? ACTIVE : INACTIVE;
397 isExpected = base.isExpected();
398 }
399
400
Ray Milkey2693bda2016-01-22 16:08:14 -0800401 return DefaultLink.builder()
402 .providerId(baseProviderId)
403 .src(src)
404 .dst(dst)
405 .type(type)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800406 .state(initialLinkState)
407 .isExpected(isExpected)
Ray Milkey2693bda2016-01-22 16:08:14 -0800408 .annotations(annotations.get())
409 .build();
Madan Jampanibad538c2015-08-19 17:35:27 -0700410 }
411
412 // Updates, if necessary the specified link and returns the appropriate event.
413 // Guarded by linkDescs value (=locking each Link)
414 private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) {
415 // Note: INDIRECT -> DIRECT transition only
416 // so that BDDP discovered Link will not overwrite LDDP Link
417 if (oldLink.state() != newLink.state() ||
kircaali28d67682016-04-11 15:08:14 +0000418 (oldLink.type() == INDIRECT && newLink.type() == DIRECT) ||
419 !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) {
Madan Jampanibad538c2015-08-19 17:35:27 -0700420
421 links.put(key, newLink);
422 return new LinkEvent(LINK_UPDATED, newLink);
423 }
424 return null;
425 }
426
427 @Override
428 public LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst) {
429 Link link = getLink(src, dst);
430 if (link == null) {
431 return null;
432 }
433
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800434 if (linkDiscoveryMode == LinkDiscoveryMode.PERMISSIVE && link.isExpected()) {
Madan Jampanibad538c2015-08-19 17:35:27 -0700435 // FIXME: this will not sync link state!!!
436 return link.state() == INACTIVE ? null :
437 updateLink(linkKey(link.src(), link.dst()), link,
Ray Milkey2693bda2016-01-22 16:08:14 -0800438 DefaultLink.builder()
439 .providerId(link.providerId())
440 .src(link.src())
441 .dst(link.dst())
442 .type(link.type())
443 .state(INACTIVE)
444 .isExpected(link.isExpected())
445 .annotations(link.annotations())
446 .build());
Madan Jampanibad538c2015-08-19 17:35:27 -0700447 }
448 return removeLink(src, dst);
449 }
450
451 @Override
452 public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
453 final LinkKey linkKey = LinkKey.linkKey(src, dst);
Madan Jampani5d4396f2015-09-02 16:04:20 -0700454 ProviderId primaryProviderId = getBaseProviderId(linkKey);
455 // Stop if there is no base provider.
456 if (primaryProviderId == null) {
457 return null;
458 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700459 LinkDescription removedLinkDescription =
Madan Jampani5d4396f2015-09-02 16:04:20 -0700460 linkDescriptions.remove(new Provided<>(linkKey, primaryProviderId));
Madan Jampanibad538c2015-08-19 17:35:27 -0700461 if (removedLinkDescription != null) {
462 return purgeLinkCache(linkKey);
463 }
464 return null;
465 }
466
467 private LinkEvent purgeLinkCache(LinkKey linkKey) {
468 Link removedLink = links.remove(linkKey);
469 if (removedLink != null) {
470 getAllProviders(linkKey).forEach(p -> linkDescriptions.remove(new Provided<>(linkKey, p)));
kircaali28d67682016-04-11 15:08:14 +0000471 linkProviders.remove(linkKey);
Madan Jampanibad538c2015-08-19 17:35:27 -0700472 return new LinkEvent(LINK_REMOVED, removedLink);
473 }
474 return null;
475 }
476
477 private Set<Link> filter(Collection<Link> links, Predicate<Link> predicate) {
478 return links.stream().filter(predicate).collect(Collectors.toSet());
479 }
480
481 private LinkEvent injectLink(Provided<LinkDescription> linkInjectRequest) {
482 log.trace("Received request to inject link {}", linkInjectRequest);
483
484 ProviderId providerId = linkInjectRequest.providerId();
485 LinkDescription linkDescription = linkInjectRequest.key();
486
487 final DeviceId deviceId = linkDescription.dst().deviceId();
488 if (!deviceClockService.isTimestampAvailable(deviceId)) {
489 // workaround for ONOS-1208
490 log.warn("Not ready to accept update. Dropping {}", linkInjectRequest);
491 return null;
492 }
493 return createOrUpdateLink(providerId, linkDescription);
494 }
495
496 private class InternalLinkTracker implements EventuallyConsistentMapListener<Provided<LinkKey>, LinkDescription> {
497 @Override
498 public void event(EventuallyConsistentMapEvent<Provided<LinkKey>, LinkDescription> event) {
499 if (event.type() == PUT) {
kircaali28d67682016-04-11 15:08:14 +0000500 linkProviders.compute(event.key().key(), (k, v) ->
501 createOrUpdateLinkProviders(v, event.key().providerId()));
Madan Jampanibad538c2015-08-19 17:35:27 -0700502 notifyDelegate(refreshLinkCache(event.key().key()));
503 } else if (event.type() == REMOVE) {
504 notifyDelegate(purgeLinkCache(event.key().key()));
kircaali28d67682016-04-11 15:08:14 +0000505 linkProviders.remove(event.key().key());
Madan Jampanibad538c2015-08-19 17:35:27 -0700506 }
507 }
508 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800509
510 private class InternalConfigListener implements NetworkConfigListener {
511
512 void reconfigure(CoreConfig coreConfig) {
513 if (coreConfig == null) {
514 linkDiscoveryMode = LinkDiscoveryMode.PERMISSIVE;
515 } else {
516 linkDiscoveryMode = coreConfig.linkDiscoveryMode();
517 }
518 if (linkDiscoveryMode == LinkDiscoveryMode.STRICT) {
519 // Remove any previous links to force them to go through the strict
520 // discovery process
Ray Milkey15551272016-02-10 16:22:02 -0800521 if (linkDescriptions != null) {
522 linkDescriptions.clear();
523 }
524 if (links != null) {
525 links.clear();
526 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800527 }
528 log.debug("config set link discovery mode to {}",
529 linkDiscoveryMode.name());
530 }
531
532 @Override
533 public void event(NetworkConfigEvent event) {
534
535 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
536 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
537 event.configClass().equals(CoreConfig.class)) {
538
539 CoreConfig cfg = netCfgService.getConfig(appId, CoreConfig.class);
540 reconfigure(cfg);
541 log.info("Reconfigured");
542 }
543 }
544 }
545
546 // Configuration properties factory
547 private final ConfigFactory factory =
548 new ConfigFactory<ApplicationId, CoreConfig>(APP_SUBJECT_FACTORY,
kircaali28d67682016-04-11 15:08:14 +0000549 CoreConfig.class,
550 "core") {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800551 @Override
552 public CoreConfig createConfig() {
553 return new CoreConfig();
554 }
555 };
Ray Milkeyd0dd1352016-01-19 10:58:41 -0800556}