Application for installing MEF services in ONOS

- Added CLI commands for installing/showing/removing ForwardingConstructs
- Addressed most of review comments from Change 8799
- Some refactoring here and there

Change-Id: I2ff067bf87f3810bd713b49cf3ac9b17b2fe6df1
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
index 7b776a0..41c57fa 100644
--- 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
@@ -15,6 +15,7 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.collect.Sets;
 import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.ConnectPoint;
@@ -24,7 +25,6 @@
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static org.slf4j.LoggerFactory.getLogger;
 
-import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -64,7 +64,7 @@
         super(connectPoint, uniCfgId);
         // TODO: Check for null
         this.role = role;
-        this.sVlanIdSet = new HashSet<>();
+        this.sVlanIdSet = Sets.newConcurrentHashSet();
         // The following applies only to service-specific ENNIs
         if (sVlanId != null) {
             this.sVlanIdSet.add(sVlanId);
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
index 85fcd2c..d8f9014 100644
--- 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
@@ -28,16 +28,63 @@
  */
 public class CarrierEthernetForwardingConstruct {
 
+    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;
+        }
+    }
+
     protected String fcId;
     protected String fcCfgId;
     protected String evcId;
     protected CarrierEthernetVirtualConnection.Type evcType;
     protected Set<CarrierEthernetLogicalTerminationPoint> ltpSet;
+    protected CarrierEthernetForwardingConstruct.State state;
+    protected CarrierEthernetForwardingConstruct.ActiveState activeState;
     protected Duration latency;
     protected CarrierEthernetMetroConnectivity metroConnectivity;
     protected boolean congruentPaths;
 
-    // FIXME: Temporary solution
+    // FIXME: Find a better way
     protected CarrierEthernetVirtualConnection evcLite;
 
     // Set to true if both directions should use the same path
@@ -54,13 +101,14 @@
         this.fcCfgId = (fcCfgId == null? fcId : fcCfgId);
         this.evcId = evcId;
         this.evcType = evcType;
-        this.ltpSet = new HashSet<>();
-        this.ltpSet.addAll(ltpSet);
+        this.state = State.INACTIVE;
+        this.ltpSet = new HashSet<>(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
+        // FIXME: This is (probably) just a 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) {
@@ -111,13 +159,29 @@
     }
 
     /**
+     * Returns connectivity state of the FC.
+     *
+     * @return connectivity state
+     */
+    public State state() {
+        return state;
+    }
+
+    /**
+     * Returns active connectivity state of the FC.
+     *
+     * @return active connectivity state
+     */
+    public ActiveState activeState() {
+        return activeState;
+    }
+
+    /**
      * Returns the "EVC" associated with FC.
      *
      * @return the "EVC" associated with FC
      */
-    public CarrierEthernetVirtualConnection evcLite() {
-        return evcLite;
-    }
+    public CarrierEthernetVirtualConnection evcLite() { return evcLite; }
 
     /**
      * Sets the id of the FC.
@@ -128,4 +192,27 @@
         this.fcId = id;
     }
 
+    /**
+     * Sets the set of LTPs.
+     *
+     * @param ltpSet the set of LTPs to be set
+     */
+    public void setLtpSet(Set<CarrierEthernetLogicalTerminationPoint> ltpSet) {
+        this.ltpSet = ltpSet;
+    }
+
+    /**
+     * Sets the connectivity state of the FC.
+     *
+     * @param state the connectivity state to set
+     */
+    public void setState(State state) { this.state = state; }
+
+    /**
+     * Sets the active connectivity state of the FC.
+     *
+     * @param activeState the active connectivity state to set
+     */
+    public void setActiveState(ActiveState activeState) { this.activeState = activeState; }
+
 }
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
index 5dace45..a195bc1 100644
--- 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
@@ -15,6 +15,8 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.ConnectPoint;
@@ -24,7 +26,6 @@
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static org.slf4j.LoggerFactory.getLogger;
 
-import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -60,15 +61,13 @@
     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<>();
