Major refactoring/modifications to allow E-LAN/E-Tree using FlowObjectives

- Path calculation, optical connectivity handling and NetworkConfig-based VLAN assignment moved to CarrierEthernetProvisioner.java
- For E-LAN/E-Tree use only paths going over the pre-calculated spanning tree
- Using BROADCAST NextObjectives with multiple treatments for E-LAN/E-Tree
- Introducing GENERIC NI type to facilitate forwarding establishment
- Some code cleanup here and there
- (REMINDER: Using FCs with CPqD still requires Change 9696)

Change-Id: Id60bcde7e3bebbb9c91d6fcbed0276af8b1b48b5
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 5f6b11c..d7b4d95 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
@@ -61,7 +61,7 @@
     public CarrierEthernetEnni(ConnectPoint connectPoint, String uniCfgId, Role role, VlanId sVlanId, String tpid,
                                Bandwidth usedCapacity) {
 
-        super(connectPoint, uniCfgId);
+        super(connectPoint, Type.ENNI, 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/CarrierEthernetForwardingConstruct.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetForwardingConstruct.java
index 245ca0c..55ce9cb 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
@@ -16,18 +16,22 @@
 package org.onosproject.ecord.carrierethernet.app;
 
 import org.onosproject.newoptical.api.OpticalPathEvent;
+import org.slf4j.Logger;
 
 import java.time.Duration;
 import java.util.HashSet;
 import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Representation of a CE Forwarding Construct.
  */
 public class CarrierEthernetForwardingConstruct {
 
+    private final Logger log = getLogger(getClass());
+
     public enum State {
 
         ACTIVE("Active"),
@@ -109,13 +113,13 @@
 
         // 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<>();
+        Set<CarrierEthernetNetworkInterface> niSet = new HashSet<>();
         ltpSet.forEach(ltp -> {
-            if (ltp.ni() instanceof CarrierEthernetUni) {
-                uniSet.add((CarrierEthernetUni) ltp.ni());
+            if (ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                niSet.add(ltp.ni());
             }
         });
-        this.evcLite = new CarrierEthernetVirtualConnection(fcId, fcCfgId, evcType, null, uniSet);
+        this.evcLite = new CarrierEthernetVirtualConnection(fcId, fcCfgId, evcType, null, niSet);
     }
 
     // TODO: Create constructor using the End-to-End service and a set of LTPs
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetGenericNi.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetGenericNi.java
new file mode 100644
index 0000000..2ddba2e
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetGenericNi.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.app;
+
+import 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;
+import org.slf4j.Logger;
+
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Set;
+
+/**
+ * Representation of a Generic Carrier Ethernet NI.
+ * Class is only mean to be used for establishing forwarding in CarrierEthernetPacketNodeManagers
+ */
+public class CarrierEthernetGenericNi extends CarrierEthernetNetworkInterface {
+
+    public enum Role {
+
+        NONE("None");
+
+        private String value;
+
+        Role(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    public CarrierEthernetGenericNi(ConnectPoint connectPoint, String uniCfgId) {
+        super(connectPoint, Type.GENERIC, uniCfgId);
+    }
+
+    public Role role() {
+        return Role.NONE;
+    }
+
+    /**
+     * Always returns null, since CE-VLAN IDs are not associated with Generic NIs.
+     *
+     * @return null
+     */
+    @Override
+    public VlanId ceVlanId() {
+        return null;
+    }
+
+    /**
+     * Always returns null, since S-TAGs are not associated with Generic NIs.
+     *
+     * @return null
+     */
+    @Override
+    public VlanId sVlanId() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+
+        return toStringHelper(this)
+                .add("id", this.id)
+                .add("cfgId", this.cfgId)
+                .add("refCount", refCount)
+                .add("capacity", this.capacity)
+                .add("usedCapacity", this.usedCapacity).toString();
+    }
+
+}
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 3ea947d..c876244 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
@@ -64,7 +64,7 @@
     public CarrierEthernetInni(ConnectPoint connectPoint, String uniCfgId, Role role, VlanId sVlanId, String tpid,
                                Bandwidth usedCapacity) {
 
-        super(connectPoint, uniCfgId);
+        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 aad7efb..ba564d4 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
@@ -52,40 +52,8 @@
         }
     }
 
-    public enum Type {
-        UNI, INNI, ENNI
-    }
-
-    /*public enum Type {
-
-        UNI("UNI"), INNI("INNI"), ENNI("ENNI");
-
-        private String value;
-
-        Type(String value) {
-            this.value = value;
-        }
-
-        @Override
-        public String toString() {
-            return value;
-        }
-
-        public static Type fromString(String value) {
-            if (value != null) {
-                for (Type b : Type.values()) {
-                    if (value.equals(b.value)) {
-                        return b;
-                    }
-                }
-            }
-            throw new IllegalArgumentException("Type " + value + " is not valid");
-        }
-    }*/
-
     protected String ltpId;
     protected String ltpCfgId;
-    protected Type type;
     protected Role role;
     // A global LTP will point to the corresponding global NI and a service LTP to the corresponding service NI
     protected CarrierEthernetNetworkInterface ni;
@@ -94,14 +62,11 @@
         checkNotNull(ni);
         this.ni = ni;
         // NOTE: Role is expected to be null for global LTPs/NIs
-        if (ni instanceof CarrierEthernetUni) {
-            this.type = Type.UNI;
+        if (ni.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
             this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetUni) ni).role().name()));
-        } else if (ni instanceof CarrierEthernetInni) {
-            this.type = Type.INNI;
+        } else if (ni.type().equals(CarrierEthernetNetworkInterface.Type.INNI)) {
             this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetInni) ni).role().name()));
-        } else {
-            this.type = Type.ENNI;
+        } else if (ni.type().equals(CarrierEthernetNetworkInterface.Type.ENNI)) {
             this.role = (ni.role() == null ? null : Role.valueOf(((CarrierEthernetEnni) ni).role().name()));
         }
         this.ltpId = this.cp().deviceId().toString() + "/" + this.cp().port().toString();
