[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
diff --git a/core/api/src/main/java/org/onosproject/net/config/Config.java b/core/api/src/main/java/org/onosproject/net/config/Config.java
index 3757d32..5f2c9f3 100644
--- a/core/api/src/main/java/org/onosproject/net/config/Config.java
+++ b/core/api/src/main/java/org/onosproject/net/config/Config.java
@@ -333,6 +333,26 @@
     }
 
     /**
+     * Gets the specified array property as a list of items.
+     *
+     * @param name     property name
+     * @param function mapper from string to item
+     * @param defaultValue default value if property not set
+     * @param <T>      type of item
+     * @return list of items
+     */
+    protected <T> List<T> getList(String name, Function<String, T> function, List<T> defaultValue) {
+        List<T> list = Lists.newArrayList();
+        JsonNode jsonNode = object.path(name);
+        if (jsonNode.isMissingNode()) {
+            return defaultValue;
+        }
+        ArrayNode arrayNode = (ArrayNode) jsonNode;
+        arrayNode.forEach(i -> list.add(function.apply(i.asText())));
+        return list;
+    }
+
+    /**
      * Sets the specified property as an array of items in a given collection or
      * clears it if null is given.
      *
diff --git a/providers/lldp/pom.xml b/providers/lldp/pom.xml
index 7bf92ed..f905276 100644
--- a/providers/lldp/pom.xml
+++ b/providers/lldp/pom.xml
@@ -55,5 +55,9 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
index d723ce1..1b16e51 100644
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LldpLinkProvider.java
@@ -38,6 +38,9 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.LinkKey;
 import org.onosproject.net.Port;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
@@ -58,12 +61,12 @@
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
-import java.io.IOException;
 import java.util.Dictionary;
 import java.util.EnumSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledExecutorService;
 
@@ -75,6 +78,7 @@
 import static org.onlab.util.Tools.get;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -87,12 +91,11 @@
 
     private static final String FORMAT =
             "Settings: enabled={}, useBDDP={}, probeRate={}, " +
-                    "staleLinkAge={}, lldpSuppression={}";
+                    "staleLinkAge={}";
 
     // When a Device/Port has this annotation, do not send out LLDP/BDDP
     public static final String NO_LLDP = "no-lldp";
 
-
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -152,13 +155,6 @@
             label = "Number of millis beyond which links will be considered stale")
     private int staleLinkAge = DEFAULT_STALE_LINK_AGE;
 
-    // FIXME: convert to use network config subsystem instead
-    private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression";
-    private static final String DEFAULT_LLDP_SUPPRESSION_CONFIG = "../config/lldp_suppression.json";
-    @Property(name = PROP_LLDP_SUPPRESSION, value = DEFAULT_LLDP_SUPPRESSION_CONFIG,
-            label = "Path to LLDP suppression configuration file")
-    private String lldpSuppression = DEFAULT_LLDP_SUPPRESSION_CONFIG;
-
     private final DiscoveryContext context = new InternalDiscoveryContext();
     private final InternalRoleListener roleListener = new InternalRoleListener();
     private final InternalDeviceListener deviceListener = new InternalDeviceListener();
@@ -171,9 +167,31 @@
     // destination connection point is mastered by this controller instance.
     private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap();
 
-    private SuppressionRules rules;
     private ApplicationId appId;
 
+    static final SuppressionRules DEFAULT_RULES
+        = new SuppressionRules(ImmutableSet.of(),
+                               EnumSet.of(Device.Type.ROADM),
+                               ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
+
+    private SuppressionRules rules = LldpLinkProvider.DEFAULT_RULES;
+
+    public static final String CONFIG_KEY = "suppression";
+
+    private final Set<ConfigFactory> factories = ImmutableSet.of(
+            new ConfigFactory<ApplicationId, SuppressionConfig>(APP_SUBJECT_FACTORY,
+                    SuppressionConfig.class,
+                    CONFIG_KEY) {
+                @Override
+                public SuppressionConfig createConfig() {
+                    return new SuppressionConfig();
+                }
+            }
+    );
+
+    private final InternalConfigListener cfgListener = new InternalConfigListener();
+
+
     /**
      * Creates an OpenFlow link provider.
      */
