[ONOS-5283] Arbitrary connect points, support multiple vlans

Change-Id: I9bd3536c08dfd8a637293460395de7e2a1dc1dc1
diff --git a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
index 8f0556c..178e1a8 100644
--- a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
+++ b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
@@ -16,14 +16,20 @@
 package org.onosproject.vpls;
 
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
-import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableSetMultimap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -45,10 +51,12 @@
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostService;
@@ -63,8 +71,7 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.routing.IntentSynchronizationAdminService;
 import org.onosproject.routing.IntentSynchronizationService;
-
-import com.google.common.collect.Sets;
+import org.onosproject.vpls.config.VplsConfigurationService;
 
 import static java.lang.String.format;
 import static org.easymock.EasyMock.anyObject;
@@ -75,33 +82,23 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import static org.onosproject.vpls.IntentInstaller.PREFIX_BROADCAST;
+import static org.onosproject.vpls.IntentInstaller.PREFIX_UNICAST;
+
 /**
  * Tests for the {@link Vpls} class.
  */
 public class VplsTest {
-
-    private static final int NUM_DEVICES = 7;
-
-    private static final MacAddress MAC1 = MacAddress.valueOf("00:00:00:00:00:01");
-    private static final MacAddress MAC2 = MacAddress.valueOf("00:00:00:00:00:02");
-    private static final MacAddress MAC3 = MacAddress.valueOf("00:00:00:00:00:03");
-    private static final MacAddress MAC4 = MacAddress.valueOf("00:00:00:00:00:04");
-    private static final MacAddress MAC5 = MacAddress.valueOf("00:00:00:00:00:05");
-    private static final MacAddress MAC6 = MacAddress.valueOf("00:00:00:00:00:06");
-    private static final MacAddress MAC7 = MacAddress.valueOf("00:00:00:00:00:07");
-
-    private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1");
-    private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2");
+    private static final String APP_NAME = "org.onosproject.vpls";
+    private static final ApplicationId APPID = TestApplicationId.create(APP_NAME);
+    private static final String DASH = "-";
+    private static final int PRIORITY_OFFSET = 1000;
+    private static final String NET1 = "net1";
+    private static final String NET2 = "net2";
+    private static final String COMPARE = "Comparing %s to %s";
 
     private static final PortNumber P1 = PortNumber.portNumber(1);
 
-    private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
-    private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
-
-    private static final int PRIORITY_OFFSET = 1000;
-    private static final String PREFIX_BROADCAST = "brc";
-    private static final String PREFIX_UNICAST = "uni";
-
     private static final DeviceId DID1 = getDeviceId(1);
     private static final DeviceId DID2 = getDeviceId(2);
     private static final DeviceId DID3 = getDeviceId(3);
@@ -109,37 +106,100 @@
     private static final DeviceId DID5 = getDeviceId(5);
     private static final DeviceId DID6 = getDeviceId(6);
 
-    private static final ConnectPoint C1 = new ConnectPoint(DID1, P1);
-    private static final ConnectPoint C2 = new ConnectPoint(DID2, P1);
-    private static final ConnectPoint C3 = new ConnectPoint(DID3, P1);
-    private static final ConnectPoint C4 = new ConnectPoint(DID4, P1);
-    private static final ConnectPoint C5 = new ConnectPoint(DID5, P1);
-    private static final ConnectPoint C6 = new ConnectPoint(DID6, P1);
+    private static final ConnectPoint CP1 = new ConnectPoint(DID1, P1);
+    private static final ConnectPoint CP2 = new ConnectPoint(DID2, P1);
+    private static final ConnectPoint CP3 = new ConnectPoint(DID3, P1);
+    private static final ConnectPoint CP4 = new ConnectPoint(DID4, P1);
+    private static final ConnectPoint CP5 = new ConnectPoint(DID5, P1);
+    private static final ConnectPoint CP6 = new ConnectPoint(DID6, P1);
 
-    private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
-    private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
-    private static final HostId HID3 = HostId.hostId(MAC3, VLAN1);
-    private static final HostId HID4 = HostId.hostId(MAC4, VLAN2);
-    private static final HostId HID5 = HostId.hostId(MAC5, VLAN2);
-    private static final HostId HID6 = HostId.hostId(MAC6, VLAN2);
-    private static final HostId HID7 = HostId.hostId(MAC7, VlanId.NONE);
+    private static final VlanId VLAN100 = VlanId.vlanId((short) 100);
+    private static final VlanId VLAN200 = VlanId.vlanId((short) 200);
+    private static final VlanId VLAN300 = VlanId.vlanId((short) 300);
 
-    private ApplicationService applicationService;
-    private CoreService coreService;
-    private HostListener hostListener;
-    private Set<Host> hostsAvailable;
-    private HostService hostService;
-    private IntentService intentService;
-    private InterfaceService interfaceService;
-    private Vpls vpls;
+    private static final MacAddress MAC1 =
+            MacAddress.valueOf("00:00:00:00:00:01");
+    private static final MacAddress MAC2 =
+            MacAddress.valueOf("00:00:00:00:00:02");
+    private static final MacAddress MAC3 =
+            MacAddress.valueOf("00:00:00:00:00:03");
+    private static final MacAddress MAC4 =
+            MacAddress.valueOf("00:00:00:00:00:04");
+    private static final MacAddress MAC5 =
+            MacAddress.valueOf("00:00:00:00:00:05");
+    private static final MacAddress MAC6 =
+            MacAddress.valueOf("00:00:00:00:00:06");
+    private static final MacAddress MAC7 =
+            MacAddress.valueOf("00:00:00:00:00:07");
 
-    private static final String APP_NAME = "org.onosproject.vpls";
-    private static final ApplicationId APPID = TestApplicationId.create(APP_NAME);
+    private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1");
+    private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2");
+
+    private static final HostId HID1 = HostId.hostId(MAC1, VLAN100);
+    private static final HostId HID2 = HostId.hostId(MAC2, VLAN100);
+    private static final HostId HID3 = HostId.hostId(MAC3, VLAN200);
+    private static final HostId HID4 = HostId.hostId(MAC4, VLAN200);
+    private static final HostId HID5 = HostId.hostId(MAC5, VLAN300);
+    private static final HostId HID6 = HostId.hostId(MAC6, VLAN300);
+    private static final HostId HID7 = HostId.hostId(MAC7, VLAN300);
 
     private static final ProviderId PID = new ProviderId("of", "foo");
 
     private static IdGenerator idGenerator;
 
+    private final Interface v100h1 =
+            new Interface("v100h1", CP1, null, null, VLAN100);
+    private final Interface v100h2 =
+            new Interface("v100h2", CP2, null, null, VLAN100);
+    private final Interface v200h1 =
+            new Interface("v200h1", CP3, null, null, VLAN200);
+    private final Interface v200h2 =
+            new Interface("v200h2", CP4, null, null, VLAN200);
+    private final Interface v300h1 =
+            new Interface("v300h1", CP5, null, null, VLAN300);
+    private final Interface v300h2 =
+            new Interface("v300h2", CP6, null, null, VLAN300);
+
+    private final Host v100host1 =
+            new DefaultHost(PID, HID1, MAC1, VLAN100,
+                    getLocation(1), Collections.singleton(IP1));
+    private final Host v100host2 =
+            new DefaultHost(PID, HID2, MAC2, VLAN100,
+                    getLocation(2), Sets.newHashSet());
+    private final Host v200host1 =
+            new DefaultHost(PID, HID3, MAC3, VLAN200,
+                    getLocation(3), Collections.singleton(IP2));
+    private final Host v200host2 =
+            new DefaultHost(PID, HID4, MAC4, VLAN200,
+                    getLocation(4), Sets.newHashSet());
+    private final Host v300host1 =
+            new DefaultHost(PID, HID5, MAC5, VLAN300,
+                    getLocation(5), Sets.newHashSet());
+    private final Host v300host2 =
+            new DefaultHost(PID, HID6, MAC6, VLAN300,
+                    getLocation(6), Sets.newHashSet());
+    private final Host v300host3 =
+            new DefaultHost(PID, HID7, MAC7, VLAN300,
+                    getLocation(7), Sets.newHashSet());
+
+    private final Set<Interface> avaliableInterfaces =
+            ImmutableSet.of(v100h1, v100h2, v200h1, v200h2, v300h1, v300h2);
+
+    private final Set<Host> avaliableHosts =
+            ImmutableSet.of(v100host1, v100host2, v200host1,
+                    v200host2, v300host1, v300host2, v300host3);
+
+    private ApplicationService applicationService;
+    private CoreService coreService;
+    private HostListener hostListener;
+    private NetworkConfigService configService;
+    private Set<Host> hostsAvailable;
+    private HostService hostService;
+    private IntentService intentService;
+    private InterfaceService interfaceService;
+    private VplsConfigurationService vplsConfigService;
+    private Vpls vpls;
+
     @Before
     public void setUp() throws Exception {
         idGenerator = new TestIdGenerator();
@@ -147,6 +207,8 @@
 
         applicationService = createMock(ApplicationService.class);
 
+        configService = createMock(NetworkConfigService.class);
+
         coreService = createMock(CoreService.class);
         expect(coreService.registerApplication(APP_NAME))
                 .andReturn(APPID);
@@ -165,12 +227,25 @@
         expectLastCall().anyTimes();
         addIntfConfig();
 
+        SetMultimap<String, Interface> vplsNetworks =
+                HashMultimap.create();
+        vplsNetworks.put(NET1, v100h1);
+        vplsNetworks.put(NET1, v200h1);
+        vplsNetworks.put(NET1, v300h1);
+        vplsNetworks.put(NET2, v100h2);
+        vplsNetworks.put(NET2, v200h2);
+        vplsNetworks.put(NET2, v300h2);
+
+        vplsConfigService = new TestVplsConfigService(vplsNetworks);
+
         vpls = new Vpls();
         vpls.applicationService = applicationService;
         vpls.coreService = coreService;
         vpls.hostService = hostService;
+        vpls.vplsConfigService = vplsConfigService;
         vpls.intentService = intentService;
         vpls.interfaceService = interfaceService;
+        vpls.configService = configService;
         vpls.intentSynchronizer = intentSynchronizer;
 
     }
@@ -181,181 +256,189 @@
     }
 
     /**
-     * Creates the interface configuration. On devices 1, 2 and 3 is configured
-     * an interface on port 1 with vlan 1. On devices 4, 5 and 6 is configured
-     * an interface on port 1 with vlan 2. On device 5 no interfaces are
-     * configured.
+     * Creates the interface configuration. On devices 1 and 2 is configured
+     * an interface on port 1 with vlan 100. On devices 3 and 4 is configured
+     * an interface on port 1 with vlan 200. On device 5 and 6 is configured
+     * an interface on port 1 with vlan 300.
      */
     private void addIntfConfig() {
-        Set<Interface> interfaces = Sets.newHashSet();
-        Set<Interface> vlanOneSet = Sets.newHashSet();
-        Set<Interface> vlanTwoSet = Sets.newHashSet();
+        Set<Interface> interfaces = ImmutableSet.copyOf(avaliableInterfaces);
+        Set<Interface> vlanOneSet = ImmutableSet.of(v100h1, v100h2);
+        Set<Interface> vlanTwoSet = ImmutableSet.of(v200h1, v200h2);
+        Set<Interface> vlanThreeSet = ImmutableSet.of(v300h1, v300h2);
 
-        for (int i = 1; i <= NUM_DEVICES - 1; i++) {
-            ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
-
-            Interface intf =
-                    new Interface("intfOne", cp, Collections.emptyList(), null,
-                                  VlanId.NONE);
-
-            if (i <= 3) {
-                intf = new Interface("intfTwo", cp, Collections.emptyList(),
-                                     null, VLAN1);
-                interfaces.add(intf);
-                vlanOneSet.add(intf);
-            } else if (i > 3 && i <= 6) {
-                intf = new Interface("intfThree", cp, Collections.emptyList(),
-                                     null, VLAN2);
-                interfaces.add(intf);
-                vlanTwoSet.add(intf);
-            }
-            expect(interfaceService.getInterfacesByPort(cp))
+        avaliableInterfaces.forEach(intf -> {
+            expect(interfaceService.getInterfacesByPort(intf.connectPoint()))
                     .andReturn(Sets.newHashSet(intf)).anyTimes();
-        }
-        expect(interfaceService.getInterfacesByVlan(VLAN1))
+        });
+        expect(interfaceService.getInterfacesByVlan(VLAN100))
                 .andReturn(vlanOneSet).anyTimes();
-        expect(interfaceService.getInterfacesByVlan(VLAN2))
+        expect(interfaceService.getInterfacesByVlan(VLAN200))
                 .andReturn(vlanTwoSet).anyTimes();
+        expect(interfaceService.getInterfacesByVlan(VLAN300))
+                .andReturn(vlanThreeSet).anyTimes();
         expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
 
         replay(interfaceService);
     }
 
     /**
-     * Checks the case in which six ports are configured with VLANs but no
-     * hosts are registered by the HostService. The first three ports have an
-     * interface configured on VLAN1, the other three on VLAN2. The number of
-     * intents expected is six: three for VLAN1, three for VLAN2. three sp2mp
-     * intents, three mp2sp intents.
+     * Six ports are configured with VLANs but no hosts are registered by the
+     * HostService. The first three ports have an interface configured on NET1,
+     * the other three on NET2. The number of intents expected is six: three for
+     * NET1, three for NET2. Six mp2sp intents. Checks if the number of intents
+     * submitted to the intent framework is equal to the number of intents
+     * expected and if all intents are equivalent.
      */
     @Test
     public void testActivateNoHosts() {
         vpls.activate();
 
         List<Intent> expectedIntents = Lists.newArrayList();
-        expectedIntents.addAll(generateVlanOneBrc());
-        expectedIntents.addAll(generateVlanTwoBrc());
+        Set<FilteredConnectPoint> fcPoints;
+
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h1, v200h1, v300h1));
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET1));
+
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h2, v200h2, v300h2));
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET2));
 
         checkIntents(expectedIntents);
     }
 
     /**
-     * Checks the case in which six ports are configured with VLANs and four
-     * hosts are registered by the HostService. The first three ports have an
-     * interface configured on VLAN1, the other three on VLAN2. The number of
-     * intents expected is twelve: six for VLAN1, six for VLAN2. six sp2mp
-     * intents, six mp2sp intents. For VLAN1 IPs are added to demonstrate it
-     * doesn't influence the number of intents created.
+     * Six ports are configured with VLANs and six hosts are registered by the
+     * HostService. The first three ports have an interface configured on NET1,
+     * the other three on NET2. The number of intents expected is twelve: six
+     * for VLAN1, six for NET2. six sp2mp intents, six mp2sp intents. For NET1
+     * IPs are added to demonstrate this doesn't influence the number of intents
+     * created. Checks if the number of intents submitted to the intent
+     * framework is equal to the number of intents expected and if all intents
+     * are equivalent.
      */
     @Test
