blob: eebfbc2df8d0212c00169998c74505fae8a6b4f6 [file] [log] [blame]
Madan Jampanibad538c2015-08-19 17:35:27 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Ray Milkeyd84f89b2018-08-17 14:54:17 -070018import com.google.common.collect.Iterables;
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
21import com.google.common.util.concurrent.Futures;
Madan Jampanibad538c2015-08-19 17:35:27 -070022import org.onlab.util.KryoNamespace;
23import org.onlab.util.SharedExecutors;
24import org.onosproject.cluster.ClusterService;
25import org.onosproject.cluster.NodeId;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080026import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Madan Jampanibad538c2015-08-19 17:35:27 -070028import org.onosproject.mastership.MastershipService;
29import org.onosproject.net.AnnotationKeys;
30import org.onosproject.net.AnnotationsUtil;
31import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.DefaultAnnotations;
33import org.onosproject.net.DefaultLink;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.Link;
Madan Jampanibad538c2015-08-19 17:35:27 -070036import org.onosproject.net.Link.Type;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080037import org.onosproject.net.LinkKey;
38import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigListener;
41import org.onosproject.net.config.NetworkConfigRegistry;
Madan Jampanibad538c2015-08-19 17:35:27 -070042import org.onosproject.net.device.DeviceClockService;
43import org.onosproject.net.link.DefaultLinkDescription;
44import org.onosproject.net.link.LinkDescription;
45import org.onosproject.net.link.LinkEvent;
46import org.onosproject.net.link.LinkStore;
47import org.onosproject.net.link.LinkStoreDelegate;
48import org.onosproject.net.provider.ProviderId;
49import org.onosproject.store.AbstractStore;
50import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
51import org.onosproject.store.cluster.messaging.MessageSubject;
52import org.onosproject.store.impl.MastershipBasedTimestamp;
53import org.onosproject.store.serializers.KryoNamespaces;
Madan Jampanibad538c2015-08-19 17:35:27 -070054import org.onosproject.store.serializers.custom.DistributedStoreSerializers;
55import org.onosproject.store.service.EventuallyConsistentMap;
56import org.onosproject.store.service.EventuallyConsistentMapEvent;
57import org.onosproject.store.service.EventuallyConsistentMapListener;
Jordan Halterman2c83a102017-08-20 17:11:41 -070058import org.onosproject.store.service.Serializer;
Madan Jampanibad538c2015-08-19 17:35:27 -070059import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Reference;
64import org.osgi.service.component.annotations.ReferenceCardinality;
Madan Jampanibad538c2015-08-19 17:35:27 -070065import org.slf4j.Logger;
66
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067import java.util.Collection;
68import java.util.Map;
69import java.util.Objects;
70import java.util.Set;
71import java.util.concurrent.atomic.AtomicReference;
72import java.util.function.Predicate;
73import java.util.stream.Collectors;
Madan Jampanibad538c2015-08-19 17:35:27 -070074
Ray Milkeyb7f0f642016-01-22 16:08:14 -080075import static org.onosproject.net.DefaultAnnotations.union;
76import static org.onosproject.net.Link.State.ACTIVE;
77import static org.onosproject.net.Link.State.INACTIVE;
78import static org.onosproject.net.Link.Type.DIRECT;
79import static org.onosproject.net.Link.Type.INDIRECT;
80import static org.onosproject.net.LinkKey.linkKey;
81import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
82import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
83import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
84import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED;
85import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
86import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE;
87import static org.slf4j.LoggerFactory.getLogger;
88
Madan Jampanibad538c2015-08-19 17:35:27 -070089/**
90 * Manages the inventory of links using a {@code EventuallyConsistentMap}.
91 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092@Component(immediate = true, service = LinkStore.class)
Madan Jampanibad538c2015-08-19 17:35:27 -070093public class ECLinkStore
kircaali28d67682016-04-11 15:08:14 +000094 extends AbstractStore<LinkEvent, LinkStoreDelegate>
95 implements LinkStore {
Madan Jampanibad538c2015-08-19 17:35:27 -070096
Ray Milkeyb7f0f642016-01-22 16:08:14 -080097 /**
98 * Modes for dealing with newly discovered links.
99 */
100 protected enum LinkDiscoveryMode {
101 /**
102 * Permissive mode - all newly discovered links are valid.
103 */
104 PERMISSIVE,
105
106 /**
107 * Strict mode - all newly discovered links must be defined in
108 * the network config.
109 */
110 STRICT
111 }
112
Madan Jampanibad538c2015-08-19 17:35:27 -0700113 private final Logger log = getLogger(getClass());
114
115 private final Map<LinkKey, Link> links = Maps.newConcurrentMap();
kircaali28d67682016-04-11 15:08:14 +0000116 private final Map<LinkKey, Set<ProviderId>> linkProviders = Maps.newConcurrentMap();
Madan Jampanibad538c2015-08-19 17:35:27 -0700117 private EventuallyConsistentMap<Provided<LinkKey>, LinkDescription> linkDescriptions;
118
kircaali28d67682016-04-11 15:08:14 +0000119
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800120 private ApplicationId appId;
121
Madan Jampanibad538c2015-08-19 17:35:27 -0700122 private static final MessageSubject LINK_INJECT_MESSAGE = new MessageSubject("inject-link-request");
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Madan Jampanibad538c2015-08-19 17:35:27 -0700125 protected StorageService storageService;
126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Madan Jampanibad538c2015-08-19 17:35:27 -0700128 protected MastershipService mastershipService;
129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Madan Jampanibad538c2015-08-19 17:35:27 -0700131 protected DeviceClockService deviceClockService;
132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Madan Jampanibad538c2015-08-19 17:35:27 -0700134 protected ClusterCommunicationService clusterCommunicator;
135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Madan Jampanibad538c2015-08-19 17:35:27 -0700137 protected ClusterService clusterService;
138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800140 protected NetworkConfigRegistry netCfgService;
141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800143 protected CoreService coreService;
144
Madan Jampanibad538c2015-08-19 17:35:27 -0700145 private EventuallyConsistentMapListener<Provided<LinkKey>, LinkDescription> linkTracker =
146 new InternalLinkTracker();
147
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800148 // Listener for config changes
149 private final InternalConfigListener cfgListener = new InternalConfigListener();
150
151 protected LinkDiscoveryMode linkDiscoveryMode = LinkDiscoveryMode.STRICT;
152
Jordan Halterman2c83a102017-08-20 17:11:41 -0700153 protected static final Serializer SERIALIZER = Serializer.using(
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700154 KryoNamespace.newBuilder()
Madan Jampanibad538c2015-08-19 17:35:27 -0700155 .register(DistributedStoreSerializers.STORE_COMMON)
156 .nextId(DistributedStoreSerializers.STORE_CUSTOM_BEGIN)
157 .register(Provided.class)
HIGUCHI Yutae7290652016-05-18 11:29:01 -0700158 .build("ECLink"));
Madan Jampanibad538c2015-08-19 17:35:27 -0700159
160 @Activate
161 public void activate() {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800162 appId = coreService.registerApplication("org.onosproject.core");
163 netCfgService.registerConfigFactory(factory);
164 netCfgService.addListener(cfgListener);
165
166 cfgListener.reconfigure(netCfgService.getConfig(appId, CoreConfig.class));
167
Madan Jampanibad538c2015-08-19 17:35:27 -0700168 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
169 .register(KryoNamespaces.API)
170 .register(MastershipBasedTimestamp.class)
171 .register(Provided.class);
172
173 linkDescriptions = storageService.<Provided<LinkKey>, LinkDescription>eventuallyConsistentMapBuilder()
174 .withName("onos-link-descriptions")
175 .withSerializer(serializer)
176 .withTimestampProvider((k, v) -> {
177 try {
178 return v == null ? null : deviceClockService.getTimestamp(v.dst().deviceId());
179 } catch (IllegalStateException e) {
180 return null;
181 }
182 }).build();
183
184 clusterCommunicator.addSubscriber(LINK_INJECT_MESSAGE,
kircaali28d67682016-04-11 15:08:14 +0000185 SERIALIZER::decode,
186 this::injectLink,
187 SERIALIZER::encode,
188 SharedExecutors.getPoolThreadExecutor());
Madan Jampanibad538c2015-08-19 17:35:27 -0700189
190 linkDescriptions.addListener(linkTracker);
191
192 log.info("Started");
193 }
194
195 @Deactivate
196 public void deactivate() {
197 linkDescriptions.removeListener(linkTracker);
198 linkDescriptions.destroy();
kircaali28d67682016-04-11 15:08:14 +0000199 linkProviders.clear();
Madan Jampanibad538c2015-08-19 17:35:27 -0700200 links.clear();
201 clusterCommunicator.removeSubscriber(LINK_INJECT_MESSAGE);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800202 netCfgService.removeListener(cfgListener);
203 netCfgService.unregisterConfigFactory(factory);
Madan Jampanibad538c2015-08-19 17:35:27 -0700204
205 log.info("Stopped");
206 }
207
208 @Override
209 public int getLinkCount() {
210 return links.size();
211 }
212
213 @Override
214 public Iterable<Link> getLinks() {
215 return links.values();
216 }
217
218 @Override
219 public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
220 return filter(links.values(), link -> deviceId.equals(link.src().deviceId()));
221 }
222
223 @Override
224 public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
225 return filter(links.values(), link -> deviceId.equals(link.dst().deviceId()));
226 }
227
228 @Override
229 public Link getLink(ConnectPoint src, ConnectPoint dst) {
230 return links.get(linkKey(src, dst));
231 }
232
233 @Override
234 public Set<Link> getEgressLinks(ConnectPoint src) {
235 return filter(links.values(), link -> src.equals(link.src()));
236 }
237
238 @Override
239 public Set<Link> getIngressLinks(ConnectPoint dst) {
240 return filter(links.values(), link -> dst.equals(link.dst()));
241 }
242
243 @Override
244 public LinkEvent createOrUpdateLink(ProviderId providerId,
245 LinkDescription linkDescription) {
246 final DeviceId dstDeviceId = linkDescription.dst().deviceId();
247 final NodeId dstNodeId = mastershipService.getMasterFor(dstDeviceId);
248
249 // Process link update only if we're the master of the destination node,
250 // otherwise signal the actual master.
251 if (clusterService.getLocalNode().id().equals(dstNodeId)) {
252 LinkKey linkKey = linkKey(linkDescription.src(), linkDescription.dst());
Ayaka Koshibe2c59acf2015-09-08 15:37:47 -0700253 Provided<LinkKey> internalLinkKey = getProvided(linkKey, providerId);
254 if (internalLinkKey == null) {
255 return null;
256 }
Jian Li68c4fc42016-01-11 16:07:03 -0800257 linkDescriptions.compute(internalLinkKey, (k, v) -> createOrUpdateLinkInternal(v, linkDescription));
Madan Jampanibad538c2015-08-19 17:35:27 -0700258 return refreshLinkCache(linkKey);
259 } else {
Thomas Vachuska1cf1fa42017-01-19 13:56:19 -0800260 // Only forward for ConfigProvider or NullProvider
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800261 // Forwarding was added as a workaround for ONOS-490
Jon Halla3fcf672017-03-28 16:53:22 -0700262 if (!"cfg".equals(providerId.scheme()) && !"null".equals(providerId.scheme())) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800263 return null;
264 }
265 // Temporary hack for NPE (ONOS-1171).
266 // Proper fix is to implement forwarding to master on ConfigProvider
Madan Jampanibad538c2015-08-19 17:35:27 -0700267 if (dstNodeId == null) {
268 return null;
269 }
270 return Futures.getUnchecked(clusterCommunicator.sendAndReceive(new Provided<>(linkDescription, providerId),
kircaali28d67682016-04-11 15:08:14 +0000271 LINK_INJECT_MESSAGE,
272 SERIALIZER::encode,
273 SERIALIZER::decode,
274 dstNodeId));
Madan Jampanibad538c2015-08-19 17:35:27 -0700275 }
276 }
277
Ayaka Koshibe2c59acf2015-09-08 15:37:47 -0700278 private Provided<LinkKey> getProvided(LinkKey linkKey, ProviderId provId) {
279 ProviderId bpid = getBaseProviderId(linkKey);
280 if (provId == null) {
281 // The LinkService didn't know who this LinkKey belongs to.
282 // A fix is to either modify the getProvider() in LinkService classes
283 // or expose the contents of linkDescriptions to the LinkService.
284 return (bpid == null) ? null : new Provided<>(linkKey, bpid);
285 } else {
286 return new Provided<>(linkKey, provId);
287 }
288 }
289
Madan Jampanibad538c2015-08-19 17:35:27 -0700290 private LinkDescription createOrUpdateLinkInternal(LinkDescription current, LinkDescription updated) {
291 if (current != null) {
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800292 Type type;
293 if (current.type() == DIRECT && updated.type() == Type.INDIRECT) {
294 // mask transition from DIRECT -> INDIRECT, likely to be triggered by BDDP
295 type = Type.DIRECT;
296 } else {
297 type = updated.type();
298 }
kircaali28d67682016-04-11 15:08:14 +0000299 return new DefaultLinkDescription(
300 current.src(),
301 current.dst(),
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800302 type,
kircaali28d67682016-04-11 15:08:14 +0000303 current.isExpected(),
304 union(current.annotations(), updated.annotations()));
Madan Jampanibad538c2015-08-19 17:35:27 -0700305 }
306 return updated;
307 }
308
kircaali28d67682016-04-11 15:08:14 +0000309 private Set<ProviderId> createOrUpdateLinkProviders(Set<ProviderId> current, ProviderId providerId) {
310 if (current == null) {
311 current = Sets.newConcurrentHashSet();
312 }
313 current.add(providerId);
314 return current;
315 }
316
Madan Jampanibad538c2015-08-19 17:35:27 -0700317 private LinkEvent refreshLinkCache(LinkKey linkKey) {
318 AtomicReference<LinkEvent.Type> eventType = new AtomicReference<>();
319 Link link = links.compute(linkKey, (key, existingLink) -> {
320 Link newLink = composeLink(linkKey);
Madan Jampani11591862016-06-27 13:58:07 -0700321 if (newLink == null) {
322 return null;
323 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700324 if (existingLink == null) {
325 eventType.set(LINK_ADDED);
326 return newLink;
327 } else if (existingLink.state() != newLink.state() ||
kircaali28d67682016-04-11 15:08:14 +0000328 existingLink.isExpected() != newLink.isExpected() ||
Yuta HIGUCHI40197862017-02-17 11:30:15 -0800329 (existingLink.type() != newLink.type()) ||
kircaali28d67682016-04-11 15:08:14 +0000330 !AnnotationsUtil.isEqual(existingLink.annotations(), newLink.annotations())) {
331 eventType.set(LINK_UPDATED);
332 return newLink;
Madan Jampanibad538c2015-08-19 17:35:27 -0700333 } else {
334 return existingLink;
335 }
336 });
337 return eventType.get() != null ? new LinkEvent(eventType.get(), link) : null;
338 }
339
340 private Set<ProviderId> getAllProviders(LinkKey linkKey) {
kircaali28d67682016-04-11 15:08:14 +0000341 return linkProviders.getOrDefault(linkKey, Sets.newConcurrentHashSet());
Madan Jampanibad538c2015-08-19 17:35:27 -0700342 }
343
344 private ProviderId getBaseProviderId(LinkKey linkKey) {
345 Set<ProviderId> allProviders = getAllProviders(linkKey);
346 if (allProviders.size() > 0) {
347 return allProviders.stream()
kircaali28d67682016-04-11 15:08:14 +0000348 .filter(p -> !p.isAncillary())
349 .findFirst()
350 .orElse(Iterables.getFirst(allProviders, null));
Madan Jampanibad538c2015-08-19 17:35:27 -0700351 }
352 return null;
353 }
354
355 private Link composeLink(LinkKey linkKey) {
356
Ray Milkey1bce6fb2016-07-15 13:38:53 -0700357 ProviderId baseProviderId = getBaseProviderId(linkKey);
358 if (baseProviderId == null) {
359 // provider was not found, this means it was already removed by the
360 // parent component.
361 return null;
362 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700363 LinkDescription base = linkDescriptions.get(new Provided<>(linkKey, baseProviderId));
Madan Jampani11591862016-06-27 13:58:07 -0700364 // short circuit if link description no longer exists
365 if (base == null) {
366 return null;
367 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700368 ConnectPoint src = base.src();
369 ConnectPoint dst = base.dst();
370 Type type = base.type();
Yuta HIGUCHI9eed0b12017-06-07 11:59:18 -0700371 DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
372 builder.putAll(base.annotations());
Madan Jampanibad538c2015-08-19 17:35:27 -0700373
374 getAllProviders(linkKey).stream()
kircaali28d67682016-04-11 15:08:14 +0000375 .map(p -> new Provided<>(linkKey, p))
376 .forEach(key -> {
377 LinkDescription linkDescription = linkDescriptions.get(key);
378 if (linkDescription != null) {
Yuta HIGUCHI9eed0b12017-06-07 11:59:18 -0700379 builder.putAll(linkDescription.annotations());
kircaali28d67682016-04-11 15:08:14 +0000380 }
381 });
Madan Jampanibad538c2015-08-19 17:35:27 -0700382
Yuta HIGUCHI9eed0b12017-06-07 11:59:18 -0700383 DefaultAnnotations annotations = builder.build();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800384 Link.State initialLinkState;
385
386 boolean isExpected;
387 if (linkDiscoveryMode == LinkDiscoveryMode.PERMISSIVE) {
388 initialLinkState = ACTIVE;
389 isExpected =
Yuta HIGUCHI9eed0b12017-06-07 11:59:18 -0700390 Objects.equals(annotations.value(AnnotationKeys.DURABLE), "true");
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800391 } else {
392 initialLinkState = base.isExpected() ? ACTIVE : INACTIVE;
393 isExpected = base.isExpected();
394 }
395
396
Ray Milkey2693bda2016-01-22 16:08:14 -0800397 return DefaultLink.builder()
398 .providerId(baseProviderId)
399 .src(src)
400 .dst(dst)
401 .type(type)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800402 .state(initialLinkState)
403 .isExpected(isExpected)
Yuta HIGUCHI9eed0b12017-06-07 11:59:18 -0700404 .annotations(annotations)
Ray Milkey2693bda2016-01-22 16:08:14 -0800405 .build();
Madan Jampanibad538c2015-08-19 17:35:27 -0700406 }
407
408 // Updates, if necessary the specified link and returns the appropriate event.
409 // Guarded by linkDescs value (=locking each Link)
410 private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) {
411 // Note: INDIRECT -> DIRECT transition only
412 // so that BDDP discovered Link will not overwrite LDDP Link
413 if (oldLink.state() != newLink.state() ||
kircaali28d67682016-04-11 15:08:14 +0000414 (oldLink.type() == INDIRECT && newLink.type() == DIRECT) ||
415 !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) {
Madan Jampanibad538c2015-08-19 17:35:27 -0700416
417 links.put(key, newLink);
418 return new LinkEvent(LINK_UPDATED, newLink);
419 }
420 return null;
421 }
422
423 @Override
424 public LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst) {
425 Link link = getLink(src, dst);
426 if (link == null) {
427 return null;
428 }
429
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800430 if (linkDiscoveryMode == LinkDiscoveryMode.PERMISSIVE && link.isExpected()) {
Madan Jampanibad538c2015-08-19 17:35:27 -0700431 // FIXME: this will not sync link state!!!
432 return link.state() == INACTIVE ? null :
433 updateLink(linkKey(link.src(), link.dst()), link,
Ray Milkey2693bda2016-01-22 16:08:14 -0800434 DefaultLink.builder()
435 .providerId(link.providerId())
436 .src(link.src())
437 .dst(link.dst())
438 .type(link.type())
439 .state(INACTIVE)
440 .isExpected(link.isExpected())
441 .annotations(link.annotations())
442 .build());
Madan Jampanibad538c2015-08-19 17:35:27 -0700443 }
444 return removeLink(src, dst);
445 }
446
447 @Override
448 public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
449 final LinkKey linkKey = LinkKey.linkKey(src, dst);
Madan Jampani5d4396f2015-09-02 16:04:20 -0700450 ProviderId primaryProviderId = getBaseProviderId(linkKey);
451 // Stop if there is no base provider.
452 if (primaryProviderId == null) {
453 return null;
454 }
Madan Jampanibad538c2015-08-19 17:35:27 -0700455 LinkDescription removedLinkDescription =
Madan Jampani5d4396f2015-09-02 16:04:20 -0700456 linkDescriptions.remove(new Provided<>(linkKey, primaryProviderId));
Madan Jampanibad538c2015-08-19 17:35:27 -0700457 if (removedLinkDescription != null) {
458 return purgeLinkCache(linkKey);
459 }
460 return null;
461 }
462
463 private LinkEvent purgeLinkCache(LinkKey linkKey) {
464 Link removedLink = links.remove(linkKey);
465 if (removedLink != null) {
466 getAllProviders(linkKey).forEach(p -> linkDescriptions.remove(new Provided<>(linkKey, p)));
kircaali28d67682016-04-11 15:08:14 +0000467 linkProviders.remove(linkKey);
Madan Jampanibad538c2015-08-19 17:35:27 -0700468 return new LinkEvent(LINK_REMOVED, removedLink);
469 }
470 return null;
471 }
472
473 private Set<Link> filter(Collection<Link> links, Predicate<Link> predicate) {
474 return links.stream().filter(predicate).collect(Collectors.toSet());
475 }
476
477 private LinkEvent injectLink(Provided<LinkDescription> linkInjectRequest) {
478 log.trace("Received request to inject link {}", linkInjectRequest);
479
480 ProviderId providerId = linkInjectRequest.providerId();
481 LinkDescription linkDescription = linkInjectRequest.key();
482
483 final DeviceId deviceId = linkDescription.dst().deviceId();
484 if (!deviceClockService.isTimestampAvailable(deviceId)) {
485 // workaround for ONOS-1208
486 log.warn("Not ready to accept update. Dropping {}", linkInjectRequest);
487 return null;
488 }
489 return createOrUpdateLink(providerId, linkDescription);
490 }
491
492 private class InternalLinkTracker implements EventuallyConsistentMapListener<Provided<LinkKey>, LinkDescription> {
493 @Override
494 public void event(EventuallyConsistentMapEvent<Provided<LinkKey>, LinkDescription> event) {
495 if (event.type() == PUT) {
kircaali28d67682016-04-11 15:08:14 +0000496 linkProviders.compute(event.key().key(), (k, v) ->
497 createOrUpdateLinkProviders(v, event.key().providerId()));
Madan Jampanibad538c2015-08-19 17:35:27 -0700498 notifyDelegate(refreshLinkCache(event.key().key()));
499 } else if (event.type() == REMOVE) {
500 notifyDelegate(purgeLinkCache(event.key().key()));
kircaali28d67682016-04-11 15:08:14 +0000501 linkProviders.remove(event.key().key());
Madan Jampanibad538c2015-08-19 17:35:27 -0700502 }
503 }
504 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800505
506 private class InternalConfigListener implements NetworkConfigListener {
507
508 void reconfigure(CoreConfig coreConfig) {
509 if (coreConfig == null) {
510 linkDiscoveryMode = LinkDiscoveryMode.PERMISSIVE;
511 } else {
512 linkDiscoveryMode = coreConfig.linkDiscoveryMode();
513 }
514 if (linkDiscoveryMode == LinkDiscoveryMode.STRICT) {
515 // Remove any previous links to force them to go through the strict
516 // discovery process
Ray Milkey15551272016-02-10 16:22:02 -0800517 if (linkDescriptions != null) {
518 linkDescriptions.clear();
519 }
520 if (links != null) {
521 links.clear();
522 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800523 }
524 log.debug("config set link discovery mode to {}",
525 linkDiscoveryMode.name());
526 }
527
528 @Override
529 public void event(NetworkConfigEvent event) {
530
531 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
532 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
533 event.configClass().equals(CoreConfig.class)) {
534
535 CoreConfig cfg = netCfgService.getConfig(appId, CoreConfig.class);
536 reconfigure(cfg);
537 log.info("Reconfigured");
538 }
539 }
540 }
541
542 // Configuration properties factory
543 private final ConfigFactory factory =
544 new ConfigFactory<ApplicationId, CoreConfig>(APP_SUBJECT_FACTORY,
kircaali28d67682016-04-11 15:08:14 +0000545 CoreConfig.class,
546 "core") {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800547 @Override
548 public CoreConfig createConfig() {
549 return new CoreConfig();
550 }
551 };
Ray Milkeyd0dd1352016-01-19 10:58:41 -0800552}