@@ -185,12 +203,30 @@
     public void activate(ComponentContext context) {
         cfgService.registerProperties(getClass());
         appId = coreService.registerApplication(PROVIDER_NAME);
+
+        cfgRegistry.addListener(cfgListener);
+        factories.forEach(cfgRegistry::registerConfigFactory);
+
+        SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
+        if (cfg == null) {
+            // If no configuration is found, register default.
+            cfg = cfgRegistry.addConfig(appId, SuppressionConfig.class);
+            cfg.deviceIds(DEFAULT_RULES.getSuppressedDevice())
+               .deviceTypes(DEFAULT_RULES.getSuppressedDeviceType())
+               .annotation(DEFAULT_RULES.getSuppressedAnnotation())
+               .apply();
+        }
+        cfgListener.reconfigureSuppressionRules(cfg);
+
         modified(context);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        cfgRegistry.removeListener(cfgListener);
+        factories.forEach(cfgRegistry::unregisterConfigFactory);
+
         cfgService.unregisterProperties(getClass(), false);
         disable();
         log.info("Stopped");
@@ -202,7 +238,6 @@
 
         boolean newEnabled, newUseBddp;
         int newProbeRate, newStaleLinkAge;
-        String newLldpSuppression;
         try {
             String s = get(properties, PROP_ENABLED);
             newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
@@ -216,16 +251,12 @@
             s = get(properties, PROP_STALE_LINK_AGE);
             newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim());
 
-            s = get(properties, PROP_LLDP_SUPPRESSION);
-            newLldpSuppression = isNullOrEmpty(s) ? DEFAULT_LLDP_SUPPRESSION_CONFIG : s;
-
         } catch (NumberFormatException e) {
             log.warn("Component configuration had invalid values", e);
             newEnabled = enabled;
             newUseBddp = useBddp;
             newProbeRate = probeRate;
             newStaleLinkAge = staleLinkAge;
-            newLldpSuppression = lldpSuppression;
         }
 
         boolean wasEnabled = enabled;
@@ -234,23 +265,19 @@
         useBddp = newUseBddp;
         probeRate = newProbeRate;
         staleLinkAge = newStaleLinkAge;
-        lldpSuppression = newLldpSuppression;
 
         if (!wasEnabled && enabled) {
             enable();
         } else if (wasEnabled && !enabled) {
             disable();
         } else {
-            // reflect changes in suppression rules to discovery helpers
-            // FIXME: After migrating to Network Configuration Subsystem,
-            //        it should be possible to update only changed subset
             if (enabled) {
                 // update all discovery helper state
                 loadDevices();
             }
         }
 
-        log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge, lldpSuppression);
+        log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge);
     }
 
     /**
@@ -262,7 +289,6 @@
         deviceService.addListener(deviceListener);
         packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
 
-        loadSuppressionRules();
         loadDevices();
 
         executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d"));
@@ -285,6 +311,7 @@
         deviceService.removeListener(deviceListener);
         packetService.removeProcessor(packetProcessor);
 
+
         if (executor != null) {
             executor.shutdownNow();
         }
@@ -298,6 +325,9 @@
      * Loads available devices and registers their ports to be probed.
      */
     private void loadDevices() {
+        if (!enabled) {
+            return;
+        }
         deviceService.getAvailableDevices()
                 .forEach(d -> updateDevice(d)
                                .ifPresent(ld -> updatePorts(ld, d.id())));
@@ -333,7 +363,6 @@
     private void removeDevice(final DeviceId deviceId) {
         discoverers.computeIfPresent(deviceId, (did, ld) -> {
             ld.stop();
-            providerService.linksVanished(deviceId);
             return null;
         });
 
@@ -357,6 +386,7 @@
             // silently ignore logical ports
             return;
         }
+
         if (rules.isSuppressed(port)) {
             log.trace("LinkDiscovery from {} disabled by configuration", port);
             removePort(port);
@@ -383,35 +413,12 @@
             if (ld != null) {
                 ld.removePort(port.number());
             }
-
-            ConnectPoint point = new ConnectPoint(d.id(), port.number());
-            providerService.linksVanished(point);
         } else {
             log.warn("Attempted to remove non-Device port", port);
         }
     }
 
     /**
-     * Loads LLDP suppression rules.
-     */
-    private void loadSuppressionRules() {
-        // FIXME: convert to use network configuration
-        SuppressionRulesStore store = new SuppressionRulesStore(lldpSuppression);
-        try {
-            log.info("Reading suppression rules from {}", lldpSuppression);
-            rules = store.read();
-        } catch (IOException e) {
-            log.info("Failed to load {}, using built-in rules", lldpSuppression);
-            // default rule to suppress ROADM to maintain compatibility
-            rules = new SuppressionRules(ImmutableSet.of(),
-                                         EnumSet.of(Device.Type.ROADM),
-                                         ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
-        }
-
-        // should refresh discoverers when we need dynamic reconfiguration
-    }
-
-    /**
      * Requests packet intercepts.
      */
     private void requestIntercepts() {
@@ -438,6 +445,17 @@
         packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
     }
 
+    protected SuppressionRules rules() {
+        return rules;
+    }
+
+    protected void updateRules(SuppressionRules newRules) {
+        if (!rules.equals(newRules)) {
+            rules = newRules;
+            loadDevices();
+        }
+    }
+
     /**
      * Processes device mastership role changes.
      */
@@ -459,7 +477,6 @@
                 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
             }
         }