+        this.sVlanIdSet = Sets.newConcurrentHashSet();
         // The following applies only to service-specific INNIs
         if (sVlanId != null) {
             this.sVlanIdSet.add(sVlanId);
@@ -163,7 +162,7 @@
      * @return S-VLAN id set
      */
     public Set<VlanId> sVlanIdSet() {
-        return sVlanIdSet;
+        return ImmutableSet.copyOf(sVlanIdSet);
     }
 
     /**
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
index ba079d4..a94c885 100644
--- 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
@@ -64,16 +64,17 @@
     public CarrierEthernetLogicalTerminationPoint(String ltpCfgId, CarrierEthernetNetworkInterface ni) {
         checkNotNull(ni);
         this.ni = ni;
+        // NOTE: Role is expected to be null for service-specific LTPs/NIs
         if (ni instanceof CarrierEthernetUni) {
             this.type = Type.UNI;
+            this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetUni) ni).role().name()));
         } else if (ni instanceof CarrierEthernetInni) {
             this.type = Type.INNI;
+            this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetInni) ni).role().name()));
         } else {
-        this.type = Type.ENNI;
+            this.type = Type.ENNI;
+            this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetEnni) ni).role().name()));
         }
-        // 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);
     }
@@ -147,7 +148,7 @@
                 .add("id", ltpId)
                 .add("cfgId", ltpCfgId)
                 .add("role", role)
-                .add("uni", ni).toString();
+                .add("ni", 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 9660ee9..610be32 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
@@ -50,6 +50,7 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -93,10 +94,11 @@
     private NetworkConfigListener netcfgListener = new InternalNetworkConfigListener();
 
     // Keeps track of the next S-VLAN tag the app will try to use
-    private static short curVlanId = 0;
+    private static short nextVlanId = 1;
 
     private static final int METRO_CONNECT_TIMEOUT_MILLIS = 7000;
 
+    // If set to false, the setup of optical connectivity using the metro app is bypassed
     private static final boolean PACKET_OPTICAL_TOPO = false;
 
     // TODO: Implement distributed store for EVCs
@@ -179,7 +181,7 @@
      *
      * @return the FC map
      */
-    public Map<String, CarrierEthernetForwardingConstruct> getFcMap() {
+    public Map<String, CarrierEthernetForwardingConstruct> fcMap() {
         return fcMap;
     }
 
@@ -274,11 +276,11 @@
                     log.warn("UNI {} could not be added to EVC.", uni.id());
                     continue;
                 } else {
-                    // Add UNI to evc description
+                    // Add UNI to EVC
                     validatedUniSet.add(uni);
                 }
             } else {
-                // Add UNI to EVC description
+                // Add UNI to EVC
                 validatedUniSet.add(uni);
             }
         }
@@ -291,17 +293,13 @@
             return null;
         }
 
-        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT) && (evc.uniSet().size() < 2)) {
+        if ((evc.type().equals(CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT)
+                || evc.type().equals(CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT))
+                && (evc.uniSet().size() < 2)) {
             log.error("{} EVC requires at least two UNIs.", evc.type().name());
             return null;
         }
 
-        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;
-        }
-
         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;
@@ -313,20 +311,19 @@
     /**
      * Establish connectivity according to the EVC type (E-Line, E-Tree, E-LAN) and the EVC parameters.
      *
-     * @param originalEvc the EVC representation
-     * @return the EVC active state (FULL or PARTIAL) or null if EVC connectivity could not be established
+     * @param evc the EVC representation
+     * @return the (potentially modified) EVC that was installed or null if EVC connectivity could not be established
      */