-    public void testFourInterfacesConfiguredHostsPresent() {
-        Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1),
-                                  Collections.singleton(IP1));
-        Host h2 = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(2),
-                                  Collections.singleton(IP2));
-        Host h3 = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(3),
-                                  Collections.EMPTY_SET);
-        Host h4 = new DefaultHost(PID, HID4, MAC4, VLAN2, getLocation(4),
-                                  Collections.EMPTY_SET);
-        Host h5 = new DefaultHost(PID, HID5, MAC5, VLAN2, getLocation(5),
-                                  Collections.EMPTY_SET);
-        Host h6 = new DefaultHost(PID, HID6, MAC6, VLAN2, getLocation(6),
-                                  Collections.EMPTY_SET);
-        hostsAvailable.addAll(Sets.newHashSet(h1, h2, h3, h4, h5, h6));
+    public void testSixInterfacesConfiguredHostsPresent() {
+        hostsAvailable.addAll(avaliableHosts);
 
         vpls.activate();
 
         List<Intent> expectedIntents = Lists.newArrayList();
-        expectedIntents.addAll(generateVlanOneBrc());
-        expectedIntents.addAll(generateVlanOneUni());
-        expectedIntents.addAll(generateVlanTwoBrc());
-        expectedIntents.addAll(generateVlanTwoUni());
+        Set<FilteredConnectPoint> fcPoints;
+        Set<Host> hosts;
+
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h1, v200h1, v300h1));
+        hosts = ImmutableSet.of(v100host1, v200host1, v300host1);
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET1));
+        expectedIntents.addAll(generateVplsUni(fcPoints, hosts, NET1));
+
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h2, v200h2, v300h2));
+        hosts = ImmutableSet.of(v100host2, v200host2, v300host2);
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET2));
+        expectedIntents.addAll(generateVplsUni(fcPoints, hosts, NET2));
 
         checkIntents(expectedIntents);
     }
 
     /**
-     * Checks the case in which six ports are configured with VLANs and
-     * initially no hosts are registered by the HostService. The first three
-     * ports have an interface configured on VLAN1, the other three have an
-     * interface configured on VLAN2. When the module starts up, three hosts -
-     * on device one, two and three - port 1 (both on VLAN1), are registered by
-     * the HostService and events are sent to the application. sp2mp intents
-     * are created for all interfaces configured and mp2sp intents are created
-     * only for the hosts attached.
-     * The number of intents expected is nine: six for VLAN1, three for VLAN2.
+     * Six ports are configured with VLANs and initially no hosts are registered
+     * by the HostService. The first three ports have an interface configured on
+     * NET1, the other three have an interface configured on NET2. When the
+     * module starts up, three hosts attached to device one, two and three -
+     * port 1, are registered by the HostService and events are sent to the
+     * application. sp2mp intents are created for all interfaces configured and
+     * mp2sp intents are created only for the hosts attached.
+     * The number of intents expected is nine: six for NET1, three for NET2.
      * Six sp2mp intents, three mp2sp intents. IPs are added on the first two
-     * hosts only to demonstrate it doesn't influence the number of intents
+     * hosts only to demonstrate this doesn't influence the number of intents
      * created.
-     * An additional host is added on device seven, port one to demonstrate
-     * that, even if it's on the same VLAN of other interfaces configured in
-     * the system, it doesn't let the application generate intents, since it's
-     * not connected to the interface configured.
+     * An additional host is added on device seven - port 1, to demonstrate that
+     * the application does not generate intents, even if the interface uses the
+     * same VLAN Id of the other interfaces configured for the specifc VPLS.
+     * Checks if the number of intents submitted to the intent framework is equal
+     * to the number of intents expected and if all intents are equivalent.
      */
     @Test
