Updating Microsemi Driver to onos-yang-tools 2.x

Change-Id: I80e3348087518a8f9a742c813b6238371a3f8f97
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
new file mode 100644
index 0000000..4df22ec
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
@@ -0,0 +1,974 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+import org.onlab.packet.EthType;
+import org.onlab.packet.EthType.EtherType;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.drivers.microsemi.yang.UniSide;
+import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnic;
+import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnin;
+import org.onosproject.drivers.microsemi.yang.utils.CeVlanMapUtils;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanHeaderInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFilteringOpParam;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.DefaultSourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.SourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.DefaultInterfaceEth0;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.InterfaceEth0;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.DefaultSourceAddressRange;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.FilterAdminStateEnum;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.ServiceListType;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.VlanIdType;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.DefaultMefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.DefaultFlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagOverwrite;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPop;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPush;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagOverwrite;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPop;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPush;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.tagpush.tagpush.PushTagTypeEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Profiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Uni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.DefaultEvc;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.Evc;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.DefaultEvcPerUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.EvcPerUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnic;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnin;
+import org.slf4j.Logger;
+
+/**
+ * An implementation of the FlowRuleProgrammable behaviour for the EA10000 device.
+ *
+ * This device is not a native Open Flow device. It has only a NETCONF interface for configuration
+ * status retrieval and notifications. It supports only a small subset of OpenFlow rules.<br>
+ *
+ * The device supports only:<br>
+ * 1) Open flow rules that blocks certain IP address ranges, but only those incoming on Port 0
+ *    and has a limit of 10 such rules<br>
+ * 2) Open flow rules that PUSH, POP and OVERWRITE VLAN tags on both ports. This can push and overwrite
+ *    both C-TAGs (0x8100) and S-TAGs (0x88a8).
+ */
+public class EA1000FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+    protected final Logger log = getLogger(getClass());
+    public static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
+    public static final int PRIORITY_DEFAULT = 50000;
+    //To protect the NETCONF session from concurrent access across flow addition and removal
+    static Semaphore sessionMutex = new Semaphore(1);
+
+    /**
+     * Get the flow entries that are present on the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are retrieved from 2 configuration
+     * areas on the EA1000 NETCONF model - from SA filtering YANG model and from EVC UNI YANG model.<br>
+     * The flow entries must match exactly the FlowRule entries in the ONOS store. If they are not an
+     * exact match the device will be requested to remove those flows and the FlowRule will stay in a
+     * PENDING_ADD state.
+     * @return A collection of Flow Entries
+     */
+    @Override
+    public Collection<FlowEntry> getFlowEntries() {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfDevice ncDevice = controller.getDevicesMap().get(handler().data().deviceId());
+        if (ncDevice == null) {
+            log.error("Internal ONOS Error. Device has been marked as reachable, " +
+                            "but deviceID {} is not in Devices Map. Continuing with empty description",
+                    handler().data().deviceId());
+            return flowEntryCollection;
+        }
+        NetconfSession session = ncDevice.getSession();
+        CoreService coreService = checkNotNull(handler().get(CoreService.class));
+        ApplicationId appId = coreService.getAppId(MICROSEMI_DRIVERS);
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        log.debug("getFlowEntries() called on EA1000FlowRuleProgrammable");
+
+        //First get the MseaSaFiltering rules
+        SourceIpaddressFiltering sip =
+                new DefaultSourceIpaddressFiltering();
+
+        MseaSaFilteringOpParam op =
+                new MseaSaFilteringOpParam();
+        op.sourceIpaddressFiltering(sip);
+
+        try {
+            MseaSaFiltering saFilteringCurrent =
+                    mseaSaFilteringService.getMseaSaFiltering(op, session);
+            if (saFilteringCurrent != null &&
+                    saFilteringCurrent.sourceIpaddressFiltering() != null) {
+                flowEntryCollection.addAll(
+                        convertSaFilteringToFlowRules(saFilteringCurrent, appId));
+            }
+        } catch (NetconfException e) {
+            if (e.getCause() instanceof TimeoutException) {
+                log.warn("Timeout exception getting SA Filt Flow Entries from {}",
+                        handler().data().deviceId());
+                return flowEntryCollection;
+            } else {
+                log.error("Unexpected error on SA Filt getFlowEntries on {}",
+                        handler().data().deviceId(), e);
+            }
+        }
+
+
+        //Then get the EVCs - there will be a flow entry per EVC
+        MefServices mefServices = new DefaultMefServices();
+        mefServices.uni(new DefaultUni());
+
+        MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
+        mseaUniEvcServiceFilter.mefServices(mefServices);
+        try {
+            MseaUniEvcService uniEvcCurrent =
+                    mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
+                            session, DatastoreId.RUNNING);
+
+            flowEntryCollection.addAll(
+                    convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
+
+        } catch (NetconfException e) {
+            if (e.getCause() instanceof TimeoutException) {
+                log.warn("Timeout exception getting EVC Flow Entries from {}",
+                        handler().data().deviceId());
+                return flowEntryCollection;
+            } else {
+                log.error("Unexpected error on EVC getFlowEntries on {}",
+                        handler().data().deviceId(), e);
+            }
+        }
+
+        return flowEntryCollection;
+    }
+
+    /**
+     * Apply the flow entries to the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+     * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
+     * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
+     * will not be in the returned set.
+     *
+     * @param rules A collection of Flow Rules to be applied to the EA1000
+     * @return A collection of the Flow Rules that have been added.
+     */
+    @Override
+    public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+        Collection<FlowRule> frAdded = new HashSet<FlowRule>();
+        if (rules == null || rules.size() == 0) {
+            return rules;
+        }
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
+        // FIXME: Change this so it's dynamically driven
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+
+        List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+        Map<Integer, Evc> evcMap = new HashMap<>();
+
+        //Retrieve the list of actual EVCs and the CeVlanMaps from device
+        List<Evc> activeEvcs = new ArrayList<>();
+        try {
+            sessionMutex.acquire();
+            MseaUniEvcService evcResponse =
+                    mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
+            //There could be zero or more EVCs
+            if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+                activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+            }
+        } catch (NetconfException | InterruptedException e1) {
+            log.warn("Unexpected error on applyFlowRules", e1);
+        }
+
+        for (FlowRule fr : rules) {
+
+            // IP SA Filtering can only apply to Port 0 optics
+            if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
+                    fr.selector().getCriterion(Type.IN_PORT) != null &&
+                    ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+                parseFrForSaRange(frAdded, saRangeList, fr);
+
+            // EVCs will be defined by Flow Rules relating to VIDs
+            } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
+                    fr.selector().getCriterion(Type.IN_PORT) != null) {
+                //There could be many Flow Rules for one EVC depending on the ceVlanMap
+                //Cannot build up the EVC until we know the details - the key is the tableID and port
+                parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
+            } else {
+                log.info("Unexpected Flow Rule type applied: " + fr);
+            }
+        }
+
+        //If there are IPv4 Flow Rules created commit them now through the
+        //MseaSaFiltering service
+        if (saRangeList.size() > 0) {
+            try {
+                mseaSaFilteringService.setMseaSaFiltering(
+                            buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
+            } catch (NetconfException e) {
+                log.error("Error applying Flow Rules to SA Filtering - will try again: " + e.getMessage());
+                sessionMutex.release();
+                return frAdded;
+            }
+        }
+        //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
+        if (evcMap.size() > 0) {
+            List<Evc> evcList = evcMap.entrySet().stream()
+                    .map(x -> x.getValue())
+                    .collect(Collectors.toList());
+            Uni uni = new DefaultUni();
+            URI deviceName = handler().data().deviceId().uri();
+            uni.name(new Identifier45("Uni-on-"
+                    + deviceName.getSchemeSpecificPart()));
+            uni.evc(evcList);
+
+            List<BwpGroup> bwpGroupList = new ArrayList<BwpGroup>();
+            BwpGroup bwpGrp = new DefaultBwpGroup();
+            bwpGrp.groupIndex((short) 0);
+            bwpGroupList.add(bwpGrp);
+            Profiles profiles = new DefaultProfiles();
+            profiles.bwpGroup(bwpGroupList);
+
+            MefServices mefServices = new DefaultMefServices();
+            mefServices.uni(uni);
+            mefServices.profiles(profiles);
+
+            MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
+            mseaUniEvcServiceFilter.mefServices(mefServices);
+            try {
+                mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, DatastoreId.RUNNING);
+            } catch (NetconfException e) {
+                log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage());
+                sessionMutex.release();
+                return frAdded;
+            }
+        }
+        sessionMutex.release();
+        return frAdded;
+    }
+
+    /**
+     * Remove flow rules from the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+     * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
+     *
+     * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
+     * @return A collection of the Flow Rules that have been removed.
+     */
+    @Override
+    public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+        log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
+
+        if (rulesToRemove.size() == 0) {
+            return rulesToRemove;
+        }
+
+        //Retrieve the list of actual EVCs and the CeVlanMaps from device
+        List<Evc> activeEvcs = new ArrayList<>();
+        List<Short> acvtiveFiltRanges = new ArrayList<>();
+        try {
+            sessionMutex.acquire();
+            MseaUniEvcService evcResponse =
+                    mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
+            //There could be zero or more EVCs
+            if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+                activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+            }
+            mseaSaFilteringService.getConfigMseaSaFilterIds(session).forEach(
+                    r -> acvtiveFiltRanges.add(r.rangeId()));
+
+        } catch (NetconfException | InterruptedException e1) {
+            log.warn("Error on removeFlowRules.", e1);
+        }
+
+        List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+        Map<Integer, String> ceVlanMapMap = new HashMap<>();
+        Map<Integer, List<Short>> flowIdMap = new HashMap<>();
+
+        Collection<FlowRule> rulesRemoved = new HashSet<FlowRule>();
+        for (FlowRule ruleToRemove : rulesToRemove) {
+            // IP SA Filtering can only apply to Port 0 optics
+            if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
+                    ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
+                    ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+                SourceAddressRange sar = new DefaultSourceAddressRange();
+                sar.rangeId((short) ruleToRemove.tableId());
+                acvtiveFiltRanges.remove(Short.valueOf((short) ruleToRemove.tableId()));
+                rulesRemoved.add(ruleToRemove);
+                saRangeList.add(sar);
+
+            } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
+                    ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
+                PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
+                VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
+                int evcId = ruleToRemove.tableId();
+                int evcKey = (evcId << 2) + (int) portNumber.toLong();
+                String activeCeVlanMap = "";
+                //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
+                // from the ceVlanMap and not the whole EVC
+                if (!ceVlanMapMap.containsKey(evcKey)) {
+                    for (Evc activeEvc:activeEvcs) {
+                        if (activeEvc.evcIndex() == evcId) {
+                            if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+                                    UniSide.CUSTOMER) {
+                                activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
+                            } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+                                    UniSide.NETWORK) {
+                                activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
+                            }
+                        }
+                    }
+                }
+
+                ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
+                if (!flowIdMap.containsKey(evcKey)) {
+                    flowIdMap.put(evcKey, new ArrayList<>());
+                }
+                flowIdMap.get(evcKey).add(vlanId.id());
+                rulesRemoved.add(ruleToRemove);
+
+            } else {
+                log.info("Unexpected Flow Rule type removal: " + ruleToRemove);
+            }
+        }
+
+        //If there are IPv4 Flow Rules created commit them now through the
+        //MseaSaFiltering service
+        if (saRangeList.size() > 0 && acvtiveFiltRanges.size() == 0) {
+            try {
+                SourceIpaddressFiltering saFilter =
+                        new DefaultSourceIpaddressFiltering();
+                MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
+                mseaSaFiltering.sourceIpaddressFiltering(saFilter);
+
+                mseaSaFilteringService.deleteMseaSaFilteringRange(
+                        mseaSaFiltering, session, DatastoreId.RUNNING);
+            } catch (NetconfException e) {
+                log.warn("Remove FlowRule on MseaSaFilteringService could not delete all SARules - "
+                        + "they may already have been deleted: " + e.getMessage());
+            }
+        } else if (saRangeList.size() > 0) {
+            try {
+                mseaSaFilteringService.deleteMseaSaFilteringRange(
+                        buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
+            } catch (NetconfException e) {
+                log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
+                        + "it may already have been deleted: " + e.getMessage());
+            }
+        }
+
+        if (ceVlanMapMap.size() > 0) {
+            try {
+                mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
+                        session, DatastoreId.RUNNING, portAssignment);
+            } catch (NetconfException e) {
+                log.warn("Remove FlowRule on MseaUniEvcService could not delete EVC - "
+                        + "it may already have been deleted: " + e.getMessage());
+            }
+        }
+
+        sessionMutex.release();
+        return rulesRemoved;
+    }
+
+    /**
+     * An internal method for extracting one EVC from a list and returning its ceVlanMap.
+     *
+     * @param evcList - the list of known EVCs
+     * @param evcIndex - the index of the EVC we're looking for
+     * @param side - the side of the UNI
+     * @return - the CEVlanMap we're looking for
+     */
+    private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
+        if (evcList != null && evcList.size() > 0) {
+            for (Evc evc:evcList) {
+                if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
+                    if (side == UniSide.CUSTOMER &&
+                        evc.evcPerUni().evcPerUnic() != null &&
+                        evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
+                        return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
+                    } else if (side == UniSide.NETWORK &&
+                        evc.evcPerUni().evcPerUnin() != null &&
+                        evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
+                        return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
+                    }
+                }
+            }
+        }
+
+        return ""; //The EVC required was not in the list
+    }
+
+    /**
+     * An internal method to convert from a FlowRule to SARange.
+     *
+     * @param frList A collection of flow rules
+     * @param saRangeList A list of SARanges
+     * @param fr A flow rule
+     */
+    private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
+        String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
+        log.debug("Applying IP address to " + ipAddrStr
+                + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
+
+        SourceAddressRange sar =
+                new DefaultSourceAddressRange();
+
+        sar.rangeId((short) fr.tableId());
+        sar.name("Flow:" + fr.id().toString());
+        sar.ipv4AddressPrefix(ipAddrStr);
+
+        frList.add(fr);
+        saRangeList.add(sar);
+    }
+
+    private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
+            List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
+        //There could be many Flow Rules for one EVC depending on the ceVlanMap
+        //Cannot build up the EVC until we know the details - the key is the tableID and port
+        Ea1000Port port = Ea1000Port.fromNum(
+                ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
+        Integer evcKey = (fr.tableId() << 2) + port.portNum();
+        VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
+        FlowMapping fm = new DefaultFlowMapping();
+        fm.ceVlanId(VlanIdType.of(sourceVid.id()));
+        fm.flowId(BigInteger.valueOf(fr.id().value()));
+
+        if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
+            //Replace ceVlanMap
+            if (port.nOrC(portAssignment) == UniSide.CUSTOMER) {
+                evcMap.get(evcKey).evcPerUni().evcPerUnic().addToFlowMapping(fm);
+                ServiceListType newCeVlanMap = new ServiceListType(
+                        CeVlanMapUtils.addtoCeVlanMap(
+                                evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap().toString(),
+                                sourceVid.toShort()));
+                evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
+            } else {
+                evcMap.get(evcKey).evcPerUni().evcPerUnin().addToFlowMapping(fm);
+                ServiceListType newCeVlanMap = new ServiceListType(
+                        CeVlanMapUtils.addtoCeVlanMap(
+                                evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap().toString(),
+                                sourceVid.toShort()));
+                evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
+            }
+        } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
+            TagManipulation tm = getTagManipulation(fr);
+            if (port.nOrC(portAssignment) == UniSide.NETWORK) {
+                ServiceListType newCeVlanMap = new ServiceListType(
+                        CeVlanMapUtils.addtoCeVlanMap(
+                                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap().toString(),
+                                sourceVid.toShort()));
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().tagManipulation(tm);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().addToFlowMapping(fm);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ingressBwpGroupIndex(getMeterId(fr.treatment()));
+            } else {
+                ServiceListType newCeVlanMap = new ServiceListType(
+                        CeVlanMapUtils.addtoCeVlanMap(
+                                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap().toString(),
+                                sourceVid.toShort()));
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().tagManipulation(tm);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().addToFlowMapping(fm);
+                evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ingressBwpGroupIndex(getMeterId(fr.treatment()));
+            }
+        } else {
+            Evc evc = new DefaultEvc();
+            EvcPerUnin epun = new CustomEvcPerUnin();
+            EvcPerUnic epuc = new CustomEvcPerUnic();
+            TagManipulation tm = getTagManipulation(fr);
+
+            UniSide side = port.nOrC(portAssignment);
+            String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
+            String newCeVlanMap =
+                    CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
+            String oppositeCeVlanMap =
+                    getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
+                            port.opposite().nOrC(portAssignment));
+            oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
+            if (side == UniSide.NETWORK) {
+                epun.ceVlanMap(new ServiceListType(newCeVlanMap));
+                epun.tagManipulation(tm);
+                epun.addToFlowMapping(fm);
+                epun.ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+                epuc.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+                epuc.ingressBwpGroupIndex(new Long(0));
+            } else {
+                epuc.ceVlanMap(new ServiceListType(newCeVlanMap));
+                epuc.tagManipulation(tm);
+                epuc.addToFlowMapping(fm);
+                epuc.ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+                epun.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+                epun.ingressBwpGroupIndex(new Long(0));
+            }
+
+            evc.evcIndex(fr.tableId());
+            evc.name(new Identifier45("EVC-" + String.valueOf(fr.tableId())));
+
+            DefaultEvcPerUni epu = new DefaultEvcPerUni();
+            epu.evcPerUnin(epun);
+            epu.evcPerUnic(epuc);
+            evc.evcPerUni(epu);
+
+            evcMap.put(evcKey, evc);
+        }
+
+        frList.add(fr);
+    }
+
+
+    private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
+        InterfaceEth0 saIf = new DefaultInterfaceEth0();
+        for (SourceAddressRange sa:saRangeList) {
+            saIf.addToSourceAddressRange(sa);
+        }
+        saIf.filterAdminState(FilterAdminStateEnum.BLACKLIST);
+
+        SourceIpaddressFiltering saFilter =
+                new DefaultSourceIpaddressFiltering();
+        saFilter.interfaceEth0(saIf);
+
+        MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
+        mseaSaFiltering.sourceIpaddressFiltering(saFilter);
+
+        return mseaSaFiltering;
+    }
+
+    private Collection<FlowEntry> convertSaFilteringToFlowRules(
+            MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        List<SourceAddressRange> saRangelist =
+                saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
+        Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
+        TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+        if (saRangelist != null) {
+            for (SourceAddressRange sa : saRangelist) {
+                Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
+
+                TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
+
+                TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+                TrafficTreatment treatment = trBuilder.drop().build();
+
+                FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
+                if (sa.name() != null && sa.name().startsWith("Flow:")) {
+                    String[] nameParts = sa.name().split(":");
+                    Long cookie = Long.valueOf(nameParts[1], 16);
+                    feBuilder = feBuilder.withCookie(cookie);
+                } else {
+                    feBuilder = feBuilder.fromApp(appId);
+                }
+
+                FlowRule fr = feBuilder
+                        .forDevice(handler().data().deviceId())
+                        .withSelector(selector)
+                        .withTreatment(treatment)
+                        .forTable(sa.rangeId())
+                        .makePermanent()
+                        .withPriority(PRIORITY_DEFAULT)
+                        .build();
+
+                flowEntryCollection.add(
+                        new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
+            }
+        }
+        return flowEntryCollection;
+    }
+
+
+    private Collection<FlowEntry> convertEvcUniToFlowRules(
+            MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
+                uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
+            log.info("No EVC's found when getting flow rules");
+            return flowEntryCollection;
+        }
+
+        for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
+            FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
+            TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+            TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
+            //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+            Short[] vlanIdsUniN =
+                    CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
+            for (Short vlanId:vlanIdsUniN) {
+                if (vlanId == 0) {
+                    continue;
+                }
+                Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
+                TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
+                long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
+
+                FlowRule frUniN = frBuilder
+                    .forDevice(handler().data().deviceId())
+                    .withSelector(tsUniN)
+                    .withTreatment(uniNTreatment)
+                    .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+                    .makePermanent()
+                    .withPriority(PRIORITY_DEFAULT)
+                    .withCookie(flowId)
+                    .build();
+                flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
+            }
+
+            TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
+            //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+            Short[] vlanIdsUniC =
+                    CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
+            if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
+                for (Short vlanId:vlanIdsUniC) {
+                    if (vlanId == 0) {
+                        continue;
+                    }
+                    Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
+                    TrafficSelector tsUniC =
+                            tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
+                    long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
+
+                    FlowRule frUniC = frBuilder
+                            .forDevice(handler().data().deviceId())
+                            .withSelector(tsUniC)
+                            .withTreatment(uniCTreatment)
+                            .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+                            .makePermanent()
+                            .withPriority(PRIORITY_DEFAULT)
+                            .withCookie(flowId)
+                            .build();
+                    flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
+                }
+            }
+        }
+
+        return flowEntryCollection;
+    }
+
+    private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
+        if (fmList == null || vlanId == null) {
+            log.warn("Flow Mapping list is null when reading EVCs");
+            return -1L;
+        }
+        for (FlowMapping fm:fmList) {
+            if (fm.ceVlanId().uint16() == vlanId.intValue()) {
+                return fm.flowId().longValue();
+            }
+        }
+        return 0L;
+    }
+
+    private String ceVlanMapForUniSide(
+            EvcPerUni evcPerUni, boolean portN) {
+        if (portN) {
+            return evcPerUni.evcPerUnin().ceVlanMap().string();
+        } else {
+            return evcPerUni.evcPerUnic().ceVlanMap().string();
+        }
+    }
+
+    private Criterion criterionPortForUniSide(
+            UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
+        boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
+        int portNum = ((cOnOptics && portN) || (!cOnOptics && !portN)) ? 1 : 0;
+        return Criteria.matchInPort(PortNumber.portNumber(portNum));
+    }
+
+    private TrafficTreatment treatmentForUniSde(
+            EvcPerUni evcPerUni, boolean portN) {
+        TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+
+        TagManipulation tm = null;
+        short meterId = 0;
+        if (portN) {
+            tm = evcPerUni.evcPerUnin().tagManipulation();
+            meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
+        } else {
+            tm = evcPerUni.evcPerUnic().tagManipulation();
+            meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
+        }
+
+        if (meterId > 0L) {
+            trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
+//            trBuilder = trBuilder.meter(MeterId.meterId(meterId)).transition(0);
+        }
+
+        if (tm == null) {
+            return trBuilder.build(); //no tag manipulation found
+        }
+
+        if (tm.getClass().equals(DefaultTagPush.class)) {
+            VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
+            PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
+            //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
+            // to be an exactMatch. See DefaultFlowRule.exactMatch()
+            trBuilder = trBuilder
+                    .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
+                            EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
+                    .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
+
+        } else if (tm.getClass().equals(DefaultTagPop.class)) {
+            trBuilder = trBuilder.popVlan();
+
+        } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
+            TagOverwrite to = (TagOverwrite) tm;
+            VlanId ovrVlanNum = VlanId
+                    .vlanId((short) (
+                            //There are 2 classes TagOverwrite - the other one is already imported
+                            to
+                            .tagOverwrite()
+                            .outerTagVlan()
+                            .uint16()));
+            trBuilder = trBuilder.setVlanId(ovrVlanNum);
+
+        }
+
+        return trBuilder.build();
+    }
+
+    private static TagManipulation getTagManipulation(FlowRule fr) {
+        boolean isPop = false;
+        boolean isPush = false;
+        VlanId vlanId = null;
+        EthType ethType = EtherType.VLAN.ethType(); //Default
+        for (Instruction inst:fr.treatment().allInstructions()) {
+            if (inst.type() == Instruction.Type.L2MODIFICATION) {
+                L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
+                if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
+                    isPop = true;
+                } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                    isPush = true;
+                    ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
+                } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
+                    vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
+                }
+            }
+        }
+
+        if (isPop) {
+            //The should be no vlanId in this case
+            TagPop pop = new DefaultTagPop();
+            org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+                .evcperuniextensionattributes.tagmanipulation
+                .tagpop.TagPop popInner =
+                    new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+                        .mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagpop.DefaultTagPop();
+            pop.tagPop(popInner);
+            return pop;
+
+        } else if (isPush && vlanId != null) {
+            TagPush push = new DefaultTagPush();
+            org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+                .evcperuniextensionattributes.tagmanipulation
+                .tagpush.TagPush pushInner =
+                    new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+                        .mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagpush.DefaultTagPush();
+            pushInner.outerTagVlan(new VlanIdType(vlanId.id()));
+            pushInner.pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
+                                PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG);
+            push.tagPush(pushInner);
+            return push;
+
+        } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
+            TagOverwrite ovr = new DefaultTagOverwrite();
+            org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+                .evcperuniextensionattributes.tagmanipulation
+                .tagoverwrite.TagOverwrite ovrInner =
+                    new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+                        .mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagoverwrite.DefaultTagOverwrite();
+            ovrInner.outerTagVlan(new VlanIdType(vlanId.id()));
+            ovr.tagOverwrite(ovrInner);
+            return ovr;
+        }
+
+        return null;
+    }
+
+    private static long getMeterId(TrafficTreatment treatment) {
+        return (treatment.metered() != null && treatment.metered().meterId() != null)
+                ? treatment.metered().meterId().id() : 0L;
+    }
+
+    /**
+     * An enumerated type that characterises the 2 port layout of the EA1000 device.
+     * The device is in an SFP package and has only 2 ports, the HOST port which
+     * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
+     */
+    public enum Ea1000Port {
+        HOST(1),
+        OPTICS(0);
+
+        private int num = 0;
+        private Ea1000Port(int num) {
+            this.num = num;
+        }
+
+        /**
+         * The numerical assignment of this port.
+         * @return The port number
+         */
+        public int portNum() {
+            return num;
+        }
+
+        /**
+         * Return the enumerated value from a port number.
+         * @param num The port number
+         * @return An enumerated value
+         */
+        public static Ea1000Port fromNum(long num) {
+            for (Ea1000Port a:Ea1000Port.values()) {
+                if (a.num == num) {
+                    return a;
+                }
+            }
+            return HOST;
+        }
+
+        /**
+         * Get the port that the UNI-N is present on.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value
+         */
+        public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
+            if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+                return OPTICS;
+            } else {
+                return HOST;
+            }
+        }
+
+        /**
+         * Get the port that the UNI-C is present on.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value
+         */
+        public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
+            if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+                return HOST;
+            } else {
+                return OPTICS;
+            }
+        }
+
+        /**
+         * Get the port opposite the current port.
+         * @return An enumerated value for the opposite side
+         */
+        public Ea1000Port opposite() {
+            if (this.equals(HOST)) {
+                return OPTICS;
+            } else {
+                return HOST;
+            }
+        }
+
+        /**
+         * Evaluate which side of the UNI on the EA1000 device this port refers to.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value representing the UniSide
+         */
+        public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
+            if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
+                    (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
+                return UniSide.CUSTOMER;
+            } else {
+                return UniSide.NETWORK;
+            }
+        }
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
new file mode 100644
index 0000000..226ad2f
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi;
+
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.Meter.Unit;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperations;
+import org.onosproject.net.meter.MeterProvider;
+import org.onosproject.net.meter.MeterProviderRegistry;
+import org.onosproject.net.meter.MeterProviderService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.CosColorType;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.PriorityType;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.coscolortype.CosColorTypeEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.DefaultMefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Profiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.Cos;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.DefaultCos;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.bwpgroup.Bwp;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.bwpgroup.DefaultBwp;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.DefaultEvcCosTypeEvcColorId;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.EvcCosTypeEvcColorId;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.evccostypeevccolorid.DefaultEvcCosTypeAll8PrioTo1EvcColor;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.evccostypeevccolorid.EvcCosTypeAll8PrioTo1EvcColor;
+import org.slf4j.Logger;
+
+/**
+ * Provider which uses an NETCONF controller to handle meters.
+ *
+ * TODO: move this to an architecture similar to FlowRuleDriverProvider in order
+ * to use a behavior to discover meters.
+ */
+@Component(immediate = true, enabled = true)
+public class EA1000MeterProvider extends AbstractProvider implements MeterProvider {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetconfController controller;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MeterProviderRegistry providerRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc;
+
+    private MeterProviderService providerService;
+
+    private static final int COS_INDEX_1 = 1;
+    private static final short DEFAULT_OUTGOING_PRIO = 3;
+
+    /**
+     * Creates a OpenFlow meter provider.
+     */
+    public EA1000MeterProvider() {
+        super(new ProviderId("netconf", "org.onosproject.provider.meter.microsemi"));
+    }
+
+    @Activate
+    public void activate() {
+        providerService = providerRegistry.register(this);
+
+    }
+
+    @Deactivate
+    public void deactivate() {
+        providerRegistry.unregister(this);
+
+        providerService = null;
+    }
+
+    @Override
+    public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
+        log.debug("Adding meterOps to Microsemi Meter Store");
+    }
+
+    @Override
+    public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
+        if (meterOp == null || deviceId == null) {
+            log.warn("Missing argument for performMeterOperation()");
+            return;
+        }
+        log.debug("{} meterOp {} to Microsemi Meter Store", meterOp.type(), meterOp);
+
+        long meterId = meterOp.meter().id().id();
+        String deviceName = deviceId.uri().getSchemeSpecificPart();
+        Unit unit = meterOp.meter().unit();
+
+        Profiles profiles = new DefaultProfiles();
+        if (meterOp.type() == MeterOperation.Type.ADD || meterOp.type() == MeterOperation.Type.MODIFY) {
+            Bwp bwp = new DefaultBwp();
+            bwp.cosIndex(COS_INDEX_1);
+            bwp.name("BWP-" + String.valueOf(meterId) + "-" + deviceName);
+
+            long cirRateKbps = 0L;
+            long cbsRateKbps = 0L;
+            long eirRateKbps = 0L;
+            long ebsRateKbps = 0L;
+            for (Band band:meterOp.meter().bands()) {
+                if (band.type() == Band.Type.REMARK) {
+                    //This relates to CIR/CBS
+                    cirRateKbps = toBitsPerSec(band.rate(), unit);
+                    cbsRateKbps = band.burst(); //Already in kbps
+                } else if (band.type() == Band.Type.DROP) {
+                    //This relates to EIR/EBS
+                    eirRateKbps = toBitsPerSec(band.rate(), unit);
+                    ebsRateKbps = band.burst(); //Already in kbps
+                }
+            }
+            bwp.committedInformationRate(cirRateKbps);
+            bwp.excessInformationRate(eirRateKbps - cirRateKbps);
+            if (meterOp.meter().isBurst()) {
+                bwp.committedBurstSize(cbsRateKbps);
+                bwp.excessBurstSize(ebsRateKbps - cbsRateKbps);
+            }
+
+            BwpGroup bwpg = new DefaultBwpGroup();
+            bwpg.groupIndex((short) meterId);
+            bwpg.addToBwp(bwp);
+
+            //Create cos-1 as referenced above - we only support 1 at the moment
+            Cos cos = new DefaultCos();
+            cos.cosIndex(COS_INDEX_1);
+            cos.name("COS-1");
+            cos.outgoingCosValue(PriorityType.of(DEFAULT_OUTGOING_PRIO));
+            cos.colorAware(true);
+            cos.colorForward(true);
+
+            EvcCosTypeAll8PrioTo1EvcColor ect =
+                    new DefaultEvcCosTypeAll8PrioTo1EvcColor();
+            ect.evcAll8ColorTo(CosColorType.of(CosColorTypeEnum.GREEN));
+            profiles.addToBwpGroup(bwpg);
+
+            EvcCosTypeEvcColorId cid = new DefaultEvcCosTypeEvcColorId();
+            cid.evcCosTypeAll8PrioTo1EvcColor(ect);
+            cos.cosTypeChoice(cid);
+            profiles.addToCos(cos);
+        } else if (meterOp.type() == MeterOperation.Type.REMOVE) {
+            BwpGroup bwpg = new DefaultBwpGroup();
+            bwpg.groupIndex((short) meterId);
+
+            profiles.addToBwpGroup(bwpg);
+        }
+
+        MefServices mefServices = new DefaultMefServices();
+        mefServices.profiles(profiles);
+
+        MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
+        mseaUniEvcServiceFilter.mefServices(mefServices);
+
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+        try {
+            if (meterOp.type() == MeterOperation.Type.REMOVE) {
+                mseaUniEvcServiceSvc.deleteMseaUniEvcService(mseaUniEvcServiceFilter,
+                        session, DatastoreId.RUNNING);
+            } else {
+                mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter,
+                        session, DatastoreId.RUNNING);
+            }
+        } catch (NetconfException e) {
+            //This can fail if the BWP Group is deleted before the EVC that is dependent on it
+            //The delete of the EVC will be called on a separate thread to that should proceed
+            //within a few seconds after which we should try again
+            AtomicInteger retry = new AtomicInteger(4);
+            if (meterOp.type() == MeterOperation.Type.REMOVE &&
+                    e.getMessage().startsWith("Failed to run edit-config through NETCONF")) {
+                while (retry.getAndDecrement() > 0) {
+                    try {
+                        Thread.sleep(1000L);
+                        log.debug("Retrying deletion of Bandwith Profile Group {}",
+                                String.valueOf(meterId));
+                        mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter,
+                                session, DatastoreId.RUNNING);
+                        return; //If it did not throw an exception
+                    } catch (InterruptedException e1) {
+                        log.debug("Error when deleting BWP profile on EA1000" +
+                                " - trying again in 1 sec", e1);
+                    } catch (NetconfException e1) {
+                        log.debug("NETCONF failed to delete profile - trying again in 1 sec", e1);
+                    }
+                }
+                log.error("Error deleting BWPGroup {} from {} after 4 tries: {}",
+                        meterId, deviceId, e.getMessage());
+            } else {
+                log.error("Error adding BWPGroup {} from {}: {}",
+                        meterId, deviceId, e.getMessage());
+                throw new UnsupportedOperationException(e);
+            }
+        }
+    }
+
+    private static long toBitsPerSec(long rate, Unit unit) {
+        if (unit == Unit.KB_PER_SEC) {
+            return rate * 8;
+        } else {
+            return -1;
+        }
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java
new file mode 100644
index 0000000..308bdff
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.drivers.microsemi.EA1000FlowRuleProgrammable.Ea1000Port;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.slf4j.Logger;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalCause;
+import com.google.common.cache.RemovalNotification;
+
+/**
+ * Support for FlowObjectives in the EA1000.
+ *
+ * Used with the CarrierEthernet App
+ *
+ */
+public class EA1000Pipeliner extends AbstractHandlerBehaviour implements Pipeliner {
+
+    protected final Logger log = getLogger(getClass());
+    protected ServiceDirectory serviceDirectory;
+    protected FlowRuleService flowRuleService;
+    protected DeviceId deviceId;
+    protected Cache<Integer, NextObjective> pendingNext;
+    protected Integer evcIdBase = 1;
+
+    @Override
+    public void init(DeviceId deviceId, PipelinerContext context) {
+        this.serviceDirectory = context.directory();
+        this.deviceId = deviceId;
+
+        flowRuleService = serviceDirectory.get(FlowRuleService.class);
+
+        pendingNext = CacheBuilder.newBuilder()
+                .expireAfterWrite(20, TimeUnit.SECONDS)
+                .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
+                    if (notification.getCause() == RemovalCause.EXPIRED) {
+                        notification.getValue().context()
+                                .ifPresent(c -> c.onError(notification.getValue(),
+                                        ObjectiveError.FLOWINSTALLATIONFAILED));
+                    }
+                }).build();
+
+        log.debug("Loaded handler behaviour EA1000Pipeliner for " + handler().data().deviceId().uri());
+    }
+
+    @Override
+    public void filter(FilteringObjective filterObjective) {
+        TrafficTreatment.Builder actions;
+        boolean oppositePort = false;
+        int evcId = -1;
+        switch (filterObjective.type()) {
+            case PERMIT:
+                if (filterObjective.meta() == null) {
+                    actions = DefaultTrafficTreatment.builder().add(Instructions.popVlan());
+                } else {
+                    oppositePort = true; //Experimental - push happens on the opposite port
+                    actions = DefaultTrafficTreatment.builder(filterObjective.meta());
+                    if (filterObjective.meta().metered() != null) {
+                        actions.meter(filterObjective.meta().metered().meterId());
+                    }
+                    actions.transition(0);
+                    boolean isPush = false;
+                    int vid = 0;
+                    for (Instruction inst:filterObjective.meta().immediate()) {
+                        if (inst.type() == Instruction.Type.L2MODIFICATION) {
+                            L2ModificationInstruction l2mod = (L2ModificationInstruction) inst;
+                            if (l2mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                                isPush = true;
+                            } else if (l2mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
+                                vid = ((ModVlanIdInstruction) l2mod).vlanId().id();
+                            }
+                        }
+                    }
+                    if (isPush && vid > 0) {
+                        evcId = vid;
+                    }
+                }
+                break;
+            case DENY:
+                actions = (filterObjective.meta() == null) ?
+                        DefaultTrafficTreatment.builder() :
+                        DefaultTrafficTreatment.builder(filterObjective.meta());
+                actions.drop();
+                break;
+            default:
+                log.warn("Unknown filter type: {}", filterObjective.type());
+                actions = DefaultTrafficTreatment.builder().drop();
+        }
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        for (Criterion c:filterObjective.conditions()) {
+            if (c.type() == Type.VLAN_VID && evcId == -1) {
+                evcId = ((VlanIdCriterion) c).vlanId().id();
+            }
+            selector.add(c);
+        }
+
+        if (filterObjective.key() != null) {
+            if (oppositePort) {
+                //Experimental
+                Ea1000Port port = Ea1000Port.fromNum(((PortCriterion) filterObjective.key()).port().toLong());
+                selector.matchInPort(PortNumber.portNumber(port.opposite().portNum()));
+            } else {
+                selector.add(filterObjective.key());
+            }
+        }
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(actions.build())
+                .fromApp(filterObjective.appId())
+                .forTable(evcId)
+                .withPriority(filterObjective.priority());
+
+        if (filterObjective.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(filterObjective.timeout());
+        }
+
+        installObjective(ruleBuilder, filterObjective);
+
+        log.debug("filter() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + filterObjective);
+    }
+
+    @Override
+    public void forward(ForwardingObjective forwardObjective) {
+        TrafficSelector selector = forwardObjective.selector();
+
+        if (forwardObjective.treatment() != null) {
+            List<Instruction> instructions = forwardObjective.treatment().immediate();
+            if (instructions != null && instructions.size() == 1
+                    && instructions.get(0).type() == Instruction.Type.OUTPUT
+                    && ((OutputInstruction) instructions.get(0)).port() == PortNumber.CONTROLLER) {
+                Set<Criterion> criteria = forwardObjective.selector().criteria();
+                log.info("EA1000 does not yet implement forwarding to CONTROLLER for flow objective for: "
+                        + handler().data().deviceId().uri()
+                        + ". "
+                        + forwardObjective);
+                return;
+            } else {
+                FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector)
+                        .fromApp(forwardObjective.appId())
+                        .withPriority(forwardObjective.priority())
+                        .withTreatment(forwardObjective.treatment());
+
+                if (forwardObjective.permanent()) {
+                    ruleBuilder.makePermanent();
+                } else {
+                    ruleBuilder.makeTemporary(forwardObjective.timeout());
+                }
+                installObjective(ruleBuilder, forwardObjective);
+            }
+        } else {
+            NextObjective nextObjective = pendingNext.getIfPresent(forwardObjective.nextId());
+            if (nextObjective != null) {
+                pendingNext.invalidate(forwardObjective.nextId());
+                nextObjective.next().forEach(treat -> {
+                    FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                            .forDevice(deviceId)
+                            .withSelector(selector)
+                            .fromApp(forwardObjective.appId())
+                            .withPriority(forwardObjective.priority())
+                            .withTreatment(treat);
+
+                    if (forwardObjective.permanent()) {
+                        ruleBuilder.makePermanent();
+                    } else {
+                        ruleBuilder.makeTemporary(forwardObjective.timeout());
+                    }
+                    installObjective(ruleBuilder, forwardObjective);
+                });
+            } else {
+                forwardObjective.context().ifPresent(c -> c.onError(forwardObjective,
+                        ObjectiveError.GROUPMISSING));
+            }
+        }
+        log.debug("EA1000: Unhandled Forwarding Objective for: "
+                + handler().data().deviceId().uri()
+                + ". "
+                + forwardObjective);
+    }
+
+    @Override
+    public void next(NextObjective nextObjective) {
+        pendingNext.put(nextObjective.id(), nextObjective);
+        nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
+
+        log.debug("next() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + nextObjective);
+    }
+
+    @Override
+    public List<String> getNextMappings(NextGroup nextGroup) {
+        log.debug("getNextMappings() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + nextGroup);
+        return new ArrayList<String>();
+    }
+
+    protected void installObjective(FlowRule.Builder ruleBuilder, Objective objective) {
+        FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
+        switch (objective.op()) {
+
+            case ADD:
+                flowBuilder.add(ruleBuilder.build());
+                break;
+            case REMOVE:
+                flowBuilder.remove(ruleBuilder.build());
+                break;
+            default:
+                log.warn("Unknown operation {}", objective.op());
+        }
+
+        flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                objective.context().ifPresent(context -> context.onSuccess(objective));
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                objective.context()
+                        .ifPresent(context -> context.onError(objective, ObjectiveError.FLOWINSTALLATIONFAILED));
+            }
+        }));
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
new file mode 100644
index 0000000..dfb8480
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.microsemi.yang.IetfSystemNetconfService;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.system.AugmentedSysSystem;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.system.DefaultAugmentedSysSystem;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.systemstate.platform.AugmentedSysPlatform;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystem;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.systemstate.platform.DefaultAugmentedSysPlatform;
+import org.onosproject.yang.gen.v1.ietfyangtypes.rev20130715.ietfyangtypes.DateAndTime;
+import org.slf4j.Logger;
+
+public class Ea1000DeviceDescription extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery {
+
+    private String serialNumber = "unavailable";
+    private String swVersion = "unavailable";
+    private String longitudeStr = null;
+    private String latitudeStr = null;
+    private final Logger log = getLogger(getClass());
+
+    public Ea1000DeviceDescription() {
+        log.info("Loaded handler behaviour Ea1000DeviceDescription.");
+    }
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+        log.info("Adding description for EA1000 device");
+
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfDevice ncDevice = controller.getDevicesMap().get(handler().data().deviceId());
+        if (ncDevice == null) {
+            log.error("Internal ONOS Error. Device has been marked as reachable, " +
+                    "but deviceID {} is not in Devices Map. Continuing with empty description",
+                    handler().data().deviceId());
+            return null;
+        }
+        NetconfSession session = ncDevice.getSession();
+        IetfSystemNetconfService ietfSystemService =
+                (IetfSystemNetconfService) checkNotNull(handler().get(IetfSystemNetconfService.class));
+
+        try {
+            IetfSystem system = ietfSystemService.getIetfSystemInit(session);
+            if (system != null && system.systemState() != null) {
+                swVersion = system.systemState().platform().osRelease();
+                AugmentedSysPlatform augmentedSysPlatform =
+                        (AugmentedSysPlatform) system.systemState()
+                        .platform().augmentation(DefaultAugmentedSysPlatform.class);
+                serialNumber = augmentedSysPlatform.deviceIdentification().serialNumber();
+                DateAndTime deviceDateAndTime = system.systemState().clock().currentDatetime();
+                OffsetDateTime odt =
+                        OffsetDateTime.parse(deviceDateAndTime.string(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+                if (odt.getYear() < OffsetDateTime.now(ZoneId.of("UTC")).getYear()) {
+                    OffsetDateTime nowUtc = OffsetDateTime.now(ZoneId.of("UTC"));
+                    log.warn("Date on device is in the past: {}. Setting it to {}", odt.toString(), nowUtc);
+                    ietfSystemService.setCurrentDatetime(nowUtc, session);
+                }
+            }
+
+            if (system != null && system.system() != null) {
+                AugmentedSysSystem augmentedSystem =
+                        (AugmentedSysSystem) system.system().augmentation(DefaultAugmentedSysSystem.class);
+                longitudeStr = augmentedSystem.longitude().toPlainString();
+                latitudeStr = augmentedSystem.latitude().toPlainString();
+            }
+        } catch (NetconfException e) {
+            log.error("Unable to retrieve init data from device: " + handler().data().deviceId().toString()
+                    + " Error: " + e.getMessage());
+            e.printStackTrace();
+        }
+
+        DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
+        DeviceId deviceId = handler().data().deviceId();
+        Device device = deviceService.getDevice(deviceId);
+        DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder();
+        if (longitudeStr != null && latitudeStr != null) {
+            annotationsBuilder.set(AnnotationKeys.LONGITUDE, longitudeStr)
+                    .set(AnnotationKeys.LATITUDE, latitudeStr).build();
+        } else {
+            log.warn("Longitude and latitude could not be retrieved from device " + deviceId);
+        }
+
+        return new DefaultDeviceDescription(device.id().uri(), Device.Type.OTHER, "Microsemi", "EA1000", swVersion,
+                serialNumber, new ChassisId(), annotationsBuilder.build());
+    }
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+
+        List<PortDescription> ports = new ArrayList<PortDescription>();
+
+        DefaultAnnotations annotationOptics = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "Optics")
+                .build();
+        PortDescription optics = new DefaultPortDescription(PortNumber.portNumber(0), true, Port.Type.FIBER, 1000,
+                annotationOptics);
+        ports.add(optics);
+
+        DefaultAnnotations annotationHost = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "Host").build();
+        PortDescription host = new DefaultPortDescription(PortNumber.portNumber(1), true, Port.Type.COPPER, 1000,
+                annotationHost);
+        ports.add(host);
+
+        return ports;
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java
new file mode 100644
index 0000000..724792e
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.onosproject.net.behaviour.MeterQuery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+
+/**
+ * Driver which always responds that all Meters are available for the Device.
+ */
+public class FullMetersAvailable extends AbstractHandlerBehaviour implements MeterQuery {
+
+    private static final long MAX_METER = 0x00000FFF;
+
+    @Override
+    public long getMaxMeters() {
+        return MAX_METER;
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java
new file mode 100644
index 0000000..b7f0e68
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+/**
+ * Loader for Microsemi device drivers.
+ */
+@Component(immediate = true)
+public class MicrosemiDriversLoader extends AbstractDriverLoader {
+
+    public MicrosemiDriversLoader() {
+        super("/microsemi-drivers.xml");
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java
new file mode 100644
index 0000000..53151bb
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ConfigGetter;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.netconf.NetconfController;
+import org.slf4j.Logger;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Used with the onos:device-configuration CLI command.
+ *
+ * This allows the full configuration to be retrieved from the device
+ */
+public class NetconfConfigGetter extends AbstractHandlerBehaviour implements ConfigGetter {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    private PacketProcessor testProcessor;
+
+    // FIXME the error string should be universal for all implementations of
+    // ConfigGetter
+    public static final String UNABLE_TO_READ_CONFIG = "config retrieval error";
+
+    @Override
+    public String getConfiguration(String type) {
+        DriverHandler handler = handler();
+        NetconfController controller = handler.get(NetconfController.class);
+
+        DeviceId ofDeviceId = handler.data().deviceId();
+        Preconditions.checkNotNull(controller, "Netconf controller is null");
+        if (type == null ||
+                (!type.equalsIgnoreCase("running")
+                        && !type.equalsIgnoreCase("candidate")
+                        && !type.equalsIgnoreCase("startup"))) {
+            log.error("Configuration type must be either 'running', 'startup' or 'candidate'. '{}' is invalid", type);
+            return UNABLE_TO_READ_CONFIG;
+        }
+        try {
+            return controller.getDevicesMap().get(ofDeviceId).getSession().getConfig(type.replace("cfgType=", ""));
+        } catch (IOException e) {
+            log.error("Configuration could not be retrieved {}", e.getMessage());
+        }
+        return UNABLE_TO_READ_CONFIG;
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java
new file mode 100644
index 0000000..7589ea7
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+public final class RpcResultParser {
+
+    private RpcResultParser() {
+        //Not called
+    }
+
+    public static String parseXml(final String deviceDescriptionResponse, final String keyWord) {
+
+        int end = deviceDescriptionResponse.lastIndexOf(keyWord);
+        end = deviceDescriptionResponse.lastIndexOf('<', end);
+        int start = deviceDescriptionResponse.lastIndexOf('>', end);
+        if (start > 1 && end > start) {
+            return deviceDescriptionResponse.substring(start + 1, end);
+        } else {
+            return null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/package-info.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/package-info.java
new file mode 100644
index 0000000..de883d1
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Microsemi device drivers.
+ */
+package org.onosproject.drivers.microsemi;
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/IetfSystemNetconfService.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/IetfSystemNetconfService.java
new file mode 100644
index 0000000..44c62f6
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/IetfSystemNetconfService.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang;
+
+import java.time.OffsetDateTime;
+
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.doupgradeandreboot.DoUpgradeAndRebootInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.doupgradeandreboot.DoUpgradeAndRebootOutput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.pullupdatetarfromtftp.PullUpdateTarFromTftpInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.readfromsyslog.ReadFromSyslogInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.readfromsyslog.ReadFromSyslogOutput;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystem;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystemOpParam;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.ietfsystem.systemrestart.SystemRestartInput;
+
+/**
+ * Extension of ietfSystemService to include NETCONF sessions.
+ *
+ * This is manually extended and should be revised if the ietf-system.yang file changes
+ */
+public interface IetfSystemNetconfService {
+    /**
+     * Returns the attribute ietfSystem.
+     *
+     * @param ietfSystem value of ietfSystem
+     * @param session An active NETCONF session
+     * @return ietfSystem
+     * @throws NetconfException if the session has any error
+     */
+    IetfSystem getIetfSystem(IetfSystemOpParam ietfSystem, NetconfSession session) throws NetconfException;
+
+    /**
+     * Returns the result of the init query.
+     *
+     * @param session An active NETCONF session
+     * @return ietfSystem
+     * @throws NetconfException if the session has any error
+     */
+    IetfSystem getIetfSystemInit(NetconfSession session) throws NetconfException;
+
+    /**
+     * Sets the value to attribute ietfSystem.
+     *
+     * @param ietfSystem value of ietfSystem
+     * @param session An active NETCONF session
+     * @param ncDs datastore type running, startup or candidate
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean setIetfSystem(IetfSystemOpParam ietfSystem, NetconfSession session,
+          DatastoreId ncDs) throws NetconfException;
+
+    /**
+     * Service interface of setCurrentDatetime.
+     *
+     * @param date input of service interface setCurrentDatetime
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void setCurrentDatetime(OffsetDateTime date, NetconfSession session) throws NetconfException;
+
+    /**
+     * Service interface of systemRestart.
+     *
+     * @param inputVar input of service interface systemRestart
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void systemRestart(SystemRestartInput inputVar, NetconfSession session) throws NetconfException;
+
+    /**
+     * Service interface of systemShutdown.
+     *
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void systemShutdown(NetconfSession session) throws NetconfException;
+
+    /**
+     * Service interface of doUpgradeAndReboot.
+     *
+     * @param inputVar input of service interface doUpgradeAndReboot
+     * @param session An active NETCONF session
+     * @return doUpgradeAndRebootOutput output of service interface doUpgradeAndReboot
+     * @throws NetconfException if the session has any error
+     */
+    DoUpgradeAndRebootOutput doUpgradeAndReboot(DoUpgradeAndRebootInput inputVar, NetconfSession session)
+            throws NetconfException;
+
+    /**
+     * Service interface of pullUpdateTarFromTftp.
+     *
+     * @param inputVar input of service interface pullUpdateTarFromTftp
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void pullUpdateTarFromTftp(PullUpdateTarFromTftpInput inputVar, NetconfSession session)
+            throws NetconfException;
+
+    /**
+     * Service interface of readFromSyslog.
+     *
+     * @param inputVar input of service interface readFromSyslog
+     * @param session An active NETCONF session
+     * @return readFromSyslogOutput output of service interface readFromSyslog
+     * @throws NetconfException if the session has any error
+     */
+    ReadFromSyslogOutput readFromSyslog(ReadFromSyslogInput inputVar, NetconfSession session)
+            throws NetconfException;
+
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MicrosemiModelRegistrator.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MicrosemiModelRegistrator.java
new file mode 100644
index 0000000..6cf8031
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MicrosemiModelRegistrator.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.yang.AbstractYangModelRegistrator;
+import org.onosproject.yang.gen.v1.entitystatetcmib.rev20051122.EntityStateTcMib;
+import org.onosproject.yang.gen.v1.fpgainternal.rev20151130.FpgaInternal;
+import org.onosproject.yang.gen.v1.ianacrypthash.rev20140806.IanaCryptHash;
+import org.onosproject.yang.gen.v1.ianaiftype.rev20140508.IanaIfType;
+import org.onosproject.yang.gen.v1.ieeetypes.rev20080522.IeeeTypes;
+import org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.IetfInetTypes;
+import org.onosproject.yang.gen.v1.ietfinterfaces.rev20140508.IetfInterfaces;
+import org.onosproject.yang.gen.v1.ietfnetconf.rev20110601.IetfNetconf;
+import org.onosproject.yang.gen.v1.ietfnetconfacm.rev20120222.IetfNetconfAcm;
+import org.onosproject.yang.gen.v1.ietfnetconfmonitoring.rev20101004.IetfNetconfMonitoring;
+import org.onosproject.yang.gen.v1.ietfnetconfnotifications.rev20120206.IetfNetconfNotifications;
+import org.onosproject.yang.gen.v1.ietfnetconfwithdefaults.rev20100609.IetfNetconfWithDefaults;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystem;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.IetfSystemMicrosemi;
+import org.onosproject.yang.gen.v1.ietfsystemtlsauth.rev20140524.IetfSystemTlsAuth;
+import org.onosproject.yang.gen.v1.ietfx509certtoname.rev20130326.IetfX509CertToName;
+import org.onosproject.yang.gen.v1.ietfyangtypes.rev20130715.IetfYangTypes;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.MseaCfm;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.mseasoamfm.rev20160229.MseaSoamFm;
+import org.onosproject.yang.gen.v1.mseasoampm.rev20160229.MseaSoamPm;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.MseaTypes;
+import org.onosproject.yang.gen.v1.mseaunievcinterface.rev20160317.MseaUniEvcInterface;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.ncnotifications.rev20080714.NcNotifications;
+import org.onosproject.yang.gen.v1.netopeercfgnetopeer.rev20130214.NetopeerCfgnetopeer;
+import org.onosproject.yang.gen.v1.notifications.rev20080714.Notifications;
+import org.onosproject.yang.gen.v1.rfc2544.rev20151020.Rfc2544;
+import org.onosproject.yang.gen.v1.svcactivationtypes.rev20151027.SvcActivationTypes;
+import org.onosproject.yang.gen.v1.y1564.rev20151029.Y1564;
+import org.onosproject.yang.model.DefaultYangModuleId;
+import org.onosproject.yang.model.YangModuleId;
+import org.onosproject.yang.runtime.AppModuleInfo;
+import org.onosproject.yang.runtime.DefaultAppModuleInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Representation of Microsemi model registrator which registers Microsemi device
+ * models.
+ */
+@Component(immediate = true)
+public class MicrosemiModelRegistrator extends AbstractYangModelRegistrator {
+
+    public MicrosemiModelRegistrator() {
+        super(IetfSystem.class, getAppInfo());
+    }
+
+    private static Map<YangModuleId, AppModuleInfo> getAppInfo() {
+        Map<YangModuleId, AppModuleInfo> appInfo = new HashMap<>();
+
+        appInfo.put(new DefaultYangModuleId("fpga-internal", "2015-11-30"),
+                new DefaultAppModuleInfo(FpgaInternal.class, null));
+        appInfo.put(new DefaultYangModuleId("iana-if-type", "2014-05-08"),
+                new DefaultAppModuleInfo(IanaIfType.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-yang-types", "2013-07-15"),
+                new DefaultAppModuleInfo(IetfYangTypes.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-sa-filtering", "2016-04-12"),
+                new DefaultAppModuleInfo(MseaSaFiltering.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-x509-cert-to-name", "2013-03-26"),
+                new DefaultAppModuleInfo(IetfX509CertToName.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-system", "2014-08-06"),
+                new DefaultAppModuleInfo(IetfSystem.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-types", "2016-02-29"),
+                new DefaultAppModuleInfo(MseaTypes.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-inet-types", "2013-07-15"),
+                new DefaultAppModuleInfo(IetfInetTypes.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-netconf-with-defaults", "2010-06-09"),
+                new DefaultAppModuleInfo(IetfNetconfWithDefaults.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-uni-evc-service", "2016-03-17"),
+                new DefaultAppModuleInfo(MseaUniEvcService.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-netconf-monitoring", "2010-10-04"),
+                new DefaultAppModuleInfo(IetfNetconfMonitoring.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-netconf-acm", "2012-02-22"),
+                new DefaultAppModuleInfo(IetfNetconfAcm.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-system-tls-auth", "2014-05-24"),
+                new DefaultAppModuleInfo(IetfSystemTlsAuth.class, null));
+        appInfo.put(new DefaultYangModuleId("rfc-2544", "2015-10-20"),
+                new DefaultAppModuleInfo(Rfc2544.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-cfm", "2016-02-29"),
+                new DefaultAppModuleInfo(MseaCfm.class, null));
+        appInfo.put(new DefaultYangModuleId("netopeer-cfgnetopeer", "2013-02-14"),
+                new DefaultAppModuleInfo(NetopeerCfgnetopeer.class, null));
+        appInfo.put(new DefaultYangModuleId("ENTITY-STATE-TC-MIB", "2005-11-22"),
+                new DefaultAppModuleInfo(EntityStateTcMib.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-soam-fm", "2016-02-29"),
+                new DefaultAppModuleInfo(MseaSoamFm.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-netconf-notifications", "2012-02-06"),
+                new DefaultAppModuleInfo(IetfNetconfNotifications.class, null));
+        appInfo.put(new DefaultYangModuleId("nc-notifications", "2008-07-14"),
+                new DefaultAppModuleInfo(NcNotifications.class, null));
+        appInfo.put(new DefaultYangModuleId("iana-crypt-hash", "2014-08-06"),
+                new DefaultAppModuleInfo(IanaCryptHash.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-uni-evc-interface", "2016-03-17"),
+                new DefaultAppModuleInfo(MseaUniEvcInterface.class, null));
+        appInfo.put(new DefaultYangModuleId("msea-soam-pm", "2016-02-29"),
+                new DefaultAppModuleInfo(MseaSoamPm.class, null));
+        appInfo.put(new DefaultYangModuleId("ieee-types", "2008-05-22"),
+                new DefaultAppModuleInfo(IeeeTypes.class, null));
+        appInfo.put(new DefaultYangModuleId("svc-activation-types", "2015-10-27"),
+                new DefaultAppModuleInfo(SvcActivationTypes.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-netconf", "2011-06-01"),
+                new DefaultAppModuleInfo(IetfNetconf.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-system-microsemi", "2016-05-05"),
+                new DefaultAppModuleInfo(IetfSystemMicrosemi.class, null));
+        appInfo.put(new DefaultYangModuleId("notifications", "2008-07-14"),
+                new DefaultAppModuleInfo(Notifications.class, null));
+        appInfo.put(new DefaultYangModuleId("y-1564", "2015-10-29"),
+                new DefaultAppModuleInfo(Y1564.class, null));
+        appInfo.put(new DefaultYangModuleId("ietf-interfaces", "2014-05-08"),
+                new DefaultAppModuleInfo(IetfInterfaces.class, null));
+        return ImmutableMap.copyOf(appInfo);
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaCfmNetconfService.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaCfmNetconfService.java
new file mode 100644
index 0000000..cdd3700
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaCfmNetconfService.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang;
+
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.MseaCfm;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.MseaCfmOpParam;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.abortloopback.AbortLoopbackInput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitlinktrace.TransmitLinktraceInput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitlinktrace.TransmitLinktraceOutput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitloopback.TransmitLoopbackInput;
+
+/**
+ * Extension of mseaCfmService to include NETCONF sessions.
+ *
+ * This is manually extended and should be revised if the msea-cfm.yang,
+ * msea-soam-pm.yang or msea-soam-fm.yang files change
+ */
+public interface MseaCfmNetconfService {
+
+    /**
+     * Returns attributes of MEP.
+     *
+     * @param mdName The name of the MD
+     * @param maName The name of the MA
+     * @param mepId The ID of the MEP
+     * @param session An active NETCONF session
+     * @return mseaCfm
+     * @throws NetconfException if the session has any error
+     */
+    MseaCfm getMepEssentials(String mdName, String maName, int mepId,
+            NetconfSession session) throws NetconfException;
+
+
+    /**
+     * Returns attributes of DM.
+     *
+     * @param mdName The name of the MD
+     * @param maName The name of the MA
+     * @param mepId The ID of the MEP
+     * @param dmId The Id of the Delay Measurement
+     * @param session An active NETCONF session
+     * @return mseaCfm
+     * @throws NetconfException if the session has any error
+     */
+    MseaCfm getSoamDm(String mdName, String maName, int mepId,
+            int dmId, NetconfSession session) throws NetconfException;
+
+    /**
+     * Sets the value to attribute mseaCfm.
+     *
+     * @param mseaCfm value of mseaCfm
+     * @param session An active NETCONF session
+     * @param targetDs one of running, candidate or startup
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean setMseaCfm(MseaCfmOpParam mseaCfm, NetconfSession session,
+                       DatastoreId targetDs) throws NetconfException;
+
+    /**
+     * Service interface of transmitLoopback.
+     *
+     * @param inputVar input of service interface transmitLoopback
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void transmitLoopback(TransmitLoopbackInput inputVar,
+                          NetconfSession session) throws NetconfException;
+
+    /**
+     * Service interface of abortLoopback.
+     *
+     * @param inputVar input of service interface abortLoopback
+     * @param session An active NETCONF session
+     * @throws NetconfException if the session has any error
+     */
+    void abortLoopback(AbortLoopbackInput inputVar,
+                       NetconfSession session) throws NetconfException;
+
+    /**
+     * Service interface of transmitLinktrace.
+     *
+     * @param inputVar input of service interface transmitLinktrace
+     * @param session An active NETCONF session
+     * @return transmitLinktraceOutput output of service interface transmitLinktrace
+     * @throws NetconfException if the session has any error
+     */
+    TransmitLinktraceOutput transmitLinktrace(TransmitLinktraceInput inputVar,
+              NetconfSession session) throws NetconfException;
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaSaFilteringNetconfService.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaSaFilteringNetconfService.java
new file mode 100644
index 0000000..f9788f3
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaSaFilteringNetconfService.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi.yang;
+
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFilteringOpParam;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
+
+import java.util.List;
+
+/**
+ * Extension of mseaSaFilteringService to include NETCONF sessions.
+ *
+ * This is manually extended and should be revised if the msea-sa-filtering.yang file changes
+ */
+public interface MseaSaFilteringNetconfService {
+    /**
+     * Returns the attribute mseaSaFiltering.
+     *
+     * @param mseaSaFiltering value of mseaSaFiltering
+     * @param session  An active NETCONF session
+     * @return mseaSaFiltering
+     * @throws NetconfException if the session has any error
+     */
+    MseaSaFiltering getMseaSaFiltering(
+            MseaSaFilteringOpParam mseaSaFiltering, final NetconfSession session)
+            throws NetconfException;
+
+    /**
+     * Get a filtered subset of the config model.
+     *
+     * @param session  An active NETCONF session
+     * @return mseaSaFiltering
+     * @throws NetconfException if the session has any error
+     */
+    public List<SourceAddressRange> getConfigMseaSaFilterIds(NetconfSession session)
+            throws NetconfException;
+
+    /**
+     * Sets the value to attribute mseaSaFiltering.
+     *
+     * @param mseaSaFiltering value of mseaSaFiltering
+     * @param session An active NETCONF session
+     * @param targetDs The NETCONF datastore to edit
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean setMseaSaFiltering(MseaSaFilteringOpParam mseaSaFiltering,
+            NetconfSession session, DatastoreId targetDs) throws NetconfException;
+
+    /**
+     * Deletes the value to attribute mseaSaFiltering.
+     *
+     * @param mseaSaFiltering value of mseaSaFiltering
+     * @param session An active NETCONF session
+     * @param targetDs The NETCONF datastore to edit
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean deleteMseaSaFilteringRange(MseaSaFilteringOpParam mseaSaFiltering,
+              NetconfSession session, DatastoreId targetDs) throws NetconfException;
+
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaUniEvcServiceNetconfService.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaUniEvcServiceNetconfService.java
new file mode 100644
index 0000000..a7f85bf
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/MseaUniEvcServiceNetconfService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi.yang;
+
+import java.util.List;
+import java.util.Map;
+
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
+
+/**
+ * Extension of mseaUniEvcServiceService to include NETCONF sessions.
+ *
+ * This is manually extended and should be revised if the msea-uni-evc-service.yang
+ * file changes
+ */
+public interface MseaUniEvcServiceNetconfService {
+    /**
+     * Returns the configuration and state attributes of the running mseaUniEvcService.
+     *
+     * @param mseaUniEvcService value of mseaUniEvcService
+     * @param session The NETCONF session
+     * @return mseaUniEvcService
+     * @throws NetconfException if the session has any error
+     */
+    MseaUniEvcService getMseaUniEvcService(
+            MseaUniEvcServiceOpParam mseaUniEvcService, NetconfSession session)
+            throws NetconfException;
+
+    /**
+     * Returns the configuration only attributes of mseaUniEvcService.
+     *
+     * @param mseaUniEvcService value of mseaUniEvcService
+     * @param session The NETCONF session
+     * @param targetDs one of running, candidate or startup
+     * @return mseaUniEvcService
+     * @throws NetconfException if the session has any error
+     */
+    MseaUniEvcService getConfigMseaUniEvcService(
+            MseaUniEvcServiceOpParam mseaUniEvcService, NetconfSession session,
+            DatastoreId targetDs) throws NetconfException;
+
+    /**
+     * Sets the value to attribute mseaUniEvcService.
+     *
+     * @param mseaUniEvcService value of mseaUniEvcService
+     * @param session The NETCONF session
+     * @param targetDs one of running, candidate or startup
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean setMseaUniEvcService(MseaUniEvcServiceOpParam mseaUniEvcService,
+            NetconfSession session, DatastoreId targetDs)
+            throws NetconfException;
+
+    /**
+     * Deletes the objects in mseaUniEvcService.
+     *
+     * @param mseaUniEvcService value of mseaUniEvcService
+     * @param session The NETCONF session
+     * @param targetDs one of running, candidate or startup
+     * @return Boolean to indicate success or failure
+     * @throws NetconfException if the session has any error
+     */
+    boolean deleteMseaUniEvcService(MseaUniEvcServiceOpParam mseaUniEvcService,
+             NetconfSession session, DatastoreId targetDs) throws NetconfException;
+
+    /**
+     * Returns a list of the CeVlanMaps on both sides of the EVC.
+     *
+     * @param session A NETCONF Session
+     * @param ncDs The datastore to affect - running, candidate or startup
+     * @return The Object Model with the VLans
+     * @throws NetconfException if the session has any error
+     */
+    MseaUniEvcService getmseaUniEvcCeVlanMaps(
+            NetconfSession session, DatastoreId ncDs)
+            throws NetconfException;
+
+    /**
+     * Replace ceVlans or delete EVCs from a device.
+     *
+     * It is necessary to have a custom command for this as the YCH cannot
+     * handle the intricacies of putting a replace operation on the
+     * ceVlanMap leaf at present
+     *
+     * @param ceVlanUpdates A Map of CeVlanMap entries to change, as flows are deleted
+     * @param flowVlanIds The IDs of flows that are being removed
+     * @param session A NETCONF Session
+     * @param targetDs The datastore to affect - running, candidate or startup
+     * @param portAssign The port assignment of the device
+     * @throws NetconfException if the session has any error
+     */
+    void removeEvcUniFlowEntries(
+            Map<Integer, String> ceVlanUpdates,
+            Map<Integer, List<Short>> flowVlanIds,
+            NetconfSession session,
+            DatastoreId targetDs,
+            UniSideInterfaceAssignmentEnum portAssign)
+                    throws NetconfException;
+
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/UniSide.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/UniSide.java
new file mode 100644
index 0000000..8ced81c
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/UniSide.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang;
+
+/**
+ * An enumeration to describe the side of a UNI - Customer or Network.
+ * For reference see MEF 6.2
+ */
+public enum UniSide {
+    CUSTOMER,
+    NETWORK
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnic.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnic.java
new file mode 100644
index 0000000..fbf89be
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnic.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.custom;
+
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.ServiceListType;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.EvcPerUniServiceTypeEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.DefaultEvcPerUnic;
+
+import java.util.List;
+
+/**
+ * Extend the DefaultEvcPerUnic so that the ceVlanMap can always be initialized at 0.
+ */
+public class CustomEvcPerUnic extends DefaultEvcPerUnic {
+    @Override
+    public ServiceListType ceVlanMap() {
+        if (ceVlanMap == null) {
+            return new ServiceListType("0");
+        }
+        return ceVlanMap;
+    }
+    @Override
+    public Object ingressBwpGroupIndex() {
+        return ingressBwpGroupIndex;
+    }
+
+    @Override
+    public EvcPerUniServiceTypeEnum evcPerUniServiceType() {
+        return evcPerUniServiceType;
+    }
+
+    @Override
+    public TagManipulation tagManipulation() {
+        return tagManipulation;
+    }
+
+    @Override
+    public List<FlowMapping> flowMapping() {
+        return flowMapping;
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnin.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnin.java
new file mode 100644
index 0000000..d8712dc
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/CustomEvcPerUnin.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.custom;
+
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.ServiceListType;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.EvcPerUniServiceTypeEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.DefaultEvcPerUnin;
+
+import java.util.List;
+
+/**
+ * Extend the DefaultEvcPerUnin so that the ceVlanMap can always be initialized at 0.
+ */
+public class CustomEvcPerUnin extends DefaultEvcPerUnin {
+    @Override
+    public ServiceListType ceVlanMap() {
+        if (ceVlanMap == null) {
+            return new ServiceListType("0");
+        }
+        return ceVlanMap;
+    }
+    @Override
+    public Object ingressBwpGroupIndex() {
+        return ingressBwpGroupIndex;
+    }
+
+    @Override
+    public EvcPerUniServiceTypeEnum evcPerUniServiceType() {
+        return evcPerUniServiceType;
+    }
+
+    @Override
+    public TagManipulation tagManipulation() {
+        return tagManipulation;
+    }
+
+    @Override
+    public List<FlowMapping> flowMapping() {
+        return flowMapping;
+    }
+
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/package-info.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/package-info.java
new file mode 100644
index 0000000..1a7a471
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/custom/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Microsemi device drivers support for NETCONF for EA1000.
+ */
+package org.onosproject.drivers.microsemi.yang.custom;
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/AbstractYangServiceImpl.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/AbstractYangServiceImpl.java
new file mode 100644
index 0000000..3867a2f
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/AbstractYangServiceImpl.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.ByteSource;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaContext;
+import org.onosproject.yang.model.SchemaContextProvider;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.CompositeStream;
+import org.onosproject.yang.runtime.DefaultCompositeData;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+import org.onosproject.yang.runtime.DefaultYangSerializerContext;
+import org.onosproject.yang.runtime.YangModelRegistry;
+import org.onosproject.yang.runtime.YangSerializer;
+import org.onosproject.yang.runtime.YangSerializerContext;
+import org.onosproject.yang.runtime.YangSerializerRegistry;
+import org.onosproject.yang.serializers.xml.XmlSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class that implements some of the core functions of a YANG model service.
+ *
+ */
+@Component(immediate = true)
+@Service
+public abstract class AbstractYangServiceImpl {
+    public static final String NC_OPERATION = "nc:operation";
+    public static final String OP_DELETE = "delete";
+
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected boolean alreadyLoaded = false;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected YangModelRegistry yangModelRegistry;
+
+//    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+//    protected SchemaContextProvider schemaContextProvider;
+
+    protected ApplicationId appId;
+
+    // xSer is not a service and is a class variable. Can be lost on deactivate.
+    // Must be recreated on activate
+    protected XmlSerializer xSer;
+    protected YangSerializerContext yCtx;
+
+    protected static final Pattern REGEX_XML_HEADER =
+            Pattern.compile("(<\\?xml).*(\\?>)", Pattern.DOTALL);
+    protected static final Pattern REGEX_RPC_REPLY =
+            Pattern.compile("(<rpc-reply)[ ]*" +
+                    "(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\")[ ]*" +
+                    "(message-id=\")[0-9]*(\">)", Pattern.DOTALL);
+    protected static final Pattern REGEX_RPC_REPLY_DATA_NS =
+            Pattern.compile("(<data)[ ]*(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)");
+    protected static final Pattern REGEX_RPC_REPLY_DATA =
+            Pattern.compile("(<data>)");
+    protected static final Pattern REGEX_RPC_REPLY_DATA_CLOSE =
+            Pattern.compile("(</data>)");
+    protected static final Pattern REGEX_RPC_REPLY_DATA_EMPTY =
+            Pattern.compile("(<data/>)");
+    protected static final Pattern REGEX_RPC_REPLY_CLOSE =
+            Pattern.compile("(</rpc-reply>)");
+
+    @Activate
+    public void activate() {
+        Set<YangSerializer> yangSer = ((YangSerializerRegistry) yangModelRegistry).getSerializers();
+        yangSer.forEach(ser -> {
+            if (ser instanceof XmlSerializer) {
+                xSer = (XmlSerializer) ser;
+            }
+        });
+        SchemaContext context = ((SchemaContextProvider) yangModelRegistry)
+                .getSchemaContext(ResourceId.builder().addBranchPointSchema("/", null).build());
+
+        yCtx = new DefaultYangSerializerContext(context, null);
+    };
+
+    @Deactivate
+    public void deactivate() {
+        alreadyLoaded = false;
+    }
+
+    /**
+     * Internal method to generically make a NETCONF get query from YANG objects.
+     * @param moFilter A YANG object model
+     * @param session A NETCONF session
+     * @return YangObjectModel
+     * @throws NetconfException if the session has any error
+     */
+    protected final ModelObjectData getNetconfObject(
+            ModelObjectData moFilter, NetconfSession session)
+                throws NetconfException {
+
+        return getConfigNetconfObject(moFilter, session, null);
+    }
+
+    /**
+     * Internal method to generically make a NETCONF get-config query from YANG objects.
+     *
+     * @param moFilter A YANG object model
+     * @param session A NETCONF session
+     * @param targetDs - running,candidate or startup
+     * @return YangObjectModel
+     * @throws NetconfException if the session has any error
+     */
+    protected final ModelObjectData getConfigNetconfObject(
+            ModelObjectData moFilter, NetconfSession session, DatastoreId targetDs)
+                throws NetconfException {
+        if (session == null) {
+            throw new NetconfException("Session is null when calling getConfigNetconfObject()");
+        }
+
+        if (moFilter == null) {
+            throw new NetconfException("Query object cannot be null");
+        }
+
+        String xmlQueryStr = encodeMoToXmlStr(moFilter, null);
+
+        log.debug("Sending <get-(config)> query on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlQueryStr);
+        String xmlResult;
+        if (targetDs == null) {
+            xmlResult = session.get(xmlQueryStr, null);
+        } else {
+            xmlResult = session.getConfig(targetDs, xmlQueryStr);
+        }
+        xmlResult = removeRpcReplyData(xmlResult);
+
+        DefaultCompositeStream resultDcs = new DefaultCompositeStream(
+                null, new ByteArrayInputStream(xmlResult.getBytes()));
+        CompositeData compositeData = xSer.decode(resultDcs, yCtx);
+
+        return ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
+    }
+
+    /**
+     * Internal method to generically make a NETCONF edit-config call from a set of YANG objects.
+     *
+     * @param moConfig A YANG object model
+     * @param session A NETCONF session
+     * @param targetDs - running,candidate or startup
+     * @param annotations A list of AnnotatedNodeInfos to be added to the DataNodes
+     * @return Boolean value indicating success or failure of command
+     * @throws NetconfException if the session has any error
+     */
+    protected final boolean setNetconfObject(
+            ModelObjectData moConfig, NetconfSession session, DatastoreId targetDs,
+            List<AnnotatedNodeInfo> annotations) throws NetconfException {
+        if (moConfig == null) {
+            throw new NetconfException("Query object cannot be null");
+        } else if (session == null) {
+            throw new NetconfException("Session is null when calling getMseaSaFiltering()");
+        } else if (targetDs == null) {
+            throw new NetconfException("TargetDs is null when calling getMseaSaFiltering()");
+        }
+
+        String xmlQueryStr = encodeMoToXmlStr(moConfig, annotations);
+        log.debug("Sending <edit-config> query on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlQueryStr);
+
+        return session.editConfig(targetDs, null, xmlQueryStr);
+    }
+
+    protected final String encodeMoToXmlStr(ModelObjectData yangObjectOpParamFilter,
+                                            List<AnnotatedNodeInfo> annotations)
+            throws NetconfException {
+        //Convert the param to XML to use as a filter
+        ResourceData rd = ((ModelConverter) yangModelRegistry).createDataNode(yangObjectOpParamFilter);
+
+        DefaultCompositeData.Builder cdBuilder =
+                        DefaultCompositeData.builder().resourceData(rd);
+        if (annotations != null) {
+            for (AnnotatedNodeInfo ani : annotations) {
+                cdBuilder.addAnnotatedNodeInfo(ani);
+            }
+        }
+        CompositeStream cs = xSer.encode(cdBuilder.build(), yCtx);
+        //Convert the param to XML to use as a filter
+
+        try {
+            ByteSource byteSource = new ByteSource() {
+                @Override
+                public InputStream openStream() throws IOException {
+                    return cs.resourceData();
+                }
+            };
+
+            return byteSource.asCharSource(Charsets.UTF_8).read();
+        } catch (IOException e) {
+            throw new NetconfException("Error decoding CompositeStream to String", e);
+        }
+    }
+
+    protected static final String removeRpcReplyData(String rpcReplyXml) {
+        rpcReplyXml = REGEX_XML_HEADER.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY_DATA_NS.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY_DATA.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY_DATA_CLOSE.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY_DATA_EMPTY.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = REGEX_RPC_REPLY_CLOSE.matcher(rpcReplyXml).replaceFirst("");
+        rpcReplyXml = rpcReplyXml.replace("\t", "");
+        return rpcReplyXml;
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/IetfSystemManager.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/IetfSystemManager.java
new file mode 100644
index 0000000..3673594
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/IetfSystemManager.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
+
+import java.io.ByteArrayInputStream;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.drivers.microsemi.yang.IetfSystemNetconfService;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.ietfsystem.DefaultSystem;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.ietfsystem.DefaultSystemState;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.doupgradeandreboot.DoUpgradeAndRebootInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.doupgradeandreboot.DoUpgradeAndRebootOutput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.pullupdatetarfromtftp.PullUpdateTarFromTftpInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.readfromsyslog.ReadFromSyslogInput;
+import org.onosproject.yang.gen.v1.ietfsystemmicrosemi.rev20160505.ietfsystemmicrosemi.readfromsyslog.ReadFromSyslogOutput;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystem;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.IetfSystemOpParam;
+import org.onosproject.yang.gen.v1.ietfsystem.rev20140806.ietfsystem.systemrestart.SystemRestartInput;
+import org.onosproject.yang.model.DefaultModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+
+/**
+ * Implementation of the IetfService YANG model service.
+ */
+@Component(immediate = true, inherit = true)
+@Service
+public class IetfSystemManager extends AbstractYangServiceImpl
+    implements IetfSystemNetconfService {
+
+    protected static final String IETF_SYSTEM = "org.onosproject.drivers.microsemi.yang.ietfsystem";
+
+    @Activate
+    public void activate() {
+        super.activate();
+        appId = coreService.registerApplication(IETF_SYSTEM);
+        log.info("IetfSystemManager Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        super.deactivate();
+        log.info("IetfSystemManager Stopped");
+    }
+
+    /**
+     * Get a filtered subset of the model.
+     * This is meant to filter the current live model
+     * against the attribute(s) given in the argument
+     * and return the filtered model.
+     * @throws NetconfException if the session has any error
+     */
+    @Override
+    public IetfSystem getIetfSystem(IetfSystemOpParam ietfSystemFilter, NetconfSession session)
+            throws NetconfException {
+
+        ModelObjectData moQuery = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) ietfSystemFilter.system())
+                .build();
+
+        ModelObjectData moReply = getNetconfObject(moQuery, session);
+
+        IetfSystemOpParam ietfSystem = new IetfSystemOpParam();
+        for (ModelObject mo:moReply.modelObjects()) {
+            if (mo instanceof DefaultSystem) {
+                ietfSystem.system((DefaultSystem) mo);
+            } else if (mo instanceof DefaultSystemState) {
+                ietfSystem.systemState((DefaultSystemState) mo);
+            }
+        }
+
+        return ietfSystem;
+    }
+
+    @Override
+    public IetfSystem getIetfSystemInit(NetconfSession session) throws NetconfException {
+        if (session == null) {
+            throw new NetconfException("Session is null when calling getIetfSystemInit()");
+        }
+
+        String xmlResult = session.get(getInitRequestBuilder(), null);
+
+        xmlResult = removeRpcReplyData(xmlResult);
+        DefaultCompositeStream resultDcs = new DefaultCompositeStream(
+                null, new ByteArrayInputStream(xmlResult.getBytes()));
+        CompositeData compositeData = xSer.decode(resultDcs, yCtx);
+
+        ModelObjectData mod = ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
+
+        IetfSystemOpParam ietfSystem = new IetfSystemOpParam();
+        for (ModelObject mo:mod.modelObjects()) {
+            if (mo instanceof DefaultSystem) {
+                ietfSystem.system((DefaultSystem) mo);
+            } else if (mo instanceof DefaultSystemState) {
+                ietfSystem.systemState((DefaultSystemState) mo);
+            }
+        }
+
+        return ietfSystem;
+    }
+
+    /**
+     * Call NETCONF edit-config with a configuration.
+     */
+    @Override
+    public boolean setIetfSystem(IetfSystemOpParam ietfSystem, NetconfSession session,
+                              DatastoreId ncDs) throws NetconfException {
+        ModelObjectData mo = DefaultModelObjectData.builder()
+                                .addModelObject(ietfSystem).build();
+        return setNetconfObject(mo, session, ncDs, null);
+    }
+
+    @Override
+    public void setCurrentDatetime(OffsetDateTime date, NetconfSession session)
+            throws NetconfException {
+        String xmlQueryStr = getSetCurrentDatetimeBuilder(date);
+        log.info("Sending <get> query on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlQueryStr);
+
+        String xmlResult = session.doWrappedRpc(xmlQueryStr);
+        log.info("Result from NETCONF RPC <set-current-datetime>: {}", xmlResult);
+    }
+
+    @Override
+    public void systemRestart(SystemRestartInput inputVar, NetconfSession session) {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public void systemShutdown(NetconfSession session) {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public DoUpgradeAndRebootOutput doUpgradeAndReboot(DoUpgradeAndRebootInput inputVar, NetconfSession session)
+            throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public void pullUpdateTarFromTftp(PullUpdateTarFromTftpInput inputVar, NetconfSession session)
+            throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public ReadFromSyslogOutput readFromSyslog(ReadFromSyslogInput inputVar, NetconfSession session)
+            throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+
+    /**
+     * Builds a request crafted to get the configuration required to create
+     * details descriptions for the device.
+     *
+     * @return The request string.
+     */
+    private static String getInitRequestBuilder() {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append("<system-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-system\" ");
+        rpc.append("xmlns:sysms=\"http://www.microsemi.com/microsemi-edge-assure/msea-system\">");
+        rpc.append("<platform>");
+        rpc.append("<os-release/>");
+        rpc.append("<sysms:device-identification>");
+        rpc.append("<sysms:serial-number/>");
+        rpc.append("</sysms:device-identification>");
+        rpc.append("</platform>");
+        rpc.append("<clock>");
+        rpc.append("<current-datetime/>");
+        rpc.append("</clock>");
+        rpc.append("</system-state>");
+        rpc.append("<system xmlns=\"urn:ietf:params:xml:ns:yang:ietf-system\" ");
+        rpc.append("xmlns:sysms=\"http://www.microsemi.com/microsemi-edge-assure/msea-system\">");
+        rpc.append("<sysms:longitude/>");
+        rpc.append("<sysms:latitude/>");
+        rpc.append("</system>");
+        return rpc.toString();
+    }
+
+    private static String getSetCurrentDatetimeBuilder(OffsetDateTime date) {
+        StringBuilder rpc = new StringBuilder();
+        rpc.append("<set-current-datetime xmlns=\"urn:ietf:params:xml:ns:yang:ietf-system\">");
+        rpc.append("<current-datetime>");
+        rpc.append(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")));
+        rpc.append("</current-datetime>");
+        rpc.append("</set-current-datetime>");
+
+        return rpc.toString();
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaCfmManager.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaCfmManager.java
new file mode 100644
index 0000000..36f48c4
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaCfmManager.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.drivers.microsemi.yang.MseaCfmNetconfService;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.MseaCfm;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.MseaCfmOpParam;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.DefaultMefCfm;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.abortloopback.AbortLoopbackInput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitlinktrace.TransmitLinktraceInput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitlinktrace.TransmitLinktraceOutput;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitloopback.TransmitLoopbackInput;
+import org.onosproject.yang.model.DefaultModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+
+import java.io.ByteArrayInputStream;
+
+/**
+ * Implementation of the MseaCfmServiceNetconf YANG model service.
+ */
+@Component(immediate = true, inherit = true)
+@Service
+public class MseaCfmManager extends AbstractYangServiceImpl
+    implements MseaCfmNetconfService {
+
+    public static final String MSEA_CFM = "org.onosproject.drivers.microsemi.yang.mseacfmservice";
+
+    @Activate
+    public void activate() {
+        super.activate();
+        appId = coreService.registerApplication(MSEA_CFM);
+        log.info("MseaCfmService Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        super.deactivate();
+        log.info("MseaCfmService Stopped");
+    }
+
+    @Override
+    public MseaCfm getMepEssentials(String mdName, String maName, int mepId,
+            NetconfSession session) throws NetconfException {
+        if (session == null) {
+            throw new NetconfException("Session is null when calling getMepEssentials()");
+        }
+
+        String xmlQueryStr = buildMepQueryString(mdName, maName, mepId);
+        log.debug("Sending <get> for " +
+                " query on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlQueryStr);
+
+        String xmlResult = session.get(xmlQueryStr, null);
+
+        xmlResult = removeRpcReplyData(xmlResult);
+        DefaultCompositeStream resultDcs = new DefaultCompositeStream(
+                null, new ByteArrayInputStream(xmlResult.getBytes()));
+        CompositeData compositeData = xSer.decode(resultDcs, yCtx);
+
+        ModelObjectData mod = ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
+
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        for (ModelObject mo:mod.modelObjects()) {
+            if (mo instanceof DefaultMefCfm) {
+                mseaCfm.mefCfm((DefaultMefCfm) mo);
+            }
+        }
+
+        return mseaCfm;
+    }
+
+    @Override
+    public MseaCfm getSoamDm(String mdName, String maName, int mepId,
+            int dmId, NetconfSession session) throws NetconfException {
+        String xmlQueryStr = buildDmQueryString(mdName, maName, mepId, dmId);
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public boolean setMseaCfm(MseaCfmOpParam mseaCfm, NetconfSession session,
+              DatastoreId targetDs) throws NetconfException {
+        ModelObjectData moEdit = DefaultModelObjectData.builder()
+                .addModelObject(mseaCfm).build();
+
+        return setNetconfObject(moEdit, session, targetDs, null);
+    }
+
+    /**
+     * Call RPCs on the device through NETCONF.
+     */
+    @Override
+    public void transmitLoopback(TransmitLoopbackInput inputVar, NetconfSession session) throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public void abortLoopback(AbortLoopbackInput inputVar, NetconfSession session) throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public TransmitLinktraceOutput transmitLinktrace(TransmitLinktraceInput inputVar, NetconfSession session)
+            throws NetconfException {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    private String buildMepQueryString(String mdName, String maName, int mepId) {
+        StringBuilder rpc = new StringBuilder();
+
+        rpc.append("<mef-cfm xmlns=\"http://www.microsemi.com/microsemi-edge-assure/msea-cfm\" ");
+        rpc.append(" xmlns:msea-soam-fm=\"http://www.microsemi.com/microsemi-edge-assure/msea-soam-fm\" ");
+        rpc.append("xmlns:msea-soam-pm=\"http://www.microsemi.com/microsemi-edge-assure/msea-soam-pm\">\n");
+        rpc.append("<maintenance-domain>\n");
+        rpc.append("<id/>\n");
+        rpc.append("<name>" + mdName + "</name>\n");
+        rpc.append("<md-level/>\n");
+        rpc.append("<maintenance-association>\n");
+        rpc.append("<id/>\n");
+        rpc.append("<name>" + maName + "</name>\n");
+        rpc.append("<ccm-interval>10ms</ccm-interval>\n");
+        rpc.append("<remote-meps/>\n");
+        rpc.append("<component-list/>\n");
+        rpc.append("<maintenance-association-end-point>\n");
+        rpc.append("<mep-identifier>" + mepId + "</mep-identifier>\n");
+        rpc.append("<interface/>\n");
+        rpc.append("<primary-vid/>\n");
+        rpc.append("<administrative-state/>\n");
+        rpc.append("<ccm-ltm-priority/>\n");
+        rpc.append("<continuity-check/>\n");
+        rpc.append("<mac-address/>\n");
+        rpc.append("<msea-soam-fm:port-status/>\n");
+        rpc.append("<msea-soam-fm:interface-status/>\n");
+        rpc.append("<msea-soam-fm:last-defect-sent/>\n");
+        rpc.append("<msea-soam-fm:rdi-transmit-status/>\n");
+        rpc.append("<loopback/>\n");
+        rpc.append("<remote-mep-database/>\n");
+        rpc.append("<linktrace/>\n");
+        rpc.append("</maintenance-association-end-point>\n");
+        rpc.append("</maintenance-association>\n");
+        rpc.append("</maintenance-domain>\n");
+        rpc.append("</mef-cfm>");
+
+        return rpc.toString();
+    }
+
+
+    private String buildDmQueryString(String mdName, String maName, int mepId, int dmId) {
+        StringBuilder rpc = new StringBuilder();
+
+        rpc.append("<mef-cfm xmlns=\"http://www.microsemi.com/microsemi-edge-assure/msea-cfm\" ");
+        rpc.append(" xmlns:msea-soam-fm=\"http://www.microsemi.com/microsemi-edge-assure/msea-soam-fm\" ");
+        rpc.append("xmlns:msea-soam-pm=\"http://www.microsemi.com/microsemi-edge-assure/msea-soam-pm\">\n");
+        rpc.append("<maintenance-domain>\n");
+        rpc.append("<id/>\n");
+        rpc.append("<name>" + mdName + "</name>\n");
+        rpc.append("<md-level/>\n");
+        rpc.append("<maintenance-association>\n");
+        rpc.append("<id/>\n");
+        rpc.append("<name>" + maName + "</name>\n");
+        rpc.append("<ccm-interval>10ms</ccm-interval>\n");
+        rpc.append("<maintenance-association-end-point>\n");
+        rpc.append("<mep-identifier>" + mepId + "</mep-identifier>\n");
+        rpc.append("<msea-soam-pm:delay-measurements>");
+        rpc.append("<msea-soam-pm:delay-measurement>");
+        rpc.append("<msea-soam-pm:dm-id>" + dmId + "</msea-soam-pm:dm-id>");
+        rpc.append("</msea-soam-pm:delay-measurement>");
+        rpc.append("</msea-soam-pm:delay-measurements>");
+        rpc.append("</maintenance-association-end-point>\n");
+        rpc.append("</maintenance-association>\n");
+        rpc.append("</maintenance-domain>\n");
+        rpc.append("</mef-cfm>");
+
+        return rpc.toString();
+    }
+
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaSaFilteringManager.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaSaFilteringManager.java
new file mode 100644
index 0000000..01af138
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaSaFilteringManager.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFilteringOpParam;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.SourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
+import org.onosproject.yang.model.DefaultModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.DefaultAnnotatedNodeInfo;
+import org.onosproject.yang.runtime.DefaultAnnotation;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of the MseaSaFiltering YANG model service.
+ */
+@Component(immediate = true, inherit = true)
+@Service
+public class MseaSaFilteringManager extends AbstractYangServiceImpl
+    implements MseaSaFilteringNetconfService {
+    public static final String MSEA_SA_FILTERING =
+            "org.onosproject.drivers.microsemi.yang.mseasafiltering";
+    public static final String MSEA_SA_FILTERING_NS =
+            "http://www.microsemi.com/microsemi-edge-assure/msea-sa-filtering";
+
+    @Activate
+    public void activate() {
+        super.activate();
+        appId = coreService.registerApplication(MSEA_SA_FILTERING);
+        log.info("MseaSaFilteringManager Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        super.deactivate();
+        log.info("MseaSaFilteringManager Stopped");
+    }
+
+    /**
+     * Get a filtered subset of the model.
+     * This is meant to filter the current live model
+     * against the attribute(s) given in the argument
+     * and return the filtered model.
+     */
+    @Override
+    public MseaSaFiltering getMseaSaFiltering(
+            MseaSaFilteringOpParam mseaSaFilteringFilter, NetconfSession session)
+            throws NetconfException {
+        ModelObjectData moQuery = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaSaFilteringFilter
+                        .sourceIpaddressFiltering())
+                .build();
+
+
+        ModelObjectData moReply = getNetconfObject(moQuery, session);
+
+        MseaSaFiltering reply = new MseaSaFilteringOpParam();
+        for (ModelObject mo:moReply.modelObjects()) {
+            if (mo instanceof SourceIpaddressFiltering) {
+                reply.sourceIpaddressFiltering((SourceIpaddressFiltering) mo);
+            }
+        }
+        return reply;
+    }
+
+    /**
+     * Get a filtered subset of the config model (from running)
+     * This is meant to filter the current live model
+     * against the attribute(s) given in the argument
+     * and return the filtered model.
+     */
+    @Override
+    public List<SourceAddressRange> getConfigMseaSaFilterIds(NetconfSession session)
+            throws NetconfException {
+
+        String xmlResult = session.getConfig(DatastoreId.RUNNING, saFilterQuery());
+        xmlResult = removeRpcReplyData(xmlResult);
+
+        DefaultCompositeStream resultDcs = new DefaultCompositeStream(
+                null, new ByteArrayInputStream(xmlResult.getBytes()));
+        CompositeData compositeData = xSer.decode(resultDcs, yCtx);
+
+        ModelObjectData moReply = ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
+
+        MseaSaFiltering reply = new MseaSaFilteringOpParam();
+        for (ModelObject mo:moReply.modelObjects()) {
+            if (mo instanceof SourceIpaddressFiltering) {
+                reply.sourceIpaddressFiltering((SourceIpaddressFiltering) mo);
+            }
+        }
+        if (reply != null && reply.sourceIpaddressFiltering() != null &&
+                reply.sourceIpaddressFiltering().interfaceEth0() != null) {
+            return reply.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
+        } else {
+            return new ArrayList<SourceAddressRange>();
+        }
+    }
+
+    /**
+     * Call NETCONF edit-config with a configuration.
+     */
+    @Override
+    public boolean setMseaSaFiltering(MseaSaFilteringOpParam mseaSaFiltering,
+           NetconfSession session, DatastoreId ncDs) throws NetconfException {
+
+        ModelObjectData moQuery = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaSaFiltering
+                        .sourceIpaddressFiltering()).build();
+
+        return setNetconfObject(moQuery, session, ncDs, null);
+    }
+
+    @Override
+    public boolean deleteMseaSaFilteringRange(MseaSaFilteringOpParam mseaSaFiltering,
+                                      NetconfSession session, DatastoreId ncDs) throws NetconfException {
+
+        ModelObjectData moQuery = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaSaFiltering
+                        .sourceIpaddressFiltering()).build();
+
+        ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
+        if (mseaSaFiltering.sourceIpaddressFiltering().interfaceEth0() != null &&
+                mseaSaFiltering.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange() != null) {
+
+            for (SourceAddressRange sar:mseaSaFiltering.sourceIpaddressFiltering()
+                    .interfaceEth0().sourceAddressRange()) {
+                String sarRangeIdStr = String.valueOf(sar.rangeId());
+
+                ResourceId.Builder ridBuilder = ResourceId.builder()
+                        .addBranchPointSchema("/", null)
+                        .addBranchPointSchema("source-ipaddress-filtering", MSEA_SA_FILTERING_NS)
+                        .addBranchPointSchema("interface-eth0", MSEA_SA_FILTERING_NS)
+                        .addBranchPointSchema("source-address-range", MSEA_SA_FILTERING_NS)
+                        .addKeyLeaf("range-id", MSEA_SA_FILTERING_NS, sarRangeIdStr);
+
+                AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                        .resourceId(ridBuilder.build())
+                        .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                        .build();
+
+                anis.add(ani);
+            }
+        } else {
+            //Delete all
+            ResourceId.Builder ridBuilder = ResourceId.builder()
+                    .addBranchPointSchema("/", null)
+                    .addBranchPointSchema("source-ipaddress-filtering", MSEA_SA_FILTERING_NS);
+            AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                    .resourceId(ridBuilder.build())
+                    .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                    .build();
+            anis.add(ani);
+        }
+
+        return setNetconfObject(moQuery, session, ncDs, anis);
+    }
+
+
+    private static String saFilterQuery() {
+        StringBuilder sb = new StringBuilder("<source-ipaddress-filtering " +
+                "xmlns=\"http://www.microsemi.com/microsemi-edge-assure/msea-sa-filtering\">");
+        sb.append("<interface-eth0>");
+        sb.append("<filter-admin-state>blacklist</filter-admin-state>");
+        sb.append("<source-address-range>");
+        sb.append("<range-id/>");
+        sb.append("</source-address-range>");
+        sb.append("</interface-eth0>");
+        sb.append("</source-ipaddress-filtering>");
+        return sb.toString();
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaUniEvcServiceManager.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaUniEvcServiceManager.java
new file mode 100644
index 0000000..f965541
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/MseaUniEvcServiceManager.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
+import org.onosproject.yang.model.DefaultModelObjectData;
+import org.onosproject.yang.model.ModelConverter;
+import org.onosproject.yang.model.ModelObject;
+import org.onosproject.yang.model.ModelObjectData;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.AnnotatedNodeInfo;
+import org.onosproject.yang.runtime.CompositeData;
+import org.onosproject.yang.runtime.DefaultAnnotatedNodeInfo;
+import org.onosproject.yang.runtime.DefaultAnnotation;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
+
+/**
+ * Implementation of the MseaUniEvcServiceService YANG model service.
+ */
+@Component(immediate = true, inherit = true)
+@Service
+public class MseaUniEvcServiceManager extends AbstractYangServiceImpl
+        implements MseaUniEvcServiceNetconfService {
+    public static final String MSEA_UNI_EVC_SVC =
+            "org.onosproject.drivers.microsemi.yang.mseaunievcservice";
+    public static final String MSEA_UNI_EVC_SVC_NS =
+            "http://www.microsemi.com/microsemi-edge-assure/msea-uni-evc-service";
+
+    @Activate
+    public void activate() {
+        super.activate();
+        appId = coreService.registerApplication(MSEA_UNI_EVC_SVC);
+        log.info("MseaUniEvcServiceManager Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        super.deactivate();
+        log.info("MseaUniEvcServiceManager Stopped");
+    }
+
+    @Override
+    public MseaUniEvcService getMseaUniEvcService(
+            MseaUniEvcServiceOpParam mseaUniEvcService, NetconfSession session)
+            throws NetconfException {
+
+        return getConfigMseaUniEvcService(mseaUniEvcService, session, null);
+    }
+
+    @Override
+    public MseaUniEvcService getConfigMseaUniEvcService(
+            MseaUniEvcServiceOpParam mseaUniEvcService, NetconfSession session,
+            DatastoreId targetDs) throws NetconfException {
+
+        ModelObjectData moFilter = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaUniEvcService.mefServices()).build();
+
+        ModelObjectData moReply = getConfigNetconfObject(moFilter, session, targetDs);
+
+        MseaUniEvcService reply = new MseaUniEvcServiceOpParam();
+        for (ModelObject mo:moReply.modelObjects()) {
+            if (mo instanceof MefServices) {
+                reply.mefServices((MefServices) mo);
+            }
+        }
+        return reply;
+    }
+
+    /**
+     * Modify the configuration.
+     */
+    @Override
+    public boolean setMseaUniEvcService(MseaUniEvcServiceOpParam mseaUniEvcService,
+                 NetconfSession session, DatastoreId ncDs) throws NetconfException {
+        ModelObjectData moEdit = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaUniEvcService.mefServices()).build();
+
+        return setNetconfObject(moEdit, session, ncDs, null);
+    }
+
+    /**
+     * Delete the configuration.
+     */
+    @Override
+    public boolean deleteMseaUniEvcService(MseaUniEvcServiceOpParam mseaUniEvcService,
+                NetconfSession session, DatastoreId ncDs) throws NetconfException {
+        ModelObjectData moEdit = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaUniEvcService.mefServices()).build();
+
+        ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
+        for (BwpGroup bwpGrp:mseaUniEvcService.mefServices().profiles().bwpGroup()) {
+            String bwpGroupIndex = String.valueOf(bwpGrp.groupIndex());
+
+            ResourceId.Builder ridBuilder = ResourceId.builder()
+                    .addBranchPointSchema("/", null)
+                    .addBranchPointSchema("mef-services", MSEA_UNI_EVC_SVC_NS)
+                    .addBranchPointSchema("profiles", MSEA_UNI_EVC_SVC_NS)
+                    .addBranchPointSchema("bwp-group", MSEA_UNI_EVC_SVC_NS)
+                    .addKeyLeaf("group-index", MSEA_UNI_EVC_SVC_NS, bwpGroupIndex);
+
+            AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                    .resourceId(ridBuilder.build())
+                    .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                    .build();
+
+            anis.add(ani);
+        }
+
+
+        return setNetconfObject(moEdit, session, ncDs, anis);
+    }
+
+
+    @Override
+    public MseaUniEvcService getmseaUniEvcCeVlanMaps(
+            NetconfSession session, DatastoreId ncDs)
+            throws NetconfException {
+        if (session == null) {
+            throw new NetconfException("Session is null when calling getMseaSaFiltering()");
+        }
+
+        String xmlResult = session.getConfig(ncDs, evcFilterQuery());
+        xmlResult = removeRpcReplyData(xmlResult);
+
+        DefaultCompositeStream resultDcs = new DefaultCompositeStream(
+                null, new ByteArrayInputStream(xmlResult.getBytes()));
+        CompositeData compositeData = xSer.decode(resultDcs, yCtx);
+
+        ModelObjectData moReply = ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
+
+        MseaUniEvcService reply = new MseaUniEvcServiceOpParam();
+        for (ModelObject mo:moReply.modelObjects()) {
+            if (mo instanceof MefServices) {
+                reply.mefServices((MefServices) mo);
+            }
+        }
+        return reply;
+    }
+
+    @Override
+    public void removeEvcUniFlowEntries(
+            Map<Integer, String> ceVlanUpdates,
+            Map<Integer, List<Short>> flowVlanIds,
+            NetconfSession session, DatastoreId targetDs,
+            UniSideInterfaceAssignmentEnum portAssign) throws NetconfException {
+
+        List<Integer> evcAlreadyHandled = new ArrayList<>();
+        StringBuilder xmlEvcUpdate = new StringBuilder(evcUniOpener());
+        for (Integer evcKey:ceVlanUpdates.keySet()) {
+            int evcId = (evcKey & ((1 << 8) - 100)) >> 2;
+            if (evcAlreadyHandled.contains(new Integer(evcId))) {
+                continue;
+            }
+            evcAlreadyHandled.add(evcId);
+            int port = (evcKey & 3);
+            String ceVlanMapThis = ceVlanUpdates.get(evcKey);
+            String ceVlanMapOpposite = ceVlanUpdates.get(evcKey ^ 1);
+
+            if ((ceVlanMapThis == null || ceVlanMapThis.isEmpty()) &&
+                    (ceVlanMapOpposite == null || ceVlanMapOpposite.isEmpty())) {
+                xmlEvcUpdate.append("<evc nc:operation=\"delete\">\n<evc-index>");
+                xmlEvcUpdate.append(Integer.toString(evcId));
+                xmlEvcUpdate.append("</evc-index>\n</evc>\n");
+            } else {
+                xmlEvcUpdate.append("<evc>\n<evc-index>");
+                xmlEvcUpdate.append(Integer.toString(evcId));
+                xmlEvcUpdate.append("</evc-index>\n<evc-per-uni>\n");
+                if (port == 0 && portAssign == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS ||
+                        port == 1 && portAssign == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) {
+                    if (ceVlanMapThis != null) {
+                        xmlEvcUpdate.append("<evc-per-uni-c>\n<ce-vlan-map nc:operation=\"replace\">");
+                        xmlEvcUpdate.append(ceVlanMapThis);
+                        xmlEvcUpdate.append("</ce-vlan-map>\n");
+                        xmlEvcUpdate.append(deleteFlowMapping(flowVlanIds.get(evcKey)));
+                        xmlEvcUpdate.append("</evc-per-uni-c>\n");
+                    }
+                    if (ceVlanMapOpposite != null) {
+                        xmlEvcUpdate.append("<evc-per-uni-n>\n<ce-vlan-map nc:operation=\"replace\">");
+                        xmlEvcUpdate.append(ceVlanMapOpposite);
+                        xmlEvcUpdate.append("</ce-vlan-map>\n");
+                        xmlEvcUpdate.append(deleteFlowMapping(flowVlanIds.get(evcKey ^ 1)));
+                        xmlEvcUpdate.append("</evc-per-uni-n>\n");
+                    }
+                } else {
+                    if (ceVlanMapThis != null) {
+                        xmlEvcUpdate.append("<evc-per-uni-n>\n<ce-vlan-map nc:operation=\"replace\">");
+                        xmlEvcUpdate.append(ceVlanMapThis);
+                        xmlEvcUpdate.append("</ce-vlan-map>\n");
+                        xmlEvcUpdate.append(deleteFlowMapping(flowVlanIds.get(evcKey)));
+                        xmlEvcUpdate.append("</evc-per-uni-n>\n");
+                    }
+                    if (ceVlanMapOpposite != null) {
+                        xmlEvcUpdate.append("<evc-per-uni-c>\n<ce-vlan-map nc:operation=\"replace\">");
+                        xmlEvcUpdate.append(ceVlanMapOpposite);
+                        xmlEvcUpdate.append("</ce-vlan-map>\n");
+                        xmlEvcUpdate.append(deleteFlowMapping(flowVlanIds.get(evcKey ^ 1)));
+                        xmlEvcUpdate.append("</evc-per-uni-c>\n");
+                    }
+                }
+
+                xmlEvcUpdate.append("</evc-per-uni>\n</evc>\n");
+            }
+        }
+        xmlEvcUpdate.append("</uni>\n</mef-services>");
+
+        log.info("Sending XML <edit-config> on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlEvcUpdate.toString());
+
+
+        session.editConfig(targetDs, null, xmlEvcUpdate.toString());
+    }
+
+
+    private static String deleteFlowMapping(List<Short> vlanIds) {
+        if (vlanIds == null || vlanIds.size() == 0) {
+            return "";
+        }
+        StringBuilder fmXmlBuilder = new StringBuilder();
+        for (long vlanId:vlanIds) {
+            fmXmlBuilder.append("<flow-mapping nc:operation=\"delete\">\n");
+            fmXmlBuilder.append("<ce-vlan-id>");
+            fmXmlBuilder.append(String.valueOf(vlanId));
+            fmXmlBuilder.append("</ce-vlan-id>\n");
+            fmXmlBuilder.append("</flow-mapping>\n");
+        }
+
+        return fmXmlBuilder.toString();
+    }
+
+    private String evcFilterQuery() {
+        StringBuilder sb = new StringBuilder("<mef-services "
+                + "xmlns=\"http://www.microsemi.com/microsemi-edge-assure/msea-uni-evc-service\">");
+        sb.append("<uni>");
+        sb.append("<evc>");
+        sb.append("<evc-index/>");
+        sb.append("<evc-per-uni>");
+        sb.append("<evc-per-uni-c>");
+        sb.append("<ce-vlan-map/>");
+        sb.append("<flow-mapping/>");
+        sb.append("<ingress-bwp-group-index/>");
+        sb.append("</evc-per-uni-c>");
+        sb.append("<evc-per-uni-n>");
+        sb.append("<ce-vlan-map/>");
+        sb.append("<flow-mapping/>");
+        sb.append("<ingress-bwp-group-index/>");
+        sb.append("</evc-per-uni-n>");
+        sb.append("</evc-per-uni>");
+        sb.append("</evc>");
+        sb.append("</uni>");
+        sb.append("</mef-services>");
+
+        return sb.toString();
+    }
+
+    private String evcUniOpener() {
+        StringBuilder sb = new StringBuilder("<mef-services ");
+        sb.append("xmlns=\"http://www.microsemi.com/microsemi-edge-assure/msea-uni-evc-service\">\n");
+        sb.append("<uni>\n");
+
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/package-info.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/package-info.java
new file mode 100644
index 0000000..ccf0dd2
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Microsemi device drivers support for NETCONF for EA1000.
+ */
+package org.onosproject.drivers.microsemi.yang.impl;
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/package-info.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/package-info.java
new file mode 100644
index 0000000..d886c69
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Microsemi device drivers support for NETCONF for EA1000.
+ */
+package org.onosproject.drivers.microsemi.yang;
\ No newline at end of file
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/CeVlanMapUtils.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/CeVlanMapUtils.java
new file mode 100644
index 0000000..52ede6d
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/CeVlanMapUtils.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.utils;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A set of static utilities that allow a ce-vlan-map to be decomposed.
+ *
+ * This is an implementation specific to Microsemi that encodes ce-vlan-map
+ * in a similar way to Section 7.9 in the MEF 10.2 specification. That specification
+ * suggests comma delimited lists of VIDs - this implementation adds on colons to
+ * specify a contiguous range of IDs
+ */
+public final class CeVlanMapUtils {
+
+    private CeVlanMapUtils() {
+        //Do not allow this utility class to be instantiated
+    }
+
+    /**
+     * Calculate the ceVlanMap in to a Set of values.
+     *
+     * From Yang description
+     *   "This object indicates the CE-VLANs associated with the specific
+     *   EVC on a UNI. CE-VLAN IDs have value of 0 to 4095. The CE-VLAN ID
+     *   list can be a single value or multiple values separated by a delimiter.
+     *   Some valid values are: '100', '1:10', '10,20,30', '1:4095'. In the
+     *   first example only CE-VLAN ID 100 is associated with the VLAN map.
+     *   In the second example the CE-VLAN map includes CE-VLAN IDs 1 through
+     *   10 (range of values). The third example indicates three separate values
+     *   that make up the CE-VLAN map. The last example indicates all CE-VLAN IDs
+     *   are included in the map (range of values). ";
+     *  reference
+     *   "[MEF 6.1] 6.1; [MEF 7.2] 6.2.1.3";
+     * @param ceVlanMap A list of vlan id's in the format described above
+     * @return A set of vlan ids
+     */
+    public static Short[] getVlanSet(String ceVlanMap) {
+        if (ceVlanMap == null || ceVlanMap.isEmpty()) {
+            return new Short[0];
+        }
+        Set<Short> ceVlanSet = new TreeSet<Short>();
+
+        String[] ceVlanMapCommas = ceVlanMap.split(",");
+        for (String ceVlanMapComma:ceVlanMapCommas) {
+            String[] ceVlanMapColon = ceVlanMapComma.split(":");
+            if (ceVlanMapColon.length == 1) {
+                ceVlanSet.add(Short.decode(ceVlanMapColon[0]));
+            } else {
+                short start = Short.decode(ceVlanMapColon[0]);
+                short end = Short.decode(ceVlanMapColon[1]);
+                if ((start < 0 || end > 4095)) {
+                    return null;
+                } else {
+                    for (short i = start; i <= end; i++) {
+                        ceVlanSet.add(i);
+                    }
+                }
+            }
+        }
+
+        return ceVlanSet.toArray(new Short[ceVlanSet.size()]);
+    }
+
+    /**
+     * Convert an array of vlan ids in to a string representation.
+     * @param vlanArray An array of vlan ids
+     * @return A string representation delimited by commas and colons
+     */
+    public static String vlanListAsString(Short[] vlanArray) {
+        boolean colonPending = false;
+        StringBuilder ceVlanMapBuilder = new StringBuilder();
+        if (vlanArray.length == 0) {
+            return "";
+        } else if (vlanArray.length == 1 && vlanArray[0] == 0) {
+            return "0";
+        }
+
+        //To ensure that there are no repeated or out-of-order elements we must convert to TreeSet
+        TreeSet<Short> vlanSet = new TreeSet<>(Arrays.asList(vlanArray));
+
+        if (vlanSet.first() == 0) {
+            vlanSet.remove(vlanSet.first());
+        }
+        short prev = vlanSet.first();
+        for (short s:vlanSet) {
+            if (s == prev) {
+                ceVlanMapBuilder.append(Short.valueOf(s));
+                continue;
+            } else if (prev == (s - 1)) {
+                colonPending = true;
+            } else {
+                if (colonPending) {
+                    ceVlanMapBuilder.append(":" + Short.valueOf(prev));
+                    colonPending = false;
+                }
+                ceVlanMapBuilder.append("," + Short.valueOf(s));
+            }
+            prev = s;
+        }
+        if (colonPending) {
+            ceVlanMapBuilder.append(":" + Short.valueOf(prev));
+        }
+
+        return ceVlanMapBuilder.toString();
+    }
+
+    /**
+     * Add an additional vlan id to an existing string representation.
+     * @param existingMap An array of vlan ids
+     * @param newVlan The new vlan ID to add
+     * @return A string representation delimited by commas and colons
+     */
+    public static String addtoCeVlanMap(String existingMap, Short newVlan) {
+        Short[] vlanArray = getVlanSet(existingMap);
+        TreeSet<Short> vlanSet = new TreeSet<>();
+        for (Short vlan:vlanArray) {
+            vlanSet.add(vlan);
+        }
+
+        vlanSet.add(newVlan);
+
+        return vlanListAsString(vlanSet.toArray(new Short[vlanSet.size()]));
+    }
+
+    /**
+     * If a string representation contains a '0' then remove it.
+     *
+     * Zero is an invalid VLAN id, and is used here as a place holder for null. Null can't
+     * be used in the EA1000 device. Once any other vlan ids are added then the zero should
+     * be removed. It is safe to call this method even if no zero is present - the method will
+     * make no change in that case.
+     *
+     * @param existingMap An string representation of vlan ids, possibly containing a zero
+     * @return A string representation delimited by commas and colons without zero
+     */
+    public static String removeZeroIfPossible(String existingMap) {
+        if (existingMap == null || existingMap.isEmpty()) {
+            return "0";
+        } else if (existingMap == "0") {
+            return existingMap;
+        }
+        return removeFromCeVlanMap(existingMap, (short) 0);
+    }
+
+    /**
+     * Remove a vlan id from an existing string representation.
+     * @param existingMap An array of vlan ids
+     * @param vlanRemove The vlan ID to remove
+     * @return A string representation delimited by commas and colons
+     */
+    public static String removeFromCeVlanMap(String existingMap, Short vlanRemove) {
+        Short[] vlanArray = getVlanSet(existingMap);
+        TreeSet<Short> vlanSet = new TreeSet<>();
+        for (Short vlan:vlanArray) {
+            if (vlan.shortValue() != vlanRemove.shortValue()) {
+                vlanSet.add(vlan);
+            }
+        }
+
+        return vlanListAsString(vlanSet.toArray(new Short[vlanSet.size()]));
+    }
+
+    /**
+     * Combine vlan ids from two existing string representations.
+     *
+     * If there are overlapping elements and ranges, these are consolidated in to one.
+     *
+     * @param set1 A string containing a set of vlan ids
+     * @param set2 A string containing a set of vlan ids
+     * @return A string representation delimited by commas and colons
+     */
+    public static String combineVlanSets(String set1, String set2) {
+        Short[] set1Array = getVlanSet(set1);
+        Short[] set2Array = getVlanSet(set2);
+        return vlanListAsString((Short[]) ArrayUtils.addAll(set1Array, set2Array));
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/IetfYangTypesUtils.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/IetfYangTypesUtils.java
new file mode 100644
index 0000000..275dc25
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/IetfYangTypesUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi.yang.utils;
+
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+import org.onosproject.yang.gen.v1.ietfyangtypes.rev20130715.ietfyangtypes.DateAndTime;
+
+/**
+ * A utility class to change various YANG types to general purpose classes.
+ */
+public final class IetfYangTypesUtils {
+    private IetfYangTypesUtils() {
+        //Hiding the public constructor for this utility class
+    }
+
+    /**
+     * Convert from Date and Time in a ietf-yang-types format to the Java Time API.
+     * @param dateAndTime A date and time from a YANG object
+     * @return A Date and Time with a Time Zone offset
+     */
+    public static OffsetDateTime fromYangDateTime(DateAndTime dateAndTime) {
+        return OffsetDateTime.parse(dateAndTime.toString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+    }
+
+    /**
+     * Convert a from Date and Time in a ietf-yang-types format to the Java Time API and rezone to a given Time Zone.
+     * @param dateAndTime A date and time from a YANG object
+     * @param zoneId The time zone to rezone the time and date to
+     * @return The rezoned time and date
+     */
+    public static ZonedDateTime fromYangDateTimeZoned(DateAndTime dateAndTime, ZoneId zoneId) {
+        return OffsetDateTime.parse(dateAndTime.toString(),
+                DateTimeFormatter.ISO_OFFSET_DATE_TIME).atZoneSameInstant(zoneId);
+    }
+
+    /**
+     * Convert a from Date and Time in a ietf-yang-types format to the Java Time API rezoned to the local Time Zone.
+     * @param dateAndTime A date and time from a YANG object
+     * @return The date and time in the zone of this local machine
+     */
+    public static LocalDateTime fromYangDateTimeToLocal(DateAndTime dateAndTime) {
+        OffsetDateTime odt = OffsetDateTime.parse(dateAndTime.toString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+
+        return LocalDateTime.ofInstant(odt.toInstant(), ZoneId.systemDefault());
+    }
+}
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/package-info.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/package-info.java
new file mode 100644
index 0000000..0c03c46
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for general utilities and helpers.
+ */
+package org.onosproject.drivers.microsemi.yang.utils;
\ No newline at end of file