blob: b1316f60f042d3c83fbe1171ee778f2e7b812a5d [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.link.impl;
tomdb0d03f2014-08-27 16:34:15 -070017
Simon Huntff663742015-05-14 13:33:05 -070018import com.google.common.base.Predicate;
19import com.google.common.collect.FluentIterable;
20import com.google.common.collect.Sets;
tomdb0d03f2014-08-27 16:34:15 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
tom5f38b3a2014-08-27 23:50:54 -070024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
tomdb0d03f2014-08-27 16:34:15 -070026import org.apache.felix.scr.annotations.Service;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070027import org.onosproject.net.provider.AbstractListenerProviderRegistry;
Changhoon Yoon541ef712015-05-23 17:18:34 +090028import org.onosproject.core.Permission;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070029import org.onosproject.incubator.net.config.NetworkConfigEvent;
30import org.onosproject.incubator.net.config.NetworkConfigListener;
31import org.onosproject.incubator.net.config.NetworkConfigService;
32import org.onosproject.incubator.net.config.basics.BasicLinkConfig;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.ConnectPoint;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070034import org.onosproject.net.DefaultAnnotations;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.DeviceId;
36import org.onosproject.net.Link;
37import org.onosproject.net.Link.State;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070038import org.onosproject.net.LinkKey;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.MastershipRole;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070040import org.onosproject.net.SparseAnnotations;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.device.DeviceService;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070044import org.onosproject.net.link.DefaultLinkDescription;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.link.LinkAdminService;
46import org.onosproject.net.link.LinkDescription;
47import org.onosproject.net.link.LinkEvent;
48import org.onosproject.net.link.LinkListener;
49import org.onosproject.net.link.LinkProvider;
50import org.onosproject.net.link.LinkProviderRegistry;
51import org.onosproject.net.link.LinkProviderService;
52import org.onosproject.net.link.LinkService;
53import org.onosproject.net.link.LinkStore;
54import org.onosproject.net.link.LinkStoreDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080055import org.onosproject.net.provider.AbstractProviderService;
tomdb0d03f2014-08-27 16:34:15 -070056import org.slf4j.Logger;
tom5f38b3a2014-08-27 23:50:54 -070057
Sahil Lele3a0cdd52015-07-21 14:16:31 -070058import java.time.Duration;
Simon Huntff663742015-05-14 13:33:05 -070059import java.util.Set;
tomdb0d03f2014-08-27 16:34:15 -070060
Ray Milkey7bbeb3f2014-12-11 14:59:26 -080061import static com.google.common.base.Preconditions.checkNotNull;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070062import static com.google.common.base.Preconditions.checkState;
63import static org.onosproject.net.LinkKey.linkKey;
Changhoon Yoon541ef712015-05-23 17:18:34 +090064import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070065import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoon541ef712015-05-23 17:18:34 +090066
Ray Milkey7bbeb3f2014-12-11 14:59:26 -080067
tomdb0d03f2014-08-27 16:34:15 -070068/**
69 * Provides basic implementation of the link SB & NB APIs.
70 */
71@Component(immediate = true)
72@Service
tom35c0dc32014-09-19 10:00:58 -070073public class LinkManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070074 extends AbstractListenerProviderRegistry<LinkEvent, LinkListener, LinkProvider, LinkProviderService>
tomdc361b62014-09-09 20:36:52 -070075 implements LinkService, LinkAdminService, LinkProviderRegistry {
tomeadbb462014-09-07 16:10:19 -070076
77 private static final String DEVICE_ID_NULL = "Device ID cannot be null";
78 private static final String LINK_DESC_NULL = "Link description cannot be null";
79 private static final String CONNECT_POINT_NULL = "Connection point cannot be null";
tomdb0d03f2014-08-27 16:34:15 -070080
tom5f38b3a2014-08-27 23:50:54 -070081 private final Logger log = getLogger(getClass());
tomdb0d03f2014-08-27 16:34:15 -070082
alshabibb5522ff2014-09-29 19:20:00 -070083 private final LinkStoreDelegate delegate = new InternalStoreDelegate();
tomc78acee2014-09-24 15:16:55 -070084
85 private final DeviceListener deviceListener = new InternalDeviceListener();
tom89b63c52014-09-16 09:19:51 -070086
Sahil Lele3a0cdd52015-07-21 14:16:31 -070087 private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
88
tom89b63c52014-09-16 09:19:51 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom35c0dc32014-09-19 10:00:58 -070090 protected LinkStore store;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom89b63c52014-09-16 09:19:51 -070093 protected DeviceService deviceService;
tom4c6606f2014-09-07 11:11:21 -070094
tom5f38b3a2014-08-27 23:50:54 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sahil Lele3a0cdd52015-07-21 14:16:31 -070096 protected NetworkConfigService networkConfigService;
97
tomdb0d03f2014-08-27 16:34:15 -070098 @Activate
99 public void activate() {
tomc78acee2014-09-24 15:16:55 -0700100 store.setDelegate(delegate);
tom96dfcab2014-08-28 09:26:03 -0700101 eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
tom89b63c52014-09-16 09:19:51 -0700102 deviceService.addListener(deviceListener);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700103 networkConfigService.addListener(networkConfigListener);
tomdb0d03f2014-08-27 16:34:15 -0700104 log.info("Started");
105 }
106
107 @Deactivate
108 public void deactivate() {
tomc78acee2014-09-24 15:16:55 -0700109 store.unsetDelegate(delegate);
tom5f38b3a2014-08-27 23:50:54 -0700110 eventDispatcher.removeSink(LinkEvent.class);
tom89b63c52014-09-16 09:19:51 -0700111 deviceService.removeListener(deviceListener);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700112 networkConfigService.removeListener(networkConfigListener);
tomdb0d03f2014-08-27 16:34:15 -0700113 log.info("Stopped");
114 }
115
116 @Override
tomeadbb462014-09-07 16:10:19 -0700117 public int getLinkCount() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900118 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700119 return store.getLinkCount();
120 }
121
122 @Override
123 public Iterable<Link> getLinks() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900124 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700125 return store.getLinks();
126 }
127
128 @Override
Yuta HIGUCHIf1f2ac02014-11-26 14:02:22 -0800129 public Iterable<Link> getActiveLinks() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900130 checkPermission(Permission.LINK_READ);
Yuta HIGUCHIf1f2ac02014-11-26 14:02:22 -0800131 return FluentIterable.from(getLinks())
132 .filter(new Predicate<Link>() {
133
134 @Override
135 public boolean apply(Link input) {
136 return input.state() == State.ACTIVE;
137 }
138 });
139 }
140
141 @Override
tomeadbb462014-09-07 16:10:19 -0700142 public Set<Link> getDeviceLinks(DeviceId deviceId) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900143 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700144 checkNotNull(deviceId, DEVICE_ID_NULL);
145 return Sets.union(store.getDeviceEgressLinks(deviceId),
tomdc361b62014-09-09 20:36:52 -0700146 store.getDeviceIngressLinks(deviceId));
tomeadbb462014-09-07 16:10:19 -0700147 }
148
149 @Override
150 public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900151 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700152 checkNotNull(deviceId, DEVICE_ID_NULL);
153 return store.getDeviceEgressLinks(deviceId);
154 }
155
156 @Override
tomd176fc42014-09-08 00:12:30 -0700157 public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900158 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700159 checkNotNull(deviceId, DEVICE_ID_NULL);
160 return store.getDeviceIngressLinks(deviceId);
161 }
162
163 @Override
164 public Set<Link> getLinks(ConnectPoint connectPoint) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900165 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700166 checkNotNull(connectPoint, CONNECT_POINT_NULL);
167 return Sets.union(store.getEgressLinks(connectPoint),
tomdc361b62014-09-09 20:36:52 -0700168 store.getIngressLinks(connectPoint));
tomeadbb462014-09-07 16:10:19 -0700169 }
170
171 @Override
172 public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900173 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700174 checkNotNull(connectPoint, CONNECT_POINT_NULL);
175 return store.getEgressLinks(connectPoint);
176 }
177
178 @Override
tomd176fc42014-09-08 00:12:30 -0700179 public Set<Link> getIngressLinks(ConnectPoint connectPoint) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900180 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700181 checkNotNull(connectPoint, CONNECT_POINT_NULL);
182 return store.getIngressLinks(connectPoint);
183 }
184
185 @Override
tomd176fc42014-09-08 00:12:30 -0700186 public Link getLink(ConnectPoint src, ConnectPoint dst) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900187 checkPermission(Permission.LINK_READ);
tomeadbb462014-09-07 16:10:19 -0700188 checkNotNull(src, CONNECT_POINT_NULL);
189 checkNotNull(dst, CONNECT_POINT_NULL);
tomd176fc42014-09-08 00:12:30 -0700190 return store.getLink(src, dst);
tomeadbb462014-09-07 16:10:19 -0700191 }
192
193 @Override
194 public void removeLinks(ConnectPoint connectPoint) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700195 if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) {
196 return;
197 }
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800198 removeLinks(getLinks(connectPoint), false);
tomeadbb462014-09-07 16:10:19 -0700199 }
200
201 @Override
202 public void removeLinks(DeviceId deviceId) {
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700203 if (deviceService.getRole(deviceId) != MastershipRole.MASTER) {
204 return;
205 }
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800206 removeLinks(getDeviceLinks(deviceId), false);
tomeadbb462014-09-07 16:10:19 -0700207 }
208
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700209 public void removeLink(ConnectPoint src, ConnectPoint dst) {
210 post(store.removeLink(src, dst));
211 }
212
tom89b63c52014-09-16 09:19:51 -0700213 // Auxiliary interceptor for device remove events to prune links that
214 // are associated with the removed device or its port.
tomc78acee2014-09-24 15:16:55 -0700215 private class InternalDeviceListener implements DeviceListener {
tom89b63c52014-09-16 09:19:51 -0700216 @Override
217 public void event(DeviceEvent event) {
218 if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) {
219 removeLinks(event.subject().id());
220 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
221 removeLinks(new ConnectPoint(event.subject().id(),
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700222 event.port().number()));
tom89b63c52014-09-16 09:19:51 -0700223 }
224 }
225 }
226
tom7869ad92014-09-09 14:32:08 -0700227 @Override
228 protected LinkProviderService createProviderService(LinkProvider provider) {
229 return new InternalLinkProviderService(provider);
230 }
231
tomdb0d03f2014-08-27 16:34:15 -0700232 // Personalized link provider service issued to the supplied provider.
tomdc361b62014-09-09 20:36:52 -0700233 private class InternalLinkProviderService
234 extends AbstractProviderService<LinkProvider>
235 implements LinkProviderService {
tomdb0d03f2014-08-27 16:34:15 -0700236
tomcfde0622014-09-09 11:02:42 -0700237 InternalLinkProviderService(LinkProvider provider) {
tomdb0d03f2014-08-27 16:34:15 -0700238 super(provider);
239 }
240
241 @Override
242 public void linkDetected(LinkDescription linkDescription) {
tomeadbb462014-09-07 16:10:19 -0700243 checkNotNull(linkDescription, LINK_DESC_NULL);
244 checkValidity();
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700245 linkDescription = validateLink(linkDescription);
tomeadbb462014-09-07 16:10:19 -0700246 LinkEvent event = store.createOrUpdateLink(provider().id(),
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700247 linkDescription);
tomdc361b62014-09-09 20:36:52 -0700248 if (event != null) {
Thomas Vachuska0e752bd2014-10-22 22:33:41 -0700249 log.info("Link {} detected", linkDescription);
tomdc361b62014-09-09 20:36:52 -0700250 post(event);
251 }
tomdb0d03f2014-08-27 16:34:15 -0700252 }
253
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700254 // returns a LinkDescription made from the union of the BasicLinkConfig
255 // annotations if it exists
256 private LinkDescription validateLink(LinkDescription linkDescription) {
257 // TODO Investigate whether this can be made more efficient
258 BasicLinkConfig cfg = networkConfigService.getConfig(linkKey(linkDescription.src(),
259 linkDescription.dst()),
260 BasicLinkConfig.class);
261 BasicLinkConfig cfgTwo = networkConfigService.getConfig(linkKey(linkDescription.dst(),
262 linkDescription.src()),
263 BasicLinkConfig.class);
264
265 checkState(cfg == null || cfg.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
266 checkState(cfgTwo == null || cfgTwo.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
267 if (cfg != null) {
268 SparseAnnotations finalSparse = processAnnotations(cfg, linkDescription);
269 // check whether config has a specified type
270 if (cfg.type() != Link.Type.DIRECT) {
271 linkDescription = new DefaultLinkDescription(linkDescription.src(),
272 linkDescription.dst(),
273 cfg.type(), finalSparse);
274 } else {
275 linkDescription = new DefaultLinkDescription(linkDescription.src(),
276 linkDescription.dst(),
277 linkDescription.type(), finalSparse);
278 }
279 }
280 return linkDescription;
281 }
282
283 // supplements or replaces linkDescriptions's annotations with BasicLinkConfig's
284 // annotations
285 private SparseAnnotations processAnnotations(BasicLinkConfig cfg, LinkDescription linkDescription) {
286 SparseAnnotations originalAnnotations = linkDescription.annotations();
287 DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
288 if (cfg.type() != Link.Type.DIRECT) {
289 newBuilder.set(cfg.TYPE, cfg.type().toString());
290 }
291 if (cfg.latency() != Duration.ofNanos(-1)) {
292 newBuilder.set(cfg.LATENCY, cfg.latency().toString());
293 }
294 if (cfg.bandwidth() != -1) {
295 newBuilder.set(cfg.BANDWIDTH, String.valueOf(cfg.bandwidth()));
296 }
297 DefaultAnnotations newAnnotations = newBuilder.build();
298 return DefaultAnnotations.union(originalAnnotations, newAnnotations);
299 }
300
tomdb0d03f2014-08-27 16:34:15 -0700301 @Override
302 public void linkVanished(LinkDescription linkDescription) {
tomeadbb462014-09-07 16:10:19 -0700303 checkNotNull(linkDescription, LINK_DESC_NULL);
304 checkValidity();
Ayaka Koshibeb5c63a02014-10-18 18:42:27 -0700305
306 ConnectPoint src = linkDescription.src();
307 ConnectPoint dst = linkDescription.dst();
alshabibdfc7afb2014-10-21 20:13:27 -0700308
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800309 LinkEvent event = store.removeOrDownLink(src, dst);
tomdc361b62014-09-09 20:36:52 -0700310 if (event != null) {
311 log.info("Link {} vanished", linkDescription);
312 post(event);
313 }
tomeadbb462014-09-07 16:10:19 -0700314 }
315
316 @Override
317 public void linksVanished(ConnectPoint connectPoint) {
318 checkNotNull(connectPoint, "Connect point cannot be null");
319 checkValidity();
alshabib12288c82014-10-23 10:24:23 -0700320
Yuta HIGUCHIddb77722014-12-11 19:39:04 -0800321 log.debug("Links for connection point {} vanished", connectPoint);
Yuta HIGUCHIe794cbe2014-10-17 13:21:23 -0700322 // FIXME: This will remove links registered by other providers
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800323 removeLinks(getLinks(connectPoint), true);
tomeadbb462014-09-07 16:10:19 -0700324 }
325
326 @Override
327 public void linksVanished(DeviceId deviceId) {
328 checkNotNull(deviceId, DEVICE_ID_NULL);
329 checkValidity();
alshabib12288c82014-10-23 10:24:23 -0700330
Yuta HIGUCHIddb77722014-12-11 19:39:04 -0800331 log.debug("Links for device {} vanished", deviceId);
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800332 removeLinks(getDeviceLinks(deviceId), true);
tomdb0d03f2014-08-27 16:34:15 -0700333 }
334 }
tomeadbb462014-09-07 16:10:19 -0700335
336 // Removes all links in the specified set and emits appropriate events.
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700337 private void removeLinks(Set<Link> links, boolean isSoftRemove) {
tomeadbb462014-09-07 16:10:19 -0700338 for (Link link : links) {
Thomas Vachuska57126fe2014-11-11 17:13:24 -0800339 LinkEvent event = isSoftRemove ?
340 store.removeOrDownLink(link.src(), link.dst()) :
341 store.removeLink(link.src(), link.dst());
Yuta HIGUCHIddb77722014-12-11 19:39:04 -0800342 if (event != null) {
343 log.info("Link {} removed/vanished", event.subject());
344 post(event);
345 }
tomeadbb462014-09-07 16:10:19 -0700346 }
347 }
348
tomc78acee2014-09-24 15:16:55 -0700349 // Store delegate to re-post events emitted from the store.
350 private class InternalStoreDelegate implements LinkStoreDelegate {
351 @Override
352 public void notify(LinkEvent event) {
353 post(event);
354 }
355 }
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700356
357 // listens for NetworkConfigEvents of type BasicLinkConfig and removes
358 // links that the config does not allow
359 private class InternalNetworkConfigListener implements NetworkConfigListener {
360 @Override
361 public void event(NetworkConfigEvent event) {
362 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
363 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
364 event.configClass().equals(BasicLinkConfig.class)) {
365 log.info("Detected Link network config event {}", event.type());
366 LinkKey lk = (LinkKey) event.subject();
367 BasicLinkConfig cfg = networkConfigService.getConfig(lk, BasicLinkConfig.class);
368 if (cfg != null && !cfg.isAllowed()) {
369 log.info("Kicking out links between {} and {}", lk.src(), lk.dst());
370 removeLink(lk.src(), lk.dst());
371 removeLink(lk.dst(), lk.src());
372 }
373 }
374 }
375 }
tomdb0d03f2014-08-27 16:34:15 -0700376}