Introduces Virtual Circuit functionality for SDX-L2

Changes:
- Implements commands: sdxl2vc, sdxl2vc-add, sdxl2vc-list, sdxl2vc-remove
- Custom exceptions handled at the VC manager
- Updated README
- Updated unit tests
- Grouped some documentation and code
- Reduced checkstyle warnings

Change-Id: I4cb211dcfd1f3517f4e594c1cc1c816f9c3cdbe3
diff --git a/sdx-l2/README.md b/sdx-l2/README.md
index 8b25f24..397f4f8 100644
--- a/sdx-l2/README.md
+++ b/sdx-l2/README.md
@@ -5,6 +5,7 @@
 
 SDX-L2 is an application for ONOS project which can provide layer 2 connectivity between edge ports of a given SDN network.
 
+
 License
 =======
 
@@ -13,16 +14,13 @@
 Information can be found here:
  [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
 
-Tips
-==============
-
-TBD.
 
 SDX-L2 dependencies
 =============================
 
 SDX-L2 implements its own ARP/NDP handler, it is important to disable the ONOS ARP/NDP handler.
 
+
 SDX-L2 installation
 =============================
 
@@ -38,9 +36,13 @@
 
         onos-app $OC1 install target/onos-app-sdx-l2-1.7.0-SNAPSHOT.oar
 
-SDX-L2 cli commands
+
+SDX-L2 CLI commands
 =============================
 
+General
+-----------------------------
+
 - Create a named SDX:
 
         sdxl2-add $sdxname
@@ -56,51 +58,149 @@
         sdxl2-list
 
 
-- Create a named SDX-L2 connection point:
+Connection Points (CP)
+-----------------------------
 
-        sdxl2cp-add [-ce_mac] $mac $sdxname $connectionpoint $vlans $sdxcpname
+- Create a named SDX-L2 CP:
 
+        sdxl2cp-add [-ce_mac $mac] $sdxname $connectionpoint $sdxcpname [$vlans]
 
-- Remove a named SDX-L2 connection point:
+  where $vlans can define:
+    - explicit VLANs, ranges or a combination of both: 5,10-15
+    - all port: -1 (or just ignore)
+
+ *note that CPs must have same number of VLANs in order to establish a VC*
+
+- Remove a named SDX-L2 CP:
 
         sdxl2cp-remove $sdxcpname
 
 
-- List all the active SDX-L2 connection points or all the active SDX connection points related to an SDX:
-
-        sdxl2cps-list [$sdxname]
-
-
-- Get the information of an SDX-L2 connection point:
+- Get the information of an SDX-L2 CP:
 
         sdxl2cp $sdxcpname
 
-<!---
 
-NOT YET MERGED!!!
+- List all active SDX-L2 CPs or all active SDX CPs related to an SDX:
 
-- Create a VC between two connection points:
+        sdxl2cp-list [$sdxname]
 
-        add-sdxl2vc $sdxname $sdxcp1 $sdxcp2
+
+Virtual Circuits (VC)
+-----------------------------
+
+- Create a VC between two CPs:
+
+        sdxl2vc-add $sdxname $sdxcp1 $sdxcp2
 
 
 - Remove a named VC:
 
-        remove-sdxl2vc $sdxcname
+        sdxl2vc-remove $sdxcname
 
 
-- List all the active layer2 virtual circuit or all the layer2 vc related to an SDX:
-
-        list-sdxl2vcs [$sdxname]
-
-
-- Get the information of a layer 2 virtual circuit:
+- Get the information of a L2 VC:
 
         sdxl2vc $sdxvcname
 
-SDXL2 GUI
+
+- List all active L2 VCs or all L2 VCs related to an SDX:
+
+        sdxl2vc-list [$sdxname]
+
+
+SDX-L2 usage examples
 =============================
 
-- TBD
+- Create a named SDX-L2:
 
---->
\ No newline at end of file
+        onos> sdxl2:sdxl2-add SDXL2Test
+        onos> sdxl2:sdxl2-list
+
+        SDXL2
+        --------------
+        SDXL2Test
+
+
+- Create two CPs and list brief and detailed info:
+
+  where the connection points are the IDs of the devices provided through the 'edge-ports' ONOS CLI command
+
+        onos> sdxl2:sdxl2cp-add -ce_mac 00:00:00:00:00:01 SDXL2Test of:0000000000000003/2 Sw3P2 5,15-17
+        onos> sdxl2:sdxl2cp-add -ce_mac 00:00:00:00:00:02 SDXL2Test of:0000000000000002/1 Sw2P1 6,19-21
+
+        onos> sdxl2:sdxl2cp-list
+
+        Status		SDXL2 Connection Point
+        -----------------------------------------------
+        ONLINE		Sw2P1
+        ONLINE		Sw3P2
+
+        onos> sdxl2:sdxl2cp Sw2P1
+
+        Status		Connection Point		Name		Vlan IDs		CE Mac Address
+        -------------------------------------------------------------------------------------------------------------
+        ONLINE		of:0000000000000002/1		Sw2P1		[6, 19, 20, 21]		00:00:00:00:00:02
+
+
+- Create a VC connecting the two CPs and get its details:
+
+        onos> sdxl2:sdxl2vc-add SDXL2Test Sw2P1 Sw3P2
+        onos> sdxl2:sdxl2vc-list
+
+        Status		Virtual Circuit
+        -----------------------------------------------
+        ONLINE		Sw2P1-Sw3P2
+
+
+        onos> sdxl2:sdxl2vc SDXL2Test:Sw2P1-Sw3P2
+
+        Status		Connection Point		Name		Vlan IDs		CE Mac Address
+        -------------------------------------------------------------------------------------------------------------
+        ONLINE		of:0000000000000002/1		Sw2P1		[6, 19, 20, 21]		00:00:00:00:00:02
+        ONLINE		of:0000000000000003/2		Sw3P2		[5, 15, 16, 17]		00:00:00:00:00:01
+
+
+        Status		Intent
+        --------------------------------------------
+        ONLINE		SDXL2Test:Sw2P1-Sw3P2,4
+        ONLINE		SDXL2Test:Sw3P2-Sw2P1,3
+        ONLINE		SDXL2Test:Sw3P2-Sw2P1,1
+        ONLINE		SDXL2Test:Sw3P2-Sw2P1,4
+        ONLINE		SDXL2Test:Sw3P2-Sw2P1,2
+        ONLINE		SDXL2Test:Sw2P1-Sw3P2,1
+        ONLINE		SDXL2Test:Sw2P1-Sw3P2,2
+        ONLINE		SDXL2Test:Sw2P1-Sw3P2,3
+
+
+- Remove VC and check it exists no longer:
+
+        onos> sdxl2:sdxl2vc-remove SDXL2Test:Sw2P1-Sw3P2
+        onos> sdxl2:sdxl2vc-list
+
+
+- Remove CPs and check they exist no longer:
+
+        onos> sdxl2:sdxl2cp-remove Sw2P1
+        onos> sdxl2:sdxl2cp-remove Sw3P2
+        onos> sdxl2:sdxl2cp-list
+
+- Remove SDX-L2 and check it does not exist anymore:
+
+        onos> sdxl2:sdxl2-list SDXL2Test
+        onos> sdxl2:sdxl2-list
+
+
+Tips
+=============================
+
+- You should define a topology and point to your local/remote ONOS instance. Some examples:
+
+  - Mininet
+        sudo mn --controller remote,ip=127.0.0.1 --tree,2,2
+  - ONOS/Mininet
+        onos-start-network
+
+- You may check the nodes available at ONOS from Mininet:
+
+        onos> edge-ports
diff --git a/sdx-l2/pom.xml b/sdx-l2/pom.xml
index 90f7236..2401c3f 100644
--- a/sdx-l2/pom.xml
+++ b/sdx-l2/pom.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
 <!--
   ~ Copyright 2016-present Open Networking Laboratory
   ~
@@ -95,6 +96,15 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.18.1</version>
+                <configuration>
+                    <useFile>false</useFile>
+                    <redirectTestOutputToFile>false</redirectTestOutputToFile>
+                </configuration>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <version>2.5.3</version>
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2ConnectionPoint.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2ConnectionPoint.java
index f5f6849..e1075df 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2ConnectionPoint.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2ConnectionPoint.java
@@ -24,22 +24,25 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import static com.google.common.base.Preconditions.*;
 
 /**
- * SDX-L2 connection point expressed as composition of a:
- * connect point; set of VLAN id; MAC address (optional).
+ * SDX-L2 Connection Point expressed as composition of a:
+ * Connect Point; set of VLAN ids; MAC address (optional).
  */
 public class SdxL2ConnectionPoint {
 
-    private String name;
+    private static final String ERROR_INVALID_VLAN = "Provide VLAN with at least value '-1' or '1'";
     private final ConnectPoint cPoint;
     private final List<VlanId> vlanIds;
     private final MacAddress ceMac;
+    private String name;
 
     /**
-     * Creates a new SDX-L2 connection point.
+     * Creates a new SDX-L2 Connection Point.
      *
      * @param name SDX-L2 connection point name
      * @param cPoint connect point
@@ -54,18 +57,151 @@
     }
 
     /**
-     * Returns the name of SDX-L2 connection point.
+     * Parses a device Connection Point from a string, set of VLANs
+     * from a string and MAC from a string.
+     * The connect point should be in the format "deviceUri/portNumber".
+     * The vlans should be in the format "vlan1,vlan2,vlan3"
+     * The mac address should be in hex
      *
-     * @return a string representing the name of connection point
+     * @param name name of the SDX-L2 Connection Point
+     * @param connectPoint Connection Point to parse
+     * @param vlans VLAN IDs to parse
+     * @param mac MAC address to parse
+     * @return a Connection Point based on the information in the string
+     *
+     */
+    public static SdxL2ConnectionPoint sdxl2ConnectionPoint(
+            String name, String connectPoint, String vlans, String mac) {
+        checkNotNull(connectPoint);
+        enforceNameFormat(name);
+        ConnectPoint connectionPoint = ConnectPoint.deviceConnectPoint(connectPoint);
+        List<VlanId> vlansList = enforceVlans(vlans);
+        MacAddress macAddress = MacAddress.ZERO;
+        if (mac != null) {
+            macAddress = MacAddress.valueOf(mac);
+        }
+        return new SdxL2ConnectionPoint(name, connectionPoint, vlansList, macAddress);
+    }
+
+    /**
+     * Parses a device Connection Point from a string and set of
+     * VLANs from a string.
+     * The Connection Point should be in the format "deviceUri/portNumber".
+     * The VLANs should be in the format "vlan1,vlan2,vlan3"
+     *
+     * @param name name of the SDX-L2 CP
+     * @param connectPoint Connection Point to parse
+     * @param vlans VLAN IDs to parse
+     * @return a Connection Point based on the information in the string
+     *
+     */
+    public static SdxL2ConnectionPoint sdxl2ConnectionPoint(
+            String name, String connectPoint, String vlans) {
+        return sdxl2ConnectionPoint(name, connectPoint, vlans, null);
+    }
+
+    /**
+     * Enforces proper format on the name of the Connection Point.
+     *
+     * @param name name of the SDX-L2 Connection Point
+     */
+    private static void enforceNameFormat(String name) {
+        checkState(!(name.contains(",") ||
+                name.contains("-") ||
+                name.contains("vlanid=") ||
+                name.contains("ConnectPoint{") ||
+                name.contains("elementId=") ||
+                name.contains("portNumber=") ||
+                name.contains("{") ||
+                name.contains("}") ||
+                name.contains("|")), "Names cannot contain some special characters");
+    }
+
+    /**
+     * Enforces proper format on the requested VLANs.
+     *
+     * @param vlans VLANs expressed explicitly, as a range or in combination
+     * @return a list of VLANs to be added
+     */
+    private static List<VlanId> enforceVlans(String vlans) {
+        String[] splitted = parseVlans(vlans);
+        List<VlanId> vlansList = new ArrayList<>();
+        for (String vlan : splitted) {
+            short vlanNumber = Short.parseShort(vlan);
+            if (!vlansList.contains(VlanId.vlanId(vlanNumber)) &&
+                    Short.parseShort(vlan) != -1 &&
+                    Short.parseShort(vlan) != 1 &&
+                    Short.parseShort(vlan) >= 0 &&
+                    Short.parseShort(vlan) != 4095) {
+                vlansList.add(VlanId.vlanId(vlanNumber));
+            }
+        }
+        return vlansList;
+    }
+
+    /**
+     * Parses the VLANs requested by the user.
+     *
+     * @param vlans VLANs expressed explicitly, as a range or in combination
+     * @return an array of VLANs to add
+     */
+    private static String[] parseVlans(String vlans) {
+        if (vlans == null) {
+            vlans = "-1";
+        }
+        ArrayList<String> vlanRange = new ArrayList<String>();
+        String[] splittedVlans;
+        String commaSeparator = ",";
+        if (vlans.contains(commaSeparator)) {
+            splittedVlans = vlans.split(commaSeparator);
+            for (String vlan : splittedVlans) {
+                vlanRange.addAll(generateNumberRange(vlan));
+            }
+        } else {
+            vlanRange.addAll(generateNumberRange(vlans));
+        }
+        splittedVlans = new String[vlanRange.size()];
+        splittedVlans = vlanRange.toArray(splittedVlans);
+        return splittedVlans;
+    }
+
+    /**
+     * Generates a range of numbers, given a string of type "X-Y" ("%d-%d").
+     *
+     * @param range range of numbers to compute
+     * @return a list with numbers between "X" and "Y" (inclusive)
+     */
+    private static ArrayList<String> generateNumberRange(String range) {
+        ArrayList<String> parsedNumbers = new ArrayList<String>();
+        Pattern p = Pattern.compile("(\\d+)-(\\d+)");
+        Matcher m = p.matcher(range);
+        if (m.matches()) {
+                int start = Integer.parseInt(m.group(1));
+                int end = Integer.parseInt(m.group(2));
+                int min = Math.min(start, end);
+                int max = Math.max(start, end);
+                for (int v = min; v <= max; v++) {
+                    parsedNumbers.add(Integer.toString(v));
+                }
+        } else {
+            parsedNumbers.add(range);
+        }
+        return parsedNumbers;
+    }
+
+    /**
+     * Returns the name of SDX-L2 Connection Point.
+     *
+     * @return a string representing the name of Connection Point
      */
     public String name() {
         return name;
     }
 
     /**
-     * Returns the connect point.
+     * Returns the Connection Point.
      *
-     * @return connect point object
+     * @return Connection Point object
      */
     public ConnectPoint connectPoint() {
         return cPoint;
@@ -89,87 +225,6 @@
         return ceMac;
     }
 
-    /**
-     * Parse a device connect point from a string, set of VLANs from a string
-     * and MAC from a string.
-     * The connect point should be in the format "deviceUri/portNumber".
-     * The VLANs should be in the format "vlan1,vlan2,vlan3"
-     * The MAC address should be in hex
-     *
-     * @param name name of the SDX-L2 connection point
-     * @param connectPoint connect point to parse
-     * @param vlans VLAN ids to parse
-     * @param mac MAC address to parse
-     * @return a SDX-L2 connection point based on the information in the string.
-     *
-     */
-    public static SdxL2ConnectionPoint
-    sdxl2ConnectionPoint(String name, String connectPoint, String vlans, String mac) {
-        checkNotNull(connectPoint);
-        checkNotNull(vlans);
-        checkState(!(name.contains(",") ||
-                name.contains("-") ||
-                name.contains("vlanid=") ||
-                name.contains("ConnectPoint{") ||
-                name.contains("elementId=") ||
-                name.contains("portNumber=") ||
-                name.contains("{") ||
-                name.contains("}") ||
-                name.contains("|")), "Names cannot contain some special characters");
-        checkNotNull(mac);
-        ConnectPoint connectionPoint = ConnectPoint.deviceConnectPoint(connectPoint);
-        String[] splitted = vlans.split(",");
-        checkArgument(splitted.length != 0, "At least '-1' or '1' as value");
-        List<VlanId> vlanslist = new ArrayList<>();
-        for (String vlan : splitted) {
-            if (!vlanslist.contains(VlanId.vlanId(Short.parseShort(vlan))) &&
-                    Short.parseShort(vlan) != -1 &&
-                    Short.parseShort(vlan) != 1) {
-                vlanslist.add(VlanId.vlanId(Short.parseShort(vlan)));
-            }
-        }
-        MacAddress macAddress = MacAddress.valueOf(mac);
-        return new SdxL2ConnectionPoint(name, connectionPoint, vlanslist, macAddress);
-    }
-
-    /**
-     * Parse a device connect point from a string and set of VLANs from a string.
-     * The connect point should be in the format "deviceUri/portNumber".
-     * The VLANs should be in the format "vlan1,vlan2,vlan3"
-     *
-     * @param name name of the SDX-L2 connection point
-     * @param connectPoint connect point to parse
-     * @param vlans VLAN ids to parse
-     * @return a SDX-L2 connection point based on the information in the string.
-     *
-     */
-    public static SdxL2ConnectionPoint sdxl2ConnectionPoint(String name, String connectPoint, String vlans) {
-        checkNotNull(connectPoint);
-        checkNotNull(vlans);
-        checkState(!(name.contains(",") ||
-                name.contains("-") ||
-                name.contains("vlanid=") ||
-                name.contains("ConnectPoint{") ||
-                name.contains("elementId=") ||
-                name.contains("portNumber=") ||
-                name.contains("{") ||
-                name.contains("}") ||
-                name.contains("|")), "Names cannot contain some special characters");
-        ConnectPoint connectionPoint = ConnectPoint.deviceConnectPoint(connectPoint);
-        String[] splitted = vlans.split(",");
-        checkArgument(splitted.length != 0, "At least '-1' or '1' as value");
-        List<VlanId> vlanslist = new ArrayList<>();
-        for (String vlan : splitted) {
-            if (!vlanslist.contains(VlanId.vlanId(Short.parseShort(vlan))) &&
-                    Short.parseShort(vlan) != -1 &&
-                    Short.parseShort(vlan) != 1) {
-                vlanslist.add(VlanId.vlanId(Short.parseShort(vlan)));
-            }
-        }
-        MacAddress macAddress = MacAddress.ZERO;
-        return new SdxL2ConnectionPoint(name, connectionPoint, vlanslist, macAddress);
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(name, cPoint, vlanIds, ceMac);
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
index 02ea103..a3ada37 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2DistributedStore.java
@@ -18,12 +18,12 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Deactivate;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.store.primitives.DefaultDistributedSet;
@@ -35,14 +35,15 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.Iterator;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
+import static java.lang.String.format;
 
 /**
  * SDX-L2 Store implementation backed by different distributed primitives.
@@ -61,12 +62,18 @@
     private Map<SdxL2ConnectionPoint, String> sdxL2CPs;
     private ConsistentMap<SdxL2ConnectionPoint, String> sdxL2cps;
 
+    private Map<String, String> sdxL2VCs;
+    private ConsistentMap<String, String> sdxL2vcs;
+
     private static String errorAddSdx = "It is not possible to add %s " +
             "because it exists";
 
     private static String errorRemoveSdx = "It is not possible to remove %s " +
             "because it does not exist";
 
+    /*
+    Error definitions for CPs.
+     */
     private static String errorAddSdxL2CPName = "It is not possible to add %s " +
             "because there is a sdxl2cp with the same name";
     private static String errorAddSdxL2CPVlans = "It is not possible to add %s " +
@@ -74,25 +81,31 @@
     private static String errorAddSdxL2CPCP = "It is not possible to add %s " +
             "because there is a conflict with %s on the connection point";
     private static String errorAddSdxL2CPSdx = "It is not possible to add %s " +
-            "because the relative sdxl2 does not exist";
+            "because the relative sdxl2 %s does not exist";
 
+    private static String errorGetSdxL2CP = "It is not possible to retrieve %s " +
+            "because it does not exist";
     private static String errorGetSdxL2CPs = "It is not possible to list the sdxl2cps " +
             "because sdxl2 %s does not exist";
 
     private static String errorRemoveSdxL2CP = "It is not possible to remove %s " +
             "because it does not exist";
 
-    private static String errorGetSdxL2CP = "It is not possible to retrieve %s " +
-            "because it does not exist";
+    /*
+    Error definitions for VCs.
+    */
+    private static String errorVCKey = "It is not possible to add vc because " +
+            "there is a problem with key %s (wrong format)";
+    private static String errorAddVCOverlap = "It is not possible to add vc " +
+            "because there is an overlap with %s";
+    private static String errorRemoveVC = "It is not possible to remove the " +
+            "vc because it does not exist";
+    private static String errorRemoveVCAux = "Virtual Circuit between %s and %s " +
+            "does not exist";
 
-    public void initForTest() {
-
-        this.sdxL2s = Sets.newHashSet();
-
-        this.sdxL2CPs = new ConcurrentHashMap<SdxL2ConnectionPoint, String>();
-
-    }
-
+    /**
+     * Activates the implementation of the SDX-L2 store.
+     */
     @Activate
     public void activate() {
 
@@ -103,10 +116,10 @@
                 .build();
 
         sdxL2s = new DefaultDistributedSet<>(this.storageService
-                .<String>setBuilder()
-                .withSerializer(Serializer.using(custom))
-                .withName("sdxl2s")
-                .build(), DistributedPrimitive.DEFAULT_OPERTATION_TIMEOUT_MILLIS);
+                                                     .<String>setBuilder()
+                                                     .withSerializer(Serializer.using(custom))
+                                                     .withName("sdxl2s")
+                                                     .build(), DistributedPrimitive.DEFAULT_OPERTATION_TIMEOUT_MILLIS);
 
         sdxL2cps = this.storageService
                 .<SdxL2ConnectionPoint, String>consistentMapBuilder()
@@ -115,20 +128,32 @@
                 .build();
         sdxL2CPs = sdxL2cps.asJavaMap();
 
+        sdxL2vcs = this.storageService.<String, String>consistentMapBuilder()
+                .withSerializer(Serializer.using(custom))
+                .withName("vcs")
+                .build();
+        sdxL2VCs = sdxL2vcs.asJavaMap();
+
         log.info("Started");
     }
 
+    /**
+     * Helper class called to initialise tests.
+     */
+    public void initForTest() {
+        this.sdxL2s = Sets.newHashSet();
+        this.sdxL2CPs = new ConcurrentHashMap<SdxL2ConnectionPoint, String>();
+        this.sdxL2VCs = new ConcurrentHashMap<String, String>();
+    }
+
+    /**
+     * Deactivates the implementation of the SDX-L2 store.
+     */
     @Deactivate
     public void deactivate() {
         log.info("Stopped");
     }
 
-    /**
-     * Creates a named SDX-L2.
-     *
-     * @param sdxl2 SDX-L2 name
-     * @throws SdxL2Exception if SDX-L2 exists
-     */
     @Override
     public void putSdxL2(String sdxl2) throws SdxL2Exception {
         boolean inserted = sdxL2s.add(sdxl2);
@@ -137,12 +162,6 @@
         }
     }
 
-    /**
-     * Removes a named SDX-L2.
-     *
-     * @param sdxl2 SDX-L2 name
-     * @throws SdxL2Exception if SDX-L2 does not exist
-     */
     @Override
     public void removeSdxL2(String sdxl2) throws SdxL2Exception {
         boolean removed = sdxL2s.remove(sdxl2);
@@ -158,35 +177,22 @@
         toRemove.forEach(key_value -> sdxL2CPs.remove(key_value.getKey()));
     }
 
-    /**
-     * Returns a set of SDX-L2 names.
-     *
-     * @return a set of SDX-L2 names
-     */
     @Override
     public Set<String> getSdxL2s() {
         return ImmutableSet.copyOf(sdxL2s);
     }
 
-    /**
-     * Adds an SDX-L2 connection point to an SDX-L2.
-     *
-     * @param sdxl2 SDX-L2 name
-     * @param connectionPoint the connection point object
-     * @throws SdxL2Exception if it is not possible to add the SDX-L2 connection point
-     */
     @Override
     public void addSdxL2ConnectionPoint(String sdxl2, SdxL2ConnectionPoint connectionPoint) throws SdxL2Exception {
-
         boolean exist = sdxL2s.contains(sdxl2);
-
+        String errorMissingSdxL2 = String.format(errorAddSdxL2CPSdx, connectionPoint.name(), sdxl2);
         if (!exist) {
-            throw new SdxL2Exception(String.format(errorAddSdxL2CPSdx, connectionPoint.name()));
+            throw new SdxL2Exception(errorMissingSdxL2);
         }
 
         Set<SdxL2ConnectionPoint> sdxl2cpsTemp = ImmutableSet.copyOf(sdxL2CPs.keySet());
         Set<SdxL2ConnectionPoint> sdxl2cpsTempByName = sdxl2cpsTemp.parallelStream().filter(
-                sdxl2cpTemp-> sdxl2cpTemp.name().equals(connectionPoint.name()
+                sdxl2cpTemp -> sdxl2cpTemp.name().equals(connectionPoint.name()
                 )
         ).collect(Collectors.toSet());
 
@@ -194,9 +200,8 @@
             throw new SdxL2Exception(String.format(errorAddSdxL2CPName, connectionPoint.name()));
         }
 
-
         Set<SdxL2ConnectionPoint> sdxl2cpsByCP = sdxl2cpsTemp.parallelStream().filter(
-                sdxl2cp_temp-> sdxl2cp_temp.connectPoint().equals(connectionPoint.connectPoint()
+                sdxl2cpTemp -> sdxl2cpTemp.connectPoint().equals(connectionPoint.connectPoint()
                 )
         ).collect(Collectors.toSet());
 
@@ -208,7 +213,7 @@
                             sdxl2cp_by_vlan.vlanIds().contains(vlanId) || sdxl2cp_by_vlan.vlanIds().size() == 0
                     )).collect(Collectors.toSet());
 
-            tempName =  sdxl2cpsByVlan.iterator().hasNext() ?  sdxl2cpsByVlan.iterator().next().name() : null;
+            tempName = sdxl2cpsByVlan.iterator().hasNext() ? sdxl2cpsByVlan.iterator().next().name() : null;
 
             if (sdxl2cpsByVlan.size() != 0) {
                 throw new SdxL2Exception(String.format(errorAddSdxL2CPVlans, connectionPoint.name(), tempName));
@@ -216,24 +221,14 @@
 
         }
 
-        tempName =  sdxl2cpsByCP.iterator().hasNext() ? sdxl2cpsByCP.iterator().next().name() : null;
-
+        tempName = sdxl2cpsByCP.iterator().hasNext() ? sdxl2cpsByCP.iterator().next().name() : null;
         if (sdxl2cpsByCP.size() != 0 && vlans.size() == 0) {
             throw new SdxL2Exception(String.format(errorAddSdxL2CPCP, connectionPoint.name(), tempName));
         }
 
         sdxL2CPs.put(connectionPoint, sdxl2);
-
     }
 
