Devices,hosts, and links can be blocked and kicked off with the network configuration api

Change-Id: I68d427f4886a7b63475df8d35383e2e347946946
diff --git a/core/net/pom.xml b/core/net/pom.xml
index c54be45..e262d4a 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -59,12 +59,25 @@
         </dependency>
 
         <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <scope>test</scope>
+            <classifier>tests</classifier>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>
             <scope>test</scope>
         </dependency>
 
         <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.scr.annotations</artifactId>
         </dependency>
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index d71b796..17ff85c 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.device.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.MastershipRole.MASTER;
@@ -45,17 +46,23 @@
 import org.onosproject.core.Permission;
 import org.onosproject.event.EventDeliveryService;
 import org.onosproject.event.ListenerRegistry;
+import org.onosproject.incubator.net.config.NetworkConfigEvent;
+import org.onosproject.incubator.net.config.NetworkConfigListener;
+import org.onosproject.incubator.net.config.NetworkConfigService;
+import org.onosproject.incubator.net.config.basics.BasicDeviceConfig;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.mastership.MastershipTerm;
 import org.onosproject.mastership.MastershipTermService;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
 import org.onosproject.net.Device.Type;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.device.DefaultDeviceDescription;
 import org.onosproject.net.device.DefaultPortDescription;
 import org.onosproject.net.device.DeviceAdminService;
@@ -104,6 +111,8 @@
 
     private ScheduledExecutorService backgroundService;
 
+    private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceStore store;
 
@@ -122,6 +131,11 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceClockProviderService deviceClockProviderService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
+
+
     @Activate
     public void activate() {
         backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background"));
@@ -130,6 +144,7 @@
         store.setDelegate(delegate);
         eventDispatcher.addSink(DeviceEvent.class, listenerRegistry);
         mastershipService.addListener(mastershipListener);
+        networkConfigService.addListener(networkConfigListener);
 
         backgroundService.scheduleWithFixedDelay(new Runnable() {
 
@@ -148,7 +163,7 @@
     @Deactivate
     public void deactivate() {
         backgroundService.shutdown();
-
+        networkConfigService.removeListener(networkConfigListener);
         store.unsetDelegate(delegate);
         mastershipService.removeListener(mastershipListener);
         eventDispatcher.removeSink(DeviceEvent.class);
@@ -286,7 +301,8 @@
                 continue;
             }
 
-            log.info("{} is reachable but did not have a valid role, reasserting", deviceId);
+            log.info("{} is reachable but did not have a valid role, reasserting",
+                     deviceId);
 
             // isReachable but was not MASTER or STANDBY, get a role and apply
             // Note: NONE triggers request to MastershipService
@@ -319,7 +335,8 @@
 
             DeviceProvider provider = provider();
             if (provider == null) {
-                log.warn("Provider for {} was not found. Cannot apply role {}", deviceId, newRole);
+                log.warn("Provider for {} was not found. Cannot apply role {}",
+                         deviceId, newRole);
                 return false;
             }
             provider.roleChanged(deviceId, newRole);
@@ -335,8 +352,8 @@
             checkNotNull(deviceId, DEVICE_ID_NULL);
             checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL);
             checkValidity();
+            deviceDescription = validateDevice(deviceDescription, deviceId);
 
-            log.info("Device {} connected", deviceId);
             // check my Role
             CompletableFuture<MastershipRole> role = mastershipService.requestRoleFor(deviceId);
             try {
@@ -362,16 +379,33 @@
                 deviceClockProviderService.setMastershipTerm(deviceId, term);
                 applyRole(deviceId, MastershipRole.MASTER);
             }
-
-            DeviceEvent event = store.createOrUpdateDevice(provider().id(),
-                                                           deviceId, deviceDescription);
-
+            DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId,
+                                                           deviceDescription);
             if (event != null) {
                 log.trace("event: {} {}", event.type(), event);
                 post(event);
             }
         }
 
