Michele Santuari
Committed by Gerrit Code Review

Polling link provider

    The provider is capable of polling the environment using the
    device driver behaviour (LinkDiscovery)

Change-Id: Ia09f866299d38c4de9b13201c9cf63b03909164a
1 +/*
2 + * Copyright 2016-present 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 + */
16 +
17 +package org.onosproject.net.behaviour;
18 +
19 +import org.onosproject.net.driver.HandlerBehaviour;
20 +import org.onosproject.net.link.LinkDescription;
21 +
22 +import java.util.Set;
23 +
24 +/**
25 + * A HandlerBehaviour to discover links.
26 + */
27 +public interface LinkDiscovery extends HandlerBehaviour {
28 +
29 +
30 + /**
31 + * Returns set of discovered {@link LinkDescription}.
32 + * @return set of LinkDescription.
33 + */
34 + Set<LinkDescription> getLinks();
35 +}
...\ No newline at end of file ...\ No newline at end of file
1 +COMPILE_DEPS = [
2 + '//lib:CORE_DEPS',
3 +]
4 +
5 +TEST_DEPS = [
6 + '//lib:TEST_ADAPTERS',
7 + '//utils/osgi:onlab-osgi-tests',
8 +]
9 +
10 +osgi_jar_with_tests (
11 + deps = COMPILE_DEPS,
12 + test_deps = TEST_DEPS,
13 +)
14 +
15 +onos_app (
16 + app_name = 'org.onosproject.linkdiscovery',
17 + title = 'Link Discovery Provider',
18 + category = 'Provider',
19 + url = 'http://onosproject.org',
20 + description = 'ONOS link discovery provider.',
21 +)
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +
3 +<!--
4 + ~ Copyright 2016-present Open Networking Laboratory
5 + ~
6 + ~ Licensed under the Apache License, Version 2.0 (the "License");
7 + ~ you may not use this file except in compliance with the License.
8 + ~ You may obtain a copy of the License at
9 + ~
10 + ~ http://www.apache.org/licenses/LICENSE-2.0
11 + ~
12 + ~ Unless required by applicable law or agreed to in writing, software
13 + ~ distributed under the License is distributed on an "AS IS" BASIS,
14 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + ~ See the License for the specific language governing permissions and
16 + ~ limitations under the License.
17 + -->
18 +<app name="org.onosproject.linkdiscovery" origin="acino.eu" version="${project.version}"
19 + category="Provider" url="http://onosproject.org" title="ONOS link discovery provider"
20 + featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
21 + features="${project.artifactId}">
22 + <description>${project.description}</description>
23 + <artifact>mvn:${project.groupId}/onos-linkdiscovery-provider/${project.version}</artifact>
24 +</app>
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +
3 +<!--
4 + ~ Copyright 2016-present Open Networking Laboratory
5 + ~
6 + ~ Licensed under the Apache License, Version 2.0 (the "License");
7 + ~ you may not use this file except in compliance with the License.
8 + ~ You may obtain a copy of the License at
9 + ~
10 + ~ http://www.apache.org/licenses/LICENSE-2.0
11 + ~
12 + ~ Unless required by applicable law or agreed to in writing, software
13 + ~ distributed under the License is distributed on an "AS IS" BASIS,
14 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + ~ See the License for the specific language governing permissions and
16 + ~ limitations under the License.
17 + --><features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
18 + <feature name="${project.artifactId}" version="${project.version}"
19 + description="${project.description}">
20 + <feature>onos-api</feature>
21 + <bundle>mvn:${project.groupId}/onos-linkdiscovery-provider/${project.version}</bundle>
22 + </feature>
23 +</features>
24 +
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
21 + <modelVersion>4.0.0</modelVersion>
22 +
23 + <parent>
24 + <groupId>org.onosproject</groupId>
25 + <artifactId>onos-providers</artifactId>
26 + <version>1.7.0-SNAPSHOT</version>
27 + </parent>
28 +
29 +
30 + <artifactId>onos-linkdiscovery-provider</artifactId>
31 + <packaging>bundle</packaging>
32 +
33 + <properties>
34 + <onos.app.name>org.onosproject.linkdiscovery</onos.app.name>
35 + <onos.app.title>Link Discovery Provider</onos.app.title>
36 + <onos.app.origin>acino.eu</onos.app.origin>
37 + <onos.app.category>Provider</onos.app.category>
38 + <onos.app.readme>ONOS link discovery provider.</onos.app.readme>
39 + </properties>
40 +
41 + <description>ONOS link discovery provider</description>
42 +
43 + <dependencies>
44 + <dependency>
45 + <groupId>org.osgi</groupId>
46 + <artifactId>org.osgi.compendium</artifactId>
47 + </dependency>
48 + <dependency>
49 + <groupId>org.onosproject</groupId>
50 + <artifactId>onlab-osgi</artifactId>
51 + <version>${project.version}</version>
52 + <classifier>tests</classifier>
53 + <scope>test</scope>
54 + </dependency>
55 + <dependency>
56 + <groupId>org.onosproject</groupId>
57 + <artifactId>onlab-junit</artifactId>
58 + <scope>test</scope>
59 + </dependency>
60 + <dependency>
61 + <groupId>org.easymock</groupId>
62 + <artifactId>easymock</artifactId>
63 + <scope>test</scope>
64 + </dependency>
65 + <dependency>
66 + <groupId>org.onosproject</groupId>
67 + <artifactId>onos-api</artifactId>
68 + <classifier>tests</classifier>
69 + <scope>test</scope>
70 + </dependency>
71 + </dependencies>
72 +
73 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016-present 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 + */
16 +
17 +package org.onosproject.provider.linkdiscovery.impl;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Modified;
23 +import org.apache.felix.scr.annotations.Property;
24 +import org.apache.felix.scr.annotations.Reference;
25 +import org.apache.felix.scr.annotations.ReferenceCardinality;
26 +import org.onosproject.cfg.ComponentConfigService;
27 +import org.onosproject.core.ApplicationId;
28 +import org.onosproject.core.CoreService;
29 +import org.onosproject.mastership.MastershipService;
30 +import org.onosproject.net.AnnotationKeys;
31 +import org.onosproject.net.DefaultAnnotations;
32 +import org.onosproject.net.Device;
33 +import org.onosproject.net.DeviceId;
34 +import org.onosproject.net.Link;
35 +import org.onosproject.net.behaviour.LinkDiscovery;
36 +import org.onosproject.net.device.DeviceEvent;
37 +import org.onosproject.net.device.DeviceListener;
38 +import org.onosproject.net.device.DeviceService;
39 +import org.onosproject.net.link.DefaultLinkDescription;
40 +import org.onosproject.net.link.LinkDescription;
41 +import org.onosproject.net.link.LinkProvider;
42 +import org.onosproject.net.link.LinkProviderRegistry;
43 +import org.onosproject.net.link.LinkProviderService;
44 +import org.onosproject.net.link.LinkService;
45 +import org.onosproject.net.provider.AbstractProvider;
46 +import org.onosproject.net.provider.ProviderId;
47 +import org.osgi.service.component.ComponentContext;
48 +import org.slf4j.Logger;
49 +
50 +import java.util.Dictionary;
51 +import java.util.HashSet;
52 +import java.util.Set;
53 +import java.util.concurrent.ScheduledExecutorService;
54 +import java.util.concurrent.ScheduledFuture;
55 +import java.util.stream.Collectors;
56 +
57 +import static com.google.common.base.Strings.isNullOrEmpty;
58 +import static java.util.concurrent.Executors.newScheduledThreadPool;
59 +import static java.util.concurrent.TimeUnit.SECONDS;
60 +import static org.onlab.util.Tools.get;
61 +import static org.onlab.util.Tools.groupedThreads;
62 +import static org.slf4j.LoggerFactory.getLogger;
63 +
64 +/**
65 + * Link provider capable of polling the environment using the device driver
66 + * {@link LinkDiscovery} behaviour.
67 + */
68 +@Component(immediate = true)
69 +public class LinkDiscoveryProvider extends AbstractProvider
70 + implements LinkProvider {
71 +
72 + protected static final String APP_NAME = "org.onosproject.linkdiscovery";
73 + protected static final String SCHEME_NAME = "linkdiscovery";
74 + private static final String LINK_PROVIDER_PACKAGE = "org.onosproject.provider.linkdiscovery";
75 + private final Logger log = getLogger(getClass());
76 + private static final int DEFAULT_POLL_DELAY_SECONDS = 20;
77 + @Property(name = "linkPollDelaySeconds", intValue = DEFAULT_POLL_DELAY_SECONDS,
78 + label = "Initial delay (in seconds) for polling link discovery")
79 + protected static int linkPollDelaySeconds = DEFAULT_POLL_DELAY_SECONDS;
80 + private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 10;
81 + @Property(name = "linkPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
82 + label = "Frequency (in seconds) for polling link discovery")
83 + protected static int linkPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
84 +
85 +
86 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 + protected LinkProviderRegistry providerRegistry;
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected CoreService coreService;
90 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 + protected LinkService linkService;
92 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 + protected MastershipService mastershipService;
94 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 + protected DeviceService deviceService;
96 + protected ScheduledExecutorService executor =
97 + newScheduledThreadPool(2, groupedThreads("onos/netconf-link",
98 + "discovery-%d"));
99 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 + protected ComponentConfigService cfgService;
101 +
102 + protected LinkProviderService providerService;
103 + private InternalDeviceListener deviceListener = new InternalDeviceListener();
104 + private ApplicationId appId;
105 + private ScheduledFuture<?> scheduledTask;
106 +
107 + /**
108 + * Creates a provider with the supplied identifier.
109 + */
110 + public LinkDiscoveryProvider() {
111 + super(new ProviderId(SCHEME_NAME, LINK_PROVIDER_PACKAGE));
112 + }
113 +
114 + @Activate
115 + public void activate(ComponentContext context) {
116 + providerService = providerRegistry.register(this);
117 + appId = coreService.registerApplication(APP_NAME);
118 + deviceService.addListener(deviceListener);
119 + cfgService.registerProperties(getClass());
120 +
121 + if (context == null) {
122 + linkPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
123 + log.info("No component configuration");
124 + } else {
125 + Dictionary<?, ?> properties = context.getProperties();
126 + linkPollFrequencySeconds =
127 + getNewPollFrequency(properties, linkPollFrequencySeconds);
128 + }
129 + scheduledTask = schedulePolling();
130 + log.info("Started");
131 + }
132 +
133 + @Deactivate
134 + public void deactivate() {
135 + cfgService.unregisterProperties(getClass(), false);
136 + deviceService.removeListener(deviceListener);
137 + providerRegistry.unregister(this);
138 + providerService = null;
139 + scheduledTask.cancel(true);
140 + executor.shutdown();
141 + log.info("Stopped");
142 + }
143 +
144 + @Modified
145 + public void modified(ComponentContext context) {
146 + if (context == null) {
147 + log.info("No component configuration");
148 + return;
149 + } else {
150 + Dictionary<?, ?> properties = context.getProperties();
151 +
152 + int newPollFrequency = getNewPollFrequency(properties, linkPollFrequencySeconds);
153 + int newPollDelay = getNewPollDealy(properties, linkPollDelaySeconds);
154 + if (newPollFrequency != linkPollFrequencySeconds ||
155 + newPollDelay != linkPollDelaySeconds) {
156 + linkPollFrequencySeconds = newPollFrequency;
157 + linkPollDelaySeconds = newPollDelay;
158 + //stops the old scheduled task
159 + scheduledTask.cancel(true);
160 + //schedules new task at the new polling rate
161 + scheduledTask = schedulePolling();
162 + }
163 + }
164 + log.info("Modified");
165 + }
166 +
167 + private int getNewPollFrequency(Dictionary<?, ?> properties, int pollFrequency) {
168 + int newPollFrequency;
169 + try {
170 + String s = get(properties, "linkPollFrequencySeconds");
171 + newPollFrequency = isNullOrEmpty(s) ? pollFrequency : Integer.parseInt(s.trim());
172 + } catch (NumberFormatException | ClassCastException e) {
173 + newPollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
174 + }
175 + return newPollFrequency;
176 + }
177 +
178 + private int getNewPollDealy(Dictionary<?, ?> properties, int pollDelay) {
179 + int newPollFrequency;
180 + try {
181 + String s = get(properties, "linkPollDelaySeconds");
182 + newPollFrequency = isNullOrEmpty(s) ? pollDelay : Integer.parseInt(s.trim());
183 + } catch (NumberFormatException | ClassCastException e) {
184 + newPollFrequency = DEFAULT_POLL_DELAY_SECONDS;
185 + }
186 + return newPollFrequency;
187 + }
188 +
189 + private ScheduledFuture schedulePolling() {
190 + return executor.scheduleAtFixedRate(this::discoverLinksTasks,
191 + linkPollDelaySeconds,
192 + linkPollFrequencySeconds,
193 + SECONDS);
194 + }
195 +
196 + private void discoverLinksTasks() {
197 + deviceService.getAvailableDevices().forEach(device -> {
198 + if (isSupported(device)) {
199 + evaluateLinks(device.id(), device.as(LinkDiscovery.class).getLinks());
200 + }
201 + });
202 + }
203 +
204 + private void evaluateLinks(DeviceId deviceId, Set<LinkDescription> discoveredLinksDesc) {
205 + //The provider will get only existing links related to LinkDiscovery
206 + Set<Link> storedLinks = linkService.getDeviceEgressLinks(deviceId)
207 + .stream()
208 + .filter(link -> {
209 + String value = link.annotations().value(AnnotationKeys.PROTOCOL);
210 + if (value != null && value.equals(SCHEME_NAME.toUpperCase())) {
211 + return true;
212 + }
213 + return false;
214 + })
215 + .collect(Collectors.toSet());
216 +
217 + //Convert Link to LinkDescription for comparison
218 + Set<LinkDescription> storedLinkDescs = new HashSet<>();
219 + storedLinks.forEach(link -> storedLinkDescs
220 + .add(new DefaultLinkDescription(
221 + link.src(), link.dst(), link.type(), link.isExpected(),
222 + DefaultAnnotations.builder().putAll(link.annotations()).build())));
223 + log.debug("Current stored links provider related {}", storedLinks);
224 +
225 + //Add the correct annotation for comparison
226 + Set<LinkDescription> discoveredLinkDescsAnn = new HashSet<>();
227 +
228 + discoveredLinksDesc.forEach(linkDesc -> discoveredLinkDescsAnn
229 + .add(new DefaultLinkDescription(
230 + linkDesc.src(), linkDesc.dst(), linkDesc.type(), false,
231 + DefaultAnnotations.builder().putAll(linkDesc.annotations())
232 + .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
233 + .build())));
234 +
235 + Set<LinkDescription> linkDescsToBeRemoved = new HashSet<>(storedLinkDescs);
236 + linkDescsToBeRemoved.removeAll(discoveredLinkDescsAnn);
237 + log.debug("Links to be removed {}", linkDescsToBeRemoved);
238 + linkDescsToBeRemoved.forEach(linkDesc ->
239 + providerService.linkVanished(linkDesc));
240 +
241 + Set<LinkDescription> linksToBeAdded = new HashSet<>(discoveredLinkDescsAnn);
242 + linksToBeAdded.removeAll(storedLinkDescs);
243 + log.debug("Links to be added {}", linksToBeAdded);
244 + linksToBeAdded.forEach(linkDesc -> providerService.linkDetected(linkDesc)
245 + );
246 + }
247 +
248 + protected boolean isSupported(Device device) {
249 + boolean supported = mastershipService.isLocalMaster(device.id())
250 + && device.is(LinkDiscovery.class);
251 + if (!supported) {
252 + log.debug("Device {} does not support LinkDiscovery", device);
253 + }
254 + return supported;
255 + }
256 +
257 + /**
258 + * Listener for core device events.
259 + */
260 + private class InternalDeviceListener implements DeviceListener {
261 + @Override
262 + public void event(DeviceEvent event) {
263 + if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
264 + executor.execute(() -> event.subject().as(LinkDiscovery.class).getLinks()
265 + .forEach(linkDesc -> {
266 + providerService.linkDetected(new DefaultLinkDescription(
267 + linkDesc.src(), linkDesc.dst(), linkDesc.type(), false,
268 + DefaultAnnotations.builder()
269 + .putAll(linkDesc.annotations())
270 + .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
271 + .build()));
272 + }));
273 + }
274 + }
275 +
276 + @Override
277 + public boolean isRelevant(DeviceEvent event) {
278 + return isSupported(event.subject());
279 + }
280 + }
281 +}
1 +/*
2 + * Copyright 2016-present 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 + */
16 +
17 +/**
18 + * Provider that uses LinkDiscovery {@link org.onosproject.net.behaviour.LinkDiscovery}
19 + * to poll the network environment as a means of link discovery.
20 + */
21 +package org.onosproject.provider.linkdiscovery.impl;
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016-present 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 + */
16 +package org.onosproject.provider.linkdiscovery.impl;
17 +
18 +import com.google.common.collect.ImmutableSet;
19 +import org.junit.Before;
20 +import org.junit.Test;
21 +import org.onlab.osgi.ComponentContextAdapter;
22 +import org.onlab.packet.ChassisId;
23 +import org.onosproject.cfg.ComponentConfigAdapter;
24 +import org.onosproject.core.ApplicationId;
25 +import org.onosproject.core.CoreService;
26 +import org.onosproject.core.DefaultApplicationId;
27 +import org.onosproject.mastership.MastershipService;
28 +import org.onosproject.mastership.MastershipServiceAdapter;
29 +import org.onosproject.net.AbstractProjectableModel;
30 +import org.onosproject.net.AnnotationKeys;
31 +import org.onosproject.net.Annotations;
32 +import org.onosproject.net.ConnectPoint;
33 +import org.onosproject.net.DefaultAnnotations;
34 +import org.onosproject.net.DefaultDevice;
35 +import org.onosproject.net.DefaultLink;
36 +import org.onosproject.net.Device;
37 +import org.onosproject.net.DeviceId;
38 +import org.onosproject.net.Link;
39 +import org.onosproject.net.LinkKey;
40 +import org.onosproject.net.PortNumber;
41 +import org.onosproject.net.behaviour.LinkDiscovery;
42 +import org.onosproject.net.device.DeviceListener;
43 +import org.onosproject.net.device.DeviceServiceAdapter;
44 +import org.onosproject.net.driver.AbstractHandlerBehaviour;
45 +import org.onosproject.net.driver.Behaviour;
46 +import org.onosproject.net.driver.Driver;
47 +import org.onosproject.net.driver.DriverAdapter;
48 +import org.onosproject.net.driver.DriverHandler;
49 +import org.onosproject.net.driver.DriverServiceAdapter;
50 +import org.onosproject.net.link.DefaultLinkDescription;
51 +import org.onosproject.net.link.LinkDescription;
52 +import org.onosproject.net.link.LinkProviderRegistryAdapter;
53 +import org.onosproject.net.link.LinkProviderServiceAdapter;
54 +import org.onosproject.net.link.LinkServiceAdapter;
55 +import org.onosproject.net.provider.ProviderId;
56 +
57 +import java.util.Dictionary;
58 +import java.util.HashSet;
59 +import java.util.Hashtable;
60 +import java.util.Set;
61 +
62 +import static org.easymock.EasyMock.*;
63 +import static org.junit.Assert.*;
64 +import static org.onlab.junit.TestTools.assertAfter;
65 +import static org.onosproject.provider.linkdiscovery.impl.LinkDiscoveryProvider.APP_NAME;
66 +import static org.onosproject.provider.linkdiscovery.impl.LinkDiscoveryProvider.SCHEME_NAME;
67 +
68 +/**
69 + * Test for polling mechanism of the NetconfLinkProvider.
70 + */
71 +public class LinkDiscoveryProviderTest {
72 +
73 + private static final ComponentContextAdapter CONTEXT =
74 + new ComponentContextAdapter() {
75 + @Override
76 + public Dictionary getProperties() {
77 + Hashtable<String, Integer> props = new Hashtable<>();
78 + props.put("linkPollFrequencySeconds", 2);
79 + props.put("linkPollDelaySeconds", 1);
80 + return props;
81 + }
82 + };
83 + // Network Mocks
84 + private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId("netconf:1.1.1.1");
85 + private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId("netconf:1.1.1.2");
86 + private static final ConnectPoint CP11 = new ConnectPoint(DEVICE_ID_1, PortNumber.portNumber(1));
87 + private static final ConnectPoint CP12 = new ConnectPoint(DEVICE_ID_1, PortNumber.portNumber(2));
88 + private static final ConnectPoint CP13 = new ConnectPoint(DEVICE_ID_1, PortNumber.portNumber(3));
89 + private static final ConnectPoint CP14 = new ConnectPoint(DEVICE_ID_1, PortNumber.portNumber(4));
90 + private static final ConnectPoint CP21 = new ConnectPoint(DEVICE_ID_2, PortNumber.portNumber(1));
91 + private static final ConnectPoint CP22 = new ConnectPoint(DEVICE_ID_2, PortNumber.portNumber(2));
92 + private static final ConnectPoint CP23 = new ConnectPoint(DEVICE_ID_2, PortNumber.portNumber(3));
93 + private static final ConnectPoint CP24 = new ConnectPoint(DEVICE_ID_2, PortNumber.portNumber(4));
94 + private static final DefaultAnnotations DEVICE_ANNOTATIONS = DefaultAnnotations.builder()
95 + .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()).build();
96 + private static final DefaultAnnotations LINK_ANNOTATIONS = DefaultAnnotations.builder()
97 + .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()).build();
98 + private static final LinkKey LINKKEY1 = LinkKey.linkKey(CP11, CP21);
99 + private static final LinkDescription LINK1 = new DefaultLinkDescription(CP11, CP21,
100 + Link.Type.DIRECT,
101 + LINK_ANNOTATIONS);
102 + private static final LinkKey LINKKEY2 = LinkKey.linkKey(CP12, CP22);
103 + private static final LinkDescription LINK2 = new DefaultLinkDescription(CP12, CP22,
104 + Link.Type.DIRECT,
105 + LINK_ANNOTATIONS);
106 + private static final LinkKey LINKKEY3 = LinkKey.linkKey(CP13, CP23);
107 + private static final LinkDescription LINK3 = new DefaultLinkDescription(CP13, CP23,
108 + Link.Type.DIRECT,
109 + DefaultAnnotations.builder()
110 + .build());
111 + private static final LinkKey LINKKEY4 = LinkKey.linkKey(CP14, CP24);
112 + private static final LinkDescription LINK4 = new DefaultLinkDescription(CP14, CP24,
113 + Link.Type.DIRECT,
114 + DefaultAnnotations.builder().build());
115 + //Service Mocks
116 + private final MockDeviceService deviceService = new MockDeviceService();
117 + private final LinkProviderRegistryAdapter linkRegistry = new LinkProviderRegistryAdapter();
118 + private final MastershipService mastershipService = new MockMastershipService();
119 + private final MockLinkService linkService = new MockLinkService();
120 + private final Driver driver = new MockDriver();
121 + //Provider related classes
122 + private LinkProviderServiceAdapter providerService;
123 + private CoreService coreService;
124 + private LinkDiscoveryProvider provider = new LinkDiscoveryProvider();
125 + private final Device device1 = new MockDevice(provider.id(), DEVICE_ID_1, Device.Type.SWITCH,
126 + "foo.inc", "0", "0", "0", new ChassisId(),
127 + DEVICE_ANNOTATIONS);
128 + private Set<DeviceListener> deviceListeners = new HashSet<>();
129 + private ApplicationId appId =
130 + new DefaultApplicationId(100, APP_NAME);
131 + private TestLink testLink = new TestLink();
132 +
133 + @Before
134 + public void setUp() {
135 + coreService = createMock(CoreService.class);
136 + expect(coreService.registerApplication(appId.name()))
137 + .andReturn(appId).anyTimes();
138 + replay(coreService);
139 + provider.coreService = coreService;
140 + provider.providerRegistry = linkRegistry;
141 + provider.deviceService = deviceService;
142 + provider.mastershipService = mastershipService;
143 + provider.linkService = linkService;
144 + provider.cfgService = new ComponentConfigAdapter();
145 + AbstractProjectableModel.setDriverService(null, new DriverServiceAdapter());
146 + provider.activate(null);
147 + providerService = linkRegistry.registeredProvider();
148 + }
149 +
150 + @Test
151 + public void activate() throws Exception {
152 + assertFalse("Provider should be registered", linkRegistry.getProviders().contains(provider));
153 + assertEquals("Device service should be registered", provider.deviceService, deviceService);
154 + assertEquals("Device listener should be added", 1, deviceListeners.size());
155 + assertNotNull("Registration expected", providerService);
156 + assertEquals("Incorrect provider", provider, providerService.provider());
157 + assertFalse("Executor should be running", provider.executor.isShutdown());
158 + assertFalse("Executor should be running", provider.executor.isTerminated());
159 + assertEquals("Incorrect polling frequency, should be default", 10,
160 + provider.linkPollFrequencySeconds);
161 + assertEquals("Incorrect polling delay , should be default", 20,
162 + provider.linkPollDelaySeconds);
163 + }
164 +
165 + @Test
166 + public void modified() throws Exception {
167 + provider.modified(CONTEXT);
168 + assertEquals("Incorrect polling frequency, should be default", 2,
169 + provider.linkPollFrequencySeconds);
170 + assertEquals("Incorrect polling delay , should be default", 1,
171 + provider.linkPollDelaySeconds);
172 +
173 + }
174 +
175 +
176 + @Test
177 + public void deactivate() throws Exception {
178 + provider.deactivate();
179 + assertEquals("Device listener should be removed", 0, deviceListeners.size());
180 + assertFalse("Provider should not be registered", linkRegistry.getProviders().contains(provider));
181 + assertTrue(provider.executor.isShutdown());
182 + assertNull(provider.providerService);
183 + }
184 +
185 +
186 + @Test
187 + public void linksTestForStoredDevice() {
188 + provider.modified(CONTEXT);
189 + providerService.discoveredLinkDescriptions().put(LINKKEY1, LINK1);
190 + providerService.discoveredLinkDescriptions().put(LINKKEY2, LINK2);
191 + providerService.discoveredLinkDescriptions().put(LINKKEY4, LINK4);
192 + testLink.addLinkDesc(LINK2);
193 + testLink.addLinkDesc(LINK3);
194 + assertAfter(1100, () -> {
195 + assertEquals("Total number of link must be 3", 3, providerService.discoveredLinkDescriptions().size());
196 + assertFalse("Link1 should be removed",
197 + providerService.discoveredLinkDescriptions().containsKey(LINKKEY1));
198 + assertTrue("Link2 should be present",
199 + providerService.discoveredLinkDescriptions().containsKey(LINKKEY2));
200 + assertTrue("Link3 should be added",
201 + providerService.discoveredLinkDescriptions().containsKey(LINKKEY3));
202 + assertEquals("Link3 should be annotated", SCHEME_NAME.toUpperCase(),
203 + providerService.discoveredLinkDescriptions()
204 + .get(LINKKEY3).annotations().value(AnnotationKeys.PROTOCOL));
205 + assertTrue("Link4 should be present because it is not related to the LinkDiscovery",
206 + providerService.discoveredLinkDescriptions().containsKey(LINKKEY4));
207 +
208 + });
209 + clear();
210 + }
211 +
212 + private void clear() {
213 + testLink.clearLinkDesc();
214 + providerService.discoveredLinkDescriptions().clear();
215 + providerService.discoveredLinks().clear();
216 + }
217 +
218 + private class MockDeviceService extends DeviceServiceAdapter {
219 +
220 + @Override
221 + public Iterable<Device> getAvailableDevices() {
222 + return ImmutableSet.of(device1);
223 + }
224 +
225 + @Override
226 + public void addListener(DeviceListener listener) {
227 + deviceListeners.add(listener);
228 + }
229 +
230 + @Override
231 + public void removeListener(DeviceListener listener) {
232 + deviceListeners.remove(listener);
233 + }
234 + }
235 +
236 + private class MockMastershipService extends MastershipServiceAdapter {
237 +
238 + @Override
239 + public boolean isLocalMaster(DeviceId deviceId) {
240 + return true;
241 + }
242 + }
243 +
244 + private class MockLinkService extends LinkServiceAdapter {
245 + @Override
246 + public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
247 + Set<Link> links = new HashSet<>();
248 + providerService.discoveredLinkDescriptions().values()
249 + .forEach(x -> links.add(DefaultLink.builder()
250 + .providerId(provider.id())
251 + .src(x.src())
252 + .dst(x.dst())
253 + .type(x.type())
254 + .isExpected(x.isExpected())
255 + .annotations(x.annotations()).build()));
256 + return ImmutableSet.copyOf(links);
257 + }
258 + }
259 +
260 + private class MockDevice extends DefaultDevice {
261 +
262 + public MockDevice(ProviderId providerId, DeviceId id, Type type,
263 + String manufacturer, String hwVersion, String swVersion,
264 + String serialNumber, ChassisId chassisId, Annotations... annotations) {
265 + super(providerId, id, type, manufacturer, hwVersion, swVersion, serialNumber,
266 + chassisId, annotations);
267 + }
268 +
269 + @Override
270 + protected Driver locateDriver() {
271 + return driver;
272 + }
273 +
274 + @Override
275 + public Driver driver() {
276 + return driver;
277 + }
278 + }
279 +
280 + private class MockDriver extends DriverAdapter {
281 + @Override
282 + public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) {
283 +
284 + return (T) testLink;
285 + }
286 + }
287 +
288 + private class TestLink extends AbstractHandlerBehaviour implements LinkDiscovery {
289 + Set<LinkDescription> linkDescriptions = new HashSet<>();
290 +
291 + @Override
292 + public Set<LinkDescription> getLinks() {
293 + return ImmutableSet.copyOf(linkDescriptions);
294 + }
295 +
296 + private void addLinkDesc(LinkDescription link) {
297 + linkDescriptions.add(link);
298 + }
299 +
300 + private void clearLinkDesc() {
301 + linkDescriptions.clear();
302 + }
303 +
304 + }
305 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016-present 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 + */
16 +
17 +/**
18 + * Test package for the Link Discovery Provider.
19 + */
20 +package org.onosproject.provider.linkdiscovery.impl;
...\ No newline at end of file ...\ No newline at end of file
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
49 <module>isis</module> 49 <module>isis</module>
50 <module>lisp</module> 50 <module>lisp</module>
51 <module>ospf</module> 51 <module>ospf</module>
52 + <module>link</module>
52 </modules> 53 </modules>
53 54
54 <dependencies> 55 <dependencies>
......