-    /**
-     * Returns all the SDX-L2 connection points names or the SDX-L2 2connection points names
-     * that are related to an SDX-L2.
-     *
-     * @param sdxl2 name (optional) of the SDX-L2
-     * @return a set of SDX-L2 connection points names, the result depends on the input parameter;
-     * @throws SdxL2Exception if SDX-L2 is present but it does not exist
-     */
     @Override
     public Set<String> getSdxL2ConnectionPoints(Optional<String> sdxl2) throws SdxL2Exception {
 
@@ -270,12 +265,6 @@
 
     }
 
-    /**
-     * Removes a named SDX-L2 connection point in an SDX-L2.
-     *
-     * @param sdxl2cp the connection point name
-     * @throws SdxL2Exception if SDX-L2 connection point does not exist
-     */
     @Override
     public void removeSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception {
 
@@ -295,13 +284,6 @@
 
     }
 
-    /**
-     * Returns an SDX-L2 connection point in a SDX-L2.
-     *
-     * @param sdxl2cp the connection point name
-     * @return the relative SDXL2ConnectionPoint object
-     * @throws SdxL2Exception if SDX-L2 connection point does not exist
-     */
     @Override
     public SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception {
         SdxL2ConnectionPoint sdxl2cpTemp = ImmutableSet.copyOf(sdxL2CPs.keySet()).parallelStream()
@@ -314,4 +296,108 @@
         return sdxl2cpTemp;
     }
 
+    @Override
+    public void addVC(String sdxl2, SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception {
+        Set<String> vcs = ImmutableSet.copyOf(
+                sdxL2VCs.keySet().parallelStream().filter((vctemp->vctemp.contains(sdxl2cplhs.toString())
+                        || vctemp.contains(sdxl2cprhs.toString()))).collect(Collectors.toSet()));
+        for (String vctemp : vcs) {
+            String[] splitted = vctemp.split("~");
+
+            if (splitted.length != 2) {
+                throw new SdxL2Exception(String.format(errorVCKey, "add", vctemp));
+            }
+
+            if (!(!sdxl2cplhs.toString().equals(splitted[0]) &&
+                    !sdxl2cplhs.toString().equals(splitted[1]) &&
+                    !sdxl2cprhs.toString().equals(splitted[0]) &&
+                    !sdxl2cprhs.toString().equals(splitted[1]))) {
+                throw new SdxL2Exception(String.format(errorAddVCOverlap, vctemp));
+            }
+        }
+
+        String cps = sdxl2cplhs.toString().compareTo(sdxl2cprhs.toString()) < 0 ?
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cplhs, sdxl2cprhs) :
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cprhs, sdxl2cplhs);
+        String name = sdxl2cplhs.name().compareTo(sdxl2cprhs.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, sdxl2, sdxl2cplhs.name(), sdxl2cprhs.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, sdxl2, sdxl2cprhs.name(), sdxl2cplhs.name());
+        sdxL2VCs.put(cps, name);
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception {
+
+        String cps = sdxl2cplhs.toString().compareTo(sdxl2cprhs.toString()) < 0 ?
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cplhs, sdxl2cprhs) :
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cprhs, sdxl2cplhs);
+        String name = sdxL2VCs.remove(cps);
+        if (name == null) {
+            throw new SdxL2Exception(String.format(errorRemoveVC));
+        }
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint cp) throws SdxL2Exception {
+
+        Set<String> vcs = ImmutableSet.copyOf(sdxL2VCs.keySet()
+                                                      .parallelStream()
+                                                      .filter((vctemp -> vctemp.contains(cp.toString())))
+                                                      .collect(Collectors.toSet()));
+
+        for (String vctemp : vcs) {
+            String[] splitted = vctemp.split("~");
+            if (splitted.length != 2) {
+                throw new SdxL2Exception(String.format(errorVCKey, "delete", vctemp));
+            }
+            if (cp.toString().equals(splitted[0]) || cp.toString().equals(splitted[1])) {
+                sdxL2VCs.remove(vctemp);
+            }
+        }
+    }
+
+    @Override
+    public void removeVCs(String sdxl2) {
+
+        Set<Map.Entry<String, String>> vcsToRemove = sdxL2VCs.entrySet().parallelStream().filter(key_value -> {
+            String[] fields = key_value.getValue().split(":");
+            return fields.length == 2 && fields[0].equals(sdxl2) ? true : false;
+        }).collect(Collectors.toSet());
+
+        vcsToRemove.forEach(key_value -> sdxL2VCs.remove(key_value.getKey()));
+    }
+
+    @Override
+    public String getVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception {
+        String cps = sdxl2cplhs.toString().compareTo(sdxl2cprhs.toString()) < 0 ?
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cplhs, sdxl2cprhs) :
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, sdxl2cprhs, sdxl2cplhs);
+
+        String encodedvc = ImmutableSet.copyOf(sdxL2VCs.keySet()).parallelStream().filter(
+                encoded_cps -> encoded_cps.equals(cps)).findFirst().orElse(null);
+
+        if (encodedvc == null) {
+            throw new SdxL2Exception(String.format(errorRemoveVCAux,
+                                                   sdxl2cplhs.name(), sdxl2cprhs.name()));
+        }
+        return encodedvc;
+    }
+
+    @Override
+    public Set<String> getVCs(Optional<String> sdxl2) {
+        if (sdxl2.isPresent()) {
+            Set<String> vcs = ImmutableSet.copyOf(sdxL2VCs.values())
+                    .parallelStream()
+                    .filter(vc -> {
+                        String[] parts = vc.split(":");
+                        return parts.length == 2 && parts[0].equals(sdxl2.get());
+                    }).collect(Collectors.toSet());
+
+            return vcs;
+        }
+        return ImmutableSet.copyOf(sdxL2VCs.values());
+    }
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Exception.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Exception.java
index 1692edc..cd7973b 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Exception.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Exception.java
@@ -21,6 +21,11 @@
  */
 public class SdxL2Exception extends Exception {
 
+    /**
+     * Returns a custom exception, given a message.
+     *
+     * @param message Exception with custom message
+     */
     public SdxL2Exception(String message) {
         super(message);
     }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MacVCManager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MacVCManager.java
new file mode 100644
index 0000000..5a76979
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MacVCManager.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+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.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Manages Virtual Circuits using MAC addresses.
+ */
+public class SdxL2MacVCManager extends SdxL2VCManager {
+
+    private static final int PRIORITY_OFFSET = 2000;
+    private static Logger log = LoggerFactory.getLogger(SdxL2MacVCManager.class);
+
+    private static String errorMacNull = "VC cannot be %s: the mac address of %s is null";
+    private static String errorMacEqual = "VC cannot be %s: same mac addresses on both sides";
+
+    /**
+     * Creates an SDX-L2 MAC VC Manager.
+     *
+     * @param sdxl2id application ID
+     * @param store reference to the SDX-L2 store
+     * @param intentService reference to the Intent service
+     */
+    public SdxL2MacVCManager(ApplicationId sdxl2id,
+                             SdxL2Store store,
+                             IntentService intentService) {
+        super(sdxl2id, store, intentService);
+        log.info("Started");
+    }
+
+    @Override
+    public Collection<Intent> buildIntents(String sdxl2, SdxL2ConnectionPoint ingress, SdxL2ConnectionPoint egress) {
+        List<Intent> intents = null;
+        TrafficSelector selector;
+        TrafficTreatment treatment;
+        Key key;
+
+        if (ingress.vlanIds().size() == egress.vlanIds().size()) {
+            intents = new ArrayList<Intent>();
+            if (ingress.vlanIds().size() == 0) {
+                selector = buildSelector(ingress.macAddress(),
+                                         egress.macAddress(),
+                                         null,
+                                         null);
+                treatment = DefaultTrafficTreatment.emptyTreatment();
+                key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+                intents.add(PointToPointIntent.builder()
+                                    .appId(appId)
+                                    .key(key)
+                                    .selector(selector)
+                                    .treatment(treatment)
+
+                                    .ingressPoint(ingress.connectPoint())
+                                    .egressPoint(egress.connectPoint())
+                                    .priority(PRIORITY_OFFSET)
+                                    .build());
+            } else {
+                Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+                Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+                int index = 1;
+                while (ingressTags.hasNext()) {
+                    selector = buildSelector(ingress.macAddress(),
+                                             egress.macAddress(),
+                                             null,
+                                             ingressTags.next());
+                    treatment = buildTreatment(egressTags.next(),
+                                               null,
+                                               false);
+                    key = generateIntentKey(sdxl2, ingress, egress, String.valueOf(index));
+
+                    intents.add(PointToPointIntent.builder()
+                                        .appId(appId)
+                                        .key(key)
+                                        .selector(selector)
+                                        .treatment(treatment)
+                                        .ingressPoint(ingress.connectPoint())
+                                        .egressPoint(egress.connectPoint())
+                                        .priority(PRIORITY_OFFSET)
+                                        .build());
+                    index = index + 1;
+                }
+            }
+            return intents;
+        }
+
+        if (ingress.vlanIds().size() == 1 && egress.vlanIds().size() == 0) {
+            Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+            selector = buildSelector(ingress.macAddress(),
+                                     egress.macAddress(),
+                                     null,
+                                     ingressTags.next());
+            treatment = buildTreatment(null,
+                                       null,
+                                       true);
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+        }
+
+        if (ingress.vlanIds().size() == 0 && egress.vlanIds().size() == 1) {
+            Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+            selector = buildSelector(ingress.macAddress(),
+                                     egress.macAddress(),
+                                     null,
+                                     null);
+            treatment = buildTreatment(null,
+                                       egressTags.next(),
+                                       false);
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+        }
+
+        log.warn(String.format(errorCreateIntents, ingress.name(), egress.name()));
+
+        return intents;
+    }
+
+    @Override
+    public void addVC(String sdxl2, SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        String action = "created";
+        checkState(!(isNullMac(sdxl2cplhs.macAddress()) && isNullMac(sdxl2cprhs.macAddress())),
+                   errorMacNull, action, sdxl2cplhs.name() + " and " + sdxl2cprhs.name());
+        checkState(!isNullMac(sdxl2cprhs.macAddress()), errorMacNull, action, sdxl2cplhs.name());
+        checkState(!isNullMac(sdxl2cprhs.macAddress()), errorMacNull, action, sdxl2cprhs.name());
+        checkState(!sdxl2cplhs.macAddress().equals(sdxl2cprhs.macAddress()), errorMacEqual, action);
+        super.addVC(sdxl2, sdxl2cplhs, sdxl2cprhs);
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        String action = "deleted";
+        checkState(!(isNullMac(sdxl2cplhs.macAddress()) && isNullMac(sdxl2cprhs.macAddress())),
+                   errorMacNull, action, sdxl2cplhs.name() + " and " + sdxl2cprhs.name());
+        checkState(!sdxl2cplhs.macAddress().equals(MacAddress.ZERO), errorMacNull, action, sdxl2cplhs.name());
+        checkState(!sdxl2cprhs.macAddress().equals(MacAddress.ZERO), errorMacNull, action, sdxl2cprhs.name());
+        checkState(!sdxl2cplhs.macAddress().equals(sdxl2cprhs.macAddress()), errorMacEqual, action);
+        super.removeVC(sdxl2cplhs, sdxl2cprhs);
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint cp) {
+        checkState(!cp.macAddress().equals(MacAddress.ZERO), errorMacNull, "deleted", cp.name());
+        super.removeVC(cp);
+    }
+
+    private boolean isNullMac(MacAddress mac) {
+        return mac.equals(MacAddress.ZERO);
+    }
+
+    private TrafficSelector buildSelector(MacAddress ingressMac,
+                                          MacAddress egressMac,
+                                          Short ethertype,
+                                          VlanId ingresstag) {
+
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthSrc(ingressMac);
+        selectorBuilder.matchEthDst(egressMac);
+        if (ethertype != null) {
+            selectorBuilder.matchEthType(ethertype);
+        }
+        if (ingresstag != null) {
+            selectorBuilder.matchVlanId(ingresstag);
+        }
+        return selectorBuilder.build();
+    }
+
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
index 21dd06a..edd7901 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
@@ -16,13 +16,12 @@
 
 package org.onosproject.sdxl2;
 
-
+import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Deactivate;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.ICMP6;
 import org.onlab.packet.IPv6;
@@ -46,6 +45,7 @@
 import java.util.Collections;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
@@ -56,52 +56,56 @@
 import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
 import static org.onosproject.net.packet.PacketPriority.CONTROL;
 
+
 /**
- * Implementation of the SdxL2Service.
+ * Implements SdxL2Service.
  */
 @Component(immediate = true)
 @Service
 public class SdxL2Manager implements SdxL2Service {
 
     private static final String SDXL2_APP = "org.onosproject.sdxl2";
+    private static final String ERROR_ADD_VC_VLANS =
+            "Cannot create VC when CPs have different number of VLANs";
+    private static final String ERROR_ADD_VC_VLANS_CLI =
+            "\u001B[0;31mError executing command: " + ERROR_ADD_VC_VLANS + "\u001B[0;49m";
+    private static final String VC_0 = "MAC";
     private static Logger log = LoggerFactory.getLogger(SdxL2Manager.class);
-
+    private static final String ERROR_ADD_VC_CPS = "Unable to find %s and %s in sdxl2=%s";
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected SdxL2Store sdxL2Store;
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentService intentService;
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EdgePortService edgePortService;
-
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
-
     protected SdxL2Processor processor = new SdxL2Processor();
-
-    protected SdxL2ArpNdpHandler arpndpHandler;
-
     protected ApplicationId appId;
-
     protected SdxL2MonitoringService monitoringManager;
-
-    protected String vcType = "MAC";
+    protected SdxL2ArpNdpHandler arpndpHandler;
+    protected SdxL2VCService vcManager;
 
 
+    /**
+     * Activates the implementation of the SDX-L2 service.
+     * @param context ComponentContext object
+     */
     @Activate
     protected void activate(ComponentContext context) {
         appId = coreService.registerApplication(SDXL2_APP);
         monitoringManager = new SdxL2MonitoringManager(appId, intentService, edgePortService);
+        SdxL2ArpNdpHandler.vcType = VC_0;
+        vcManager = new SdxL2MacVCManager(appId, sdxL2Store, intentService);
         handleArpNdp();
         log.info("Started");
     }
 
-
-
+    /**
+     * Deactivates the implementation of the SDX-L2 service.
+     */
     @Deactivate
     protected void deactivate() {
         this.cleanSdxL2();
@@ -109,11 +113,6 @@
         log.info("Stopped");
     }
 
-    /**
-     * Creates a named SDX-L2.
-     *
-     * @param sdxl2 SDX-L2 name
-     */
     @Override
     public void createSdxL2(String sdxl2) {
 
@@ -128,14 +127,8 @@
         } catch (SdxL2Exception e) {
             log.info(e.getMessage());
         }
-
     }
 
-    /**
-     * Deletes a named SDX-L2.
-     *
-     * @param sdxl2 SDX-L2 name
-     */
     @Override
     public void deleteSdxL2(String sdxl2) {
 
@@ -149,22 +142,11 @@
 
     }
 
-    /**
-     * Returns a set of SDX-L2 names.
-     *
-     * @return a set of SDX-L2 names
-     */
     @Override
     public Set<String> getSdxL2s() {
         return this.sdxL2Store.getSdxL2s();
     }
 
-    /**
-     * Adds an SDX-L2 connection point to an SDX-L2.
-     *
-     * @param sdxl2   SDX-L2 name
-     * @param sdxl2cp SDX-L2 connection point object
-     */
     @Override
     public void addSdxL2ConnectionPoint(String sdxl2, SdxL2ConnectionPoint sdxl2cp) {
 
@@ -179,12 +161,6 @@
 
     }
 
-    /**
-     * Returns all the SDX-L2 connection points names in a SDX-L2 or all the SDX-L2 connection points names.
-     *
-     * @param sdxl2 SDX-L2 name
-     * @return a set of SDX-L2 connection points names
-     */
     @Override
     public Set<String> getSdxL2ConnectionPoints(Optional<String> sdxl2) {
 
@@ -195,14 +171,8 @@
         }
 
         return Collections.emptySet();
-
     }
 
-    /**
-     * Removes an SDX-L2 connection point from an SDX-L2.
-     *
-     * @param sdxl2cp SDX-L2 connection point name
-     */
     @Override
     public void removeSdxL2ConnectionPoint(String sdxl2cp) {
 
@@ -216,12 +186,55 @@
 
     }
 
-    /**
-     * Returns an SDX-L2 connection point in a SDX-L2.
-     *
-     * @param sdxl2cp SDX-L2 connection point name
-     * @return the relative SdxL2ConnectionPoint object
-     */
+    @Override
+    public void addVC(String sdxl2, String sdxl2cplhs, String sdxl2cprhs) {
+        SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(sdxl2cplhs);
+        SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(sdxl2cprhs);
+
+        Set<String> cps = this.getSdxL2ConnectionPoints(Optional.of(sdxl2))
+                .parallelStream()
+                .filter(cptemp -> (cptemp.equals(sdxl2cplhs) || cptemp.equals(sdxl2cprhs)))
+                .collect(Collectors.toSet());
+
+        checkState(cps.size() == 2, ERROR_ADD_VC_CPS, sdxl2cplhs, sdxl2cprhs, sdxl2);
+
+        if ((lhs.vlanIds().size() != rhs.vlanIds().size()) &&
+                (lhs.vlanIds().size() > 1 || rhs.vlanIds().size() > 1)) {
+            // User can correct this issue in the CLI. Show in console and log
+            System.err.println(ERROR_ADD_VC_VLANS_CLI);
+            log.info(ERROR_ADD_VC_VLANS);
+            return;
+        }
+        this.vcManager.addVC(sdxl2, lhs, rhs);
+    }
+
+    @Override
+    public void removeVC(String vc) {
+        checkNotNull(vc, "VC name cannot be null");
+        String[] splitKeyCPs = vc.split(":");
+        checkState(splitKeyCPs.length == 2, "Bad name format $sdx:$something");
+        String[] cps = splitKeyCPs[1].split("-");
+        checkState(cps.length == 2, "Bad name format $sdx:$lhs-$rhs");
+
+        String lhsName = cps[0];
+        String rhsName = cps[1];
+        SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(lhsName);
+        SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(rhsName);
+        if (lhs == null || rhs == null) {
+            return;
+        }
+
+        Set<String> cpsByVC = this.getSdxL2ConnectionPoints(Optional.of(splitKeyCPs[0]))
+                .parallelStream()
+                .filter(tempCP -> (tempCP.equals(lhs.name()) || tempCP.equals(rhs.name())))
+                .collect(Collectors.toSet());
+
+        if (cpsByVC.size() != 2) {
+            return;
+        }
+        this.vcManager.removeVC(lhs, rhs);
+    }
+
     @Override
     public SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) {
         checkNotNull(sdxl2cp, "SdxL2ConnectionPoint name cannot be null");
@@ -230,28 +243,42 @@
         } catch (SdxL2Exception e) {
             log.info(e.getMessage());
         }