+        // returns a DeviceDescription made from the union of the BasicDeviceConfig
+        // annotations if it exists
+        private DeviceDescription validateDevice(DeviceDescription deviceDescription, DeviceId deviceId) {
+            BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
+            checkState(cfg == null || cfg.isAllowed(), "Device " + deviceId + " is not allowed");
+            log.info("Device {} connected", deviceId);
+            if (cfg != null) {
+                SparseAnnotations finalSparse = processAnnotations(cfg, deviceDescription, deviceId);
+                if (cfg.type() != Type.SWITCH) {
+                    deviceDescription = new DefaultDeviceDescription(deviceDescription,
+                                                                     cfg.type(), finalSparse);
+                } else {
+                    deviceDescription = new DefaultDeviceDescription(deviceDescription,
+                            deviceDescription.type(), finalSparse);
+                }
+            }
+            return deviceDescription;
+        }
+
         @Override
         public void deviceDisconnected(DeviceId deviceId) {
             checkNotNull(deviceId, DEVICE_ID_NULL);
@@ -433,7 +467,7 @@
                                 List<PortDescription> portDescriptions) {
             checkNotNull(deviceId, DEVICE_ID_NULL);
             checkNotNull(portDescriptions,
-                         "Port descriptions list cannot be null");
+                    "Port descriptions list cannot be null");
             checkValidity();
             if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
                 // Never been a master for this device
@@ -459,7 +493,8 @@
             if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
                 // Never been a master for this device
                 // any update will be ignored.
-                log.trace("Ignoring {} port update on standby node. {}", deviceId, portDescription);
+                log.trace("Ignoring {} port update on standby node. {}", deviceId,
+                          portDescription);
                 return;
             }
 
@@ -486,7 +521,7 @@
             // FIXME: implement response to this notification
 
             log.debug("got reply to a role request for {}: asked for {}, and got {}",
-                     deviceId, requested, response);
+                    deviceId, requested, response);
 
             if (requested == null && response == null) {
                 // something was off with DeviceProvider, maybe check channel too?
@@ -525,6 +560,37 @@
                                                            deviceId, portStatistics);
             post(event);
         }
+
+        // supplements or replaces deviceDescription annotations with
+        // BasicDeviceConfig annotations
+        private SparseAnnotations processAnnotations(BasicDeviceConfig cfg, DeviceDescription deviceDescription,
+                                                     DeviceId deviceId) {
+            SparseAnnotations originalAnnotations = deviceDescription.annotations();
+            DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
+            if (cfg.driver() != deviceId.toString()) {
+                newBuilder.set(cfg.DRIVER, cfg.driver());
+            }
+            if (cfg.type() != Type.SWITCH) {
+                newBuilder.set(cfg.TYPE, cfg.type().toString());
+            }
+            if (cfg.name() != null) {
+                newBuilder.set(cfg.NAME, cfg.name());
+            }
+            if (cfg.latitude() != -1) {
+                newBuilder.set(cfg.LATITUDE, Double.toString(cfg.latitude()));
+            }
+            if (cfg.longitude() != -1) {
+                newBuilder.set(cfg.LONGITUDE, Double.toString(cfg.longitude()));
+            }
+            if (cfg.rackAddress() != null) {
+                newBuilder.set(cfg.RACK_ADDRESS, cfg.rackAddress());
+            }
+            if (cfg.owner() != null) {
+                newBuilder.set(cfg.OWNER, cfg.owner());
+            }
+            DefaultAnnotations newAnnotations = newBuilder.build();
+            return DefaultAnnotations.union(originalAnnotations, newAnnotations);
+        }
     }
 
     // Posts the specified event to the local event dispatcher.
@@ -727,4 +793,30 @@
         }
         return results;
     }