-    public CarrierEthernetVirtualConnection.ActiveState establishConnectivity(
-            CarrierEthernetVirtualConnection originalEvc) {
+    public CarrierEthernetVirtualConnection establishConnectivity(CarrierEthernetVirtualConnection evc) {
 
         // If EVC already exists, remove it and reestablish with new parameters
-        if (originalEvc.id() != null && evcMap.containsKey(originalEvc.id())) {
-            return updateEvc(originalEvc);
+        if (evc.id() != null && evcMap.containsKey(evc.id())) {
+            return updateEvc(evc);
         } else {
-            originalEvc.setId(null);
+            evc.setId(null);
         }
 
-        CarrierEthernetVirtualConnection evc = validateEvc(originalEvc);
+        validateEvc(evc);
 
         if (evc == null) {
             log.error("EVC could not be installed, please check log for details.");
@@ -341,16 +338,16 @@
         // Temporary set for indicating which UNIs were finally included in the EVC
         Set<CarrierEthernetUni> usedUniSet = new HashSet<>();
 
-        Iterator<CarrierEthernetUni> it1 = uniSet.iterator();
-        while (it1.hasNext()) {
+        Iterator<CarrierEthernetUni> uniIt1 = uniSet.iterator();
+        while (uniIt1.hasNext()) {
 
-            CarrierEthernetUni uni1 = it1.next();
+            CarrierEthernetUni uni1 = uniIt1.next();
 
             // Iterate through all the remaining UNIs
-            Iterator<CarrierEthernetUni> it2 = uniSet.iterator();
-            while (it2.hasNext()) {
+            Iterator<CarrierEthernetUni> uniIt2 = uniSet.iterator();
+            while (uniIt2.hasNext()) {
 
-                CarrierEthernetUni uni2 = it2.next();
+                CarrierEthernetUni uni2 = uniIt2.next();
 
                 // Skip equals
                 if (uni1.equals(uni2)) {
@@ -409,7 +406,7 @@
                 usedUniSet.add(uni2);
             }
             // Remove UNI from temporary set so that each pair is visited only once
-            it1.remove();
+            uniIt1.remove();
         }
 
         // Update the EVC UNI set, based on the UNIs actually used
@@ -431,16 +428,16 @@
             }
         }
 
-        return evc.activeState();
+        return evc;
     }
 
     /**
      * Reestablish connectivity for an existing EVC.
      *
-     * @param originalEvc the updated CE evc definition
-     * @return boolean value indicating whether the EVC could be established even partially
+     * @param originalEvc the updated EVC definition
+     * @return the (potentially modified) EVC that was installed or null if EVC connectivity could not be established
      */
-    public CarrierEthernetVirtualConnection.ActiveState updateEvc(CarrierEthernetVirtualConnection originalEvc) {
+    public CarrierEthernetVirtualConnection updateEvc(CarrierEthernetVirtualConnection originalEvc) {
         // Just checking again
         if (evcMap.containsKey(originalEvc.id())) {
             log.info("Updating existing EVC {}", originalEvc.id());
@@ -492,9 +489,9 @@
     }
 
     /**
-     * Removes all resources associated with the application.
+     * Removes all installed EVCs and the associated resources.
      *
-     * This will be called either from the deactivate method or as a response to a CLI command.
+     * This will be called either from the deactivate method or as a response to a CLI/REST command.
      * */
     public void removeAllEvcs() {
         evcMap.keySet().forEach(evcId -> {
@@ -503,12 +500,14 @@
             cePktProvisioner.removeBandwidthProfiles(evc);
             removeMetroConnectivity(evc.metroConnectivity().id());
             removeBandwidthProfiles(evcId);
+            // Avoid excessively incrementing VLAN ids
+            nextVlanId = evc.vlanId().toShort();
         });
         evcMap.clear();
     }
 
     /**
-     * Removes all resources associated with a specific EVC.
+     * Removes all resources associated with a specific installed EVC.
      *
      * @param evcId the EVC id
      * */
@@ -519,18 +518,20 @@
             cePktProvisioner.removeBandwidthProfiles(evc);
             removeMetroConnectivity(evc.metroConnectivity().id());
             removeBandwidthProfiles(evcId);
+            // Avoid excessively incrementing VLAN ids
+            nextVlanId = evc.vlanId().toShort();
             evcMap.remove(evcId);
         }
     }
 
     // FIXME: Rethink this approach
     /**
-     * Installs all resources associated with a specific FC.
+     * Verify the validity of an FC representation taking also into account current network status.
      *
-     * @param fc the FC to install
-     * @return the FC that was installed
-     * */
-    public CarrierEthernetForwardingConstruct installFc(CarrierEthernetForwardingConstruct fc) {
+     * @param fc the provided FC representation
+     * @return a valid, potentially modified FC representation, or null if the FC could not be validated
+     */
+    private CarrierEthernetForwardingConstruct validateFc(CarrierEthernetForwardingConstruct fc) {
 
         // Try to set a unique VLAN id for the FC unless the EVC is being updated
         // TODO: Add different connectivity types
@@ -591,10 +592,54 @@
             }
         }
 
-        // Temporary set for iterating through EVC NI pairs
+        // TODO: Add validation for INNIs/ENNIs as well
+
+        // Update the FC LTP set, based on the UNIs actually used
+        Set<CarrierEthernetLogicalTerminationPoint> validatedLtpSet = new HashSet<>();
+        Iterator<CarrierEthernetLogicalTerminationPoint> ltpIt = fc.ltpSet().iterator();
+        while(ltpIt.hasNext()) {
+            CarrierEthernetLogicalTerminationPoint ltp = ltpIt.next();
+            if ((ltp.ni() instanceof CarrierEthernetUni) && (!validatedUniSet.contains(ltp.ni()))) {
+                continue;
+            }
+            validatedLtpSet.add(ltp);
+        }
+        fc.setLtpSet(validatedLtpSet);
+
+        return fc;
+    }
+
+    // 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) {
+
+        // If FC already exists, remove it and reestablish with new parameters
+        if (fc.id() != null && fcMap.containsKey(fc.id())) {
+            return updateFc(fc);
+        } else {
+            fc.setId(null);
+        }
+
+        validateFc(fc);
+
+        if (fc == null) {
+            log.error("FC could not be installed, please check log for details.");
+            return null;
+        }
+
+        boolean allPairsConnected = true;
+
+        // Temporary set for iterating through FC NI pairs
 
         Set<CarrierEthernetNetworkInterface> niSet = new HashSet<>();
-        fc.ltpSet().forEach(ltp -> niSet.add(ltp.ni()));
+        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<>();
@@ -610,8 +655,6 @@
 
                 CarrierEthernetNetworkInterface ni2 = it2.next();
 
-                log.info("Trying to establish connectivity between {} and {}", ni1.id(), ni2.id());
-
                 // Skip equals
                 if (ni1.equals(ni2)) {
                     continue;
@@ -624,9 +667,13 @@
 
                 if (!cePktProvisioner.setupConnectivity(ni1, ni2, fc.evcLite())) {
                     log.warn("Could not set up packet connectivity between {} and {}", ni1, ni2);
+                    allPairsConnected = false;
                     continue;
                 }
 
+                // Indicate that connection for at least one LTP pair has been established
+                fc.setState(CarrierEthernetForwardingConstruct.State.ACTIVE);
+
                 // Add UNIs to the set of UNIs used by the EVC
                 usedNiSet.add(ni1);
                 usedNiSet.add(ni2);
@@ -635,21 +682,53 @@
             it1.remove();
         }
 
-        // TODO: Update the EVC NI set, based on the NIs actually used
-        //fc.setNiSet(usedNiSet);
-        // Also update the corresponding evcLite
+        // Update the FC LTP set, based on the NIs actually used
+        Set<CarrierEthernetLogicalTerminationPoint> usedLtpSet = new HashSet<>();
+        fc.ltpSet().forEach(ltp -> {
+            if (usedNiSet.contains(ltp.ni())) {
+                usedLtpSet.add(ltp);
+            }
+        });
+        fc.setLtpSet(usedLtpSet);
 
-        // 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());
+        // If no pair was connected, do not register the FC
+        if (fc.state().equals(CarrierEthernetForwardingConstruct.State.ACTIVE)) {
+            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());
+        }
+
+        if (fc.state().equals(CarrierEthernetForwardingConstruct.State.ACTIVE)) {
+            if (allPairsConnected) {
+                fc.setActiveState(CarrierEthernetForwardingConstruct.ActiveState.FULL);
+            } else {
+                fc.setActiveState(CarrierEthernetForwardingConstruct.ActiveState.PARTIAL);
+            }
+        }
 
         return fc;
     }
 
     /**
+     * Reestablish connectivity for an existing FC.
+     *
+     * @param fc the updated FC representation
+     * @return the possibly modified FC that was installed or null if updated FC could not be installed
+     */
+    public CarrierEthernetForwardingConstruct updateFc(CarrierEthernetForwardingConstruct fc) {
+        // Just checking again
+        if (fcMap.containsKey(fc.id())) {
+            log.info("Updating existing FC {}", fc.id());
+            // Keep the VLAN ID of the original FC
+            fc.evcLite().setVlanId(fcMap.get(fc.id()).evcLite().vlanId());
+            removeFc(fc.id());
+        }
+        return installFc(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.
@@ -681,37 +760,25 @@
      * */
     public VlanId generateVlanId() {
 
-        Set<VlanId> vlanIdSet = new HashSet<>();
-        VlanId vlanId = null;
-
-        evcMap.values().forEach(evc -> vlanIdSet.add(evc.vlanId));
+        List<VlanId> vlanList = evcMap.values().stream().map(CarrierEthernetVirtualConnection::vlanId)
+                .collect(Collectors.toList());
 
         // If all vlanIds are being used return null, else try to find the next available one
-        if (vlanIdSet.size() <  VlanId.MAX_VLAN - 1) {
-            do {
-                curVlanId = nextValidShort(curVlanId);
-                vlanId = VlanId.vlanId(curVlanId);
+        if (vlanList.size() <  VlanId.MAX_VLAN - 1) {
+            while (vlanList.contains(VlanId.vlanId(nextVlanId))) {
+                // Get next valid short
+                nextVlanId = (nextVlanId >= VlanId.MAX_VLAN || nextVlanId <= 0 ? 1 : (short) (nextVlanId + 1));
             }
-            while (vlanIdSet.contains(vlanId));
         }
 
-        return vlanId;
-    }
-
-    private short nextValidShort(short i) {
-
-        if (i >= VlanId.MAX_VLAN || i <= 0) {
-            return 1;
-        } else {
-            return (short) (i + 1);
-        }
+        return (vlanList.contains(VlanId.vlanId(nextVlanId)) ? null : VlanId.vlanId(nextVlanId));
     }
 
     /**
-     * Generates a unique id in the context of the CE app.
+     * Generates a unique EVC id in the context of the CE app.
      *
      * @param evc the EVC representation
-     * @return the generated vlanId or null if none found
+     * @return the generated EVC id or null if none found
      * */
     public String generateEvcId(CarrierEthernetVirtualConnection evc) {
 
@@ -829,7 +896,6 @@
                     uniMap.put(ltp.ni().id(), (CarrierEthernetUni) ltp.ni());
                 }
             }
-            // TODO: Add LTPs
         });
     }
 
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
index 4cb178e..45ffb9d 100644
--- 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
@@ -15,6 +15,7 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.base.Objects;
 import org.onlab.util.Bandwidth;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
@@ -157,4 +158,21 @@
                 .add("usedCapacity", usedCapacity).toString();
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        CarrierEthernetNetworkInterface that = (CarrierEthernetNetworkInterface) o;
+        return Objects.equal(connectPoint, that.connectPoint);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(connectPoint);
+    }
+
 }
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 872cd60..a625e57 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
@@ -15,6 +15,8 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
 import org.onosproject.net.ConnectPoint;
