Application for installing MEF services in ONOS

Some code cleanup.

Change-Id: If70eee3f2198be969ee664f44aed7b95af61d91c
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetEnni.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetEnni.java
new file mode 100644
index 0000000..7b776a0
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetEnni.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onlab.packet.VlanId;
+import org.onlab.util.Bandwidth;
+import org.onosproject.net.ConnectPoint;
+import org.slf4j.Logger;
+
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Representation of a Carrier Ethernet ENNI.
+ * Class can be used in different two ways:
+ * 1. As a global ENNI descriptor containing one or more BW profiles
+ * 2. As a service-specific ENNI descriptor containing a single S-VLAN tag and including a type (e.g. hub, spoke)
+ */
+public class CarrierEthernetEnni extends CarrierEthernetNetworkInterface {
+
+    private final Logger log = getLogger(getClass());
+
+    public enum Role {
+
+        HUB("Hub"),
+        SPOKE("Spoke");
+
+        private String value;
+
+        Role(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    protected Role role;
+    protected Set<VlanId> sVlanIdSet;
+    String tpid;
+
+    public CarrierEthernetEnni(ConnectPoint connectPoint, String uniCfgId, Role role, VlanId sVlanId, String tpid,
+                               Bandwidth usedCapacity) {
+
+        super(connectPoint, uniCfgId);
+        // TODO: Check for null
+        this.role = role;
+        this.sVlanIdSet = new HashSet<>();
+        // The following applies only to service-specific ENNIs
+        if (sVlanId != null) {
+            this.sVlanIdSet.add(sVlanId);
+            // TODO: Use Hub/Spoke role correctly
+            this.role = Role.HUB;
+            this.usedCapacity = usedCapacity;
+            this.tpid = tpid;
+        }
+    }
+
+    /**
+     * Adds the resources associated with an EVC-specific ENNI to a global ENNI.
+     *
+     * @param enni the EVC ENNI to be added
+     */
+    // TODO: Make these methods abstract
+    public void addEvcEnni(CarrierEthernetEnni enni) {
+
+        // Add S-VLAN ID
+        if (enni.sVlanId() != null) {
+            this.sVlanIdSet.add(enni.sVlanId());
+        }
+        // Used capacity cannot be more than ENNI capacity
+        this.usedCapacity = Bandwidth.bps(Math.min(this.usedCapacity.bps() + enni.usedCapacity().bps(), this.capacity.bps()));
+    }
+
+    /**
+     * Removes the resources associated with a service-specific ENNI from a global ENNI.
+     *
+     * @param enni the service ENNI to be added
+     */
+    public void removeEvcEnni(CarrierEthernetEnni enni) {
+
+        // Remove UNI CE-VLAN ID
+        sVlanIdSet.remove(enni.sVlanId());
+
+        // Redundant check - should be avoided by check in validateBwp
+        this.usedCapacity = Bandwidth.bps(Math.max(this.usedCapacity.bps() - enni.usedCapacity().bps(), 0));
+    }
+
+    /**
+     * Validates whether an EVC-specific ENNI is compatible with a global ENNI.
+     *
+     * @param enni the EVC-specific UNI
+     * @return boolean value indicating whether the UNIs are compatible
+     */
+    public boolean validateEvcEnni(CarrierEthernetEnni enni) {
+
+        // Check if the S-VLAN ID of the ENNI is already included in global ENNI
+        if (enni.sVlanId() != null) {
+            if (sVlanIdSet.contains(enni.sVlanId())) {
+                log.error("S-VLAN ID {} already exists in ENNI {}", enni.sVlanId().toString(), this.id());
+                return false;
+            }
+        }
+
+        // Check whether there are enough available resources on the ENNI
+        if (usedCapacity.bps() + enni.usedCapacity().bps() > capacity.bps()) {
+            log.error("ENNI {} cannot be added to global ENNI {} due to lack of resources", enni.id(), this.id());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns ENNI role - applicable only to service-specific ENNIs.
+     *
+     * @return ENNI role
+     */
+    public Role role() {
+        return role;
+    }
+
+    /**
+     * Returns the S-VLAN id associated with a service ENNI, or the first S-VLAN ID found for a global ENNI.
+     *
+     * @return S-VLAN id
+     */
+    public VlanId sVlanId() {
+        if (sVlanIdSet.isEmpty()) {
+            return null;
+        } else {
+            return sVlanIdSet.iterator().next();
+        }
+    }
+
+    /**
+     * Returns ENNI tpid - applicable only to service-specific ENNIs.
+     *
+     * @return tpid
+     */
+    public String tpid() {
+        return tpid;
+    }
+
+    /**
+     * Returns the set of S-VLAN ids associated with the ENNI.
+     *
+     * @return S-VLAN id set
+     */
+    public Set<VlanId> sVlanIdSet() {
+        return sVlanIdSet;
+    }
+
+    @Override
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", this.id)
+                .add("cfgId", this.cfgId)
+                .add("role", role)
+                .add("sVlanIds", sVlanIdSet)
+                .add("capacity", this.capacity)
+                .add("usedCapacity", this.usedCapacity).toString();
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetForwardingConstruct.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetForwardingConstruct.java
new file mode 100644
index 0000000..85fcd2c
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetForwardingConstruct.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onosproject.ecord.metro.api.MetroPathEvent;
+
+import java.time.Duration;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Representation of a CE Forwarding Construct.
+ */
+public class CarrierEthernetForwardingConstruct {
+
+    protected String fcId;
+    protected String fcCfgId;
+    protected String evcId;
+    protected CarrierEthernetVirtualConnection.Type evcType;
+    protected Set<CarrierEthernetLogicalTerminationPoint> ltpSet;
+    protected Duration latency;
+    protected CarrierEthernetMetroConnectivity metroConnectivity;
+    protected boolean congruentPaths;
+
+    // FIXME: Temporary solution
+    protected CarrierEthernetVirtualConnection evcLite;
+
+    // Set to true if both directions should use the same path
+    private static final boolean CONGRUENT_PATHS = true;
+
+    private static final Duration DEFAULT_LATENCY = Duration.ofMillis(50);
+
+    // TODO: Maybe fcCfgId and evcId are not needed?
+    // Note: fcId should be provided only when updating an existing FC
+    public CarrierEthernetForwardingConstruct(String fcId, String fcCfgId,
+                                              String evcId, CarrierEthernetVirtualConnection.Type evcType,
+                                              Set<CarrierEthernetLogicalTerminationPoint> ltpSet) {
+        this.fcId = fcId;
+        this.fcCfgId = (fcCfgId == null? fcId : fcCfgId);
+        this.evcId = evcId;
+        this.evcType = evcType;
+        this.ltpSet = new HashSet<>();
+        this.ltpSet.addAll(ltpSet);
+        this.congruentPaths = CONGRUENT_PATHS;
+        this.latency = DEFAULT_LATENCY;
+        this.metroConnectivity = new CarrierEthernetMetroConnectivity(null, MetroPathEvent.Type.PATH_REMOVED);
+
+        // FIXME: Temporary solution: Create a lightweight EVC out of the FC which can be used with existing methods
+        Set<CarrierEthernetUni> uniSet = new HashSet<>();
+        ltpSet.forEach(ltp -> {
+            if (ltp.ni() instanceof CarrierEthernetUni) {
+                uniSet.add((CarrierEthernetUni) ltp.ni());
+            }
+        });
+        this.evcLite = new CarrierEthernetVirtualConnection(fcId, fcCfgId, evcType, null, uniSet);
+    }
+
+    // TODO: Create constructor using the End-to-End service and a set of LTPs
+
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", fcId)
+                .add("cfgId", fcCfgId)
+                .add("evcId", evcId)
+                .add("evcType", evcType)
+                .add("metroConnectId", (metroConnectivity.id() == null ? "null" : metroConnectivity.id().value()))
+                .add("LTPs", ltpSet).toString();
+    }
+
+    /**
+     * Returns the id of the FC.
+     *
+     * @return id of the FC
+     */
+    public String id() {
+        return fcId;
+    }
+
+    /**
+     * Returns the set of LTPs associated with the FC.
+     *
+     * @return set of LTPs associated with the FC
+     */
+    public Set<CarrierEthernetLogicalTerminationPoint> ltpSet() {
+        return ltpSet;
+    }
+
+    /**
+     * Returns the type of the EVC associated with the FC.
+     *
+     * @return type of associated EVC
+     */
+    public CarrierEthernetVirtualConnection.Type evcType() {
+        return evcType;
+    }
+
+    /**
+     * Returns the "EVC" associated with FC.
+     *
+     * @return the "EVC" associated with FC
+     */
+    public CarrierEthernetVirtualConnection evcLite() {
+        return evcLite;
+    }
+
+    /**
+     * Sets the id of the FC.
+     *
+     * @param id the id to set to the FC
+     */
+    public void setId(String id) {
+        this.fcId = id;
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetInni.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetInni.java
new file mode 100644
index 0000000..5dace45
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetInni.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onlab.packet.VlanId;
+import org.onlab.util.Bandwidth;
+import org.onosproject.net.ConnectPoint;
+import org.slf4j.Logger;
+
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Representation of a Carrier Ethernet INNI.
+ * Class can be used in different two ways:
+ * 1. As a global INNI descriptor containing one or more BW profiles
+ * 2. As a service-specific INNI descriptor containing a single S-VLAN tag and including a type (e.g. hub, spoke)
+ */
+public class CarrierEthernetInni extends CarrierEthernetNetworkInterface {
+
+    private final Logger log = getLogger(getClass());
+
+    public enum Role {
+
+        HUB("Hub"),
+        // FIXME: Remove that after hackathon?
+        TRUNK("Trunk"),
+        SPOKE("Spoke");
+
+        private String value;
+
+        Role(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    protected Role role;
+    protected Set<VlanId> sVlanIdSet;
+    String tpid;
+
+
+    // TODO: Add TPID?
+    public CarrierEthernetInni(ConnectPoint connectPoint, String uniCfgId, Role role, VlanId sVlanId, String tpid,
+                               Bandwidth usedCapacity) {
+
+        super(connectPoint, uniCfgId);
+        // TODO: Check for null
+        this.role = role;
+        this.sVlanIdSet = new HashSet<>();
+        // The following applies only to service-specific INNIs
+        if (sVlanId != null) {
+            this.sVlanIdSet.add(sVlanId);
+            // TODO: Use role correctly
+            this.role = Role.HUB;
+            this.usedCapacity = usedCapacity;
+            this.tpid = tpid;
+        }
+    }
+
+    /**
+     * Adds the resources associated with an EVC-specific INNI to a global INNI.
+     *
+     * @param inni the EVC INNI to be added
+     */
+    // TODO: Make these methods abstract
+    public void addEvcInni(CarrierEthernetInni inni) {
+
+        // Add S-VLAN ID
+        if (inni.sVlanId() != null) {
+            this.sVlanIdSet.add(inni.sVlanId());
+        }
+        // Used capacity cannot be more than INNI capacity
+        this.usedCapacity = Bandwidth.bps(Math.min(this.usedCapacity.bps() + inni.usedCapacity().bps(),
+                this.capacity.bps()));
+    }
+
+    /**
+     * Removes the resources associated with a service-specific INNI from a global INNI.
+     *
+     * @param inni the service INNI to be added
+     */
+    public void removeEvcInni(CarrierEthernetInni inni) {
+
+        // Remove UNI CE-VLAN ID
+        sVlanIdSet.remove(inni.sVlanId());
+
+        // Redundant check - should be avoided by check in validateBwp
+        this.usedCapacity = Bandwidth.bps(Math.max(this.usedCapacity.bps() - inni.usedCapacity().bps(), 0));
+    }
+
+    /**
+     * Validates whether an EVC-specific INNI is compatible with a global INNI.
+     *
+     * @param inni the EVC-specific UNI
+     * @return boolean value indicating whether the UNIs are compatible
+     */
+    public boolean validateEvcInni(CarrierEthernetInni inni) {
+
+        // Check if the S-VLAN ID of the INNI is already included in global INNI
+        if (inni.sVlanId() != null) {
+            if (sVlanIdSet.contains(inni.sVlanId())) {
+                log.error("S-VLAN ID {} already exists in INNI {}", inni.sVlanId().toString(), this.id());
+                return false;
+            }
+        }
+
+        // Check whether there are enough available resources on the INNI
+        if (usedCapacity.bps() + inni.usedCapacity().bps() > capacity.bps()) {
+            log.error("INNI {} cannot be added to global INNI {} due to lack of resources", inni.id(), this.id());
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns INNI role - applicable only to service-specific INNIs.
+     *
+     * @return INNI role
+     */
+    public Role role() {
+        return role;
+    }
+
+    /**
+     * Returns the S-VLAN id associated with a service INNI, or the first S-VLAN ID found for a global INNI.
+     *
+     * @return S-VLAN id
+     */
+    public VlanId sVlanId() {
+        if (sVlanIdSet.isEmpty()) {
+            return null;
+        } else {
+            return sVlanIdSet.iterator().next();
+        }
+    }
+
+    /**
+     * Returns the set of S-VLAN ids associated with the INNI.
+     *
+     * @return S-VLAN id set
+     */
+    public Set<VlanId> sVlanIdSet() {
+        return sVlanIdSet;
+    }
+
+    /**
+     * Returns INNI tpid - applicable only to service-specific INNIs.
+     *
+     * @return tpid
+     */
+    public String tpid() {
+        return tpid;
+    }
+
+    @Override
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", this.id)
+                .add("cfgId", this.cfgId)
+                .add("role", role)
+                .add("sVlanIds", sVlanIdSet)
+                .add("capacity", this.capacity)
+                .add("usedCapacity", this.usedCapacity).toString();
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetLogicalTerminationPoint.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetLogicalTerminationPoint.java
new file mode 100644
index 0000000..ba079d4
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetLogicalTerminationPoint.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onosproject.net.ConnectPoint;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of a CE Logical Termination Point.
+ */
+public class CarrierEthernetLogicalTerminationPoint {
+
+    public enum Role {
+
+        WORKING("Working"),
+        PROTECTION("Protection"),
+        PROTECTED("Protected"),
+        SYMMETRIC("Symmetric"),
+        HUB("Hub"),
+        SPOKE("Spoke"),
+        LEAF("Leaf"),
+        // FIXME: Remove that after hackathon?
+        TRUNK("Trunk"),
+        ROOT("Root");
+
+        private String value;
+
+        Role(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    public enum Type {
+        UNI, INNI, ENNI
+    }
+
+    protected String ltpId;
+    protected String ltpCfgId;
+    protected Type type;
+    protected Role role;
+    // A global LTP will point to the corresponding global NI and a service LTP to the corresponding service NI
+    protected CarrierEthernetNetworkInterface ni;
+
+    public CarrierEthernetLogicalTerminationPoint(String ltpCfgId, CarrierEthernetNetworkInterface ni) {
+        checkNotNull(ni);
+        this.ni = ni;
+        if (ni instanceof CarrierEthernetUni) {
+            this.type = Type.UNI;
+        } else if (ni instanceof CarrierEthernetInni) {
+            this.type = Type.INNI;
+        } else {
+        this.type = Type.ENNI;
+        }
+        // NOTE: Role is expected to be null for service-specific LTPs/NIs
+        this.role = (ni.role() == null? null : CarrierEthernetLogicalTerminationPoint.Role
+                .valueOf(ni.role().toString()));
+        this.ltpId = this.cp().deviceId().toString() + "/" + this.cp().port().toString();
+        this.ltpCfgId = (ltpCfgId == null ? this.ltpId : ltpCfgId);
+    }
+
+    /**
+     * Returns associated connect point.
+     *
+     * @return associated connect point
+     */
+    public ConnectPoint cp() {
+        return ni.cp();
+    }
+
+    /**
+     * Returns LTP string identifier.
+     *
+     * @return LTP string identifier
+     */
+    public String id() {
+        return ltpId;
+    }
+
+    /**
+     * Returns LTP string config identifier.
+     *
+     * @return LTP string config identifier
+     */
+    public String cfgId() {
+        return ltpCfgId;
+    }
+
+    /**
+     * Returns LTP role - applicable only to service-specific LTPs.
+     *
+     * @return LTP role
+     */
+    public Role role() {
+        return role;
+    }
+
+    /**
+     * Returns LTP type.
+     *
+     * @return LTP type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the NI associated with the LTP or null of there is none.
+     *
+     * @return NI associated with LTP
+     */
+    public CarrierEthernetNetworkInterface ni() {
+        return ni;
+    }
+
+    /**
+     * Returns the scope of the LTP (always matches that of the associated NI).
+     *
+     * @return LTP scope
+     */
+    public CarrierEthernetNetworkInterface.Scope scope() {
+        return this.ni().scope();
+    }
+
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", ltpId)
+                .add("cfgId", ltpCfgId)
+                .add("role", role)
+                .add("uni", ni).toString();
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
index 3e02151..9660ee9 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetManager.java
@@ -97,11 +97,15 @@
 
     private static final int METRO_CONNECT_TIMEOUT_MILLIS = 7000;
 
-    private static final boolean PACKET_OPTICAL_TOPO = true;
+    private static final boolean PACKET_OPTICAL_TOPO = false;
 
-    // TODO: Implement distributed store for CE services
-    // The installed CE services
-    private final Map<String, CarrierEthernetService> serviceMap = new ConcurrentHashMap<>();
+    // TODO: Implement distributed store for EVCs
+    // The installed EVCs
+    private final Map<String, CarrierEthernetVirtualConnection> evcMap = new ConcurrentHashMap<>();
+
+    // TODO: Implement distributed store for Forwarding Constructs
+    // The installed Forwarding Constructs
+    private final Map<String, CarrierEthernetForwardingConstruct> fcMap = new ConcurrentHashMap<>();
 
     // TODO: Refactor this part
     private final Map<MetroConnectivityId, MetroPathEvent.Type> metroConnectStatusMap = new ConcurrentHashMap<>();
@@ -112,6 +116,9 @@
 
     // Map of connect points and corresponding VLAN tag
     private Map<ConnectPoint, VlanId> portVlanMap = new ConcurrentHashMap<>();
+    // TODO: Implement distributed store for CE LTPs
+    // The installed CE LTPs
+    private final Map<String, CarrierEthernetLogicalTerminationPoint> ltpMap = new ConcurrentHashMap<>();
 
     /**
      * Activate this component.
@@ -128,7 +135,8 @@
      */
     @Deactivate
     public void deactivate() {
-        removeAllServices();
+        removeAllEvcs();
+        removeAllFcs();
         metroPathService.removeListener(metroEventListener);
         networkConfigService.removeListener(netcfgListener);
 
@@ -136,32 +144,61 @@
     }
 
     /**
-     * Returns the map of installed services.
+     * Returns the map of installed EVCs.
      *
-     * @return map of installed services
+     * @return map of installed EVCs
      */
-    public  Map<String, CarrierEthernetService> serviceMap() {
-        return this.serviceMap;
+    public  Map<String, CarrierEthernetVirtualConnection> evcMap() {
+        return this.evcMap;
     }
 
-    // TODO: Add method to remove a UNI from an already installed service
+    // TODO: Add method to remove a UNI from an already installed EVC
 
     /**
-     * Get an installed CE using its id.
+     * Get an installed EVC using its id.
      *
-     * @return the CE service definition or null if the service doesn't exist
+     * @param evcId the EVC id
+     * @return the EVC representation or null if the EVC doesn't exist
      */
-    public CarrierEthernetService getService(String serviceId) {
-        return ((serviceMap.get(serviceId) == null) ? null : serviceMap.get(serviceId));
+    public CarrierEthernetVirtualConnection getEvc(String evcId) {
+        return ((evcMap.get(evcId) == null) ? null : evcMap.get(evcId));
     }
 
     /**
-     * Get the map containing all installed services
+     * Get an installed FC using its id.
      *
-     * @return the CE service map
+     * @param fcId the FC id
+     * @return the FC representation or null if the EVC doesn't exist
      */
-    public Map<String, CarrierEthernetService> getServiceMap() {
-        return serviceMap;
+    public CarrierEthernetForwardingConstruct getFc(String fcId) {
+        return ((fcMap.get(fcId) == null) ? null : fcMap.get(fcId));
+    }
+
+    /**
+     * Get the map containing all installed FCs
+     *
+     * @return the FC map
+     */
+    public Map<String, CarrierEthernetForwardingConstruct> getFcMap() {
+        return fcMap;
+    }
+
+    /**
+     * Get the map containing all installed EVCs
+     *
+     * @return the EVC map
+     */
+    public Map<String, CarrierEthernetVirtualConnection> getEvcMap() {
+        return evcMap;
+    }
+
+    /**
+     * Get the map containing all global LTPs
+     *
+     * @return the global LTP map
+     */
+    public Map<String, CarrierEthernetLogicalTerminationPoint> getLtpMap() {
+        return ltpMap;
     }
 
     /**
@@ -174,128 +211,134 @@
     }
 
     /**
-     * Verify the validity of a CE service definition taking also into account current network status.
+     * Verify the validity of an EVC representation taking also into account current network status.
      *
-     * @param originalService the provided CE service definition
-     * @return a valid, potentially modified service description, or null if the service could not be validated
+     * @param originalEvc the provided EVC representation
+     * @return a valid, potentially modified EVC representation, or null if the EVC could not be validated
      */
-    private CarrierEthernetService validateService(CarrierEthernetService originalService) {
+    private CarrierEthernetVirtualConnection validateEvc(CarrierEthernetVirtualConnection originalEvc) {
 
-        // Make a copy of the provided service, since it may be modified
-        CarrierEthernetService service = originalService;
+        // Make a copy of the provided EVC, since it may be modified
+        CarrierEthernetVirtualConnection evc = originalEvc;
 
-        // Try to set a unique VLAN id for the service unless the service is being updated
+        // Try to set a unique VLAN id for the EVC unless the EVC is being updated
         // TODO: Add different connectivity types
-        if (service.vlanId() == null) {
-            service.setVlanId(generateVlanId());
-            if (service.vlanId() == null) {
+        if (evc.vlanId() == null) {
+            evc.setVlanId(generateVlanId());
+            if (evc.vlanId() == null) {
                 log.error("No available VLAN id found.");
                 return null;
             }
         }
 
-        // Verify that CE-VLAN ID is provided to either all UNIs or none and set the virtualService flag accordingly
+        // Verify that CE-VLAN ID is provided to either all UNIs or none and set the virtualEvc flag accordingly
         boolean isVirtual = false;
-        Iterator<CarrierEthernetUni> it = service.uniSet().iterator();
+        Iterator<CarrierEthernetUni> it = evc.uniSet().iterator();
         while (it.hasNext()) {
             CarrierEthernetUni uni = it.next();
             if (uni.ceVlanId() == null && isVirtual) {
-                log.error("Could not validate the virtual status of the service.");
+                log.error("Could not validate the virtual status of the EVC.");
                 return null;
             } else if (uni.ceVlanId() != null){
                 isVirtual = true;
             }
         }
-        service.setIsVirtual(isVirtual);
+        evc.setIsVirtual(isVirtual);
 
-        // Set unique id for the service unless the service is being updated
-        if (service.id() == null) {
-            service.setId(generateServiceId(service));
+        // Set unique id for the EVC unless the EVC is being updated
+        if (evc.id() == null) {
+            evc.setId(generateEvcId(evc));
         }
 
         Set<CarrierEthernetUni> validatedUniSet = new HashSet<>();
 
-        // Check the UNIs of the service, possibly removing UNIs that are incompatible with existing ones
-        it = service.uniSet().iterator();
+        // Check the UNIs of the EVC, possibly removing UNIs that are incompatible with existing ones
+        it = evc.uniSet().iterator();
         while (it.hasNext()) {
             CarrierEthernetUni uni = it.next();
-            // Change the name of the UNI's BWP to the service name if it is an EVC BWP
+            // Change the name of the UNI's BWP to the EVC name if it is an EVC BWP
             if (uni.bwp().type().equals(CarrierEthernetBandwidthProfile.Type.EVC)) {
-                uni.bwp().setId(service.id());
+                uni.bwp().setId(evc.id());
             }
             // Check first if UNI already exists by checking against the global UNI Map
             if (uniMap.keySet().contains(uni.id())) {
                 CarrierEthernetUni existingUni = uniMap.get(uni.id());
-                // Check if the service-specific UNI is compatible with the global one
-                if (!(existingUni.validateServiceUni(uni))) {
-                    // If service is of ROOT_MULTIPOINT type and we have removed the root, return null
-                    if (service.type() == CarrierEthernetService.Type.ROOT_MULTIPOINT &&
-                            uni.type() == CarrierEthernetUni.Type.ROOT) {
-                        log.error("Root UNI could not be added to %s service.", service.type().name());
+                // Check if the EVC-specific UNI is compatible with the global one
+                if (!(existingUni.validateEvcUni(uni))) {
+                    // If EVC is of ROOT_MULTIPOINT type and we have removed the root, return null
+                    if (evc.type() == CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT &&
+                            uni.role() == CarrierEthernetUni.Role.ROOT) {
+                        log.error("Root UNI could not be added to %s EVC.", evc.type().name());
                         return null;
                     }
-                    log.warn("UNI {} could not be added to service.", uni.id());
+                    log.warn("UNI {} could not be added to EVC.", uni.id());
                     continue;
                 } else {
-                    // Add UNI to service description
+                    // Add UNI to evc description
                     validatedUniSet.add(uni);
                 }
             } else {
-                // Add UNI to service description
+                // Add UNI to EVC description
                 validatedUniSet.add(uni);
             }
         }
 
-        // Update the service UNI set, based on the validated UNIs
-        service.setUniSet(validatedUniSet);
+        // Update the EVC UNI set, based on the validated UNIs
+        evc.setUniSet(validatedUniSet);
 
-        if (service.type().equals(CarrierEthernetService.Type.ROOT_MULTIPOINT) && (service.uniSet().size() < 2)) {
-            log.error("{} service requires at least two UNIs.", service.type().name());
+        if (evc.uniSet().size() > evc.maxNumUni()) {
+            log.error("{} EVC can have at most {} UNIs.", evc.maxNumUni());
             return null;
         }
 
-        if (service.type().equals(CarrierEthernetService.Type.MULTIPOINT_TO_MULTIPOINT) &&
-                (service.uniSet().size() < 3)) {
-            log.error("{} service requires more than two UNIs.", service.type().name());
+        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT) && (evc.uniSet().size() < 2)) {
+            log.error("{} EVC requires at least two UNIs.", evc.type().name());
             return null;
         }
 
-        if (service.type().equals(CarrierEthernetService.Type.POINT_TO_POINT) && (service.uniSet().size() != 2)) {
-            log.error("{} service requires exactly two UNIs.", service.type().name());
+        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT) &&
+                (evc.uniSet().size() < 3)) {
+            log.error("{} EVC requires more than two UNIs.", evc.type().name());
             return null;
         }
 
-        return service;
+        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT) && (evc.uniSet().size() != 2)) {
+            log.error("{} EVC requires exactly two UNIs.", evc.type().name());
+            return null;
+        }
+
+        return evc;
     }
 
     /**
-     * Establish connectivity according to the service type (E-Line, E-Tree, E-LAN) and the service parameters.
+     * Establish connectivity according to the EVC type (E-Line, E-Tree, E-LAN) and the EVC parameters.
      *
-     * @param originalService the CE service definition
-     * @return boolean value indicating whether the service could be established even partially
+     * @param originalEvc the EVC representation
+     * @return the EVC active state (FULL or PARTIAL) or null if EVC connectivity could not be established
      */
-    public boolean establishConnectivity(CarrierEthernetService originalService) {
+    public CarrierEthernetVirtualConnection.ActiveState establishConnectivity(
+            CarrierEthernetVirtualConnection originalEvc) {
 
-        // If service already exists, remove it and reestablish with new parameters
-        if (originalService.id() != null && serviceMap.containsKey(originalService.id())) {
-            return updateService(originalService);
+        // If EVC already exists, remove it and reestablish with new parameters
+        if (originalEvc.id() != null && evcMap.containsKey(originalEvc.id())) {
+            return updateEvc(originalEvc);
         } else {
-            originalService.setId(null);
+            originalEvc.setId(null);
         }
 
-        CarrierEthernetService service = validateService(originalService);
+        CarrierEthernetVirtualConnection evc = validateEvc(originalEvc);
 
-        boolean outcome = false;
-
-        if (service == null) {
-            log.error("Service could not be installed, please check log for details.");
-            return outcome;
+        if (evc == null) {
+            log.error("EVC could not be installed, please check log for details.");
+            return null;
         }
 
-        // Temporary set for iterating through service UNI pairs
-        Set<CarrierEthernetUni> uniSet = service.uniSet();
+        boolean allPairsConnected = true;
 
-        // Temporary set for indicating which UNIs were finally included in the service
+        // Temporary set for iterating through EVC UNI pairs
+        Set<CarrierEthernetUni> uniSet = evc.uniSet();
+
+        // Temporary set for indicating which UNIs were finally included in the EVC
         Set<CarrierEthernetUni> usedUniSet = new HashSet<>();
 
         Iterator<CarrierEthernetUni> it1 = uniSet.iterator();
@@ -315,51 +358,53 @@
                 }
 
                 // Do not establish connectivity between leaf UNIs (applies to Rooted_Multipoint)
-                if (uni1.type() == CarrierEthernetUni.Type.LEAF && uni2.type() == CarrierEthernetUni.Type.LEAF) {
+                if (uni1.role() == CarrierEthernetUni.Role.LEAF && uni2.role() == CarrierEthernetUni.Role.LEAF) {
                     continue;
                 }
 
                 MetroConnectivityId metroConnectId = null;
 
                 if (PACKET_OPTICAL_TOPO) {
-                    metroConnectId = setupMetroConnectivity(uni1.cp(), uni2.cp(), uni1.bwp().cir(), service.latency());
+                    metroConnectId = setupMetroConnectivity(uni1.cp(), uni2.cp(), uni1.bwp().cir(), evc.latency());
 
                     if (metroConnectId == null ||
                             metroConnectStatusMap.get(metroConnectId) != MetroPathEvent.Type.PATH_INSTALLED) {
                         log.error("Could not establish metro connectivity between {} and {}" +
                                         " (metro id and status: {}, {})", uni1.cp(), uni2.cp(), metroConnectId,
                                 (metroConnectId == null ? "null" : metroConnectStatusMap.get(metroConnectId)));
-                        //continue;
+                        allPairsConnected = false;
+                        continue;
                     }
 
                     if (metroConnectId != null) {
-                        service.setMetroConnectivityId(metroConnectId);
-                        service.setMetroConnectivityStatus(metroConnectStatusMap.get(metroConnectId));
+                        evc.setMetroConnectivityId(metroConnectId);
+                        evc.setMetroConnectivityStatus(metroConnectStatusMap.get(metroConnectId));
                     }
 
-                    log.info("Metro connectivity id and status for CE service {}: {}, {}", service.id(),
-                            service.metroConnectivity().id(), service.metroConnectivity().status());
+                    log.info("Metro connectivity id and status for EVC {}: {}, {}", evc.id(),
+                            evc.metroConnectivity().id(), evc.metroConnectivity().status());
 
                     if (metroConnectId != null) {
                         // TODO: find vlanIds for both CO and store to service
                         Optional<VlanId> vlanId = getVlanTag(metroPathService.getPath(metroConnectId));
                         if (vlanId.isPresent()) {
-                            log.info("VLAN ID {} is assigned to CE service {}", vlanId.get(), service.id());
-                            service.setVlanId(vlanId.get());
+                            log.info("VLAN ID {} is assigned to CE service {}", vlanId.get(), evc.id());
+                            evc.setVlanId(vlanId.get());
                         }
                     }
                 }
 
-                if (!cePktProvisioner.setupConnectivity(uni1, uni2, service)) {
+                if (!cePktProvisioner.setupConnectivity(uni1, uni2, evc)) {
                     log.warn("Could not set up packet connectivity between {} and {}", uni1, uni2);
                     removeMetroConnectivity(metroConnectId);
+                    allPairsConnected = false;
                     continue;
                 }
 
                 // Indicate that connection for at least one UNI pair has been established
-                outcome = true;
+                evc.setState(CarrierEthernetVirtualConnection.State.ACTIVE);
 
-                // Add UNIs to the set of UNIs used by the service
+                // Add UNIs to the set of UNIs used by the EVC
                 usedUniSet.add(uni1);
                 usedUniSet.add(uni2);
             }
@@ -367,52 +412,60 @@
             it1.remove();
         }
 
-        // Update the service UNI set, based on the UNIs actually used
-        service.setUniSet(usedUniSet);
+        // Update the EVC UNI set, based on the UNIs actually used
+        evc.setUniSet(usedUniSet);
 
-        // If no pair was connected, do not register the service
-        if (outcome) {
-            serviceMap.put(service.id(), service);
-            cePktProvisioner.applyBandwidthProfiles(service);
-            // Apply the BWPs of the service UNI to the global UNIs, creating them if needed
-            applyBandwidthProfiles(service.uniSet());
+        // If no pair was connected, do not register the EVC
+        if (evc.state().equals(CarrierEthernetVirtualConnection.State.ACTIVE)) {
+            evcMap.put(evc.id(), evc);
+            cePktProvisioner.applyBandwidthProfiles(evc);
+            // Apply the BWPs of the EVC UNI to the global UNIs, creating them if needed
+            applyBandwidthProfiles(evc.uniSet());
         }
 
-        return outcome;
+        if (evc.state().equals(CarrierEthernetVirtualConnection.State.ACTIVE)) {
+            if (allPairsConnected) {
+                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.FULL);
+            } else {
+                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.PARTIAL);
+            }
+        }
+
+        return evc.activeState();
     }
 
     /**
-     * Reestablish connectivity for an existing service.
+     * Reestablish connectivity for an existing EVC.
      *
-     * @param originalService the updated CE service definition
-     * @return boolean value indicating whether the service could be established even partially
+     * @param originalEvc the updated CE evc definition
+     * @return boolean value indicating whether the EVC could be established even partially
      */
-    public boolean updateService(CarrierEthernetService originalService) {
+    public CarrierEthernetVirtualConnection.ActiveState updateEvc(CarrierEthernetVirtualConnection originalEvc) {
         // Just checking again
-        if (serviceMap.containsKey(originalService.id())) {
-            log.info("Updating existing service {}", originalService.id());
-            // Keep the VLAN ID of the original service
-            originalService.setVlanId(serviceMap.get(originalService.id()).vlanId());
-            removeService(originalService.id());
+        if (evcMap.containsKey(originalEvc.id())) {
+            log.info("Updating existing EVC {}", originalEvc.id());
+            // Keep the VLAN ID of the original EVC
+            originalEvc.setVlanId(evcMap.get(originalEvc.id()).vlanId());
+            removeEvc(originalEvc.id());
         }
-        return establishConnectivity(originalService);
+        return establishConnectivity(originalEvc);
     }
 
     /**
-     * Applies bandwidth profiles to the UNIs of a service and adds them if needed to the global UNI map.
+     * Applies bandwidth profiles to the UNIs of an EVC and adds them if needed to the global UNI map.
      *
-     * @param  uniSet set of UNIs that are included in the service
+     * @param  uniSet set of UNIs that are included in the EVC
      */
     private void applyBandwidthProfiles(Set<CarrierEthernetUni> uniSet) {
 
         uniSet.forEach(uni -> {
             if (!(uniMap.keySet().contains(uni.id()))) {
-                // Just add the UNI as it appears at the service
+                // Just add the UNI as it appears at the EVC
                 uniMap.put(uni.id(), uni);
             } else {
                 // Add UNI resources (BWP, CE-VLAN ID) to existing global UNI
                 CarrierEthernetUni newUni = uniMap.get(uni.id());
-                newUni.addServiceUni(uni);
+                newUni.addEvcUni(uni);
                 // Update config identifier
                 newUni.setCfgId(uni.cfgId());
                 uniMap.put(uni.id(), newUni);
@@ -421,19 +474,19 @@
     }
 
     /**
-     * Removes bandwidth profiles from the UNIs of a service and removes them if needed from the global UNI map.
+     * Removes bandwidth profiles from the UNIs of an EVC and removes them if needed from the global UNI map.
      *
-     * @param serviceId the CE service id
+     * @param evcId the EVC id
      */
-    private void removeBandwidthProfiles(String serviceId) {
+    private void removeBandwidthProfiles(String evcId) {
 
-        serviceMap.get(serviceId).uniSet().forEach(uni -> {
+        evcMap.get(evcId).uniSet().forEach(uni -> {
             // TODO: Check if the bandwidth profile really needs to be removed (e.g. may be CoS)
-            cePktProvisioner.removeBandwidthProfiles(serviceMap.get(serviceId));
+            cePktProvisioner.removeBandwidthProfiles(evcMap.get(evcId));
 
             // Remove UNI resources (BWP, CE-VLAN ID) from global UNI
             CarrierEthernetUni newUni = uniMap.get(uni.id());
-            newUni.removeServiceUni(uni);
+            newUni.removeEvcUni(uni);
             uniMap.put(uni.id(), newUni);
         });
     }
@@ -443,30 +496,181 @@
      *
      * This will be called either from the deactivate method or as a response to a CLI command.
      * */
-    public void removeAllServices() {
-        serviceMap.keySet().forEach(serviceId -> {
-            CarrierEthernetService service = serviceMap.get(serviceId);
-            cePktProvisioner.removeConnectivity(service);
-            cePktProvisioner.removeBandwidthProfiles(service);
-            removeMetroConnectivity(service.metroConnectivity().id());
-            removeBandwidthProfiles(serviceId);
+    public void removeAllEvcs() {
+        evcMap.keySet().forEach(evcId -> {
+            CarrierEthernetVirtualConnection evc = evcMap.get(evcId);
+            cePktProvisioner.removeConnectivity(evc);
+            cePktProvisioner.removeBandwidthProfiles(evc);
+            removeMetroConnectivity(evc.metroConnectivity().id());
+            removeBandwidthProfiles(evcId);
         });
-        serviceMap.clear();
+        evcMap.clear();
     }
 
     /**
-     * Removes all resources associated with a specific CE service.
+     * Removes all resources associated with a specific EVC.
      *
-     * @param serviceId the CE service id
+     * @param evcId the EVC id
      * */
-    public void removeService(String serviceId) {
-        if (serviceMap.containsKey(serviceId)) {
-            CarrierEthernetService service = serviceMap.get(serviceId);
-            cePktProvisioner.removeConnectivity(service);
-            cePktProvisioner.removeBandwidthProfiles(service);
-            removeMetroConnectivity(service.metroConnectivity().id());
-            removeBandwidthProfiles(serviceId);
-            serviceMap.remove(serviceId);
+    public void removeEvc(String evcId) {
+        if (evcMap.containsKey(evcId)) {
+            CarrierEthernetVirtualConnection evc = evcMap.get(evcId);
+            cePktProvisioner.removeConnectivity(evc);
+            cePktProvisioner.removeBandwidthProfiles(evc);
+            removeMetroConnectivity(evc.metroConnectivity().id());
+            removeBandwidthProfiles(evcId);
+            evcMap.remove(evcId);
+        }
+    }
+
+    // FIXME: Rethink this approach
+    /**
+     * Installs all resources associated with a specific FC.
+     *
+     * @param fc the FC to install
+     * @return the FC that was installed
+     * */
+    public CarrierEthernetForwardingConstruct installFc(CarrierEthernetForwardingConstruct fc) {
+
+        // Try to set a unique VLAN id for the FC unless the EVC is being updated
+        // TODO: Add different connectivity types
+        fc.evcLite().setVlanId(generateVlanId());
+        if (fc.evcLite().vlanId() == null) {
+            log.error("No available VLAN id found.");
+            return null;
+        }
+
+        // Verify that CE-VLAN ID is provided to either all UNIs or none and set the virtualEvc flag accordingly
+        boolean isVirtual = false;
+        Iterator<CarrierEthernetUni> it = fc.evcLite().uniSet().iterator();
+        while (it.hasNext()) {
+            CarrierEthernetUni uni = it.next();
+            if (uni.ceVlanId() == null && isVirtual) {
+                log.error("Could not validate the virtual status of the EVC.");
+                return null;
+            } else if (uni.ceVlanId() != null){
+                isVirtual = true;
+            }
+        }
+        fc.evcLite().setIsVirtual(isVirtual);
+
+        // Generate and set unique FC id
+        fc.setId(generateEvcId(fc.evcLite()));
+        fc.evcLite().setId(fc.id());
+
+        Set<CarrierEthernetUni> validatedUniSet = new HashSet<>();
+
+        // Check the UNIs of the EVC, possibly removing UNIs that are incompatible with existing ones
+        it = fc.evcLite().uniSet().iterator();
+        while (it.hasNext()) {
+            CarrierEthernetUni uni = it.next();
+            // Change the name of the UNI's BWP to the EVC name if it is an EVC BWP
+            if (uni.bwp().type().equals(CarrierEthernetBandwidthProfile.Type.EVC)) {
+                uni.bwp().setId(fc.evcLite().id());
+            }
+            // Check first if UNI already exists by checking against the global UNI Map
+            if (uniMap.keySet().contains(uni.id())) {
+                CarrierEthernetUni existingUni = uniMap.get(uni.id());
+                // Check if the EVC-specific UNI is compatible with the global one
+                if (!(existingUni.validateEvcUni(uni))) {
+                    // If EVC is of ROOT_MULTIPOINT type and we have removed the root, return null
+                    if (fc.evcLite().type() == CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT &&
+                            uni.role() == CarrierEthernetUni.Role.ROOT) {
+                        log.error("Root UNI could not be added to %s EVC.", fc.evcLite().type().name());
+                        return null;
+                    }
+                    log.warn("UNI {} could not be added to EVC.", uni.id());
+                    continue;
+                } else {
+                    // Add UNI to evc description
+                    validatedUniSet.add(uni);
+                }
+            } else {
+                // Add UNI to EVC description
+                validatedUniSet.add(uni);
+            }
+        }
+
+        // Temporary set for iterating through EVC NI pairs
+
+        Set<CarrierEthernetNetworkInterface> niSet = new HashSet<>();
+        fc.ltpSet().forEach(ltp -> niSet.add(ltp.ni()));
+
+        // Temporary set for indicating which NIs were finally included in the FC
+        Set<CarrierEthernetNetworkInterface> usedNiSet = new HashSet<>();
+
+        Iterator<CarrierEthernetNetworkInterface> it1 = niSet.iterator();
+        while (it1.hasNext()) {
+
+            CarrierEthernetNetworkInterface ni1 = it1.next();
+
+            // Iterate through all the remaining UNIs
+            Iterator<CarrierEthernetNetworkInterface> it2 = niSet.iterator();
+            while (it2.hasNext()) {
+
+                CarrierEthernetNetworkInterface ni2 = it2.next();
+
+                log.info("Trying to establish connectivity between {} and {}", ni1.id(), ni2.id());
+
+                // Skip equals
+                if (ni1.equals(ni2)) {
+                    continue;
+                }
+
+                // Do not establish connectivity between leaf UNIs (applies to Rooted_Multipoint)
+                if (ni1.role() == CarrierEthernetUni.Role.LEAF && ni2.role() == CarrierEthernetUni.Role.LEAF) {
+                    continue;
+                }
+
+                if (!cePktProvisioner.setupConnectivity(ni1, ni2, fc.evcLite())) {
+                    log.warn("Could not set up packet connectivity between {} and {}", ni1, ni2);
+                    continue;
+                }
+
+                // Add UNIs to the set of UNIs used by the EVC
+                usedNiSet.add(ni1);
+                usedNiSet.add(ni2);
+            }
+            // Remove NI from temporary set so that each pair is visited only once
+            it1.remove();
+        }
+
+        // TODO: Update the EVC NI set, based on the NIs actually used
+        //fc.setNiSet(usedNiSet);
+        // Also update the corresponding evcLite
+
+        // TODO: Do the appropriate checks
+        fcMap.put(fc.id(), fc);
+        evcMap.put(fc.evcLite().id(), fc.evcLite());
+        cePktProvisioner.applyBandwidthProfiles(fc.evcLite());
+        // Apply the BWPs of the EVC UNI to the global UNIs, creating them if needed
+        applyBandwidthProfiles(fc.evcLite().uniSet());
+
+        return fc;
+    }
+
+    /**
+     * Removes all resources associated with the application.
+     *
+     * This will be called either from the deactivate method or as a response to a CLI command.
+     * */
+    public void removeAllFcs() {
+        fcMap.keySet().forEach(fcId -> {
+            removeEvc(fcMap.get(fcId).evcLite().id());
+        });
+        fcMap.clear();
+    }
+
+    // FIXME: Rethink this approach
+    /**
+     * Removes all resources associated with a specific FC.
+     *
+     * @param fcId the FC id
+     * */
+    public void removeFc(String fcId) {
+        if (fcMap.containsKey(fcId)) {
+            removeEvc(fcMap.get(fcId).evcLite().id());
+            fcMap.remove(fcId);
         }
     }
 
@@ -480,7 +684,7 @@
         Set<VlanId> vlanIdSet = new HashSet<>();
         VlanId vlanId = null;
 
-        serviceMap.values().forEach(service -> vlanIdSet.add(service.vlanId));
+        evcMap.values().forEach(evc -> vlanIdSet.add(evc.vlanId));
 
         // If all vlanIds are being used return null, else try to find the next available one
         if (vlanIdSet.size() <  VlanId.MAX_VLAN - 1) {
@@ -506,36 +710,38 @@
     /**
      * Generates a unique id in the context of the CE app.
      *
+     * @param evc the EVC representation
      * @return the generated vlanId or null if none found
      * */
-    public String generateServiceId(CarrierEthernetService service) {
+    public String generateEvcId(CarrierEthernetVirtualConnection evc) {
 
         // TODO: Add different connectivity types
 
         String tmpType;
 
-        if (service.type().equals(CarrierEthernetService.Type.POINT_TO_POINT)) {
+        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT)) {
             tmpType = "Line";
-        } else if (service.type().equals(CarrierEthernetService.Type.MULTIPOINT_TO_MULTIPOINT)) {
+        } else if (evc.type().equals(CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT)) {
             tmpType = "LAN";
         } else {
             tmpType = "Tree";
         }
 
-        String serviceId = "E" + (service.isVirtual() ? "V" : "") + "P-" + tmpType + "-" +
-                service.vlanId().toString();
+        String evcId = "E" + (evc.isVirtual() ? "V" : "") + "P-" + tmpType + "-" +
+                evc.vlanId().toString();
 
-        return serviceId;
+        return evcId;
     }
 
     /**
-     * Adds all potential UNIs to the global UNI map if they are not already there.
+     * Returns all potential UNIs.
      *
+     * @return set of all potential UNIs
      * */
-    // TODO: Modify to return set of UNIs so that method can be reused in Uni Completer
-    public void addGlobalUnis() {
+    public Set<CarrierEthernetUni> getGlobalUnis() {
 
         CarrierEthernetUni uni;
+        Set<CarrierEthernetUni> uniSet = new HashSet<>();
         // Generate the device ID/port number identifiers
         for (Device device : deviceService.getDevices()) {
             for (Port port : deviceService.getPorts(device.id())) {
@@ -548,14 +754,83 @@
                     if (linkService.getEgressLinks(cp).isEmpty() && linkService.getIngressLinks(cp).isEmpty() &&
                             device.type().equals(Device.Type.SWITCH)) {
                         uni = new CarrierEthernetUni(cp, cpString, null, null, null);
-                        // Add UNI only if it's not already there
-                        if (!uniMap.containsKey(uni.id())) {
-                            uniMap.put(uni.id(), uni);
-                        }
+                        uniSet.add(uni);
                     }
                 }
             }
         }
+        return uniSet;
+    }
+
+    /**
+     * Adds a set of potential UNIs to the global UNI map if they are not already there.
+     *
+     * @param uniSet set of potential UNIs to add to global UNI map
+     * */
+    public void addGlobalUnis(Set<CarrierEthernetUni> uniSet) {
+        uniSet.forEach(uni -> {
+            // Add UNI only if it's not already there
+            if (!uniMap.containsKey(uni.id())) {
+                uniMap.put(uni.id(), uni);
+            }
+        });
+    }
+
+    /**
+     * Returns all potential LTPs.
+     *
+     * @return set of all potential LTPs
+     * */
+    public Set<CarrierEthernetLogicalTerminationPoint> getGlobalLtps() {
+
+        CarrierEthernetLogicalTerminationPoint ltp;
+        CarrierEthernetUni uni;
+        CarrierEthernetInni inni;
+        Set<CarrierEthernetLogicalTerminationPoint> ltpSet = new HashSet<>();
+        // Generate the device ID/port number identifiers
+        for (Device device : deviceService.getDevices()) {
+            for (Port port : deviceService.getPorts(device.id())) {
+                // Consider only physical ports which are currently active
+                if (!port.number().isLogical() && port.isEnabled()) {
+                    String cpString = device.id().toString() + "/" + port.number();
+                    ConnectPoint cp = ConnectPoint.deviceConnectPoint(cpString);
+                    // Add LTP associated with generated connect point only if it belongs to a packet switch
+                    if (device.type().equals(Device.Type.SWITCH)) {
+                        // Add a UNI associated with generated connect point only if it doesn't belong to any link
+                        if (linkService.getEgressLinks(cp).isEmpty() && linkService.getIngressLinks(cp).isEmpty()) {
+                            uni = new CarrierEthernetUni(cp, cpString, null, null, null);
+                            ltp = new CarrierEthernetLogicalTerminationPoint(cpString, uni);
+                        } else {
+                            inni = new CarrierEthernetInni(cp, cpString, null, null, null, null);
+                            ltp = new CarrierEthernetLogicalTerminationPoint(cpString, inni);
+                        }
+                        ltpSet.add(ltp);
+                    }
+                }
+            }
+        }
+        return ltpSet;
+    }
+
+    /**
+     * Adds a set of potential LTPs and their UNIs to the global LTP/UNI maps if they are not already there.
+     *
+     * @param ltpSet set of potential LTPs to add to global LTP map
+     * */
+    public void addGlobalLtps(Set<CarrierEthernetLogicalTerminationPoint> ltpSet) {
+        ltpSet.forEach(ltp -> {
+            // Add LTP only if it's not already there
+            if (!ltpMap.containsKey(ltp.id())) {
+                ltpMap.put(ltp.id(), ltp);
+            }
+            // If LTP contains a UNI, add it only if it's not already there
+            if (ltp.ni() != null && ltp.ni() instanceof CarrierEthernetUni) {
+                if (!uniMap.containsKey(ltp.ni().id())) {
+                    uniMap.put(ltp.ni().id(), (CarrierEthernetUni) ltp.ni());
+                }
+            }
+            // TODO: Add LTPs
+        });
     }
 
     /**
@@ -597,7 +872,7 @@
         MetroConnectivityId metroConnectId = metroPathService.setupConnectivity(ingress, egress, bandwidth, latency);
         if (metroConnectId != null) {
             long startTime = System.currentTimeMillis();
-            while (((System.currentTimeMillis() - startTime) < METRO_CONNECT_TIMEOUT_MILLIS) &&
+            while (((System.currentTimeMillis() - startTime) < (long) METRO_CONNECT_TIMEOUT_MILLIS) &&
                     (metroConnectStatusMap.get(metroConnectId) != MetroPathEvent.Type.PATH_INSTALLED)) {
             }
         }
@@ -608,7 +883,7 @@
         if (metroConnectId != null) {
             metroPathService.removeConnectivity(metroConnectId);
             long startTime = System.currentTimeMillis();
-            while (((System.currentTimeMillis() - startTime) < METRO_CONNECT_TIMEOUT_MILLIS) &&
+            while (((System.currentTimeMillis() - startTime) < (long) METRO_CONNECT_TIMEOUT_MILLIS) &&
                     (metroConnectStatusMap.get(metroConnectId) != MetroPathEvent.Type.PATH_REMOVED)) {
             }
         }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetMetroConnectivity.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetMetroConnectivity.java
new file mode 100644
index 0000000..d2a611f
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetMetroConnectivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onosproject.ecord.metro.api.MetroConnectivityId;
+import org.onosproject.ecord.metro.api.MetroPathEvent;
+
+/**
+ * Represents a metro optical connection.
+ */
+
+class CarrierEthernetMetroConnectivity {
+
+    // TODO: In the future this may be replaced by a connectivity intent
+    // FIXME: Need to keep a set of MetroConnectivityIds
+
+    private MetroConnectivityId id;
+    private MetroPathEvent.Type status;
+
+    public CarrierEthernetMetroConnectivity(MetroConnectivityId id, MetroPathEvent.Type status) {
+        this.id = id;
+        this.status = status;
+    }
+
+    public MetroConnectivityId id() {
+        return this.id;
+    }
+
+    public MetroPathEvent.Type status() {
+        return this.status;
+    }
+
+    public void setId(MetroConnectivityId id) {
+        this.id = id;
+    }
+
+    public void setStatus(MetroPathEvent.Type status) {
+        this.status = status;
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetNetworkInterface.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetNetworkInterface.java
new file mode 100644
index 0000000..4cb178e
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetNetworkInterface.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onlab.util.Bandwidth;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.device.DeviceService;
+import org.slf4j.Logger;
+
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Representation of a Carrier Ethernet Network Interface (UNI, INNI or ENNI).
+ */
+public abstract class CarrierEthernetNetworkInterface {
+
+    private final Logger log = getLogger(getClass());
+
+    protected DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
+
+    public enum Scope {
+        GLOBAL, SERVICE
+    }
+
+    protected ConnectPoint connectPoint;
+    protected String id;
+    protected String cfgId;
+    protected Bandwidth capacity;
+    protected Bandwidth usedCapacity;
+    protected Scope scope;
+
+
+    public CarrierEthernetNetworkInterface(ConnectPoint connectPoint, String cfgId) {
+        checkNotNull(connectPoint);
+        this.connectPoint = connectPoint;
+        this.id = this.connectPoint.deviceId().toString() + "/" + this.connectPoint.port().toString();
+        this.cfgId = (cfgId == null ? this.id : cfgId);
+        this.capacity = Bandwidth.mbps(deviceService.getPort(connectPoint.deviceId(), connectPoint.port())
+                .portSpeed());
+        this.usedCapacity = Bandwidth.mbps((double) 0);
+        this.scope = null;
+    }
+
+    /**
+     * Returns associated connect point.
+     *
+     * @return associated connect point
+     */
+    public ConnectPoint cp() {
+        return connectPoint;
+    }
+
+    /**
+     * Returns NI string identifier.
+     *
+     * @return NI string identifier
+     */
+    public String id() {
+        return id;
+    }
+
+    /**
+     * Returns NI string config identifier.
+     *
+     * @return NI string config identifier
+     */
+    public String cfgId() {
+        return cfgId;
+    }
+
+    /**
+     * Returns NI capacity.
+     *
+     * @return NI capacity
+     */
+    public Bandwidth capacity() {
+        return capacity;
+    }
+
+    /**
+     * Returns NI used capacity.
+     *
+     * @return NI used capacity
+     */
+    public Bandwidth usedCapacity() {
+        return usedCapacity;
+    }
+
+    /**
+     * Returns the scope of the NI (GLOBAL or SERVICE).
+     *
+     * @return NI scope
+     */
+    public Scope scope() {
+        return scope;
+    }
+
+    /**
+     * Sets NI string identifier.
+     *
+     * @param id the UNI string identifier to set
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    /**
+     * Sets NI string config identifier.
+     *
+     * @param cfgId the UNI string config identifier to set
+     */
+    public void setCfgId(String cfgId) {
+        this.cfgId = cfgId;
+    }
+
+    /**
+     * Sets NI capacity.
+     *
+     * @param capacity the capacity to set
+     */
+    public void setCapacity(Bandwidth capacity) {
+        this.capacity = capacity;
+    }
+
+    /**
+     * Returns the NI type, depending on the NI.
+     *
+     * @param <T> the NI type
+     * @return the NI type
+     */
+    public abstract <T> T role();
+
+    @Override
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", id)
+                .add("cfgId", cfgId)
+                .add("capacity", capacity)
+                .add("usedCapacity", usedCapacity).toString();
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
index 92dd5f9..2936a44 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
@@ -130,8 +130,9 @@
     protected void deactivate() {}
 
     @Override
-    public void setNodeForwarding(CarrierEthernetService service, CarrierEthernetUni srcUni, CarrierEthernetUni dstUni,
-                           ConnectPoint ingress, ConnectPoint egress, boolean first, boolean last) {
+    public void setNodeForwarding(CarrierEthernetVirtualConnection service, CarrierEthernetNetworkInterface srcNi,
+                                  CarrierEthernetNetworkInterface dstNi, ConnectPoint ingress, ConnectPoint egress,
+                                  boolean first, boolean last) {
 
         // TODO: Produce error if ingress and egress do not belong to same device
 
@@ -144,8 +145,12 @@
             flowRuleSet = new HashSet<>();
         }
 
-        flowRuleSet.addAll(createFlowRules(service.id(), srcUni.ceVlanId(), service.vlanId(),
+        // FIXME: Uncomment this after Hackathon
+        flowRuleSet.addAll(createNrpFlowRule(service.id(), srcNi, dstNi, service.vlanId(),
                 ingress, egress, first, last));
+        /*flowRuleSet.addAll(createFlowRules(service.id(), ((CarrierEthernetUni) srcNi).ceVlanId(), service.vlanId(),
+                ingress, egress, first, last));*/
+
 
         egressCpSet.add(egress);
 
@@ -154,6 +159,79 @@
 
     }
 
+    // Directly creates FlowRules using GROUP action (meant for OF1.3 non-OFDPA devices)
+    private Set<FlowRule> createNrpFlowRule(String serviceId, CarrierEthernetNetworkInterface srcNi,
+                                            CarrierEthernetNetworkInterface dstNi, VlanId vlanId,
+                                             ConnectPoint ingress, ConnectPoint egress,
+                                             boolean first, boolean last) {
+
+        Set<FlowRule> flowRuleSet = new HashSet<>();
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+                .matchInPort(ingress.port());
+
+        TrafficTreatment.Builder tBuilder;
+        if (first) {
+
+            // Decide what to do depending on the type of NI (UNI/INNI/ENNI)
+            if ((srcNi instanceof CarrierEthernetInni) || (srcNi instanceof CarrierEthernetEnni) ) {
+                VlanId sVlanId;
+                if (srcNi instanceof CarrierEthernetInni) {
+                    sVlanId = ((CarrierEthernetInni) srcNi).sVlanId();
+                } else {
+                    sVlanId = ((CarrierEthernetEnni) srcNi).sVlanId();
+                }
+                if (sVlanId != null) {
+                    sBuilder.matchVlanId(sVlanId);
+                }
+                tBuilder = DefaultTrafficTreatment.builder();
+                // Pop S-TAG if it exists and add the new one
+                // TODO: Check TPID
+                tBuilder.popVlan();
+                tBuilder.pushVlan().setVlanId(vlanId);
+            } else {
+                VlanId ceVlanId = ((CarrierEthernetUni) srcNi).ceVlanId();
+                // If this is a virtual service, match also on CE-VLAN ID at first hop
+                if (ceVlanId != null) {
+                    sBuilder.matchVlanId(ceVlanId);
+                }
+                tBuilder = DefaultTrafficTreatment.builder();
+                tBuilder.pushVlan().setVlanId(vlanId);
+            }
+        } else {
+            sBuilder.matchVlanId(vlanId);
+            tBuilder = DefaultTrafficTreatment.builder();
+        }
+
+        if (last) {
+            // If NI is not a UNI, keep the existing tags - they will be popped at the entrance of the next FC
+            if (dstNi instanceof CarrierEthernetUni) {
+                tBuilder.popVlan();
+            }
+        }
+        tBuilder.setOutput(egress.port());
+
+        // Check if flow with same selector already exists. If yes, modify existing flow rule if needed
+        flowRuleService.getFlowRulesById(appId).forEach(flowRule -> {
+            if (flowRule.deviceId().equals(egress.deviceId()) && flowRule.selector().equals(sBuilder.build())) {
+                flowRule.treatment().allInstructions().forEach(instruction -> {
+                    // If this is an OUTPUT instruction and output is different than existing, add the group
+                    if (instruction.type() == Instruction.Type.OUTPUT &&
+                            !(instruction.equals(Instructions.createOutput(egress.port())))) {
+                        tBuilder.add(instruction);
+                    }
+                });
+            }
+        });
+
+        // FIXME: For efficiency do not send FlowMod again if the new treatment is exactly the same as the existing one
+        FlowRule flowRule = createFlowRule(egress.deviceId(), PRIORITY, sBuilder.build(), tBuilder.build(), 0);
+        flowRuleService.applyFlowRules(flowRule);
+        flowRuleSet.add(flowRule);
+
+        return flowRuleSet;
+    }
+
     // FIXME: Temporary solution for establishing flow rules according to switch type
     private Set<FlowRule> createFlowRules(String serviceId, VlanId ceVlanId, VlanId vlanId,
                                           ConnectPoint ingress, ConnectPoint egress, boolean first, boolean last) {
@@ -164,7 +242,7 @@
         Set<FlowRule> flowRuleSet = new HashSet<>();
         if (sw.softwareDescription().equals("OF-DPA 2.0")) {
             flowRuleSet = createOfdpaFlowRules(serviceId, ceVlanId, vlanId, ingress, egress, first, last);
-            //createFilteringForwarding(serviceId, ceVlanId, vlanId, ingress, egress, first, last);
+            //createFilteringForwarding(evcId, ceVlanId, vlanId, ingress, egress, first, last);
         } else if (sw.factory().getVersion() == OFVersion.OF_13) {
             flowRuleSet = createOF13FlowRule(serviceId, ceVlanId, vlanId, ingress, egress, first, last);
         } else {
@@ -544,6 +622,8 @@
     @Override
     void applyBandwidthProfileResources(String serviceId, CarrierEthernetUni uni) {
 
+        log.info("Trying to apply BW profile resources for service {}", serviceId);
+
         Dpid dpid = Dpid.dpid(uni.cp().deviceId().uri());
         OpenFlowSwitch sw = controller.getSwitch(dpid);
 
@@ -735,7 +815,7 @@
     }
 
     @Override
-    void removeAllForwardingResources(CarrierEthernetService service) {
+    void removeAllForwardingResources(CarrierEthernetVirtualConnection service) {
         removeFlowRules(service.id());
         removeGroups(service);
     }
@@ -757,7 +837,7 @@
      * @param service the CE service definition
      * */
     // Note: A Group cannot be shared by multiple services since GroupIds/GroupKeys include the service VLAN ID
-    private void removeGroups(CarrierEthernetService service) {
+    private void removeGroups(CarrierEthernetVirtualConnection service) {
 
         Set<ConnectPoint> egressCpSet = egressCpMap.remove(service.id());
         Set<ConnectPoint> uniCpSet = new HashSet<>();
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeManager.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeManager.java
index 3b2b771..c833df5 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeManager.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeManager.java
@@ -22,14 +22,14 @@
  */
 public abstract class CarrierEthernetPacketNodeManager {
 
-    abstract void setNodeForwarding(CarrierEthernetService service, CarrierEthernetUni srcUni,
-                                    CarrierEthernetUni dstUni, ConnectPoint ingress, ConnectPoint egress,
+    abstract void setNodeForwarding(CarrierEthernetVirtualConnection service, CarrierEthernetNetworkInterface srcNi,
+                                    CarrierEthernetNetworkInterface dstNi, ConnectPoint ingress, ConnectPoint egress,
                                     boolean first, boolean last);
 
     abstract void applyBandwidthProfileResources(String serviceId, CarrierEthernetUni uni);
 
     abstract void removeBandwidthProfileResources(String serviceId, CarrierEthernetUni uni);
 
-    abstract void removeAllForwardingResources(CarrierEthernetService service);
+    abstract void removeAllForwardingResources(CarrierEthernetVirtualConnection service);
 
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java
index a2d993a..f4ae5e1 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java
@@ -63,16 +63,18 @@
 
     }
 
-    public boolean setupConnectivity(CarrierEthernetUni uni1, CarrierEthernetUni uni2, CarrierEthernetService service) {
+    // TODO: Get LTPs as input
+    // TODO: setNodeForwarding should be able to decide what to do depending on if some of the LTPs is a UNI
+    public boolean setupConnectivity(CarrierEthernetNetworkInterface ni1, CarrierEthernetNetworkInterface ni2, CarrierEthernetVirtualConnection service) {
 
         // Find the paths for both directions at the same time, so that we can skip the pair if needed
-        List<Link> forwardLinks = selectLinkPath(uni1, uni2, service);
-        List<Link> backwardLinks = selectLinkPath(uni2, uni1, service);
+        List<Link> forwardLinks = selectLinkPath(ni1, ni2, service);
+        List<Link> backwardLinks = selectLinkPath(ni2, ni1, service);
 
         // Skip this UNI pair if no feasible path could be found
         if (forwardLinks == null || (!service.congruentPaths() && backwardLinks == null)) {
             log.warn("There are no feasible paths between {} and {}.",
-                    uni1.cp().deviceId(), uni2.cp().deviceId());
+                    ni1.cp().deviceId(), ni2.cp().deviceId());
             return false;
         }
 
@@ -87,7 +89,7 @@
             //  TODO: Select node manager depending on device protocol
             // Set forwarding only on packet switches
             if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                ceOfPktNodeManager.setNodeForwarding(service, uni1, uni2, ingress, egress, first, last);
+                ceOfPktNodeManager.setNodeForwarding(service, ni1, ni2, ingress, egress, first, last);
             }
 
             if (service.congruentPaths()) {
@@ -96,7 +98,7 @@
                 egress = forwardLinks.get(forwardLinks.size() - i - 2).dst();
                 //  TODO: Select node manager depending on device protocol
                 if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                    ceOfPktNodeManager.setNodeForwarding(service, uni2, uni1, ingress, egress, first, last);
+                    ceOfPktNodeManager.setNodeForwarding(service, ni2, ni1, ingress, egress, first, last);
                 }
             }
         }
@@ -110,7 +112,7 @@
                 ConnectPoint egress = backwardLinks.get(i + 1).src();
                 //  TODO: Select node manager depending on device protocol
                 if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                    ceOfPktNodeManager.setNodeForwarding(service, uni2, uni1, ingress, egress, first, last);
+                    ceOfPktNodeManager.setNodeForwarding(service, ni2, ni1, ingress, egress, first, last);
                 }
             }
         }
@@ -119,21 +121,21 @@
     }
 
     /**
-     * Select a feasible link path between two UNIs based on the CE service parameters.
+     * Select a feasible link path between two NIs based on the CE service parameters.
      *
-     * @param uni1 the first UNI
-     * @param uni2 the second UNI
+     * @param ni1 the first NI
+     * @param ni2 the second NI
      * @param service the CE service descriptor
      */
-    private List<Link> selectLinkPath(CarrierEthernetUni uni1, CarrierEthernetUni uni2,
-                                      CarrierEthernetService service) {
+    private List<Link> selectLinkPath(CarrierEthernetNetworkInterface ni1, CarrierEthernetNetworkInterface ni2,
+                                      CarrierEthernetVirtualConnection service) {
 
-        List<Constraint> constraints = ImmutableList.<Constraint>builder()
+        /*List<Constraint> constraints = ImmutableList.<Constraint>builder()
                 .add(new BandwidthConstraint(uni1.bwp().cir()))
                 .add(new LatencyConstraint(service.latency()))
-                .build();
+                .build();*/
 
-        Set<Path> paths = pathService.getPaths(uni1.cp().deviceId(), uni2.cp().deviceId());
+        Set<Path> paths = pathService.getPaths(ni1.cp().deviceId(), ni2.cp().deviceId());
 
         Path path = null;
 
@@ -147,9 +149,9 @@
             return null;
         } else {
             List<Link> links = new ArrayList<>();
-            links.add(createEdgeLink(uni1.cp(), true));
+            links.add(createEdgeLink(ni1.cp(), true));
             links.addAll(path.links());
-            links.add(createEdgeLink(uni2.cp(), false));
+            links.add(createEdgeLink(ni2.cp(), false));
             return links;
         }
     }
@@ -162,7 +164,7 @@
         return i == 0;
     }
 
-    public void removeConnectivity(CarrierEthernetService service) {
+    public void removeConnectivity(CarrierEthernetVirtualConnection service) {
         // TODO: Add here the same call for all node manager types
         ceOfPktNodeManager.removeAllForwardingResources(service);
     }
@@ -172,7 +174,7 @@
      *
      * @param service the CE service definition
      */
-    public void applyBandwidthProfiles(CarrierEthernetService service) {
+    public void applyBandwidthProfiles(CarrierEthernetVirtualConnection service) {
         //  TODO: Select node manager depending on device protocol
         service.uniSet().forEach(uni -> ceOfPktNodeManager.applyBandwidthProfileResources(service.id(), uni));
     }
@@ -182,7 +184,7 @@
      *
      * @param service the CE service definition
      */
-    public void removeBandwidthProfiles(CarrierEthernetService service) {
+    public void removeBandwidthProfiles(CarrierEthernetVirtualConnection service) {
         //  TODO: Select node manager depending on device protocol
         service.uniSet().forEach(uni -> ceOfPktNodeManager.removeBandwidthProfileResources(service.id(), uni));
     }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java
deleted file mode 100644
index 4f992d4..0000000
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetService.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2016 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.ecord.carrierethernet.app;
-
-import org.onlab.packet.VlanId;
-import org.onosproject.ecord.metro.api.MetroConnectivityId;
-import org.onosproject.ecord.metro.api.MetroPathEvent;
-
-import java.time.Duration;
-import java.util.HashSet;
-import java.util.Set;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Representation of a Carrier Ethernet Service along with relevant ONOS-related resources.
- */
-public class CarrierEthernetService {
-
-    public enum Type {
-        POINT_TO_POINT, MULTIPOINT_TO_MULTIPOINT, ROOT_MULTIPOINT
-    }
-
-    protected String serviceId;
-    protected String serviceCfgId;
-    protected Type serviceType;
-    // FIXME: single vlanId is a hack for ONS2016.  CE service must store vlanId for each CO.
-    protected VlanId vlanId;
-    protected boolean isVirtual;
-    protected Set<CarrierEthernetUni> uniSet;
-    protected Duration latency;
-    protected CarrierEthernetServiceMetroConnectivity metroConnectivity;
-    protected boolean congruentPaths;
-
-    // Set to true if both directions should use the same path
-    private static final boolean CONGRUENT_PATHS = true;
-
-    private static final Duration DEFAULT_LATENCY = Duration.ofMillis(50);
-
-    // Note: serviceId should be provided only when updating an existing service
-    public CarrierEthernetService(String serviceId, String serviceCfgId, Type serviceType,
-                                  Set<CarrierEthernetUni> uniSet) {
-        this.serviceId = serviceId;
-        this.serviceCfgId = serviceCfgId;
-        this.serviceType = serviceType;
-        this.vlanId = null;
-        this.uniSet = new HashSet<>();
-        this.uniSet.addAll(uniSet);
-        this.congruentPaths = CONGRUENT_PATHS;
-        this.latency = DEFAULT_LATENCY;
-        this.metroConnectivity = new CarrierEthernetServiceMetroConnectivity(null, MetroPathEvent.Type.PATH_REMOVED);
-    }
-
-    /**
-     * Returns service identifier.
-     *
-     * @return service identifier
-     */
-    public String id() {
-        return serviceId;
-    }
-
-    /**
-     * Returns service config identifier.
-     *
-     * @return service config identifier
-     */
-    public String cfgId() {
-        return serviceCfgId;
-    }
-
-    /**
-     * Returns type of service.
-     *
-     * @return type of service
-     */
-    public Type type() {
-        return serviceType;
-    }
-
-    /**
-     * Returns Vlan id.
-     *
-     * @return Vlan id
-     */
-    public VlanId vlanId() {
-        return vlanId;
-    }
-
-    /**
-     * Returns the Virtual status of the service (i.e. if all UNIs have CE-VLAN ids).
-     *
-     * @return true if service is virtual, false otherwise
-     */
-    public boolean isVirtual() {
-        return isVirtual;
-    }
-
-    /**
-     * Returns set of UNIs.
-     *
-     * @return set of UNIs
-     */
-    public Set<CarrierEthernetUni> uniSet() {
-        return uniSet;
-    }
-
-    /**
-     * Returns latency constraint.
-     *
-     * @return latency constraint
-     */
-    public Duration latency() {
-        return latency;
-    }
-
-    /**
-     * Returns true if service requires congruent paths.
-     *
-     * @return true if congruent paths required
-     */
-    public boolean congruentPaths() {
-        return congruentPaths;
-    }
-
-    /**
-     * Sets service identifier.
-     *
-     * @param serviceId the service identifier to set
-     */
-    public void setId(String serviceId) {
-        this.serviceId = serviceId;
-    }
-
-    /**
-     * Sets service config identifier.
-     *
-     * @param serviceCfgId service config identifier
-     */
-    public void setCfgId(String serviceCfgId) {
-        this.serviceCfgId = serviceCfgId;
-    }
-
-    /**
-     * Sets the set of UNIs.
-     *
-     * @param uniSet the set of UNIs to be set
-     */
-    public void setUniSet(Set<CarrierEthernetUni> uniSet) {
-        this.uniSet = uniSet;
-    }
-
-    /**
-     * Sets the value of the congruent paths parameter.
-     *
-     * @param congruentPaths the congruent paths parameter value to set
-     */
-    public void setCongruentPaths(boolean congruentPaths) {
-        this.congruentPaths = congruentPaths;
-    }
-
-    /**
-     * Sets the vlanId to be used by the service.
-     *
-     * @param vlanId the vlanId to set
-     */
-    public void setVlanId(VlanId vlanId) {
-        this.vlanId = vlanId;
-    }
-
-    /**
-     * Sets the Virtual status of the service.
-     *
-     * @param isVirtual boolean value with the status to set
-     */
-    public void setIsVirtual(boolean isVirtual) {
-        this.isVirtual = isVirtual;
-    }
-
-    /**
-     * Gets metro connectivity id.
-     *
-     * @return the metro connectivity of the service
-     */
-    public CarrierEthernetServiceMetroConnectivity metroConnectivity() {
-        return this.metroConnectivity;
-    }
-
-    /**
-     * Sets metro connectivity id.
-     *
-     * @param id the metro connectivity identifier to set
-     */
-    public void setMetroConnectivityId(MetroConnectivityId id) {
-        this.metroConnectivity.setId(id);
-    }
-
-    /**
-     * Sets metro connectivity status.
-     *
-     * @param status the metro connectivity status
-     */
-    public void setMetroConnectivityStatus(MetroPathEvent.Type status) {
-        this.metroConnectivity.setStatus(status);
-    }
-
-    public String toString() {
-
-        return toStringHelper(this)
-                .add("id", serviceId)
-                .add("cfgId", serviceCfgId)
-                .add("type", serviceType)
-                .add("vlanId", vlanId)
-                .add("metroConnectId", (metroConnectivity.id() == null ? "null" : metroConnectivity.id().value()))
-                .add("UNIs", uniSet).toString();
-    }
-
-    class CarrierEthernetServiceMetroConnectivity {
-
-        // TODO: In the future this may be replaced by a connectivity intent
-        // FIXME: Need to keep a set of MetroConnectivityIds
-
-        private MetroConnectivityId id;
-        private MetroPathEvent.Type status;
-
-        CarrierEthernetServiceMetroConnectivity(MetroConnectivityId id, MetroPathEvent.Type status) {
-            this.id = id;
-            this.status = status;
-        }
-
-        public MetroConnectivityId id() {
-            return this.id;
-        }
-
-        public MetroPathEvent.Type status() {
-            return this.status;
-        }
-
-        public void setId(MetroConnectivityId id) {
-            this.id = id;
-        }
-
-        public void setStatus(MetroPathEvent.Type status) {
-            this.status = status;
-        }
-
-    }
-
-}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetUni.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetUni.java
index d68bd33..872cd60 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetUni.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetUni.java
@@ -17,13 +17,12 @@
 
 import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
-import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.device.DeviceService;
 import org.slf4j.Logger;
 
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.Collection;
@@ -39,23 +38,29 @@
  * 1. As a global UNI descriptor containing one or more BW profiles
  * 2. As a service-specific UNI descriptor containing a single BW profile and including a type (root, leaf)
  */
-public class CarrierEthernetUni {
+public class CarrierEthernetUni extends CarrierEthernetNetworkInterface {
 
     private final Logger log = getLogger(getClass());
 
-    protected DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
+    public enum Role {
 
-    public enum Type {
-        ROOT, LEAF
+        ROOT("Root"),
+        LEAF("Leaf");
+
+        private String value;
+
+        Role(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
     }
 
-    protected ConnectPoint connectPoint;
-    protected String uniId;
-    protected String uniCfgId;
-    protected Type type;
+    protected Role role;
     protected Set<VlanId> ceVlanIdSet;
-    protected Bandwidth capacity;
-    protected Bandwidth usedCapacity;
 
     // Note: INTERFACE BWP map can only have up to one element
     protected final Map<CarrierEthernetBandwidthProfile.Type, Map<String, CarrierEthernetBandwidthProfile>> bwpMap =
@@ -63,20 +68,16 @@
 
     // TODO: May be needed to add refCount for CoS BWPs - only applicable to global UNIs
 
-    public CarrierEthernetUni(ConnectPoint connectPoint, String uniCfgId, Type type, VlanId ceVlanId,
+    public CarrierEthernetUni(ConnectPoint connectPoint, String uniCfgId, Role role, VlanId ceVlanId,
                               CarrierEthernetBandwidthProfile bwp) {
-        // TODO: Check for null
-        this.connectPoint = connectPoint;
-        this.uniId = this.connectPoint.deviceId().toString() + "/" + this.connectPoint.port().toString();
-        this.uniCfgId = (uniCfgId == null ? this.uniId : uniCfgId);
-        this.type = type;
+        super(connectPoint, uniCfgId);
+        this.role = role;
+        // FIXME: Set the NI scope directly instead?
+        this.scope = (role == null ? Scope.GLOBAL : Scope.SERVICE);
         this.ceVlanIdSet = new HashSet<>();
         if (ceVlanId != null) {
             this.ceVlanIdSet.add(ceVlanId);
         }
-        this.capacity = Bandwidth.mbps(deviceService.getPort(connectPoint.deviceId(), connectPoint.port())
-                .portSpeed());
-        this.usedCapacity = Bandwidth.mbps((double) 0);
         for (CarrierEthernetBandwidthProfile.Type bwpType : CarrierEthernetBandwidthProfile.Type.values()) {
             this.bwpMap.put(bwpType, new HashMap<>());
         }
@@ -85,14 +86,14 @@
             // Limit the CIR of the provided bwp according to UNI capacity
             if (bwp.cir().bps() > this.capacity.bps()) {
                 log.warn("UNI {}: Limiting provided CIR ({} bps) to UNI capacity ({} bps)",
-                        this.uniId, (long) bwp.cir().bps(), this.capacity);
+                        this.id, (long) bwp.cir().bps(), this.capacity);
             }
             bwp.setCir(Bandwidth.bps(Math.min(bwp.cir().bps(), this.capacity.bps())));
 
             // Limit the EIR of the provided bwp according to the UNI capacity minus CIR
             if (bwp.eir().bps() > this.capacity.bps() - bwp.cir().bps()) {
                 log.warn("UNI {}: Limiting provided EIR ({} bps) to UNI capacity minus CIR ({} bps)",
-                        this.uniId, bwp.eir().bps(), this.capacity.bps() - bwp.cir().bps());
+                        this.id, bwp.eir().bps(), this.capacity.bps() - bwp.cir().bps());
             }
             bwp.setEir(Bandwidth.bps(Math.min(bwp.eir().bps(), this.capacity.bps() - bwp.cir().bps())));
 
@@ -101,11 +102,11 @@
     }
 
     /**
-     * Adds the resources associated with a service-specific UNI to a global UNI.
+     * Adds the resources associated with an EVC-specific UNI to a global UNI.
      *
-     * @param uni the service UNI to be added
+     * @param uni the EVC UNI to be added
      */
-    public void addServiceUni(CarrierEthernetUni uni) {
+    public void addEvcUni(CarrierEthernetUni uni) {
 
         // Add CE-VLAN ID
         if (uni.ceVlanId() != null) {
@@ -140,7 +141,7 @@
      *
      * @param uni the service UNI to be added
      */
-    public void removeServiceUni(CarrierEthernetUni uni) {
+    public void removeEvcUni(CarrierEthernetUni uni) {
 
         // Remove UNI CE-VLAN ID
         ceVlanIdSet.remove(uni.ceVlanId());
@@ -155,12 +156,12 @@
     }
 
     /**
-     * Validates whether a service-specific UNI is compatible with a global UNI.
+     * Validates whether an EVC-specific UNI is compatible with a global UNI.
      *
-     * @param uni the service-specific UNI
+     * @param uni the EVC-specific UNI
      * @return boolean value indicating whether the UNIs are compatible
      */
-    public boolean validateServiceUni(CarrierEthernetUni uni) {
+    public boolean validateEvcUni(CarrierEthernetUni uni) {
 
         // Check if the CE-VLAN ID of the UNI is already included in global UNI
         if (uni.ceVlanId() != null) {
@@ -200,39 +201,12 @@
     }
 
     /**
-     * Returns associated connect point.
+     * Returns UNI role (ROOT or LEAF) - applicable only to service-specific UNIs.
      *
-     * @return associated connect point
+     * @return UNI role
      */
-    public ConnectPoint cp() {
-        return connectPoint;
-    }
-
-    /**
-     * Returns UNI string identifier.
-     *
-     * @return UNI string identifier
-     */
-    public String id() {
-        return uniId;
-    }
-
-    /**
-     * Returns UNI string config identifier.
-     *
-     * @return UNI string config identifier
-     */
-    public String cfgId() {
-        return uniCfgId;
-    }
-
-    /**
-     * Returns UNI type (ROOT or LEAF) - applicable only to service-specific UNIs.
-     *
-     * @return UNI type
-     */
-    public Type type() {
-        return type;
+    public Role role() {
+        return role;
     }
 
     /**
@@ -259,7 +233,7 @@
 
     /**
      * Returns the first non-null BWP of the UNI found - used mainly for service-specific UNIs.
-     * Note: The Service-specific UNI representation will only have one BWP
+     * Note: The EVC-specific UNI representation will only have one BWP
      *
      * @return first non-null BWP of the UNI
      */
@@ -289,43 +263,16 @@
         return Collections.emptyList();
     }
 
-    /**
-     * Returns UNI capacity in bps.
-     *
-     * @return UNI capacity
-     */
-    public Bandwidth capacity() {
-        return capacity;
-    }
-
-    /**
-     * Sets UNI string identifier.
-     *
-     * @param uniId the UNI string identifier to set
-     */
-    public void setId(String uniId) {
-        this.uniId = uniId;
-    }
-
-    /**
-     * Sets UNI string config identifier.
-     *
-     * @param uniCfgId the UNI string config identifier to set
-     */
-    public void setCfgId(String uniCfgId) {
-        this.uniCfgId = uniCfgId;
-    }
-
     @Override
     public String toString() {
 
         return toStringHelper(this)
-                .add("id", uniId)
-                .add("cfgId", uniCfgId)
-                .add("type", type)
+                .add("id", this.id)
+                .add("cfgId", this.cfgId)
+                .add("role", role)
                 .add("ceVlanIds", ceVlanIdSet)
-                .add("capacity", capacity)
-                .add("usedCapacity", usedCapacity)
+                .add("capacity", this.capacity)
+                .add("usedCapacity", this.usedCapacity)
                 .add("bandwidthProfiles", this.bwps()).toString();
     }
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetVirtualConnection.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetVirtualConnection.java
new file mode 100644
index 0000000..3f34284
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetVirtualConnection.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.app;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.ecord.metro.api.MetroConnectivityId;
+import org.onosproject.ecord.metro.api.MetroPathEvent;
+
+import java.time.Duration;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Representation of a Carrier Ethernet Service along with relevant ONOS-related resources.
+ */
+// FIXME: Consider renaming, since it actually represents a service rather than an EVC.
+// FIXME: Term "Service" though might be confusing in the ONOS context.
+public class CarrierEthernetVirtualConnection {
+
+    public enum Type {
+
+        POINT_TO_POINT("Point_To_Point"),
+        MULTIPOINT_TO_MULTIPOINT("Multipoint_To_Multipoint"),
+        ROOT_MULTIPOINT("Root_Multipoint");
+
+        private String value;
+
+        Type(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+
+        public static Type fromString(String value) {
+            if (value != null) {
+                for (Type b : Type.values()) {
+                    if (value.equals(b.value)) {
+                        return b;
+                    }
+                }
+            }
+            throw new IllegalArgumentException("Type " + value + " is not valid");
+        }
+    }
+
+    public enum State {
+
+        ACTIVE("Active"),
+        INACTIVE("Inactive");
+
+        private String value;
+
+        State(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+
+        public static State fromString(String value) {
+            if (value != null) {
+                for (State b : State.values()) {
+                    if (value.equals(b.value)) {
+                        return b;
+                    }
+                }
+            }
+            throw new IllegalArgumentException("State " + value + " is not valid");
+        }
+    }
+
+    public enum ActiveState {
+
+        FULL("Full"),
+        PARTIAL("Partial");
+
+        private String value;
+
+        ActiveState(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    // FIXME: single vlanId is a hack for ONS2016.  CE service must store vlanId for each CO.
+    protected String evcId;
+    protected String evcCfgId;
+    protected Type evcType;
+    protected State evcState;
+    protected ActiveState evcActiveState;
+    protected VlanId vlanId;
+    protected boolean isVirtual;
+    protected Integer maxNumUni;
+    protected Set<CarrierEthernetUni> uniSet;
+    protected Duration latency;
+    protected CarrierEthernetMetroConnectivity metroConnectivity;
+    protected boolean congruentPaths;
+
+    // Set to true if both directions should use the same path
+    private static final boolean CONGRUENT_PATHS = true;
+
+    private static final Duration DEFAULT_LATENCY = Duration.ofMillis(50);
+
+    // Maximum possible number of UNIs for non-Point-to-Point EVCs
+    public static final Integer MAX_NUM_UNI = 1000;
+
+    // Note: evcId should be provided only when updating an existing service
+    public CarrierEthernetVirtualConnection(String evcId, String evcCfgId, Type evcType, Integer maxNumUni,
+                                            Set<CarrierEthernetUni> uniSet) {
+        this.evcId = evcId;
+        this.evcCfgId = evcCfgId;
+        this.evcType = evcType;
+        this.evcState = State.INACTIVE;
+        this.evcActiveState = null;
+        this.maxNumUni = (maxNumUni != null ? maxNumUni : (evcType.equals(Type.POINT_TO_POINT) ? 2 : MAX_NUM_UNI));
+        this.vlanId = null;
+        this.uniSet = new HashSet<>();
+        this.uniSet.addAll(uniSet);
+        this.congruentPaths = CONGRUENT_PATHS;
+        this.latency = DEFAULT_LATENCY;
+        this.metroConnectivity = new CarrierEthernetMetroConnectivity(null, MetroPathEvent.Type.PATH_REMOVED);
+    }
+
+    /**
+     * Returns service identifier.
+     *
+     * @return service identifier
+     */
+    public String id() {
+        return evcId;
+    }
+
+    /**
+     * Returns service config identifier.
+     *
+     * @return service config identifier
+     */
+    public String cfgId() {
+        return evcCfgId;
+    }
+
+    /**
+     * Returns type of service.
+     *
+     * @return type of service
+     */
+    public Type type() {
+        return evcType;
+    }
+
+    /**
+     * Returns connectivity state of the EVC.
+     *
+     * @return connectivity state
+     */
+    public State state() {
+        return evcState;
+    }
+
+    /**
+     * Returns active connectivity state of the EVC.
+     *
+     * @return active connectivity state
+     */
+    public ActiveState activeState() {
+        return evcActiveState;
+    }
+
+    /**
+     * Returns Vlan id.
+     *
+     * @return Vlan id
+     */
+    public VlanId vlanId() {
+        return vlanId;
+    }
+
+    /**
+     * Returns the Virtual status of the service (i.e. if all UNIs have CE-VLAN ids).
+     *
+     * @return true if service is virtual, false otherwise
+     */
+    public boolean isVirtual() {
+        return isVirtual;
+    }
+
+    /**
+     * Returns the maximum number of UNIs in the EVC.
+     *
+     * @return true the maximum number of UNIs in the EVC
+     */
+    public Integer maxNumUni() { return maxNumUni; }
+
+    /**
+     * Returns set of UNIs.
+     *
+     * @return set of UNIs
+     */
+    public Set<CarrierEthernetUni> uniSet() {
+        return uniSet;
+    }
+
+    /**
+     * Returns latency constraint.
+     *
+     * @return latency constraint
+     */
+    public Duration latency() {
+        return latency;
+    }
+
+    /**
+     * Returns true if service requires congruent paths.
+     *
+     * @return true if congruent paths required
+     */
+    public boolean congruentPaths() {
+        return congruentPaths;
+    }
+
+    /**
+     * Sets service identifier.
+     *
+     * @param serviceId the service identifier to set
+     */
+    public void setId(String serviceId) {
+        this.evcId = serviceId;
+    }
+
+    /**
+     * Sets service config identifier.
+     *
+     * @param serviceCfgId service config identifier
+     */
+    public void setCfgId(String serviceCfgId) {
+        this.evcCfgId = serviceCfgId;
+    }
+
+    /**
+     * Sets the set of UNIs.
+     *
+     * @param uniSet the set of UNIs to be set
+     */
+    public void setUniSet(Set<CarrierEthernetUni> uniSet) {
+        this.uniSet = uniSet;
+    }
+
+    /**
+     * Sets the connectivity state of the EVC.
+     *
+     * @param evcState the connectivity state to set
+     */
+    public void setState(State evcState) { this.evcState = evcState; }
+
+    /**
+     * Sets the active connectivity state of the EVC.
+     *
+     * @param evcActiveState the active connectivity state to set
+     */
+    public void setActiveState(ActiveState evcActiveState) { this.evcActiveState = evcActiveState; }
+
+    /**
+     * Sets the value of the congruent paths parameter.
+     *
+     * @param congruentPaths the congruent paths parameter value to set
+     */
+    public void setCongruentPaths(boolean congruentPaths) {
+        this.congruentPaths = congruentPaths;
+    }
+
+    /**
+     * Sets the vlanId to be used by the service.
+     *
+     * @param vlanId the vlanId to set
+     */
+    public void setVlanId(VlanId vlanId) {
+        this.vlanId = vlanId;
+    }
+
+    /**
+     * Sets the Virtual status of the service.
+     *
+     * @param isVirtual boolean value with the status to set
+     */
+    public void setIsVirtual(boolean isVirtual) {
+        this.isVirtual = isVirtual;
+    }
+
+    /**
+     * Gets metro connectivity id.
+     *
+     * @return the metro connectivity of the service
+     */
+    public CarrierEthernetMetroConnectivity metroConnectivity() {
+        return this.metroConnectivity;
+    }
+
+    /**
+     * Sets metro connectivity id.
+     *
+     * @param id the metro connectivity identifier to set
+     */
+    public void setMetroConnectivityId(MetroConnectivityId id) {
+        this.metroConnectivity.setId(id);
+    }
+
+    /**
+     * Sets metro connectivity status.
+     *
+     * @param status the metro connectivity status
+     */
+    public void setMetroConnectivityStatus(MetroPathEvent.Type status) {
+        this.metroConnectivity.setStatus(status);
+    }
+
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", evcId)
+                .add("cfgId", evcCfgId)
+                .add("type", evcType)
+                .add("vlanId", vlanId)
+                .add("metroConnectId", (metroConnectivity.id() == null ? "null" : metroConnectivity.id().value()))
+                .add("UNIs", uniSet).toString();
+    }
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateServiceCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateServiceCommand.java
index ae2d2cc..7253de2 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateServiceCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateServiceCommand.java
@@ -23,7 +23,7 @@
 import org.onlab.util.Bandwidth;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetBandwidthProfile;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
-import org.onosproject.ecord.carrierethernet.app.CarrierEthernetService;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetVirtualConnection;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetUni;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
@@ -59,6 +59,9 @@
     @Option(name = "-id", aliases = "--service-id", description = "The ID of a service to be updated" +
             " (if service does not exist, a new service will be installed)", required = false, multiValued = false)
     String argServiceId = null;
+    @Option(name = "-u", aliases = "--maxNumUni", description = "The maximum number of UNIs in the EVC",
+            required = false, multiValued = false)
+    String argMaxNumUni = null;
     @Option(name = "-c", aliases = "--cir", description = "The CIR in Mbps", required = false, multiValued = false)
     String argCir = "0";
     @Option(name = "-e", aliases = "--eir", description = "The EIR in Mbps", required = false, multiValued = false)
@@ -73,12 +76,12 @@
     @Override
     protected void execute() {
 
-        CarrierEthernetManager cem = get(CarrierEthernetManager.class);
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
 
-        CarrierEthernetService service = new CarrierEthernetService(argServiceId, argServiceCfgId,
-                generateServiceType(), generateUniSet());
+        CarrierEthernetVirtualConnection evc = new CarrierEthernetVirtualConnection(argServiceId, argServiceCfgId,
+                generateServiceType(), generateMaxNumUni(), generateUniSet());
 
-        cem.establishConnectivity(service);
+        evcManager.establishConnectivity(evc);
     }
 
     /**
@@ -95,12 +98,36 @@
      *
      * @return the CE service type
      */
-    CarrierEthernetService.Type generateServiceType() {
+    CarrierEthernetVirtualConnection.Type generateServiceType() {
         if (argServiceType == null) {
             return ((argUniList.size() > 2) ?
-                    CarrierEthernetService.Type.MULTIPOINT_TO_MULTIPOINT : CarrierEthernetService.Type.POINT_TO_POINT);
+                    CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT :
+                    CarrierEthernetVirtualConnection.Type.POINT_TO_POINT);
         } else {
-            return CarrierEthernetService.Type.valueOf(argServiceType);
+            // TODO: Catch exception
+            return CarrierEthernetVirtualConnection.Type.fromString(argServiceType);
+        }
+    }
+
+    /**
+     * Return the EVC maxNumUni parameter based on the CLI-supplied arguments.
+     *
+     * @return the maxNumUni parameter
+     */
+    Integer generateMaxNumUni() {
+        if (argMaxNumUni == null) {
+            if (argServiceType == null) {
+                return ((argUniList.size() > 2) ?
+                        CarrierEthernetVirtualConnection.MAX_NUM_UNI : 2);
+            } else {
+                // TODO: Catch exception
+                CarrierEthernetVirtualConnection.Type evcType =
+                        CarrierEthernetVirtualConnection.Type.fromString(argServiceType);
+                return (evcType.equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT) ? 2 :
+                        CarrierEthernetVirtualConnection.MAX_NUM_UNI);
+            }
+        } else {
+            return Integer.valueOf(argMaxNumUni);
         }
     }
 
@@ -135,11 +162,11 @@
 
         Set<CarrierEthernetUni> uniSet = new HashSet<>();
 
-        CarrierEthernetService.Type serviceType = generateServiceType();
+        CarrierEthernetVirtualConnection.Type serviceType = generateServiceType();
 
         // We assume that first UNI supplied is always root
         uniSet.add(new CarrierEthernetUni(ConnectPoint.deviceConnectPoint(argFirstUni), null,
-                CarrierEthernetUni.Type.ROOT, generateCeVlanId(),
+                CarrierEthernetUni.Role.ROOT, generateCeVlanId(),
                 new CarrierEthernetBandwidthProfile(
                         generateBandwidthProfileId(argFirstUni),
                         null,
@@ -150,10 +177,10 @@
                         Long.parseLong(argEbs)
                 )));
 
-        final CarrierEthernetUni.Type uniType;
+        final CarrierEthernetUni.Role uniType;
         // For E-Line and E-LAN all UNIs are roots. For E-Tree all UNIs are leafs except from one
-        uniType = ((serviceType == CarrierEthernetService.Type.ROOT_MULTIPOINT) ?
-                CarrierEthernetUni.Type.LEAF : CarrierEthernetUni.Type.ROOT);
+        uniType = ((serviceType == CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT) ?
+                CarrierEthernetUni.Role.LEAF : CarrierEthernetUni.Role.ROOT);
 
         argUniList.forEach(argUni -> uniSet.add(new CarrierEthernetUni(ConnectPoint.deviceConnectPoint(argUni), null,
                 uniType, generateCeVlanId(),
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListLtpsCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListLtpsCommand.java
new file mode 100644
index 0000000..da642c6
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListLtpsCommand.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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.ecord.carrierethernet.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetLogicalTerminationPoint;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+import org.onosproject.cli.AbstractShellCommand;
+
+import java.util.Collection;
+
+/**
+ * CLI command for listing all CE LTPs.
+ */
+@Command(scope = "onos", name = "ce-ltp-list",
+        description = "Lists all Carrier Ethernet LTPs.")
+public class CarrierEthernetListLtpsCommand extends AbstractShellCommand {
+
+    @Override
+    protected void execute() {
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        // Populate global LTP map
+        evcManager.addGlobalLtps(evcManager.getGlobalLtps());
+        printLtps(evcManager.getLtpMap().values());
+    }
+
+    private void printLtps(Collection<CarrierEthernetLogicalTerminationPoint> ltps) {
+        ltps.forEach(ltp -> print("  %s", ltp));
+    }
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListServicesCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListServicesCommand.java
index ee1dbc1..9861732 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListServicesCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListServicesCommand.java
@@ -17,7 +17,7 @@
 
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
-import org.onosproject.ecord.carrierethernet.app.CarrierEthernetService;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetVirtualConnection;
 import org.onosproject.cli.AbstractShellCommand;
 
 import java.util.Collection;
@@ -31,11 +31,11 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager cem = get(CarrierEthernetManager.class);
-        printServices(cem.serviceMap().values());
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        printServices(evcManager.evcMap().values());
     }
 
-    private void printServices(Collection<CarrierEthernetService> services) {
+    private void printServices(Collection<CarrierEthernetVirtualConnection> services) {
         services.forEach(service -> print("  %s", service));
     }
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListUnisCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListUnisCommand.java
index 71ca648..2904602 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListUnisCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListUnisCommand.java
@@ -31,10 +31,10 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager cem = get(CarrierEthernetManager.class);
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
         // Populate global UNI map
-        cem.addGlobalUnis();
-        printUnis(cem.getUniMap().values());
+        evcManager.addGlobalUnis(evcManager.getGlobalUnis());
+        printUnis(evcManager.getUniMap().values());
     }
 
     private void printUnis(Collection<CarrierEthernetUni> unis) {
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllServicesCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllServicesCommand.java
index 0232e82..201a2b8 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllServicesCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllServicesCommand.java
@@ -28,7 +28,7 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager cem = get(CarrierEthernetManager.class);
-        cem.removeAllServices();
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        evcManager.removeAllEvcs();
     }
 }
\ No newline at end of file
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveServiceCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveServiceCommand.java
index 1c088cb..7e9b156 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveServiceCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveServiceCommand.java
@@ -32,7 +32,7 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager cem = get(CarrierEthernetManager.class);
-        cem.removeService(argServiceId);
+        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        evcManager.removeEvc(argServiceId);
     }
 }
\ No newline at end of file
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceIdCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceIdCompleter.java
index 7ebc192..d712882 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceIdCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceIdCompleter.java
@@ -28,9 +28,9 @@
     public int complete(String buffer, int cursor, List<String> candidates) {
 
         StringsCompleter delegate = new StringsCompleter();
-        CarrierEthernetManager cem = AbstractShellCommand.get(CarrierEthernetManager.class);
+        CarrierEthernetManager evcManager = AbstractShellCommand.get(CarrierEthernetManager.class);
         SortedSet<String> strings = delegate.getStrings();
-        cem.serviceMap().keySet().forEach(serviceId -> strings.add(serviceId));
+        evcManager.evcMap().keySet().forEach(serviceId -> strings.add(serviceId));
         return delegate.complete(buffer, cursor, candidates);
     }
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceTypeCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceTypeCompleter.java
index 0499cf8..e97617a 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceTypeCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetServiceTypeCompleter.java
@@ -17,6 +17,7 @@
 
 import org.apache.karaf.shell.console.Completer;
 import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetVirtualConnection;
 
 import java.util.List;
 import java.util.SortedSet;
@@ -29,9 +30,9 @@
 
         SortedSet<String> strings = delegate.getStrings();
 
-        strings.add("POINT_TO_POINT");
-        strings.add("MULTIPOINT_TO_MULTIPOINT");
-        strings.add("ROOT_MULTIPOINT");
+        for (CarrierEthernetVirtualConnection.Type type : CarrierEthernetVirtualConnection.Type.values()) {
+            strings.add(type.toString());
+        }
 
         return delegate.complete(buffer, cursor, candidates);
     }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetUniCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetUniCompleter.java
index f8d6f03..3bf10ac 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetUniCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetUniCompleter.java
@@ -18,11 +18,7 @@
 import org.apache.karaf.shell.console.Completer;
 import org.apache.karaf.shell.console.completer.StringsCompleter;
 import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.Port;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.link.LinkService;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
 
 import java.util.List;
 import java.util.SortedSet;
@@ -38,26 +34,11 @@
 
         StringsCompleter delegate = new StringsCompleter();
 
-        LinkService linkService = AbstractShellCommand.get(LinkService.class);
-        DeviceService service = AbstractShellCommand.get(DeviceService.class);
+        CarrierEthernetManager evcManager =
+                AbstractShellCommand.get(CarrierEthernetManager.class);
 
-        // Generate the device ID/port number identifiers
-        for (Device device : service.getDevices()) {
-            SortedSet<String> strings = delegate.getStrings();
-            for (Port port : service.getPorts(device.id())) {
-                // Consider only physical ports which are currently active
-                if (!port.number().isLogical() && port.isEnabled()) {
-                    String cpString = device.id().toString() + "/" + port.number();
-                    ConnectPoint cp = ConnectPoint.deviceConnectPoint(cpString);
-                    // Add the generated connect point only if it doesn't belong to any link
-                    // and if the device is a packet switch
-                    if (linkService.getEgressLinks(cp).isEmpty() && linkService.getIngressLinks(cp).isEmpty() &&
-                            device.type().equals(Device.Type.SWITCH)) {
-                        strings.add(cpString);
-                    }
-                }
-            }
-        }
+        SortedSet<String> strings = delegate.getStrings();
+        evcManager.getGlobalUnis().forEach(uni -> strings.add(uni.id()));
 
         return delegate.complete(buffer, cursor, candidates);
     }
diff --git a/ecord/carrierethernet/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/ecord/carrierethernet/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 886a712..c9b8ca8 100644
--- a/ecord/carrierethernet/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/ecord/carrierethernet/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -50,6 +50,12 @@
 
     <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
         <command>
+            <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetListLtpsCommand"/>
+        </command>
+    </command-bundle>
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
             <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetListUnisCommand"/>
         </command>
     </command-bundle>