+
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+                    event.configClass().equals(BasicDeviceConfig.class)) {
+                log.info("Detected Device network config event {}", event.type());
+                kickOutBadDevice(((DeviceId) event.subject()));
+            }
+        }
+    }
+
+    // checks if the specified device is allowed by the BasicDeviceConfig
+    // and if not, removes it
+    private void kickOutBadDevice(DeviceId deviceId) {
+        BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
+        if (!cfg.isAllowed()) {
+            Device badDevice = getDevice(deviceId);
+            if (badDevice != null) {
+                removeDevice(deviceId);
+            } else {
+                log.info("Failed removal: Device {} does not exist", deviceId);
+            }
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index 3335f5a..d36db84 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -27,11 +27,18 @@
 import org.onosproject.core.Permission;
 import org.onosproject.event.EventDeliveryService;
 import org.onosproject.event.ListenerRegistry;
+import org.onosproject.incubator.net.config.NetworkConfigEvent;
+import org.onosproject.incubator.net.config.NetworkConfigListener;
+import org.onosproject.incubator.net.config.NetworkConfigService;
+import org.onosproject.incubator.net.config.basics.BasicHostConfig;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
+import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.DefaultHostDescription;
 import org.onosproject.net.host.HostAdminService;
 import org.onosproject.net.host.HostDescription;
 import org.onosproject.net.host.HostEvent;
@@ -51,6 +58,7 @@
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
 
@@ -70,6 +78,8 @@
     private final ListenerRegistry<HostEvent, HostListener>
             listenerRegistry = new ListenerRegistry<>();
 
+    private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
+
     private HostStoreDelegate delegate = new InternalStoreDelegate();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -84,6 +94,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
     private HostMonitor monitor;
 
     @Activate
@@ -91,7 +104,7 @@
         log.info("Started");
         store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
-
+        networkConfigService.addListener(networkConfigListener);
         monitor = new HostMonitor(deviceService,  packetService, this);
         monitor.start();
     }
@@ -100,6 +113,7 @@
     public void deactivate() {
         store.unsetDelegate(delegate);
         eventDispatcher.removeSink(HostEvent.class);
+        networkConfigService.removeListener(networkConfigListener);
         log.info("Stopped");
     }
 
@@ -246,7 +260,6 @@
     private class InternalHostProviderService
             extends AbstractProviderService<HostProvider>
             implements HostProviderService {
-
         InternalHostProviderService(HostProvider provider) {
             super(provider);
         }
@@ -255,6 +268,7 @@
         public void hostDetected(HostId hostId, HostDescription hostDescription) {
             checkNotNull(hostId, HOST_ID_NULL);
             checkValidity();
+            hostDescription = validateHost(hostDescription, hostId);
             HostEvent event = store.createOrUpdateHost(provider().id(), hostId,
                                                        hostDescription);
             if (event != null) {
@@ -262,6 +276,21 @@
             }
         }
 
+        // returns a HostDescription made from the union of the BasicHostConfig
+        // annotations if it exists
+        private HostDescription validateHost(HostDescription hostDescription, HostId hostId) {
+            BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
+            checkState(cfg == null || cfg.isAllowed(), "Host {} is not allowed", hostId);
+            if (cfg != null) {
+                SparseAnnotations finalSparse = processAnnotations(cfg, hostDescription);
+                hostDescription = new DefaultHostDescription(hostId.mac(),
+                                                             hostDescription.vlan(),
+                                                             hostDescription.location(),
+                                                             finalSparse);
+            }
+            return hostDescription;
+        }
+
         @Override
         public void hostVanished(HostId hostId) {
             checkNotNull(hostId, HOST_ID_NULL);
@@ -273,6 +302,30 @@
         }
     }
 
+    // Supplements or replaces hostDescriptions's annotations with BasicHostConfig's
+    // annotations
+    private SparseAnnotations processAnnotations(BasicHostConfig cfg, HostDescription hostDescription) {
+        SparseAnnotations originalAnnotations = hostDescription.annotations();
+        DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
+        if (cfg.name() != null) {
+            newBuilder.set(cfg.NAME, cfg.name());
+        }
+        if (cfg.latitude() != -1) {
+            newBuilder.set(cfg.LATITUDE, Double.toString(cfg.latitude()));
+        }
+        if (cfg.longitude() != -1) {
+            newBuilder.set(cfg.LONGITUDE, Double.toString(cfg.longitude()));
+        }
+        if (cfg.rackAddress() != null) {
+            newBuilder.set(cfg.RACK_ADDRESS, cfg.rackAddress());
+        }
+        if (cfg.owner() != null) {
+            newBuilder.set(cfg.OWNER, cfg.owner());
+        }
+        DefaultAnnotations newAnnotations = newBuilder.build();
+        return DefaultAnnotations.union(originalAnnotations, newAnnotations);
+    }
+
     // Posts the specified event to the local event dispatcher.
     private void post(HostEvent event) {
         if (event != null) {
@@ -287,4 +340,32 @@
             post(event);
         }
     }
+
+    // listens for NetworkConfigEvents of type BasicHostConfig and removes
+    // links that the config does not allow
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+                    event.configClass().equals(BasicHostConfig.class)) {
+                log.info("Detected Host network config event {}", event.type());
+                kickOutBadHost(((HostId) event.subject()));
+            }
+        }
+    }
+
+    // checks if the specified host is allowed by the BasicHostConfig
+    // and if not, removes it
+    private void kickOutBadHost(HostId hostId) {
+        BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
+        if (cfg != null && !cfg.isAllowed()) {
+            Host badHost = getHost(hostId);
+            if (badHost != null) {
+                removeHost(hostId);
+            } else {
+                log.info("Failed removal: Host {} does not exist", hostId);
+            }
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
index 75134f3..e6fa300 100644
--- a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
+++ b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java
@@ -27,14 +27,22 @@
 import org.onosproject.core.Permission;
 import org.onosproject.event.EventDeliveryService;
 import org.onosproject.event.ListenerRegistry;
+import org.onosproject.incubator.net.config.NetworkConfigEvent;
+import org.onosproject.incubator.net.config.NetworkConfigListener;
+import org.onosproject.incubator.net.config.NetworkConfigService;
+import org.onosproject.incubator.net.config.basics.BasicLinkConfig;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
 import org.onosproject.net.Link.State;
+import org.onosproject.net.LinkKey;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.link.DefaultLinkDescription;
 import org.onosproject.net.link.LinkAdminService;
 import org.onosproject.net.link.LinkDescription;
 import org.onosproject.net.link.LinkEvent;
@@ -49,9 +57,12 @@
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
+import java.time.Duration;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.onosproject.net.LinkKey.linkKey;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppGuard.checkPermission;
 
@@ -78,6 +89,8 @@
 
     private final DeviceListener deviceListener = new InternalDeviceListener();
 
+    private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkStore store;
 
@@ -87,11 +100,15 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EventDeliveryService eventDispatcher;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
     @Activate
     public void activate() {
         store.setDelegate(delegate);
         eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
         deviceService.addListener(deviceListener);
+        networkConfigService.addListener(networkConfigListener);
         log.info("Started");
     }
 
@@ -100,6 +117,7 @@
         store.unsetDelegate(delegate);
         eventDispatcher.removeSink(LinkEvent.class);
         deviceService.removeListener(deviceListener);
+        networkConfigService.removeListener(networkConfigListener);
         log.info("Stopped");
     }
 
@@ -206,17 +224,19 @@
         removeLinks(getDeviceLinks(deviceId), false);
     }
 