@@ -28,7 +30,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -74,7 +75,7 @@
         this.role = role;
         // FIXME: Set the NI scope directly instead?
         this.scope = (role == null ? Scope.GLOBAL : Scope.SERVICE);
-        this.ceVlanIdSet = new HashSet<>();
+        this.ceVlanIdSet = Sets.newConcurrentHashSet();
         if (ceVlanId != null) {
             this.ceVlanIdSet.add(ceVlanId);
         }
@@ -144,7 +145,9 @@
     public void removeEvcUni(CarrierEthernetUni uni) {
 
         // Remove UNI CE-VLAN ID
-        ceVlanIdSet.remove(uni.ceVlanId());
+        if (uni.ceVlanId() != null) {
+            ceVlanIdSet.remove(uni.ceVlanId());
+        }
 
         // Remove UNI BWP
         CarrierEthernetBandwidthProfile bwp = uni.bwp();
@@ -228,7 +231,7 @@
      * @return CE-VLAN id set
      */
     public Set<VlanId> ceVlanIdSet() {
-        return ceVlanIdSet;
+        return ImmutableSet.copyOf(ceVlanIdSet);
     }
 
     /**
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
index 3f34284..cc2649a 100644
--- 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
@@ -15,6 +15,7 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import com.google.common.collect.ImmutableSet;
 import org.onlab.packet.VlanId;
 import org.onosproject.ecord.metro.api.MetroConnectivityId;
 import org.onosproject.ecord.metro.api.MetroPathEvent;
@@ -138,8 +139,7 @@
         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.uniSet = new HashSet<>(uniSet);
         this.congruentPaths = CONGRUENT_PATHS;
         this.latency = DEFAULT_LATENCY;
         this.metroConnectivity = new CarrierEthernetMetroConnectivity(null, MetroPathEvent.Type.PATH_REMOVED);
@@ -221,7 +221,7 @@
      * @return set of UNIs
      */
     public Set<CarrierEthernetUni> uniSet() {
-        return uniSet;
+        return ImmutableSet.copyOf(uniSet);
     }
 
     /**
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateFcCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateFcCommand.java
new file mode 100644
index 0000000..d6260e2
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetCreateFcCommand.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.cli;
+
+import com.google.common.collect.Lists;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Bandwidth;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.*;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * CLI command for generating Carrier Ethernet Forwarding Constructs.
+ */
+@Command(scope = "onos", name = "ce-fc-create",
+        description = "Creates and installs a Carrier Ethernet Forwarding Construct.")
+public class CarrierEthernetCreateFcCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "argFcCfgId",
+            description = "Service configuration ID", required = true, multiValued = false)
+    String argFcCfgId = null;
+    @Argument(index = 1, name = "argEvcType", description =
+            "Service type (defaults to POINT_TO_POINT or MULTIPOINT_TO_MULTIPOINT, depending on number of LTPs)",
+            required = false, multiValued = false)
+    String argEvcType = null;
+    @Argument(index = 2, name = "argFirstLtp", description =
+            "First LTP in list (if point to multipoint, this is the root)", required = true, multiValued = false)
+    String argFirstLtp = null;
+    @Argument(index = 3, name = "argLtpList",
+            description = "List of remaining LTPs (if point to multipoint, these are the leaves)",
+            required = true, multiValued = true)
+    List<String> argLtpList = Lists.newArrayList();
+    @Option(name = "-v", aliases = "--cevlan", description = "CE-VLAN ID (applied to all UNIs)",
+            required = false, multiValued = false)
+    String argCeVlanId = null;
+    @Option(name = "-s", aliases = "--svlan", description = "S-TAG (applied to all INNIs/ENNIs)",
+            required = false, multiValued = false)
+    String argsTag = null;
+    @Option(name = "-id", aliases = "--fc-id", description = "The ID of an FC to be updated" +
+            " (if FC does not exist, a new FC will be installed)", required = false, multiValued = false)
+    String argFcId = 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)
+    String argEir = "0";
+    @Option(name = "-cbs", aliases = "--cbs", description = "The CBS in Bytes", required = false, multiValued = false)
+    String argCbs = "0";
+    @Option(name = "-ebs", aliases = "--ebs", description = "The EBS in Bytes", required = false, multiValued = false)
+    String argEbs = "0";
+
+    // TODO: Add further arguments for VLAN tag preservation, CoS preservation etc.
+
+    @Override
+    protected void execute() {
+
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+
+        CarrierEthernetForwardingConstruct fc = new CarrierEthernetForwardingConstruct(argFcId, argFcCfgId, null,
+                generateServiceType(), generateLtpSet());
+
+        ceManager.installFc(fc);
+    }
+
+    /**
+     * Return the CE-VLAN ID for the CE service based on the CLI-supplied argument.
+     *
+     * @return CE-VLAN ID for the CE service
+     */
+    private VlanId generateVlanId(String argVlanId) {
+        return ((argVlanId == null) ? null : VlanId.vlanId(Short.parseShort(argVlanId)));
+    }
+
+    /**
+     * Return the CE service type based on the CLI-supplied arguments.
+     *
+     * @return the CE service type
+     */
+    private CarrierEthernetVirtualConnection.Type generateServiceType() {
+        if (argEvcType == null) {
+            // FIXME: This probably applies only to list of UNIs
+            return ((argLtpList.size() > 2) ?
+                    CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT :
+                    CarrierEthernetVirtualConnection.Type.POINT_TO_POINT);
+        } else {
+            // TODO: Catch exception
+            return CarrierEthernetVirtualConnection.Type.fromString(argEvcType);
+        }
+    }
+
+    /**
+     * Return the BW profile type based on the CLI-supplied arguments.
+     *
+     * @return the BWP profile type
+     */
+    private CarrierEthernetBandwidthProfile.Type generateBandwidthProfileType() {
+        // TODO: Add the CoS BW profile case
+        return ((argCeVlanId == null) ?
+                CarrierEthernetBandwidthProfile.Type.INTERFACE : CarrierEthernetBandwidthProfile.Type.EVC);
+    }
+
+    /**
+     * Return the BW profile id based on the CLI-supplied arguments.
+     *
+     * @param uniId the UNI id
+     * @return the BW profile id
+     */
+    private String generateBandwidthProfileId(String uniId) {
+        // TODO: Add the CoS BW profile case
+        return ((argCeVlanId == null) ? uniId : argFcCfgId);
+    }
+
+    /**
+     * Return the set of UNIs for the FC based on the CLI-supplied arguments.
+     *
+     * @return the set of UNIs for the FC
+     */
+    private Set<CarrierEthernetLogicalTerminationPoint> generateLtpSet() {
+
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+
+        // Update list of global LTPs in the network
+        ceManager.addGlobalLtps(ceManager.getGlobalLtps());
+
+        Set<CarrierEthernetLogicalTerminationPoint> ltpSet = new HashSet<>();
+
+        CarrierEthernetVirtualConnection.Type serviceType = generateServiceType();
+
+        // We assume that first UNI supplied is always root
+        ltpSet.add(new CarrierEthernetLogicalTerminationPoint(argFirstLtp,
+                generateNi(argFirstLtp, CarrierEthernetUni.Role.ROOT)));
+
+        // For E-Line and E-LAN all UNIs are roots. For E-Tree all UNIs are leafs except from one
+        argLtpList.forEach(argLtp -> ltpSet
+                .add(new CarrierEthernetLogicalTerminationPoint(argLtp,
+                        generateNi(argLtp,
+                                ((serviceType == CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT) ?
+                                CarrierEthernetUni.Role.LEAF : CarrierEthernetUni.Role.ROOT)))));
+
+        return ltpSet;
+    }
+
+    private CarrierEthernetNetworkInterface generateNi(String ltpId, CarrierEthernetUni.Role role) {
+
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+
+        if(ceManager.getLtpMap().get(ltpId).ni() instanceof CarrierEthernetUni) {
+            return new CarrierEthernetUni(ConnectPoint.deviceConnectPoint(ltpId), null,
+                    role, generateVlanId(argCeVlanId),
+                    new CarrierEthernetBandwidthProfile(
+                            generateBandwidthProfileId(ltpId),
+                            null,
+                            generateBandwidthProfileType(),
+                            Bandwidth.mbps(Double.parseDouble(argCir)),
+                            Bandwidth.mbps(Double.parseDouble(argEir)),
+                            Long.parseLong(argCbs),
+                            Long.parseLong(argEbs)
+                    ));
+        } else if(ceManager.getLtpMap().get(ltpId).ni() instanceof CarrierEthernetInni) {
+            // FIXME: Use role properly
+            return new CarrierEthernetInni(ConnectPoint.deviceConnectPoint(ltpId), null,
+                    CarrierEthernetInni.Role.TRUNK, generateVlanId(argsTag), null, Bandwidth.bps((double) 0));
+        } else {
+            // FIXME: Use role properly
+            return new CarrierEthernetEnni(ConnectPoint.deviceConnectPoint(ltpId), null,
+                    CarrierEthernetEnni.Role.HUB, generateVlanId(argsTag), null, Bandwidth.bps((double) 0));
+        }
+    }
+
+}
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 7253de2..477d4c3 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
@@ -76,12 +76,12 @@
     @Override
     protected void execute() {
 
-        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
 
         CarrierEthernetVirtualConnection evc = new CarrierEthernetVirtualConnection(argServiceId, argServiceCfgId,
                 generateServiceType(), generateMaxNumUni(), generateUniSet());
 
-        evcManager.establishConnectivity(evc);
+        ceManager.establishConnectivity(evc);
     }
 
     /**
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListFcsCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListFcsCommand.java
new file mode 100644
index 0000000..3e60c5b
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetListFcsCommand.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetForwardingConstruct;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+import java.util.Collection;
+
+/**
+ * CLI command for listing all installed Forwarding Constructs.
+ */
+@Command(scope = "onos", name = "ce-fc-list",
+        description = "Lists all Carrier Ethernet Forwarding Constructs.")
+public class CarrierEthernetListFcsCommand extends AbstractShellCommand {
+
+    @Override
+    protected void execute() {
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        printFcs(ceManager.fcMap().values());
+    }
+
+    private void printFcs(Collection<CarrierEthernetForwardingConstruct> fcs) {
+        fcs.forEach(fc -> print("  %s", fc));
+    }
+}
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
index da642c6..983e3cb 100644
--- 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
@@ -31,10 +31,10 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
         // Populate global LTP map