@@ -109,16 +74,15 @@
     }
 
     public CarrierEthernetLogicalTerminationPoint(ConnectPoint cp, String ltpCfgId,
-                                                  CarrierEthernetLogicalTerminationPoint.Type ltpType) {
-        this.type = ltpType;
+                                                  CarrierEthernetNetworkInterface.Type niType) {
         this.ltpId = cp.deviceId().toString() + "/" + cp.port().toString();
         this.ltpCfgId = (ltpCfgId == null ? this.ltpId : ltpCfgId);
         // NOTE: Role is expected to be null for service-specific LTPs/NIs
-        if (ltpType.equals(CarrierEthernetLogicalTerminationPoint.Type.UNI)) {
+        if (niType.equals(CarrierEthernetNetworkInterface.Type.UNI)) {
             this.ni = new CarrierEthernetUni(cp, ltpId, null, null, null);
-        } else if (ltpType.equals(CarrierEthernetLogicalTerminationPoint.Type.INNI)) {
+        } else if (niType.equals(CarrierEthernetNetworkInterface.Type.INNI))  {
             this.ni = new CarrierEthernetInni(cp, ltpId, null, null, null, null);
-        } else {
+        } else if (niType.equals(CarrierEthernetNetworkInterface.Type.ENNI)) {
             this.ni = new CarrierEthernetEnni(cp, ltpId, null, null, null, null);
         }
     }
@@ -164,8 +128,8 @@
      *
      * @return LTP type
      */
-    public Type type() {
-        return type;
+    public CarrierEthernetNetworkInterface.Type type() {
+        return ni.type();
     }
 
     /**
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 47e494f..d22e8c6 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
@@ -15,7 +15,6 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -25,37 +24,21 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.VlanId;
 
-import org.onlab.util.Bandwidth;
-import org.onosproject.newoptical.api.OpticalConnectivityId;
-import org.onosproject.newoptical.api.OpticalPathEvent;
-import org.onosproject.newoptical.api.OpticalPathListener;
-import org.onosproject.newoptical.api.OpticalPathService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
-import org.onosproject.net.Link;
 import org.onosproject.net.Port;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.link.LinkService;
 import org.slf4j.Logger;
 
-import java.time.Duration;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-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;
-import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
 import static org.slf4j.LoggerFactory.getLogger;
 
 @Component(immediate = true)
@@ -71,37 +54,11 @@
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected OpticalPathService opticalPathService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CarrierEthernetPacketProvisioner cePktProvisioner;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry cfgRegistry;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigService networkConfigService;
-
-    private final List<ConfigFactory<?, ?>> factories = ImmutableList.of(
-            new ConfigFactory<ConnectPoint, PortVlanConfig>(CONNECT_POINT_SUBJECT_FACTORY,
-                    PortVlanConfig.class, PortVlanConfig.CONFIG_KEY) {
-                @Override
-                public PortVlanConfig createConfig() {
-                    return new PortVlanConfig();
-                }
-            });
-
-    private OpticalPathListener opticalEventListener = new OpticalEventListener();
-    private NetworkConfigListener netcfgListener = new InternalNetworkConfigListener();
+    protected CarrierEthernetProvisioner ceProvisioner;
 
     // Keeps track of the next S-VLAN tag the app will try to use
     private static short nextVlanId = 1;
 
-    private static final int OPTICAL_CONNECT_TIMEOUT_MILLIS = 7000;
-
-    // If set to false, the setup of optical connectivity using the metro app is bypassed
-    private boolean pktOpticalTopo = false;
-
     // TODO: Implement distributed store for EVCs
     // The installed EVCs
     private final Map<String, CarrierEthernetVirtualConnection> evcMap = new ConcurrentHashMap<>();
@@ -110,19 +67,15 @@
     // The installed Forwarding Constructs
     private final Map<String, CarrierEthernetForwardingConstruct> fcMap = new ConcurrentHashMap<>();
 
-    // TODO: Refactor this part
-    private final Map<OpticalConnectivityId, OpticalPathEvent.Type> opticalConnectStatusMap = new ConcurrentHashMap<>();
-
     // TODO: Implement distributed store for CE UNIs
     // The installed CE UNIs
     private final Map<String, CarrierEthernetUni> uniMap = new ConcurrentHashMap<>();
     private final Set<String> removedUniSet = Sets.newConcurrentHashSet();;
 
-    // Map of connect points and corresponding VLAN tag
-    private Map<ConnectPoint, VlanId> portVlanMap = new ConcurrentHashMap<>();
     // TODO: Implement distributed store for CE LTPs
     // The installed CE LTPs
     private final Map<String, CarrierEthernetLogicalTerminationPoint> ltpMap = new ConcurrentHashMap<>();
+
     // The LTP ids that have been explicitly removed (or requested to be removed) from the global LTP map
     private final Set<String> removedLtpSet = Sets.newConcurrentHashSet();;
 
@@ -130,11 +83,7 @@
      * Activate this component.
      */
     @Activate
-    public void activate() {
-        factories.forEach(cfgRegistry::registerConfigFactory);
-        networkConfigService.addListener(netcfgListener);
-        opticalPathService.addListener(opticalEventListener);
-    }
+    public void activate() {}
 
     /**
      * Deactivate this component.
@@ -143,10 +92,6 @@
     public void deactivate() {
         removeAllEvcs();
         removeAllFcs();
-        opticalPathService.removeListener(opticalEventListener);
-        networkConfigService.removeListener(netcfgListener);
-
-        factories.forEach(cfgRegistry::unregisterConfigFactory);
     }
 
     /**
@@ -229,14 +174,19 @@
         }
 
         // Verify that CE-VLAN ID is provided to either all UNIs or none and set the virtualEvc flag accordingly
+        // Note: Checking also that all NIs are UNIs
         boolean isVirtual = false;
-        Iterator<CarrierEthernetUni> it = evc.uniSet().iterator();
+        Iterator<CarrierEthernetNetworkInterface> it = evc.niSet().iterator();
         while (it.hasNext()) {
-            CarrierEthernetUni uni = it.next();
-            if (uni.ceVlanId() == VlanId.NONE && isVirtual) {
+            CarrierEthernetNetworkInterface ni = it.next();
+            if (!ni.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                log.error("All EVC NIs have to be of type UNI.");
+                return null;
+            }
+            if (ni.ceVlanId() == VlanId.NONE && isVirtual) {
                 log.error("Could not validate the virtual status of the EVC.");
                 return null;
-            } else if (uni.ceVlanId() != VlanId.NONE){
+            } else if (ni.ceVlanId() != VlanId.NONE){
                 isVirtual = true;
             }
         }
@@ -247,12 +197,12 @@
             evc.setId(generateEvcId(evc));
         }
 
-        Set<CarrierEthernetUni> validatedUniSet = new HashSet<>();
+        Set<CarrierEthernetNetworkInterface> validatedUniSet = new HashSet<>();
 
         // Check the UNIs of the EVC, possibly removing UNIs that are incompatible with existing global ones
-        it = evc.uniSet().iterator();
+        it = evc.niSet().iterator();
         while (it.hasNext()) {
-            CarrierEthernetUni uni = it.next();
+            CarrierEthernetUni uni = (CarrierEthernetUni) it.next();
             // Change the name of the UNI's BWP to the EVC name if it is an EVC BWP
             if (uni.bwp().type().equals(CarrierEthernetBandwidthProfile.Type.EVC)) {
                 uni.bwp().setId(evc.id());
@@ -281,21 +231,21 @@
         }
 
         // Update the EVC UNI set, based on the validated UNIs
-        evc.setUniSet(validatedUniSet);
+        evc.setNiSet(validatedUniSet);
 
-        if (evc.uniSet().size() > evc.maxNumUni()) {
+        if (evc.niSet().size() > evc.maxNumUni()) {
             log.error("{} EVC can have at most {} UNIs.", evc.maxNumUni());
             return null;
         }
 
         if ((evc.type().equals(CarrierEthernetVirtualConnection.Type.ROOT_MULTIPOINT)
                 || evc.type().equals(CarrierEthernetVirtualConnection.Type.MULTIPOINT_TO_MULTIPOINT))
-                && (evc.uniSet().size() < 2)) {
+                && (evc.niSet().size() < 2)) {
             log.error("{} EVC requires at least two UNIs.", evc.type().name());
             return null;
         }
 
-        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT) && (evc.uniSet().size() != 2)) {
+        if (evc.type().equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT) && (evc.niSet().size() != 2)) {
             log.error("{} EVC requires exactly two UNIs.", evc.type().name());
             return null;
         }
@@ -303,6 +253,7 @@
         return evc;
     }
 
+    // TODO: Refactor so that EVCs are always made of FCs
     /**
      * Establish connectivity according to the EVC type (E-Line, E-Tree, E-LAN) and the EVC parameters.
      *
@@ -318,112 +269,25 @@
             evc.setId(null);
         }
 
-        validateEvc(evc);
+        evc = validateEvc(evc);
 
         if (evc == null) {
             log.error("EVC could not be installed, please check log for details.");
             return null;
         }
 
-        boolean allPairsConnected = true;
-
-        // Temporary set for iterating through EVC UNI pairs
-        Set<CarrierEthernetUni> uniSet = new HashSet<>(evc.uniSet());
-
-        // Temporary set for indicating which UNIs were finally included in the EVC
-        Set<CarrierEthernetUni> usedUniSet = new HashSet<>();
-
-        Iterator<CarrierEthernetUni> uniIt1 = uniSet.iterator();
-        while (uniIt1.hasNext()) {
-
-            CarrierEthernetUni uni1 = uniIt1.next();
-
-            // Iterate through all the remaining UNIs
-            Iterator<CarrierEthernetUni> uniIt2 = uniSet.iterator();
-            while (uniIt2.hasNext()) {
-
-                CarrierEthernetUni uni2 = uniIt2.next();
-
-                // Skip equals
-                if (uni1.equals(uni2)) {
-                    continue;
-                }
-
-                // Do not establish connectivity between leaf UNIs (applies to Rooted_Multipoint)
-                if (uni1.role() == CarrierEthernetUni.Role.LEAF && uni2.role() == CarrierEthernetUni.Role.LEAF) {
-                    continue;
-                }
-
-                OpticalConnectivityId opticalConnectId = null;
-
-                if (pktOpticalTopo) {
-                    opticalConnectId = setupOpticalConnectivity(uni1.cp(), uni2.cp(), uni1.bwp().cir(), evc.latency());
-
-                    if (opticalConnectId == null ||
-                            opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_INSTALLED) {
-                        log.error("Could not establish optical connectivity between {} and {}" +
-                                        " (optical id and status: {}, {})", uni1.cp(), uni2.cp(), opticalConnectId,
-                                (opticalConnectId == null ? "null" : opticalConnectStatusMap.get(opticalConnectId)));
-                        allPairsConnected = false;
-                        continue;
-                    }
-
-                    if (opticalConnectId != null) {
-                        evc.setMetroConnectivityId(opticalConnectId);
-                        evc.setMetroConnectivityStatus(opticalConnectStatusMap.get(opticalConnectId));
-                    }
-
-                    log.info("Metro connectivity id and status for EVC {}: {}, {}", evc.id(),
-                            evc.metroConnectivity().id(), evc.metroConnectivity().status());
-
-                    if (opticalConnectId != null) {
-                        // TODO: find vlanIds for both CO and store to service
-                        opticalPathService.getPath(opticalConnectId).ifPresent(links -> {
-                            getVlanTag(links).ifPresent(vlan -> {
-                                log.info("VLAN ID {} is assigned to CE service {}", vlan, evc.id());
-                                evc.setVlanId(vlan);
-                            });
-                        });
-                    }
-                }
-
-                if (!cePktProvisioner.setupConnectivity(uni1, uni2, evc)) {
-                    log.warn("Could not set up packet connectivity between {} and {}", uni1, uni2);
-                    removeOpticalConnectivity(opticalConnectId);
-                    allPairsConnected = false;
-                    continue;
-                }
-
-                // Indicate that connection for at least one UNI pair has been established
-                evc.setState(CarrierEthernetVirtualConnection.State.ACTIVE);
-
-                // Add UNIs to the set of UNIs used by the EVC
-                usedUniSet.add(uni1);
-                usedUniSet.add(uni2);
-            }
-            // Remove UNI from temporary set so that each pair is visited only once
-            uniIt1.remove();
-        }
-
-        // Update the EVC UNI set, based on the UNIs actually used
-        evc.setUniSet(usedUniSet);
+        ceProvisioner.setupConnectivity(evc.niSet(), evc);
 
         // If no pair was connected, do not register the EVC
         if (evc.state().equals(CarrierEthernetVirtualConnection.State.ACTIVE)) {
-            evcMap.put(evc.id(), evc);
-            cePktProvisioner.applyBandwidthProfiles(evc);
+            // Apply BWP-related resources (e.g. Meters) to the packet switches
+            ceProvisioner.applyBandwidthProfiles(evc);
             // Apply the BWPs of the EVC UNI to the global UNIs, creating them if needed
-            applyBandwidthProfiles(evc.uniSet());
+            applyBandwidthProfiles(evc.niSet());
             // Increment the global UNI reference count
-            usedUniSet.forEach(uni -> uniMap.get(uni.id()).refCount().incrementAndGet());
-        }
-
-        if (evc.state().equals(CarrierEthernetVirtualConnection.State.ACTIVE)) {
-            if (allPairsConnected) {
-                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.FULL);
-            } else {
-                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.PARTIAL);
-            }
+            // FIXME: Remove this as soon as EVCs are made of FCs
+            evc.niSet().forEach(uni -> uniMap.get(uni.id()).refCount().incrementAndGet());
+            evcMap.put(evc.id(), evc);
         }
 
         return evc;
@@ -449,17 +313,17 @@
     /**
      * Applies bandwidth profiles to the UNIs of an EVC and if needed adds the UNIs to the global UNI map.
      *
-     * @param  uniSet set of UNIs that are included in the EVC
+     * @param  niSet set of UNIs that are included in the EVC
      */
-    private void applyBandwidthProfiles(Set<CarrierEthernetUni> uniSet) {
+    private void applyBandwidthProfiles(Set<CarrierEthernetNetworkInterface> niSet) {
 
-        uniSet.forEach(uni -> {
+        niSet.forEach(uni -> {
             if (!(uniMap.keySet().contains(uni.id()))) {
                 // Just add the UNI as it appears at the EVC
-                uniMap.put(uni.id(), uni);
+                uniMap.put(uni.id(), (CarrierEthernetUni) uni);
             } else {
                 // Add UNI resources (BWP, CE-VLAN ID) to existing global UNI
-                uniMap.get(uni.id()).addEvcUni(uni);
+                uniMap.get(uni.id()).addEvcUni((CarrierEthernetUni) uni);
                 // Update config identifier
                 uniMap.get(uni.id()).setCfgId(uni.cfgId());
             }
@@ -473,12 +337,12 @@
      */
     private void removeBandwidthProfiles(String evcId) {
 
-        evcMap.get(evcId).uniSet().forEach(uni -> {
+        evcMap.get(evcId).niSet().forEach(uni -> {
             // TODO: Check if the bandwidth profile really needs to be removed (e.g. may be CoS)
-            cePktProvisioner.removeBandwidthProfiles(evcMap.get(evcId));
+            ceProvisioner.removeBandwidthProfiles(evcMap.get(evcId));
 
             // Remove UNI resources (BWP, CE-VLAN ID) from global UNI
-            uniMap.get(uni.id()).removeEvcUni(uni);
+            uniMap.get(uni.id()).removeEvcUni((CarrierEthernetUni) uni);
         });
     }
 
@@ -490,15 +354,14 @@
     public void removeAllEvcs() {
         evcMap.keySet().forEach(evcId -> {
             CarrierEthernetVirtualConnection evc = evcMap.get(evcId);
-            cePktProvisioner.removeConnectivity(evc);
-            cePktProvisioner.removeBandwidthProfiles(evc);
-            removeOpticalConnectivity(evc.metroConnectivity().id());
+            ceProvisioner.removeConnectivity(evc);
+            ceProvisioner.removeBandwidthProfiles(evc);
             removeBandwidthProfiles(evcId);
             // Avoid excessively incrementing VLAN ids
             nextVlanId = (evc.vlanId().toShort() < nextVlanId ? evc.vlanId().toShort() : nextVlanId);
             // Decrement the global UNI and corresponding NI refCount
             // FIXME: Remove this as soon as EVCs are always made of FCs
-            evc.uniSet().forEach(uni -> uniMap.get(uni.id()).refCount().decrementAndGet());
+            evc.niSet().forEach(uni -> uniMap.get(uni.id()).refCount().decrementAndGet());
         });
         evcMap.clear();
     }
@@ -511,20 +374,18 @@
     public void removeEvc(String evcId) {
         if (evcMap.containsKey(evcId)) {
             CarrierEthernetVirtualConnection evc = evcMap.get(evcId);
-            cePktProvisioner.removeConnectivity(evc);
-            cePktProvisioner.removeBandwidthProfiles(evc);
-            removeOpticalConnectivity(evc.metroConnectivity().id());
+            ceProvisioner.removeConnectivity(evc);
+            ceProvisioner.removeBandwidthProfiles(evc);
             removeBandwidthProfiles(evcId);
             // Avoid excessively incrementing VLAN ids
             nextVlanId = (evc.vlanId().toShort() < nextVlanId ? evc.vlanId().toShort() : nextVlanId);
             // Decrement the global UNI and corresponding NI refCount
             // FIXME: Remove this as soon as EVCs are always made of FCs
-            evc.uniSet().forEach(uni -> uniMap.get(uni.id()).refCount().decrementAndGet());
+            evc.niSet().forEach(uni -> uniMap.get(uni.id()).refCount().decrementAndGet());
             evcMap.remove(evcId);
         }
     }
 
-    // FIXME: Rethink this approach
     /**
      * Verify the validity of an FC representation taking also into account current network status.
      *
@@ -543,9 +404,9 @@
 
         // Verify that CE-VLAN ID is provided to either all UNIs or none and set the virtualEvc flag accordingly
         boolean isVirtual = false;
-        Iterator<CarrierEthernetUni> it = fc.evcLite().uniSet().iterator();
+        Iterator<CarrierEthernetNetworkInterface> it = fc.evcLite().niSet().iterator();
         while (it.hasNext()) {
-            CarrierEthernetUni uni = it.next();
+            CarrierEthernetUni uni = (CarrierEthernetUni) it.next();
             if (uni.ceVlanId() == null && isVirtual) {
                 log.error("Could not validate the virtual status of the EVC.");
                 return null;
@@ -562,9 +423,9 @@
         Set<CarrierEthernetUni> validatedUniSet = new HashSet<>();
 
         // Check the UNIs of the EVC, possibly removing UNIs that are incompatible with existing ones
-        it = fc.evcLite().uniSet().iterator();
+        it = fc.evcLite().niSet().iterator();
         while (it.hasNext()) {
-            CarrierEthernetUni uni = it.next();
+            CarrierEthernetUni uni = (CarrierEthernetUni) it.next();
             // Change the name of the UNI's BWP to the EVC name if it is an EVC BWP
             if (uni.bwp().type().equals(CarrierEthernetBandwidthProfile.Type.EVC)) {
                 uni.bwp().setId(fc.evcLite().id());
@@ -599,7 +460,8 @@
         Iterator<CarrierEthernetLogicalTerminationPoint> ltpIt = fc.ltpSet().iterator();
         while(ltpIt.hasNext()) {
             CarrierEthernetLogicalTerminationPoint ltp = ltpIt.next();
-            if ((ltp.ni() instanceof CarrierEthernetUni) && (!validatedUniSet.contains(ltp.ni()))) {
+            if ((ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI))
+                    && (!validatedUniSet.contains(ltp.ni()))) {
                 continue;
             }
             validatedLtpSet.add(ltp);
@@ -609,7 +471,6 @@
         return fc;
     }
 
-    // FIXME: Rethink this approach
     /**
      * Installs all resources associated with a specific FC.
      *
@@ -625,89 +486,55 @@
             fc.setId(null);
         }
 
-        validateFc(fc);
+        fc = 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());
         });
 
-        // Temporary set for indicating which NIs were finally included in the FC
-        Set<CarrierEthernetNetworkInterface> usedNiSet = new HashSet<>();
+        ceProvisioner.setupConnectivity(niSet, fc.evcLite());
 
-        Iterator<CarrierEthernetNetworkInterface> it1 = niSet.iterator();
-        while (it1.hasNext()) {
-
-            CarrierEthernetNetworkInterface ni1 = it1.next();
-
-            // Iterate through all the remaining UNIs
-            Iterator<CarrierEthernetNetworkInterface> it2 = niSet.iterator();
-            while (it2.hasNext()) {
-
-                CarrierEthernetNetworkInterface ni2 = it2.next();
-
-                // Skip equals
-                if (ni1.equals(ni2)) {
-                    continue;
-                }
-
-                // Do not establish connectivity between leaf UNIs (applies to Rooted_Multipoint)
-                if (ni1.role() == CarrierEthernetUni.Role.LEAF && ni2.role() == CarrierEthernetUni.Role.LEAF) {
-                    continue;
-                }
-
-                if (!cePktProvisioner.setupConnectivity(ni1, ni2, fc.evcLite())) {
-                    log.warn("Could not set up packet connectivity between {} and {}", ni1, ni2);
-                    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);
-            }
-            // Remove NI from temporary set so that each pair is visited only once
-            it1.remove();
-        }
-
+        // FIXME: Update the LTP set within setupConnectivity()
         // 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())) {
+        Iterator<CarrierEthernetLogicalTerminationPoint> ltpIt = fc.ltpSet().iterator();
+        while (ltpIt.hasNext()) {
+            CarrierEthernetLogicalTerminationPoint ltp = ltpIt.next();
+            if (fc.evcLite().niSet().contains(ltp.ni())) {
                 usedLtpSet.add(ltp);
             }
-        });
+        }
         fc.setLtpSet(usedLtpSet);
 
+        // Set FC state according to EVC Lite state
+        fc.setState(CarrierEthernetForwardingConstruct.State.valueOf(fc.evcLite().state().name()));
+        fc.setActiveState(CarrierEthernetForwardingConstruct.ActiveState.valueOf(fc.evcLite().activeState().name()));
+
         // If no pair was connected, do not register the FC
         if (fc.state().equals(CarrierEthernetForwardingConstruct.State.ACTIVE)) {
+            // Apply BWP-related resources (e.g. Meters) to the packet switches
+            // FIXME: Hack - Resetting the evcLite set to only UNIs until setupConnectivity() uses FCs
+            Set<CarrierEthernetNetworkInterface> tempNiSet = new HashSet<>();
+            fc.ltpSet().forEach(ltp -> {
+                if (ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                    tempNiSet.add(ltp.ni());
+                }
+            });
+            fc.evcLite().setNiSet(tempNiSet);
+            ceProvisioner.applyBandwidthProfiles(fc.evcLite());
+            // Apply the BWPs of the EVC UNI to the global UNIs, creating them if needed
+            applyBandwidthProfiles(fc.evcLite().niSet());
+            // Increment the global LTP and corresponding NI refCount
+            fc.ltpSet().forEach(ltp -> ltpMap.get(ltp.id()).refCount().incrementAndGet());
             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());
-            // Increment the global LTP and corresponding NI refCount
-            usedLtpSet.forEach(ltp -> ltpMap.get(ltp.id()).refCount().incrementAndGet());
-        }
-
-        if (fc.state().equals(CarrierEthernetForwardingConstruct.State.ACTIVE)) {
-            if (allPairsConnected) {
-                fc.setActiveState(CarrierEthernetForwardingConstruct.ActiveState.FULL);
-            } else {
-                fc.setActiveState(CarrierEthernetForwardingConstruct.ActiveState.PARTIAL);
-            }
         }
 
         return fc;
@@ -738,11 +565,17 @@
     public void removeAllFcs() {
         fcMap.keySet().forEach(fcId -> {
             removeEvc(fcMap.get(fcId).evcLite().id());
+            // FIXME: Remove the UNI constraint as soon as EVCs are always made of FCs
+            fcMap.get(fcId).ltpSet()
+                    .forEach(ltp -> {
+                        if (!(ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI))) {
+                            ltpMap.get(ltp.id()).refCount().decrementAndGet();
+                        }
+                    });
         });
         fcMap.clear();
     }
 
-    // FIXME: Rethink this approach
     /**
      * Removes all resources associated with a specific FC.
      *
@@ -756,7 +589,7 @@
             // FIXME: Remove the UNI constraint as soon as EVCs are always constructed of FCs
             fcMap.get(fcId).ltpSet()
                     .forEach(ltp -> {
-                        if (!(ltp.ni() instanceof CarrierEthernetUni)) {
+                        if (!(ltp.ni().type().equals(CarrierEthernetNetworkInterface.Type.UNI))) {
                             ltpMap.get(ltp.id()).refCount().decrementAndGet();
                         }
                     });
@@ -932,7 +765,7 @@
             return null;
         }
 
-        if (validateLtpType(cp, CarrierEthernetLogicalTerminationPoint.Type.UNI) == null) {
+        if (validateLtpType(cp, CarrierEthernetNetworkInterface.Type.UNI) == null) {
             return null;
         }
 
@@ -1001,7 +834,7 @@
      * @return a new validated LTP or null if the validation failed
      * */
     public CarrierEthernetLogicalTerminationPoint generateLtp(ConnectPoint cp,
-                                                               CarrierEthernetLogicalTerminationPoint.Type ltpType) {
+                                                               CarrierEthernetNetworkInterface.Type ltpType) {
 
         String ltpId = cp.deviceId().toString() + "/" + cp.port().toString();
 
@@ -1014,14 +847,14 @@
             return null;
         }
         if (!deviceService.getDevice(cp.deviceId()).type().equals(Device.Type.SWITCH)) {
-            log.error("Could not generate LTP {}: Device {} is not a switch", ltpId, cp.deviceId());
+            log.debug("Could not generate LTP {}: Device {} is not a switch", ltpId, cp.deviceId());
             return null;
         }
 
         Port port = deviceService.getPort(cp.deviceId(), cp.port());
 
         if (!port.isEnabled())  {
-            log.warn("Could not generate LTP {}: Port {} is not enabled", ltpId, port.number().toString());
+            log.debug("Could not generate LTP {}: Port {} is not enabled", ltpId, port.number().toString());
             return null;
         }
 
@@ -1046,14 +879,14 @@
      * @param ltpType the type of the LTP to be validated or null in case a type is to be decided by the method
      * @return the ltpType if validation succeeded, a new type depending on cp and topo, or null if validation failed
      * */
-    private CarrierEthernetLogicalTerminationPoint.Type validateLtpType(
-            ConnectPoint cp, CarrierEthernetLogicalTerminationPoint.Type ltpType) {
+    private CarrierEthernetNetworkInterface.Type validateLtpType(
+            ConnectPoint cp, CarrierEthernetNetworkInterface.Type ltpType) {
         if (linkService.getEgressLinks(cp).isEmpty() && linkService.getIngressLinks(cp).isEmpty()) {
             // A connect point can be a UNI only if it doesn't belong to any link
             if (ltpType == null) {
                 // If provided type is null, decide about the LTP type based on connectivity
-                return CarrierEthernetLogicalTerminationPoint.Type.UNI;
-            } else if (ltpType.equals(CarrierEthernetLogicalTerminationPoint.Type.UNI)) {
+                return CarrierEthernetNetworkInterface.Type.UNI;
+            } else if (ltpType.equals(CarrierEthernetNetworkInterface.Type.UNI)) {
                 // Validate type
                 return ltpType;
             } else {
@@ -1063,9 +896,9 @@
             // A connect point can be an INNI or ENNI only if it belongs to a link
             if (ltpType == null) {
                 // If provided type is null, decide about the LTP type based on connectivity
-                return CarrierEthernetLogicalTerminationPoint.Type.INNI;
-            } else if (ltpType.equals(CarrierEthernetLogicalTerminationPoint.Type.INNI) ||
-                    ltpType.equals(CarrierEthernetLogicalTerminationPoint.Type.ENNI)) {
+                return CarrierEthernetNetworkInterface.Type.INNI;
+            } else if (ltpType.equals(CarrierEthernetNetworkInterface.Type.INNI) ||
+                    ltpType.equals(CarrierEthernetNetworkInterface.Type.ENNI)) {
                 // Validate type
                 return ltpType;
             } else {
@@ -1098,85 +931,4 @@
         }
     }
 
-    public void setPktOpticalTopo(boolean pktOpticalTopo) {
-        this.pktOpticalTopo = pktOpticalTopo;
-    }
-
-    /**
-     * Returns VLAN tag assigned to given path.
-     * @param links List of links that composes path
-     * @return VLAN tag if found any. empty if not found.
-     */
-    private Optional<VlanId> getVlanTag(List<Link> links) {
-        checkNotNull(links);
-        Optional<ConnectPoint> edge = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
-                .filter(portVlanMap::containsKey)
-                .findAny();
-
-        if (edge.isPresent()) {
-            return Optional.of(portVlanMap.get(edge.get()));
-        }
-
-        return Optional.empty();
-    }
-
-    private class OpticalEventListener implements OpticalPathListener {
-
-        @Override
-        public void event(OpticalPathEvent event) {
-            switch (event.type()) {
-                case PATH_INSTALLED: case PATH_REMOVED:
-                    log.info("Optical path event {} received for {}.", event.type(), event.subject());
-                    opticalConnectStatusMap.put(event.subject(), event.type());
-                    break;
-                default:
-                    log.error("Unexpected optical event type.");
-                    break;
-            }
-        }
-    }
-
-    private OpticalConnectivityId setupOpticalConnectivity(ConnectPoint ingress, ConnectPoint egress,
-                                                           Bandwidth bandwidth, Duration latency) {
-        OpticalConnectivityId opticalConnectId = opticalPathService.setupConnectivity(ingress, egress, bandwidth, latency);
-        if (opticalConnectId != null) {
-            long startTime = System.currentTimeMillis();
-            while (((System.currentTimeMillis() - startTime) < (long) OPTICAL_CONNECT_TIMEOUT_MILLIS) &&
-                    (opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_INSTALLED)) {
-            }
-        }
-        return opticalConnectId;
-    }
-
-    private void removeOpticalConnectivity(OpticalConnectivityId opticalConnectId) {
-        if (opticalConnectId != null) {
-            opticalPathService.removeConnectivity(opticalConnectId);
-            long startTime = System.currentTimeMillis();
-            while (((System.currentTimeMillis() - startTime) < (long) OPTICAL_CONNECT_TIMEOUT_MILLIS) &&
-                    (opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_REMOVED)) {
-            }
-        }
-    }
-
-
-    private class InternalNetworkConfigListener implements NetworkConfigListener {
-
-        @Override
-        public void event(NetworkConfigEvent event) {
-            if (!event.configClass().equals(PortVlanConfig.class)) {
-                return;
-            }
-
-            ConnectPoint cp = (ConnectPoint) event.subject();
-            PortVlanConfig config = networkConfigService.getConfig(cp, PortVlanConfig.class);
-            if (config != null && config.portVlanId().isPresent()) {
-                log.info("VLAN tag {} is assigned to port {}", config.portVlanId().get(), cp);
-                portVlanMap.put(cp, config.portVlanId().get());
-            } else {
-                log.info("VLAN tag is removed from port {}", cp);
-                portVlanMap.remove(cp);
-            }
-        }
-
-    }
 }
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 06ce3c0..4c0e3b4 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
@@ -18,31 +18,30 @@
 import com.google.common.base.Objects;
 import org.onlab.packet.VlanId;
 import org.onlab.util.Bandwidth;
-import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.device.DeviceService;
-import org.slf4j.Logger;
-
+import org.onlab.osgi.DefaultServiceDirectory;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Representation of a Carrier Ethernet Network Interface (UNI, INNI or ENNI).
  */
 public abstract class CarrierEthernetNetworkInterface {
 
-    private final Logger log = getLogger(getClass());
-
-    protected DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);
+    protected DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
 
     public enum Scope {
         GLOBAL, SERVICE
     }
 
+    public enum Type {
+        UNI, INNI, ENNI, GENERIC
+    }
+
     protected ConnectPoint connectPoint;
     protected String id;
     protected String cfgId;
@@ -50,10 +49,13 @@
     protected Bandwidth usedCapacity;
     protected Scope scope;
     protected AtomicInteger refCount;
+    protected Type type;
 
 
-    public CarrierEthernetNetworkInterface(ConnectPoint connectPoint, String cfgId) {
+    public CarrierEthernetNetworkInterface(ConnectPoint connectPoint, Type type, String cfgId) {
         checkNotNull(connectPoint);
+        checkNotNull(type);
+        this.type = type;
         this.connectPoint = connectPoint;
         this.id = this.connectPoint.deviceId().toString() + "/" + this.connectPoint.port().toString();
         this.cfgId = (cfgId == null ? this.id : cfgId);
@@ -133,6 +135,15 @@
     }
 
     /**
+     * Returns the type of the NI (UNI, INNI or ENNI).
+     *
+     * @return NI scope
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
      * Returns counter with the number of references (from EVCs/FCs) to the particular NI.
      *
      * @return number of references counter
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
index 73368a2..10bc43b 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetOpenFlowPacketNodeManager.java
@@ -96,36 +96,29 @@
     protected void deactivate() {}
 
     @Override
-    public void setNodeForwarding(CarrierEthernetVirtualConnection evc, CarrierEthernetNetworkInterface srcNi,
-                                  CarrierEthernetNetworkInterface dstNi, ConnectPoint ingress, ConnectPoint egress,
-                                  boolean first, boolean last) {
+    public void setNodeForwarding(CarrierEthernetVirtualConnection evc, CarrierEthernetNetworkInterface ingressNi,
+                                  Set<CarrierEthernetNetworkInterface> egressNiSet) {
 
-        // FIXME: Is this necessary? Can first and last be true at the same time?
-        if(srcNi.cp().deviceId().equals(dstNi.cp().deviceId())) {
-            log.error("Source and destination NI must belong to different devices.");
+        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(evc.id(), new LinkedList<>());
 
         // TODO: Get created FlowObjectives from this method
-        createFlowObjectives(evc, srcNi, dstNi, ingress, egress, first, last);
+        createFlowObjectives(evc, ingressNi, egressNiSet);
     }
 
     /**
-     * Creates and submits FlowObjectives depending on the role of the device in the EVC and the types of srcNi/dstNi.
+     * Creates and submits FlowObjectives depending on role of the device in the EVC and ingress/egress NI types.
      *
      * @param evc the EVC representation
-     * @param srcNi the source network interface (UNI, INNI or ENNI) of the EVC for this forwarding segment
-     * @param dstNi the destination network interface (UNI, INNI or ENNI) of the EVC for this forwarding segment
-     * @param ingress the ingress connect point at the current device
-     * @param egress the egress connect point at the current device
-     * @param first is true if the current device is the first node in the end-to-end path
-     * @param last is true if the current device is the last node in the end-to-end path
+     * @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(CarrierEthernetVirtualConnection evc, CarrierEthernetNetworkInterface srcNi,
-                                      CarrierEthernetNetworkInterface dstNi, ConnectPoint ingress, ConnectPoint egress,
-                                      boolean first, boolean last) {
+    private void createFlowObjectives(CarrierEthernetVirtualConnection evc, CarrierEthernetNetworkInterface ingressNi,
+                                      Set<CarrierEthernetNetworkInterface> egressNiSet) {
 
         /////////////////////////////////////////
         // Prepare and submit filtering objective
@@ -134,37 +127,36 @@
         FilteringObjective.Builder filteringObjectiveBuilder = DefaultFilteringObjective.builder()
                 .permit().fromApp(appId)
                 .withPriority(PRIORITY)
-                .withKey(Criteria.matchInPort(ingress.port()));
+                .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(evc.vlanId());
 
-        if (first) {
-            if ((srcNi instanceof CarrierEthernetInni) || (srcNi instanceof CarrierEthernetEnni) ) {
-                // TODO: Check TPID? Also: Is is possible to receive untagged pkts at an INNI/ENNI?
-                // First node of an FC should match on S-TAG if it's an INNI/ENNI
-                filterVlanIdCriterion = Criteria.matchVlanId(srcNi.sVlanId());
-                // Translate S-TAG to the one used in the current FC
-                filterTreatmentBuilder.setVlanId(evc.vlanId());
-            } else {
-                // First node of an FC should match on CE-VLAN ID (if present) if it's a UNI
-                filterVlanIdCriterion = Criteria.matchVlanId(srcNi.ceVlanId());
-                // Push S-TAG of current FC on top of existing CE-VLAN ID
-                filterTreatmentBuilder.pushVlan().setVlanId(evc.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(evc.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(evc.vlanId());
         }
 
         filteringObjectiveBuilder.addCondition(filterVlanIdCriterion);
 
         // Do not add meta if there are no instructions (i.e. if not first)
-        if (first) {
+        if (!(ingressNi.type().equals(CarrierEthernetNetworkInterface.Type.GENERIC))) {
             filteringObjectiveBuilder.withMeta(filterTreatmentBuilder.build());
         }
 
-        flowObjectiveService.filter(ingress.deviceId(), filteringObjectiveBuilder.add());
-        flowObjectiveMap.get(evc.id()).addFirst(Pair.of(ingress.deviceId(), filteringObjectiveBuilder.add()));
+        flowObjectiveService.filter(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add());
+        flowObjectiveMap.get(evc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), filteringObjectiveBuilder.add()));
 
         ////////////////////////////////////////////////////
         // Prepare and submit next and forwarding objectives
@@ -172,51 +164,36 @@
 
         TrafficSelector fwdSelector = DefaultTrafficSelector.builder()
                 .matchVlanId(evc.vlanId())
-                .matchInPort(ingress.port())
+                .matchInPort(ingressNi.cp().port())
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .build();
 
-        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 (last && (dstNi instanceof CarrierEthernetUni)) {
-            nextTreatmentBuilder.popVlan();
-        }
-        Instruction outInstruction = Instructions.createOutput(egress.port());
-        nextTreatmentBuilder.add(outInstruction);
-
-        // Check if flow rule with same selector already exists (e.g. when branching in an E-LAN or E-Tree).
-        // If yes, it will be replaced, so we need to include its output in the currently prepared NextObjective
-        Iterator<FlowRule> flowRuleIt = flowRuleService.getFlowRulesById(appId).iterator();
-        while (flowRuleIt.hasNext()) {
-            FlowRule flowRule = flowRuleIt.next();
-            if (flowRule.deviceId().equals(egress.deviceId()) && flowRule.selector().equals(fwdSelector)) {
-                Iterator<Instruction> instructionIt = flowRule.treatment().allInstructions().iterator();
-                while (instructionIt.hasNext()) {
-                    Instruction instruction = instructionIt.next();
-                    // If this is an GROUP instruction and it's different than existing, add it to FlowObjective
-                    if (instruction.type().equals(outInstruction.type()) &&
-                            !(instruction.equals(outInstruction))) {
-                            nextTreatmentBuilder.add(instruction);
-                    }
-                }
-            }
-        }
-
-        // Setting higher priority to fwd/next objectives to bypass filter in case of match conflict in OVS switches
-
         Integer nextId = flowObjectiveService.allocateNextId();
 
-        NextObjective nextObjective = DefaultNextObjective.builder()
+        // 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.SIMPLE)
+                .withType(NextObjective.Type.BROADCAST)
                 .withPriority(PRIORITY + 1)
                 .withMeta(fwdSelector)
-                .addTreatment(nextTreatmentBuilder.build())
-                .withId(nextId)
-                .add();
+                .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()
@@ -226,14 +203,12 @@
                 .nextStep(nextId)
                 .add();
 
-        flowObjectiveService.next(egress.deviceId(), nextObjective);
+        flowObjectiveService.next(ingressNi.cp().deviceId(), nextObjective);
         // Add all NextObjectives at the end of the list so that they will be removed last
-        flowObjectiveMap.get(evc.id()).addLast(Pair.of(ingress.deviceId(), nextObjective));
+        flowObjectiveMap.get(evc.id()).addLast(Pair.of(ingressNi.cp().deviceId(), nextObjective));
 
-        flowObjectiveService.forward(egress.deviceId(), forwardingObjective);
-        flowObjectiveMap.get(evc.id()).addFirst(Pair.of(ingress.deviceId(), forwardingObjective));
-
-        // FIXME: For efficiency do not send FlowObjective again if new treatment is exactly the same as existing one
+        flowObjectiveService.forward(ingressNi.cp().deviceId(), forwardingObjective);
+        flowObjectiveMap.get(evc.id()).addFirst(Pair.of(ingressNi.cp().deviceId(), forwardingObjective));
     }
 
     @Override
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 5b68d36..4be8901 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
@@ -15,16 +15,15 @@
  */
 package org.onosproject.ecord.carrierethernet.app;
 
-import org.onosproject.net.ConnectPoint;
+import java.util.Set;
 
 /**
  * Abstraction of a class used to control Carrier Ethernet nodes according to their control protocol.
  */
 public abstract class CarrierEthernetPacketNodeManager {
 
-    abstract void setNodeForwarding(CarrierEthernetVirtualConnection service, CarrierEthernetNetworkInterface srcNi,
-                                    CarrierEthernetNetworkInterface dstNi, ConnectPoint ingress, ConnectPoint egress,
-                                    boolean first, boolean last);
+    abstract void setNodeForwarding(CarrierEthernetVirtualConnection evc, CarrierEthernetNetworkInterface srcNi,
+                                    Set<CarrierEthernetNetworkInterface> dstNiSet);
 
     abstract void applyBandwidthProfileResources(CarrierEthernetVirtualConnection service, CarrierEthernetUni uni);
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java
deleted file mode 100644
index 54a0ec8..0000000
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetPacketProvisioner.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2016 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.ecord.carrierethernet.app;
-
-import org.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.onosproject.net.Device;
-import org.onosproject.net.Link;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Path;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.topology.PathService;
-import org.slf4j.Logger;
-
-import java.util.Set;
-import java.util.List;
-import java.util.ArrayList;
-
-import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
-import static org.slf4j.LoggerFactory.getLogger;
-
-@Component(immediate = true)
-@Service (value = CarrierEthernetPacketProvisioner.class)
-public class CarrierEthernetPacketProvisioner {
-
-    private final Logger log = getLogger(getClass());
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected PathService pathService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CarrierEthernetOpenFlowPacketNodeManager ceOfPktNodeManager;
-
-    @Activate
-    protected void activate() {}
-
-    @Deactivate
-    protected void deactivate() {
-
-    }
-
-    // TODO: Get LTPs as input
-    public boolean setupConnectivity(CarrierEthernetNetworkInterface ni1, CarrierEthernetNetworkInterface ni2, CarrierEthernetVirtualConnection service) {
-
-        // Find the paths for both directions at the same time, so that we can skip the pair if needed
-        List<Link> forwardLinks = selectLinkPath(ni1, ni2, service);
-        List<Link> backwardLinks = selectLinkPath(ni2, ni1, service);
-
-        // Skip this UNI pair if no feasible path could be found
-        if (forwardLinks == null || (!service.congruentPaths() && backwardLinks == null)) {
-            log.warn("There are no feasible paths between {} and {}.",
-                    ni1.cp().deviceId(), ni2.cp().deviceId());
-            return false;
-        }
-
-        // Establish connectivity for the packet switches
-        // TODO: Send some kind of gRPC message to BigSwitches
-        for (int i = 0; i < forwardLinks.size() - 1; i++) {
-            // Create flows for the forward direction
-            boolean first = isFirst(i);
-            boolean last = isLast(forwardLinks, i);
-            ConnectPoint ingress = forwardLinks.get(i).dst();
-            ConnectPoint egress = forwardLinks.get(i + 1).src();
-            //  TODO: Select node manager depending on device protocol
-            // Set forwarding only on packet switches
-            if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                ceOfPktNodeManager.setNodeForwarding(service, ni1, ni2, ingress, egress, first, last);
-            }
-
-            if (service.congruentPaths()) {
-                // Create flows for the forward direction using the reverse path
-                ingress = forwardLinks.get(forwardLinks.size() - i - 1).src();
-                egress = forwardLinks.get(forwardLinks.size() - i - 2).dst();
-                //  TODO: Select node manager depending on device protocol
-                if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                    ceOfPktNodeManager.setNodeForwarding(service, ni2, ni1, ingress, egress, first, last);
-                }
-            }
-        }
-
-        if (!service.congruentPaths()) {
-            // Create flows for the backward direction using a path potentially different from the reverse one
-            for (int i = 0; i < backwardLinks.size() - 1; i++) {
-                boolean first = isFirst(i);
-                boolean last = isLast(backwardLinks, i);
-                ConnectPoint ingress = backwardLinks.get(i).dst();
-                ConnectPoint egress = backwardLinks.get(i + 1).src();
-                //  TODO: Select node manager depending on device protocol
-                if (deviceService.getDevice(ingress.deviceId()).type().equals(Device.Type.SWITCH)) {
-                    ceOfPktNodeManager.setNodeForwarding(service, ni2, ni1, ingress, egress, first, last);
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Select a feasible link path between two NIs based on the CE service parameters.
-     *
-     * @param ni1 the first NI
-     * @param ni2 the second NI
-     * @param service the CE service descriptor
-     */
-    private List<Link> selectLinkPath(CarrierEthernetNetworkInterface ni1, CarrierEthernetNetworkInterface ni2,
-                                      CarrierEthernetVirtualConnection service) {
-
-        /*List<Constraint> constraints = ImmutableList.<Constraint>builder()
-                .add(new BandwidthConstraint(uni1.bwp().cir()))
-                .add(new LatencyConstraint(service.latency()))
-                .build();*/
-
-        Set<Path> paths = pathService.getPaths(ni1.cp().deviceId(), ni2.cp().deviceId());
-
-        Path path = null;
-
-        for (Path p : paths) {
-            // TODO: Select path in more sophisticated way and return null if any of the constraints cannot be met
-            path = p;
-            break;
-        }
-
-        if (path == null) {
-            return null;
-        } else {
-            List<Link> links = new ArrayList<>();
-            links.add(createEdgeLink(ni1.cp(), true));
-            links.addAll(path.links());
-            links.add(createEdgeLink(ni2.cp(), false));
-            return links;
-        }
-    }
-
-    private boolean isLast(List<Link> links, int i) {
-        return i == links.size() - 2;
-    }
-
-    private boolean isFirst(int i) {
-        return i == 0;
-    }
-
-    public void removeConnectivity(CarrierEthernetVirtualConnection evc) {
-        // TODO: Add here the same call for all node manager types
-        ceOfPktNodeManager.removeAllForwardingResources(evc);
-    }
-
-    /**
-     * Applies bandwidth profiles to the UNIs of an EVC.
-     *
-     * @param evc the EVC representation
-     */
-    public void applyBandwidthProfiles(CarrierEthernetVirtualConnection evc) {
-        //  TODO: Select node manager depending on device protocol
-        evc.uniSet().forEach(uni -> ceOfPktNodeManager.applyBandwidthProfileResources(evc, uni));
-    }
-
-    /**
-     * Removes bandwidth profiles from the UNIs of an EVC.
-     *
-     * @param evc the EVC representation
-     */
-    public void removeBandwidthProfiles(CarrierEthernetVirtualConnection evc) {
-        //  TODO: Select node manager depending on device protocol
-        evc.uniSet().forEach(uni -> ceOfPktNodeManager.removeBandwidthProfileResources(evc.id(), uni));
-    }
-
-}
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
new file mode 100644
index 0000000..86e6306
--- /dev/null
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/app/CarrierEthernetProvisioner.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ecord.carrierethernet.app;
+
+import com.google.common.collect.ImmutableList;
+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.VlanId;
+import org.onlab.util.Bandwidth;
+import org.onosproject.net.Link;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Path;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.Device;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.PathService;
+import org.onosproject.net.topology.TopologyEdge;
+import org.onosproject.net.topology.TopologyService;
+import org.onosproject.newoptical.api.OpticalConnectivityId;
+import org.onosproject.newoptical.api.OpticalPathEvent;
+import org.onosproject.newoptical.api.OpticalPathListener;
+import org.onosproject.newoptical.api.OpticalPathService;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.provider.ProviderId;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
+import static org.slf4j.LoggerFactory.getLogger;
+
+@Component(immediate = true)
+@Service (value = CarrierEthernetProvisioner.class)
+public class CarrierEthernetProvisioner {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PathService pathService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TopologyService topologyService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CarrierEthernetOpenFlowPacketNodeManager ceOfPktNodeManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpticalPathService opticalPathService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry cfgRegistry;
+
+    private final List<ConfigFactory<?, ?>> factories = ImmutableList.of(
+            new ConfigFactory<ConnectPoint, PortVlanConfig>(CONNECT_POINT_SUBJECT_FACTORY,
+                    PortVlanConfig.class, PortVlanConfig.CONFIG_KEY) {
+                @Override
+                public PortVlanConfig createConfig() {
+                    return new PortVlanConfig();
+                }
+            });
+
+    // Map of connect points and corresponding VLAN tag
+    private Map<ConnectPoint, VlanId> portVlanMap = new ConcurrentHashMap<>();
+
+    private OpticalPathListener opticalEventListener = new OpticalEventListener();
+
+    private NetworkConfigListener netcfgListener = new InternalNetworkConfigListener();
+
+    private static final int OPTICAL_CONNECT_TIMEOUT_MILLIS = 7000;
+
+    // If set to false, the setup of optical connectivity using the metro app is bypassed
+    // TODO: Use the Component Configuration mechanism to set this parameter
+    private boolean pktOpticalTopo = false;
+
+    // TODO: Refactor this part
+    private final Map<OpticalConnectivityId, OpticalPathEvent.Type> opticalConnectStatusMap = new ConcurrentHashMap<>();
+
+    @Activate
+    protected void activate() {
+        opticalPathService.addListener(opticalEventListener);
+        networkConfigService.addListener(netcfgListener);
+        factories.forEach(cfgRegistry::registerConfigFactory);
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        opticalPathService.removeListener(opticalEventListener);
+        networkConfigService.removeListener(netcfgListener);
+        factories.forEach(cfgRegistry::unregisterConfigFactory);
+    }
+
+    // TODO: Get FC as input
+    public void setupConnectivity(Set<CarrierEthernetNetworkInterface> niSet, CarrierEthernetVirtualConnection evc) {
+
+        boolean allPairsConnected = true;
+
+        HashMap<CarrierEthernetNetworkInterface, HashSet<CarrierEthernetNetworkInterface>> ingressEgressNiMap =
+                new HashMap<>();
+
+        // Temporary set for iterating through NI pairs
+        Set<CarrierEthernetNetworkInterface> tempNiSet = new HashSet<>(niSet);
+
+        // Temporary set for indicating which NIs were finally included
+        Set<CarrierEthernetNetworkInterface> usedNiSet = new HashSet<>();
+
+        Iterator<CarrierEthernetNetworkInterface> niIt1 = tempNiSet.iterator();
+        while (niIt1.hasNext()) {
+
+            CarrierEthernetNetworkInterface ni1 = niIt1.next();
+
+            // Iterate through all the remaining NIs
+            Iterator<CarrierEthernetNetworkInterface> niIt2 = tempNiSet.iterator();
+            while (niIt2.hasNext()) {
+
+                CarrierEthernetNetworkInterface ni2 = niIt2.next();
+
+                // Skip equals
+                if (ni1.equals(ni2)) {
+                    continue;
+                }
+
+                // Do not establish connectivity between leaf NIs (applies to Rooted_Multipoint)
+                if (ni1.role().equals(CarrierEthernetUni.Role.LEAF)
+                        && ni2.role().equals(CarrierEthernetUni.Role.LEAF)) {
+                    continue;
+                }
+
+                OpticalConnectivityId opticalConnectId = null;
+
+                if (pktOpticalTopo) {
+
+                    Bandwidth reqBw;
+
+                    if (ni1.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                        reqBw = ((CarrierEthernetUni) ni1).bwp().cir();
+                    } else if (ni2.type().equals(CarrierEthernetNetworkInterface.Type.UNI)) {
+                        reqBw = ((CarrierEthernetUni) ni2).bwp().cir();
+                    } else {
+                        reqBw = Bandwidth.bps((double) 0);
+                    }
+
+                    opticalConnectId = setupOpticalConnectivity(ni1.cp(), ni2.cp(), reqBw, evc.latency());
+
+                    if (opticalConnectId == null ||
+                            opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_INSTALLED) {
+                        log.error("Could not establish optical connectivity between {} and {}" +
+                                        " (optical id and status: {}, {})", ni1.cp(), ni2.cp(), opticalConnectId,
+                                (opticalConnectId == null ? "null" : opticalConnectStatusMap.get(opticalConnectId)));
+                        allPairsConnected = false;
+                        continue;
+                    }
+
+                    if (opticalConnectId != null) {
+                        evc.setMetroConnectivityId(opticalConnectId);
+                        evc.setMetroConnectivityStatus(opticalConnectStatusMap.get(opticalConnectId));
+                    }
+
+                    log.info("Metro connectivity id and status for EVC {}: {}, {}", evc.id(),
+                            evc.metroConnectivity().id(), evc.metroConnectivity().status());
+
+                    if (opticalConnectId != null) {
+                        // TODO: find vlanIds for both CO and store to service
+                        opticalPathService.getPath(opticalConnectId).ifPresent(links -> {
+                            getVlanTag(links).ifPresent(vlan -> {
+                                log.info("VLAN ID {} is assigned to CE service {}", vlan, evc.id());
+                                evc.setVlanId(vlan);
+                            });
+                        });
+                    }
+                }
+
+                // Update the cpPathHashSet based on the calculated paths
+                if (!updateIngressEgressNiMap(ni1, ni2, ingressEgressNiMap, evc.congruentPaths(), evc.type())) {
+                    removeOpticalConnectivity(opticalConnectId);
+                    allPairsConnected = false;
+                    continue;
+                }
+
+                // Indicate that connection for at least one NI pair has been established
+                evc.setState(CarrierEthernetVirtualConnection.State.ACTIVE);
+
+                // Add NIs to the set of NIs used by the EVC
+                usedNiSet.add(ni1);
+                usedNiSet.add(ni2);
+            }
+            // Remove NI from temporary set so that each pair is visited only once
+            niIt1.remove();
+        }
+
+        // Establish connectivity using the ingressEgressNiMap
+        ingressEgressNiMap.keySet().forEach(srcNi -> {
+            // Set forwarding only on packet switches
+            if (deviceService.getDevice(srcNi.cp().deviceId()).type().equals(Device.Type.SWITCH)) {
+                ceOfPktNodeManager.setNodeForwarding(evc, srcNi, ingressEgressNiMap.get(srcNi));
+            }
+        });
+
+        // Update the NI set, based on the NIs actually used
+        evc.setNiSet(usedNiSet);
+
+        if (evc.state().equals(CarrierEthernetVirtualConnection.State.ACTIVE)) {
+            if (allPairsConnected) {
+                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.FULL);
+            } else {
+                evc.setActiveState(CarrierEthernetVirtualConnection.ActiveState.PARTIAL);
+            }
+        }
+    }
+
+    /**
+     * Select a feasible link path between two NIs
+     *
+     * @param ni1 the first NI
+     * @param ni2 the second NI
+     * @param ingressEgressNiMap the method will add here any ingress-egress NI associations
+     * @param congruentPaths if true indicates that n1->n2 will follow the same path as n2->n1
+     * @return true if the path was updated and false if a path could not be found in any of the directions
+     */
+    private boolean updateIngressEgressNiMap(CarrierEthernetNetworkInterface ni1, CarrierEthernetNetworkInterface ni2,
+                                      HashMap<CarrierEthernetNetworkInterface,
+                                              HashSet<CarrierEthernetNetworkInterface>> ingressEgressNiMap,
+                                boolean congruentPaths, CarrierEthernetVirtualConnection.Type evcType) {
+
+        // Find the paths for both directions at the same time, so that we can skip the pair if needed
+        List<Link> forwardLinks = generateLinkList(ni1.cp(), ni2.cp(), evcType);
+        List<Link> backwardLinks =
+                congruentPaths ? generateInverseLinkList(forwardLinks) : generateLinkList(ni2.cp(), ni1.cp(), evcType);
+
+        // Skip this UNI pair if no feasible path could be found
+        if (forwardLinks == null || (backwardLinks == null)) {
+            log.warn("There are no feasible paths between {} and {}.",
+                    ni1.cp().deviceId(), ni2.cp().deviceId());
+            return false;
+        }
+
+        // Populate the ingress/egress NI map for the forward and backward paths
+        populateIngressEgressNiMap(ni1, ni2, forwardLinks, ingressEgressNiMap);
+        populateIngressEgressNiMap(ni2, ni1, backwardLinks, ingressEgressNiMap);
+
+        return true;
+    }
+
+    private void populateIngressEgressNiMap(CarrierEthernetNetworkInterface srcNi,
+                                            CarrierEthernetNetworkInterface dstNi,
+                                            List<Link> linkList,
+                                            HashMap<CarrierEthernetNetworkInterface,
+                                                    HashSet<CarrierEthernetNetworkInterface>> ingressEgressNiMap
+                                            ) {
+        // Add the src and destination NIs as well as the associated Generic NIs
+        ingressEgressNiMap.putIfAbsent(srcNi, new HashSet<>());
+        ingressEgressNiMap.get(srcNi).add(new CarrierEthernetGenericNi(linkList.get(1).src(), null));
+        CarrierEthernetGenericNi ingressNi =
+                new CarrierEthernetGenericNi(linkList.get(linkList.size() - 2).dst(), null);
+        ingressEgressNiMap.putIfAbsent(ingressNi, new HashSet<>());
+        ingressEgressNiMap.get(ingressNi).add(dstNi);
+
+        // Go through the links and create/add the intermediate NIs
+        for (int i = 1; i < linkList.size() - 2; i++) {
+            ingressNi = new CarrierEthernetGenericNi(linkList.get(i).dst(), null);
+            ingressEgressNiMap.putIfAbsent(ingressNi, new HashSet<>());
+            ingressEgressNiMap.get(ingressNi).add(new CarrierEthernetGenericNi(linkList.get(i + 1).src(), null));
+        }
+    }
+
+    private List<Link> generateLinkList(ConnectPoint cp1, ConnectPoint cp2,
+                                        CarrierEthernetVirtualConnection.Type evcType) {
+
+        Set<Path> paths;
+        if (evcType.equals(CarrierEthernetVirtualConnection.Type.POINT_TO_POINT)) {
+            // For point-to-point connectivity use the pre-calculated paths to make sure the shortest paths are chosen
+            paths = pathService.getPaths(cp1.deviceId(), cp2.deviceId());
+        } else {
+            // Recalculate path so that it's over the pre-calculated spanning tree
+            // FIXME: Find a more efficient way (avoid recalculating paths)
+            paths = pathService.getPaths(cp1.deviceId(), cp2.deviceId(), new SpanningTreeWeight());
+        }
+
+        // Just select any of the returned paths
+        // TODO: Select path in more sophisticated way and return null if any of the constraints cannot be met
+        Path path = paths.iterator().hasNext() ? paths.iterator().next() : null;
+
+        if (path == null) {
+            return null;
+        }
+
+        List<Link> links = new ArrayList<>();
+        links.add(createEdgeLink(cp1, true));
+        links.addAll(path.links());
+        links.add(createEdgeLink(cp2, false));
+
+        return links;
+    }
+
+    private List<Link> generateInverseLinkList(List<Link> originalLinks) {
+
+        if (originalLinks == null) {
+            return null;
+        }
+
+        List<Link> inverseLinks = new ArrayList<>();
+
+        inverseLinks.add(createEdgeLink(originalLinks.get(originalLinks.size() - 1).src(), true));
+
+        for (int i = originalLinks.size() - 2 ; i > 0 ; i--) {
+            // FIXME: Check again the Link creation parameters
+            inverseLinks.add(DefaultLink.builder()
+                    .src(originalLinks.get(i).dst())
+                    .dst(originalLinks.get(i).src())
+                    .type(Link.Type.DIRECT)
+                    .providerId(new ProviderId("none", "none"))
+                    .build());
+        }
+        inverseLinks.add(createEdgeLink(originalLinks.get(0).dst(), false));
+
+        return inverseLinks;
+    }
+
+    public void removeConnectivity(CarrierEthernetVirtualConnection evc) {
+        // TODO: Add here the same call for all node manager types
+        ceOfPktNodeManager.removeAllForwardingResources(evc);
+        removeOpticalConnectivity(evc.metroConnectivity().id());
+    }
+
+    /**
+     * Applies bandwidth profiles to the UNIs of an EVC.
+     *
+     * @param evc the EVC representation
+     */
+    public void applyBandwidthProfiles(CarrierEthernetVirtualConnection evc) {
+        //  TODO: Select node manager depending on device protocol
+        evc.niSet().forEach((uni -> ceOfPktNodeManager.applyBandwidthProfileResources(evc, (CarrierEthernetUni) uni)));
+    }
+
+    /**
+     * Removes bandwidth profiles from the UNIs of an EVC.
+     *
+     * @param evc the EVC representation
+     */
+    public void removeBandwidthProfiles(CarrierEthernetVirtualConnection evc) {
+        //  TODO: Select node manager depending on device protocol
+        evc.niSet().forEach(uni -> ceOfPktNodeManager
+                .removeBandwidthProfileResources(evc.id(), (CarrierEthernetUni) uni));
+    }
+
+    private class OpticalEventListener implements OpticalPathListener {
+
+        @Override
+        public void event(OpticalPathEvent event) {
+            switch (event.type()) {
+                case PATH_INSTALLED: case PATH_REMOVED:
+                    log.info("Optical path event {} received for {}.", event.type(), event.subject());
+                    opticalConnectStatusMap.put(event.subject(), event.type());
+                    break;
+                default:
+                    log.error("Unexpected optical event type.");
+                    break;
+            }
+        }
+    }
+
+    private OpticalConnectivityId setupOpticalConnectivity(ConnectPoint ingress, ConnectPoint egress,
+                                                           Bandwidth bandwidth, Duration latency) {
+        OpticalConnectivityId opticalConnectId = opticalPathService
+                .setupConnectivity(ingress, egress, bandwidth, latency);
+        if (opticalConnectId != null) {
+            long startTime = System.currentTimeMillis();
+            while (((System.currentTimeMillis() - startTime) < (long) OPTICAL_CONNECT_TIMEOUT_MILLIS) &&
+                    (opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_INSTALLED)) {
+            }
+        }
+        return opticalConnectId;
+    }
+
+    private void removeOpticalConnectivity(OpticalConnectivityId opticalConnectId) {
+        if (opticalConnectId != null) {
+            opticalPathService.removeConnectivity(opticalConnectId);
+            long startTime = System.currentTimeMillis();
+            while (((System.currentTimeMillis() - startTime) < (long) OPTICAL_CONNECT_TIMEOUT_MILLIS) &&
+                    (opticalConnectStatusMap.get(opticalConnectId) != OpticalPathEvent.Type.PATH_REMOVED)) {
+            }
+        }
+    }
+
+    public void setPktOpticalTopo(boolean pktOpticalTopo) {
+        this.pktOpticalTopo = pktOpticalTopo;
+    }
+
+    /**
+     * Returns VLAN tag assigned to given path.
+     * @param links List of links that composes path
+     * @return VLAN tag if found any. empty if not found.
+     */
+    private Optional<VlanId> getVlanTag(List<Link> links) {
+        checkNotNull(links);
+        Optional<ConnectPoint> edge = links.stream().flatMap(l -> Stream.of(l.src(), l.dst()))
+                .filter(portVlanMap::containsKey)
+                .findAny();
+
+        if (edge.isPresent()) {
+            return Optional.of(portVlanMap.get(edge.get()));
+        }
+
+        return Optional.empty();
+    }
+
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            if (!event.configClass().equals(PortVlanConfig.class)) {
+                return;
+            }
+
+            ConnectPoint cp = (ConnectPoint) event.subject();
+            PortVlanConfig config = networkConfigService.getConfig(cp, PortVlanConfig.class);
+            if (config != null && config.portVlanId().isPresent()) {
+                log.info("VLAN tag {} is assigned to port {}", config.portVlanId().get(), cp);
+                portVlanMap.put(cp, config.portVlanId().get());
+            } else {
+                log.info("VLAN tag is removed from port {}", cp);
+                portVlanMap.remove(cp);
+            }
+        }
+
+    }
+
+    /**
+     * Checks if a connect point is on the pre-calculated spanning tree.
+     *
+     * @param cp the connect point to check
+     * @return true if the connect point is on the spanning tree and false otherwise
+     */
+    private boolean isBroadCastPoint(ConnectPoint cp) {
+        // TODO: Get topology snapshot so that same spanning tree is used by all pairs if topology changes
+        return topologyService.isBroadcastPoint(topologyService.currentTopology(), cp);
+    }
+
+    /**
+     * Weight class to cause path selection only on the pre-calculated spanning tree.
+     */
+    private class SpanningTreeWeight implements LinkWeight {
+
+        @Override
+        public double weight(TopologyEdge edge) {
+            if (!isBroadCastPoint(edge.link().src()) || !isBroadCastPoint(edge.link().dst())) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+
+}
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 de67b23..4c75831 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
@@ -70,7 +70,7 @@
 
     public CarrierEthernetUni(ConnectPoint cp, String uniCfgId, Role role, VlanId ceVlanId,
                               CarrierEthernetBandwidthProfile bwp) {
-        super(cp, uniCfgId);
+        super(cp, Type.UNI, uniCfgId);
         this.role = role;
         // FIXME: Set the NI scope directly instead?
         this.scope = (role == null ? Scope.GLOBAL : Scope.SERVICE);
@@ -101,7 +101,7 @@
     }
 
     public CarrierEthernetUni(ConnectPoint cp, String uniCfgId) {
-        super(cp, uniCfgId);
+        super(cp, Type.UNI, uniCfgId);
         this.scope = Scope.GLOBAL;
         for (CarrierEthernetBandwidthProfile.Type bwpType : CarrierEthernetBandwidthProfile.Type.values()) {
             this.bwpMap.put(bwpType, new HashMap<>());
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 b5e7d18..854c818 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
@@ -27,10 +27,8 @@
 import static com.google.common.base.MoreObjects.toStringHelper;
 
 /**
- * Representation of a Carrier Ethernet Service along with relevant ONOS-related resources.
+ * Representation of a Carrier Ethernet EVC.
  */
-// FIXME: Consider renaming, since it actually represents a service rather than an EVC.
-// FIXME: Term "Service" though might be confusing in the ONOS context.
 public class CarrierEthernetVirtualConnection {
 
     public enum Type {
@@ -116,7 +114,7 @@
     protected VlanId vlanId;
     protected boolean isVirtual;
     protected Integer maxNumUni;
-    protected Set<CarrierEthernetUni> uniSet;
+    protected Set<CarrierEthernetNetworkInterface> niSet;
     protected Duration latency;
     protected CarrierEthernetMetroConnectivity metroConnectivity;
     protected boolean congruentPaths;
@@ -131,7 +129,7 @@
 
     // Note: evcId should be provided only when updating an existing service
     public CarrierEthernetVirtualConnection(String evcId, String evcCfgId, Type evcType, Integer maxNumUni,
-                                            Set<CarrierEthernetUni> uniSet) {
+                                            Set<CarrierEthernetNetworkInterface> niSet) {
         this.evcId = evcId;
         this.evcCfgId = evcCfgId;
         this.evcType = evcType;
@@ -139,7 +137,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<>(uniSet);
+        this.niSet = new HashSet<>(niSet);
         this.congruentPaths = CONGRUENT_PATHS;
         this.latency = DEFAULT_LATENCY;
         this.metroConnectivity = new CarrierEthernetMetroConnectivity(null, OpticalPathEvent.Type.PATH_REMOVED);
@@ -220,8 +218,8 @@
      *
      * @return set of UNIs
      */
-    public Set<CarrierEthernetUni> uniSet() {
-        return ImmutableSet.copyOf(uniSet);
+    public Set<CarrierEthernetNetworkInterface> niSet() {
+        return ImmutableSet.copyOf(niSet);
     }
 
     /**
@@ -263,10 +261,10 @@
     /**
      * Sets the set of UNIs.
      *
-     * @param uniSet the set of UNIs to be set
+     * @param niSet the set of UNIs to be set
      */
-    public void setUniSet(Set<CarrierEthernetUni> uniSet) {
-        this.uniSet = uniSet;
+    public void setNiSet(Set<CarrierEthernetNetworkInterface> niSet) {
+        this.niSet = niSet;
     }
 
     /**
@@ -345,6 +343,6 @@
                 .add("type", evcType)
                 .add("vlanId", vlanId)
                 .add("metroConnectId", (metroConnectivity.id() == null ? "null" : metroConnectivity.id().id()))
-                .add("UNIs", uniSet).toString();
+                .add("NIs", niSet).toString();
     }
 }
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 2292bff..c0f663b 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,6 +23,7 @@
 import org.onlab.util.Bandwidth;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetBandwidthProfile;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetManager;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetNetworkInterface;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetVirtualConnection;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetUni;
 import org.onosproject.cli.AbstractShellCommand;
@@ -158,9 +159,9 @@
      *
      * @return the set of UNIs for the CE EVC
      */
-    Set<CarrierEthernetUni> generateUniSet() {
+    Set<CarrierEthernetNetworkInterface> generateUniSet() {
 
-        Set<CarrierEthernetUni> uniSet = new HashSet<>();
+        Set<CarrierEthernetNetworkInterface> uniSet = new HashSet<>();
 
         CarrierEthernetVirtualConnection.Type evcType = generateEvcType();
 
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateLtpCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateLtpCommand.java
index 7f74aa1..4c957d0 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateLtpCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetCreateLtpCommand.java
@@ -49,11 +49,11 @@
 
         CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
 
-        CarrierEthernetLogicalTerminationPoint.Type ltpType = null;
+        CarrierEthernetNetworkInterface.Type ltpType = null;
 
         if (!argLtpType.equals("AUTO")) {
             try {
-                ltpType = CarrierEthernetLogicalTerminationPoint.Type.valueOf(argLtpType);
+                ltpType = CarrierEthernetNetworkInterface.Type.valueOf(argLtpType);
             } catch (IllegalArgumentException e) {
                 log.error("{} is not a valid LTP type, skipping LTP generation.");
                 return;
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetPktOpticalTopoCommand.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetPktOpticalTopoCommand.java
index 7b4cb86..8985ff3 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetPktOpticalTopoCommand.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/commands/CarrierEthernetPktOpticalTopoCommand.java
@@ -18,22 +18,22 @@
 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;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetProvisioner;
 
 /**
  * CLI command for indicating whether CE app controls a packet optical topology.
  */
 @Command(scope = "onos", name = "ce-pkt-optical-topo",
-        description = "Carrier Ethernet service removal command.")
+        description = "Carrier Ethernet packet-optical topology setup command.")
 public class CarrierEthernetPktOpticalTopoCommand extends AbstractShellCommand {
 
     @Argument(index = 0, name = "pktOptTopoArg", description = "Set to true if CE app " +
-            "controls a packet optical topology", required = true, multiValued = false)
+            "controls a packet-optical topology", required = true, multiValued = false)
     String pktOptTopoArg = null;
 
     @Override
     protected void execute() {
-        CarrierEthernetManager ceManager = get(CarrierEthernetManager.class);
-        ceManager.setPktOpticalTopo(Boolean.parseBoolean(pktOptTopoArg));
+        CarrierEthernetProvisioner ceProvisioner = get(CarrierEthernetProvisioner.class);
+        ceProvisioner.setPktOpticalTopo(Boolean.parseBoolean(pktOptTopoArg));
     }
 }
diff --git a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpTypeCompleter.java b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpTypeCompleter.java
index d46a2cb..79c065f 100644
--- a/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpTypeCompleter.java
+++ b/ecord/carrierethernet/src/main/java/org/onosproject/ecord/carrierethernet/cli/completers/CarrierEthernetLtpTypeCompleter.java
@@ -18,6 +18,7 @@
 import org.apache.karaf.shell.console.Completer;
 import org.apache.karaf.shell.console.completer.StringsCompleter;
 import org.onosproject.ecord.carrierethernet.app.CarrierEthernetLogicalTerminationPoint;
+import org.onosproject.ecord.carrierethernet.app.CarrierEthernetNetworkInterface;
 
 import java.util.List;
 import java.util.SortedSet;
@@ -30,7 +31,7 @@
 
         SortedSet<String> strings = delegate.getStrings();
 
-        for (CarrierEthernetLogicalTerminationPoint.Type type : CarrierEthernetLogicalTerminationPoint.Type.values()) {
+        for (CarrierEthernetNetworkInterface.Type type : CarrierEthernetNetworkInterface.Type.values()) {
             strings.add(type.toString());
         }
         strings.add("AUTO");