-
     }
 
     /**
@@ -488,16 +505,21 @@
                     } else {
                         log.debug("Port down {}", port);
                         removePort(port);
+                        providerService.linksVanished(new ConnectPoint(port.element().id(),
+                                                                       port.number()));
                     }
                     break;
                 case PORT_REMOVED:
                     log.debug("Port removed {}", port);
                     removePort(port);
+                    providerService.linksVanished(new ConnectPoint(port.element().id(),
+                                                                   port.number()));
                     break;
                 case DEVICE_REMOVED:
                 case DEVICE_SUSPENDED:
                     log.debug("Device removed {}", deviceId);
                     removeDevice(deviceId);
+                    providerService.linksVanished(deviceId);
                     break;
                 case DEVICE_AVAILABILITY_CHANGED:
                     if (deviceService.isAvailable(deviceId)) {
@@ -506,6 +528,7 @@
                     } else {
                         log.debug("Device down {}", deviceId);
                         removeDevice(deviceId);
+                        providerService.linksVanished(deviceId);
                     }
                     break;
                 case PORT_STATS_UPDATED:
@@ -636,4 +659,30 @@
         }
     }
 
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        private synchronized void reconfigureSuppressionRules(SuppressionConfig cfg) {
+            if (cfg == null) {
+                log.error("Suppression Config is null.");
+                return;
+            }
+
+            SuppressionRules newRules = new SuppressionRules(cfg.deviceIds(),
+                                                             cfg.deviceTypes(),
+                                                             cfg.annotation());
+
+            updateRules(newRules);
+        }
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (event.configClass().equals(SuppressionConfig.class) &&
+                (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) {
+                SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
+                reconfigureSuppressionRules(cfg);
+                log.trace("Network config reconfigured");
+            }
+        }
+    }
 }
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionConfig.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionConfig.java
new file mode 100644
index 0000000..20bafb3
--- /dev/null
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionConfig.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.provider.lldp.impl;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import static org.onosproject.provider.lldp.impl.LldpLinkProvider.DEFAULT_RULES;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * LLDP suppression config class.
+ */
+public class SuppressionConfig extends Config<ApplicationId> {
+    private static final String DEVICE_IDS = "deviceIds";
+    private static final String DEVICE_TYPES = "deviceTypes";
+    private static final String ANNOTATION = "annotation";
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+    private static final List<DeviceId>  DEFAULT_DEVICE_IDS
+                    = ImmutableList.copyOf(DEFAULT_RULES.getSuppressedDevice());
+    private static final List<Device.Type>  DEFAULT_DEVICE_TYPES
+                = ImmutableList.copyOf(DEFAULT_RULES.getSuppressedDeviceType());
+
+    private final Logger log = getLogger(getClass());
+
+    /**
+     * Returns device IDs on which LLDP is suppressed.
+     *
+     * @return Set of DeviceId objects
+     */
+    @Deprecated
+    public Set<DeviceId> deviceIds() {
+        return ImmutableSet.copyOf(getList(DEVICE_IDS, DeviceId::deviceId, DEFAULT_DEVICE_IDS));
+    }
+
+    /**
+     * Sets device IDs on which LLDP is suppressed.
+     *
+     * @param deviceIds new set of device IDs; null to clear
+     * @return self
+     */
+    @Deprecated
+    public SuppressionConfig deviceIds(Set<DeviceId> deviceIds) {
+        return (SuppressionConfig) setOrClear(DEVICE_IDS, deviceIds);
+    }
+
+    /**
+     * Returns types of devices on which LLDP is suppressed.
+     *
+     * @return set of device types
+     */
+    public Set<Device.Type> deviceTypes() {
+        return ImmutableSet.copyOf(getList(DEVICE_TYPES, Device.Type::valueOf, DEFAULT_DEVICE_TYPES));
+    }
+
+    /**
+     * Sets types of devices on which LLDP is suppressed.
+     *
+     * @param deviceTypes new set of device types; null to clear
+     * @return self
+     */
+    public SuppressionConfig deviceTypes(Set<Device.Type> deviceTypes) {
+        return (SuppressionConfig) setOrClear(DEVICE_TYPES, deviceTypes);
+    }
+
+    /**
+     * Returns annotation of Ports on which LLDP is suppressed.
+     *
+     * @return key-value pairs of annotation
+     */
+    public Map<String, String> annotation() {
+        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+
+        String jsonAnnotation = get(ANNOTATION, null);
+        if (jsonAnnotation == null || jsonAnnotation.isEmpty()) {
+            return ImmutableMap.of();
+        }
+
+        JsonNode annotationNode;
+        try {
+            annotationNode = MAPPER.readTree(jsonAnnotation);
+        } catch (IOException e) {
+            log.error("Failed to read JSON tree from: {}", jsonAnnotation);
+            return ImmutableMap.of();
+        }
+
+        if (annotationNode.isObject()) {
+            ObjectNode obj = (ObjectNode) annotationNode;
+            Iterator<Map.Entry<String, JsonNode>> it = obj.fields();
+            while (it.hasNext()) {
+                Map.Entry<String, JsonNode> entry = it.next();
+                final String key = entry.getKey();
+                final JsonNode value = entry.getValue();
+
+                if (value.isValueNode()) {
+                    if (value.isNull()) {
+                        builder.put(key, SuppressionRules.ANY_VALUE);
+                    } else {
+                        builder.put(key, value.asText());
+                    }
+                } else {
+                    log.warn("Encountered unexpected JSON field {} for annotation", entry);
+                }
+            }
+        } else {
+            log.error("Encountered unexpected JSONNode {} for annotation", annotationNode);
+            return ImmutableMap.of();
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Sets annotation of Ports on which LLDP is suppressed.
+     *
+     * @param annotation new key-value pair of annotation; null to clear
+     * @return self
+     */
+    public SuppressionConfig annotation(Map<String, String> annotation) {
+
+        // ANY_VALUE should be null in JSON
+        Map<String, String> config = Maps.transformValues(annotation,
+                      v -> (v == SuppressionRules.ANY_VALUE) ? null : v);
+
+        String jsonAnnotation = null;
+
+        try {
+            // TODO Store annotation as a Map instead of a String (which needs NetworkConfigRegistry modification)
+            jsonAnnotation = MAPPER.writeValueAsString(config);
+        } catch (JsonProcessingException e) {
+            log.error("Failed to write JSON from: {}", annotation);
+        }
+
+        return (SuppressionConfig) setOrClear(ANNOTATION, jsonAnnotation);
+    }
+}
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRules.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRules.java
index 27c75eb..9cda07c 100644
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRules.java
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRules.java
@@ -18,6 +18,7 @@
 
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 
 import org.onosproject.net.Annotations;
@@ -28,6 +29,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.base.MoreObjects;
 
 public class SuppressionRules {
 
@@ -103,4 +105,34 @@
     Map<String, String> getSuppressedAnnotation() {
         return suppressedAnnotation;
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(suppressedDevice,
+                            suppressedDeviceType,
+                            suppressedAnnotation);
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if (object != null && getClass() == object.getClass()) {
+            SuppressionRules that = (SuppressionRules) object;
+            return Objects.equals(this.suppressedDevice,
+                                  that.suppressedDevice)
+                    && Objects.equals(this.suppressedDeviceType,
+                                      that.suppressedDeviceType)
+                    && Objects.equals(this.suppressedAnnotation,
+                                      that.suppressedAnnotation);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("suppressedDevice", suppressedDevice)
+                .add("suppressedDeviceType", suppressedDeviceType)
+                .add("suppressedAnnotation", suppressedAnnotation)
+                .toString();
+    }
 }
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRulesStore.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRulesStore.java
deleted file mode 100644
index 360bebd..0000000
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/SuppressionRulesStore.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2014-2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.provider.lldp.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import com.fasterxml.jackson.core.JsonEncoding;
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.slf4j.Logger;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/*
- * JSON file example
- *
-
-{
-  "deviceId" : [ "of:2222000000000000" ],
-  "deviceType" : [ "ROADM" ],
-  "annotation" : { "no-lldp" : null, "sendLLDP" : "false" }
-}
- */
-
-/**
- * Allows for reading and writing LLDP suppression definition as a JSON file.
- */
-public class SuppressionRulesStore {
-
-    private static final String DEVICE_ID = "deviceId";
-    private static final String DEVICE_TYPE = "deviceType";
-    private static final String ANNOTATION = "annotation";
-
-    private final Logger log = getLogger(getClass());
-
-    private final File file;
-
-    /**
-     * Creates a reader/writer of the LLDP suppression definition file.
-     *
-     * @param filePath location of the definition file
-     */
-    public SuppressionRulesStore(String filePath) {
-        file = new File(filePath);
-    }
-
-    /**
-     * Creates a reader/writer of the LLDP suppression definition file.
-     *
-     * @param file definition file
-     */
-    public SuppressionRulesStore(File file) {
-        this.file = checkNotNull(file);
-    }
-
-    /**
-     * Returns SuppressionRules.
-     *
-     * @return SuppressionRules
-     * @throws IOException if error occurred while reading the data
-     */
-    public SuppressionRules read() throws IOException {
-        final Set<DeviceId> suppressedDevice = new HashSet<>();
-        final EnumSet<Device.Type> suppressedDeviceType = EnumSet.noneOf(Device.Type.class);
-        final Map<String, String> suppressedAnnotation = new HashMap<>();
-
-        ObjectMapper mapper = new ObjectMapper();
-        ObjectNode root = (ObjectNode) mapper.readTree(file);
-
-        for (JsonNode deviceId : root.get(DEVICE_ID)) {
-            if (deviceId.isTextual()) {
-                suppressedDevice.add(DeviceId.deviceId(deviceId.asText()));
-            } else {
-                log.warn("Encountered unexpected JSONNode {} for deviceId", deviceId);
-            }
-        }
-
-        for (JsonNode deviceType : root.get(DEVICE_TYPE)) {
-            if (deviceType.isTextual()) {
-                suppressedDeviceType.add(Device.Type.valueOf(deviceType.asText()));
-            } else {
-                log.warn("Encountered unexpected JSONNode {} for deviceType", deviceType);
-            }
-        }
-
-        JsonNode annotation = root.get(ANNOTATION);
-        if (annotation.isObject()) {
-            ObjectNode obj = (ObjectNode) annotation;
-            Iterator<Entry<String, JsonNode>> it = obj.fields();
-            while (it.hasNext()) {
-                Entry<String, JsonNode> entry = it.next();
-                final String key = entry.getKey();
-                final JsonNode value = entry.getValue();
-
-                if (value.isValueNode()) {
-                    if (value.isNull()) {
-                        suppressedAnnotation.put(key, SuppressionRules.ANY_VALUE);
-                    } else {
-                        suppressedAnnotation.put(key, value.asText());
-                    }
-                } else {
-                    log.warn("Encountered unexpected JSON field {} for annotation", entry);
-                }
-            }
-        } else {
-            log.warn("Encountered unexpected JSONNode {} for annotation", annotation);
-        }
-
-        return new SuppressionRules(suppressedDevice,
-                                    suppressedDeviceType,
-                                    suppressedAnnotation);
-    }
-
-    /**
-     * Writes the given SuppressionRules.
-     *
-     * @param rules SuppressionRules
-     * @throws IOException if error occurred while writing the data
-     */
-    public void write(SuppressionRules rules) throws IOException {
-        ObjectMapper mapper = new ObjectMapper();
-        ObjectNode root = mapper.createObjectNode();
-        ArrayNode deviceIds = mapper.createArrayNode();
-        ArrayNode deviceTypes = mapper.createArrayNode();
-        ObjectNode annotations = mapper.createObjectNode();
-        root.set(DEVICE_ID, deviceIds);
-        root.set(DEVICE_TYPE, deviceTypes);
-        root.set(ANNOTATION, annotations);
-
-        rules.getSuppressedDevice()
-            .forEach(deviceId -> deviceIds.add(deviceId.toString()));
-
-        rules.getSuppressedDeviceType()
-            .forEach(type -> deviceTypes.add(type.toString()));
-
-        rules.getSuppressedAnnotation().forEach((key, value) -> {
-            if (value == SuppressionRules.ANY_VALUE) {
-                annotations.putNull(key);
-            } else {
-                annotations.put(key, value);
-            }
-        });
-        mapper.writeTree(new JsonFactory().createGenerator(file, JsonEncoding.UTF8),
-                         root);
-    }
-}
diff --git a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LldpLinkProviderTest.java b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LldpLinkProviderTest.java
index e775a27..ecf60c1 100644
--- a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LldpLinkProviderTest.java
+++ b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LldpLinkProviderTest.java
@@ -15,8 +15,11 @@
  */
 package org.onosproject.provider.lldp.impl;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.junit.After;
@@ -43,6 +46,11 @@
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceServiceAdapter;
@@ -62,15 +70,25 @@
 import org.onosproject.net.provider.ProviderId;
 
 import java.nio.ByteBuffer;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Collections;
 import java.util.concurrent.CompletableFuture;
 
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.provider.lldp.impl.LldpLinkProvider.DEFAULT_RULES;
+import static org.junit.Assert.assertFalse;
+
 
 public class LldpLinkProviderTest {
 
@@ -89,18 +107,23 @@
     private final TestPacketService packetService = new TestPacketService();
     private final TestDeviceService deviceService = new TestDeviceService();
     private final TestMasterShipService masterService = new TestMasterShipService();
+    private final TestNetworkConfigRegistry configRegistry = new TestNetworkConfigRegistry();
 
     private CoreService coreService;
     private TestLinkProviderService providerService;
 
     private PacketProcessor testProcessor;
     private DeviceListener deviceListener;
+    private NetworkConfigListener configListener;
 
     private ApplicationId appId =
             new DefaultApplicationId(100, "org.onosproject.provider.lldp");
 
+    private TestSuppressionConfig cfg;
+
     @Before
     public void setUp() {
+        cfg = new TestSuppressionConfig();
         coreService = createMock(CoreService.class);
         expect(coreService.registerApplication(appId.name()))
             .andReturn(appId).anyTimes();
@@ -108,6 +131,7 @@
 
         provider.cfgService = new ComponentConfigAdapter();
         provider.coreService = coreService;
+        provider.cfgRegistry = configRegistry;
 
         provider.deviceService = deviceService;
         provider.linkService = linkService;
@@ -151,6 +175,7 @@
      */
     @Test
     public void switchSuppressed() {
+
         // add device to stub DeviceService
         deviceService.putDevice(device(DID3));
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
@@ -163,7 +188,11 @@
                                               .build()));
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
 
-        assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3));
+        // discovery on device is expected to be gone or stopped
+        LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
+        if (linkDiscovery != null) {
+            assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
+        }
     }
 
     @Test
@@ -201,7 +230,7 @@
      * Checks that discovery on reconfigured switch are properly restarted.
      */
     @Test
-    public void portSuppressedByDeviceConfig() {
+    public void portSuppressedByDeviceAnnotationConfig() {
 
         /// When Device is configured with suppression:ON, Port also is same
 
@@ -237,10 +266,91 @@
     }
 
     /**
+     * Checks that discovery on reconfigured switch are properly restarted.
+     */
+    @Test
+    public void portSuppressedByDeviceIdConfig() {
+
+        /// When Device is configured without suppression:OFF,
+        /// Port should be included for discovery
+
+        // add device in stub DeviceService without suppression configured
+        deviceService.putDevice(device(DID3));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
+
+        // non-suppressed port added to suppressed device
+        final long portno3 = 3L;
+        deviceService.putPorts(DID3, port(DID3, portno3, true));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true)));
+
+        // discovery should succeed
+        assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
+        assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3));
+
+        // add suppression rule for "deviceId: "of:0000000000000003""
+        provider.updateRules(new SuppressionRules(ImmutableSet.of(DID3),
+                                                  ImmutableSet.of(),
+                                                  ImmutableMap.of()));
+
+        /// When Device is reconfigured with suppression:ON, Port also is same
+
+        // update device in stub DeviceService with suppression configured
+        deviceService.putDevice(device(DID3));
+        // update the Port in stub DeviceService. (Port has reference to Device)
+        deviceService.putPorts(DID3, port(DID3, portno3, true));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
+
+        // discovery on device is expected to be stopped
+        LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
+        if (linkDiscovery != null) {
+            assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
+        }
+    }
+
+    /**
+     * Checks that discovery on reconfigured switch are properly restarted.
+     */
+    @Test
+    public void portSuppressedByDeviceTypeConfig() {
+
+        /// When Device is configured without suppression:OFF,
+        /// Port should be included for discovery
+
+        // add device in stub DeviceService without suppression configured
+        deviceService.putDevice(device(DID1, Device.Type.SWITCH));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
+
+        // non-suppressed port added to suppressed device
+        final long portno3 = 3L;
+        deviceService.putPorts(DID1, port(DID1, portno3, true));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, portno3, true)));
+
+        // add device in stub DeviceService with suppression configured
+        deviceService.putDevice(device(DID2, Device.Type.ROADM));
+        deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID2));
+
+        // non-suppressed port added to suppressed device
+        final long portno4 = 4L;
+        deviceService.putPorts(DID2, port(DID2, portno4, true));
+        deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID2, port(DID2, portno4, true)));
+
+        // discovery should succeed for this device
+        assertFalse("Discoverer is expected to start", provider.discoverers.get(DID1).isStopped());
+        assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID1).containsPort(portno3));
+
+        // discovery on device is expected to be stopped for this device
+        LinkDiscovery linkDiscovery = provider.discoverers.get(DID2);
+        if (linkDiscovery != null) {
+            assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
+        }
+    }
+
+    /**
      * Checks that discovery on reconfigured port are properly restarted.
      */
     @Test
     public void portSuppressedByPortConfig() {
+
         // add device in stub DeviceService without suppression configured
         deviceService.putDevice(device(DID3));
         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
@@ -314,6 +424,11 @@
                              "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
     }
 