-    public void testFourInterfacesThreeHostEventsSameVlan() {
+    public void testSixInterfacesThreeHostEventsSameVpls() {
         vpls.activate();
 
-        Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1),
-                                  Collections.singleton(IP1));
-        Host h2 = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(2),
-                                  Collections.singleton(IP2));
-        Host h3 = new DefaultHost(PID, HID3, MAC3, VLAN1, getLocation(3),
-                                  Collections.EMPTY_SET);
-        Host h7 = new DefaultHost(PID, HID7, MAC7, VLAN1, getLocation(7),
-                                  Collections.EMPTY_SET);
-        hostsAvailable.addAll(Sets.newHashSet(h1, h2, h3, h7));
+        List<Intent> expectedIntents = Lists.newArrayList();
+        Set<FilteredConnectPoint> fcPoints;
+        Set<Host> hosts;
+
+        hostsAvailable.addAll(Sets.newHashSet(v100host1, v200host1, v300host1, v300host3));
 
         hostsAvailable.forEach(host ->
-            hostListener.event(new HostEvent(HostEvent.Type.HOST_ADDED, host)));
+                hostListener.event(new HostEvent(HostEvent.Type.HOST_ADDED, host)));
 
-        List<Intent> expectedIntents = Lists.newArrayList();
-        expectedIntents.addAll(generateVlanOneBrc());
-        expectedIntents.addAll(generateVlanOneUni());
-        expectedIntents.addAll(generateVlanTwoBrc());
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h1, v200h1, v300h1));
+        hosts = ImmutableSet.of(v100host1, v200host1, v300host1);
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET1));
+        expectedIntents.addAll(generateVplsUni(fcPoints, hosts, NET1));
+
+        fcPoints = buildFCPoints(ImmutableSet.of(v100h2, v200h2, v300h2));
+        expectedIntents.addAll(generateVplsBrc(fcPoints, NET2));
 
         checkIntents(expectedIntents);
     }
 
     /**
-     * Checks the case in which six ports are configured with VLANs and
-     * initially no hosts are registered by the HostService. The first three
-     * ports have an interface configured on VLAN1, the other three have an
-     * interface configured on VLAN2. When the module starts up, two hosts -
-     * on device one and four - port 1 (VLAN 1 and VLAN 2), are registered by
-     * the HostService and events are sent to the application. sp2mp intents
-     * are created for all interfaces configured and no mp2sp intents are created
-     * at all, since the minimum number of hosts needed on the same vlan to
-     * create mp2sp intents is 2.
-     * The number of intents expected is six: three for VLAN1, three for VLAN2.
-     * six sp2mp intents, zero mp2sp intents. IPs are added on the first host
-     * only to demonstrate it doesn't influence the number of intents created.
+     * Generates a list of the expected sp2mp intents for a VPLS.
+     *
+     * @param fcPoints the filtered connect point
+     * @param name the name of the VPLS
+     * @return the list of expected sp2mp intents for the given VPLS
      */