+    public void removeLink(ConnectPoint src, ConnectPoint dst) {
+        post(store.removeLink(src, dst));
+    }
+
     @Override
     public void addListener(LinkListener listener) {
         checkPermission(Permission.LINK_EVENT);
-
         listenerRegistry.addListener(listener);
     }
 
     @Override
     public void removeListener(LinkListener listener) {
         checkPermission(Permission.LINK_EVENT);
-
         listenerRegistry.removeListener(listener);
     }
 
@@ -229,7 +249,7 @@
                 removeLinks(event.subject().id());
             } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
                 removeLinks(new ConnectPoint(event.subject().id(),
-                                             event.port().number()));
+                        event.port().number()));
             }
         }
     }
@@ -252,15 +272,62 @@
         public void linkDetected(LinkDescription linkDescription) {
             checkNotNull(linkDescription, LINK_DESC_NULL);
             checkValidity();
-
+            linkDescription = validateLink(linkDescription);
             LinkEvent event = store.createOrUpdateLink(provider().id(),
-                                                       linkDescription);
+                    linkDescription);
             if (event != null) {
                 log.info("Link {} detected", linkDescription);
                 post(event);
             }
         }
 
+        // returns a LinkDescription made from the union of the BasicLinkConfig
+        // annotations if it exists
+        private LinkDescription validateLink(LinkDescription linkDescription) {
+            // TODO Investigate whether this can be made more efficient
+            BasicLinkConfig cfg = networkConfigService.getConfig(linkKey(linkDescription.src(),
+                                                                         linkDescription.dst()),
+                                                                 BasicLinkConfig.class);
+            BasicLinkConfig cfgTwo = networkConfigService.getConfig(linkKey(linkDescription.dst(),
+                                                                            linkDescription.src()),
+                                                                    BasicLinkConfig.class);
+
+            checkState(cfg == null || cfg.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
+            checkState(cfgTwo == null || cfgTwo.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
+            if (cfg != null) {
+                SparseAnnotations finalSparse = processAnnotations(cfg, linkDescription);
+                // check whether config has a specified type
+                if (cfg.type() != Link.Type.DIRECT) {
+                    linkDescription = new DefaultLinkDescription(linkDescription.src(),
+                                                                 linkDescription.dst(),
+                                                                 cfg.type(), finalSparse);
+                } else {
+                    linkDescription = new DefaultLinkDescription(linkDescription.src(),
+                                                                 linkDescription.dst(),
+                                                                 linkDescription.type(), finalSparse);
+                }
+            }
+            return linkDescription;
+        }
+
+        // supplements or replaces linkDescriptions's annotations with BasicLinkConfig's
+        // annotations
+        private SparseAnnotations processAnnotations(BasicLinkConfig cfg, LinkDescription linkDescription) {
+            SparseAnnotations originalAnnotations = linkDescription.annotations();
+            DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
+            if (cfg.type() != Link.Type.DIRECT) {
+                newBuilder.set(cfg.TYPE, cfg.type().toString());
+            }
+            if (cfg.latency() != Duration.ofNanos(-1)) {
+                newBuilder.set(cfg.LATENCY, cfg.latency().toString());
+            }
+            if (cfg.bandwidth() != -1) {
+                newBuilder.set(cfg.BANDWIDTH, String.valueOf(cfg.bandwidth()));
+            }
+            DefaultAnnotations newAnnotations = newBuilder.build();
+            return DefaultAnnotations.union(originalAnnotations, newAnnotations);
+        }
+
         @Override
         public void linkVanished(LinkDescription linkDescription) {
             checkNotNull(linkDescription, LINK_DESC_NULL);
@@ -297,7 +364,7 @@
     }
 
     // Removes all links in the specified set and emits appropriate events.
-    private void  removeLinks(Set<Link> links, boolean isSoftRemove) {
+    private void removeLinks(Set<Link> links, boolean isSoftRemove) {
         for (Link link : links) {
             LinkEvent event = isSoftRemove ?
                     store.removeOrDownLink(link.src(), link.dst()) :
@@ -323,4 +390,24 @@
             post(event);
         }
     }
+
+    // listens for NetworkConfigEvents of type BasicLinkConfig and removes
+    // links that the config does not allow
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+                    event.configClass().equals(BasicLinkConfig.class)) {
+                log.info("Detected Link network config event {}", event.type());
+                LinkKey lk = (LinkKey) event.subject();
+                BasicLinkConfig cfg = networkConfigService.getConfig(lk, BasicLinkConfig.class);
+                if (cfg != null && !cfg.isAllowed()) {
+                    log.info("Kicking out links between {} and {}", lk.src(), lk.dst());
+                    removeLink(lk.src(), lk.dst());
+                    removeLink(lk.dst(), lk.src());
+                }
+            }
+        }
+    }
 }