+    private DefaultDevice device(DeviceId did, Device.Type type) {
+        return new DefaultDevice(ProviderId.NONE, did, type,
+                "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
+    }
+
     private DefaultDevice device(DeviceId did, Annotations annotations) {
         return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
                              "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations);
@@ -367,6 +482,127 @@
     }
 
 
+    @Test
+    public void addDeviceIdRule() {
+        DeviceId deviceId1 = DeviceId.deviceId("of:0000000000000001");
+        DeviceId deviceId2 = DeviceId.deviceId("of:0000000000000002");
+        Set<DeviceId> deviceIds = new HashSet<>();
+
+        deviceIds.add(deviceId1);
+        cfg.deviceIds(deviceIds);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        assertTrue(provider.rules().getSuppressedDevice().contains(deviceId1));
+        assertFalse(provider.rules().getSuppressedDevice().contains(deviceId2));
+    }
+
+    @Test
+    public void updateDeviceIdRule() {
+        DeviceId deviceId1 = DeviceId.deviceId("of:0000000000000001");
+        DeviceId deviceId2 = DeviceId.deviceId("of:0000000000000002");
+        Set<DeviceId> deviceIds = new HashSet<>();
+
+        deviceIds.add(deviceId1);
+        cfg.deviceIds(deviceIds);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        deviceIds.add(deviceId2);
+        cfg.deviceIds(deviceIds);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
+
+        assertTrue(provider.rules().getSuppressedDevice().contains(deviceId1));
+        assertTrue(provider.rules().getSuppressedDevice().contains(deviceId2));
+    }
+
+    @Test
+    public void addDeviceTypeRule() {
+        Device.Type deviceType1 = Device.Type.ROADM;
+        Device.Type deviceType2 = Device.Type.SWITCH;
+
+        Set<Device.Type> deviceTypes = new HashSet<>();
+        deviceTypes.add(deviceType1);
+
+        cfg.deviceTypes(deviceTypes);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType1));
+        assertFalse(provider.rules().getSuppressedDeviceType().contains(deviceType2));
+    }
+
+    @Test
+    public void updateDeviceTypeRule() {
+        Device.Type deviceType1 = Device.Type.ROADM;
+        Device.Type deviceType2 = Device.Type.SWITCH;
+        Set<Device.Type> deviceTypes = new HashSet<>();
+
+        deviceTypes.add(deviceType1);
+        cfg.deviceTypes(deviceTypes);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        deviceTypes.add(deviceType2);
+        cfg.deviceTypes(deviceTypes);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
+
+        assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType1));
+        assertTrue(provider.rules().getSuppressedDeviceType().contains(deviceType2));
+    }
+
+    @Test
+    public void addAnnotationRule() {
+        final String key1 = "key1", key2 = "key2";
+        final String value1 = "value1";
+
+        Map<String, String> annotation = new HashMap<>();
+        annotation.put(key1, value1);
+
+        cfg.annotation(annotation);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
+        assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
+        assertFalse(provider.rules().getSuppressedAnnotation().containsKey(key2));
+    }
+
+    @Test
+    public void updateAnnotationRule() {
+        final String key1 = "key1", key2 = "key2";
+        final String value1 = "value1", value2 = "value2";
+        Map<String, String> annotation = new HashMap<>();
+
+        annotation.put(key1, value1);
+        cfg.annotation(annotation);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_ADDED);
+
+        assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
+        assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
+        assertFalse(provider.rules().getSuppressedAnnotation().containsKey(key2));
+
+        annotation.put(key2, value2);
+        cfg.annotation(annotation);
+
+        configEvent(NetworkConfigEvent.Type.CONFIG_UPDATED);
+
+        assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key1));
+        assertEquals(value1, provider.rules().getSuppressedAnnotation().get(key1));
+        assertTrue(provider.rules().getSuppressedAnnotation().containsKey(key2));
+        assertEquals(value2, provider.rules().getSuppressedAnnotation().get(key2));
+    }
+
+    private void configEvent(NetworkConfigEvent.Type evType) {
+        configListener.event(new NetworkConfigEvent(evType,
+                appId,
+                SuppressionConfig.class));
+    }
+
+
     private class TestLinkRegistry implements LinkProviderRegistry {
 
         @Override
@@ -627,4 +863,58 @@
 
     private class TestLinkService extends LinkServiceAdapter {
     }
+
+    private final class TestNetworkConfigRegistry
+        extends NetworkConfigRegistryAdapter {
+        @Override
+        public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+            ConfigApplyDelegate delegate = config -> { };
+            ObjectMapper mapper = new ObjectMapper();
+            return (C) cfg;
+        }
+
+        @Override
+        public void addListener(NetworkConfigListener listener) {
+            configListener = listener;
+        }
+    }
+
+    private final class TestSuppressionConfig extends SuppressionConfig {
+        private Set<DeviceId> deviceIds = new HashSet<>(DEFAULT_RULES.getSuppressedDevice());
+        private Set<Device.Type> deviceTypes = new HashSet<>(DEFAULT_RULES.getSuppressedDeviceType());
+        private Map<String, String> annotation = new HashMap<>(DEFAULT_RULES.getSuppressedAnnotation());
+
+        @Override
+        public Set<DeviceId> deviceIds() {
+            return ImmutableSet.copyOf(deviceIds);
+        }
+
+        @Override
+        public SuppressionConfig deviceIds(Set<DeviceId> deviceIds) {
+            this.deviceIds = ImmutableSet.copyOf(deviceIds);
+            return this;
+        }
+
+        @Override
+        public Set<Device.Type> deviceTypes() {
+            return ImmutableSet.copyOf(deviceTypes);
+        }
+
+        @Override
+        public SuppressionConfig deviceTypes(Set<Device.Type> deviceTypes) {
+            this.deviceTypes = ImmutableSet.copyOf(deviceTypes);
+            return this;
+        }
+
+        @Override
+        public Map<String, String> annotation() {
+            return ImmutableMap.copyOf(annotation);
+        }
+
+        @Override
+        public SuppressionConfig annotation(Map<String, String> annotation) {
+            this.annotation = ImmutableMap.copyOf(annotation);
+            return this;
+        }
+    }
 }