-    @Test
-    public void testFourInterfacesTwoHostEventsDifferentVlan() {
-        vpls.activate();
+    private List<SinglePointToMultiPointIntent>
+    generateVplsBrc(Set<FilteredConnectPoint> fcPoints, String name) {
+        List<SinglePointToMultiPointIntent> intents = Lists.newArrayList();
 
-        Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(1),
-                                  Collections.singleton(IP1));
-        Host h4 = new DefaultHost(PID, HID4, MAC4, VLAN2, getLocation(4),
-                                  Collections.EMPTY_SET);
-        hostsAvailable.addAll(Sets.newHashSet(h1, h4));
+        fcPoints.forEach(point -> {
+            Set<FilteredConnectPoint> otherPoints =
+                    fcPoints.stream()
+                            .filter(fcp -> !fcp.equals(point))
+                            .collect(Collectors.toSet());
 
-        hostsAvailable.forEach(host -> {
-            hostListener.event(new HostEvent(HostEvent.Type.HOST_ADDED, host));
+            Key brckey = buildKey(PREFIX_BROADCAST,
+                    point.connectPoint(), name, MacAddress.BROADCAST);
+
+            intents.add(buildBrcIntent(brckey, point, otherPoints));
         });
 
-        List<Intent> expectedIntents = Lists.newArrayList();
-        expectedIntents.addAll(generateVlanOneBrc());
-        expectedIntents.addAll(generateVlanTwoBrc());
-
-        checkIntents(expectedIntents);
+        return intents;
     }
 
     /**
-     * Checks both that the number of intents in submitted in the intent
-     * framework it's equal to the number of intents expected and that all
-     * intents are equivalent.
+     * Generates a list of expected mp2sp intents for a given VPLS.
+     *
+     * @param fcPoints the filtered connect point
+     * @param hosts the hosts
+     * @param name the name of the VPLS
+     * @return the list of expected mp2sp intents for the given VPLS
+     */
+    private List<MultiPointToSinglePointIntent>
+    generateVplsUni(Set<FilteredConnectPoint> fcPoints, Set<Host> hosts, String name) {
+        List<MultiPointToSinglePointIntent> intents = Lists.newArrayList();
+
+        hosts.forEach(host -> {
+            FilteredConnectPoint hostPoint = getHostPoint(host, fcPoints);
+
+            Set<FilteredConnectPoint> otherPoints =
+                    fcPoints.stream()
+                            .filter(fcp -> !fcp.equals(hostPoint))
+                            .collect(Collectors.toSet());
+
+            Key uniKey = buildKey(PREFIX_UNICAST,
+                    host.location(), name, host.mac());
+
+            intents.add(buildUniIntent(uniKey, otherPoints, hostPoint, host));
+        });
+
+        return intents;
+    }
+
+    /**
+     * Checks if the number of intents submitted to the intent framework is equal
+     * to the number of intents expected and if all intents are equivalent.
      *
      * @param intents the list of intents expected
      */
@@ -367,8 +450,8 @@
             for (Intent intentTwo : intentService.getIntents()) {
                 if (intentOne.key().equals(intentTwo.key())) {
                     found = true;
-                    assertTrue(format("Comparing %s and %s", intentOne, intentTwo),
-                               IntentUtils.intentsAreEqual(intentOne, intentTwo));
+                    assertTrue(format(COMPARE, intentOne, intentTwo),
+                            IntentUtils.intentsAreEqual(intentOne, intentTwo));
                     break;
                 }
             }
@@ -377,190 +460,143 @@
     }
 
     /**
-     * Generates the list of the expected sp2mp intents for VLAN 1.
+     * Builds a broadcast intent.
      *
-     * @return the list of expected sp2mp intents for VLAN 1
-     */
-    private List<SinglePointToMultiPointIntent> generateVlanOneBrc() {
-        Key key = null;
-
-        List<SinglePointToMultiPointIntent> intents = Lists.newArrayList();
-
-        // Building sp2mp intent for H1 - VLAN1
-        key = Key.of((PREFIX_BROADCAST + "-" + DID1 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildBrcIntent(key, C1, Sets.newHashSet(C2, C3), VLAN1));
-
-        // Building sp2mp intent for H2 - VLAN1
-        key = Key.of((PREFIX_BROADCAST + "-" + DID2 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildBrcIntent(key, C2, Sets.newHashSet(C1, C3), VLAN1));
-
-        // Building sp2mp intent for H3 - VLAN1
-        key = Key.of((PREFIX_BROADCAST + "-" + DID3 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildBrcIntent(key, C3, Sets.newHashSet(C1, C2), VLAN1));
-
-        return intents;
-    }
-
-    /**
-     * Generates the list of the expected mp2sp intents for VLAN 1.
-     *
-     * @return the list of expected mp2sp intents for VLAN 1
-     */
-    private List<MultiPointToSinglePointIntent> generateVlanOneUni() {
-        Key key = null;
-
-        List<MultiPointToSinglePointIntent> intents = Lists.newArrayList();
-
-        // Building mp2sp intent for H1 - VLAN1
-        key = Key.of((PREFIX_UNICAST + "-" + DID1 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C2, C3), C1, VLAN1, MAC1));
-
-        // Building mp2sp intent for H2 - VLAN1
-        key = Key.of((PREFIX_UNICAST + "-" + DID2 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C1, C3), C2, VLAN1, MAC2));
-
-        // Building mp2sp intent for H3 - VLAN1
-        key = Key.of((PREFIX_UNICAST + "-" + DID3 + "-" + P1 + "-" + VLAN1),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C1, C2), C3, VLAN1, MAC3));
-
-        return intents;
-    }
-
-    /**
-     * Generates the list of the expected sp2mp intents for VLAN 2.
-     *
-     * @return the list of expected sp2mp intents for VLAN 2
-     */
-    private List<SinglePointToMultiPointIntent> generateVlanTwoBrc() {
-        Key key = null;
-
-        List<SinglePointToMultiPointIntent> intents = Lists.newArrayList();
-
-        // Building sp2mp intent for H4 - VLAN2
-        key = Key.of((PREFIX_BROADCAST + "-" + DID4 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildBrcIntent(key, C4, Sets.newHashSet(C5, C6), VLAN2));
-
-        // Building sp2mp intent for H5 - VLAN2
-        key = Key.of((PREFIX_BROADCAST + "-" + DID5 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildBrcIntent(key, C5, Sets.newHashSet(C4, C6), VLAN2));
-
-        // Building sp2mp intent for H6 - VLAN2
-        key = Key.of((PREFIX_BROADCAST + "-" + DID6 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildBrcIntent(key, C6, Sets.newHashSet(C4, C5), VLAN2));
-
-        return intents;
-    }
-
-    /**
-     * Generates the list of the expected mp2sp intents for VLAN 2.
-     *
-     * @return the list of expected mp2sp intents for VLAN 2
-     */
-    private List<MultiPointToSinglePointIntent> generateVlanTwoUni() {
-        Key key = null;
-
-        List<MultiPointToSinglePointIntent> intents = Lists.newArrayList();
-
-        // Building mp2sp intent for H4 - VLAN2
-        key = Key.of((PREFIX_UNICAST + "-" + DID4 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C5, C6), C4, VLAN2, MAC4));
-
-        // Building mp2sp intent for H5 - VLAN2
-        key = Key.of((PREFIX_UNICAST + "-" + DID5 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C4, C6), C5, VLAN2, MAC5));
-
-        // Building mp2sp intent for H6 - VLAN2
-        key = Key.of((PREFIX_UNICAST + "-" + DID6 + "-" + P1 + "-" + VLAN2),
-                     APPID);
-        intents.add(buildUniIntent(key, Sets.newHashSet(C4, C5), C6, VLAN2, MAC6));
-
-        return intents;
-    }
-
-    /**
-     * Builds a Single Point to Multi Point intent.
-     *
-     * @param key  The intent key
-     * @param src  The source Connect Point
-     * @param dsts The destination Connect Points
-     * @return Single Point to Multi Point intent generated.
+     * @param key the key to identify the intent
+     * @param src the ingress connect point
+     * @param dsts the egress connect points
+     * @return the generated single-point to multi-point intent
      */
     private SinglePointToMultiPointIntent buildBrcIntent(Key key,
-                                                         ConnectPoint src,
-                                                         Set<ConnectPoint> dsts,
-                                                         VlanId vlanId) {
+                                                           FilteredConnectPoint src,
+                                                           Set<FilteredConnectPoint> dsts) {
         SinglePointToMultiPointIntent intent;
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
-
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchEthDst(MacAddress.BROADCAST)
-                .matchVlanId(vlanId)
                 .build();
 
         intent = SinglePointToMultiPointIntent.builder()
                 .appId(APPID)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
-                .ingressPoint(src)
-                .egressPoints(dsts)
+                .filteredIngressPoint(src)
+                .filteredEgressPoints(dsts)
                 .priority(PRIORITY_OFFSET)
                 .build();
         return intent;
     }
 
     /**
-     * Builds a Multi Point to Single Point intent.
+     * Builds a unicast intent.
      *
-     * @param key  The intent key
-     * @param srcs The source Connect Points
-     * @param dst  The destination Connect Point
-     * @return Multi Point to Single Point intent generated.
+     * @param key the key to identify the intent
+     * @param srcs the ingress connect points
+     * @param dst the egress connect point
+     * @param host the destination Host
+     * @return the generated multi-point to single-point intent
      */
     private MultiPointToSinglePointIntent buildUniIntent(Key key,
-                                                         Set<ConnectPoint> srcs,
-                                                         ConnectPoint dst,
-                                                         VlanId vlanId,
-                                                         MacAddress mac) {
-        MultiPointToSinglePointIntent intent;
+                                                           Set<FilteredConnectPoint> srcs,
+                                                           FilteredConnectPoint dst,
+                                                           Host host) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchEthDst(host.mac())
+                .build();
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
-
-        TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
-                .matchEthDst(mac)
-                .matchVlanId(vlanId);
-
-        TrafficSelector selector = builder.build();
-
-        intent = MultiPointToSinglePointIntent.builder()
+        return MultiPointToSinglePointIntent.builder()
                 .appId(APPID)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
-                .ingressPoints(srcs)
-                .egressPoint(dst)
+                .filteredIngressPoints(srcs)
+                .filteredEgressPoint(dst)
                 .priority(PRIORITY_OFFSET)
                 .build();
-        return intent;
+
     }
 
     /**
-     * Returns the device ID of the ith device.
+     * Returns the filtered connect point associated to a given host.
      *
-     * @param i device to get the ID of
-     * @return the device ID
+     * @param host the target host
+     * @param fcps the filtered connected points
+     * @return the filtered connect point associated to the given host; null
+     * otherwise
+     */
+    private FilteredConnectPoint getHostPoint(Host host,
+                                              Set<FilteredConnectPoint> fcps) {
+        return fcps.stream()
+                .filter(fcp -> fcp.connectPoint().equals(host.location()))
+                .filter(fcp -> {
+                    VlanIdCriterion vlanCriterion =
+                            (VlanIdCriterion) fcp.trafficSelector().
+                                    getCriterion(Criterion.Type.VLAN_VID);
+
+                    return vlanCriterion != null &&
+                            vlanCriterion.vlanId().equals(host.vlan());
+                })
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * Computes a set of filtered connect points from given interfaces.
+     *
+     * @param interfaces the interfaces belonging to the VPLS
+     * @return the set of filtered connect points
+     */
+    private Set<FilteredConnectPoint> buildFCPoints(Set<Interface> interfaces) {
+        // Build all filtered connected point in the network
+        return interfaces
+                .stream()
+                .map(intf -> {
+                    TrafficSelector.Builder selectorBuilder =
+                            DefaultTrafficSelector.builder();
+
+                    if (!intf.vlan().equals(VlanId.NONE)) {
+                        selectorBuilder.matchVlanId(intf.vlan());
+                    }
+
+                    return new FilteredConnectPoint(intf.connectPoint(),
+                            selectorBuilder.build());
+                })
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Builds an intent Key either for a single-point to multi-point or
+     * multi-point to single-point intent, based on a prefix that defines
+     * the intent type, the connection point representing the source or the
+     * destination and the VLAN Id representing the network.
+     *
+     * @param prefix the key prefix
+     * @param cPoint the ingress/egress connect point
+     * @param networkName the VPLS name
+     * @param hostMac the ingress/egress MAC address
+     * @return the key to identify the intent
+     */
+    private Key buildKey(String prefix,
+                           ConnectPoint cPoint,
+                           String networkName,
+                           MacAddress hostMac) {
+        String keyString = networkName +
+                DASH +
+                prefix +
+                DASH +
+                cPoint.deviceId() +
+                DASH +
+                cPoint.port() +
+                DASH +
+                hostMac;
+
+        return Key.of(keyString, APPID);
+    }
+
+    /**
+     * Returns the device Id of the ith device.
+     *
+     * @param i the device to get the Id of
+     * @return the device Id
      */
     private static DeviceId getDeviceId(int i) {
         return DeviceId.deviceId("" + i);
@@ -571,8 +607,8 @@
     }
 
     /**
-     * Represents a fake IntentService class that easily allows to store and
-     * retrieve intents without implementing the IntentService logic.
+     * Represents a fake IntentService class that allows to store and retrieve
+     * intents without implementing the IntentService logic.
      */
     private class TestIntentService extends IntentServiceAdapter {
 
@@ -628,13 +664,15 @@
         @Override
         public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
             return hosts.stream()
-                    .filter(h -> h.location().elementId().equals(connectPoint.elementId())
-                              && h.location().port().equals(connectPoint.port()))
+                    .filter(h -> h.location().equals(connectPoint))
                     .collect(Collectors.toSet());
         }
 
     }
 
+    /**
+     * Represents a fake IdGenerator class for intents.
+     */
     private static class TestIdGenerator implements IdGenerator {
 
         private final AtomicLong id = new AtomicLong(0);
@@ -656,7 +694,7 @@
         private final IntentService intentService;
 
         /**
-         * Creates a new test intent synchronizer.
+         * Creates a new intent test synchronizer.
          *
          * @param intentService intent service
          */
@@ -687,4 +725,120 @@
         }
     }
 