-
         return null;
     }
 
-    /**
-     * Returns the state of the Intent that has been provided as input.
-     *
-     * @param intentKey key of the intent;
-     * @return the last state of the intent;
-     */
+    @Override
+    public Set<String> getVirtualCircuits(Optional<String> sdxl2) {
+        return this.vcManager.getVCs(sdxl2);
+    }
+
+    @Override
+    public VirtualCircuit getVirtualCircuit(String sdxl2vc) {
+        checkNotNull(sdxl2vc, "VC name cannot be null");
+        String[] splitKeyCPs = sdxl2vc.split(":");
+        checkState(splitKeyCPs.length == 2, "Bad name format $sdx:$something");
+        String[] cps = splitKeyCPs[1].split("-");
+        checkState(cps.length == 2, "Bad name format $sdx:$lhs-$rhs");
+
+        SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(cps[0]);
+        SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(cps[1]);
+        VirtualCircuit vc = null;
+        if (lhs == null || rhs == null) {
+            return vc;
+        }
+
+        String result = this.vcManager.getVC(lhs, rhs);
+        if (result != null) {
+            vc = new VirtualCircuit(lhs, rhs);
+        }
+        return vc;
+    }
+
     @Override
     public SdxL2State getIntentState(Key intentKey) {
         checkNotNull(intentKey, "Intent key cannot be null");
         return this.monitoringManager.getIntentState(intentKey);
     }
 
-    /**
-     * Returns the state of the EdgePort that has been provided as input.
-     *
-     * @param edgeport the connect point representing the edge port
-     * @return the last state of the edgeport;
-     */
     @Override
     public SdxL2State getEdgePortState(ConnectPoint edgeport) {
         checkNotNull(edgeport, "Edge port cannot be null");
@@ -267,11 +294,11 @@
     }
 
     /**
-     * It requests ARP and NDP packets to the PacketService
+     * Requests ARP and NDP packets to the PacketService
      * and registers the SDX-L2 PacketProcessor.
      */
     private void handleArpNdp() {
-        SdxL2ArpNdpHandler.vcType = vcType;
+        SdxL2ArpNdpHandler.vcType = VC_0;
         arpndpHandler = new SdxL2ArpNdpHandler(intentService, packetService, appId);
         packetService.addProcessor(processor, PacketProcessor.director(1));
 
@@ -280,7 +307,7 @@
                 DefaultTrafficSelector.builder();
         selectorBuilder.matchEthType(TYPE_ARP);
         packetService.requestPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                     CONTROL, appId, Optional.<DeviceId>empty());
 
         // IPv6 Neighbor Solicitation packet.
         selectorBuilder = DefaultTrafficSelector.builder();
@@ -288,7 +315,7 @@
         selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
         selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
         packetService.requestPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                     CONTROL, appId, Optional.<DeviceId>empty());
 
         // IPv6 Neighbor Advertisement packet.
         selectorBuilder = DefaultTrafficSelector.builder();
@@ -296,7 +323,7 @@
         selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
         selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
         packetService.requestPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                     CONTROL, appId, Optional.<DeviceId>empty());
     }
 
     /**
@@ -312,21 +339,21 @@
                 DefaultTrafficSelector.builder();
         selectorBuilder.matchEthType(TYPE_ARP);
         packetService.cancelPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                    CONTROL, appId, Optional.<DeviceId>empty());
 
         selectorBuilder = DefaultTrafficSelector.builder();
         selectorBuilder.matchEthType(TYPE_IPV6);
         selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
         selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
         packetService.cancelPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                    CONTROL, appId, Optional.<DeviceId>empty());
 
         selectorBuilder = DefaultTrafficSelector.builder();
         selectorBuilder.matchEthType(TYPE_IPV6);
         selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
         selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
         packetService.cancelPackets(selectorBuilder.build(),
-                CONTROL, appId, Optional.<DeviceId>empty());
+                                    CONTROL, appId, Optional.<DeviceId>empty());
     }
 
     /**
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MplsVCManager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MplsVCManager.java
new file mode 100644
index 0000000..3a6c33d
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2MplsVCManager.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Manages Virtual Circuits using MPLS headers.
+ */
+public class SdxL2MplsVCManager extends SdxL2VCManager {
+
+    private static final int PRIORITY_OFFSET = 2000;
+    private static Logger log = LoggerFactory.getLogger(SdxL2MplsVCManager.class);
+
+    // TODO Remember to create two intents: one for IPv4 and one for IPv6
+
+    /**
+     * Creates an SDX-L2 MPLS VC Manager.
+     *
+     * @param sdxl2id application ID
+     * @param store reference to the SDX-L2 store
+     * @param intentService reference to the Intent service
+     */
+    public SdxL2MplsVCManager(ApplicationId sdxl2id,
+                              SdxL2Store store,
+                              IntentService intentService) {
+
+        super(sdxl2id, store, intentService);
+        log.info("Started");
+    }
+
+    @Override
+    public Collection<Intent> buildIntents(String sdxl2, SdxL2ConnectionPoint ingress,
+                                           SdxL2ConnectionPoint egress) {
+        List<Intent> intents = null;
+        TrafficSelector selector;
+        TrafficTreatment treatment;
+        List<Constraint> encapsulation;
+        Key key;
+
+        if (ingress.vlanIds().size() == egress.vlanIds().size()) {
+            intents = new ArrayList<Intent>();
+            if (ingress.vlanIds().size() == 0) {
+
+                selector = buildSelector(null, null);
+                treatment = DefaultTrafficTreatment.emptyTreatment();
+                encapsulation = buildConstraints();
+
+                key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+                intents.add(PointToPointIntent.builder()
+                                    .appId(appId)
+                                    .key(key)
+                                    .selector(selector)
+                                    .treatment(treatment)
+                                    .constraints(encapsulation)
+                                    .ingressPoint(ingress.connectPoint())
+                                    .egressPoint(egress.connectPoint())
+                                    .priority(PRIORITY_OFFSET)
+                                    .build());
+            } else {
+
+                Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+                Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+                int index = 1;
+                while (ingressTags.hasNext()) {
+                    selector = buildSelector(null, ingressTags.next());
+                    treatment = buildTreatment(egressTags.next(),
+                                               null,
+                                               false);
+                    encapsulation = buildConstraints();
+
+                    key = generateIntentKey(sdxl2, ingress, egress, String.valueOf(index));
+
+                    intents.add(PointToPointIntent.builder()
+                                        .appId(appId)
+                                        .key(key)
+                                        .selector(selector)
+                                        .treatment(treatment)
+                                        .constraints(encapsulation)
+                                        .ingressPoint(ingress.connectPoint())
+                                        .egressPoint(egress.connectPoint())
+                                        .priority(PRIORITY_OFFSET)
+                                        .build());
+                    index = index + 1;
+                }
+
+            }
+            return intents;
+        }
+
+        if (ingress.vlanIds().size() == 1 && egress.vlanIds().size() == 0) {
+
+            Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+
+            selector = buildSelector(null, ingressTags.next());
+            treatment = buildTreatment(null,
+                                       null,
+                                       true);
+            encapsulation = buildConstraints();
+
+
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .constraints(encapsulation)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+
+        }
+
+        if (ingress.vlanIds().size() == 0 && egress.vlanIds().size() == 1) {
+
+            Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+
+            selector = buildSelector(null, null);
+            treatment = buildTreatment(null,
+                                       egressTags.next(),
+                                       false);
+            encapsulation = buildConstraints();
+
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .constraints(encapsulation)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+        }
+
+        log.warn(String.format(errorCreateIntents, ingress.name(), egress.name()));
+
+        return intents;
+    }
+
+    @Override
+    protected List<Constraint> buildConstraints() {
+        final List<Constraint> constraints = new LinkedList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.MPLS));
+        return constraints;
+    }
+
+}
\ No newline at end of file
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
index 94629d7..8601abb 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Service.java
@@ -39,61 +39,94 @@
     /**
      * Deletes a named SDX-L2.
      *
-     * @param sdxl2 SDX-L2 name
+     * @param sdxl2 name of SDX-L2
      */
     void deleteSdxL2(String sdxl2);
 
     /**
      * Returns a set of SDX-L2 names.
      *
-     * @return a set of SDX-L2 names
+     * @return set of SDX-L2 names
      */
     Set<String> getSdxL2s();
 
     /**
-     * Adds an SDX-L2 connection point to an SDX-L2.
+     * Adds a Connection Point to an SDX-L2.
      *
-     * @param sdxl2 SDX-L2 name
-     * @param sdxl2cp SDX-L2 connection point object
+     * @param sdxl2 name of SDX-L2
+     * @param sdxl2cp SDX-L2 Connection Point object
      */
     void addSdxL2ConnectionPoint(String sdxl2, SdxL2ConnectionPoint sdxl2cp);
 
     /**
-     * Returns all the SDX-L2 connection points names in a SDX-L2 or all the SDX-L2 connection points names.
+     * Returns all names of Connection Points names in a SDX-L2 or
+     * all the names of SDX-L2 Connection Points.
      *
-     * @param sdxl2 SDX-L2 name
+     * @param sdxl2 name of SDX-L2
      * @return a set of SDX-L2 connection points names
      */
     Set<String> getSdxL2ConnectionPoints(Optional<String> sdxl2);
 
     /**
-     * Removes an SDX-L2 connection point from an SDX-L2.
+     * Removes a Connection Point from an SDX-L2.
      *
-     * @param sdxl2cp SDX-L2 connection point name
+     * @param sdxl2cp name of SDX-L2 Connection Point
      */
     void removeSdxL2ConnectionPoint(String sdxl2cp);
 
     /**
-     * Returns an SDX-L2 connection point in a SDX-L2.
+     * Creates an L2 Virtual Circuit between two SDX-L2 Connection Points.
      *
-     * @param sdxl2cp SDX-L2 connection point name
+     * @param sdxl2 name of SDX-L2
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs name of SDX-L2 CP, right hand side of the VC
+     */
+    void addVC(String sdxl2, String sdxl2cplhs, String sdxl2cprhs);
+
+    /**
+     * Deletes a Virtual Circuit between Connection Points in an SDX-L2.
+     *
+     * @param vc name of SDX-L2 VC
+     */
+    void removeVC(String vc);
+
+    /**
+     * Returns a Connection Point in an SDX-L2.
+     *
+     * @param sdxl2cp name of SDX-L2 Connection Point
      * @return the relative SdxL2ConnectionPoint object
      */
     SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp);
 
     /**
+     * Returns all the Virtual Circuits in an SDX-L2.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @return set of Virtual Circuits names
+     */
+    Set<String> getVirtualCircuits(Optional<String> sdxl2);
+
+    /**
+     * Returns a Virtual Circuit in an SDX-L2.
+     *
+     * @param sdxl2vc name of the SDX-L2 VC
+     * @return the relative VirtualCircuit object
+     */
+    VirtualCircuit getVirtualCircuit(String sdxl2vc);
+
+    /**
      * Returns the state of the Intent that has been provided as input.
      *
-     * @param intentKey key of the intent;
-     * @return the last state of the intent;
+     * @param intentKey key of the intent
+     * @return the last state of the intent
      */
     SdxL2State getIntentState(Key intentKey);
 
     /**
      * Returns the state of the EdgePort that has been provided as input.
      *
-     * @param edgeport the connect point representing the edge port
-     * @return the last state of the edgeport;
+     * @param edgeport the Connection Point representing the edge port
+     * @return the last state of the edge port
      */
     SdxL2State getEdgePortState(ConnectPoint edgeport);
 
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
index c19ee42..0c465ee 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Store.java
@@ -27,32 +27,32 @@
     /**
      * Creates a named SDX-L2.
      *
-     * @param sdxl2 SDX-L2 name
-     * @throws SdxL2Exception if SDX-L2 exists
+     * @param sdxl2 name of SDX-L2
+     * @throws SdxL2Exception if SDX-L2 is not added
      */
     void putSdxL2(String sdxl2) throws SdxL2Exception;
 
     /**
      * Removes a named SDX-L2.
      *
-     * @param sdxl2 SDX-L2 name
-     * @throws SdxL2Exception if SDX-L2 does not exist
+     * @param sdxl2 name of SDX-L2
+     * @throws SdxL2Exception if SDX-L2 is not removed
      */
     void removeSdxL2(String sdxl2) throws SdxL2Exception;
 
     /**
      * Returns a set of SDX-L2 names.
      *
-     * @return a set of SDX-L2 names
+     * @return set of SDX-L2 names
      */
     Set<String> getSdxL2s();
 
     /**
-     * Adds an SDX-L2 connection point to an SDX-L2.
+     * Adds a Connection Point to an SDX-L2.
      *
-     * @param sdxl2 SDX-L2 name
-     * @param connectionPoint the SDX-L2 connection point object
-     * @throws SdxL2Exception if it is not possible to add the SDX-L2 connection point
+     * @param sdxl2 name of SDX-L2
+     * @param connectionPoint SDX-L2 cCnnection Point object
+     * @throws SdxL2Exception if SDX-L2 is not added
      */
     void addSdxL2ConnectionPoint(String sdxl2, SdxL2ConnectionPoint connectionPoint) throws SdxL2Exception;
 
@@ -60,28 +60,81 @@
      * Returns all the SDX-L2 connection points names or the SDX-L2 connection points name
      * that are related to an SDX-L2.
      *
-     * @param sdxl2 name (optional) of the SDX-L2
+     * @param sdxl2 name of the SDX-L2 (optional)
      * @return a set of SDX-L2 connection points names, the result depends on the input parameter;
-     * @throws SdxL2Exception if SDX-L2 is present but it does not exist
+     * @throws SdxL2Exception if SDX-L2 cannot be found
      */
     Set<String> getSdxL2ConnectionPoints(Optional<String> sdxl2) throws SdxL2Exception;
 
-
     /**
-     * Removes a named SDX-L2 connection point in an SDX-L2.
+     * Removes a named Connection Point in an SDX-L2.
      *
-     * @param sdxl2cp the connection point name
-     * @throws SdxL2Exception if the connection point does not exist
+     * @param sdxl2cp name of Connection Point
+     * @throws SdxL2Exception if SDX-L2 Connection Point does not exist
      */
     void removeSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception;
 
     /**
-     * Returns an SDX-L2 connection point in a SDX-L2.
+     * Returns a Connection Point in a SDX-L2.
      *
-     * @param sdxl2cp the connection point name
-     * @return the relative SDXL2ConnectionPoint object
-     * @throws SdxL2Exception if SDX-L2 connection point does not exist
+     * @param sdxl2cp name of Connection Point
+     * @return relative SDX-L2 Connection Point
+     * @throws SdxL2Exception if SDX-L2 CP cannot be found
      */
     SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) throws SdxL2Exception;
 