-        evcManager.addGlobalLtps(evcManager.getGlobalLtps());
-        printLtps(evcManager.getLtpMap().values());
+        ceManager.addGlobalLtps(ceManager.getGlobalLtps());
+        printLtps(ceManager.getLtpMap().values());
     }
 
     private void printLtps(Collection<CarrierEthernetLogicalTerminationPoint> ltps) {
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 9861732..9a697e4 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
@@ -31,8 +31,8 @@
 
     @Override
     protected void execute() {
-        CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
-        printServices(evcManager.evcMap().values());
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        printServices(ceManager.evcMap().values());
     }
 
     private void printServices(Collection<CarrierEthernetVirtualConnection> services) {
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 2904602..3a4f409 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 evcManager = get(CarrierEthernetManager.class);
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
         // Populate global UNI map
-        evcManager.addGlobalUnis(evcManager.getGlobalUnis());
-        printUnis(evcManager.getUniMap().values());
+        ceManager.addGlobalUnis(ceManager.getGlobalUnis());
+        printUnis(ceManager.getUniMap().values());
     }
 
     private void printUnis(Collection<CarrierEthernetUni> unis) {
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetLtpCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetLtpCompleter.java
new file mode 100644
index 0000000..045483f
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetLtpCompleter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.cli;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * LTP ConnectPoint completer.
+ */
+public class CarrierEthernetLtpCompleter implements Completer {
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+
+        // TODO: Add memory
+
+        StringsCompleter delegate = new StringsCompleter();
+
+        CarrierEthernetManager ceManager =
+                AbstractShellCommand.get(CarrierEthernetManager.class);
+
+        SortedSet<String> strings = delegate.getStrings();
+        ceManager.getGlobalLtps().forEach(uni -> strings.add(uni.id()));
+
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllFcsCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllFcsCommand.java
new file mode 100644
index 0000000..09ebb8f
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveAllFcsCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+/**
+ * CLI command for removing all installed Carrier Ethernet Forwarding Constructs.
+ */
+@Command(scope = "onos", name = "ce-fc-remove-all",
+        description = "Removes all installed Carrier Ethernet Forwarding Constructs.")
+public class CarrierEthernetRemoveAllFcsCommand extends AbstractShellCommand {
+
+    @Override
+    protected void execute() {
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        ceManager.removeAllFcs();
+    }
+}
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 201a2b8..8d047e1 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 evcManager = get(CarrierEthernetManager.class);
-        evcManager.removeAllEvcs();
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        ceManager.removeAllEvcs();
     }
 }
\ No newline at end of file
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveFcCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveFcCommand.java
new file mode 100644
index 0000000..7bedc36
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetRemoveFcCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+/**
+ * CLI command for removing an installed Carrier Ethernet Forwarding Construct.
+ */
+@Command(scope = "onos", name = "ce-fc-remove",
+        description = "Carrier Ethernet service removal command.")
+public class CarrierEthernetRemoveFcCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "argFcId", description = "Forwarding Construct ID", required = true, multiValued = false)
+    String argFcId = null;
+
+    @Override
+    protected void execute() {
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        ceManager.removeFc(argFcId);
+    }
+}
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 7e9b156..fec19c7 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 evcManager = get(CarrierEthernetManager.class);
-        evcManager.removeEvc(argServiceId);
+        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
+        ceManager.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 d712882..ca03154 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 evcManager = AbstractShellCommand.get(CarrierEthernetManager.class);
+        CarrierEthernetManager ceManager = AbstractShellCommand.get(CarrierEthernetManager.class);
         SortedSet<String> strings = delegate.getStrings();