+    /**
+     * Represents a fake VplsConfigService class which is needed for testing.
+     */
+    private class TestVplsConfigService implements VplsConfigurationService {
+
+        private final SetMultimap<String, Interface> vplsNetworks;
+        private Set<String> vplsAffectByApi = new HashSet<>();
+
+        TestVplsConfigService(SetMultimap<String, Interface> vplsNetworks) {
+            this.vplsNetworks = vplsNetworks;
+        }
+
+        @Override
+        public void addVpls(String name, Set<String> ifaces) {
+            if (!vplsNetworks.containsKey(name)) {
+                ifaces.forEach(iface -> {
+                    avaliableInterfaces.forEach(intf -> {
+                        if (intf.name().equals(iface)) {
+                            vplsNetworks.put(name, intf);
+                        }
+                    });
+                });
+            }
+        }
+
+        @Override
+        public void removeVpls(String name) {
+            if (vplsNetworks.containsKey(name)) {
+                vplsNetworks.removeAll(name);
+            }
+        }
+
+        @Override
+        public void addInterfaceToVpls(String name, String iface) {
+            if (!vplsNetworks.containsKey(name)) {
+                avaliableInterfaces.forEach(intf -> {
+                    if (intf.name().equals(iface)) {
+                        vplsNetworks.put(name, intf);
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void removeInterfaceFromVpls(String iface) {
+            SetMultimap<String, Interface> search = HashMultimap.create(vplsNetworks);
+            search.entries().forEach(e -> {
+                if (e.getValue().name().equals(iface)) {
+                    vplsNetworks.remove(e.getKey(), iface);
+                }
+            });
+        }
+
+        @Override
+        public void cleanVpls() {
+            vplsNetworks.clear();
+        }
+
+        @Override
+        public Set<String> getVplsAffectedByApi() {
+            Set<String> vplsNames = ImmutableSet.copyOf(vplsAffectByApi);
+
+            vplsAffectByApi.clear();
+
+            return vplsNames;
+        }
+
+        @Override
+        public Set<Interface> getAllInterfaces() {
+            return vplsNetworks.values()
+                    .stream()
+                    .collect(Collectors.toSet());
+        }
+
+        @Override
+        public Set<Interface> getVplsInterfaces(String name) {
+            return vplsNetworks.get(name)
+                    .stream()
+                    .collect(Collectors.toSet());
+        }
+
+        @Override
+        public Set<String> getAllVpls() {
+            return vplsNetworks.keySet();
+        }
+
+        @Override
+        public Set<String> getOldVpls() {
+            return vplsNetworks.keySet();
+        }
+
+        @Override
+        public SetMultimap<String, Interface> getVplsNetworks() {
+            return ImmutableSetMultimap.copyOf(vplsNetworks);
+        }
+
+        @Override
+        public SetMultimap<String, Interface> getVplsNetwork(VlanId vlan,
+                                                             ConnectPoint connectPoint) {
+            String vplsNetworkName =
+                    vplsNetworks.entries().stream()
+                            .filter(e -> e.getValue().connectPoint().equals(connectPoint))
+                            .filter(e -> e.getValue().vlan().equals(vlan))
+                            .map(e -> e.getKey())
+                            .findFirst()
+                            .orElse(null);
+            SetMultimap<String, Interface> result = HashMultimap.create();
+            if (vplsNetworkName != null && vplsNetworks.containsKey(vplsNetworkName)) {
+                vplsNetworks.get(vplsNetworkName)
+                        .forEach(intf -> result.put(vplsNetworkName, intf));
+                return result;
+            }
+            return null;
+        }
+
+    }
 }