+    /**
+     * Creates a Virtual Circuit between two SDX-L2 Connection Points.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs name of SDX-L2 CP, right hand side of the VC
+     * @throws SdxL2Exception if SDX-L2 VC cannot be added
+     */
+    void addVC(String sdxl2, SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception;;
+
+    /**
+     * Deletes a Virtual Circuit between Connection Points in an SDX-L2.
+     *
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs ame of SDX-L2 CP, right hand side of the VC
+     * @throws SdxL2Exception if no name is provided for VC
+     */
+    void removeVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception;;
+
+    /**
+     * Deletes a Virtual Circuit where a given SDX-L2 CP acts as endpoint.
+     *
+     * @param cp Connection Point
+     * @throws SdxL2Exception if appropriate VC identifier is not provided
+     */
+    void removeVC(SdxL2ConnectionPoint cp) throws SdxL2Exception;;
+
+    /**
+     * Removes all Virtual Circuits created in a given SDX-L2.
+     *
+     * @param sdxl2 name of SDX-L2
+     */
+    void removeVCs(String sdxl2);
+
+    /**
+     * Returns an encoded Virtual Circuit in a SDX-L2.
+     *
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs ame of SDX-L2 CP, right hand side of the VC
+     * @return the encoded Virtual Circuit
+     * @throws SdxL2Exception if no matching VC exists
+     */
+    String getVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs)
+            throws SdxL2Exception;
+
+    /**
+     * Returns a) all Virtual Circuits, or b) Virtual Circuits in a given SDX-L2.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @return set of names for Virtual Circuits
+     */
+    Set<String> getVCs(Optional<String> sdxl2);
 }
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCManager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCManager.java
new file mode 100644
index 0000000..1d4d4e1
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCManager.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.NotImplementedException;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+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.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.lang.String.format;
+
+
+/**
+ * Manages Virtual Circuits.
+ * Base class extended by different types of VCs.
+ */
+public class SdxL2VCManager implements SdxL2VCService {
+
+    private static Logger log = LoggerFactory.getLogger(SdxL2VCManager.class);
+
+    protected static final String MATCH_FORMAT = "%s-%s";
+    protected static final String NAME_FORMAT = "%s:%s-%s";
+    protected static final String SDXL2_CPS_FORMAT = "%s~%s";
+    protected static final String KEY_FORMAT = "%s,%s";
+
+    protected ApplicationId appId;
+    protected SdxL2Store sdxL2Store;
+    protected IntentService intentService;
+
+    private static String errorIntentsForward = "Unable to create forward Intents";
+    private static String errorIntentsReverse = "Unable to create reverse Intents";
+    protected static String errorCreateIntents = "Unable to create Intents for %s-%s";
+
+
+    /**
+     * Creates an SDX-L2 VC Manager.
+     *
+     * @param sdxl2id application ID
+     * @param store reference to the SDX-L2 store
+     * @param intentService reference to the Intent service
+     */
+    public SdxL2VCManager(ApplicationId sdxl2id,
+                          SdxL2Store store,
+                          IntentService intentService) {
+
+        this.appId = sdxl2id;
+        this.sdxL2Store = store;
+        this.intentService = intentService;
+    }
+
+    @Override
+    public void addVC(String sdxl2, SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        try {
+            this.sdxL2Store.addVC(sdxl2, sdxl2cplhs, sdxl2cprhs);
+
+            Collection<Intent> intentsFW = buildIntents(sdxl2, sdxl2cplhs, sdxl2cprhs);
+            Collection<Intent> intentsRV = buildIntents(sdxl2, sdxl2cprhs, sdxl2cplhs);
+
+            if (intentsFW == null) {
+                System.err.println("\u001B[0;31mError executing command: "
+                                           + errorIntentsForward + "\u001B[0;49m");
+                return;
+            }
+            if (intentsRV == null) {
+                System.err.println("\u001B[0;31mError executing command: "
+                                           + errorIntentsReverse + "\u001B[0;49m");
+                return;
+            }
+
+            List<Intent> intents = new ArrayList<Intent>();
+            intents.addAll(intentsFW);
+            intents.addAll(intentsRV);
+            intents.forEach(intent -> {
+                intentService.submit(intent);
+            });
+        } catch (SdxL2Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        try {
+            this.sdxL2Store.removeVC(sdxl2cplhs, sdxl2cprhs);
+            Iterables.filter(intentService.getIntents(), intent ->
+                    (matches(sdxl2cplhs, sdxl2cprhs, intent) ||
+                            (matches(sdxl2cprhs, sdxl2cplhs, intent))))
+                    .forEach(intentService::withdraw);
+        } catch (SdxL2Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void removeVC(SdxL2ConnectionPoint cp) {
+        try {
+            this.sdxL2Store.removeVC(cp);
+            Iterables.filter(intentService.getIntents(), intent -> (matches(cp, intent)))
+                    .forEach(intentService::withdraw);
+        } catch (SdxL2Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    /**
+     * Creates a set of Intents for the ingress and egress SDX-L2 Connection Point.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @param ingress the ingress point with the relative traffic attributes
+     * @param egress  the egress point with the relative traffic attributes
+     * @return a set of intent or a null set;
+     */
+    public Collection<Intent> buildIntents(String sdxl2, SdxL2ConnectionPoint ingress,
+                                           SdxL2ConnectionPoint egress) {
+        throw new NotImplementedException("buildIntents not implemented");
+    }
+
+    /**
+     * Matches an intent given two SDX-L2 connection points.
+     *
+     * @param sdxl2cplhs left hand side of the virtual circuit
+     * @param sdxl2cprhs right hand side of the virtual circuit
+     * @param intent     intent to match
+     * @return result of the match
+     */
+    protected boolean matches(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs, Intent intent) {
+        if (!Objects.equals(appId, intent.appId())) {
+            // different app ids
+            return false;
+        }
+
+        String key = intent.key().toString();
+        String[] fields = key.split(":");
+        String cps = format(MATCH_FORMAT, sdxl2cplhs.name(), sdxl2cprhs.name());
+
+        return fields.length == 2 && fields[1].contains(cps);
+    }
+
+    /**
+     * Matches an intent given an SDX-L2 Connection Point.
+     *
+     * @param cp hand side of a Virtual Circuit
+     * @param intent intent to match
+     * @return result of the match
+     */
+    protected boolean matches(SdxL2ConnectionPoint cp, Intent intent) {
+        if (!Objects.equals(appId, intent.appId())) {
+            // different app ids
+            return false;
+        }
+
+        String key = intent.key().toString();
+        String[] fields = key.split(":");
+
+        if (fields.length != 2) {
+            return false;
+        }
+        String[] cps = fields[1].split(",");
+
+        if (cps.length != 2) {
+            return false;
+        }
+        String[] hss = cps[0].split("-");
+
+        return hss.length == 2 && (hss[0].equals(cp.name()) || hss[1].equals(cp.name()));
+    }
+
+    @Override
+    public void removeVCs(String sdxl2) {
+        this.sdxL2Store.removeVCs(sdxl2);
+        Iterables.filter(intentService.getIntents(), intent -> (matches(sdxl2, intent)))
+                .forEach(intentService::withdraw);
+
+    }
+
+    /**
+     * Matches an intent given an SDX-L2 Connection Point.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @param intent intent to match
+     * @return result of the match
+     */
+    protected boolean matches(String sdxl2, Intent intent) {
+        if (!Objects.equals(appId, intent.appId())) {
+            // different app ids
+            return false;
+        }
+
+        String key = intent.key().toString();
+        String[] fields = key.split(":");
+
+        return fields.length == 2 && fields[0].equals(sdxl2);
+    }
+
+    @Override
+    public Set<String> getVCs(Optional<String> sdxl2) {
+        return this.sdxL2Store.getVCs(sdxl2);
+    }
+
+    @Override
+    public String getVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        try {
+            return this.sdxL2Store.getVC(sdxl2cplhs, sdxl2cprhs);
+        } catch (SdxL2Exception e) {
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Returns Intent key from SDX-L2 and two SDX-L2 Connection Points.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @param cpone sdxl2 connection point one
+     * @param cptwo sdxl2 connection point two
+     * @param index digit used to help identify Intent
+     * @return canonical intent string key
+     */
+    protected Key generateIntentKey(String sdxl2, SdxL2ConnectionPoint cpone,
+                                    SdxL2ConnectionPoint cptwo, String index) {
+        String cps = format(NAME_FORMAT, sdxl2, cpone.name(), cptwo.name());
+        String key = format(KEY_FORMAT, cps, index);
+        return Key.of(key, appId);
+    }
+
+    /**
+     * Returns the traffic treatment, used in the definition of the intents.
+     *
+     * @param setVlan VLAN to set
+     * @param pushVlan VLAN to push
+     * @param popVlan boolean to indicate whether a popVlan action is
+     *                performed (true) or not (false)
+     * @return TrafficTreatment object
+     */
+    protected TrafficTreatment buildTreatment(VlanId setVlan,
+                                            VlanId pushVlan,
+                                            boolean popVlan) {
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        if (setVlan != null) {
+            treatmentBuilder.setVlanId(setVlan);
+        }
+        if (pushVlan != null) {
+            treatmentBuilder.pushVlan();
+            treatmentBuilder.setVlanId(pushVlan);
+        }
+        if (popVlan) {
+            treatmentBuilder.popVlan();
+        }
+        return treatmentBuilder.build();
+    }
+
+    /**
+     * Returns the traffic selector, used in the definition of the intents.
+     *
+     * @param ethertype name of the Ethernet type used (e.g.  of SDX-L2
+     * @param ingresstag VLAN id used at the ingress
+     * @return TrafficSelector object
+     */
+    protected TrafficSelector buildSelector(Short ethertype, VlanId ingresstag) {
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        if (ethertype != null) {
+            selectorBuilder.matchEthType(ethertype);
+        }
+        if (ingresstag != null) {
+            selectorBuilder.matchVlanId(ingresstag);
+        }
+        return selectorBuilder.build();
+    }
+
+    /**
+     * Returns constraints depending on the encapsulation used on the VC.
+     *
+     * @return list of constraints to be used in the intents
+     */
+    protected List<Constraint> buildConstraints() {
+        throw new NotImplementedException("buildConstraints not implemented");
+    }
+}
\ No newline at end of file
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCService.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCService.java
new file mode 100644
index 0000000..6f65b8b
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VCService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Service that allows the creation of L2 Virtual Circuits
+ * between edge ports of a given SDN network.
+ */
+public interface SdxL2VCService {
+
+    /**
+     * Creates an L2 Virtual Circuit between two SDX-L2 Connection Points.
+     *
+     * @param sdxl2 name of SDX-L2
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs name of SDX-L2 CP, right hand side of the VC
+     */
+    void addVC(String sdxl2, SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs);
+
+    /**
+     * Deletes a Virtual Circuit from an SDX-L2.
+     *
+     * @param sdxl2cplhs name of SDX-L2 CP, left hand side of the VC
+     * @param sdxl2cprhs name of SDX-L2 CP, right hand side of the VC
+     */
+    void removeVC(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs);
+
+    /**
+     * Deletes a Virtual Circuit where a given SDX-L2 CP acts as endpoint.
+     *
+     * @param cp Connection Point
+     */
+    void removeVC(SdxL2ConnectionPoint cp);
+
+    /**
+     * Removes all Virtual Circuits created in a given SDX-L2.
+     *
+     * @param sdxl2 name of SDX-L2
+     */
+    void removeVCs(String sdxl2);
+
+    /**
+     * Returns Virtual Circuits (either all or those created in a given SDX-L2).
+     *
+     * @param sdxl2 name of SDX-L2
+     * @return the set of virtual circuits name
+     */
+    Set<String> getVCs(Optional<String> sdxl2);
+
+    /**
+     * Returns an encoded Virtual Circuit in a given SDX-L2.
+     *
+     * @param lhs left hand side of the VC
+     * @param rhs right hand side of the VC
+     * @return encoded VC
+     */
+    String getVC(SdxL2ConnectionPoint lhs, SdxL2ConnectionPoint rhs);
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VlanVCManager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VlanVCManager.java
new file mode 100644
index 0000000..ddf6896
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2VlanVCManager.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Manages Virtual Circuits using VLANs.
+ */
+public class SdxL2VlanVCManager extends SdxL2VCManager {
+
+    private static final int PRIORITY_OFFSET = 2000;
+    private static Logger log = LoggerFactory.getLogger(SdxL2VlanVCManager.class);
+
+    /**
+     * Creates an SDX-L2 VLAN VC Manager.
+     *
+     * @param sdxl2id application ID
+     * @param store reference to the SDX-L2 store
+     * @param intentService reference to the Intent service
+     */
+    public SdxL2VlanVCManager(ApplicationId sdxl2id,
+                              SdxL2Store store,
+                              IntentService intentService) {
+        super(sdxl2id, store, intentService);
+        log.info("Started");
+    }
+
+    @Override
+    public Collection<Intent> buildIntents(String sdxl2, SdxL2ConnectionPoint ingress, SdxL2ConnectionPoint egress) {
+        List<Intent> intents = null;
+        TrafficSelector selector;
+        TrafficTreatment treatment;
+        List<Constraint> encapsulation;
+        Key key;
+
+        if (ingress.vlanIds().size() == egress.vlanIds().size()) {
+            intents = new ArrayList<Intent>();
+            if (ingress.vlanIds().size() == 0) {
+
+                selector = buildSelector(null, null);
+                treatment = DefaultTrafficTreatment.emptyTreatment();
+                encapsulation = buildConstraints();
+
+                key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+                intents.add(PointToPointIntent.builder()
+                                    .appId(appId)
+                                    .key(key)
+                                    .selector(selector)
+                                    .treatment(treatment)
+                                    .constraints(encapsulation)
+                                    .ingressPoint(ingress.connectPoint())
+                                    .egressPoint(egress.connectPoint())
+                                    .priority(PRIORITY_OFFSET)
+                                    .build());
+            } else {
+
+                Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+                Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+                int index = 1;
+                while (ingressTags.hasNext()) {
+
+                    selector = buildSelector(null, ingressTags.next());
+                    treatment = buildTreatment(egressTags.next(),
+                                               null,
+                                               false);
+                    encapsulation = buildConstraints();
+
+                    key = generateIntentKey(sdxl2, ingress, egress, String.valueOf(index));
+
+                    intents.add(PointToPointIntent.builder()
+                                        .appId(appId)
+                                        .key(key)
+                                        .selector(selector)
+                                        .treatment(treatment)
+                                        .constraints(encapsulation)
+                                        .ingressPoint(ingress.connectPoint())
+                                        .egressPoint(egress.connectPoint())
+                                        .priority(PRIORITY_OFFSET)
+                                        .build());
+                    index = index + 1;
+                }
+
+            }
+            return intents;
+        }
+
+        if (ingress.vlanIds().size() == 1 && egress.vlanIds().size() == 0) {
+
+            Iterator<VlanId> ingressTags = ingress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+
+            selector = buildSelector(null, ingressTags.next());
+            treatment = buildTreatment(null,
+                                       null,
+                                       true);
+            encapsulation = buildConstraints();
+
+
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .constraints(encapsulation)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+
+        }
+
+        if (ingress.vlanIds().size() == 0 && egress.vlanIds().size() == 1) {
+
+            Iterator<VlanId> egressTags = egress.vlanIds().iterator();
+            intents = new ArrayList<Intent>();
+
+            selector = buildSelector(null, null);
+            treatment = buildTreatment(null,
+                                       egressTags.next(),
+                                       false);
+            encapsulation = buildConstraints();
+
+            key = generateIntentKey(sdxl2, ingress, egress, "1");
+
+            intents.add(PointToPointIntent.builder()
+                                .appId(appId)
+                                .key(key)
+                                .selector(selector)
+                                .treatment(treatment)
+                                .constraints(encapsulation)
+                                .ingressPoint(ingress.connectPoint())
+                                .egressPoint(egress.connectPoint())
+                                .priority(PRIORITY_OFFSET)
+                                .build());
+            return intents;
+        }
+
+        log.warn(String.format(errorCreateIntents, ingress.name(), egress.name()));
+
+        return intents;
+    }
+
+    @Override
+    protected List<Constraint> buildConstraints() {
+        final List<Constraint> constraints = new LinkedList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+        return constraints;
+    }
+
+}
\ No newline at end of file
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/VirtualCircuit.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/VirtualCircuit.java
new file mode 100644
index 0000000..1561382
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/VirtualCircuit.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Abstraction of a L2 Virtual Circuit.
+ * Note the circuit is expressed as a composition of two SDX-L2 Connection Points.
+ */
+public class VirtualCircuit {
+
+    private final String name;
+    private final SdxL2ConnectionPoint sdxl2cplhs;
+    private final SdxL2ConnectionPoint sdxl2cprhs;
+
+    /**
+     * Creates a new Virtual Circuit.
+     *
+     * @param sdxl2cplhs left hand side of the virtual circuit
+     * @param sdxl2cprhs right hand side of the virtual circuit
+     */
+    public VirtualCircuit(SdxL2ConnectionPoint sdxl2cplhs, SdxL2ConnectionPoint sdxl2cprhs) {
+        this.name = sdxl2cplhs.name() + "-" + sdxl2cprhs.name();
+        this.sdxl2cplhs = sdxl2cplhs;
+        this.sdxl2cprhs = sdxl2cprhs;
+    }
+
+    /**
+     * Returns the left hand side of the Virtual Circuit.
+     *
+     * @return SDX-L2 Connection Point
+     */
+    public SdxL2ConnectionPoint lhs() {
+        return sdxl2cplhs;
+    }
+
+    /**
+     * Returns the right hand side of the Virtual Circuit.
+     *
+     * @return SDX-L2 Connection Point
+     */
+    public SdxL2ConnectionPoint rhs() {
+        return sdxl2cprhs;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, sdxl2cplhs, sdxl2cprhs);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof VirtualCircuit) {
+            final VirtualCircuit other = (VirtualCircuit) obj;
+            return (Objects.equals(this.sdxl2cplhs, other.sdxl2cplhs) &&
+                    Objects.equals(this.sdxl2cprhs, other.sdxl2cprhs)) ||
+                    (Objects.equals(this.sdxl2cplhs, other.sdxl2cprhs) &&
+                            Objects.equals(this.sdxl2cprhs, other.sdxl2cplhs));
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("name", name)
+                .add("lhs", sdxl2cplhs)
+                .add("rhs", sdxl2cprhs)
+                .toString();
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCPCommand.java
index eb000b8..ea13441 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCPCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCPCommand.java
@@ -27,38 +27,33 @@
 /**
  * CLI to create a named SDX-L2 connection point.
  */
-@Command(scope = "sdxl2", name = "sdxl2cp-add", description = "Create a named sdx-l2 connection point")
+@Command(scope = "sdxl2", name = "sdxl2cp-add", description = "Creates a named SDX-L2 Connection Point")
 public class SdxL2AddCPCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2name", description = "Sdxl2name",
+    @Argument(index = 0, name = "sdxl2name", description = "Name of SDX-L2",
             required = true, multiValued = false)
-    String sdxl2name = null;
+    private String sdxl2name = null;
 
-    @Argument(index = 1, name = "connectionpoint", description = "Connection point",
+    @Argument(index = 1, name = "connectionpoint", description = "Identifier of SDX-L2 Connection point",
             required = true, multiValued = false)
-    String cp = null;
+    private String cp = null;
 
-    @Argument(index = 2, name = "vlans", description = "Customer edge vlans separated by comma",
+    @Argument(index = 2, name = "sdxl2cpname", description = "Name of SDX-L2 Connection Point",
             required = true, multiValued = false)
-    String vlans = null;
+    private String sdxl2cpname = null;
 
-    @Argument(index = 3, name = "sdxl2cpname", description = "Sdxl2 connection point name",
-            required = true, multiValued = false)
-    String sdxl2cpname = null;
+    @Argument(index = 3, name = "vlans", description = "Customer edge VLANs, separated by dash " +
+            "and comma", required = false, multiValued = false)
+    private String vlans = null;
 
-    @Option(name = "-ce_mac", description = "Customer edge mac address",
+    @Option(name = "-ce_mac", description = "Customer edge MAC address",
             required = false, multiValued = false)
-    String mac = null;
+    private String mac = null;
 
     @Override
     protected void execute() {
         SdxL2Service sdxl2Service = get(SdxL2Service.class);
-        SdxL2ConnectionPoint sdxl2cp;
-        if (mac != null) {
-            sdxl2cp = SdxL2ConnectionPoint.sdxl2ConnectionPoint(sdxl2cpname, cp, vlans, mac);
-        } else {
-            sdxl2cp = SdxL2ConnectionPoint.sdxl2ConnectionPoint(sdxl2cpname, cp, vlans);
-        }
+        SdxL2ConnectionPoint sdxl2cp = SdxL2ConnectionPoint.sdxl2ConnectionPoint(sdxl2cpname, cp, vlans, mac);
         sdxl2Service.addSdxL2ConnectionPoint(sdxl2name, sdxl2cp);
     }
 
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCommand.java
index c7bb963..4aea7be 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddCommand.java
@@ -24,11 +24,11 @@
 /**
  * CLI to create SDX-L2.
  */
-@Command(scope = "sdxl2", name = "sdxl2-add", description = "Create a sdx-l2")
+@Command(scope = "sdxl2", name = "sdxl2-add", description = "Creates a SDX-L2")
 public class SdxL2AddCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2name", description = "Sdxl2 name", required = true, multiValued = false)
-    String sdxl2 = null;
+    @Argument(index = 0, name = "sdxl2name", description = "Name of SDX-L2", required = true, multiValued = false)
+    private String sdxl2 = null;
 
     @Override
     protected void execute() {
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddVCCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddVCCommand.java
new file mode 100644
index 0000000..2a75e37
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2AddVCCommand.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl2.SdxL2Service;
+
+/**
+ * CLI to create a VC between two Connection Points in the same SDX-L2.
+ */
+@Command(scope = "sdxl2", name = "sdxl2vc-add",
+        description = "Creates a VC between two Connection Points in the same SDX-L2")
+public class SdxL2AddVCCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "sdxl2name", description = "Name of SDX-L2",
+            required = true, multiValued = false)
+    private String sdxL2name = null;
+
+    @Argument(index = 1, name = "lhs", description = "Left hand side Connection Point",
+            required = true, multiValued = false)
+    private String lhs = null;
+
+    @Argument(index = 2, name = "rhs", description = "Right hand side Connection Point",
+            required = true, multiValued = false)
+    private String rhs = null;
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        sdxl2Service.addVC(sdxL2name, lhs, rhs);
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java
index 8f5b3ea..779da65 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetCPCommand.java
@@ -24,13 +24,13 @@
 import org.onosproject.sdxl2.SdxL2State;
 
 /**
- * Cli to print the details of an SdxL2ConnectionPoint.
+ * CLI to print the details of an SdxL2ConnectionPoint.
  */
-@Command(scope = "sdxl2", name = "sdxl2cp", description = "Prints the details of an SDXL2ConnectionPoint")
+@Command(scope = "sdxl2", name = "sdxl2cp", description = "Prints the details of an SDX-L2 Connection Point")
 public class SdxL2GetCPCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2cpname", description = "Sdxl2cp name", required = true, multiValued = false)
-    String sdxl2cpname = null;
+    @Argument(index = 0, name = "sdxl2cpname", description = "Name of SDX-L2", required = true, multiValued = false)
+    private String sdxl2cpname = null;
 
     private static final String HEADER       = "\n\u001B[1;37mStatus\t\t" +
             "Connection Point\t\tName\t\tVlan IDs\t\tCE Mac Address\u001B[0m";
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetVCCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetVCCommand.java
new file mode 100644
index 0000000..66efaf7
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2GetVCCommand.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import com.google.common.collect.Iterables;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.sdxl2.SdxL2ConnectionPoint;
+import org.onosproject.sdxl2.SdxL2Service;
+import org.onosproject.sdxl2.SdxL2State;
+import org.onosproject.sdxl2.VirtualCircuit;
+
+import java.util.Iterator;
+
+import static java.lang.String.format;
+
+/**
+ * CLI to print the details of a Virtual Circuit in an SDX-L2.
+ */
+@Command(scope = "sdxl2", name = "sdxl2vc", description = "Prints the details of an SDX-L2 Virtual Circuit")
+public class SdxL2GetVCCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "sdxl2vcname", description = "Name of SDX-L2 VC", required = true, multiValued = false)
+    private String sdxl2vcname = null;
+
+    private  static final String MATCH_FORMAT = "%s-%s";
+    private static final String HEADER_CP =
+            "\n\u001B[1;37mStatus\t\tConnection Point\t\tName\t\tVlan IDs\t\tCE Mac Address\u001B[0m";
+    private static final String SEPARATOR_CP = "\u001B[1;37m------------" +
+            "-----------------------------------------------------------" +
+            "--------------------------------------\u001B[0m";
+    private static final String FORMAT_SDXL2CP_ONLINE =
+            "\u001B[1;32m%s\u001B[0m\t\t\u001B[1;37m%s/%s\t\t%s\t\t%s\t\t%s\u001B[0m";
+    private static final String FORMAT_SDXL2CP_OFFLINE =
+            "\u001B[1;31m%s\u001B[0m\t\t\u001B[1;37m%s/%s\t\t%s\t\t%s\t\t%s\u001B[0m";
+
+    private static final String HEADER_VC =
+            "\n\u001B[1;37mStatus\t\tIntent\u001B[0m";
+    private static final String SEPARATOR_VC =
+            "\u001B[1;37m--------------------------------------------\u001B[0m";
+    private static final String FORMAT_SDXL2VC_ONLINE =
+            "\u001B[1;32m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+    private static final String FORMAT_SDXL2VC_OFFLINE =
+            "\u001B[1;31m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+    private static final String FORMAT_SDXL2VC_CHECK =
+            "\u001B[1;33m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        VirtualCircuit virtualCircuit;
+        SdxL2ConnectionPoint sdxl2ConnectionPoint;
+        SdxL2State state;
+        virtualCircuit = sdxl2Service.getVirtualCircuit(sdxl2vcname);
+        if (virtualCircuit == null) {
+            return;
+        }
+
+        print(HEADER_CP);
+        print(SEPARATOR_CP);
+
+        sdxl2ConnectionPoint = virtualCircuit.lhs();
+        state = sdxl2Service.getEdgePortState(sdxl2ConnectionPoint.connectPoint());
+        if (state == SdxL2State.ONLINE) {
+            print(FORMAT_SDXL2CP_ONLINE,
+                  "ONLINE",
+                  sdxl2ConnectionPoint.connectPoint().elementId(),
+                  sdxl2ConnectionPoint.connectPoint().port(),
+                  sdxl2ConnectionPoint.name(),
+                  sdxl2ConnectionPoint.vlanIds(),
+                  sdxl2ConnectionPoint.macAddress());
+        } else if (state == SdxL2State.OFFLINE) {
+            print(FORMAT_SDXL2CP_OFFLINE,
+                  "OFFLINE",
+                  sdxl2ConnectionPoint.connectPoint().elementId(),
+                  sdxl2ConnectionPoint.connectPoint().port(),
+                  sdxl2ConnectionPoint.name(),
+                  sdxl2ConnectionPoint.vlanIds(),
+                  sdxl2ConnectionPoint.macAddress());
+        }
+
+
+        sdxl2ConnectionPoint = virtualCircuit.rhs();
+        state = sdxl2Service.getEdgePortState(sdxl2ConnectionPoint.connectPoint());
+        if (state == SdxL2State.ONLINE) {
+            print(FORMAT_SDXL2CP_ONLINE,
+                  "ONLINE",
+                  sdxl2ConnectionPoint.connectPoint().elementId(),
+                  sdxl2ConnectionPoint.connectPoint().port(),
+                  sdxl2ConnectionPoint.name(),
+                  sdxl2ConnectionPoint.vlanIds(),
+                  sdxl2ConnectionPoint.macAddress());
+        } else if (state == SdxL2State.OFFLINE) {
+            print(FORMAT_SDXL2CP_OFFLINE,
+                  "OFFLINE",
+                  sdxl2ConnectionPoint.connectPoint().elementId(),
+                  sdxl2ConnectionPoint.connectPoint().port(),
+                  sdxl2ConnectionPoint.name(),
+                  sdxl2ConnectionPoint.vlanIds(),
+                  sdxl2ConnectionPoint.macAddress());
+        }
+        print("");
+
+        print(HEADER_VC);
+        print(SEPARATOR_VC);
+        IntentService intentService = get(IntentService.class);
+        Iterator<Intent> intents = Iterables.filter(intentService.getIntents(), intent ->
+                (matches(virtualCircuit.lhs(), virtualCircuit.rhs(), intent) ||
+                        (matches(virtualCircuit.rhs(), virtualCircuit.lhs(), intent)))).iterator();
+        Intent intent;
+        Key key;
+        while (intents.hasNext()) {
+            intent = intents.next();
+            key = intent.key();
+            state = sdxl2Service.getIntentState(key);
+            if (state == SdxL2State.ONLINE) {
+                print(FORMAT_SDXL2VC_ONLINE,
+                      "ONLINE",
+                      key);
+            } else if (state == SdxL2State.OFFLINE) {
+                print(FORMAT_SDXL2VC_OFFLINE,
+                      "OFFLINE",
+                      key);
+            } else {
+                print(FORMAT_SDXL2VC_CHECK,
+                      "CHECK",
+                      key);
+            }
+        }
+        print("");
+    }
+
+    /**
+     * Matches an intent given two sdxl2 connection points.
+     *
+     * @param lhs    left hand side of the virtual circuit
+     * @param rhs    right hand side of the virtual circuit
+     * @param intent intent to match
+     * @return result of the match
+     */
+    private boolean matches(SdxL2ConnectionPoint lhs, SdxL2ConnectionPoint rhs, Intent intent) {
+
+        String key = intent.key().toString();
+        String[] fields = key.split(":");
+        String cps = format(MATCH_FORMAT, lhs.name(), rhs.name());
+
+        return fields.length == 2 && fields[1].contains(cps);
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java
index b25f349..4e702af 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCPCommand.java
@@ -29,12 +29,12 @@
 /**
  * CLI to list the SDX-L2 connection points.
  */
-@Command(scope = "sdxl2", name = "sdxl2cps-list", description = "Lists " +
-        "all the sdxl2 connection points. Argument not required the name of sdxl2")
+@Command(scope = "sdxl2", name = "sdxl2cp-list", description = "Lists " +
+        "all the SDX-L2 Connection Points. Argument not required the name of SDX-L2")
 public class SdxL2ListCPCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2name", description = "sdxl2name", required = false, multiValued = false)
-    String sdxl2 = null;
+    @Argument(index = 0, name = "sdxl2name", description = "Name of SDX-L2", required = false, multiValued = false)
+    private String sdxl2 = null;
 
     private static final String HEADER = "\n\u001B[1;37mStatus\t\tSDXL2 Connection Point\u001B[0m";
     private static final String SEPARATOR = "\u001B[1;37m-----------------------------------------------\u001B[0m";
@@ -48,9 +48,9 @@
         Set<String> result = sdxl2Service.getSdxL2ConnectionPoints(sdxl2name);
         SdxL2ConnectionPoint sdxl2ConnectionPoint;
         SdxL2State sdxl2cpState;
+        print(HEADER);
+        print(SEPARATOR);
         if (result.size() > 0) {
-            print(HEADER);
-            print(SEPARATOR);
             for (String sdxl2cp : result) {
                 sdxl2ConnectionPoint = sdxl2Service.getSdxL2ConnectionPoint(sdxl2cp);
                 if (sdxl2ConnectionPoint == null) {
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
index 42f91d1..f03b656 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListCommand.java
@@ -25,7 +25,7 @@
 /**
  * CLI to list the SDX-L2s.
  */
-@Command(scope = "sdxl2", name = "sdxl2-list", description = "Lists the sdx-l2s")
+@Command(scope = "sdxl2", name = "sdxl2-list", description = "Lists the SDX-L2s")
 public class SdxL2ListCommand extends AbstractShellCommand {
 
     private static final String HEADER = "\n\u001B[1;37mSDXL2\u001B[0m";
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListVCCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListVCCommand.java
new file mode 100644
index 0000000..13eb0f9
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2ListVCCommand.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import com.google.common.collect.Iterables;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.sdxl2.SdxL2ConnectionPoint;
+import org.onosproject.sdxl2.SdxL2Service;
+import org.onosproject.sdxl2.SdxL2State;
+import org.onosproject.sdxl2.VirtualCircuit;
+
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.lang.String.format;
+
+/**
+ * CLI to delete a Connection Point in an SDX-L2.
+ */
+@Command(scope = "sdxl2", name = "sdxl2vc-list",
+        description = "Lists all the SDX-L2 Virtual Circuits. Argument not required the name of SDX-L2")
+public class SdxL2ListVCCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "Name of SDX-L2",
+            description = "Sdxl2 name", required = false, multiValued = false)
+    private String sdxl2 = null;
+
+    private static final String MATCH_FORMAT = "%s-%s";
+
+    private static final String HEADER =
+            "\n\u001B[1;37mStatus\t\tVirtual Circuit\u001B[0m";
+    private static final String SEPARATOR =
+            "\u001B[1;37m-----------------------------------------------\u001B[0m";
+    private static final String FORMAT_SDXL2VC_ONLINE =
+            "\u001B[1;32m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+    private static final String FORMAT_SDXL2VC_OFFLINE =
+            "\u001B[1;31m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+    private static final String FORMAT_SDXL2VC_CHECK =
+            "\u001B[1;33m%s\u001B[0m\t\t\u001B[1;37m%s\u001B[0m";
+
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        Optional<String> sdxl2name = Optional.ofNullable(sdxl2);
+        Set<String> result = sdxl2Service.getVirtualCircuits(sdxl2name);
+        VirtualCircuit vc;
+        SdxL2State state;
+        print(HEADER);
+        print(SEPARATOR);
+        if (result.size() > 0) {
+            String[] sdxl2VC;
+            for (String sdxl2vc : result) {
+                sdxl2VC = sdxl2vc.split(":");
+                vc = sdxl2Service.getVirtualCircuit(sdxl2vc);
+                if (vc == null) {
+                    break;
+                }
+                state = this.getVirtualCircuitState(vc);
+                if (state == SdxL2State.ONLINE) {
+                    print(FORMAT_SDXL2VC_ONLINE, "ONLINE", sdxl2VC[1]);
+                } else if (state == SdxL2State.OFFLINE) {
+                    print(FORMAT_SDXL2VC_OFFLINE, "OFFLINE", sdxl2VC[1]);
+                } else {
+                    print(FORMAT_SDXL2VC_CHECK, "CHECK", sdxl2VC[1]);
+                }
+            }
+            print("");
+        }
+    }
+
+    /**
+     * Retrieves status of a Virtual Circuit from the status of its
+     * Connection Points.
+     *
+     * @param vc VirtualCircuit object
+     * @return state of the Virtual Circuit
+     */
+    private SdxL2State getVirtualCircuitState(VirtualCircuit vc) {
+        IntentService intentService = get(IntentService.class);
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        SdxL2State intentState = SdxL2State.ONLINE;
+        SdxL2State lhsState;
+        SdxL2State rhsstate;
+        Iterator<Intent> intents = Iterables.filter(intentService.getIntents(), intent ->
+                (matches(vc.lhs(), vc.rhs(), intent) ||
+                        (matches(vc.rhs(), vc.lhs(), intent)))).iterator();
+        Intent intent;
+        Key key;
+        int numIntents = 0;
+        int numIntentsOffline = 0;
+        while (intents.hasNext()) {
+            intent = intents.next();
+            key = intent.key();
+            intentState = sdxl2Service.getIntentState(key);
+            if (intentState == SdxL2State.OFFLINE || intentState == SdxL2State.CHECK) {
+                numIntentsOffline = numIntentsOffline + 1;
+            }
+            numIntents = numIntents + 1;
+        }
+
+        if (numIntents == numIntentsOffline) {
+            return SdxL2State.OFFLINE;
+        }
+
+        lhsState = sdxl2Service.getEdgePortState(vc.lhs().connectPoint());
+        if (lhsState == SdxL2State.OFFLINE) {
+            return SdxL2State.OFFLINE;
+        }
+
+        rhsstate = sdxl2Service.getEdgePortState(vc.rhs().connectPoint());
+        if (rhsstate == SdxL2State.OFFLINE) {
+            return SdxL2State.OFFLINE;
+        }
+
+        if (intentState == SdxL2State.ONLINE && lhsState == SdxL2State.ONLINE &&
+                rhsstate == SdxL2State.ONLINE) {
+            return SdxL2State.ONLINE;
+        }
+
+        return SdxL2State.CHECK;
+    }
+
+    /**
+     * Matches an intent given two SDX-L2 Connection Points.
+     *
+     * @param lhs    left hand side of the virtual circuit
+     * @param rhs    right hand side of the virtual circuit
+     * @param intent intent to match
+     * @return result of the match
+     */
+    private boolean matches(SdxL2ConnectionPoint lhs, SdxL2ConnectionPoint rhs, Intent intent) {
+        String key = intent.key().toString();
+        String[] fields = key.split(":");
+        String cps = format(MATCH_FORMAT, lhs.name(), rhs.name());
+
+        return fields.length == 2 && fields[1].contains(cps);
+    }
+}
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCPCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCPCommand.java
index 3e1dfee..00da8c5 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCPCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCPCommand.java
@@ -23,14 +23,14 @@
 import org.onosproject.sdxl2.SdxL2Service;
 
 /**
- * CLI to delete a named SDX-L2 connection point.
+ * CLI to delete a named SDX-L2 Connection Point.
  */
-@Command(scope = "sdxl2", name = "sdxl2cp-remove", description = "Remove a named sdxl2 connection point")
+@Command(scope = "sdxl2", name = "sdxl2cp-remove", description = "Removes a named SDX-L2 Connection Point")
 public class SdxL2RemoveCPCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2cpname", description = "Sdxl2 connection point name",
+    @Argument(index = 0, name = "sdxl2cpname", description = "Name of SDX-L2 Connection Point",
             required = true, multiValued = false)
-    String sdxl2cpname = null;
+    private String sdxl2cpname = null;
 
     @Override
     protected void execute() {
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCommand.java
index aecb899..ab416e4 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCommand.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveCommand.java
@@ -24,12 +24,12 @@
 /**
  * CLI to delete a named SDX-L2.
  */
-@Command(scope = "sdxl2", name = "sdxl2-remove", description = "Delete a sdx-l2")
+@Command(scope = "sdxl2", name = "sdxl2-remove", description = "Deletes a SDX-L2")
 public class SdxL2RemoveCommand extends AbstractShellCommand {
 
-    @Argument(index = 0, name = "sdxl2name", description = "Sdxl2 name",
+    @Argument(index = 0, name = "sdxl2name", description = "Name of SDX-L2",
             required = true, multiValued = false)
-    String sdxl2 = null;
+    private String sdxl2 = null;
 
     @Override
     protected void execute() {
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveVCCommand.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveVCCommand.java
new file mode 100644
index 0000000..d4b8d25
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/SdxL2RemoveVCCommand.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl2.SdxL2Service;
+
+/**
+ * CLI to delete a named Virtual Circuit in an SDX-L2.
+ */
+@Command(scope = "sdxl2", name = "sdxl2vc-remove", description = "Removes a named Virtual Circuit")
+public class SdxL2RemoveVCCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "sdxl2vcname", description = "Name of SDX-L2 Virtual Circuit",
+            required = true, multiValued = false)
+    private String sdxL2VCname = null;
+
+    @Override
+    protected void execute() {
+        SdxL2Service sdxl2Service = get(SdxL2Service.class);
+        sdxl2Service.removeVC(sdxL2VCname);
+    }
+
+}
+
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2CPNameCompleter.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2CPNameCompleter.java
index 706c1e3..31bebb4 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2CPNameCompleter.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2CPNameCompleter.java
@@ -25,7 +25,7 @@
 import java.util.Optional;
 
 /**
- * Completes SDX-L2 connection point names.
+ * Completes name for SDX-L2 Connection Point.
  */
 public class SdxL2CPNameCompleter implements Completer {
 
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2NameCompleter.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2NameCompleter.java
index 50b4366..df31856 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2NameCompleter.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2NameCompleter.java
@@ -24,7 +24,7 @@
 import java.util.List;
 
 /**
- * Completes SDX-L2 names.
+ * Completes name for SDX-L2.
  */
 public class SdxL2NameCompleter implements Completer {
 
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2VCNameCompleter.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2VCNameCompleter.java
new file mode 100644
index 0000000..e61c33f
--- /dev/null
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/cli/completer/SdxL2VCNameCompleter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2.cli.completer;
+
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.sdxl2.SdxL2Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Completes name for SDX-L2 Virtual Circuit.
+ */
+public class SdxL2VCNameCompleter implements Completer {
+
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        SdxL2Service service = AbstractShellCommand.get(SdxL2Service.class);
+        delegate.getStrings().addAll(service.getVirtualCircuits(Optional.ofNullable(null)));
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/sdx-l2/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/sdx-l2/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 5d576d5..76b3572 100644
--- a/sdx-l2/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/sdx-l2/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -13,6 +13,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
+
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
 
     <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
@@ -42,15 +43,39 @@
             </completers>
         </command>
         <command>
+            <action class="org.onosproject.sdxl2.cli.SdxL2GetCPCommand"/>
+            <completers>
+                <ref component-id="sdxl2cpnameCompleter"/>
+            </completers>
+        </command>
+        <command>
             <action class="org.onosproject.sdxl2.cli.SdxL2ListCPCommand"/>
             <completers>
                 <ref component-id="sdxl2Completer"/>
             </completers>
         </command>
         <command>
-            <action class="org.onosproject.sdxl2.cli.SdxL2GetCPCommand"/>
+            <action class="org.onosproject.sdxl2.cli.SdxL2AddVCCommand"/>
             <completers>
-                <ref component-id="sdxl2cpnameCompleter"/>
+                <ref component-id="sdxl2vcnameCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.sdxl2.cli.SdxL2RemoveVCCommand"/>
+            <completers>
+                <ref component-id="sdxl2vcnameCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.sdxl2.cli.SdxL2GetVCCommand"/>
+            <completers>
+                <ref component-id="sdxl2vcnameCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.sdxl2.cli.SdxL2ListVCCommand"/>
+            <completers>
+                <ref component-id="sdxl2Completer"/>
             </completers>
         </command>
     </command-bundle>
@@ -58,5 +83,6 @@
     <bean id="sdxl2Completer" class="org.onosproject.sdxl2.cli.completer.SdxL2NameCompleter"/>
     <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
     <bean id="sdxl2cpnameCompleter" class="org.onosproject.sdxl2.cli.completer.SdxL2CPNameCompleter"/>
+    <bean id="sdxl2vcnameCompleter" class="org.onosproject.sdxl2.cli.completer.SdxL2VCNameCompleter"/>
 
 </blueprint>
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/IntentServiceTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/IntentServiceTest.java
new file mode 100644
index 0000000..a9711d3
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/IntentServiceTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import com.google.common.collect.Sets;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentServiceAdapter;
+import org.onosproject.net.intent.Key;
+
+import java.util.Set;
+
+/**
+ * Represents a fake IntentService class that easily allows to store and
+ * retrieve intents without implementing the IntentService logic.
+ */
+public class IntentServiceTest extends IntentServiceAdapter {
+
+    private Set<Intent> intents;
+
+    /**
+     * Defines a set of intents.
+     */
+    public IntentServiceTest() {
+        intents = Sets.newHashSet();
+    }
+
+    @Override
+    public void submit(Intent intent) {
+        intents.add(intent);
+    }
+
+    @Override
+    public long getIntentCount() {
+        return intents.size();
+    }
+
+    @Override
+    public Iterable<Intent> getIntents() {
+        return  Sets.newHashSet(intents.iterator());
+    }
+
+    @Override
+    public Intent getIntent(Key intentKey) {
+        for (Intent intent : intents) {
+            if (intent.key().equals(intentKey)) {
+                return intent;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void withdraw(Intent intent) {
+        intents.remove(intent);
+    }
+
+}
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MacVCManagerTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MacVCManagerTest.java
new file mode 100644
index 0000000..32865c7
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MacVCManagerTest.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+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.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentUtils;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+/**
+ * Unit tests for SDX-L2 Mac VC Manager.
+ */
+public class SdxL2MacVCManagerTest extends AbstractIntentTest {
+
+    private static final String SDXL2_2 = "sdxl2_test2";
+    private static final String CP1 = "of:00000000000001/1";
+    private static final String CP2 = "of:00000000000002/1";
+    private static final String CP5 = "of:00000000000002/4";
+    private static final String CP6 = "of:00000000000004/4";
+    private static final String CP7 = "of:0000000000000a/4";
+    private static final String CP8 = "of:00000000000009/4";
+    private static final String CP9 = "of:0000000000000a/4";
+    private static final String CP10 = "of:00000000000009/4";
+    private static final String VLANS1 = "2,3,4";
+    private static final ArrayList<String> VLANS1_ARRAY =
+            new ArrayList<String>(Arrays.asList(VLANS1.split(",")));
+    private static final String VLANS2 = "4,5,6";
+    private static final ArrayList<String> VLANS2_ARRAY =
+            new ArrayList<String>(Arrays.asList(VLANS2.split(",")));
+
+    private static final String VLANS5 = "100";
+    private static final String VLANS6 = "1";
+    private static final String VLANS7 = "1";
+    private static final String VLANS8 = "111";
+    private static final String VLANS9 = "1";
+    private static final String VLANS10 = "1";
+    private static final String CEMAC1 = "52:40:00:12:44:01";
+    private static final String CEMAC2 = "51:12:11:00:23:01";
+    private static final String CEMAC5 = "52:12:11:00:23:11";
+    private static final String CEMAC6 = "52:12:11:a0:23:11";
+    private static final String CEMAC7 = "52:12:21:00:25:11";
+    private static final String CEMAC8 = "52:12:14:a0:23:11";
+    private static final String CEMAC9 = "52:12:21:00:28:11";
+    private static final String CEMAC10 = "52:12:14:aa:23:11";
+    private static final String NAME_FORMAT = "%s:%s-%s";
+    private static final String KEY_FORMAT = "%s,%s";
+    private static final ApplicationId APPID = TestApplicationId.create("foo");
+    private static final int POINT_TO_POINT_INDEXES = 3;
+    private SdxL2MacVCManager manager;
+    private List<PointToPointIntent> intentList;
+
+    /**
+     * Prepare environment before starting testing MAC-based VCs.
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        SdxL2DistributedStore store = new SdxL2DistributedStore();
+        store.initForTest();
+        manager = new SdxL2MacVCManager(APPID, store, new IntentServiceTest());
+        intentList = setIntents();
+    }
+
+    /**
+     * Clean up environment after finishing testing MAC-based VCs.
+     */
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
+    public List<PointToPointIntent> setIntents() {
+        List<PointToPointIntent> intents = new ArrayList<PointToPointIntent>();
+        intents.addAll(setupConnectionPoints1To2());
+        intents.addAll(setupConnectionPoints5To6());
+        intents.addAll(setupConnectionPoints7To8());
+        intents.addAll(setupConnectionPoints9To10());
+        return intents;
+    }
+
+    private TrafficTreatment buildTreatment(VlanId setVlan,
+                                            VlanId pushVlan,
+                                            boolean popVlan) {
+
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        if (setVlan != null) {
+            treatmentBuilder.setVlanId(setVlan);
+        }
+        if (pushVlan != null) {
+            treatmentBuilder.pushVlan();
+            treatmentBuilder.setVlanId(pushVlan);
+        }
+        if (popVlan) {
+            treatmentBuilder.popVlan();
+        }
+        return treatmentBuilder.build();
+    }
+
+    private TrafficSelector buildSelector(MacAddress ingressMac,
+                                          MacAddress egressMac,
+                                          Short etherType,
+                                          VlanId ingressTag) {
+
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthSrc(ingressMac);
+        selectorBuilder.matchEthDst(egressMac);
+        if (etherType != null) {
+            selectorBuilder.matchEthType(etherType);
+        }
+        if (ingressTag != null) {
+            selectorBuilder.matchVlanId(ingressTag);
+        }
+        return selectorBuilder.build();
+    }
+
+    private Key generateIntentKey(String sdxl2, SdxL2ConnectionPoint cpOne, SdxL2ConnectionPoint cpTwo, String index) {
+        String cps = format(NAME_FORMAT, sdxl2, cpOne.name(), cpTwo.name());
+        String key = format(KEY_FORMAT, cps, index);
+        return Key.of(key, APPID);
+    }
+
+    @Test
+    public void testConnectionSetup() {
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        while (lhs.hasNext()) {
+            manager.addVC(SDXL2_2, lhs.next(), rhs.next());
+        }
+
+        assertEquals(intentList.size(), manager.intentService.getIntentCount());
+
+        for (Intent emulatedIntent : intentList) {
+            boolean found = false;
+            for (Intent realIntent : manager.intentService.getIntents()) {
+                if (emulatedIntent.key().equals(realIntent.key())) {
+                    found = true;
+                    assertTrue(format("Comparing %s and %s", emulatedIntent, realIntent),
+                               IntentUtils.intentsAreEqual(emulatedIntent, realIntent));
+                    break;
+                }
+            }
+            assertTrue(found);
+        }
+    }
+
+    public List<SdxL2ConnectionPoint> setupLhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        cps.add(cpone);
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5, CEMAC5);
+        cps.add(cpfive);
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7, CEMAC7);
+        cps.add(cpseven);
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9, CEMAC9);
+        cps.add(cpnine);
+        return cps;
+    }
+
+    public List<SdxL2ConnectionPoint> setupRhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        cps.add(cptwo);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6, CEMAC6);
+        cps.add(cpsix);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8, CEMAC8);
+        cps.add(cpeight);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10, CEMAC10);
+        cps.add(cpten);
+        return cps;
+    }
+
+    private List<PointToPointIntent> setupConnectionPoints(String keyIndex,
+                                                           SdxL2ConnectionPoint lhs, String lhsID,
+                                                           String lhsMac, String lhsVlan,
+                                                           TrafficTreatment lhsBuiltTreatment,
+                                                           SdxL2ConnectionPoint rhs, String rhsID,
+                                                           String rhsMac, String rhsVlan,
+                                                           TrafficTreatment rhsBuiltTreatment) {
+        List<PointToPointIntent> intents = new ArrayList<PointToPointIntent>();
+        VlanId lhsVlanValue = null, rhsVlanValue = null;
+        if (lhsVlan != null) {
+            lhsVlanValue = VlanId.vlanId(Short.parseShort(lhsVlan));
+        }
+        if (rhsVlan != null) {
+            rhsVlanValue = VlanId.vlanId(Short.parseShort(rhsVlan));
+        }
+
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, lhs, rhs, keyIndex))
+                            .selector(buildSelector(MacAddress.valueOf(lhsMac),
+                                                    MacAddress.valueOf(rhsMac),
+                                                    null, lhsVlanValue))
+                            .treatment(lhsBuiltTreatment)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(lhsID))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(rhsID))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, rhs, lhs, keyIndex))
+                            .selector(buildSelector(MacAddress.valueOf(rhsMac),
+                                                    MacAddress.valueOf(lhsMac),
+                                                    null, rhsVlanValue))
+                            .treatment(rhsBuiltTreatment)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(rhsID))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(lhsID))
+                            .priority(2000)
+                            .build());
+        return intents;
+    }
+
+    private List<PointToPointIntent> setupConnectionPoints1To2() {
+        List<PointToPointIntent> intents = new ArrayList<PointToPointIntent>();
+        String lhsID = CP1;
+        ArrayList<String> lhsVlan = VLANS1_ARRAY;
+        String lhsMac = CEMAC1;
+        String rhsID = CP2;
+        ArrayList<String> rhsVlan = VLANS2_ARRAY;
+        String rhsMac = CEMAC2;
+        SdxL2ConnectionPoint lhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint(
+                "TEST1", lhsID, VLANS1, lhsMac);
+        SdxL2ConnectionPoint rhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint(
+                "TEST2", rhsID, VLANS2, rhsMac);
+        TrafficTreatment lhsBuiltTreatment, rhsBuiltTreatment;
+
+        for (int i = 0; i < POINT_TO_POINT_INDEXES; i++) {
+            lhsBuiltTreatment = buildTreatment(VlanId.vlanId(rhsVlan.get(i)), null, false);
+            rhsBuiltTreatment = buildTreatment(VlanId.vlanId(lhsVlan.get(i)), null, false);
+            intents.addAll(setupConnectionPoints(Integer.toString(i + 1),
+                                    lhs, lhsID, lhsMac, lhsVlan.get(i), lhsBuiltTreatment,
+                                    rhs, rhsID, rhsMac, rhsVlan.get(i), rhsBuiltTreatment));
+        }
+        return intents;
+    }
+
+    private List<PointToPointIntent> setupConnectionPoints5To6() {
+        String lhsID = CP5;
+        String lhsVlan = VLANS5;
+        String lhsMac = CEMAC5;
+        SdxL2ConnectionPoint lhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", lhsID, lhsVlan, lhsMac);
+        String rhsID = CP6;
+        String rhsVlan = VLANS6;
+        String rhsMac = CEMAC6;
+        SdxL2ConnectionPoint rhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", rhsID, rhsVlan, rhsMac);
+        TrafficTreatment lhsBuiltTreatment =  buildTreatment(null, null, true);
+        TrafficTreatment rhsBuiltTreatment = buildTreatment(null, VlanId.vlanId(Short.parseShort(lhsVlan)), false);
+        return setupConnectionPoints("1", lhs, lhsID, lhsMac, lhsVlan, lhsBuiltTreatment,
+                                     rhs, rhsID, rhsMac, null, rhsBuiltTreatment);
+    }
+
+    private List<PointToPointIntent> setupConnectionPoints7To8() {
+        String lhsID = CP7;
+        String lhsVlan = VLANS7;
+        String lhsMac = CEMAC7;
+        SdxL2ConnectionPoint lhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", lhsID, lhsVlan, lhsMac);
+        String rhsID = CP8;
+        String rhsVlan = VLANS8;
+        String rhsMac = CEMAC8;
+        SdxL2ConnectionPoint rhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", rhsID, rhsVlan, rhsMac);
+        TrafficTreatment lhsBuiltTreatment = buildTreatment(null, VlanId.vlanId(Short.parseShort(rhsVlan)), false);
+        TrafficTreatment rhsBuiltTreatment = buildTreatment(null, null, true);
+        return setupConnectionPoints("1", lhs, lhsID, lhsMac, null, lhsBuiltTreatment,
+                                     rhs, rhsID, rhsMac, rhsVlan, rhsBuiltTreatment);
+    }
+
+    private List<PointToPointIntent> setupConnectionPoints9To10() {
+        String lhsID = CP9;
+        String lhsVlan = VLANS9;
+        String lhsMac = CEMAC9;
+        SdxL2ConnectionPoint lhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", lhsID, lhsVlan, lhsMac);
+        String rhsID = CP10;
+        String rhsVlan = VLANS10;
+        String rhsMac = CEMAC10;
+        SdxL2ConnectionPoint rhs = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", rhsID, rhsVlan, rhsMac);
+        TrafficTreatment nullTreatment = buildTreatment(null, null, false);
+        return setupConnectionPoints("1", lhs, lhsID, lhsMac, null, nullTreatment,
+                                     rhs, rhsID, rhsMac, null, nullTreatment);
+    }
+
+    @Test
+    public void removeConnection() {
+        testConnectionSetup();
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        removedIntents.addAll(setupConnectionPoints1To2());
+
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5, CEMAC5);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6, CEMAC6);
+        removedIntents.addAll(setupConnectionPoints5To6());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7, CEMAC7);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8, CEMAC8);
+        removedIntents.addAll(setupConnectionPoints7To8());
+
+        manager.removeVC(cpone, cptwo);
+        manager.removeVC(cpfive, cpsix);
+        manager.removeVC(cpseven, cpeight);
+
+        assertEquals(2, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+
+    @Test
+    public void testRemoveVCbyCP() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        removedIntents.addAll(setupConnectionPoints1To2());
+
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6, CEMAC6);
+        removedIntents.addAll(setupConnectionPoints5To6());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7, CEMAC7);
+        removedIntents.addAll(setupConnectionPoints7To8());
+
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10, CEMAC10);
+        removedIntents.addAll(setupConnectionPoints9To10());
+
+        manager.removeVC(cpone);
+        manager.removeVC(cpsix);
+        manager.removeVC(cpseven);
+        manager.removeVC(cpten);
+
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+
+        assertEquals(0, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+
+    @Test
+    public void testRemoveVCbySdx() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+
+        removedIntents.addAll(setupConnectionPoints1To2());
+        removedIntents.addAll(setupConnectionPoints5To6());
+        removedIntents.addAll(setupConnectionPoints7To8());
+        removedIntents.addAll(setupConnectionPoints9To10());
+        manager.removeVCs(SDXL2_2);
+
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.of(SDXL2_2)));
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+}
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2ManagerTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2ManagerTest.java
index 1b502b1..1017e72 100644
--- a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2ManagerTest.java
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2ManagerTest.java
@@ -19,23 +19,71 @@
 import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.onosproject.TestApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.MockIdGenerator;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Set;
 
