Add explicit flow rules to receive control packets: ARP, LLDP, BDDP

This fixes ONOS-540

NOTES:
 * Currently, the flow rules are pushed by each module that needs to receive
   the corresponding control packets:
   - ARP: ProxyArpManager, HostLocationProvider
   - LLDP and BDDP: LLDPLinkProvider
 * Pushing the corresponding IPv6 rules for Neighbor Discovery is not done yet
 * In the future, we might want to consider an explicit service to
   subscribe for receiving particular control packets

Change-Id: I292ad11a2e48390624f381c278e55e5d0af93c6d
diff --git a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
index 51aedd7..cd35359 100644
--- a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
+++ b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java
@@ -31,6 +31,8 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.Host;
@@ -41,7 +43,12 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.InterfaceIpAddress;
@@ -72,6 +79,8 @@
 
     private final Logger log = getLogger(getClass());
 
+    private static final int FLOW_RULE_PRIORITY = 40000;
+
     private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
     private static final String REQUEST_NULL = "Arp request cannot be null.";
     private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
@@ -79,6 +88,12 @@
     private static final String NOT_ARP_REPLY = "ARP is not a reply.";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -96,15 +111,22 @@
     private final Multimap<Device, PortNumber> externalPorts =
             HashMultimap.<Device, PortNumber>create();
 
+    private ApplicationId appId;
+
     /**
      * Listens to both device service and link service to determine
      * whether a port is internal or external.
      */
     @Activate
     public void activate() {
+        appId =
+            coreService.registerApplication("org.onosproject.net.proxyarp");
+
         deviceService.addListener(new InternalDeviceListener());
         linkService.addListener(new InternalLinkListener());
         determinePortLocations();
+        pushRules();
+
         log.info("Started");
     }
 
@@ -396,6 +418,36 @@
         return eth;
     }
 
