Separating creating BW profiles from applying BW profiles and some other fixes

- Adding new createBandwidthProfiles() method in CarrierEthernetProvisioner, called before forwarding establishment
- Adding meter instruction in FilterTreatment so that it can be used if needed
- Do not explicitly apply meters to NETCONF devices (assuming it has already been done during forwarding establishment)
- Improving completers for addition/removal of UNIs/LTPs
- Remove UNIs/LTPs from removedUniSet/removedLtpSet when they are added after having first been removed
- Refactoring applyBandwidthProfileResources() to apply meter on installed flowRule which pushes the FC vlanId on UNI port
- Some Javadoc corrections
- Fixing potential NPE in addEcNi() of CarrierEthernetUni.java
- Fixes based on Patchset 1 comments

Change-Id: I824482d9469e8f30df866602c882ff7ec12117f9
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 68886f5..f9d99ac 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
@@ -30,8 +30,8 @@
 /**
  * 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)
+ * 1. As a global ENNI descriptor containing one or more S-VLAN tags
+ * 2. As a service-specific ENNI descriptor containing a single S-VLAN tag and including a role (e.g. hub, spoke)
  */
 public class CarrierEthernetEnni extends CarrierEthernetNetworkInterface <CarrierEthernetEnni> {
 
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 64c8f4f..68e2caa 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
@@ -31,8 +31,8 @@
 /**
  * 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)
+ * 1. As a global INNI descriptor containing one or more S-VLAN tags
+ * 2. As a service-specific INNI descriptor containing a single S-VLAN tag and including a role (e.g. hub, spoke)
  */
 public class CarrierEthernetInni extends CarrierEthernetNetworkInterface <CarrierEthernetInni> {
 
@@ -68,6 +68,7 @@
                                Bandwidth usedCapacity) {
 
         super(connectPoint, Type.INNI, uniCfgId);
+
         // TODO: Check for null
         this.role = role;
         this.sVlanIdSet = Sets.newConcurrentHashSet();
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 cd4ccef..ca2f54e 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
@@ -175,9 +175,9 @@
     }
 
     /**
-     * Returns LTP role - applicable only to EVC- or FC-specific LTPs.
+     * Sets LTP role - applicable only to EVC- or FC-specific LTPs.
      *
-     * @param role he LTP role to set
+     * @param role the LTP role to set
      */
     public void setRole(Role role) {
         this.role = role;
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 a304fd0..a44e78c 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
@@ -707,9 +707,13 @@
             return null;
         }
 
+        // Create BW profiles first so that they will be available if needed during the connectivity phase
+        ceProvisioner.createBandwidthProfiles(fc);
+
         ceProvisioner.setupConnectivity(fc);
 
         // If connectivity was not successful, then do not register the FC and do not apply BW profiles
+        // If not, the BW profiles that were created earlier need to be removed
         if (fc.state().equals(CarrierEthernetForwardingConstruct.State.ACTIVE)) {
             // Apply BWP-related resources (e.g. Meters) to the packet switches
             ceProvisioner.applyBandwidthProfiles(fc);
@@ -719,6 +723,8 @@
             // Increment the global LTP and corresponding NI refCount
             fc.ltpSet().forEach(ltp -> ltpMap.get(ltp.id()).refCount().incrementAndGet());
             fcMap.put(fc.id(), fc);
+        } else {
+            ceProvisioner.removeBandwidthProfiles(fc);
         }
 
         return fc;
@@ -941,9 +947,11 @@
     /**
      * Returns all potential UNIs from the topology.
      *
+     * @param excludeAdded indicates that UNIs already added in the UNI map should not be in the returned set
+     * @param includeRemoved indicates that UNIs explicitly removed from the UNI map should be in the returned set
      * @return set of all potential UNIs in the topology
      * */
-    public Set<CarrierEthernetUni> getUnisFromTopo() {
+    public Set<CarrierEthernetUni> getUnisFromTopo(boolean excludeAdded, boolean includeRemoved) {
 
         CarrierEthernetUni uni;
         Set<CarrierEthernetUni> uniSet = new HashSet<>();
@@ -954,8 +962,10 @@
                     String cpString = device.id().toString() + "/" + port.number();
                     ConnectPoint cp = ConnectPoint.deviceConnectPoint(cpString);
                     uni = generateUni(cp);
-                    // Check if LTP was generated and whether it's currently removed
-                    if (uni != null && !removedUniSet.contains(uni.id())) {
+                    // Check if UNI was generated and whether it's currently removed
+                    if (uni != null
+                            && (includeRemoved || !removedUniSet.contains(uni.id()))
+                            && (!excludeAdded || !uniMap.containsKey(uni.id()))) {
                         uniSet.add(uni);
                     }
                 }
@@ -1018,8 +1028,12 @@
             // FIXME: Assumes LTP and UNI id are the same
             if (!ltpMap.containsKey(uni.id())) {
                 ltpMap.put(uni.id(), new CarrierEthernetLogicalTerminationPoint(uni.id(), uni));
+                // Remove LTP from deleted set
+                removedLtpSet.remove(uni.id());
             }
             uniMap.put(uni.id(), uni);
+            // Remove UNI from deleted set
+            removedUniSet.remove(uni.id());
             return  uni;
         } else {
             return null;
@@ -1028,10 +1042,11 @@
 
     /**
      * Returns all potential LTPs from the topology.
-     *
+     * @param excludeAdded indicates that LTPs already added in the LTP map should not be in the returned set
+     * @param includeRemoved indicates that LTPs explicitly removed from the LTP map should be in the returned set
      * @return set of all potential LTPs in the topology
      * */
-    public Set<CarrierEthernetLogicalTerminationPoint> getLtpsFromTopo() {
+    public Set<CarrierEthernetLogicalTerminationPoint> getLtpsFromTopo(boolean excludeAdded, boolean includeRemoved) {
 
         CarrierEthernetLogicalTerminationPoint ltp;
         Set<CarrierEthernetLogicalTerminationPoint> ltpSet = new HashSet<>();
@@ -1043,7 +1058,9 @@
                     ConnectPoint cp = ConnectPoint.deviceConnectPoint(cpString);
                     ltp = generateLtp(cp, null);
                     // Check if LTP was generated and whether it's currently removed
-                    if (ltp != null && !removedLtpSet.contains(ltp.id())) {
+                    if (ltp != null
+                            && (includeRemoved || !removedLtpSet.contains(ltp.id()))
+                            && (!excludeAdded || !ltpMap.containsKey(ltp.id()))) {
                         // Check additionally if associated UNI is currently removed
                         if (!(ltp.ni() instanceof CarrierEthernetUni) || !removedUniSet.contains(ltp.ni().id())) {
                             ltpSet.add(ltp);
@@ -1148,9 +1165,12 @@
      * */
     public CarrierEthernetLogicalTerminationPoint addGlobalLtp(CarrierEthernetLogicalTerminationPoint ltp) {
         // If LTP contains a UNI, add it only if it's not already there, else point to the existing UNI
+        // FIXME: Assumes LTP and UNI id are the same
         if (ltp.ni() != null && ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
             if (!uniMap.containsKey(ltp.ni().id())) {
                 uniMap.put(ltp.ni().id(), (CarrierEthernetUni) ltp.ni());
+                // Remove UNI from deleted set
+                removedUniSet.remove(ltp.id());
             } else {
                 ltp.setNi(uniMap.get(ltp.ni().id()));
             }
@@ -1172,6 +1192,8 @@
                 }
             }
             ltpMap.put(ltp.id(), ltp);
+            // Remove LTP from deleted set
+            removedLtpSet.remove(ltp.id());
             return ltp;
         } else {
             return null;
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
deleted file mode 100644
index 285fe5f..0000000
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
+++ /dev/null
@@ -1,479 +0,0 @@
-package org.onosproject.ecord.carrierethernet.app;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultFlowRule;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criteria;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.PortCriterion;
-import org.onosproject.net.flow.criteria.VlanIdCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flowobjective.*;
-import org.onosproject.net.meter.Meter;
-import org.onosproject.net.meter.MeterId;
-import org.onosproject.net.meter.MeterRequest;
-import org.onosproject.net.meter.Band;
-import org.onosproject.net.meter.DefaultBand;
-import org.onosproject.net.meter.MeterService;
-import org.onosproject.net.meter.DefaultMeterRequest;
-import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowController;
-import org.onosproject.openflow.controller.OpenFlowSwitch;
-import org.slf4j.Logger;
-
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Iterator;
-import java.util.ListIterator;
-
-import org.apache.commons.lang3.tuple.Pair;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- *  Class used to control Carrier Ethernet nodes according to the OpenFlow (1.3 and above) protocol.
- */
-@Component(immediate = true)
-@Service (value = CarrierEthernetOpenFlowPacketNodeManager.class)
-public class CarrierEthernetOpenFlowPacketNodeManager extends CarrierEthernetPacketNodeManager {
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CoreService coreService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected FlowRuleService flowRuleService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected MeterService meterService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected FlowObjectiveService flowObjectiveService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected OpenFlowController controller;
-
-    private final Logger log = getLogger(getClass());
-
-    private static ApplicationId appId;
-
-    private static final int PRIORITY = 50000;
-
-    // TODO: Below maps to be replaced by the meter ids and flow objectives associated with each CE Intent
-
-    // FIXME: Replace with Pair<DeviceId, MeterId>
-    private final Map<String, Set<DeviceMeterId>> deviceMeterIdMap = new HashMap<>();
-    private final Map<String, LinkedList<Pair<DeviceId, Objective>>> flowObjectiveMap = new HashMap();
-
-    @Activate
-    protected void activate() {
-        appId = coreService.registerApplication("org.onosproject.ecord.carrierethernet");
-    }
-
-    @Deactivate
-    protected void deactivate() {}
-
-    @Override
-    public void setNodeForwarding(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface ingressNi,
-                                  Set<CarrierEthernetNetworkInterface> egressNiSet) {
-
-        if (ingressNi == null || egressNiSet.isEmpty()) {
-            log.error("There needs to be at least one ingress and one egress NI to set forwarding.");
-            return;
-        }
-
-        flowObjectiveMap.putIfAbsent(fc.id(), new LinkedList<>());
-
-        // TODO: Get created FlowObjectives from this method
-        createFlowObjectives(fc, ingressNi, egressNiSet);
-    }
-
-    /**
-     * Creates and submits FlowObjectives depending on role of the device in the FC and ingress/egress NI types.
-     *
-     * @param fc the FC representation
-     * @param ingressNi the ingress NI (UNI, INNI, ENNI or GENERIC) of the EVC for this forwarding segment
-     * @param  egressNiSet the set of egress NIs (UNI, INNI, ENNI or GENERIC) of the EVC for this forwarding segment
-     */
-    private void createFlowObjectives(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface ingressNi,
-                                      Set<CarrierEthernetNetworkInterface> egressNiSet) {
-
-        /////////////////////////////////////////
-        // Prepare and submit filtering objective
-        /////////////////////////////////////////
-
-        FilteringObjective.Builder filteringObjectiveBuilder = DefaultFilteringObjective.builder()
-                .permit().fromApp(appId)
-                .withPriority(PRIORITY)
-                .withKey(Criteria.matchInPort(ingressNi.cp().port()));
-
-        TrafficTreatment.Builder filterTreatmentBuilder = DefaultTrafficTreatment.builder();
-
-        // In general, nodes would match on the VLAN tag assigned to the EVC/FC
-        Criterion filterVlanIdCriterion = Criteria.matchVlanId(fc.vlanId());
-
-        if ((ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.INNI))
-                || (ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.ENNI)) ) {
-            // TODO: Check TPID? Also: Is is possible to receive untagged pkts at an INNI/ENNI?
-            // Source node of an FC should match on S-TAG if it's an INNI/ENNI
-            filterVlanIdCriterion = Criteria.matchVlanId(ingressNi.sVlanId());
-            // Translate S-TAG to the one used in the current FC
-            filterTreatmentBuilder.setVlanId(fc.vlanId());
-        } else if (ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
-            // Source node of an FC should match on CE-VLAN ID (if present) if it's a UNI
-            filterVlanIdCriterion = Criteria.matchVlanId(ingressNi.ceVlanId());
-            // Push S-TAG of current FC on top of existing CE-VLAN ID
-            filterTreatmentBuilder.pushVlan().setVlanId(fc.vlanId());
-        }
-
-        filteringObjectiveBuilder.addCondition(filterVlanIdCriterion);
-
-        // Do not add meta if there are no instructions (i.e. if not first)
-        if (!(ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.GENERIC))) {
-            filteringObjectiveBuilder.withMeta(filterTreatmentBuilder.build());
-        }
-
-        flowObjectiveService.filter(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add());
-        flowObjectiveMap.get(fc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add()));
-
-        ////////////////////////////////////////////////////
-        // Prepare and submit next and forwarding objectives
-        ////////////////////////////////////////////////////
-
-        TrafficSelector fwdSelector = DefaultTrafficSelector.builder()
-                .matchVlanId(fc.vlanId())
-                .matchInPort(ingressNi.cp().port())
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .build();
-
-        Integer nextId = flowObjectiveService.allocateNextId();
-
-        // Setting higher priority to fwd/next objectives to bypass filter in case of match conflict in OVS switches
-        NextObjective.Builder nextObjectiveBuider = DefaultNextObjective.builder()
-                .fromApp(appId)
-                .makePermanent()
-                .withType(NextObjective.Type.BROADCAST)
-                .withPriority(PRIORITY + 1)
-                .withMeta(fwdSelector)
-                .withId(nextId);
-
-         egressNiSet.forEach(egressNi -> {
-            // TODO: Check if ingressNi and egressNi are on the same device?
-            TrafficTreatment.Builder nextTreatmentBuilder = DefaultTrafficTreatment.builder();
-            // If last NI in FC is not UNI, keep the existing S-TAG - it will be translated at the entrance of the next FC
-            if (egressNi.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
-                nextTreatmentBuilder.popVlan();
-            }
-            Instruction outInstruction = Instructions.createOutput(egressNi.cp().port());
-            nextTreatmentBuilder.add(outInstruction);
-            nextObjectiveBuider.addTreatment(nextTreatmentBuilder.build());
-        });
-
-        NextObjective nextObjective = nextObjectiveBuider.add();
-
-        // Setting higher priority to fwd/next objectives to bypass filter in case of match conflict in OVS switches
-        ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
-                .fromApp(appId)
-                .makePermanent()
-                .withFlag(ForwardingObjective.Flag.VERSATILE)
-                .withPriority(PRIORITY + 1)
-                .withSelector(fwdSelector)
-                .nextStep(nextId)
-                .add();
-
-        flowObjectiveService.next(ingressNi.cp().deviceId(), nextObjective);
-        // Add all NextObjectives at the end of the list so that they will be removed last
-        flowObjectiveMap.get(fc.id()).addLast(Pair.of(ingressNi.cp().deviceId(), nextObjective));
-
-        flowObjectiveService.forward(ingressNi.cp().deviceId(), forwardingObjective);
-        flowObjectiveMap.get(fc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), forwardingObjective));
-    }
-
-    @Override
-    void applyBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni) {
-
-        Dpid dpid = Dpid.dpid(uni.cp().deviceId().uri());
-        OpenFlowSwitch sw = controller.getSwitch(dpid);
-
-        // Do not apply meters to OFDPA 2.0 switches since they are not currently supported
-        if (sw.softwareDescription().equals("OF-DPA 2.0")) {
-            return;
-        }
-
-        // Create meters and add them to global MeterId map
-        Set<DeviceMeterId> deviceMeterIdSet = deviceMeterIdMap.get(fc.id());
-        if (deviceMeterIdSet == null) {
-            deviceMeterIdSet = new HashSet<>();
-        }
-        deviceMeterIdSet.addAll(createMeters(uni));
-        deviceMeterIdMap.put(fc.id(), deviceMeterIdSet);
-
-        // Apply meters to already installed flows
-
-        Set<FlowRule> newFlowRuleSet = new HashSet<>();
-
-        // Get flow rules belonging to service and having as in_port the UNI connect point
-
-        // FIXME: Check for flow rules associated with evcId
-        for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
-            PortCriterion portCriterion = (PortCriterion) flowRule.selector().getCriterion(Criterion.Type.IN_PORT);
-            VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) flowRule.selector()
-                    .getCriterion(Criterion.Type.VLAN_VID);
-            if (portCriterion == null || vlanIdCriterion == null) {
-                continue;
-            }
-            PortNumber inPort = portCriterion.port();
-            VlanId flowInVlanId = vlanIdCriterion.vlanId();
-            if (inPort == null || flowInVlanId == null) {
-                continue;
-            }
-            ConnectPoint flowInCp = new ConnectPoint(flowRule.deviceId(), inPort);
-            // FIXME: Maybe check also if there is a group action?
-            // TODO: Check the vlanIds of all FCs comprising the EVC????
-            if (uni.cp().equals(flowInCp) && fc.vlanId().equals(flowInVlanId)) {
-                // Need to add to the flow the meters associated with the same device
-                Set<DeviceMeterId> tmpDeviceMeterIdSet = new HashSet<>();
-                deviceMeterIdMap.get(fc.id()).forEach(deviceMeterId -> {
-                    if (deviceMeterId.deviceId().equals(flowRule.deviceId())) {
-                        tmpDeviceMeterIdSet.add(deviceMeterId);
-                    }
-                });
-                // Modify and submit flow rule only if there are meters to add
-                if (!tmpDeviceMeterIdSet.isEmpty()) {
-                    FlowRule newFlowRule = addMetersToFlowRule(flowRule, tmpDeviceMeterIdSet);
-                    flowRuleService.applyFlowRules(newFlowRule);
-                    newFlowRuleSet.add(newFlowRule);
-                } else {
-                    newFlowRuleSet.add(flowRule);
-                }
-            } else {
-                newFlowRuleSet.add(flowRule);
-            }
-        }
-    }
-
-    /**
-     * Creates and submits a meter with the required bands for a UNI.
-     *
-     * @param uni the UNI descriptor
-     * @return set of meter ids of the meters created
-     */
-    private Set<DeviceMeterId> createMeters(CarrierEthernetUni uni) {
-
-        // TODO: Check if meter already exists before adding it?
-
-        Set<DeviceMeterId> deviceMeterIdSet = new HashSet<>();
-
-        long longCir = (long) (uni.bwp().cir().bps() / 8000);
-        long longEir = (long) (uni.bwp().eir().bps() / 8000);
-
-        MeterRequest.Builder meterRequestBuilder;
-        Meter meter;
-        Band.Builder bandBuilder;
-
-        Set<Band> bandSet = new HashSet<>();
-
-        // If EIR is zero do not create the REMARK meter
-        if (longEir != 0) {
-            // Mark frames that exceed CIR as Best Effort
-            bandBuilder = DefaultBand.builder()
-                    .ofType(Band.Type.REMARK)
-                    .withRate(longCir)
-                    .dropPrecedence((short) 0);
-
-            if (uni.bwp().cbs() != 0) {
-                bandBuilder.burstSize(uni.bwp().cbs());
-            }
-
-            bandSet.add(bandBuilder.build());
-        }
-
-        // If CIR is zero do not create the DROP meter
-        if (longCir != 0) {
-            // Drop all frames that exceed CIR + EIR
-            bandBuilder = DefaultBand.builder()
-                    .ofType(Band.Type.DROP)
-                    .withRate(longCir + longEir);
-
-            if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
-                // FIXME: Use CBS and EBS correctly according to MEF specs
-                bandBuilder.burstSize(uni.bwp().cbs() + uni.bwp().ebs());
-            }
-
-            bandSet.add(bandBuilder.build());
-        }
-
-        // Create meter only if at least one band was created
-        if (!bandSet.isEmpty()) {
-            meterRequestBuilder = DefaultMeterRequest.builder()
-                    .forDevice(uni.cp().deviceId())
-                    .fromApp(appId)
-                    .withUnit(Meter.Unit.KB_PER_SEC)
-                    .withBands(bandSet);
-
-            if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
-                meterRequestBuilder.burst();
-            }
-
-            meter = meterService.submit(meterRequestBuilder.add());
-            deviceMeterIdSet.add(new DeviceMeterId(uni.cp().deviceId(), meter.id()));
-        }
-
-        return deviceMeterIdSet;
-    }
-
-    private FlowRule addMetersToFlowRule(FlowRule flowRule, Set<DeviceMeterId> deviceMeterIdSet) {
-
-        // FIXME: Refactor to use only single meter
-
-        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
-                .builder(flowRule.treatment());
-
-        deviceMeterIdSet.forEach(deviceMeterId -> {
-            tBuilder.meter(deviceMeterId.meterId());
-        });
-
-        return createFlowRule(flowRule.deviceId(), flowRule.priority(),
-                flowRule.selector(), tBuilder.build(), flowRule.tableId());
-    }
-
-    @Override
-    void removeBandwidthProfileResources(String fcId, CarrierEthernetUni uni) {
-        removeMeters(fcId, uni);
-    }
-
-    /**
-     * Removes the meters associated with a specific UNI of an FC.
-     *
-     * @param fcId the EVC ID
-     * @param uni the UNI descriptor
-     * */
-    private void removeMeters(String fcId, CarrierEthernetUni uni) {
-
-        Set<DeviceMeterId> newDeviceMeterIdSet = deviceMeterIdMap.get(fcId);
-        DeviceMeterId tmpDeviceMeterId;
-
-        Collection<Meter> meters = meterService.getMeters(uni.cp().deviceId());
-
-        Iterator<Meter> it = meters.iterator();
-        while (it.hasNext()) {
-            Meter meter = it.next();
-            tmpDeviceMeterId = new DeviceMeterId(uni.cp().deviceId(), meter.id());
-            if (meter.appId().equals(appId) &&
-                    deviceMeterIdMap.get(fcId).contains(tmpDeviceMeterId)) {
-                MeterRequest.Builder mBuilder;
-                mBuilder = DefaultMeterRequest.builder()
-                        .fromApp(meter.appId())
-                        .forDevice(meter.deviceId())
-                        .withUnit(meter.unit())
-                        .withBands(meter.bands());
-                if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
-                    mBuilder.burst();
-                }
-                meterService.withdraw(mBuilder.remove(), meter.id());
-                newDeviceMeterIdSet.remove(tmpDeviceMeterId);
-            }
-        }
-
-        deviceMeterIdMap.put(fcId, newDeviceMeterIdSet);
-    }
-
-    @Override
-    void removeAllForwardingResources(CarrierEthernetForwardingConstruct fc) {
-        removeFlowObjectives(fc.id());
-    }
-
-    /**
-     * Removes all flow objectives installed by the application which are associated with a specific FC.
-     *
-     * @param fcId the FC id
-     * */
-    private void removeFlowObjectives(String fcId) {
-        // Note: A Flow Rule cannot be shared by multiple FCs due to different VLAN or CE-VLAN ID match.
-        List<Pair<DeviceId, Objective>> flowObjectiveList = flowObjectiveMap.remove(fcId);
-        // NextObjectives will be removed after all other Objectives
-        ListIterator<Pair<DeviceId, Objective>> objIter = flowObjectiveList.listIterator();
-        while (objIter.hasNext()) {
-            Pair<DeviceId, Objective> deviceObjectivePair = objIter.next();
-            flowObjectiveService.apply(deviceObjectivePair.getLeft(), deviceObjectivePair.getRight().copy().remove());
-        }
-
-    }
-
-    // FIXME: Replace with Pair<DeviceId, MeterId>
-    /**
-     * Utility class to compensate for the fact that MeterIds are not unique system-wide.
-     * */
-    class DeviceMeterId {
-        private DeviceId deviceId;
-        private MeterId meterId;
-
-        DeviceMeterId(DeviceId deviceId, MeterId meterId) {
-            this.deviceId = deviceId;
-            this.meterId = meterId;
-        }
-
-        public DeviceId deviceId() {
-            return deviceId;
-        }
-
-        public MeterId meterId() {
-            return meterId;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(deviceId, meterId);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj instanceof DeviceMeterId) {
-                DeviceMeterId other = (DeviceMeterId) obj;
-                if (this.deviceId().equals(other.deviceId()) && this.meterId().equals(other.meterId())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    private FlowRule createFlowRule(DeviceId deviceId, int priority,
-                                    TrafficSelector selector, TrafficTreatment treatment, int tableId) {
-        return DefaultFlowRule.builder()
-                .fromApp(appId)
-                .forDevice(deviceId)
-                .makePermanent()
-                .withPriority(priority)
-                .withSelector(selector)
-                .withTreatment(treatment)
-                .forTable(tableId)
-                .build();
-    }
-
-}
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 b34d12a..f03b912 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Open Networking Laboratory
+ * 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.
@@ -15,20 +15,505 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flowobjective.*;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.MeterService;
+import org.onosproject.net.meter.DefaultMeterRequest;
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.Objects;
 import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.apache.commons.lang3.tuple.Pair;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
- * Abstraction of a class used to control Carrier Ethernet nodes according to their control protocol.
+ *  Class used to control Carrier Ethernet nodes according to the OpenFlow (1.3 and above) protocol.
  */
-public abstract class CarrierEthernetPacketNodeManager {
+@Component(immediate = true)
+@Service (value = CarrierEthernetPacketNodeService.class)
+public class CarrierEthernetPacketNodeManager implements CarrierEthernetPacketNodeService {
 
-    abstract void setNodeForwarding(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface srcNi,
-                                    Set<CarrierEthernetNetworkInterface> dstNiSet);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
 
-    abstract void applyBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
 
-    abstract void removeBandwidthProfileResources(String fcId, CarrierEthernetUni uni);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MeterService meterService;
 
-    abstract void removeAllForwardingResources(CarrierEthernetForwardingConstruct fc);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenFlowController controller;
+
+    private final Logger log = getLogger(getClass());
+
+    private static ApplicationId appId;
+
+    private static final int PRIORITY = 50000;
+
+    // TODO: Below maps to be replaced by the meter ids and flow objectives associated with each CE Intent
+
+    // FIXME: Replace with Pair<DeviceId, MeterId>
+    private final Map<String, Set<DeviceMeterId>> deviceMeterIdMap = new HashMap<>();
+    private final Map<String, LinkedList<Pair<DeviceId, Objective>>> flowObjectiveMap = new HashMap();
+
+    @Activate
+    protected void activate() {
+        appId = coreService.registerApplication("org.onosproject.ecord.carrierethernet");
+    }
+
+    @Deactivate
+    protected void deactivate() {}
+
+    @Override
+    public void setNodeForwarding(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface ingressNi,
+                                  Set<CarrierEthernetNetworkInterface> egressNiSet) {
+
+        if (ingressNi == null || egressNiSet.isEmpty()) {
+            log.error("There needs to be at least one ingress and one egress NI to set forwarding.");
+            return;
+        }
+
+        flowObjectiveMap.putIfAbsent(fc.id(), new LinkedList<>());
+
+        // TODO: Get created FlowObjectives from this method
+        createFlowObjectives(fc, ingressNi, egressNiSet);
+    }
+
+    /**
+     * Creates and submits FlowObjectives depending on role of the device in the FC and ingress/egress NI types.
+     *
+     * @param fc the FC representation
+     * @param ingressNi the ingress NI (UNI, INNI, ENNI or GENERIC) of the EVC for this forwarding segment
+     * @param  egressNiSet the set of egress NIs (UNI, INNI, ENNI or GENERIC) of the EVC for this forwarding segment
+     */
+    private void createFlowObjectives(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface ingressNi,
+                                      Set<CarrierEthernetNetworkInterface> egressNiSet) {
+
+        /////////////////////////////////////////
+        // Prepare and submit filtering objective
+        /////////////////////////////////////////
+
+        FilteringObjective.Builder filteringObjectiveBuilder = DefaultFilteringObjective.builder()
+                .permit().fromApp(appId)
+                .withPriority(PRIORITY)
+                .withKey(Criteria.matchInPort(ingressNi.cp().port()));
+
+        TrafficTreatment.Builder filterTreatmentBuilder = DefaultTrafficTreatment.builder();
+
+        // In general, nodes would match on the VLAN tag assigned to the EVC/FC
+        Criterion filterVlanIdCriterion = Criteria.matchVlanId(fc.vlanId());
+
+        if ((ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.INNI))
+                || (ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.ENNI)) ) {
+            // TODO: Check TPID? Also: Is is possible to receive untagged pkts at an INNI/ENNI?
+            // Source node of an FC should match on S-TAG if it's an INNI/ENNI
+            filterVlanIdCriterion = Criteria.matchVlanId(ingressNi.sVlanId());
+            // Translate S-TAG to the one used in the current FC
+            filterTreatmentBuilder.setVlanId(fc.vlanId());
+        } else if (ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+            // Source node of an FC should match on CE-VLAN ID (if present) if it's a UNI
+            filterVlanIdCriterion = Criteria.matchVlanId(ingressNi.ceVlanId());
+            // Obtain related Meter (if it exists) and add it in the treatment in case it may be used
+            deviceMeterIdMap.get(fc.id()).forEach(deviceMeterId -> {
+                if (deviceMeterId.deviceId().equals(ingressNi.cp().deviceId())) {
+                    filterTreatmentBuilder.meter(deviceMeterId.meterId());
+                }
+            });
+            // Push S-TAG of current FC on top of existing CE-VLAN ID
+            filterTreatmentBuilder.pushVlan().setVlanId(fc.vlanId());
+        }
+
+        filteringObjectiveBuilder.addCondition(filterVlanIdCriterion);
+
+        // Do not add meta if there are no instructions (i.e. if not first)
+        if (!(ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.GENERIC))) {
+            filteringObjectiveBuilder.withMeta(filterTreatmentBuilder.build());
+        }
+
+        flowObjectiveService.filter(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add());
+        flowObjectiveMap.get(fc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add()));
+
+        ////////////////////////////////////////////////////
+        // Prepare and submit next and forwarding objectives
+        ////////////////////////////////////////////////////
+
+        TrafficSelector fwdSelector = DefaultTrafficSelector.builder()
+                .matchVlanId(fc.vlanId())
+                .matchInPort(ingressNi.cp().port())
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .build();
+
+        Integer nextId = flowObjectiveService.allocateNextId();
+
+        // Setting higher priority to fwd/next objectives to bypass filter in case of match conflict in OVS switches
+        NextObjective.Builder nextObjectiveBuider = DefaultNextObjective.builder()
+                .fromApp(appId)
+                .makePermanent()
+                .withType(NextObjective.Type.BROADCAST)
+                .withPriority(PRIORITY + 1)
+                .withMeta(fwdSelector)
+                .withId(nextId);
+
+         egressNiSet.forEach(egressNi -> {
+            // TODO: Check if ingressNi and egressNi are on the same device?
+            TrafficTreatment.Builder nextTreatmentBuilder = DefaultTrafficTreatment.builder();
+            // If last NI in FC is not UNI, keep the existing S-TAG - it will be translated at the entrance of the next FC
+            if (egressNi.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                nextTreatmentBuilder.popVlan();
+            }
+            Instruction outInstruction = Instructions.createOutput(egressNi.cp().port());
+            nextTreatmentBuilder.add(outInstruction);
+            nextObjectiveBuider.addTreatment(nextTreatmentBuilder.build());
+        });
+
+        NextObjective nextObjective = nextObjectiveBuider.add();
+
+        // Setting higher priority to fwd/next objectives to bypass filter in case of match conflict in OVS switches
+        ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+                .fromApp(appId)
+                .makePermanent()
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .withPriority(PRIORITY + 1)
+                .withSelector(fwdSelector)
+                .nextStep(nextId)
+                .add();
+
+        flowObjectiveService.next(ingressNi.cp().deviceId(), nextObjective);
+        // Add all NextObjectives at the end of the list so that they will be removed last
+        flowObjectiveMap.get(fc.id()).addLast(Pair.of(ingressNi.cp().deviceId(), nextObjective));
+
+        flowObjectiveService.forward(ingressNi.cp().deviceId(), forwardingObjective);
+        flowObjectiveMap.get(fc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), forwardingObjective));
+    }
+
+    @Override
+    public void createBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni) {
+        // Create meters and add them to global MeterId map
+        Set<DeviceMeterId> deviceMeterIdSet = deviceMeterIdMap.get(fc.id());
+        if (deviceMeterIdSet == null) {
+            deviceMeterIdSet = new HashSet<>();
+        }
+        deviceMeterIdSet.addAll(createMeters(uni));
+        deviceMeterIdMap.put(fc.id(), deviceMeterIdSet);
+    }
+
+    @Override
+    public void applyBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni) {
+
+        DeviceId deviceId = uni.cp().deviceId();
+
+        // Do not apply meters to NETCONF-controlled switches here since they should have been applied in the pipeline
+        // FIXME: Is there a better way to check this?
+        if (deviceId.uri().getScheme().equals("netconf")) {
+            return;
+        }
+
+        Dpid dpid = Dpid.dpid(deviceId.uri());
+        OpenFlowSwitch sw = controller.getSwitch(dpid);
+
+        // Do not apply meters to OFDPA 2.0 switches since they are not currently supported
+        if (sw.softwareDescription().equals("OF-DPA 2.0")) {
+            return;
+        }
+
+        // Get installed flows with the same appId/deviceId with IN_PORT = UNI port which push the FC vlanId
+        List<FlowRule> flowRuleList =
+                StreamSupport.stream(flowRuleService.getFlowEntries(deviceId).spliterator(), false)
+                .filter(flowRule -> flowRule.appId() == appId.id()
+                        && getPushedVlanFromTreatment(flowRule.treatment()).equals(fc.vlanId())
+                        && getInPortNumberFromSelector(flowRule.selector()).equals(uni.cp().port()))
+                .collect(Collectors.toList());
+
+        // Apply meters to flows
+        for (FlowRule flowRule : flowRuleList) {
+            // Need to add to the flow the meters associated with the same device
+            Set<DeviceMeterId> tmpDeviceMeterIdSet = new HashSet<>();
+            deviceMeterIdMap.get(fc.id()).forEach(deviceMeterId -> {
+                if (deviceMeterId.deviceId().equals(flowRule.deviceId())) {
+                    tmpDeviceMeterIdSet.add(deviceMeterId);
+                }
+            });
+            // Modify and submit flow rule only if there are meters to add
+            if (!tmpDeviceMeterIdSet.isEmpty()) {
+                FlowRule newFlowRule = addMetersToFlowRule(flowRule, tmpDeviceMeterIdSet);
+                flowRuleService.applyFlowRules(newFlowRule);
+            }
+        }
+    }
+
+    private VlanId getPushedVlanFromTreatment(TrafficTreatment treatment) {
+        boolean pushVlan = false;
+        VlanId pushedVlan = null;
+        for (Instruction instruction : treatment.allInstructions()) {
+            if (instruction.type().equals(Instruction.Type.L2MODIFICATION)) {
+                L2ModificationInstruction l2ModInstr = (L2ModificationInstruction) instruction;
+                if (l2ModInstr.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_PUSH)) {
+                    pushVlan = true;
+                } else if (l2ModInstr.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_ID) && pushVlan) {
+                    pushedVlan = ((L2ModificationInstruction.ModVlanIdInstruction) instruction).vlanId();
+                }
+            }
+        }
+        return pushedVlan != null ? pushedVlan : VlanId.NONE;
+    }
+
+    private PortNumber getInPortNumberFromSelector(TrafficSelector selector) {
+        for (Criterion criterion : selector.criteria()) {
+            if (criterion.type().equals(Criterion.Type.IN_PORT)) {
+                return ((PortCriterion) criterion).port();
+            }
+        }
+        return PortNumber.portNumber("-1");
+    }
+
+    /**
+     * Creates and submits a meter with the required bands for a UNI.
+     *
+     * @param uni the UNI descriptor
+     * @return set of meter ids of the meters created
+     */
+    private Set<DeviceMeterId> createMeters(CarrierEthernetUni uni) {
+
+        // TODO: Check if meter already exists before adding it?
+
+        Set<DeviceMeterId> deviceMeterIdSet = new HashSet<>();
+
+        long longCir = (long) (uni.bwp().cir().bps() / 8000);
+        long longEir = (long) (uni.bwp().eir().bps() / 8000);
+
+        MeterRequest.Builder meterRequestBuilder;
+        Meter meter;
+        Band.Builder bandBuilder;
+
+        Set<Band> bandSet = new HashSet<>();
+
+        // If EIR is zero do not create the REMARK meter
+        if (longEir != 0) {
+            // Mark frames that exceed CIR as Best Effort
+            bandBuilder = DefaultBand.builder()
+                    .ofType(Band.Type.REMARK)
+                    .withRate(longCir)
+                    .dropPrecedence((short) 0);
+
+            if (uni.bwp().cbs() != 0) {
+                bandBuilder.burstSize(uni.bwp().cbs());
+            }
+
+            bandSet.add(bandBuilder.build());
+        }
+
+        // If CIR is zero do not create the DROP meter
+        if (longCir != 0) {
+            // Drop all frames that exceed CIR + EIR
+            bandBuilder = DefaultBand.builder()
+                    .ofType(Band.Type.DROP)
+                    .withRate(longCir + longEir);
+
+            if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
+                // FIXME: Use CBS and EBS correctly according to MEF specs
+                bandBuilder.burstSize(uni.bwp().cbs() + uni.bwp().ebs());
+            }
+
+            bandSet.add(bandBuilder.build());
+        }
+
+        // Create meter only if at least one band was created
+        if (!bandSet.isEmpty()) {
+            meterRequestBuilder = DefaultMeterRequest.builder()
+                    .forDevice(uni.cp().deviceId())
+                    .fromApp(appId)
+                    .withUnit(Meter.Unit.KB_PER_SEC)
+                    .withBands(bandSet);
+
+            if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
+                meterRequestBuilder.burst();
+            }
+
+            meter = meterService.submit(meterRequestBuilder.add());
+            deviceMeterIdSet.add(new DeviceMeterId(uni.cp().deviceId(), meter.id()));
+        }
+
+        return deviceMeterIdSet;
+    }
+
+    private FlowRule addMetersToFlowRule(FlowRule flowRule, Set<DeviceMeterId> deviceMeterIdSet) {
+
+        // FIXME: Refactor to use only single meter
+
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
+                .builder(flowRule.treatment());
+
+        deviceMeterIdSet.forEach(deviceMeterId -> {
+            tBuilder.meter(deviceMeterId.meterId()).
+                    transition(flowRule.treatment().tableTransition().tableId());
+        });
+
+        return createFlowRule(flowRule.deviceId(), flowRule.priority(),
+                flowRule.selector(), tBuilder.build(), flowRule.tableId());
+    }
+
+    @Override
+    public void removeBandwidthProfileResources(String fcId, CarrierEthernetUni uni) {
+        removeMeters(fcId, uni);
+    }
+
+    /**
+     * Removes the meters associated with a specific UNI of an FC.
+     *
+     * @param fcId the EVC ID
+     * @param uni the UNI descriptor
+     * */
+    private void removeMeters(String fcId, CarrierEthernetUni uni) {
+
+        Set<DeviceMeterId> newDeviceMeterIdSet = deviceMeterIdMap.get(fcId);
+        DeviceMeterId tmpDeviceMeterId;
+
+        Collection<Meter> meters = meterService.getMeters(uni.cp().deviceId());
+
+        Iterator<Meter> it = meters.iterator();
+        while (it.hasNext()) {
+            Meter meter = it.next();
+            tmpDeviceMeterId = new DeviceMeterId(uni.cp().deviceId(), meter.id());
+            if (meter.appId().equals(appId) &&
+                    deviceMeterIdMap.get(fcId).contains(tmpDeviceMeterId)) {
+                MeterRequest.Builder mBuilder;
+                mBuilder = DefaultMeterRequest.builder()
+                        .fromApp(meter.appId())
+                        .forDevice(meter.deviceId())
+                        .withUnit(meter.unit())
+                        .withBands(meter.bands());
+                if (uni.bwp().cbs() != 0 || uni.bwp().ebs() != 0) {
+                    mBuilder.burst();
+                }
+                meterService.withdraw(mBuilder.remove(), meter.id());
+                newDeviceMeterIdSet.remove(tmpDeviceMeterId);
+            }
+        }
+
+        deviceMeterIdMap.put(fcId, newDeviceMeterIdSet);
+    }
+
+    @Override
+    public void removeAllForwardingResources(CarrierEthernetForwardingConstruct fc) {
+        removeFlowObjectives(fc.id());
+    }
+
+    /**
+     * Removes all flow objectives installed by the application which are associated with a specific FC.
+     *
+     * @param fcId the FC id
+     * */
+    private void removeFlowObjectives(String fcId) {
+        // Note: A Flow Rule cannot be shared by multiple FCs due to different VLAN or CE-VLAN ID match.
+        List<Pair<DeviceId, Objective>> flowObjectiveList = flowObjectiveMap.remove(fcId);
+        // NextObjectives will be removed after all other Objectives
+        ListIterator<Pair<DeviceId, Objective>> objIter = flowObjectiveList.listIterator();
+        while (objIter.hasNext()) {
+            Pair<DeviceId, Objective> deviceObjectivePair = objIter.next();
+            flowObjectiveService.apply(deviceObjectivePair.getLeft(), deviceObjectivePair.getRight().copy().remove());
+        }
+
+    }
+
+    // FIXME: Replace with Pair<DeviceId, MeterId>
+    /**
+     * Utility class to compensate for the fact that MeterIds are not unique system-wide.
+     * */
+    class DeviceMeterId {
+        private DeviceId deviceId;
+        private MeterId meterId;
+
+        DeviceMeterId(DeviceId deviceId, MeterId meterId) {
+            this.deviceId = deviceId;
+            this.meterId = meterId;
+        }
+
+        public DeviceId deviceId() {
+            return deviceId;
+        }
+
+        public MeterId meterId() {
+            return meterId;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(deviceId, meterId);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof DeviceMeterId) {
+                DeviceMeterId other = (DeviceMeterId) obj;
+                if (this.deviceId().equals(other.deviceId()) && this.meterId().equals(other.meterId())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private FlowRule createFlowRule(DeviceId deviceId, int priority,
+                                    TrafficSelector selector, TrafficTreatment treatment, int tableId) {
+        return DefaultFlowRule.builder()
+                .fromApp(appId)
+                .forDevice(deviceId)
+                .makePermanent()
+                .withPriority(priority)
+                .withSelector(selector)
+                .withTreatment(treatment)
+                .forTable(tableId)
+                .build();
+    }
 
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeService.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeService.java
new file mode 100644
index 0000000..081acde
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketNodeService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.app;
+
+import java.util.Set;
+
+/**
+ * Abstraction of a class used to control Carrier Ethernet nodes according to their control protocol.
+ */
+public interface CarrierEthernetPacketNodeService {
+
+    void setNodeForwarding(CarrierEthernetForwardingConstruct fc, CarrierEthernetNetworkInterface srcNi,
+                                    Set<CarrierEthernetNetworkInterface> dstNiSet);
+
+    void createBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni);
+
+    void applyBandwidthProfileResources(CarrierEthernetForwardingConstruct fc, CarrierEthernetUni uni);
+
+    void removeBandwidthProfileResources(String fcId, CarrierEthernetUni uni);
+
+    void removeAllForwardingResources(CarrierEthernetForwardingConstruct fc);
+
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetProvisioner.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetProvisioner.java
index bbbecad..b0c6d8c 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetProvisioner.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetProvisioner.java
@@ -77,7 +77,7 @@
     protected TopologyService topologyService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CarrierEthernetOpenFlowPacketNodeManager ceOfPktNodeManager;
+    protected CarrierEthernetPacketNodeService cePktNodeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpticalPathService opticalPathService;
@@ -239,7 +239,7 @@
         ingressEgressNiMap.keySet().forEach(srcNi -> {
             // Set forwarding only on packet switches
             if (deviceService.getDevice(srcNi.cp().deviceId()).type().equals(Device.Type.SWITCH)) {
-                ceOfPktNodeManager.setNodeForwarding(fc, srcNi, ingressEgressNiMap.get(srcNi));
+                cePktNodeService.setNodeForwarding(fc, srcNi, ingressEgressNiMap.get(srcNi));
             }
         });
 
@@ -379,18 +379,28 @@
 
     public void removeConnectivity(CarrierEthernetForwardingConstruct fc) {
         // TODO: Add here the same call for all node manager types
-        ceOfPktNodeManager.removeAllForwardingResources(fc);
+        cePktNodeService.removeAllForwardingResources(fc);
         removeOpticalConnectivity(fc.metroConnectivity().id());
     }
 
     /**
+     * Creates bandwidth profiles at the UNIs of an FC.
+     *
+     * @param fc the FC representation
+     */
+    public void createBandwidthProfiles(CarrierEthernetForwardingConstruct fc) {
+        //  TODO: Select node manager depending on device protocol
+        fc.uniSet().forEach(uni -> cePktNodeService.createBandwidthProfileResources(fc, uni));
+    }
+
+    /**
      * Applies bandwidth profiles to the UNIs of an FC.
      *
      * @param fc the FC representation
      */
     public void applyBandwidthProfiles(CarrierEthernetForwardingConstruct fc) {
         //  TODO: Select node manager depending on device protocol
-        fc.uniSet().forEach(uni -> ceOfPktNodeManager.applyBandwidthProfileResources(fc, uni));
+        fc.uniSet().forEach(uni -> cePktNodeService.applyBandwidthProfileResources(fc, uni));
     }
 
     /**
@@ -402,7 +412,7 @@
         //  TODO: Select node manager depending on device protocol
         fc.ltpSet().forEach((ltp -> {
             if (ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
-                ceOfPktNodeManager.removeBandwidthProfileResources(fc.id(), (CarrierEthernetUni) ltp.ni());
+                cePktNodeService.removeBandwidthProfileResources(fc.id(), (CarrierEthernetUni) ltp.ni());
             }
         }));
     }
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 75ac1b6..6303108 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
@@ -71,6 +71,7 @@
     public CarrierEthernetUni(ConnectPoint cp, String uniCfgId, Role role, VlanId ceVlanId,
                               CarrierEthernetBandwidthProfile bwp) {
         super(cp, Type.UNI, uniCfgId);
+
         this.role = role;
         // FIXME: Set the NI scope directly instead?
         this.scope = (role == null ? Scope.GLOBAL : Scope.SERVICE);
@@ -137,11 +138,13 @@
 
         // Add UNI BWP
         CarrierEthernetBandwidthProfile bwp = uni.bwp();
-        Map<String, CarrierEthernetBandwidthProfile> subBwpMap = this.bwpMap.get(bwp.type());
-        subBwpMap.put(bwp.id(), bwp);
-        this.bwpMap.put(bwp.type(), subBwpMap);
-        // Used capacity cannot be more than UNI capacity (redundant check - should be avoided by check in validateBwp)
-        this.usedCapacity = Bandwidth.bps(Math.min(this.usedCapacity.bps() + bwp.cir().bps(), this.capacity.bps()));
+        if (bwp != null) {
+            Map<String, CarrierEthernetBandwidthProfile> subBwpMap = this.bwpMap.get(bwp.type());
+            subBwpMap.put(bwp.id(), bwp);
+            this.bwpMap.put(bwp.type(), subBwpMap);
+            // Used capacity cannot be more than UNI capacity (redundant check - should be avoided by check in validateBwp)
+            this.usedCapacity = Bandwidth.bps(Math.min(this.usedCapacity.bps() + bwp.cir().bps(), this.capacity.bps()));
+        }
     }
 
     /**
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateEvcCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateEvcCommand.java
index b95236b..a92fae6 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateEvcCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateEvcCommand.java
@@ -23,7 +23,6 @@
 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.CarrierEthernetNetworkInterface;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetVirtualConnection;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetUni;
 import org.onosproject.cli.AbstractShellCommand;
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateFcCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateFcCommand.java
index ee7f058..0a2e6f3 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateFcCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateFcCommand.java
@@ -139,7 +139,7 @@
         CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
 
         // Update list of global LTPs in the network
-        ceManager.getLtpsFromTopo().forEach(ltp -> ceManager.addGlobalLtp(ltp));
+        ceManager.getLtpsFromTopo(true, false).forEach(ltp -> ceManager.addGlobalLtp(ltp));
 
         Set<CarrierEthernetLogicalTerminationPoint> ltpSet = new HashSet<>();
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListLtpsCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListLtpsCommand.java
index 0188437..588d40d 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListLtpsCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListLtpsCommand.java
@@ -33,7 +33,7 @@
     protected void execute() {
         CarrierEthernetManager evcManager = get(CarrierEthernetManager.class);
         // Populate global LTP map
-        evcManager.getLtpsFromTopo().forEach(ltp -> evcManager.addGlobalLtp(ltp));
+        evcManager.getLtpsFromTopo(false, false).forEach(ltp -> evcManager.addGlobalLtp(ltp));
         printLtps(evcManager.ltpMap().values());
     }
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListUnisCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListUnisCommand.java
index 98e600f..ce635f2 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListUnisCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetListUnisCommand.java
@@ -33,7 +33,7 @@
     protected void execute() {
         CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
         // Populate global UNI map
-        ceManager.getUnisFromTopo().forEach(uni -> ceManager.addGlobalUni(uni));
+        ceManager.getUnisFromTopo(false, false).forEach(uni -> ceManager.addGlobalUni(uni));
         printUnis(ceManager.getUniMap().values());
     }
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpCompleter.java
index 79d5de5..e72c431 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpCompleter.java
@@ -24,7 +24,7 @@
 import java.util.SortedSet;
 
 /**
- * LTP ID completer.
+ * LTP id completer, including only LTPs that have been added to the LTP map.
  */
 public class CarrierEthernetLtpCompleter extends AbstractCompleter {
     @Override
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialLtpCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialLtpCompleter.java
index 3e1b62f..29c5179 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialLtpCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialLtpCompleter.java
@@ -24,7 +24,7 @@
 import java.util.SortedSet;
 
 /**
- * Potential LTP ConnectPoint completer.
+ * LTP id completer, excluding LTPs already added and including LTPs that have been removed.
  */
 public class CarrierEthernetPotentialLtpCompleter extends AbstractCompleter {
     @Override
@@ -34,9 +34,8 @@
         SortedSet<String> strings = delegate.getStrings();
 
         CarrierEthernetManager ceManager = AbstractShellCommand.get(CarrierEthernetManager.class);
-        ceManager.getLtpsFromTopo().forEach(ltp -> strings.add(ltp.id()));
+        ceManager.getLtpsFromTopo(true, true).forEach(ltp -> strings.add(ltp.id()));
 
         return delegate.complete(buffer, cursor, candidates);
     }
-
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialUniCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialUniCompleter.java
index 7a1e3e1..c0bdbfe 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialUniCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetPotentialUniCompleter.java
@@ -24,7 +24,7 @@
 import java.util.SortedSet;
 
 /**
- * Potential UNI ConnectPoint completer.
+ * UNI id completer, excluding UNIs that have already been added and including UNIs that have been removed.
  */
 public class CarrierEthernetPotentialUniCompleter extends AbstractCompleter {
 
@@ -35,9 +35,8 @@
         SortedSet<String> strings = delegate.getStrings();
 
         CarrierEthernetManager ceManager = AbstractShellCommand.get(CarrierEthernetManager.class);
-        ceManager.getUnisFromTopo().forEach(uni -> strings.add(uni.id()));
+        ceManager.getUnisFromTopo(true, true).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/completers/CarrierEthernetUniCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetUniCompleter.java
index 15f446c..ef00759 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetUniCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetUniCompleter.java
@@ -24,7 +24,7 @@
 import java.util.SortedSet;
 
 /**
- * UNI ID completer.
+ * UNI id completer, including only UNIs that have been added to the UNI map.
  */
 public class CarrierEthernetUniCompleter extends AbstractCompleter {
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidLtpCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidLtpCompleter.java
new file mode 100644
index 0000000..da9335d
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidLtpCompleter.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.completers;
+
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * LTP id completer, not including LTPs that have been removed.
+ */
+public class CarrierEthernetValidLtpCompleter extends AbstractCompleter {
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+
+        StringsCompleter delegate = new UniqueStringsCompleter();
+        SortedSet<String> strings = delegate.getStrings();
+
+        CarrierEthernetManager ceManager = AbstractShellCommand.get(CarrierEthernetManager.class);
+        ceManager.getLtpsFromTopo(false, false).forEach(ltp -> strings.add(ltp.id()));
+
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidUniCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidUniCompleter.java
new file mode 100644
index 0000000..d0f49de
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetValidUniCompleter.java
@@ -0,0 +1,42 @@
+/*
+ * 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.completers;
+
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * UNI id completer, not including UNIs that have been removed.
+ */
+public class CarrierEthernetValidUniCompleter extends AbstractCompleter {
+
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+
+        StringsCompleter delegate = new UniqueStringsCompleter();
+        SortedSet<String> strings = delegate.getStrings();
+
+        CarrierEthernetManager ceManager = AbstractShellCommand.get(CarrierEthernetManager.class);
+        ceManager.getUnisFromTopo(false, false).forEach(uni -> strings.add(uni.id()));
+
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
\ No newline at end of file
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 1643486..117e7c1 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
@@ -21,8 +21,8 @@
             <completers>
                 <ref component-id="placeholderCompleter"/>
                 <ref component-id="carrierEthernetEvcTypeCompleter"/>
-                <ref component-id="carrierEthernetPotentialUniCompleter"/>
-                <ref component-id="carrierEthernetPotentialUniCompleter"/>
+                <ref component-id="carrierEthernetValidUniCompleter"/>
+                <ref component-id="carrierEthernetValidUniCompleter"/>
             </completers>
         </command>
     </command-bundle>
@@ -33,8 +33,8 @@
             <completers>
                 <ref component-id="placeholderCompleter"/>
                 <ref component-id="carrierEthernetEvcTypeCompleter"/>
-                <ref component-id="carrierEthernetPotentialLtpCompleter"/>
-                <ref component-id="carrierEthernetPotentialLtpCompleter"/>
+                <ref component-id="carrierEthernetValidLtpCompleter"/>
+                <ref component-id="carrierEthernetValidLtpCompleter"/>
             </completers>
         </command>
     </command-bundle>
@@ -98,7 +98,7 @@
             <action class="org.onosproject.ecord.carrierethernet.cli.commands.CarrierEthernetCreateLtpCommand"/>
             <completers>
                 <ref component-id="carrierEthernetLtpTypeCompleter"/>
-                <ref component-id="carrierEthernetConnectPointCompleter"/>
+                <ref component-id="carrierEthernetPotentialLtpCompleter"/>
             </completers>
         </command>
     </command-bundle>
@@ -107,7 +107,7 @@
         <command>
             <action class="org.onosproject.ecord.carrierethernet.cli.commands.CarrierEthernetCreateUniCommand"/>
             <completers>
-                <ref component-id="carrierEthernetConnectPointCompleter"/>
+                <ref component-id="carrierEthernetPotentialUniCompleter"/>
             </completers>
         </command>
     </command-bundle>
@@ -150,6 +150,8 @@
     <bean id="carrierEthernetLtpTypeCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetLtpTypeCompleter"/>
     <bean id="carrierEthernetUniCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetUniCompleter"/>
     <bean id="carrierEthernetLtpCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetLtpCompleter"/>
+    <bean id="carrierEthernetValidUniCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetValidUniCompleter"/>
+    <bean id="carrierEthernetValidLtpCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetValidLtpCompleter"/>
     <bean id="carrierEthernetBooleanCompleter" class="org.onosproject.ecord.carrierethernet.cli.completers.CarrierEthernetBooleanCompleter"/>