+import static java.lang.String.format;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-
+import static org.junit.Assert.assertNull;
 
 /**
  * Tests SdxL2Manager functionality.
  */
 public class SdxL2ManagerTest {
 
+    public static final String SDXL2 = "test";
+    public static final String SDXL2_2 = "test2";
+    public static final String CP1 = "of:00000000000001/1";
+    public static final String CP2 = "of:00000000000002/1";
+    public static final String CP3 = "of:00000000000003/1";
+    public static final String CP4 = "of:00000000000003/2";
+    public static final String CP5 = "of:00000000000004/2";
+    public static final String VLANS1 = "1,2,3,4";
+    public static final String VLANS2 = "-1";
+    public static final String VLANS3 = "1,2,3";
+    public static final String VLANS4 = "2,2,2";
+    public static final String VLANS7 = "5";
+    public static final String VLANS8 = "3,2,1";
+    public static final String CEMAC1 = "52:40:00:12:44:01";
+    public static final String CEMAC2 = "52:44:00:12:44:01";
+    public static final String CEMAC3 = "54:40:00:12:44:01";
+    public static final String CEMAC4 = "52:40:00:12:42:01";
+    public static final String CEMAC5 = "52:40:00:10:44:01";
+    public static final String CEMAC6 = "52:40:00:12:46:01";
+    public static final String CP6 = "of:00000000000004/3";
+    public static final String CP7 = "of:00000000000004/3";
+    public static final String CP8 = "of:00000000000005/2";
+    public static final String VLANS6 = "1,2,3,4";
+    public static final String VLANS5 = "8,9,10";
+    public static final String CEMAC7 = "52:40:00:12:46:01";
+    public static final String CEMAC8 = "52:40:90:12:46:01";
+    @Rule
+    public ExpectedException exceptionAddVC1 = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionAddVC2 = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionRemoveVC1 = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionRemoveVC2 = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionSdxL2Name = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionDelSdxL2Name = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionGetVC2 = ExpectedException.none();
     protected SdxL2Manager manager;
+    protected IdGenerator idGenerator = new MockIdGenerator();
 
     @Before
     public void setUp() {
@@ -44,19 +92,19 @@
         SdxL2DistributedStore store = new SdxL2DistributedStore();
         store.initForTest();
         manager.sdxL2Store = store;
+        SdxL2MacVCManager vcManager = new SdxL2MacVCManager(
+                manager.appId, manager.sdxL2Store, new IntentServiceTest());
+        manager.vcManager = vcManager;
+        Intent.bindIdGenerator(idGenerator);
     }
 
     @After
     public void tearDown() {
+        Intent.unbindIdGenerator(idGenerator);
     }
 
-    public static final String SDXL2 = "test";
-    public static final String SDXL2_2 = "test2";
-
-
     @Test
     public void testCreateSdxL2s() {
-
         manager.createSdxL2(SDXL2);
         manager.createSdxL2(SDXL2_2);
         manager.createSdxL2(SDXL2);
@@ -85,23 +133,8 @@
         assertNotEquals(sdxl2, old);
     }
 
-    public static final String CP1 = "of:00000000000001/1";
-    public static final String CP2 = "of:00000000000002/1";
-    public static final String CP3 = "of:00000000000003/1";
-    public static final String CP4 = "of:00000000000003/2";
-    public static final String CP5 = "of:00000000000004/2";
-
-    public static final String VLANS1 = "1,2,3,4";
-    public static final String VLANS2 = "-1";
-    public static final String VLANS3 = "1,2,3";
-    public static final String VLANS4 = "2,2,2";
-    public static final String VLANS7 = "5";
-    public static final String VLANS8 = "3,2,1";
-
-    public static final String CEMAC1 = "52:40:00:12:44:01";
-
     @Test
-    public void testaddSdxL2ConnectionPoint() {
+    public void testAddSdxL2ConnectionPoint() {
 
         manager.createSdxL2(SDXL2);
         manager.createSdxL2(SDXL2_2);
@@ -125,12 +158,12 @@
         SdxL2ConnectionPoint ten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2, ten);
 
-        SdxL2ConnectionPoint fourteen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("RO1",
-                "of:0000000000000003/3", "1", "52:54:00:04:E5:9E");
+        SdxL2ConnectionPoint fourteen = SdxL2ConnectionPoint.
+                sdxl2ConnectionPoint("RO1", "of:0000000000000003/3", "1", "52:54:00:04:E5:9E");
         manager.addSdxL2ConnectionPoint("test1", fourteen);
 
-        SdxL2ConnectionPoint fifteen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("RO2",
-                "of:0000000000000009/3", "1", "52:54:00:68:F7:D9");
+        SdxL2ConnectionPoint fifteen = SdxL2ConnectionPoint.
+                sdxl2ConnectionPoint("RO2", "of:0000000000000009/3", "1", "52:54:00:68:F7:D9");
         manager.addSdxL2ConnectionPoint("test1", fifteen);
 
         SdxL2ConnectionPoint two = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP2, VLANS1, CEMAC1);
@@ -157,14 +190,14 @@
     }
 
     @Test