diff --git a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
index 4d8d2fc..7597e7c 100644
--- a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
@@ -32,6 +32,7 @@
 import org.onosproject.cluster.NodeId;
 import org.onosproject.event.Event;
 import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.mastership.MastershipTerm;
 import org.onosproject.mastership.MastershipTermService;
@@ -115,8 +116,10 @@
         mgr.termService = mastershipManager;
         mgr.clusterService = new TestClusterService();
         mgr.deviceClockProviderService = new TestClockProviderService();
+        mgr.networkConfigService = new TestNetworkConfigService();
         mgr.activate();
 
+
         service.addListener(listener);
 
         provider = new TestProvider();
@@ -349,4 +352,7 @@
             return registerdBefore.contains(deviceId);
         }
     }
+
+    private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+    }
 }
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
index 77b199b..9e113f3 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -37,6 +37,7 @@
 import org.onlab.packet.VlanId;
 import org.onosproject.event.Event;
 import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
@@ -123,6 +124,7 @@
         mgr.store = new SimpleHostStore();
         mgr.eventDispatcher = new TestEventDispatcher();
         registry = mgr;
+        mgr.networkConfigService = new TestNetworkConfigService();
         mgr.activate();
 
         mgr.addListener(listener);
@@ -520,4 +522,7 @@
         assertTrue(storedAddresses.size() == 2);
         assertTrue(storedAddresses.equals(Sets.newHashSet(add1, add2)));
     }
+
+    private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+    }
 }
diff --git a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
index f164fa8..391b2fd 100644
--- a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
@@ -20,6 +20,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onosproject.event.Event;
+import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.Device;
@@ -86,6 +87,7 @@
     protected DeviceManager devmgr = new TestDeviceManager();
 
 
+
     @Before
     public void setUp() {
         mgr = new LinkManager();
@@ -95,6 +97,7 @@
         mgr.store = new SimpleLinkStore();
         mgr.eventDispatcher = new TestEventDispatcher();
         mgr.deviceService = devmgr;
+        mgr.networkConfigService = new TestNetworkConfigService();
         mgr.activate();
 
         DEVICEIDMAP.put(DID1, DEV1);
@@ -302,5 +305,6 @@
         }
 
     }
-
+    private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+    }
 }