-        evcManager.evcMap().keySet().forEach(serviceId -> strings.add(serviceId));
+        ceManager.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/CarrierEthernetUniCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/CarrierEthernetUniCompleter.java
index 3bf10ac..853fb5b 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
@@ -34,11 +34,11 @@
 
         StringsCompleter delegate = new StringsCompleter();
 
-        CarrierEthernetManager evcManager =
+        CarrierEthernetManager ceManager =
                 AbstractShellCommand.get(CarrierEthernetManager.class);
 
         SortedSet<String> strings = delegate.getStrings();
-        evcManager.getGlobalUnis().forEach(uni -> strings.add(uni.id()));
+        ceManager.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 c9b8ca8..fe9e145 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
@@ -29,6 +29,18 @@
 
     <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
         <command>
+            <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetCreateFcCommand"/>
+            <completers>
+                <ref component-id="placeholderCompleter"/>
+                <ref component-id="carrierEthernetServiceTypeCompleter"/>
+                <ref component-id="carrierEthernetLtpCompleter"/>
+                <ref component-id="carrierEthernetLtpCompleter"/>
+            </completers>
+        </command>
+    </command-bundle>
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
             <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetRemoveServiceCommand"/>
             <completers>
                 <ref component-id="carrierEthernetServiceIdCompleter"/>
@@ -60,10 +72,32 @@
         </command>
     </command-bundle>
 
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetListFcsCommand"/>
+        </command>
+    </command-bundle>
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetRemoveFcCommand"/>
+            <completers>
+                <ref component-id="carrierEthernetServiceIdCompleter"/>
+            </completers>
+        </command>
+    </command-bundle>
+
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+        <command>
+            <action class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetRemoveAllFcsCommand"/>
+        </command>
+    </command-bundle>
+
     <bean id="placeholderCompleter" class="org.onosproject.cli.PlaceholderCompleter"/>
     <bean id="carrierEthernetServiceTypeCompleter" class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetServiceTypeCompleter"/>
     <bean id="carrierEthernetServiceIdCompleter" class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetServiceIdCompleter"/>
     <bean id="carrierEthernetUniCompleter" class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetUniCompleter"/>
+    <bean id="carrierEthernetLtpCompleter" class="org.onosproject.ecord.carrierethernet.cli.CarrierEthernetLtpCompleter"/>
     <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/>
 
 </blueprint>