-    public void testgetSdxL2ConnectionPoints() {
+    public void testGetSdxL2ConnectionPoints() {
 
         manager.createSdxL2(SDXL2);
         manager.createSdxL2(SDXL2_2);
 
         Set<String> allExt = Sets.newHashSet();
         Set<String> allExtBySdxl2 = Sets.newHashSet();
-        Set<String> allExtBySdxl22 = Sets.newHashSet();
+        Set<String> allExtBySdxl2Aux = Sets.newHashSet();
 
         SdxL2ConnectionPoint one = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP1, VLANS1, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2, one);
@@ -177,7 +210,7 @@
         SdxL2ConnectionPoint six = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM3", CP1, VLANS7, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2_2, six);
         allExt.add(six.name());
-        allExtBySdxl22.add(six.name());
+        allExtBySdxl2Aux.add(six.name());
         SdxL2ConnectionPoint seven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("MI3", CP3, VLANS3, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2, seven);
         allExt.add(seven.name());
@@ -185,7 +218,7 @@
         SdxL2ConnectionPoint nine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP4, VLANS8, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2_2, nine);
         allExt.add(nine.name());
-        allExtBySdxl22.add(nine.name());
+        allExtBySdxl2Aux.add(nine.name());
         SdxL2ConnectionPoint ten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC1);
         manager.addSdxL2ConnectionPoint(SDXL2, ten);
         allExt.add(ten.name());
