Committed by
Yuta Higuchi
Configuration to suppress LLDP discovery
Change-Id: I3b14df6682839f14694b69330a0943facd4f3a6f
Showing
8 changed files
with
633 additions
and
23 deletions
| ... | @@ -34,6 +34,11 @@ | ... | @@ -34,6 +34,11 @@ |
| 34 | 34 | ||
| 35 | <dependencies> | 35 | <dependencies> |
| 36 | <dependency> | 36 | <dependency> |
| 37 | + <groupId>org.osgi</groupId> | ||
| 38 | + <artifactId>org.osgi.compendium</artifactId> | ||
| 39 | + </dependency> | ||
| 40 | + | ||
| 41 | + <dependency> | ||
| 37 | <groupId>org.onosproject</groupId> | 42 | <groupId>org.onosproject</groupId> |
| 38 | <artifactId>onos-api</artifactId> | 43 | <artifactId>onos-api</artifactId> |
| 39 | <classifier>tests</classifier> | 44 | <classifier>tests</classifier> | ... | ... |
| ... | @@ -18,6 +18,8 @@ package org.onosproject.provider.lldp.impl; | ... | @@ -18,6 +18,8 @@ package org.onosproject.provider.lldp.impl; |
| 18 | import org.apache.felix.scr.annotations.Activate; | 18 | import org.apache.felix.scr.annotations.Activate; |
| 19 | import org.apache.felix.scr.annotations.Component; | 19 | import org.apache.felix.scr.annotations.Component; |
| 20 | import org.apache.felix.scr.annotations.Deactivate; | 20 | import org.apache.felix.scr.annotations.Deactivate; |
| 21 | +import org.apache.felix.scr.annotations.Modified; | ||
| 22 | +import org.apache.felix.scr.annotations.Property; | ||
| 21 | import org.apache.felix.scr.annotations.Reference; | 23 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 23 | import org.onosproject.mastership.MastershipEvent; | 25 | import org.onosproject.mastership.MastershipEvent; |
| ... | @@ -38,8 +40,16 @@ import org.onosproject.net.packet.PacketProcessor; | ... | @@ -38,8 +40,16 @@ import org.onosproject.net.packet.PacketProcessor; |
| 38 | import org.onosproject.net.packet.PacketService; | 40 | import org.onosproject.net.packet.PacketService; |
| 39 | import org.onosproject.net.provider.AbstractProvider; | 41 | import org.onosproject.net.provider.AbstractProvider; |
| 40 | import org.onosproject.net.provider.ProviderId; | 42 | import org.onosproject.net.provider.ProviderId; |
| 43 | +import org.osgi.service.component.ComponentContext; | ||
| 41 | import org.slf4j.Logger; | 44 | import org.slf4j.Logger; |
| 42 | 45 | ||
| 46 | +import com.google.common.base.Strings; | ||
| 47 | +import com.google.common.collect.ImmutableMap; | ||
| 48 | +import com.google.common.collect.ImmutableSet; | ||
| 49 | + | ||
| 50 | +import java.io.IOException; | ||
| 51 | +import java.util.Dictionary; | ||
| 52 | +import java.util.EnumSet; | ||
| 43 | import java.util.Map; | 53 | import java.util.Map; |
| 44 | import java.util.concurrent.ConcurrentHashMap; | 54 | import java.util.concurrent.ConcurrentHashMap; |
| 45 | import java.util.concurrent.ScheduledExecutorService; | 55 | import java.util.concurrent.ScheduledExecutorService; |
| ... | @@ -57,6 +67,13 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -57,6 +67,13 @@ import static org.slf4j.LoggerFactory.getLogger; |
| 57 | @Component(immediate = true) | 67 | @Component(immediate = true) |
| 58 | public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | 68 | public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 59 | 69 | ||
| 70 | + | ||
| 71 | + private static final String PROP_USE_BDDP = "useBDDP"; | ||
| 72 | + | ||
| 73 | + private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression"; | ||
| 74 | + | ||
| 75 | + private static final String DEFAULT_LLDP_SUPPRESSION_CONFIG = "../config/lldp_suppression.json"; | ||
| 76 | + | ||
| 60 | private final Logger log = getLogger(getClass()); | 77 | private final Logger log = getLogger(getClass()); |
| 61 | 78 | ||
| 62 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 79 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| ... | @@ -75,17 +92,26 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -75,17 +92,26 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 75 | 92 | ||
| 76 | private ScheduledExecutorService executor; | 93 | private ScheduledExecutorService executor; |
| 77 | 94 | ||
| 78 | - private final boolean useBDDP = true; | 95 | + @Property(name = PROP_USE_BDDP, boolValue = true, |
| 96 | + label = "use BDDP for link discovery") | ||
| 97 | + private boolean useBDDP = true; | ||
| 79 | 98 | ||
| 80 | private static final long INIT_DELAY = 5; | 99 | private static final long INIT_DELAY = 5; |
| 81 | private static final long DELAY = 5; | 100 | private static final long DELAY = 5; |
| 82 | 101 | ||
| 102 | + @Property(name = PROP_LLDP_SUPPRESSION, value = DEFAULT_LLDP_SUPPRESSION_CONFIG, | ||
| 103 | + label = "Path to LLDP suppression configuration file") | ||
| 104 | + private String filePath = DEFAULT_LLDP_SUPPRESSION_CONFIG; | ||
| 105 | + | ||
| 106 | + | ||
| 83 | private final InternalLinkProvider listener = new InternalLinkProvider(); | 107 | private final InternalLinkProvider listener = new InternalLinkProvider(); |
| 84 | 108 | ||
| 85 | private final InternalRoleListener roleListener = new InternalRoleListener(); | 109 | private final InternalRoleListener roleListener = new InternalRoleListener(); |
| 86 | 110 | ||
| 87 | protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>(); | 111 | protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>(); |
| 88 | 112 | ||
| 113 | + private SuppressionRules rules; | ||
| 114 | + | ||
| 89 | /** | 115 | /** |
| 90 | * Creates an OpenFlow link provider. | 116 | * Creates an OpenFlow link provider. |
| 91 | */ | 117 | */ |
| ... | @@ -95,6 +121,8 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -95,6 +121,8 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 95 | 121 | ||
| 96 | @Activate | 122 | @Activate |
| 97 | public void activate() { | 123 | public void activate() { |
| 124 | + loadSuppressionRules(); | ||
| 125 | + | ||
| 98 | providerService = providerRegistry.register(this); | 126 | providerService = providerRegistry.register(this); |
| 99 | deviceService.addListener(listener); | 127 | deviceService.addListener(listener); |
| 100 | packetSevice.addProcessor(listener, 0); | 128 | packetSevice.addProcessor(listener, 0); |
| ... | @@ -102,10 +130,19 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -102,10 +130,19 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 102 | 130 | ||
| 103 | LinkDiscovery ld; | 131 | LinkDiscovery ld; |
| 104 | for (Device device : deviceService.getAvailableDevices()) { | 132 | for (Device device : deviceService.getAvailableDevices()) { |
| 133 | + if (rules.isSuppressed(device)) { | ||
| 134 | + log.debug("LinkDiscovery from {} disabled by configuration", device.id()); | ||
| 135 | + continue; | ||
| 136 | + } | ||
| 105 | ld = new LinkDiscovery(device, packetSevice, masterService, | 137 | ld = new LinkDiscovery(device, packetSevice, masterService, |
| 106 | providerService, useBDDP); | 138 | providerService, useBDDP); |
| 107 | discoverers.put(device.id(), ld); | 139 | discoverers.put(device.id(), ld); |
| 108 | for (Port p : deviceService.getPorts(device.id())) { | 140 | for (Port p : deviceService.getPorts(device.id())) { |
| 141 | + if (rules.isSuppressed(p)) { | ||
| 142 | + log.debug("LinkDiscovery from {}@{} disabled by configuration", | ||
| 143 | + p.number(), device.id()); | ||
| 144 | + continue; | ||
| 145 | + } | ||
| 109 | if (!p.number().isLogical()) { | 146 | if (!p.number().isLogical()) { |
| 110 | ld.addPort(p); | 147 | ld.addPort(p); |
| 111 | } | 148 | } |
| ... | @@ -134,6 +171,45 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -134,6 +171,45 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 134 | log.info("Stopped"); | 171 | log.info("Stopped"); |
| 135 | } | 172 | } |
| 136 | 173 | ||
| 174 | + @Modified | ||
| 175 | + public void modified(ComponentContext context) { | ||
| 176 | + if (context == null) { | ||
| 177 | + return; | ||
| 178 | + } | ||
| 179 | + @SuppressWarnings("rawtypes") | ||
| 180 | + Dictionary properties = context.getProperties(); | ||
| 181 | + | ||
| 182 | + String s = (String) properties.get(PROP_USE_BDDP); | ||
| 183 | + if (Strings.isNullOrEmpty(s)) { | ||
| 184 | + useBDDP = true; | ||
| 185 | + } else { | ||
| 186 | + useBDDP = Boolean.valueOf(s); | ||
| 187 | + } | ||
| 188 | + s = (String) properties.get(PROP_LLDP_SUPPRESSION); | ||
| 189 | + if (Strings.isNullOrEmpty(s)) { | ||
| 190 | + filePath = DEFAULT_LLDP_SUPPRESSION_CONFIG; | ||
| 191 | + } else { | ||
| 192 | + filePath = s; | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + loadSuppressionRules(); | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + private void loadSuppressionRules() { | ||
| 199 | + SuppressionRulesStore store = new SuppressionRulesStore(filePath); | ||
| 200 | + try { | ||
| 201 | + rules = store.read(); | ||
| 202 | + } catch (IOException e) { | ||
| 203 | + log.info("Failed to load {}, using built-in rules", filePath); | ||
| 204 | + // default rule to suppress ROADM to maintain compatibility | ||
| 205 | + rules = new SuppressionRules(ImmutableSet.of(), | ||
| 206 | + EnumSet.of(Device.Type.ROADM), | ||
| 207 | + ImmutableMap.of()); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + // should refresh discoverers when we need dynamic reconfiguration | ||
| 211 | + } | ||
| 212 | + | ||
| 137 | private class InternalRoleListener implements MastershipListener { | 213 | private class InternalRoleListener implements MastershipListener { |
| 138 | 214 | ||
| 139 | @Override | 215 | @Override |
| ... | @@ -150,6 +226,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -150,6 +226,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 150 | log.warn("Device {} doesn't exist, or isn't there yet", deviceId); | 226 | log.warn("Device {} doesn't exist, or isn't there yet", deviceId); |
| 151 | return; | 227 | return; |
| 152 | } | 228 | } |
| 229 | + if (rules.isSuppressed(device)) { | ||
| 230 | + return; | ||
| 231 | + } | ||
| 153 | synchronized (discoverers) { | 232 | synchronized (discoverers) { |
| 154 | if (!discoverers.containsKey(deviceId)) { | 233 | if (!discoverers.containsKey(deviceId)) { |
| 155 | // ideally, should never reach here | 234 | // ideally, should never reach here |
| ... | @@ -180,20 +259,24 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -180,20 +259,24 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 180 | switch (event.type()) { | 259 | switch (event.type()) { |
| 181 | case DEVICE_ADDED: | 260 | case DEVICE_ADDED: |
| 182 | case DEVICE_UPDATED: | 261 | case DEVICE_UPDATED: |
| 183 | - synchronized (discoverers) { | 262 | + synchronized (discoverers) { |
| 184 | - ld = discoverers.get(deviceId); | 263 | + ld = discoverers.get(deviceId); |
| 185 | - if (ld == null) { | 264 | + if (ld == null) { |
| 186 | - log.debug("Device added ({}) {}", event.type(), | 265 | + if (rules.isSuppressed(device)) { |
| 187 | - deviceId); | 266 | + log.debug("LinkDiscovery from {} disabled by configuration", device.id()); |
| 188 | - discoverers.put(deviceId, new LinkDiscovery(device, | 267 | + return; |
| 189 | - packetSevice, masterService, providerService, | 268 | + } |
| 190 | - useBDDP)); | 269 | + log.debug("Device added ({}) {}", event.type(), |
| 191 | - } else { | 270 | + deviceId); |
| 192 | - if (ld.isStopped()) { | 271 | + discoverers.put(deviceId, new LinkDiscovery(device, |
| 193 | - log.debug("Device restarted ({}) {}", event.type(), | 272 | + packetSevice, masterService, providerService, |
| 194 | - deviceId); | 273 | + useBDDP)); |
| 195 | - ld.start(); | 274 | + } else { |
| 196 | - } | 275 | + if (ld.isStopped()) { |
| 276 | + log.debug("Device restarted ({}) {}", event.type(), | ||
| 277 | + deviceId); | ||
| 278 | + ld.start(); | ||
| 279 | + } | ||
| 197 | } | 280 | } |
| 198 | } | 281 | } |
| 199 | break; | 282 | break; |
| ... | @@ -204,6 +287,11 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -204,6 +287,11 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 204 | if (ld == null) { | 287 | if (ld == null) { |
| 205 | return; | 288 | return; |
| 206 | } | 289 | } |
| 290 | + if (rules.isSuppressed(port)) { | ||
| 291 | + log.debug("LinkDiscovery from {}@{} disabled by configuration", | ||
| 292 | + port.number(), device.id()); | ||
| 293 | + return; | ||
| 294 | + } | ||
| 207 | if (!port.number().isLogical()) { | 295 | if (!port.number().isLogical()) { |
| 208 | log.debug("Port added {}", port); | 296 | log.debug("Port added {}", port); |
| 209 | ld.addPort(port); | 297 | ld.addPort(port); |
| ... | @@ -280,6 +368,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -280,6 +368,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 280 | try { | 368 | try { |
| 281 | LinkDiscovery ld = null; | 369 | LinkDiscovery ld = null; |
| 282 | for (Device dev : deviceService.getDevices()) { | 370 | for (Device dev : deviceService.getDevices()) { |
| 371 | + if (rules.isSuppressed(dev)) { | ||
| 372 | + continue; | ||
| 373 | + } | ||
| 283 | DeviceId did = dev.id(); | 374 | DeviceId did = dev.id(); |
| 284 | synchronized (discoverers) { | 375 | synchronized (discoverers) { |
| 285 | if (!discoverers.containsKey(did)) { | 376 | if (!discoverers.containsKey(did)) { |
| ... | @@ -287,6 +378,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -287,6 +378,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { |
| 287 | masterService, providerService, useBDDP); | 378 | masterService, providerService, useBDDP); |
| 288 | discoverers.put(did, ld); | 379 | discoverers.put(did, ld); |
| 289 | for (Port p : deviceService.getPorts(did)) { | 380 | for (Port p : deviceService.getPorts(did)) { |
| 381 | + if (rules.isSuppressed(p)) { | ||
| 382 | + continue; | ||
| 383 | + } | ||
| 290 | if (!p.number().isLogical()) { | 384 | if (!p.number().isLogical()) { |
| 291 | ld.addPort(p); | 385 | ld.addPort(p); |
| 292 | } | 386 | } | ... | ... |
| ... | @@ -344,14 +344,12 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -344,14 +344,12 @@ public class LinkDiscovery implements TimerTask { |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | private void sendProbes(Long portNumber) { | 346 | private void sendProbes(Long portNumber) { |
| 347 | - if (device.type() != Device.Type.ROADM) { | 347 | + log.trace("Sending probes out to {}@{}", portNumber, device.id()); |
| 348 | - log.trace("Sending probes out to {}@{}", portNumber, device.id()); | 348 | + OutboundPacket pkt = this.createOutBoundLLDP(portNumber); |
| 349 | - OutboundPacket pkt = this.createOutBoundLLDP(portNumber); | 349 | + pktService.emit(pkt); |
| 350 | - pktService.emit(pkt); | 350 | + if (useBDDP) { |
| 351 | - if (useBDDP) { | 351 | + OutboundPacket bpkt = this.createOutBoundBDDP(portNumber); |
| 352 | - OutboundPacket bpkt = this.createOutBoundBDDP(portNumber); | 352 | + pktService.emit(bpkt); |
| 353 | - pktService.emit(bpkt); | ||
| 354 | - } | ||
| 355 | } | 353 | } |
| 356 | } | 354 | } |
| 357 | 355 | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.provider.lldp.impl; | ||
| 18 | + | ||
| 19 | +import java.util.Map; | ||
| 20 | +import java.util.Map.Entry; | ||
| 21 | +import java.util.Set; | ||
| 22 | + | ||
| 23 | +import org.onosproject.net.Annotations; | ||
| 24 | +import org.onosproject.net.Device; | ||
| 25 | +import org.onosproject.net.DeviceId; | ||
| 26 | +import org.onosproject.net.Element; | ||
| 27 | +import org.onosproject.net.Port; | ||
| 28 | + | ||
| 29 | +import com.google.common.collect.ImmutableMap; | ||
| 30 | +import com.google.common.collect.ImmutableSet; | ||
| 31 | + | ||
| 32 | +public class SuppressionRules { | ||
| 33 | + | ||
| 34 | + public static final String ANY_VALUE = "(any)"; | ||
| 35 | + | ||
| 36 | + private final Set<DeviceId> suppressedDevice; | ||
| 37 | + private final Set<Device.Type> suppressedDeviceType; | ||
| 38 | + private final Map<String, String> suppressedAnnotation; | ||
| 39 | + | ||
| 40 | + public SuppressionRules(Set<DeviceId> suppressedDevice, | ||
| 41 | + Set<Device.Type> suppressedType, | ||
| 42 | + Map<String, String> suppressedAnnotation) { | ||
| 43 | + | ||
| 44 | + this.suppressedDevice = ImmutableSet.copyOf(suppressedDevice); | ||
| 45 | + this.suppressedDeviceType = ImmutableSet.copyOf(suppressedType); | ||
| 46 | + this.suppressedAnnotation = ImmutableMap.copyOf(suppressedAnnotation); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public boolean isSuppressed(Device device) { | ||
| 50 | + if (suppressedDevice.contains(device.id())) { | ||
| 51 | + return true; | ||
| 52 | + } | ||
| 53 | + if (suppressedDeviceType.contains(device.type())) { | ||
| 54 | + return true; | ||
| 55 | + } | ||
| 56 | + final Annotations annotations = device.annotations(); | ||
| 57 | + if (containsSuppressionAnnotation(annotations)) { | ||
| 58 | + return true; | ||
| 59 | + } | ||
| 60 | + return false; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public boolean isSuppressed(Port port) { | ||
| 64 | + Element parent = port.element(); | ||
| 65 | + if (parent instanceof Device) { | ||
| 66 | + if (isSuppressed((Device) parent)) { | ||
| 67 | + return true; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + final Annotations annotations = port.annotations(); | ||
| 72 | + if (containsSuppressionAnnotation(annotations)) { | ||
| 73 | + return true; | ||
| 74 | + } | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + private boolean containsSuppressionAnnotation(final Annotations annotations) { | ||
| 79 | + for (Entry<String, String> entry : suppressedAnnotation.entrySet()) { | ||
| 80 | + final String suppValue = entry.getValue(); | ||
| 81 | + final String suppKey = entry.getKey(); | ||
| 82 | + if (suppValue == ANY_VALUE) { | ||
| 83 | + if (annotations.keys().contains(suppKey)) { | ||
| 84 | + return true; | ||
| 85 | + } | ||
| 86 | + } else { | ||
| 87 | + if (suppValue.equals(annotations.value(suppKey))) { | ||
| 88 | + return true; | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + return false; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + Set<DeviceId> getSuppressedDevice() { | ||
| 96 | + return suppressedDevice; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + Set<Device.Type> getSuppressedDeviceType() { | ||
| 100 | + return suppressedDeviceType; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + Map<String, String> getSuppressedAnnotation() { | ||
| 104 | + return suppressedAnnotation; | ||
| 105 | + } | ||
| 106 | +} |
providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRulesStore.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 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 | ||
| 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 | ||
| 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 | +} |
providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionRulesStoreTest.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 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 | +} |
providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionRulesTest.java
0 → 100644
| 1 | +package org.onosproject.provider.lldp.impl; | ||
| 2 | + | ||
| 3 | +import static org.junit.Assert.*; | ||
| 4 | +import static org.onosproject.net.DeviceId.deviceId; | ||
| 5 | + | ||
| 6 | +import org.junit.Before; | ||
| 7 | +import org.junit.Test; | ||
| 8 | +import org.onlab.packet.ChassisId; | ||
| 9 | +import org.onosproject.net.Annotations; | ||
| 10 | +import org.onosproject.net.DefaultAnnotations; | ||
| 11 | +import org.onosproject.net.DefaultDevice; | ||
| 12 | +import org.onosproject.net.DefaultPort; | ||
| 13 | +import org.onosproject.net.Device; | ||
| 14 | +import org.onosproject.net.DeviceId; | ||
| 15 | +import org.onosproject.net.Port; | ||
| 16 | +import org.onosproject.net.PortNumber; | ||
| 17 | +import org.onosproject.net.provider.ProviderId; | ||
| 18 | + | ||
| 19 | +import com.google.common.collect.ImmutableMap; | ||
| 20 | +import com.google.common.collect.ImmutableSet; | ||
| 21 | + | ||
| 22 | +public class SuppressionRulesTest { | ||
| 23 | + | ||
| 24 | + private static final DeviceId NON_SUPPRESSED_DID = deviceId("of:1111000000000000"); | ||
| 25 | + private static final DeviceId SUPPRESSED_DID = deviceId("of:2222000000000000"); | ||
| 26 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
| 27 | + private static final String MFR = "whitebox"; | ||
| 28 | + private static final String HW = "1.1.x"; | ||
| 29 | + private static final String SW1 = "3.8.1"; | ||
| 30 | + private static final String SN = "43311-12345"; | ||
| 31 | + private static final ChassisId CID = new ChassisId(); | ||
| 32 | + | ||
| 33 | + private static final PortNumber P1 = PortNumber.portNumber(1); | ||
| 34 | + | ||
| 35 | + private SuppressionRules rules; | ||
| 36 | + | ||
| 37 | + @Before | ||
| 38 | + public void setUp() throws Exception { | ||
| 39 | + rules = new SuppressionRules(ImmutableSet.of(SUPPRESSED_DID), | ||
| 40 | + ImmutableSet.of(Device.Type.ROADM), | ||
| 41 | + ImmutableMap.of("no-lldp", SuppressionRules.ANY_VALUE, | ||
| 42 | + "sendLLDP", "false")); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Test | ||
| 46 | + public void testSuppressedDeviceId() { | ||
| 47 | + Device device = new DefaultDevice(PID, | ||
| 48 | + SUPPRESSED_DID, | ||
| 49 | + Device.Type.SWITCH, | ||
| 50 | + MFR, HW, SW1, SN, CID); | ||
| 51 | + assertTrue(rules.isSuppressed(device)); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + public void testSuppressedDeviceType() { | ||
| 56 | + Device device = new DefaultDevice(PID, | ||
| 57 | + NON_SUPPRESSED_DID, | ||
| 58 | + Device.Type.ROADM, | ||
| 59 | + MFR, HW, SW1, SN, CID); | ||
| 60 | + assertTrue(rules.isSuppressed(device)); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + @Test | ||
| 64 | + public void testSuppressedDeviceAnnotation() { | ||
| 65 | + Annotations annotation = DefaultAnnotations.builder() | ||
| 66 | + .set("no-lldp", "random") | ||
| 67 | + .build(); | ||
| 68 | + | ||
| 69 | + Device device = new DefaultDevice(PID, | ||
| 70 | + NON_SUPPRESSED_DID, | ||
| 71 | + Device.Type.SWITCH, | ||
| 72 | + MFR, HW, SW1, SN, CID, annotation); | ||
| 73 | + assertTrue(rules.isSuppressed(device)); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @Test | ||
| 77 | + public void testSuppressedDeviceAnnotationExact() { | ||
| 78 | + Annotations annotation = DefaultAnnotations.builder() | ||
| 79 | + .set("sendLLDP", "false") | ||
| 80 | + .build(); | ||
| 81 | + | ||
| 82 | + Device device = new DefaultDevice(PID, | ||
| 83 | + NON_SUPPRESSED_DID, | ||
| 84 | + Device.Type.SWITCH, | ||
| 85 | + MFR, HW, SW1, SN, CID, annotation); | ||
| 86 | + assertTrue(rules.isSuppressed(device)); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Test | ||
| 90 | + public void testNotSuppressedDevice() { | ||
| 91 | + Device device = new DefaultDevice(PID, | ||
| 92 | + NON_SUPPRESSED_DID, | ||
| 93 | + Device.Type.SWITCH, | ||
| 94 | + MFR, HW, SW1, SN, CID); | ||
| 95 | + assertFalse(rules.isSuppressed(device)); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + @Test | ||
| 99 | + public void testSuppressedPortOnSuppressedDevice() { | ||
| 100 | + Device device = new DefaultDevice(PID, | ||
| 101 | + SUPPRESSED_DID, | ||
| 102 | + Device.Type.SWITCH, | ||
| 103 | + MFR, HW, SW1, SN, CID); | ||
| 104 | + Port port = new DefaultPort(device, P1, true); | ||
| 105 | + | ||
| 106 | + assertTrue(rules.isSuppressed(port)); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + @Test | ||
| 110 | + public void testSuppressedPortAnnotation() { | ||
| 111 | + Annotations annotation = DefaultAnnotations.builder() | ||
| 112 | + .set("no-lldp", "random") | ||
| 113 | + .build(); | ||
| 114 | + Device device = new DefaultDevice(PID, | ||
| 115 | + NON_SUPPRESSED_DID, | ||
| 116 | + Device.Type.SWITCH, | ||
| 117 | + MFR, HW, SW1, SN, CID); | ||
| 118 | + Port port = new DefaultPort(device, P1, true, annotation); | ||
| 119 | + | ||
| 120 | + assertTrue(rules.isSuppressed(port)); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + @Test | ||
| 124 | + public void testSuppressedPortAnnotationExact() { | ||
| 125 | + Annotations annotation = DefaultAnnotations.builder() | ||
| 126 | + .set("sendLLDP", "false") | ||
| 127 | + .build(); | ||
| 128 | + Device device = new DefaultDevice(PID, | ||
| 129 | + NON_SUPPRESSED_DID, | ||
| 130 | + Device.Type.SWITCH, | ||
| 131 | + MFR, HW, SW1, SN, CID); | ||
| 132 | + Port port = new DefaultPort(device, P1, true, annotation); | ||
| 133 | + | ||
| 134 | + assertTrue(rules.isSuppressed(port)); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + @Test | ||
| 138 | + public void testNotSuppressedPort() { | ||
| 139 | + Device device = new DefaultDevice(PID, | ||
| 140 | + NON_SUPPRESSED_DID, | ||
| 141 | + Device.Type.SWITCH, | ||
| 142 | + MFR, HW, SW1, SN, CID); | ||
| 143 | + Port port = new DefaultPort(device, P1, true); | ||
| 144 | + | ||
| 145 | + assertFalse(rules.isSuppressed(port)); | ||
| 146 | + } | ||
| 147 | +} |
-
Please register or login to post a comment