diff --git a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionConfigTest.java b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionConfigTest.java
new file mode 100644
index 0000000..781ed17
--- /dev/null
+++ b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionConfigTest.java
@@ -0,0 +1,86 @@
+package org.onosproject.provider.lldp.impl;
+
+import static org.junit.Assert.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class SuppressionConfigTest {
+    private static final String APP_NAME = "SuppressionConfigTest";
+    private static final TestApplicationId APP_ID = new TestApplicationId(APP_NAME);
+    private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId("of:1111000000000000");
+    private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId("of:2222000000000000");
+    private static final Device.Type DEVICE_TYPE_1 = Device.Type.ROADM;
+    private static final Device.Type DEVICE_TYPE_2 = Device.Type.FIBER_SWITCH;
+    private static final String ANNOTATION_KEY_1 = "no_lldp";
+    private static final String ANNOTATION_VALUE_1 = "true";
+    private static final String ANNOTATION_KEY_2 = "sendLLDP";
+    private static final String ANNOTATION_VALUE_2 = "false";
+
+    private SuppressionConfig cfg;
+
+    @Before
+    public void setUp() throws Exception {
+        ConfigApplyDelegate delegate = config -> { };
+        ObjectMapper mapper = new ObjectMapper();
+        cfg = new SuppressionConfig();
+        cfg.init(APP_ID, LldpLinkProvider.CONFIG_KEY, JsonNodeFactory.instance.objectNode(), mapper, delegate);
+    }
+
+    @Test
+    public void testDeviceIds() {
+        Set<DeviceId> inputIds = new HashSet<DeviceId>() { {
+            add(DEVICE_ID_1);
+            add(DEVICE_ID_2);
+        } };
+
+        assertNotNull(cfg.deviceIds(inputIds));
+
+        Set<DeviceId> outputIds = cfg.deviceIds();
+        assertTrue(outputIds.contains(DEVICE_ID_1));
+        assertTrue(outputIds.contains(DEVICE_ID_2));
+        assertEquals(outputIds.size(), 2);
+    }
+
+    @Test
+    public void testDeviceTypes() {
+        Set<Device.Type> inputTypes = new HashSet<Device.Type>() { {
+            add(DEVICE_TYPE_1);
+            add(DEVICE_TYPE_2);
+        } };
+
+        assertNotNull(cfg.deviceTypes(inputTypes));
+
+        Set<Device.Type> outputTypes = cfg.deviceTypes();
+        assertTrue(outputTypes.contains(DEVICE_TYPE_1));
+        assertTrue(outputTypes.contains(DEVICE_TYPE_2));
+        assertEquals(outputTypes.size(), 2);
+    }
+
+    @Test
+    public void testDeviceAnnotation() {
+        Map<String, String> inputMap = new HashMap<String, String>() { {
+            put(ANNOTATION_KEY_1, ANNOTATION_VALUE_1);
+            put(ANNOTATION_KEY_2, ANNOTATION_VALUE_2);
+        } };
+
+        assertNotNull(cfg.annotation(inputMap));
+
+        Map<String, String> outputMap = cfg.annotation();
+        assertEquals(outputMap.get(ANNOTATION_KEY_1), ANNOTATION_VALUE_1);
+        assertEquals(outputMap.get(ANNOTATION_KEY_2), ANNOTATION_VALUE_2);
+        assertEquals(outputMap.size(), 2);
+    }
+
+}
diff --git a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionRulesStoreTest.java b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionRulesStoreTest.java
deleted file mode 100644
index 0ac3112..0000000
--- a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/SuppressionRulesStoreTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2014-2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.provider.lldp.impl;
-
-import static org.junit.Assert.*;
-import static org.onosproject.net.DeviceId.deviceId;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.onosproject.net.Device;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.io.Resources;
-
-public class SuppressionRulesStoreTest {
-
-    @Rule
-    public TemporaryFolder tempFolder = new TemporaryFolder();
-
-    // "lldp_suppression.json"
-    SuppressionRules testData
-        = new SuppressionRules(ImmutableSet.of(deviceId("of:2222000000000000")),
-                               ImmutableSet.of(Device.Type.ROADM),
-                               ImmutableMap.of("no-lldp", SuppressionRules.ANY_VALUE,
-                                               "sendLLDP", "false"));
-
-    private static void assertRulesEqual(SuppressionRules expected, SuppressionRules actual) {
-        assertEquals(expected.getSuppressedDevice(),
-                     actual.getSuppressedDevice());
-        assertEquals(expected.getSuppressedDeviceType(),
-                     actual.getSuppressedDeviceType());
-        assertEquals(expected.getSuppressedAnnotation(),
-                     actual.getSuppressedAnnotation());
-    }
-
-    @Test
-    public void testRead() throws URISyntaxException, IOException {
-        Path path = Paths.get(Resources.getResource("lldp_suppression.json").toURI());
-
-        SuppressionRulesStore store = new SuppressionRulesStore(path.toString());
-
-        SuppressionRules rules = store.read();
-
-        assertRulesEqual(testData, rules);
-    }
-
-    @Test
-    public void testWrite() throws IOException {
-        File newFile = tempFolder.newFile();
-        SuppressionRulesStore store = new SuppressionRulesStore(newFile);
-        store.write(testData);
-
-        SuppressionRulesStore reload = new SuppressionRulesStore(newFile);
-        SuppressionRules rules = reload.read();
-
-        assertRulesEqual(testData, rules);
-    }
-}
diff --git a/providers/lldp/src/test/resources/lldp_suppression.json b/providers/lldp/src/test/resources/lldp_suppression.json
deleted file mode 100644
index 062e73a..0000000
--- a/providers/lldp/src/test/resources/lldp_suppression.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "deviceId" : [ "of:2222000000000000" ],
-  "deviceType" : [ "ROADM" ],
-  "annotation" : { "no-lldp" : null, "sendLLDP" : "false" }
-}
-
diff --git a/tools/package/config/samples/network-cfg.json b/tools/package/config/samples/network-cfg.json
index 9232847..a11237d 100644
--- a/tools/package/config/samples/network-cfg.json
+++ b/tools/package/config/samples/network-cfg.json
@@ -62,5 +62,12 @@
 		]
 	    }
 	}
+        "org.onosproject.provider.lldp": {
+            "suppression": {
+                "deviceIds": [ "of:2222000000000000" ],
+                "deviceTypes": [ "ROADM" ],
+                "annotation": { "no-lldp": null, "sendLLDP" : "false" }
+            }
+        }
     }
 }