@@ -197,20 +230,20 @@
 
         assertEquals(allExt, all);
         assertNotEquals(allExtBySdxl2, all);
-        assertNotEquals(allExtBySdxl22, all);
+        assertNotEquals(allExtBySdxl2Aux, all);
 
         assertNotEquals(allExt, allBySdxl2);
         assertEquals(allExtBySdxl2, allBySdxl2);
-        assertNotEquals(allExtBySdxl22, allBySdxl2);
+        assertNotEquals(allExtBySdxl2Aux, allBySdxl2);
 
         assertNotEquals(allExt, allBySdxl22);
         assertNotEquals(allExtBySdxl2, allBySdxl22);
-        assertEquals(allExtBySdxl22, allBySdxl22);
+        assertEquals(allExtBySdxl2Aux, allBySdxl22);
 
     }
 
     @Test
-    public void testremoveSdxL2ConnectionPoint() {
+    public void testRemoveSdxL2ConnectionPoint() {
 
         manager.createSdxL2(SDXL2);
         manager.createSdxL2(SDXL2_2);
@@ -241,7 +274,50 @@
     }
 
     @Test
-    public void testgetSdxL2ConnectionPoint() {
+    public void test2RemoveSdxL2s() {
+        manager.createSdxL2(SDXL2);
+        manager.createSdxL2(SDXL2_2);
+
+        Set<String> sdxL2CPs = Sets.newHashSet();
+        Set<String> sdxl2CPsAux = Sets.newHashSet();
+
+        SdxL2ConnectionPoint one = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP1, VLANS1, CEMAC1);
+        sdxL2CPs.add(one.name());
+        manager.addSdxL2ConnectionPoint(SDXL2, one);
+
+        SdxL2ConnectionPoint three = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM2", CP2, VLANS2, CEMAC1);
+        sdxL2CPs.add(three.name());
+        manager.addSdxL2ConnectionPoint(SDXL2, three);
+
+        SdxL2ConnectionPoint six = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM3", CP1, VLANS7, CEMAC1);
+        sdxl2CPsAux.add(six.name());
+        manager.addSdxL2ConnectionPoint(SDXL2_2, six);
+
+        SdxL2ConnectionPoint seven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("MI3", CP3, VLANS3, CEMAC1);
+        sdxL2CPs.add(seven.name());
+        manager.addSdxL2ConnectionPoint(SDXL2, seven);
+
+        SdxL2ConnectionPoint nine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP4, VLANS8, CEMAC1);
+        sdxl2CPsAux.add(nine.name());
+        manager.addSdxL2ConnectionPoint(SDXL2_2, nine);
+
+        SdxL2ConnectionPoint ten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC1);
+        sdxL2CPs.add(ten.name());
+        manager.addSdxL2ConnectionPoint(SDXL2, ten);
+
+        manager.deleteSdxL2(SDXL2);
+
+        assertEquals(sdxl2CPsAux, this.manager.getSdxL2ConnectionPoints(Optional.of(SDXL2_2)));
+        assertEquals(sdxl2CPsAux, this.manager.getSdxL2ConnectionPoints(Optional.ofNullable(null)));
+        manager.deleteSdxL2(SDXL2_2);
+
+        assertEquals(Collections.emptySet(), this.manager.getSdxL2ConnectionPoints(Optional.of(SDXL2)));
+        assertEquals(Collections.emptySet(), this.manager.getSdxL2ConnectionPoints(Optional.of(SDXL2_2)));
+
+    }
+
+    @Test
+    public void testGetSdxL2ConnectionPoint() {
 
         manager.createSdxL2(SDXL2);
         manager.createSdxL2(SDXL2_2);
@@ -284,4 +360,240 @@
 
     }
 
