Naoki Shiota
Committed by Gerrit Code Review

[ONOS-3205] Migrate LLDP Link Discovery configuration to Network Configuration System

- deviceIds under suppression will be moved out to different location. (See ONOS-3461)

Change-Id: I6ebe0ce7f5f2d26e7ee7175974e19305f7c17fad
...@@ -333,6 +333,26 @@ public abstract class Config<S> { ...@@ -333,6 +333,26 @@ public abstract class Config<S> {
333 } 333 }
334 334
335 /** 335 /**
336 + * Gets the specified array property as a list of items.
337 + *
338 + * @param name property name
339 + * @param function mapper from string to item
340 + * @param defaultValue default value if property not set
341 + * @param <T> type of item
342 + * @return list of items
343 + */
344 + protected <T> List<T> getList(String name, Function<String, T> function, List<T> defaultValue) {
345 + List<T> list = Lists.newArrayList();
346 + JsonNode jsonNode = object.path(name);
347 + if (jsonNode.isMissingNode()) {
348 + return defaultValue;
349 + }
350 + ArrayNode arrayNode = (ArrayNode) jsonNode;
351 + arrayNode.forEach(i -> list.add(function.apply(i.asText())));
352 + return list;
353 + }
354 +
355 + /**
336 * Sets the specified property as an array of items in a given collection or 356 * Sets the specified property as an array of items in a given collection or
337 * clears it if null is given. 357 * clears it if null is given.
338 * 358 *
......
...@@ -55,5 +55,9 @@ ...@@ -55,5 +55,9 @@
55 <scope>test</scope> 55 <scope>test</scope>
56 </dependency> 56 </dependency>
57 57
58 + <dependency>
59 + <groupId>com.fasterxml.jackson.core</groupId>
60 + <artifactId>jackson-databind</artifactId>
61 + </dependency>
58 </dependencies> 62 </dependencies>
59 </project> 63 </project>
......
...@@ -38,6 +38,9 @@ import org.onosproject.net.Device; ...@@ -38,6 +38,9 @@ import org.onosproject.net.Device;
38 import org.onosproject.net.DeviceId; 38 import org.onosproject.net.DeviceId;
39 import org.onosproject.net.LinkKey; 39 import org.onosproject.net.LinkKey;
40 import org.onosproject.net.Port; 40 import org.onosproject.net.Port;
41 +import org.onosproject.net.config.ConfigFactory;
42 +import org.onosproject.net.config.NetworkConfigEvent;
43 +import org.onosproject.net.config.NetworkConfigListener;
41 import org.onosproject.net.config.NetworkConfigRegistry; 44 import org.onosproject.net.config.NetworkConfigRegistry;
42 import org.onosproject.net.device.DeviceEvent; 45 import org.onosproject.net.device.DeviceEvent;
43 import org.onosproject.net.device.DeviceListener; 46 import org.onosproject.net.device.DeviceListener;
...@@ -58,12 +61,12 @@ import org.onosproject.net.provider.ProviderId; ...@@ -58,12 +61,12 @@ import org.onosproject.net.provider.ProviderId;
58 import org.osgi.service.component.ComponentContext; 61 import org.osgi.service.component.ComponentContext;
59 import org.slf4j.Logger; 62 import org.slf4j.Logger;
60 63
61 -import java.io.IOException;
62 import java.util.Dictionary; 64 import java.util.Dictionary;
63 import java.util.EnumSet; 65 import java.util.EnumSet;
64 import java.util.Map; 66 import java.util.Map;
65 import java.util.Optional; 67 import java.util.Optional;
66 import java.util.Properties; 68 import java.util.Properties;
69 +import java.util.Set;
67 import java.util.concurrent.ConcurrentHashMap; 70 import java.util.concurrent.ConcurrentHashMap;
68 import java.util.concurrent.ScheduledExecutorService; 71 import java.util.concurrent.ScheduledExecutorService;
69 72
...@@ -75,6 +78,7 @@ import static org.onlab.packet.Ethernet.TYPE_LLDP; ...@@ -75,6 +78,7 @@ import static org.onlab.packet.Ethernet.TYPE_LLDP;
75 import static org.onlab.util.Tools.get; 78 import static org.onlab.util.Tools.get;
76 import static org.onlab.util.Tools.groupedThreads; 79 import static org.onlab.util.Tools.groupedThreads;
77 import static org.onosproject.net.Link.Type.DIRECT; 80 import static org.onosproject.net.Link.Type.DIRECT;
81 +import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
78 import static org.slf4j.LoggerFactory.getLogger; 82 import static org.slf4j.LoggerFactory.getLogger;
79 83
80 /** 84 /**
...@@ -87,12 +91,11 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -87,12 +91,11 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
87 91
88 private static final String FORMAT = 92 private static final String FORMAT =
89 "Settings: enabled={}, useBDDP={}, probeRate={}, " + 93 "Settings: enabled={}, useBDDP={}, probeRate={}, " +
90 - "staleLinkAge={}, lldpSuppression={}"; 94 + "staleLinkAge={}";
91 95
92 // When a Device/Port has this annotation, do not send out LLDP/BDDP 96 // When a Device/Port has this annotation, do not send out LLDP/BDDP
93 public static final String NO_LLDP = "no-lldp"; 97 public static final String NO_LLDP = "no-lldp";
94 98
95 -
96 private final Logger log = getLogger(getClass()); 99 private final Logger log = getLogger(getClass());
97 100
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -152,13 +155,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -152,13 +155,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
152 label = "Number of millis beyond which links will be considered stale") 155 label = "Number of millis beyond which links will be considered stale")
153 private int staleLinkAge = DEFAULT_STALE_LINK_AGE; 156 private int staleLinkAge = DEFAULT_STALE_LINK_AGE;
154 157
155 - // FIXME: convert to use network config subsystem instead
156 - private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression";
157 - private static final String DEFAULT_LLDP_SUPPRESSION_CONFIG = "../config/lldp_suppression.json";
158 - @Property(name = PROP_LLDP_SUPPRESSION, value = DEFAULT_LLDP_SUPPRESSION_CONFIG,
159 - label = "Path to LLDP suppression configuration file")
160 - private String lldpSuppression = DEFAULT_LLDP_SUPPRESSION_CONFIG;
161 -
162 private final DiscoveryContext context = new InternalDiscoveryContext(); 158 private final DiscoveryContext context = new InternalDiscoveryContext();
163 private final InternalRoleListener roleListener = new InternalRoleListener(); 159 private final InternalRoleListener roleListener = new InternalRoleListener();
164 private final InternalDeviceListener deviceListener = new InternalDeviceListener(); 160 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
...@@ -171,9 +167,31 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -171,9 +167,31 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
171 // destination connection point is mastered by this controller instance. 167 // destination connection point is mastered by this controller instance.
172 private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap(); 168 private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap();
173 169
174 - private SuppressionRules rules;
175 private ApplicationId appId; 170 private ApplicationId appId;
176 171
172 + static final SuppressionRules DEFAULT_RULES
173 + = new SuppressionRules(ImmutableSet.of(),
174 + EnumSet.of(Device.Type.ROADM),
175 + ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
176 +
177 + private SuppressionRules rules = LldpLinkProvider.DEFAULT_RULES;
178 +
179 + public static final String CONFIG_KEY = "suppression";
180 +
181 + private final Set<ConfigFactory> factories = ImmutableSet.of(
182 + new ConfigFactory<ApplicationId, SuppressionConfig>(APP_SUBJECT_FACTORY,
183 + SuppressionConfig.class,
184 + CONFIG_KEY) {
185 + @Override
186 + public SuppressionConfig createConfig() {
187 + return new SuppressionConfig();
188 + }
189 + }
190 + );
191 +
192 + private final InternalConfigListener cfgListener = new InternalConfigListener();
193 +
194 +
177 /** 195 /**
178 * Creates an OpenFlow link provider. 196 * Creates an OpenFlow link provider.
179 */ 197 */
...@@ -185,12 +203,30 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -185,12 +203,30 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
185 public void activate(ComponentContext context) { 203 public void activate(ComponentContext context) {
186 cfgService.registerProperties(getClass()); 204 cfgService.registerProperties(getClass());
187 appId = coreService.registerApplication(PROVIDER_NAME); 205 appId = coreService.registerApplication(PROVIDER_NAME);
206 +
207 + cfgRegistry.addListener(cfgListener);
208 + factories.forEach(cfgRegistry::registerConfigFactory);
209 +
210 + SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
211 + if (cfg == null) {
212 + // If no configuration is found, register default.
213 + cfg = cfgRegistry.addConfig(appId, SuppressionConfig.class);
214 + cfg.deviceIds(DEFAULT_RULES.getSuppressedDevice())
215 + .deviceTypes(DEFAULT_RULES.getSuppressedDeviceType())
216 + .annotation(DEFAULT_RULES.getSuppressedAnnotation())
217 + .apply();
218 + }
219 + cfgListener.reconfigureSuppressionRules(cfg);
220 +
188 modified(context); 221 modified(context);
189 log.info("Started"); 222 log.info("Started");
190 } 223 }
191 224
192 @Deactivate 225 @Deactivate
193 public void deactivate() { 226 public void deactivate() {
227 + cfgRegistry.removeListener(cfgListener);
228 + factories.forEach(cfgRegistry::unregisterConfigFactory);
229 +
194 cfgService.unregisterProperties(getClass(), false); 230 cfgService.unregisterProperties(getClass(), false);
195 disable(); 231 disable();
196 log.info("Stopped"); 232 log.info("Stopped");
...@@ -202,7 +238,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -202,7 +238,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
202 238
203 boolean newEnabled, newUseBddp; 239 boolean newEnabled, newUseBddp;
204 int newProbeRate, newStaleLinkAge; 240 int newProbeRate, newStaleLinkAge;
205 - String newLldpSuppression;
206 try { 241 try {
207 String s = get(properties, PROP_ENABLED); 242 String s = get(properties, PROP_ENABLED);
208 newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim()); 243 newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
...@@ -216,16 +251,12 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -216,16 +251,12 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
216 s = get(properties, PROP_STALE_LINK_AGE); 251 s = get(properties, PROP_STALE_LINK_AGE);
217 newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim()); 252 newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim());
218 253
219 - s = get(properties, PROP_LLDP_SUPPRESSION);
220 - newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s;
221 -
222 } catch (NumberFormatException e) { 254 } catch (NumberFormatException e) {
223 log.warn("Component configuration had invalid values", e); 255 log.warn("Component configuration had invalid values", e);
224 newEnabled = enabled; 256 newEnabled = enabled;
225 newUseBddp = useBddp; 257 newUseBddp = useBddp;
226 newProbeRate = probeRate; 258 newProbeRate = probeRate;
227 newStaleLinkAge = staleLinkAge; 259 newStaleLinkAge = staleLinkAge;
228 - newLldpSuppression = lldpSuppression;
229 } 260 }
230 261
231 boolean wasEnabled = enabled; 262 boolean wasEnabled = enabled;
...@@ -234,23 +265,19 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -234,23 +265,19 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
234 useBddp = newUseBddp; 265 useBddp = newUseBddp;
235 probeRate = newProbeRate; 266 probeRate = newProbeRate;
236 staleLinkAge = newStaleLinkAge; 267 staleLinkAge = newStaleLinkAge;
237 - lldpSuppression = newLldpSuppression;
238 268
239 if (!wasEnabled && enabled) { 269 if (!wasEnabled && enabled) {
240 enable(); 270 enable();
241 } else if (wasEnabled && !enabled) { 271 } else if (wasEnabled && !enabled) {
242 disable(); 272 disable();
243 } else { 273 } else {
244 - // reflect changes in suppression rules to discovery helpers
245 - // FIXME: After migrating to Network Configuration Subsystem,
246 - // it should be possible to update only changed subset
247 if (enabled) { 274 if (enabled) {
248 // update all discovery helper state 275 // update all discovery helper state
249 loadDevices(); 276 loadDevices();
250 } 277 }
251 } 278 }
252 279
253 - log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge, lldpSuppression); 280 + log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge);
254 } 281 }
255 282
256 /** 283 /**
...@@ -262,7 +289,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -262,7 +289,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
262 deviceService.addListener(deviceListener); 289 deviceService.addListener(deviceListener);
263 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0)); 290 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
264 291
265 - loadSuppressionRules();
266 loadDevices(); 292 loadDevices();
267 293
268 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d")); 294 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d"));
...@@ -285,6 +311,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -285,6 +311,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
285 deviceService.removeListener(deviceListener); 311 deviceService.removeListener(deviceListener);
286 packetService.removeProcessor(packetProcessor); 312 packetService.removeProcessor(packetProcessor);
287 313
314 +
288 if (executor != null) { 315 if (executor != null) {
289 executor.shutdownNow(); 316 executor.shutdownNow();
290 } 317 }
...@@ -298,6 +325,9 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -298,6 +325,9 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
298 * Loads available devices and registers their ports to be probed. 325 * Loads available devices and registers their ports to be probed.
299 */ 326 */
300 private void loadDevices() { 327 private void loadDevices() {
328 + if (!enabled) {
329 + return;
330 + }
301 deviceService.getAvailableDevices() 331 deviceService.getAvailableDevices()
302 .forEach(d -> updateDevice(d) 332 .forEach(d -> updateDevice(d)
303 .ifPresent(ld -> updatePorts(ld, d.id()))); 333 .ifPresent(ld -> updatePorts(ld, d.id())));
...@@ -333,7 +363,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -333,7 +363,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
333 private void removeDevice(final DeviceId deviceId) { 363 private void removeDevice(final DeviceId deviceId) {
334 discoverers.computeIfPresent(deviceId, (did, ld) -> { 364 discoverers.computeIfPresent(deviceId, (did, ld) -> {
335 ld.stop(); 365 ld.stop();
336 - providerService.linksVanished(deviceId);
337 return null; 366 return null;
338 }); 367 });
339 368
...@@ -357,6 +386,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -357,6 +386,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
357 // silently ignore logical ports 386 // silently ignore logical ports
358 return; 387 return;
359 } 388 }
389 +
360 if (rules.isSuppressed(port)) { 390 if (rules.isSuppressed(port)) {
361 log.trace("LinkDiscovery from {} disabled by configuration", port); 391 log.trace("LinkDiscovery from {} disabled by configuration", port);
362 removePort(port); 392 removePort(port);
...@@ -383,35 +413,12 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -383,35 +413,12 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
383 if (ld != null) { 413 if (ld != null) {
384 ld.removePort(port.number()); 414 ld.removePort(port.number());
385 } 415 }
386 -
387 - ConnectPoint point = new ConnectPoint(d.id(), port.number());
388 - providerService.linksVanished(point);
389 } else { 416 } else {
390 log.warn("Attempted to remove non-Device port", port); 417 log.warn("Attempted to remove non-Device port", port);
391 } 418 }
392 } 419 }
393 420
394 /** 421 /**
395 - * Loads LLDP suppression rules.
396 - */
397 - private void loadSuppressionRules() {
398 - // FIXME: convert to use network configuration
399 - SuppressionRulesStore store = new SuppressionRulesStore(lldpSuppression);
400 - try {
401 - log.info("Reading suppression rules from {}", lldpSuppression);
402 - rules = store.read();
403 - } catch (IOException e) {
404 - log.info("Failed to load {}, using built-in rules", lldpSuppression);
405 - // default rule to suppress ROADM to maintain compatibility
406 - rules = new SuppressionRules(ImmutableSet.of(),
407 - EnumSet.of(Device.Type.ROADM),
408 - ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
409 - }
410 -
411 - // should refresh discoverers when we need dynamic reconfiguration
412 - }
413 -
414 - /**
415 * Requests packet intercepts. 422 * Requests packet intercepts.
416 */ 423 */
417 private void requestIntercepts() { 424 private void requestIntercepts() {
...@@ -438,6 +445,17 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -438,6 +445,17 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
438 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId); 445 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
439 } 446 }
440 447
448 + protected SuppressionRules rules() {
449 + return rules;
450 + }
451 +
452 + protected void updateRules(SuppressionRules newRules) {
453 + if (!rules.equals(newRules)) {
454 + rules = newRules;
455 + loadDevices();
456 + }
457 + }
458 +
441 /** 459 /**
442 * Processes device mastership role changes. 460 * Processes device mastership role changes.
443 */ 461 */
...@@ -459,7 +477,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -459,7 +477,6 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
459 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id())); 477 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
460 } 478 }
461 } 479 }
462 -
463 } 480 }
464 481
465 /** 482 /**
...@@ -488,16 +505,21 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -488,16 +505,21 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
488 } else { 505 } else {
489 log.debug("Port down {}", port); 506 log.debug("Port down {}", port);
490 removePort(port); 507 removePort(port);
508 + providerService.linksVanished(new ConnectPoint(port.element().id(),
509 + port.number()));
491 } 510 }
492 break; 511 break;
493 case PORT_REMOVED: 512 case PORT_REMOVED:
494 log.debug("Port removed {}", port); 513 log.debug("Port removed {}", port);
495 removePort(port); 514 removePort(port);
515 + providerService.linksVanished(new ConnectPoint(port.element().id(),
516 + port.number()));
496 break; 517 break;
497 case DEVICE_REMOVED: 518 case DEVICE_REMOVED:
498 case DEVICE_SUSPENDED: 519 case DEVICE_SUSPENDED:
499 log.debug("Device removed {}", deviceId); 520 log.debug("Device removed {}", deviceId);
500 removeDevice(deviceId); 521 removeDevice(deviceId);
522 + providerService.linksVanished(deviceId);
501 break; 523 break;
502 case DEVICE_AVAILABILITY_CHANGED: 524 case DEVICE_AVAILABILITY_CHANGED:
503 if (deviceService.isAvailable(deviceId)) { 525 if (deviceService.isAvailable(deviceId)) {
...@@ -506,6 +528,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -506,6 +528,7 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
506 } else { 528 } else {
507 log.debug("Device down {}", deviceId); 529 log.debug("Device down {}", deviceId);
508 removeDevice(deviceId); 530 removeDevice(deviceId);
531 + providerService.linksVanished(deviceId);
509 } 532 }
510 break; 533 break;
511 case PORT_STATS_UPDATED: 534 case PORT_STATS_UPDATED:
...@@ -636,4 +659,30 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -636,4 +659,30 @@ public class LldpLinkProvider extends AbstractProvider implements LinkProvider {
636 } 659 }
637 } 660 }
638 661
662 + private class InternalConfigListener implements NetworkConfigListener {
663 +
664 + private synchronized void reconfigureSuppressionRules(SuppressionConfig cfg) {
665 + if (cfg == null) {
666 + log.error("Suppression Config is null.");
667 + return;
668 + }
669 +
670 + SuppressionRules newRules = new SuppressionRules(cfg.deviceIds(),
671 + cfg.deviceTypes(),
672 + cfg.annotation());
673 +
674 + updateRules(newRules);
675 + }
676 +
677 + @Override
678 + public void event(NetworkConfigEvent event) {
679 + if (event.configClass().equals(SuppressionConfig.class) &&
680 + (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
681 + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) {
682 + SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
683 + reconfigureSuppressionRules(cfg);
684 + log.trace("Network config reconfigured");
685 + }
686 + }
687 + }
639 } 688 }
......
1 +/*
2 + * Copyright 2014-2015 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.lldp.impl;
17 +
18 +import com.fasterxml.jackson.core.JsonProcessingException;
19 +import com.fasterxml.jackson.databind.JsonNode;
20 +import com.fasterxml.jackson.databind.ObjectMapper;
21 +import com.fasterxml.jackson.databind.node.ObjectNode;
22 +import com.google.common.collect.ImmutableList;
23 +import com.google.common.collect.ImmutableMap;
24 +import com.google.common.collect.ImmutableSet;
25 +import com.google.common.collect.Maps;
26 +
27 +import org.onosproject.core.ApplicationId;
28 +import org.onosproject.net.Device;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.config.Config;
31 +import org.slf4j.Logger;
32 +
33 +import java.io.IOException;
34 +import java.util.Iterator;
35 +import java.util.List;
36 +import java.util.Map;
37 +import java.util.Set;
38 +import static org.onosproject.provider.lldp.impl.LldpLinkProvider.DEFAULT_RULES;
39 +import static org.slf4j.LoggerFactory.getLogger;
40 +
41 +/**
42 + * LLDP suppression config class.
43 + */
44 +public class SuppressionConfig extends Config<ApplicationId> {
45 + private static final String DEVICE_IDS = "deviceIds";
46 + private static final String DEVICE_TYPES = "deviceTypes";
47 + private static final String ANNOTATION = "annotation";
48 +
49 + private static final ObjectMapper MAPPER = new ObjectMapper();
50 + private static final List<DeviceId> DEFAULT_DEVICE_IDS
51 + = ImmutableList.copyOf(DEFAULT_RULES.getSuppressedDevice());
52 + private static final List<Device.Type> DEFAULT_DEVICE_TYPES
53 + = ImmutableList.copyOf(DEFAULT_RULES.getSuppressedDeviceType());
54 +
55 + private final Logger log = getLogger(getClass());
56 +
57 + /**
58 + * Returns device IDs on which LLDP is suppressed.
59 + *
60 + * @return Set of DeviceId objects
61 + */
62 + @Deprecated
63 + public Set<DeviceId> deviceIds() {
64 + return ImmutableSet.copyOf(getList(DEVICE_IDS, DeviceId::deviceId, DEFAULT_DEVICE_IDS));
65 + }
66 +
67 + /**
68 + * Sets device IDs on which LLDP is suppressed.
69 + *
70 + * @param deviceIds new set of device IDs; null to clear
71 + * @return self
72 + */
73 + @Deprecated
74 + public SuppressionConfig deviceIds(Set<DeviceId> deviceIds) {
75 + return (SuppressionConfig) setOrClear(DEVICE_IDS, deviceIds);
76 + }
77 +
78 + /**
79 + * Returns types of devices on which LLDP is suppressed.
80 + *
81 + * @return set of device types
82 + */
83 + public Set<Device.Type> deviceTypes() {
84 + return ImmutableSet.copyOf(getList(DEVICE_TYPES, Device.Type::valueOf, DEFAULT_DEVICE_TYPES));
85 + }
86 +
87 + /**
88 + * Sets types of devices on which LLDP is suppressed.
89 + *
90 + * @param deviceTypes new set of device types; null to clear
91 + * @return self
92 + */
93 + public SuppressionConfig deviceTypes(Set<Device.Type> deviceTypes) {
94 + return (SuppressionConfig) setOrClear(DEVICE_TYPES, deviceTypes);
95 + }
96 +
97 + /**
98 + * Returns annotation of Ports on which LLDP is suppressed.
99 + *
100 + * @return key-value pairs of annotation
101 + */
102 + public Map<String, String> annotation() {
103 + ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
104 +
105 + String jsonAnnotation = get(ANNOTATION, null);
106 + if (jsonAnnotation == null || jsonAnnotation.isEmpty()) {
107 + return ImmutableMap.of();
108 + }
109 +
110 + JsonNode annotationNode;
111 + try {
112 + annotationNode = MAPPER.readTree(jsonAnnotation);
113 + } catch (IOException e) {
114 + log.error("Failed to read JSON tree from: {}", jsonAnnotation);
115 + return ImmutableMap.of();
116 + }
117 +
118 + if (annotationNode.isObject()) {
119 + ObjectNode obj = (ObjectNode) annotationNode;
120 + Iterator<Map.Entry<String, JsonNode>> it = obj.fields();
121 + while (it.hasNext()) {
122 + Map.Entry<String, JsonNode> entry = it.next();
123 + final String key = entry.getKey();
124 + final JsonNode value = entry.getValue();
125 +
126 + if (value.isValueNode()) {
127 + if (value.isNull()) {
128 + builder.put(key, SuppressionRules.ANY_VALUE);
129 + } else {
130 + builder.put(key, value.asText());
131 + }
132 + } else {
133 + log.warn("Encountered unexpected JSON field {} for annotation", entry);
134 + }
135 + }
136 + } else {
137 + log.error("Encountered unexpected JSONNode {} for annotation", annotationNode);
138 + return ImmutableMap.of();
139 + }
140 +
141 + return builder.build();
142 + }
143 +
144 + /**
145 + * Sets annotation of Ports on which LLDP is suppressed.
146 + *
147 + * @param annotation new key-value pair of annotation; null to clear
148 + * @return self
149 + */
150 + public SuppressionConfig annotation(Map<String, String> annotation) {
151 +
152 + // ANY_VALUE should be null in JSON
153 + Map<String, String> config = Maps.transformValues(annotation,
154 + v -> (v == SuppressionRules.ANY_VALUE) ? null : v);
155 +
156 + String jsonAnnotation = null;
157 +
158 + try {
159 + // TODO Store annotation as a Map instead of a String (which needs NetworkConfigRegistry modification)
160 + jsonAnnotation = MAPPER.writeValueAsString(config);
161 + } catch (JsonProcessingException e) {
162 + log.error("Failed to write JSON from: {}", annotation);
163 + }
164 +
165 + return (SuppressionConfig) setOrClear(ANNOTATION, jsonAnnotation);
166 + }
167 +}
...@@ -18,6 +18,7 @@ package org.onosproject.provider.lldp.impl; ...@@ -18,6 +18,7 @@ package org.onosproject.provider.lldp.impl;
18 18
19 import java.util.Map; 19 import java.util.Map;
20 import java.util.Map.Entry; 20 import java.util.Map.Entry;
21 +import java.util.Objects;
21 import java.util.Set; 22 import java.util.Set;
22 23
23 import org.onosproject.net.Annotations; 24 import org.onosproject.net.Annotations;
...@@ -28,6 +29,7 @@ import org.onosproject.net.Port; ...@@ -28,6 +29,7 @@ import org.onosproject.net.Port;
28 29
29 import com.google.common.collect.ImmutableMap; 30 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.ImmutableSet; 31 import com.google.common.collect.ImmutableSet;
32 +import com.google.common.base.MoreObjects;
31 33
32 public class SuppressionRules { 34 public class SuppressionRules {
33 35
...@@ -103,4 +105,34 @@ public class SuppressionRules { ...@@ -103,4 +105,34 @@ public class SuppressionRules {
103 Map<String, String> getSuppressedAnnotation() { 105 Map<String, String> getSuppressedAnnotation() {
104 return suppressedAnnotation; 106 return suppressedAnnotation;
105 } 107 }
108 +
109 + @Override
110 + public int hashCode() {
111 + return Objects.hash(suppressedDevice,
112 + suppressedDeviceType,
113 + suppressedAnnotation);
114 + }
115 +
116 + @Override
117 + public boolean equals(Object object) {
118 + if (object != null && getClass() == object.getClass()) {
119 + SuppressionRules that = (SuppressionRules) object;
120 + return Objects.equals(this.suppressedDevice,
121 + that.suppressedDevice)
122 + && Objects.equals(this.suppressedDeviceType,
123 + that.suppressedDeviceType)
124 + && Objects.equals(this.suppressedAnnotation,
125 + that.suppressedAnnotation);
126 + }
127 + return false;
128 + }
129 +
130 + @Override
131 + public String toString() {
132 + return MoreObjects.toStringHelper(this)
133 + .add("suppressedDevice", suppressedDevice)
134 + .add("suppressedDeviceType", suppressedDeviceType)
135 + .add("suppressedAnnotation", suppressedAnnotation)
136 + .toString();
137 + }
106 } 138 }
......
1 -/*
2 - * Copyright 2014-2015 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.lldp.impl;
17 -
18 -import static com.google.common.base.Preconditions.checkNotNull;
19 -import static org.slf4j.LoggerFactory.getLogger;
20 -
21 -import com.fasterxml.jackson.core.JsonEncoding;
22 -import com.fasterxml.jackson.core.JsonFactory;
23 -import com.fasterxml.jackson.databind.JsonNode;
24 -import com.fasterxml.jackson.databind.ObjectMapper;
25 -import com.fasterxml.jackson.databind.node.ArrayNode;
26 -import com.fasterxml.jackson.databind.node.ObjectNode;
27 -
28 -import org.onosproject.net.Device;
29 -import org.onosproject.net.DeviceId;
30 -import org.slf4j.Logger;
31 -
32 -import java.io.File;
33 -import java.io.IOException;
34 -import java.util.EnumSet;
35 -import java.util.HashMap;
36 -import java.util.HashSet;
37 -import java.util.Iterator;
38 -import java.util.Map;
39 -import java.util.Map.Entry;
40 -import java.util.Set;
41 -
42 -/*
43 - * JSON file example
44 - *
45 -
46 -{
47 - "deviceId" : [ "of:2222000000000000" ],
48 - "deviceType" : [ "ROADM" ],
49 - "annotation" : { "no-lldp" : null, "sendLLDP" : "false" }
50 -}
51 - */
52 -
53 -/**
54 - * Allows for reading and writing LLDP suppression definition as a JSON file.
55 - */
56 -public class SuppressionRulesStore {
57 -
58 - private static final String DEVICE_ID = "deviceId";
59 - private static final String DEVICE_TYPE = "deviceType";
60 - private static final String ANNOTATION = "annotation";
61 -
62 - private final Logger log = getLogger(getClass());
63 -
64 - private final File file;
65 -
66 - /**
67 - * Creates a reader/writer of the LLDP suppression definition file.
68 - *
69 - * @param filePath location of the definition file
70 - */
71 - public SuppressionRulesStore(String filePath) {
72 - file = new File(filePath);
73 - }
74 -
75 - /**
76 - * Creates a reader/writer of the LLDP suppression definition file.
77 - *
78 - * @param file definition file
79 - */
80 - public SuppressionRulesStore(File file) {
81 - this.file = checkNotNull(file);
82 - }
83 -
84 - /**
85 - * Returns SuppressionRules.
86 - *
87 - * @return SuppressionRules
88 - * @throws IOException if error occurred while reading the data
89 - */
90 - public SuppressionRules read() throws IOException {
91 - final Set<DeviceId> suppressedDevice = new HashSet<>();
92 - final EnumSet<Device.Type> suppressedDeviceType = EnumSet.noneOf(Device.Type.class);
93 - final Map<String, String> suppressedAnnotation = new HashMap<>();
94 -
95 - ObjectMapper mapper = new ObjectMapper();
96 - ObjectNode root = (ObjectNode) mapper.readTree(file);
97 -
98 - for (JsonNode deviceId : root.get(DEVICE_ID)) {
99 - if (deviceId.isTextual()) {
100 - suppressedDevice.add(DeviceId.deviceId(deviceId.asText()));
101 - } else {
102 - log.warn("Encountered unexpected JSONNode {} for deviceId", deviceId);
103 - }
104 - }
105 -
106 - for (JsonNode deviceType : root.get(DEVICE_TYPE)) {
107 - if (deviceType.isTextual()) {
108 - suppressedDeviceType.add(Device.Type.valueOf(deviceType.asText()));
109 - } else {
110 - log.warn("Encountered unexpected JSONNode {} for deviceType", deviceType);
111 - }
112 - }
113 -
114 - JsonNode annotation = root.get(ANNOTATION);
115 - if (annotation.isObject()) {
116 - ObjectNode obj = (ObjectNode) annotation;
117 - Iterator<Entry<String, JsonNode>> it = obj.fields();
118 - while (it.hasNext()) {
119 - Entry<String, JsonNode> entry = it.next();
120 - final String key = entry.getKey();
121 - final JsonNode value = entry.getValue();
122 -
123 - if (value.isValueNode()) {
124 - if (value.isNull()) {
125 - suppressedAnnotation.put(key, SuppressionRules.ANY_VALUE);
126 - } else {
127 - suppressedAnnotation.put(key, value.asText());
128 - }
129 - } else {
130 - log.warn("Encountered unexpected JSON field {} for annotation", entry);
131 - }
132 - }
133 - } else {
134 - log.warn("Encountered unexpected JSONNode {} for annotation", annotation);
135 - }
136 -
137 - return new SuppressionRules(suppressedDevice,
138 - suppressedDeviceType,
139 - suppressedAnnotation);
140 - }
141 -
142 - /**
143 - * Writes the given SuppressionRules.
144 - *
145 - * @param rules SuppressionRules
146 - * @throws IOException if error occurred while writing the data
147 - */
148 - public void write(SuppressionRules rules) throws IOException {
149 - ObjectMapper mapper = new ObjectMapper();
150 - ObjectNode root = mapper.createObjectNode();
151 - ArrayNode deviceIds = mapper.createArrayNode();
152 - ArrayNode deviceTypes = mapper.createArrayNode();
153 - ObjectNode annotations = mapper.createObjectNode();
154 - root.set(DEVICE_ID, deviceIds);
155 - root.set(DEVICE_TYPE, deviceTypes);
156 - root.set(ANNOTATION, annotations);
157 -
158 - rules.getSuppressedDevice()
159 - .forEach(deviceId -> deviceIds.add(deviceId.toString()));
160 -
161 - rules.getSuppressedDeviceType()
162 - .forEach(type -> deviceTypes.add(type.toString()));
163 -
164 - rules.getSuppressedAnnotation().forEach((key, value) -> {
165 - if (value == SuppressionRules.ANY_VALUE) {
166 - annotations.putNull(key);
167 - } else {
168 - annotations.put(key, value);
169 - }
170 - });
171 - mapper.writeTree(new JsonFactory().createGenerator(file, JsonEncoding.UTF8),
172 - root);
173 - }
174 -}
...@@ -15,8 +15,11 @@ ...@@ -15,8 +15,11 @@
15 */ 15 */
16 package org.onosproject.provider.lldp.impl; 16 package org.onosproject.provider.lldp.impl;
17 17
18 +import com.fasterxml.jackson.databind.ObjectMapper;
18 import com.google.common.collect.ArrayListMultimap; 19 import com.google.common.collect.ArrayListMultimap;
19 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.ImmutableList;
21 +import com.google.common.collect.ImmutableMap;
22 +import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.Lists; 23 import com.google.common.collect.Lists;
21 import com.google.common.collect.Maps; 24 import com.google.common.collect.Maps;
22 import org.junit.After; 25 import org.junit.After;
...@@ -43,6 +46,11 @@ import org.onosproject.net.DeviceId; ...@@ -43,6 +46,11 @@ import org.onosproject.net.DeviceId;
43 import org.onosproject.net.MastershipRole; 46 import org.onosproject.net.MastershipRole;
44 import org.onosproject.net.Port; 47 import org.onosproject.net.Port;
45 import org.onosproject.net.PortNumber; 48 import org.onosproject.net.PortNumber;
49 +import org.onosproject.net.config.Config;
50 +import org.onosproject.net.config.ConfigApplyDelegate;
51 +import org.onosproject.net.config.NetworkConfigEvent;
52 +import org.onosproject.net.config.NetworkConfigListener;
53 +import org.onosproject.net.config.NetworkConfigRegistryAdapter;
46 import org.onosproject.net.device.DeviceEvent; 54 import org.onosproject.net.device.DeviceEvent;
47 import org.onosproject.net.device.DeviceListener; 55 import org.onosproject.net.device.DeviceListener;
48 import org.onosproject.net.device.DeviceServiceAdapter; 56 import org.onosproject.net.device.DeviceServiceAdapter;
...@@ -62,15 +70,25 @@ import org.onosproject.net.provider.AbstractProviderService; ...@@ -62,15 +70,25 @@ import org.onosproject.net.provider.AbstractProviderService;
62 import org.onosproject.net.provider.ProviderId; 70 import org.onosproject.net.provider.ProviderId;
63 71
64 import java.nio.ByteBuffer; 72 import java.nio.ByteBuffer;
65 -import java.util.Collections;
66 import java.util.HashMap; 73 import java.util.HashMap;
74 +import java.util.HashSet;
67 import java.util.List; 75 import java.util.List;
68 import java.util.Map; 76 import java.util.Map;
69 import java.util.Set; 77 import java.util.Set;
78 +import java.util.Collections;
70 import java.util.concurrent.CompletableFuture; 79 import java.util.concurrent.CompletableFuture;
71 80
72 -import static org.easymock.EasyMock.*; 81 +import static org.easymock.EasyMock.createMock;
73 -import static org.junit.Assert.*; 82 +import static org.easymock.EasyMock.expect;
83 +import static org.easymock.EasyMock.replay;
84 +
85 +import static org.junit.Assert.assertNull;
86 +import static org.junit.Assert.assertNotNull;
87 +import static org.junit.Assert.assertEquals;
88 +import static org.junit.Assert.assertTrue;
89 +import static org.onosproject.provider.lldp.impl.LldpLinkProvider.DEFAULT_RULES;
90 +import static org.junit.Assert.assertFalse;
91 +
74 92
75 public class LldpLinkProviderTest { 93 public class LldpLinkProviderTest {
76 94
...@@ -89,18 +107,23 @@ public class LldpLinkProviderTest { ...@@ -89,18 +107,23 @@ public class LldpLinkProviderTest {
89 private final TestPacketService packetService = new TestPacketService(); 107 private final TestPacketService packetService = new TestPacketService();
90 private final TestDeviceService deviceService = new TestDeviceService(); 108 private final TestDeviceService deviceService = new TestDeviceService();
91 private final TestMasterShipService masterService = new TestMasterShipService(); 109 private final TestMasterShipService masterService = new TestMasterShipService();
110 + private final TestNetworkConfigRegistry configRegistry = new TestNetworkConfigRegistry();
92 111
93 private CoreService coreService; 112 private CoreService coreService;
94 private TestLinkProviderService providerService; 113 private TestLinkProviderService providerService;
95 114
96 private PacketProcessor testProcessor; 115 private PacketProcessor testProcessor;
97 private DeviceListener deviceListener; 116 private DeviceListener deviceListener;
117 + private NetworkConfigListener configListener;
98 118
99 private ApplicationId appId = 119 private ApplicationId appId =
100 new DefaultApplicationId(100, "org.onosproject.provider.lldp"); 120 new DefaultApplicationId(100, "org.onosproject.provider.lldp");
101 121
122 + private TestSuppressionConfig cfg;
123 +
102 @Before 124 @Before
103 public void setUp() { 125 public void setUp() {
126 + cfg = new TestSuppressionConfig();
104 coreService = createMock(CoreService.class); 127 coreService = createMock(CoreService.class);
105 expect(coreService.registerApplication(appId.name())) 128 expect(coreService.registerApplication(appId.name()))
106 .andReturn(appId).anyTimes(); 129 .andReturn(appId).anyTimes();
...@@ -108,6 +131,7 @@ public class LldpLinkProviderTest { ...@@ -108,6 +131,7 @@ public class LldpLinkProviderTest {
108 131
109 provider.cfgService = new ComponentConfigAdapter(); 132 provider.cfgService = new ComponentConfigAdapter();
110 provider.coreService = coreService; 133 provider.coreService = coreService;
134 + provider.cfgRegistry = configRegistry;
111 135
112 provider.deviceService = deviceService; 136 provider.deviceService = deviceService;
113 provider.linkService = linkService; 137 provider.linkService = linkService;
...@@ -151,6 +175,7 @@ public class LldpLinkProviderTest { ...@@ -151,6 +175,7 @@ public class LldpLinkProviderTest {
151 */ 175 */
152 @Test 176 @Test
153 public void switchSuppressed() { 177 public void switchSuppressed() {
178 +
154 // add device to stub DeviceService 179 // add device to stub DeviceService
155 deviceService.putDevice(device(DID3)); 180 deviceService.putDevice(device(DID3));
156 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); 181 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
...@@ -163,7 +188,11 @@ public class LldpLinkProviderTest { ...@@ -163,7 +188,11 @@ public class LldpLinkProviderTest {
163 .build())); 188 .build()));
164 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3)); 189 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
165 190
166 - assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3)); 191 + // discovery on device is expected to be gone or stopped
192 + LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
193 + if (linkDiscovery != null) {
194 + assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
195 + }
167 } 196 }
168 197
169 @Test 198 @Test
...@@ -201,7 +230,7 @@ public class LldpLinkProviderTest { ...@@ -201,7 +230,7 @@ public class LldpLinkProviderTest {
201 * Checks that discovery on reconfigured switch are properly restarted. 230 * Checks that discovery on reconfigured switch are properly restarted.
202 */ 231 */
203 @Test 232 @Test
204 - public void portSuppressedByDeviceConfig() { 233 + public void portSuppressedByDeviceAnnotationConfig() {
205 234
206 /// When Device is configured with suppression:ON, Port also is same 235 /// When Device is configured with suppression:ON, Port also is same
207 236
...@@ -237,10 +266,91 @@ public class LldpLinkProviderTest { ...@@ -237,10 +266,91 @@ public class LldpLinkProviderTest {
237 } 266 }
238 267
239 /** 268 /**
269 + * Checks that discovery on reconfigured switch are properly restarted.
270 + */
271 + @Test
272 + public void portSuppressedByDeviceIdConfig() {
273 +
274 + /// When Device is configured without suppression:OFF,
275 + /// Port should be included for discovery
276 +
277 + // add device in stub DeviceService without suppression configured
278 + deviceService.putDevice(device(DID3));
279 + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
280 +
281 + // non-suppressed port added to suppressed device
282 + final long portno3 = 3L;
283 + deviceService.putPorts(DID3, port(DID3, portno3, true));
284 + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true)));
285 +
286 + // discovery should succeed
287 + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
288 + assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3));
289 +
290 + // add suppression rule for "deviceId: "of:0000000000000003""
291 + provider.updateRules(new SuppressionRules(ImmutableSet.of(DID3),
292 + ImmutableSet.of(),
293 + ImmutableMap.of()));
294 +
295 + /// When Device is reconfigured with suppression:ON, Port also is same
296 +
297 + // update device in stub DeviceService with suppression configured
298 + deviceService.putDevice(device(DID3));
299 + // update the Port in stub DeviceService. (Port has reference to Device)
300 + deviceService.putPorts(DID3, port(DID3, portno3, true));
301 + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
302 +
303 + // discovery on device is expected to be stopped
304 + LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
305 + if (linkDiscovery != null) {
306 + assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
307 + }
308 + }
309 +
310 + /**
311 + * Checks that discovery on reconfigured switch are properly restarted.
312 + */
313 + @Test
314 + public void portSuppressedByDeviceTypeConfig() {
315 +
316 + /// When Device is configured without suppression:OFF,
317 + /// Port should be included for discovery
318 +
319 + // add device in stub DeviceService without suppression configured
320 + deviceService.putDevice(device(DID1, Device.Type.SWITCH));
321 + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
322 +
323 + // non-suppressed port added to suppressed device
324 + final long portno3 = 3L;
325 + deviceService.putPorts(DID1, port(DID1, portno3, true));
326 + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, portno3, true)));
327 +
328 + // add device in stub DeviceService with suppression configured
329 + deviceService.putDevice(device(DID2, Device.Type.ROADM));
330 + deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID2));
331 +
332 + // non-suppressed port added to suppressed device
333 + final long portno4 = 4L;
334 + deviceService.putPorts(DID2, port(DID2, portno4, true));
335 + deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID2, port(DID2, portno4, true)));
336 +
337 + // discovery should succeed for this device
338 + assertFalse("Discoverer is expected to start", provider.discoverers.get(DID1).isStopped());
339 + assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID1).containsPort(portno3));
340 +
341 + // discovery on device is expected to be stopped for this device
342 + LinkDiscovery linkDiscovery = provider.discoverers.get(DID2);
343 + if (linkDiscovery != null) {
344 + assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
345 + }
346 + }
347 +
348 + /**
240 * Checks that discovery on reconfigured port are properly restarted. 349 * Checks that discovery on reconfigured port are properly restarted.
241 */ 350 */
242 @Test 351 @Test
243 public void portSuppressedByPortConfig() { 352 public void portSuppressedByPortConfig() {
353 +
244 // add device in stub DeviceService without suppression configured 354 // add device in stub DeviceService without suppression configured
245 deviceService.putDevice(device(DID3)); 355 deviceService.putDevice(device(DID3));
246 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3)); 356 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
...@@ -314,6 +424,11 @@ public class LldpLinkProviderTest { ...@@ -314,6 +424,11 @@ public class LldpLinkProviderTest {
314 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId()); 424 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
315 } 425 }
316 426
427 + private DefaultDevice device(DeviceId did, Device.Type type) {
428 + return new DefaultDevice(ProviderId.NONE, did, type,
429 + "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
430 + }
431 +
317 private DefaultDevice device(DeviceId did, Annotations annotations) { 432 private DefaultDevice device(DeviceId did, Annotations annotations) {
318 return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH, 433 return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
319 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations); 434 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations);
...@@ -367,6 +482,127 @@ public class LldpLinkProviderTest { ...@@ -367,6 +482,127 @@ public class LldpLinkProviderTest {
367 } 482 }
368 483
369 484
485 + @Test
486 + public void addDeviceIdRule() {
487 + DeviceId deviceId1 = DeviceId.deviceId("of:0000000000000001");
488 + DeviceId deviceId2 = DeviceId.deviceId("of:0000000000000002");
489 + Set<DeviceId> deviceIds = new HashSet<>();
490 +
491 + deviceIds.add(deviceId1);
492 + cfg.deviceIds(deviceIds);
493 +
494 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
495 +
496 + assertTrue(provider.rules().getSuppressedDevice().contains(deviceId1));
497 + assertFalse(provider.rules().getSuppressedDevice().contains(deviceId2));
498 + }
499 +
500 + @Test
501 + public void updateDeviceIdRule() {
502 + DeviceId deviceId1 = DeviceId.deviceId("of:0000000000000001");
503 + DeviceId deviceId2 = DeviceId.deviceId("of:0000000000000002");
504 + Set<DeviceId> deviceIds = new HashSet<>();
505 +
506 + deviceIds.add(deviceId1);
507 + cfg.deviceIds(deviceIds);
508 +
509 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
510 +
511 + deviceIds.add(deviceId2);
512 + cfg.deviceIds(deviceIds);
513 +
514 + configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
515 +
516 + assertTrue(provider.rules().getSuppressedDevice().contains(deviceId1));
517 + assertTrue(provider.rules().getSuppressedDevice().contains(deviceId2));
518 + }
519 +
520 + @Test
521 + public void addDeviceTypeRule() {
522 + Device.Type deviceType1 = Device.Type.ROADM;
523 + Device.Type deviceType2 = Device.Type.SWITCH;
524 +
525 + Set<Device.Type> deviceTypes = new HashSet<>();
526 + deviceTypes.add(deviceType1);
527 +
528 + cfg.deviceTypes(deviceTypes);
529 +
530 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
531 +
532 + assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType1));
533 + assertFalse(provider.rules().getSuppressedDeviceType().contains(deviceType2));
534 + }
535 +
536 + @Test
537 + public void updateDeviceTypeRule() {
538 + Device.Type deviceType1 = Device.Type.ROADM;
539 + Device.Type deviceType2 = Device.Type.SWITCH;
540 + Set<Device.Type> deviceTypes = new HashSet<>();
541 +
542 + deviceTypes.add(deviceType1);
543 + cfg.deviceTypes(deviceTypes);
544 +
545 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
546 +
547 + deviceTypes.add(deviceType2);
548 + cfg.deviceTypes(deviceTypes);
549 +
550 + configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
551 +
552 + assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType1));
553 + assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType2));
554 + }
555 +
556 + @Test
557 + public void addAnnotationRule() {
558 + final String key1 = "key1", key2 = "key2";
559 + final String value1 = "value1";
560 +
561 + Map<String, String> annotation = new HashMap<>();
562 + annotation.put(key1, value1);
563 +
564 + cfg.annotation(annotation);
565 +
566 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
567 +
568 + assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
569 + assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
570 + assertFalse(provider.rules().getSuppressedAnnotation().containsKey(key2));
571 + }
572 +
573 + @Test
574 + public void updateAnnotationRule() {
575 + final String key1 = "key1", key2 = "key2";
576 + final String value1 = "value1", value2 = "value2";
577 + Map<String, String> annotation = new HashMap<>();
578 +
579 + annotation.put(key1, value1);
580 + cfg.annotation(annotation);
581 +
582 + configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
583 +
584 + assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
585 + assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
586 + assertFalse(provider.rules().getSuppressedAnnotation().containsKey(key2));
587 +
588 + annotation.put(key2, value2);
589 + cfg.annotation(annotation);
590 +
591 + configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
592 +
593 + assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
594 + assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
595 + assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key2));
596 + assertEquals(value2, provider.rules().getSuppressedAnnotation().get(key2));
597 + }
598 +
599 + private void configEvent(NetworkConfigEvent.Type evType) {
600 + configListener.event(new NetworkConfigEvent(evType,
601 + appId,
602 + SuppressionConfig.class));
603 + }
604 +
605 +
370 private class TestLinkRegistry implements LinkProviderRegistry { 606 private class TestLinkRegistry implements LinkProviderRegistry {
371 607
372 @Override 608 @Override
...@@ -627,4 +863,58 @@ public class LldpLinkProviderTest { ...@@ -627,4 +863,58 @@ public class LldpLinkProviderTest {
627 863
628 private class TestLinkService extends LinkServiceAdapter { 864 private class TestLinkService extends LinkServiceAdapter {
629 } 865 }
866 +
867 + private final class TestNetworkConfigRegistry
868 + extends NetworkConfigRegistryAdapter {
869 + @Override
870 + public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
871 + ConfigApplyDelegate delegate = config -> { };
872 + ObjectMapper mapper = new ObjectMapper();
873 + return (C) cfg;
874 + }
875 +
876 + @Override
877 + public void addListener(NetworkConfigListener listener) {
878 + configListener = listener;
879 + }
880 + }
881 +
882 + private final class TestSuppressionConfig extends SuppressionConfig {
883 + private Set<DeviceId> deviceIds = new HashSet<>(DEFAULT_RULES.getSuppressedDevice());
884 + private Set<Device.Type> deviceTypes = new HashSet<>(DEFAULT_RULES.getSuppressedDeviceType());
885 + private Map<String, String> annotation = new HashMap<>(DEFAULT_RULES.getSuppressedAnnotation());
886 +
887 + @Override
888 + public Set<DeviceId> deviceIds() {
889 + return ImmutableSet.copyOf(deviceIds);
890 + }
891 +
892 + @Override
893 + public SuppressionConfig deviceIds(Set<DeviceId> deviceIds) {
894 + this.deviceIds = ImmutableSet.copyOf(deviceIds);
895 + return this;
896 + }
897 +
898 + @Override
899 + public Set<Device.Type> deviceTypes() {
900 + return ImmutableSet.copyOf(deviceTypes);
901 + }
902 +
903 + @Override
904 + public SuppressionConfig deviceTypes(Set<Device.Type> deviceTypes) {
905 + this.deviceTypes = ImmutableSet.copyOf(deviceTypes);
906 + return this;
907 + }
908 +
909 + @Override
910 + public Map<String, String> annotation() {
911 + return ImmutableMap.copyOf(annotation);
912 + }
913 +
914 + @Override
915 + public SuppressionConfig annotation(Map<String, String> annotation) {
916 + this.annotation = ImmutableMap.copyOf(annotation);
917 + return this;
918 + }
919 + }
630 } 920 }
......
1 +package org.onosproject.provider.lldp.impl;
2 +
3 +import static org.junit.Assert.*;
4 +
5 +import com.fasterxml.jackson.databind.ObjectMapper;
6 +import com.fasterxml.jackson.databind.node.JsonNodeFactory;
7 +import org.junit.Before;
8 +import org.junit.Test;
9 +import org.onosproject.TestApplicationId;
10 +import org.onosproject.net.Device;
11 +import org.onosproject.net.DeviceId;
12 +import org.onosproject.net.config.ConfigApplyDelegate;
13 +
14 +import java.util.HashMap;
15 +import java.util.HashSet;
16 +import java.util.Map;
17 +import java.util.Set;
18 +
19 +public class SuppressionConfigTest {
20 + private static final String APP_NAME = "SuppressionConfigTest";
21 + private static final TestApplicationId APP_ID = new TestApplicationId(APP_NAME);
22 + private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId("of:1111000000000000");
23 + private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId("of:2222000000000000");
24 + private static final Device.Type DEVICE_TYPE_1 = Device.Type.ROADM;
25 + private static final Device.Type DEVICE_TYPE_2 = Device.Type.FIBER_SWITCH;
26 + private static final String ANNOTATION_KEY_1 = "no_lldp";
27 + private static final String ANNOTATION_VALUE_1 = "true";
28 + private static final String ANNOTATION_KEY_2 = "sendLLDP";
29 + private static final String ANNOTATION_VALUE_2 = "false";
30 +
31 + private SuppressionConfig cfg;
32 +
33 + @Before
34 + public void setUp() throws Exception {
35 + ConfigApplyDelegate delegate = config -> { };
36 + ObjectMapper mapper = new ObjectMapper();
37 + cfg = new SuppressionConfig();
38 + cfg.init(APP_ID, LldpLinkProvider.CONFIG_KEY, JsonNodeFactory.instance.objectNode(), mapper, delegate);
39 + }
40 +
41 + @Test
42 + public void testDeviceIds() {
43 + Set<DeviceId> inputIds = new HashSet<DeviceId>() { {
44 + add(DEVICE_ID_1);
45 + add(DEVICE_ID_2);
46 + } };
47 +
48 + assertNotNull(cfg.deviceIds(inputIds));
49 +
50 + Set<DeviceId> outputIds = cfg.deviceIds();
51 + assertTrue(outputIds.contains(DEVICE_ID_1));
52 + assertTrue(outputIds.contains(DEVICE_ID_2));
53 + assertEquals(outputIds.size(), 2);
54 + }
55 +
56 + @Test
57 + public void testDeviceTypes() {
58 + Set<Device.Type> inputTypes = new HashSet<Device.Type>() { {
59 + add(DEVICE_TYPE_1);
60 + add(DEVICE_TYPE_2);
61 + } };
62 +
63 + assertNotNull(cfg.deviceTypes(inputTypes));
64 +
65 + Set<Device.Type> outputTypes = cfg.deviceTypes();
66 + assertTrue(outputTypes.contains(DEVICE_TYPE_1));
67 + assertTrue(outputTypes.contains(DEVICE_TYPE_2));
68 + assertEquals(outputTypes.size(), 2);
69 + }
70 +
71 + @Test
72 + public void testDeviceAnnotation() {
73 + Map<String, String> inputMap = new HashMap<String, String>() { {
74 + put(ANNOTATION_KEY_1, ANNOTATION_VALUE_1);
75 + put(ANNOTATION_KEY_2, ANNOTATION_VALUE_2);
76 + } };
77 +
78 + assertNotNull(cfg.annotation(inputMap));
79 +
80 + Map<String, String> outputMap = cfg.annotation();
81 + assertEquals(outputMap.get(ANNOTATION_KEY_1), ANNOTATION_VALUE_1);
82 + assertEquals(outputMap.get(ANNOTATION_KEY_2), ANNOTATION_VALUE_2);
83 + assertEquals(outputMap.size(), 2);
84 + }
85 +
86 +}
1 -/*
2 - * Copyright 2014-2015 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.lldp.impl;
18 -
19 -import static org.junit.Assert.*;
20 -import static org.onosproject.net.DeviceId.deviceId;
21 -
22 -import java.io.File;
23 -import java.io.IOException;
24 -import java.net.URISyntaxException;
25 -import java.nio.file.Path;
26 -import java.nio.file.Paths;
27 -
28 -import org.junit.Rule;
29 -import org.junit.Test;
30 -import org.junit.rules.TemporaryFolder;
31 -import org.onosproject.net.Device;
32 -
33 -import com.google.common.collect.ImmutableMap;
34 -import com.google.common.collect.ImmutableSet;
35 -import com.google.common.io.Resources;
36 -
37 -public class SuppressionRulesStoreTest {
38 -
39 - @Rule
40 - public TemporaryFolder tempFolder = new TemporaryFolder();
41 -
42 - // "lldp_suppression.json"
43 - SuppressionRules testData
44 - = new SuppressionRules(ImmutableSet.of(deviceId("of:2222000000000000")),
45 - ImmutableSet.of(Device.Type.ROADM),
46 - ImmutableMap.of("no-lldp", SuppressionRules.ANY_VALUE,
47 - "sendLLDP", "false"));
48 -
49 - private static void assertRulesEqual(SuppressionRules expected, SuppressionRules actual) {
50 - assertEquals(expected.getSuppressedDevice(),
51 - actual.getSuppressedDevice());
52 - assertEquals(expected.getSuppressedDeviceType(),
53 - actual.getSuppressedDeviceType());
54 - assertEquals(expected.getSuppressedAnnotation(),
55 - actual.getSuppressedAnnotation());
56 - }
57 -
58 - @Test
59 - public void testRead() throws URISyntaxException, IOException {
60 - Path path = Paths.get(Resources.getResource("lldp_suppression.json").toURI());
61 -
62 - SuppressionRulesStore store = new SuppressionRulesStore(path.toString());
63 -
64 - SuppressionRules rules = store.read();
65 -
66 - assertRulesEqual(testData, rules);
67 - }
68 -
69 - @Test
70 - public void testWrite() throws IOException {
71 - File newFile = tempFolder.newFile();
72 - SuppressionRulesStore store = new SuppressionRulesStore(newFile);
73 - store.write(testData);
74 -
75 - SuppressionRulesStore reload = new SuppressionRulesStore(newFile);
76 - SuppressionRules rules = reload.read();
77 -
78 - assertRulesEqual(testData, rules);
79 - }
80 -}
1 -{
2 - "deviceId" : [ "of:2222000000000000" ],
3 - "deviceType" : [ "ROADM" ],
4 - "annotation" : { "no-lldp" : null, "sendLLDP" : "false" }
5 -}
6 -
...@@ -62,5 +62,12 @@ ...@@ -62,5 +62,12 @@
62 ] 62 ]
63 } 63 }
64 } 64 }
65 + "org.onosproject.provider.lldp": {
66 + "suppression": {
67 + "deviceIds": [ "of:2222000000000000" ],
68 + "deviceTypes": [ "ROADM" ],
69 + "annotation": { "no-lldp": null, "sendLLDP" : "false" }
70 + }
71 + }
65 } 72 }
66 } 73 }
......