+    /**
+     * Pushes flow rules to all devices.
+     */
+    private void pushRules() {
+        for (Device device : deviceService.getDevices()) {
+            pushRules(device);
+        }
+    }
+
+    /**
+     * Pushes flow rules to the device to receive control packets that need
+     * to be processed.
+     *
+     * @param device the device to push the rules to
+     */
+    private synchronized void pushRules(Device device) {
+        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+
+        // Get all ARP packets
+        sbuilder.matchEthType(Ethernet.TYPE_ARP);
+        tbuilder.punt();
+        FlowRule flowArp =
+            new DefaultFlowRule(device.id(),
+                                sbuilder.build(), tbuilder.build(),
+                                FLOW_RULE_PRIORITY, appId, 0, true);
+
+        flowRuleService.applyFlowRules(flowArp);
+    }
+
     public class InternalLinkListener implements LinkListener {
 
         @Override
@@ -440,6 +492,8 @@
             Device device = event.subject();
             switch (event.type()) {
                 case DEVICE_ADDED:
+                    pushRules(device);
+                    break;
                 case DEVICE_AVAILABILITY_CHANGED:
                 case DEVICE_SUSPENDED:
                 case DEVICE_UPDATED:
diff --git a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
index 7ece2e8..c364d8b 100644
--- a/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
@@ -18,6 +18,7 @@
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -32,6 +33,9 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultHost;
 import org.onosproject.net.Device;
@@ -44,6 +48,8 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.host.HostService;
@@ -97,9 +103,13 @@
 
     private TestPacketService packetService;
 
+    private CoreService coreService;
     private DeviceService deviceService;
+    private FlowRuleService flowRuleService;
     private LinkService linkService;
     private HostService hostService;
+    private ApplicationId appId = new DefaultApplicationId((short) 100,
+                "org.onosproject.net.proxyarp");
 
     @Before
     public void setUp() throws Exception {
@@ -113,7 +123,9 @@
         proxyArp.hostService = hostService;
 
         createTopology();
+        proxyArp.coreService = coreService;
         proxyArp.deviceService = deviceService;
+        proxyArp.flowRuleService = flowRuleService;
         proxyArp.linkService = linkService;
 
         proxyArp.activate();
@@ -130,6 +142,16 @@
      * addresses configured.
      */
     private void createTopology() {
+        coreService = createMock(CoreService.class);
+        expect(coreService.registerApplication(appId.name()))
+            .andReturn(appId).anyTimes();
+        replay(coreService);
+
+        flowRuleService = createMock(FlowRuleService.class);
+        flowRuleService.applyFlowRules(anyObject(FlowRule.class));
+        expectLastCall().anyTimes();
+        replay(flowRuleService);
+
         deviceService = createMock(DeviceService.class);
         linkService = createMock(LinkService.class);
 
diff --git a/providers/host/pom.xml b/providers/host/pom.xml
index 5cf7c40..2ea2ad6 100644
--- a/providers/host/pom.xml
+++ b/providers/host/pom.xml
@@ -52,6 +52,11 @@
             <classifier>tests</classifier>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index ffe6c41..7c3d2ec 100644
--- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -22,14 +22,23 @@
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
+import org.onosproject.net.Device;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.DefaultHostDescription;
 import org.onosproject.net.host.HostDescription;
 import org.onosproject.net.host.HostProvider;
@@ -68,6 +77,14 @@
 
     private final Logger log = getLogger(getClass());
 
+    private static final int FLOW_RULE_PRIORITY = 40000;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostProviderRegistry providerRegistry;
 
@@ -88,6 +105,8 @@
     private final InternalHostProvider processor = new InternalHostProvider();
     private final DeviceListener deviceListener = new InternalDeviceListener();
 
+    private ApplicationId appId;
+
     @Property(name = "hostRemovalEnabled", boolValue = true,
             label = "Enable host removal on port/device down events")
     private boolean hostRemovalEnabled = true;
@@ -102,10 +121,15 @@
 
     @Activate
     public void activate(ComponentContext context) {
+        appId =
+            coreService.registerApplication("org.onosproject.provider.host");
+
         modified(context);
         providerService = providerRegistry.register(this);
         pktService.addProcessor(processor, 1);
         deviceService.addListener(deviceListener);
+        pushRules();
+
         log.info("Started");
     }
 
@@ -137,6 +161,36 @@
         log.info("Triggering probe on device {}", host);
     }
 
+    /**
+     * Pushes flow rules to all devices.
+     */
+    private void pushRules() {
+        for (Device device : deviceService.getDevices()) {
+            pushRules(device);
+        }
+    }
+
+    /**
+     * Pushes flow rules to the device to receive control packets that need
+     * to be processed.
+     *
+     * @param device the device to push the rules to
+     */
+    private synchronized void pushRules(Device device) {
+        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+
+        // Get all ARP packets
+        sbuilder.matchEthType(Ethernet.TYPE_ARP);
+        tbuilder.punt();
+        FlowRule flowArp =
+            new DefaultFlowRule(device.id(),
+                                sbuilder.build(), tbuilder.build(),
+                                FLOW_RULE_PRIORITY, appId, 0, true);
+
+        flowRuleService.applyFlowRules(flowArp);
+    }
+
     private class InternalHostProvider implements PacketProcessor {
 
         @Override
@@ -204,23 +258,40 @@
     private class InternalDeviceListener implements DeviceListener {
         @Override
         public void event(DeviceEvent event) {
-            if (!hostRemovalEnabled) {
-                return;
-            }
-
-            DeviceEvent.Type type = event.type();
-            DeviceId deviceId = event.subject().id();
-            if (type == DeviceEvent.Type.PORT_UPDATED) {
-                ConnectPoint point = new ConnectPoint(deviceId, event.port().number());
-                removeHosts(hostService.getConnectedHosts(point));
-
-            } else if (type == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
-                if (!deviceService.isAvailable(deviceId)) {
-                    removeHosts(hostService.getConnectedHosts(deviceId));
+            Device device = event.subject();
+            switch (event.type()) {
+            case DEVICE_ADDED:
+                pushRules(device);
+                break;
+            case DEVICE_AVAILABILITY_CHANGED:
+                if (hostRemovalEnabled &&
+                    !deviceService.isAvailable(device.id())) {
+                    removeHosts(hostService.getConnectedHosts(device.id()));
                 }
-
-            } else if (type == DeviceEvent.Type.DEVICE_REMOVED) {
-                removeHosts(hostService.getConnectedHosts(deviceId));
+                break;
+            case DEVICE_SUSPENDED:
+            case DEVICE_UPDATED:
+                // Nothing to do?
+                break;
+            case DEVICE_REMOVED:
+                if (hostRemovalEnabled) {
+                    removeHosts(hostService.getConnectedHosts(device.id()));
+                }
+                break;
+            case PORT_ADDED:
+                break;
+            case PORT_UPDATED:
+                if (hostRemovalEnabled) {
+                    ConnectPoint point =
+                        new ConnectPoint(device.id(), event.port().number());
+                    removeHosts(hostService.getConnectedHosts(point));
+                }
+                break;
+            case PORT_REMOVED:
+                // Nothing to do?
+                break;
+            default:
+                break;
             }
         }
     }
diff --git a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
index 84c2ee6..4db62b4 100644
--- a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
+++ b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
@@ -15,10 +15,19 @@
  */
 package org.onosproject.provider.host.impl;
 
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+
 import com.google.common.collect.ImmutableSet;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.DefaultHost;
@@ -31,6 +40,8 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.HostDescription;
 import org.onosproject.net.host.HostProvider;
@@ -56,6 +67,7 @@
 import org.onlab.packet.VlanId;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Set;
@@ -118,10 +130,29 @@
     private final TestPacketService packetService = new TestPacketService();
 
     private PacketProcessor testProcessor;
+    private CoreService coreService;
+    private FlowRuleService flowRuleService;
     private TestHostProviderService providerService;
 
+    private ApplicationId appId = new DefaultApplicationId((short) 100,
+                "org.onosproject.provider.host");
+
     @Before
     public void setUp() {
+
+        coreService = createMock(CoreService.class);
+        expect(coreService.registerApplication(appId.name()))
+            .andReturn(appId).anyTimes();
+        replay(coreService);
+
+        flowRuleService = createMock(FlowRuleService.class);
+        flowRuleService.applyFlowRules(anyObject(FlowRule.class));
+        expectLastCall().anyTimes();
+        replay(flowRuleService);
+
+        provider.coreService = coreService;
+        provider.flowRuleService = flowRuleService;
+
         provider.providerRegistry = hostRegistry;
         provider.topologyService = topoService;
         provider.pktService = packetService;
@@ -189,8 +220,9 @@
     @After
     public void tearDown() {
         provider.deactivate();
+        provider.coreService = null;
+        provider.flowRuleService = null;
         provider.providerRegistry = null;
-
     }
 
     private class TestHostRegistry implements HostProviderRegistry {
@@ -339,6 +371,11 @@
         public void addListener(DeviceListener listener) {
             this.listener = listener;
         }
+
+        @Override
+        public Iterable<Device> getDevices() {
+            return Collections.emptyList();
+        }
     }
 
     private class TestHostService extends HostServiceAdapter {
diff --git a/providers/lldp/pom.xml b/providers/lldp/pom.xml
index 6fa7e3d..1170406 100644
--- a/providers/lldp/pom.xml
+++ b/providers/lldp/pom.xml
@@ -44,5 +44,12 @@
             <classifier>tests</classifier>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </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 0fe9676..0169e02 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
@@ -22,6 +22,9 @@
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
@@ -32,6 +35,13 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.link.LinkProvider;
 import org.onosproject.net.link.LinkProviderRegistry;
 import org.onosproject.net.link.LinkProviderService;
@@ -67,7 +77,6 @@
 @Component(immediate = true)
 public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
 
-
     private static final String PROP_USE_BDDP = "useBDDP";
 
     private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression";
@@ -76,6 +85,14 @@
 
     private final Logger log = getLogger(getClass());
 
+    private static final int FLOW_RULE_PRIORITY = 40000;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkProviderRegistry providerRegistry;
 
@@ -111,6 +128,7 @@
     protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
 
     private SuppressionRules rules;
+    private ApplicationId appId;
 
     /**
      * Creates an OpenFlow link provider.
@@ -121,6 +139,9 @@
 
     @Activate
     public void activate() {
+        appId =
+            coreService.registerApplication("org.onosproject.provider.lldp");
+
         loadSuppressionRules();
 
         providerService = providerRegistry.register(this);
@@ -153,6 +174,8 @@
         executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), INIT_DELAY,
                 DELAY, TimeUnit.SECONDS);
 
+        pushRules();
+
         log.info("Started");
     }
 
@@ -210,6 +233,48 @@
         // should refresh discoverers when we need dynamic reconfiguration
     }
 
+    /**
+     * Pushes flow rules to all devices.
+     */
+    private void pushRules() {
+        for (Device device : deviceService.getDevices()) {
+            pushRules(device);
+        }
+    }
+
+    /**
+     * Pushes flow rules to the device to receive control packets that need
+     * to be processed.
+     *
+     * @param device the device to push the rules to
+     */
+    private synchronized void pushRules(Device device) {
+        TrafficSelector.Builder sbuilder;
+        TrafficTreatment.Builder tbuilder;
+
+        // Get all LLDP packets
+        sbuilder = DefaultTrafficSelector.builder();
+        tbuilder = DefaultTrafficTreatment.builder();
+        sbuilder.matchEthType(Ethernet.TYPE_LLDP);
+        tbuilder.punt();
+        FlowRule flowLldp =
+            new DefaultFlowRule(device.id(),
+                                sbuilder.build(), tbuilder.build(),
+                                FLOW_RULE_PRIORITY, appId, 0, true);
+
+        // Get all BDDP packets
+        sbuilder = DefaultTrafficSelector.builder();
+        tbuilder = DefaultTrafficTreatment.builder();
+        sbuilder.matchEthType(Ethernet.TYPE_BSN);
+        tbuilder.punt();
+        FlowRule flowBddp =
+            new DefaultFlowRule(device.id(),
+                                sbuilder.build(), tbuilder.build(),
+                                FLOW_RULE_PRIORITY, appId, 0, true);
+
+        flowRuleService.applyFlowRules(flowLldp, flowBddp);
+    }
+
     private class InternalRoleListener implements MastershipListener {
 
         @Override
@@ -258,6 +323,8 @@
             final DeviceId deviceId = device.id();
             switch (event.type()) {
                 case DEVICE_ADDED:
+                    pushRules(device);
+                    // FALLTHROUGH
                 case DEVICE_UPDATED:
                     synchronized (discoverers) {
                         ld = discoverers.get(deviceId);
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 b37ee00..6da1716 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,6 +15,11 @@
  */
 package org.onosproject.provider.lldp.impl;
 
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Lists;
@@ -25,6 +30,9 @@
 import org.junit.Test;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.cluster.RoleInfo;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.ConnectPoint;
@@ -38,6 +46,8 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.link.LinkDescription;
 import org.onosproject.net.link.LinkProvider;
@@ -80,14 +90,33 @@
     private final TestDeviceService deviceService = new TestDeviceService();
     private final TestMasterShipService masterService = new TestMasterShipService();
 
+    private CoreService coreService;
+    private FlowRuleService flowRuleService;
     private TestLinkProviderService providerService;
 
     private PacketProcessor testProcessor;
     private DeviceListener deviceListener;
 
+    private ApplicationId appId = new DefaultApplicationId((short) 100,
+                "org.onosproject.provider.lldp");
+
     @Before
     public void setUp() {
 
+        coreService = createMock(CoreService.class);
+        expect(coreService.registerApplication(appId.name()))
+            .andReturn(appId).anyTimes();
+        replay(coreService);
+
+        flowRuleService = createMock(FlowRuleService.class);
+        flowRuleService.applyFlowRules(anyObject(FlowRule.class),
+                                       anyObject(FlowRule.class));
+        expectLastCall().anyTimes();
+        replay(flowRuleService);
+
+        provider.coreService = coreService;
+        provider.flowRuleService = flowRuleService;
+
         provider.deviceService = deviceService;
         provider.packetSevice = packetService;
         provider.providerRegistry = linkService;
@@ -178,6 +207,8 @@
     @After
     public void tearDown() {
         provider.deactivate();
+        provider.coreService = null;
+        provider.flowRuleService = null;
         provider.providerRegistry = null;
         provider.deviceService = null;
         provider.packetSevice = null;