+    @Test
+    public void testAddVCChecks() {
+
+        manager.createSdxL2(SDXL2);
+        manager.createSdxL2(SDXL2_2);
+
+        SdxL2ConnectionPoint one = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint two = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM2", CP2, VLANS2, CEMAC2);
+        SdxL2ConnectionPoint three = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM3", CP1, VLANS7, CEMAC3);
+        SdxL2ConnectionPoint four = SdxL2ConnectionPoint.sdxl2ConnectionPoint("MI3", CP3, VLANS3, CEMAC4);
+        SdxL2ConnectionPoint five = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP4, VLANS8, CEMAC5);
+        SdxL2ConnectionPoint six = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC6);
+        SdxL2ConnectionPoint seven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI23", CP6, VLANS6, CEMAC7);
+        SdxL2ConnectionPoint eight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI24", CP7, VLANS5, CEMAC8);
+        SdxL2ConnectionPoint nine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI25", CP8, VLANS5, CEMAC8);
+
+        manager.addSdxL2ConnectionPoint(SDXL2, one);
+        manager.addSdxL2ConnectionPoint(SDXL2, two);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, three);
+        manager.addSdxL2ConnectionPoint(SDXL2, four);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, five);
+        manager.addSdxL2ConnectionPoint(SDXL2, six);
+        manager.addSdxL2ConnectionPoint(SDXL2, seven);
+        manager.addSdxL2ConnectionPoint(SDXL2, eight);
+        manager.addSdxL2ConnectionPoint(SDXL2, nine);
+
+        manager.addVC(SDXL2, two.name(), six.name());
+        manager.addVC(SDXL2, seven.name(), nine.name());
+        manager.addVC(SDXL2, one.name(), two.name());
+        manager.addVC(SDXL2, one.name(), four.name());
+        manager.addVC(SDXL2, one.name(), six.name());
+        manager.addVC(SDXL2, two.name(), four.name());
+        manager.addVC(SDXL2, seven.name(), eight.name());
+
+        exceptionAddVC2.expect(IllegalStateException.class);
+        manager.addVC(SDXL2, four.name() + "x", five.name());
+        manager.addVC(SDXL2, one.name(), three.name());
+        manager.addVC(SDXL2, one.name(), five.name());
+        manager.addVC(SDXL2, two.name(), three.name());
+        manager.addVC(SDXL2, two.name(), five.name());
+        manager.addVC(SDXL2, three.name(), four.name());
+        manager.addVC(SDXL2, three.name(), five.name());
+        manager.addVC(SDXL2, three.name(), six.name());
+        manager.addVC(SDXL2, four.name(), five.name());
+    }
+
+    @Test
+    public void testRemoveVCChecks() {
+
+        manager.createSdxL2(SDXL2);
+        manager.createSdxL2(SDXL2_2);
+
+        SdxL2ConnectionPoint one = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint two = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM2", CP2, VLANS2, CEMAC2);
+        SdxL2ConnectionPoint three = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM3", CP1, VLANS7, CEMAC3);
+        SdxL2ConnectionPoint four = SdxL2ConnectionPoint.sdxl2ConnectionPoint("MI3", CP3, VLANS3, CEMAC4);
+        SdxL2ConnectionPoint five = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP4, VLANS8, CEMAC5);
+        SdxL2ConnectionPoint six = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC6);
+        SdxL2ConnectionPoint seven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI23", CP6, VLANS6, CEMAC7);
+        SdxL2ConnectionPoint eight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI24", CP7, VLANS5, CEMAC8);
+        SdxL2ConnectionPoint nine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI25", CP8, VLANS5, CEMAC8);
+
+        manager.addSdxL2ConnectionPoint(SDXL2, one);
+        manager.addSdxL2ConnectionPoint(SDXL2, two);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, three);
+        manager.addSdxL2ConnectionPoint(SDXL2, four);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, five);
+        manager.addSdxL2ConnectionPoint(SDXL2, six);
+        manager.addSdxL2ConnectionPoint(SDXL2, seven);
+        manager.addSdxL2ConnectionPoint(SDXL2, eight);
+        manager.addSdxL2ConnectionPoint(SDXL2, nine);
+
+        manager.addVC(SDXL2, two.name(), six.name());
+        manager.addVC(SDXL2, seven.name(), nine.name());
+
+        String vc;
+        vc = two.name().compareTo(six.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), six.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, six.name(), two.name());
+        manager.removeVC(vc);
+
+        vc = seven.name().compareTo(nine.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, seven.name(), nine.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, seven.name(), nine.name());
+        manager.removeVC(vc);
+
+        vc = one.name().compareTo(four.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), four.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, four.name(), one.name());
+        manager.removeVC(vc);
+        vc = one.name().compareTo(five.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), five.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, five.name(), one.name());
+        manager.removeVC(vc);
+        vc = one.name().compareTo(six.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), six.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, six.name(), one.name());
+        manager.removeVC(vc);
+        vc = two.name().compareTo(three.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), three.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, three.name(), two.name());
+        manager.removeVC(vc);
+        vc = two.name().compareTo(four.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), four.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, four.name(), two.name());
+        manager.removeVC(vc);
+        vc = two.name().compareTo(five.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), five.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, five.name(), two.name());
+        manager.removeVC(vc);
+        vc = three.name().compareTo(four.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, three.name(), four.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, four.name(), three.name());
+        manager.removeVC(vc);
+        vc = three.name().compareTo(five.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, three.name(), five.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, five.name(), three.name());
+        manager.removeVC(vc);
+        vc = three.name().compareTo(six.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, three.name(), six.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, six.name(), three.name());
+        manager.removeVC(vc);
+        vc = four.name().compareTo(five.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, four.name(), five.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, five.name(), four.name());
+        manager.removeVC(vc);
+        vc = seven.name().compareTo(eight.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, seven.name(), eight.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, eight.name(), seven.name());
+        manager.removeVC(vc);
+        vc = seven.name().compareTo(nine.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2_2, seven.name(), nine.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, seven.name(), nine.name());
+        manager.removeVC(vc);
+        vc = seven.name().compareTo(nine.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2 + "x", seven.name(), nine.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, seven.name(), nine.name());
+        manager.removeVC(vc);
+
+        exceptionRemoveVC1.expect(IllegalStateException.class);
+        vc = one.name().compareTo(three.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), three.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, three.name(), one.name());
+        manager.removeVC(vc);
+        manager.removeVC(":A");
+        manager.removeVC("A:B");
+
+        vc = four.name().compareTo(five.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, four.name() + "x", five.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, five.name(), four.name() + "x");
+        manager.removeVC(vc);
+
+        vc = one.name().compareTo(two.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), two.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), one.name());
+        manager.removeVC(vc);
+    }
+
+    @Test
+    public void testSdxL2NameChecks() {
+        String sdxL2 = "";
+        String sdxL2Aux = "test3,4";
+
+        exceptionSdxL2Name.expect(NullPointerException.class);
+        exceptionSdxL2Name.expectMessage("name cannot be null");
+        manager.createSdxL2(null);
+
+        manager.createSdxL2(sdxL2);
+
+        exceptionSdxL2Name.expect(IllegalStateException.class);
+        exceptionSdxL2Name.expectMessage("names cannot contain commas");
+        manager.createSdxL2(sdxL2Aux);
+    }
+
+    @Test
+    public void testDeleteSdxL2NameChecks() {
+        String sdxL2 = "";
+        exceptionDelSdxL2Name.expect(NullPointerException.class);
+        exceptionDelSdxL2Name.expectMessage("name cannot be null");
+        manager.deleteSdxL2(null);
+        manager.createSdxL2(sdxL2);
+        manager.deleteSdxL2(sdxL2);
+    }
+
+    @Test
+    public void testGetVC() {
+        manager.createSdxL2(SDXL2);
+        manager.createSdxL2(SDXL2_2);
+
+        SdxL2ConnectionPoint one = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint two = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM2", CP2, VLANS2, CEMAC2);
+        SdxL2ConnectionPoint three = SdxL2ConnectionPoint.sdxl2ConnectionPoint("ROM3", CP1, VLANS7, CEMAC3);
+        SdxL2ConnectionPoint four = SdxL2ConnectionPoint.sdxl2ConnectionPoint("MI3", CP3, VLANS3, CEMAC4);
+        SdxL2ConnectionPoint five = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP4, VLANS8, CEMAC5);
+        SdxL2ConnectionPoint six = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP5, VLANS2, CEMAC6);
+        SdxL2ConnectionPoint seven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI23", CP6, VLANS6, CEMAC7);
+        SdxL2ConnectionPoint eight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI24", CP7, VLANS5, CEMAC8);
+        SdxL2ConnectionPoint nine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI25", CP8, VLANS5, CEMAC8);
+
+        String vc;
+        VirtualCircuit expectedVC;
+        VirtualCircuit actualVC;
+
+        manager.addSdxL2ConnectionPoint(SDXL2, one);
+        manager.addSdxL2ConnectionPoint(SDXL2, two);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, three);
+        manager.addSdxL2ConnectionPoint(SDXL2, four);
+        manager.addSdxL2ConnectionPoint(SDXL2_2, five);
+        manager.addSdxL2ConnectionPoint(SDXL2, six);
+        manager.addSdxL2ConnectionPoint(SDXL2, seven);
+        manager.addSdxL2ConnectionPoint(SDXL2, eight);
+        manager.addSdxL2ConnectionPoint(SDXL2, nine);
+
+        // VC created using the manager, check against manually generates
+        manager.addVC(SDXL2, two.name(), six.name());
+        vc = two.name().compareTo(six.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), six.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, six.name(), two.name());
+        expectedVC = new VirtualCircuit(two, six);
+        actualVC = manager.getVirtualCircuit(vc);
+        assertEquals(expectedVC, actualVC);
+
+        // VC not created, check that getVC returns null if VC does not exist
+        vc = one.name().compareTo(two.name().toString()) < 0 ?
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, one.name(), two.name()) :
+                format(SdxL2VCManager.NAME_FORMAT, SDXL2, two.name(), one.name());
+        expectedVC = new VirtualCircuit(one, two);
+        actualVC = manager.getVirtualCircuit(vc);
+        assertNotEquals(expectedVC, actualVC);
+        assertNull(actualVC);
+
+        // Testing illegal character
+        exceptionGetVC2.expect(IllegalStateException.class);
+        manager.getVirtualCircuit(":A");
+        manager.getVirtualCircuit("A:B");
+    }
 }
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MplsVCManagerTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MplsVCManagerTest.java
new file mode 100644
index 0000000..914678b
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2MplsVCManagerTest.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+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.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentUtils;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Optional;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests for SDX-L2 MPLS VC Manager.
+ */
+public class SdxL2MplsVCManagerTest extends AbstractIntentTest {
+
+    private static final String SDXL2_2 = "sdxl2_test2";
+    private static final String CP1 = "of:00000000000001/1";
+    private static final String CP2 = "of:00000000000002/1";
+    private static final String CP5 = "of:00000000000002/4";
+    private static final String CP6 = "of:00000000000004/4";
+    private static final String CP7 = "of:0000000000000a/4";
+    private static final String CP8 = "of:00000000000009/4";
+    private static final String CP9 = "of:0000000000000a/4";
+    private static final String CP10 = "of:00000000000009/4";
+    private static final String VLANS1 = "2,3,4";
+    private static final String VLANS2 = "4,5,6";
+    private static final String VLANS5 = "100";
+    private static final String VLANS6 = "1";
+    private static final String VLANS7 = "1";
+    private static final String VLANS8 = "111";
+    private static final String VLANS9 = "1";
+    private static final String VLANS10 = "1";
+    private static final String NAME_FORMAT = "%s:%s-%s";
+    private static final String KEY_FORMAT = "%s,%s";
+    private static final ApplicationId APPID = TestApplicationId.create("foo");
+    private SdxL2MplsVCManager manager;
+    private List<PointToPointIntent> intentList;
+
+    /**
+     * Prepare environment before starting testing MPLS-based VCs.
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        SdxL2DistributedStore store = new SdxL2DistributedStore();
+        store.initForTest();
+        manager = new SdxL2MplsVCManager(APPID, store, new IntentServiceTest());
+        intentList = setIntents();
+    }
+
+    /**
+     * Clean up environment after finishing testing MPLS-based VCs.
+     */
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
+    private List<PointToPointIntent> setIntents() {
+        List<PointToPointIntent> intents = new ArrayList<PointToPointIntent>();
+        List<Constraint> encapsulation = buildConstraints();
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "2"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "2"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "3"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "3"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                            .priority(2000)
+                            .build());
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpFive, cpSix, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                            .treatment(buildTreatment(null, null, true))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpSix, cpFive, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                            .priority(2000)
+                            .build());
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpSeven, cpEight, "1"))
+                            .selector(buildSelector(null, null))
+                            .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpEight, cpSeven, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, true))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                            .priority(2000)
+                            .build());
+
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpNine, cpTen, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpTen, cpNine, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                            .priority(2000)
+                            .build());
+
+        return intents;
+    }
+
+    private TrafficTreatment buildTreatment(VlanId setVlan,
+                                            VlanId pushVlan,
+                                            boolean popVlan) {
+
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        if (setVlan != null) {
+            treatmentBuilder.setVlanId(setVlan);
+        }
+        if (pushVlan != null) {
+            treatmentBuilder.pushVlan();
+            treatmentBuilder.setVlanId(pushVlan);
+        }
+        if (popVlan) {
+            treatmentBuilder.popVlan();
+        }
+        return treatmentBuilder.build();
+    }
+
+    private TrafficSelector buildSelector(Short ethertype,
+                                          VlanId ingresstag) {
+
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        if (ethertype != null) {
+            selectorBuilder.matchEthType(ethertype);
+        }
+        if (ingresstag != null) {
+            selectorBuilder.matchVlanId(ingresstag);
+        }
+        return selectorBuilder.build();
+    }
+
+    private List<Constraint> buildConstraints() {
+        final List<Constraint> constraints = new LinkedList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.MPLS));
+        return constraints;
+    }
+
+    private Key generateIntentKey(String sdxl2, SdxL2ConnectionPoint cpOne,
+                                  SdxL2ConnectionPoint cpTwo, String index) {
+        String cps = format(NAME_FORMAT, sdxl2, cpOne.name(), cpTwo.name());
+        String key = format(KEY_FORMAT, cps, index);
+        return Key.of(key, APPID);
+    }
+
+    @Test
+    public void testConnectionSetup() {
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        while (lhs.hasNext()) {
+            manager.addVC(SDXL2_2, lhs.next(), rhs.next());
+        }
+
+        assertEquals(intentList.size(), manager.intentService.getIntentCount());
+
+        for (Intent emulatedIntent : intentList) {
+            boolean found = false;
+            for (Intent realIntent : manager.intentService.getIntents()) {
+                if (emulatedIntent.key().equals(realIntent.key())) {
+                    found = true;
+                    assertTrue(format("Comparing %s and %s", emulatedIntent, realIntent),
+                               IntentUtils.intentsAreEqual(emulatedIntent, realIntent));
+                    break;
+                }
+            }
+            assertTrue(found);
+        }
+
+    }
+
+    private List<SdxL2ConnectionPoint> setupLhsCPs() {
+
+        List<SdxL2ConnectionPoint> cps = new ArrayList<>();
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        cps.add(cpOne);
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        cps.add(cpFive);
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        cps.add(cpSeven);
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        cps.add(cpNine);
+
+        return cps;
+    }
+
+    private List<SdxL2ConnectionPoint> setupRhsCPs() {
+
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+        cps.add(cpTwo);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        cps.add(cpSix);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        cps.add(cpEight);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        cps.add(cpTen);
+
+        return cps;
+    }
+
+
+    @Test
+    public void removeConnection() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<>();
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpFive, cpSix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSix, cpFive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSeven, cpEight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpEight, cpSeven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+        manager.removeVC(cpOne, cpTwo);
+        manager.removeVC(cpFive, cpSix);
+        manager.removeVC(cpSeven, cpEight);
+
+        assertEquals(2, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+    }
+
+
+    @Test
+    public void testremoveVCbyCP() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpFive, cpSix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSix, cpFive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSeven, cpEight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpEight, cpSeven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpNine, cpTen, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTen, cpNine, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .priority(2000)
+                                    .build());
+
+
+        manager.removeVC(cpOne);
+        manager.removeVC(cpSix);
+        manager.removeVC(cpSeven);
+        manager.removeVC(cpTen);
+
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+
+        assertEquals(0, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+
+    @Test
+    public void testremoveVCbySdx() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<>();
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpOne, cpTwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTwo, cpOne, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpFive, cpSix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSix, cpFive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpSeven, cpEight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpEight, cpSeven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpNine, cpTen, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpTen, cpNine, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .priority(2000)
+                                    .build());
+
+        manager.removeVCs(SDXL2_2);
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.of(SDXL2_2)));
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+    }
+}
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VCManagerTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VCManagerTest.java
new file mode 100644
index 0000000..26323fb
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VCManagerTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+
+public class SdxL2VCManagerTest {
+
+    private static final String SDXL2_1 = "sdxl2_test1";
+    private static final String CP1 = "of:00000000000001/1";
+    private static final String CP2 = "of:00000000000002/1";
+    private static final String VLANS1 = "2,3,4";
+    private static final String VLANS2 = "4,5,6";
+    private static final String CEMAC1 = "52:40:00:12:44:01";
+    private static final String CEMAC2 = "51:12:11:00:23:01";
+    private static final String CP3 = "of:00000000000002/2";
+    private static final String VLANS3 = "8,9,10";
+    private static final String CEMAC3 = "52:12:11:00:23:01";
+    private static final String SDXL2_2 = "sdxl2_test2";
+    private static final String CP5 = "of:00000000000002/4";
+    private static final String VLANS5 = "100";
+    private static final String CEMAC5 = "52:12:11:00:23:11";
+    private static final String CP6 = "of:00000000000004/4";
+    private static final String VLANS6 = "1";
+    private static final String CEMAC6 = "52:12:11:a0:23:11";
+    private static final String CP7 = "of:0000000000000a/4";
+    private static final String VLANS7 = "1";
+    private static final String CEMAC7 = "52:12:21:00:25:11";
+    private static final String CP8 = "of:00000000000009/4";
+    private static final String VLANS8 = "111";
+    private static final String CEMAC8 = "52:12:14:a0:23:11";
+    private static final String CP9 = "of:0000000000000a/4";
+    private static final String VLANS9 = "1";
+    private static final String CEMAC9 = "52:12:21:00:28:11";
+    private static final String CP10 = "of:00000000000009/4";
+    private static final String VLANS10 = "1";
+    private static final String CEMAC10 = "52:12:14:aa:23:11";
+    private static final ApplicationId APPID = TestApplicationId.create("foo");
+    @Rule
+    public ExpectedException exceptionAddVC = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionRemoveVC = ExpectedException.none();
+    @Rule
+    public ExpectedException exceptionGetVC = ExpectedException.none();
+    private SdxL2MacVCManager manager;
+    private IdGenerator idGenerator = new MockIdGenerator();
+
+    /**
+     * Prepare environment before starting testing VCs.
+     */
+    @Before
+    public void setUp() {
+        SdxL2DistributedStore store = new SdxL2DistributedStore();
+        store.initForTest();
+        manager = new SdxL2MacVCManager(
+                APPID, store, new IntentServiceTest());
+        Intent.bindIdGenerator(idGenerator);
+    }
+
+    /**
+     * Clean up environment after finishing testing VCs.
+     */
+    @After
+    public void tearDown() {
+        Intent.unbindIdGenerator(idGenerator);
+    }
+
+    @Test
+    public void testgenerateKey() {
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpOneAux = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC1);
+
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC1);
+        SdxL2ConnectionPoint cpTwoAux = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+
+        Key key1 = manager.generateIntentKey(SDXL2_1, cpOne, cpTwo, "1");
+        Key key2 = manager.generateIntentKey(SDXL2_1, cpOneAux, cpTwoAux, "1");
+        assertNotEquals(key1, key2);
+
+        Key key3 = manager.generateIntentKey(SDXL2_1, cpOne, cpTwoAux, "1");
+        Key key4 = manager.generateIntentKey(SDXL2_1, cpOneAux, cpTwo, "1");
+        assertNotEquals(key3, key4);
+    }
+
+    @Test
+    public void testAddVCChecks() {
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        manager.addVC(SDXL2_1, cpFive, cpSix);
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        manager.addVC(SDXL2_1, cpSeven, cpEight);
+
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST3", CP3, VLANS3, CEMAC3);
+        manager.addVC(SDXL2_1, cpNine, cpTen);
+
+        exceptionAddVC.expect(IllegalStateException.class);
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC1);
+        manager.addVC(SDXL2_1, cpOne, cpTwo);
+    }
+
+    @Test
+    public void testremoveVCChecks() {
+        SdxL2ConnectionPoint cpOne = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpTwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC1);
+
+        SdxL2ConnectionPoint cpFive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpSix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+
+        SdxL2ConnectionPoint cpSeven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        SdxL2ConnectionPoint cpEight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+
+        SdxL2ConnectionPoint cpNine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpTen = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST3", CP3, VLANS3, CEMAC3);
+
+        manager.addVC(SDXL2_1, cpFive, cpSix);
+        manager.removeVC(cpFive, cpSix);
+        manager.removeVC(cpSeven, cpEight);
+        manager.removeVC(cpNine, cpTen);
+
+        exceptionRemoveVC.expect(IllegalStateException.class);
+        manager.removeVC(cpOne, cpTwo);
+    }
+
+    @Test
+    public void testGetVC() {
+        connectionSetup();
+
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        String vc;
+        SdxL2ConnectionPoint one;
+        SdxL2ConnectionPoint two;
+        while (lhs.hasNext()) {
+            one = lhs.next();
+            two = rhs.next();
+            vc = one.toString().compareTo(two.toString()) < 0 ?
+                    format(SdxL2VCManager.SDXL2_CPS_FORMAT, one, two) :
+                    format(SdxL2VCManager.SDXL2_CPS_FORMAT, two, one);
+            assertEquals(vc, manager.getVC(one, two));
+        }
+
+        SdxL2ConnectionPoint cpLeft = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint cpRight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP3, VLANS3, CEMAC1);
+
+        // This VC has not been created before
+        vc = cpLeft.toString().compareTo(cpRight.toString()) < 0 ?
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, cpLeft, cpRight) :
+                format(SdxL2VCManager.SDXL2_CPS_FORMAT, cpRight, cpLeft);
+
+        assertNull(manager.getVC(cpLeft, cpRight));
+    }
+
+    @Test
+    public void testgetVCs() {
+        connectionSetup();
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        Set<String> expectedVCs = Sets.newHashSet();
+        String vc;
+        String lhsName;
+        String rhsName;
+        while (lhs.hasNext()) {
+            lhsName = lhs.next().name();
+            rhsName = rhs.next().name();
+            vc = lhsName.compareTo(rhsName.toString()) < 0 ?
+                    format(SdxL2VCManager.NAME_FORMAT, SDXL2_2, lhsName, rhsName) :
+                    format(SdxL2VCManager.NAME_FORMAT, SDXL2_2, rhsName, lhsName);
+            expectedVCs.add(vc);
+        }
+        Set<String> vcs = manager.getVCs(Optional.of(SDXL2_2));
+        assertEquals(expectedVCs, vcs);
+        vcs = manager.getVCs(Optional.of(SDXL2_1));
+        assertEquals(Collections.emptySet(), vcs);
+        vcs = manager.getVCs(Optional.ofNullable(null));
+        assertEquals(expectedVCs, vcs);
+    }
+
+    public List<SdxL2ConnectionPoint> setupLhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1, CEMAC1);
+        cps.add(cpone);
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5, CEMAC5);
+        cps.add(cpfive);
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7, CEMAC7);
+        cps.add(cpseven);
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9, CEMAC9);
+        cps.add(cpnine);
+        return cps;
+    }
+
+    public List<SdxL2ConnectionPoint> setupRhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2, CEMAC2);
+        cps.add(cptwo);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6, CEMAC6);
+        cps.add(cpsix);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8, CEMAC8);
+        cps.add(cpeight);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10, CEMAC10);
+        cps.add(cpten);
+        return cps;
+    }
+
+    private void connectionSetup() {
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        while (lhs.hasNext()) {
+            manager.addVC(SDXL2_2, lhs.next(), rhs.next());
+        }
+    }
+}
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VlanVCManagerTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VlanVCManagerTest.java
new file mode 100644
index 0000000..e6dd921
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/SdxL2VlanVCManagerTest.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+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.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentUtils;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests for SdxL2VlanVCManager.
+ */
+public class SdxL2VlanVCManagerTest extends AbstractIntentTest {
+
+    private static final String SDXL2_2 = "sdxl2_test2";
+    private static final String CP1 = "of:00000000000001/1";
+    private static final String CP2 = "of:00000000000002/1";
+    private static final String CP5 = "of:00000000000002/4";
+    private static final String CP6 = "of:00000000000004/4";
+    private static final String CP7 = "of:0000000000000a/4";
+    private static final String CP8 = "of:00000000000009/4";
+    private static final String CP9 = "of:0000000000000a/4";
+    private static final String CP10 = "of:00000000000009/4";
+    private static final String VLANS1 = "2,3,4";
+    private static final ArrayList<String> VLANS1_ARRAY =
+            new ArrayList<String>(Arrays.asList(VLANS1.split(",")));;
+    private static final String VLANS2 = "4,5,6";
+    private static final ArrayList<String> VLANS2_ARRAY =
+            new ArrayList<String>(Arrays.asList(VLANS2.split(",")));;
+    private static final String VLANS5 = "100";
+    private static final String VLANS6 = "1";
+    private static final String VLANS7 = "1";
+    private static final String VLANS8 = "111";
+    private static final String VLANS9 = "1";
+    private static final String VLANS10 = "1";
+    private static final String NAME_FORMAT = "%s:%s-%s";
+    private static final String KEY_FORMAT = "%s,%s";
+    private static final ApplicationId APPID = TestApplicationId.create("foo");
+    private static final int POINT_TO_POINT_INDEXES = 3;
+    private SdxL2VlanVCManager manager;
+    private List<PointToPointIntent> intentList;
+
+    /**
+     * Prepare environment before starting testing VLAN-based VCs.
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        SdxL2DistributedStore store = new SdxL2DistributedStore();
+        store.initForTest();
+        manager = new SdxL2VlanVCManager(
+                APPID, store, new IntentServiceTest());
+        intentList = setIntents();
+    }
+
+    /**
+     * Clean up environment after finishing testing VLAN-based VCs.
+     */
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
+    public List<PointToPointIntent> setIntents() {
+        List<PointToPointIntent> intents = new ArrayList<PointToPointIntent>();
+        List<Constraint> encapsulation = buildConstraints();
+
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+        for (int i = 0; i < POINT_TO_POINT_INDEXES; i++) {
+            intents.add(PointToPointIntent.builder()
+                                .appId(APPID)
+                                .key(generateIntentKey(SDXL2_2, cpone, cptwo, Integer.toString(i + 1))) // 1
+                                .selector(buildSelector(null, VlanId.vlanId(Short.parseShort(VLANS1_ARRAY.get(i)))))
+                                .treatment(buildTreatment(
+                                        VlanId.vlanId(Short.parseShort(VLANS2_ARRAY.get(i))), null, false))
+                                .constraints(encapsulation)
+                                .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                .priority(2000)
+                                .build());
+            intents.add(PointToPointIntent.builder()
+                                .appId(APPID)
+                                .key(generateIntentKey(SDXL2_2, cptwo, cpone, Integer.toString(i + 1)))
+                                .selector(buildSelector(null, VlanId.vlanId(Short.parseShort(VLANS2_ARRAY.get(i)))))
+                                .treatment(buildTreatment(
+                                        VlanId.vlanId(Short.parseShort(VLANS1_ARRAY.get(i))), null, false))
+                                .constraints(encapsulation)
+                                .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                .priority(2000)
+                                .build());
+        }
+
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpfive, cpsix, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                            .treatment(buildTreatment(null, null, true))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpsix, cpfive, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                            .priority(2000)
+                            .build());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpseven, cpeight, "1"))
+                            .selector(buildSelector(null, null))
+                            .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                            .constraints(encapsulation)
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpeight, cpseven, "1"))
+                            .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, true))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                            .priority(2000)
+                            .build());
+
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpnine, cpten, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                            .priority(2000)
+                            .build());
+        intents.add(PointToPointIntent.builder()
+                            .appId(APPID)
+                            .key(generateIntentKey(SDXL2_2, cpten, cpnine, "1"))
+                            .selector(buildSelector(null, null))
+                            .constraints(encapsulation)
+                            .treatment(buildTreatment(null, null, false))
+                            .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                            .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                            .priority(2000)
+                            .build());
+
+        return intents;
+    }
+
+    private TrafficTreatment buildTreatment(VlanId setVlan,
+                                            VlanId pushVlan,
+                                            boolean popVlan) {
+
+        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+        if (setVlan != null) {
+            treatmentBuilder.setVlanId(setVlan);
+        }
+        if (pushVlan != null) {
+            treatmentBuilder.pushVlan();
+            treatmentBuilder.setVlanId(pushVlan);
+        }
+        if (popVlan) {
+            treatmentBuilder.popVlan();
+        }
+        return treatmentBuilder.build();
+    }
+
+    private TrafficSelector buildSelector(Short ethertype,
+                                          VlanId ingresstag) {
+
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        if (ethertype != null) {
+            selectorBuilder.matchEthType(ethertype);
+        }
+        if (ingresstag != null) {
+            selectorBuilder.matchVlanId(ingresstag);
+        }
+        return selectorBuilder.build();
+    }
+
+    protected List<Constraint> buildConstraints() {
+        final List<Constraint> constraints = new LinkedList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+        return constraints;
+    }
+
+    private Key generateIntentKey(String sdxl2, SdxL2ConnectionPoint cpone, SdxL2ConnectionPoint cptwo, String index) {
+        String cps = format(NAME_FORMAT, sdxl2, cpone.name(), cptwo.name());
+        String key = format(KEY_FORMAT, cps, index);
+        return Key.of(key, APPID);
+    }
+
+    @Test
+    public void testConnectionSetup() {
+        Iterator<SdxL2ConnectionPoint> lhs = setupLhsCPs().iterator();
+        Iterator<SdxL2ConnectionPoint> rhs = setupRhsCPs().iterator();
+        while (lhs.hasNext() && rhs.hasNext()) {
+            manager.addVC(SDXL2_2, lhs.next(), rhs.next());
+        }
+
+        assertEquals(intentList.size(), manager.intentService.getIntentCount());
+
+        for (Intent emulatedIntent : intentList) {
+            boolean found = false;
+            for (Intent realIntent : manager.intentService.getIntents()) {
+                if (emulatedIntent.key().equals(realIntent.key())) {
+                    found = true;
+                    assertTrue(format("Comparing %s and %s", emulatedIntent, realIntent),
+                               IntentUtils.intentsAreEqual(emulatedIntent, realIntent));
+                    break;
+                }
+            }
+            assertTrue(found);
+        }
+    }
+
+    public List<SdxL2ConnectionPoint> setupLhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        cps.add(cpone);
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        cps.add(cpfive);
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        cps.add(cpseven);
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        cps.add(cpnine);
+        return cps;
+    }
+
+    public List<SdxL2ConnectionPoint> setupRhsCPs() {
+        List<SdxL2ConnectionPoint> cps = new ArrayList<SdxL2ConnectionPoint>();
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+        cps.add(cptwo);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        cps.add(cpsix);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        cps.add(cpeight);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        cps.add(cpten);
+        return cps;
+    }
+
+
+    @Test
+    public void removeConnection() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpfive, cpsix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpsix, cpfive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpseven, cpeight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpeight, cpseven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+
+        manager.removeVC(cpone, cptwo);
+        manager.removeVC(cpfive, cpsix);
+        manager.removeVC(cpseven, cpeight);
+
+        assertEquals(2, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+
+
+    @Test
+    public void testRemoveVCbyCP() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpfive, cpsix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpsix, cpfive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpseven, cpeight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpeight, cpseven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpnine, cpten, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpten, cpnine, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .priority(2000)
+                                    .build());
+
+        manager.removeVC(cpone);
+        manager.removeVC(cpsix);
+        manager.removeVC(cpseven);
+        manager.removeVC(cpten);
+
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+
+        assertEquals(0, manager.intentService.getIntentCount());
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+
+    @Test
+    public void testremoveVCbySdx() {
+        testConnectionSetup();
+
+        List<PointToPointIntent> removedIntents = new ArrayList<PointToPointIntent>();
+        SdxL2ConnectionPoint cpone = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST1", CP1, VLANS1);
+        SdxL2ConnectionPoint cptwo = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST2", CP2, VLANS2);
+
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("2"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("2")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("3"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("5")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "2"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("5"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("3")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpone, cptwo, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("4"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("6")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cptwo, cpone, "3"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("6"))))
+                                    .treatment(buildTreatment(VlanId.vlanId(Short.parseShort("4")), null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP2))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP1))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpfive = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST5", CP5, VLANS5);
+        SdxL2ConnectionPoint cpsix = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST6", CP6, VLANS6);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpfive, cpsix, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("100"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpsix, cpfive, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("100")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP6))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP5))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpseven = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST7", CP7, VLANS7);
+        SdxL2ConnectionPoint cpeight = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST8", CP8, VLANS8);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpseven, cpeight, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, VlanId.vlanId(Short.parseShort("111")), false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpeight, cpseven, "1"))
+                                    .selector(buildSelector(null, VlanId.vlanId(Short.parseShort("111"))))
+                                    .treatment(buildTreatment(null, null, true))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP8))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP7))
+                                    .priority(2000)
+                                    .build());
+
+        SdxL2ConnectionPoint cpnine = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST9", CP9, VLANS9);
+        SdxL2ConnectionPoint cpten = SdxL2ConnectionPoint.sdxl2ConnectionPoint("TEST10", CP10, VLANS10);
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpnine, cpten, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .priority(2000)
+                                    .build());
+        removedIntents.add(PointToPointIntent.builder()
+                                    .appId(APPID)
+                                    .key(generateIntentKey(SDXL2_2, cpten, cpnine, "1"))
+                                    .selector(buildSelector(null, null))
+                                    .treatment(buildTreatment(null, null, false))
+                                    .ingressPoint(ConnectPoint.deviceConnectPoint(CP10))
+                                    .egressPoint(ConnectPoint.deviceConnectPoint(CP9))
+                                    .priority(2000)
+                                    .build());
+
+        manager.removeVCs(SDXL2_2);
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.ofNullable(null)));
+        assertEquals(Collections.emptySet(), manager.getVCs(Optional.of(SDXL2_2)));
+
+        for (Intent removedIntent : removedIntents) {
+            boolean found = false;
+            for (Intent existingIntent : manager.intentService.getIntents()) {
+                if (removedIntent.key().equals(existingIntent.key())) {
+                    found = true;
+                    assertTrue(format("Intent %s equal %s", removedIntent, existingIntent),
+                               !IntentUtils.intentsAreEqual(removedIntent, existingIntent));
+                    break;
+                }
+            }
+            assertTrue(!found);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/sdx-l2/src/test/java/org/onosproject/sdxl2/VirtualCircuitTest.java b/sdx-l2/src/test/java/org/onosproject/sdxl2/VirtualCircuitTest.java
new file mode 100644
index 0000000..97dadcb
--- /dev/null
+++ b/sdx-l2/src/test/java/org/onosproject/sdxl2/VirtualCircuitTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.sdxl2;
+
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests VirtualCircuit functionalities.
+ */
+public class VirtualCircuitTest {
+
+
+    public static final String CP1 = "of:00000000000001/1";
+    public static final String CP2 = "of:00000000000002/1";
+    public static final String VLANS1 = "1,2,3,4";
+    public static final String VLANS3 = "1,2,3";
+    public static final String CEMAC1 = "52:40:00:12:44:01";
+    public static final String CEMAC6 = "52:40:00:12:44:02";
+
+    /*
+     * Tests VC with different VLANs.
+     */
+    @Test
+    public void testVC1() {
+        SdxL2ConnectionPoint scp1 = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint scp2 = SdxL2ConnectionPoint.sdxl2ConnectionPoint("GE4", CP2, VLANS3, CEMAC6);
+        VirtualCircuit vc1 = new VirtualCircuit(scp1, scp2);
+    }
+
+    /*
+    Tests creating VC with the same VLANs.
+    */
+    @Test
+    public void testVCEquality() {
+        SdxL2ConnectionPoint scp1 = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI1", CP1, VLANS1, CEMAC1);
+        SdxL2ConnectionPoint scp2 = SdxL2ConnectionPoint.sdxl2ConnectionPoint("GE4", CP2, VLANS3, CEMAC6);
+        VirtualCircuit vc1 = new VirtualCircuit(scp1, scp2);
+        VirtualCircuit vc2 = new VirtualCircuit(scp2, scp1);
+        assertEquals(vc1, vc2);
+        SdxL2ConnectionPoint scp3 = SdxL2ConnectionPoint.sdxl2ConnectionPoint("FI2", CP1, VLANS1, CEMAC1);
+        VirtualCircuit vc3 = new VirtualCircuit(scp1, scp3);
+        assertNotEquals(vc1, vc3);
+    }
+
+}