[ONOS-7262] Cfm improvements to allow RMeps and Mds and Mas to be added and deleted

Change-Id: Ibffb13d046bfb29dbe88de7b558c95fbf9db046d
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
index 341bd7d..f3c5b6e 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
@@ -20,6 +20,12 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
@@ -45,29 +51,7 @@
         CfmMdService service = get(CfmMdService.class);
 
         if (name != null) {
-            String[] nameParts = name.split("[()]");
-            if (nameParts.length != 2) {
-                throw new IllegalArgumentException("Invalid name format. " +
-                        "Must be in the format of <identifier(name-type)>");
-            }
-
-            MdId mdId = null;
-            MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameParts[1]);
-            switch (nameTypeEnum) {
-                case DOMAINNAME:
-                    mdId = MdIdDomainName.asMdId(nameParts[0]);
-                    break;
-                case MACANDUINT:
-                    mdId = MdIdMacUint.asMdId(nameParts[0]);
-                    break;
-                case NONE:
-                    mdId = MdIdNone.asMdId();
-                    break;
-                case CHARACTERSTRING:
-                default:
-                    mdId = MdIdCharStr.asMdId(nameParts[0]);
-            }
-
+            MdId mdId = parseMdName(name);
             print("Maintenance Domain:");
             Optional<MaintenanceDomain> md = service.getMaintenanceDomain(mdId);
             print(printMd(md));
@@ -131,4 +115,59 @@
 
         return sb.toString();
     }
+
+    public static MdId parseMdName(String mdStr) {
+        String[] nameParts = mdStr.split("[()]");
+        if (nameParts.length != 2) {
+            throw new IllegalArgumentException("Invalid name format. " +
+                    "Must be in the format of <identifier(name-type)>");
+        }
+
+        MdId mdId = null;
+        MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameParts[1]);
+        switch (nameTypeEnum) {
+            case DOMAINNAME:
+                mdId = MdIdDomainName.asMdId(nameParts[0]);
+                break;
+            case MACANDUINT:
+                mdId = MdIdMacUint.asMdId(nameParts[0]);
+                break;
+            case NONE:
+                mdId = MdIdNone.asMdId();
+                break;
+            case CHARACTERSTRING:
+            default:
+                mdId = MdIdCharStr.asMdId(nameParts[0]);
+        }
+        return mdId;
+    }
+
+    public static MaIdShort parseMaName(String maStr) {
+        String[] nameParts = maStr.split("[()]");
+        if (nameParts.length != 2) {
+            throw new IllegalArgumentException("Invalid name format. " +
+                    "Must be in the format of <identifier(name-type)>");
+        }
+
+        MaIdShort maId = null;
+        MaIdShort.MaIdType nameTypeEnum = MaIdShort.MaIdType.valueOf(nameParts[1]);
+        switch (nameTypeEnum) {
+            case ICCY1731:
+                maId = MaIdIccY1731.asMaId(nameParts[0]);
+                break;
+            case PRIMARYVID:
+                maId = MaIdPrimaryVid.asMaId(nameParts[0]);
+                break;
+            case RFC2685VPNID:
+                maId = MaIdRfc2685VpnId.asMaIdHex(nameParts[0]);
+                break;
+            case TWOOCTET:
+                maId = MaId2Octet.asMaId(nameParts[0]);
+            case CHARACTERSTRING:
+            default:
+                maId = MaIdCharStr.asMaId(nameParts[0]);
+        }
+        return maId;
+    }
+
 }
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListCommand.java
new file mode 100644
index 0000000..b406947
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListCommand.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.slf4j.Logger;
+
+import static org.onosproject.cfm.cli.CfmMdListMdCommand.parseMaName;
+import static org.onosproject.cfm.cli.CfmMdListMdCommand.parseMdName;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Lists a particular Maintenance Domain.
+ */
+@Command(scope = "onos", name = "cfm-mep-list",
+        description = "Lists a filtered set of MEPs or all if no parameters specified.")
+public class CfmMepListCommand extends AbstractShellCommand {
+    private final Logger log = getLogger(getClass());
+    @Argument(index = 0, name = "md",
+            description = "Maintenance Domain name and type (in brackets) - will use all MDs if not specified",
+            required = false, multiValued = false)
+    String mdStr = null;
+    @Argument(index = 1, name = "ma",
+            description = "Maintenance Association name and type (in brackets) - requires MD",
+            required = false, multiValued = false)
+    String maStr = null;
+    @Argument(index = 2, name = "mep",
+            description = "MEP identifier - requires MD and MA",
+            required = false, multiValued = false)
+    String mepStr = null;
+
+    @Override
+    protected void execute() {
+        CfmMepService mepService = get(CfmMepService.class);
+        CfmMdService mdService = get(CfmMdService.class);
+
+        if (mdStr != null && !mdStr.isEmpty()) {
+
+
+            MdId mdId = parseMdName(mdStr);
+            print(printMdId(mdId));
+
+            if (maStr != null && !maStr.isEmpty()) {
+                MaIdShort maId = parseMaName(maStr);
+                print(printMaId(maId));
+
+                if (mepStr != null && !mepStr.isEmpty()) {
+                    MepId mepId = MepId.valueOf(Short.parseShort(mepStr));
+                    try {
+                        MepEntry mep = mepService.getMep(mdId, maId, mepId);
+                        if (mep != null) {
+                            print(printMepEntry(mep));
+                        }
+                    } catch (CfmConfigException e) {
+                        log.error("Error retrieving Mep details {}",
+                                new MepKeyId(mdId, maId, mepId), e);
+                    }
+
+                    //MD, MA and MEP given
+                } else {
+                    //MD and MA given but no MEP given
+                    try {
+                        mepService.getAllMeps(mdId, maId).forEach(mep -> {
+                            print(printMepEntry(mep));
+                        });
+                    } catch (CfmConfigException e) {
+                        log.error("Error retrieving Meps for {}/{}",
+                                mdId.mdName(), maId.maName(), e);
+                    }
+                }
+            } else {
+                //MD given but no MA given
+                mdService.getAllMaintenanceAssociation(mdId).forEach(ma -> {
+                    print(printMaId(ma.maId()));
+                    try {
+                        mepService.getAllMeps(mdId, ma.maId()).forEach(mep -> {
+                            print(printMepEntry(mep));
+                        });
+                    } catch (CfmConfigException e) {
+                        log.error("Error retrieving Meps for {}/{}",
+                                mdId.mdName(), ma.maId().maName(), e);
+                    }
+                });
+
+            }
+        } else {
+            mdService.getAllMaintenanceDomain().forEach(md -> {
+                print(printMdId(md.mdId()));
+
+                mdService.getAllMaintenanceAssociation(md.mdId()).forEach(ma -> {
+                    print(printMaId(ma.maId()));
+                    try {
+                        mepService.getAllMeps(md.mdId(), ma.maId()).forEach(mep -> {
+                            print(printMepEntry(mep));
+                        });
+                    } catch (CfmConfigException e) {
+                        log.error("Error retrieving Meps for {}/{}",
+                                md.mdId().mdName(), ma.maId().maName(), e);
+                    }
+                });
+            });
+        }
+    }
+
+    /**
+     * Print the whole MEP Entry (config and status).
+     * @param mep The MEPEntry to print
+     * @return A string with MepEntry details
+     */
+    public static String printMepEntry(MepEntry mep) {
+        StringBuffer sb = new StringBuffer("MEP: ");
+        sb.append(mep.mepId());
+        sb.append(" Device:" + mep.deviceId());
+        sb.append(", Port: " + mep.port());
+        sb.append(", Vlan: " + mep.primaryVid());
+        sb.append(", AdminSt: " + mep.administrativeState());
+        sb.append(", CciEnabled: " + mep.cciEnabled());
+        sb.append(", Priority: " + mep.ccmLtmPriority());
+        sb.append("\n"); //The following are state
+        sb.append(", Total CCMs: " + mep.totalCcmsTransmitted());
+        sb.append(", MAC: " + mep.macAddress());
+        sb.append(", Fault: " + mep.fngState());
+
+        mep.activeRemoteMepList().forEach(rmep -> {
+            sb.append("\n\tRmep: " + rmep.remoteMepId());
+            sb.append(", Mac: " + rmep.macAddress());
+            sb.append(", State: " + rmep.state());
+            sb.append(", Failed Time: " + rmep.failedOrOkTime());
+
+        });
+
+
+        return sb.toString();
+    }
+
+    public static String printMdId(MdId mdId) {
+        StringBuffer sb = new StringBuffer("MD: ");
+        sb.append(mdId.mdName());
+        sb.append("(" + mdId.nameType() + ")");
+        return sb.toString();
+    }
+
+    public static String printMaId(MaIdShort maId) {
+        StringBuffer sb = new StringBuffer("MA: ");
+        sb.append(maId.maName());
+        sb.append("(" + maId.nameType() + ")");
+        return sb.toString();
+    }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListDeviceCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListDeviceCommand.java
new file mode 100644
index 0000000..c99399a
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMepListDeviceCommand.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.net.DeviceId;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Lists all the MEPs on a particular device.
+ */
+@Command(scope = "onos", name = "cfm-mep-device-list",
+        description = "Lists a set of MEPs filtered by device.")
+public class CfmMepListDeviceCommand extends AbstractShellCommand {
+    private final Logger log = getLogger(getClass());
+    @Argument(index = 0, name = "device",
+            description = "Device Id",
+            required = true, multiValued = false)
+    String deviceStr = null;
+
+    @Override
+    protected void execute() {
+        CfmMepService mepService = get(CfmMepService.class);
+        if (deviceStr != null) {
+            DeviceId deviceId = DeviceId.deviceId(deviceStr);
+            try {
+                mepService.getAllMepsByDevice(deviceId).forEach(mep -> {
+                    print(printMep(mep));
+                });
+            } catch (CfmConfigException e) {
+                log.error("Error retrieving Meps for Device {}",
+                        deviceId, e);
+            }
+        }
+    }
+
+    /**
+     * Print only the config part of the MEP.
+     * @param mep The MEP to print
+     * @return A string with MD name, MA name and Mep details
+     */
+    public static String printMep(Mep mep) {
+        StringBuffer sb = new StringBuffer("MEP: ");
+        sb.append(mep.mdId().mdName() + "/");
+        sb.append(mep.maId().maName() + "/");
+        sb.append(mep.mepId());
+        sb.append(" Device:" + mep.deviceId());
+        sb.append(", Port: " + mep.port());
+        sb.append(", Vlan: " + mep.primaryVid());
+        sb.append(", AdminSt: " + mep.administrativeState());
+        sb.append(", CciEnabled: " + mep.cciEnabled());
+        sb.append(", Priority: " + mep.ccmLtmPriority());
+
+        return sb.toString();
+    }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmDeviceIdCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmDeviceIdCompleter.java
new file mode 100644
index 0000000..6e2e29f
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmDeviceIdCompleter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.cfm.cli.completer;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DeviceService;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * CLI completer for Devices that support Meps.
+ */
+public class CfmDeviceIdCompleter implements Completer {
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        // Delegate string completer
+        StringsCompleter delegate = new StringsCompleter();
+
+        // Fetch our service and feed it's offerings to the string completer
+        DeviceService service = AbstractShellCommand.get(DeviceService.class);
+        Iterator<Device> it = service.getDevices().iterator();
+        SortedSet<String> strings = delegate.getStrings();
+        while (it.hasNext()) {
+            Device device = it.next();
+            if (device.is(CfmMepProgrammable.class)) {
+                strings.add(device.id().toString());
+            }
+        }
+
+        // Now let the completer do the work for figuring out what to offer.
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMepIdCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMepIdCompleter.java
new file mode 100644
index 0000000..6019916
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMepIdCompleter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.onosproject.cli.AbstractShellCommand.get;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * CLI completer for Mep Id creation.
+ */
+public class CfmMepIdCompleter extends AbstractChoicesCompleter {
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public List<String> choices() {
+        List<String> choices = new ArrayList<>();
+
+        CfmMdService mdService = get(CfmMdService.class);
+        CfmMepService mepService = get(CfmMepService.class);
+
+        mdService.getAllMaintenanceDomain().forEach(md -> {
+            choices.add(new StringBuilder(md.mdId().mdName())
+                            .append("(")
+                            .append(md.mdId().nameType())
+                            .append(")").toString());
+
+            md.maintenanceAssociationList().forEach(ma -> {
+                    choices.add(new StringBuilder(md.mdId().mdName())
+                            .append("(")
+                            .append(md.mdId().nameType())
+                            .append(") ")
+                            .append(ma.maId().maName())
+                            .append("(")
+                            .append(ma.maId().nameType())
+                            .append(")").toString());
+
+                    try {
+                        mepService.getAllMeps(md.mdId(), ma.maId()).forEach(mep ->
+                                choices.add(new StringBuilder(md.mdId().mdName())
+                                        .append("(")
+                                        .append(md.mdId().nameType())
+                                        .append(") ")
+                                        .append(ma.maId().maName())
+                                        .append("(")
+                                        .append(ma.maId().nameType())
+                                        .append(") ")
+                                        .append(mep.mepId()).toString())
+                        );
+                    } catch (CfmConfigException e) {
+                        log.warn("Unable to retrieve mep details", e);
+                    }
+                }
+            );
+        });
+
+        return choices;
+    }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/rest/CfmWebApplication.java b/apps/cfm/src/main/java/org/onosproject/cfm/rest/CfmWebApplication.java
index 13157f2..b32174e 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/rest/CfmWebApplication.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/rest/CfmWebApplication.java
@@ -32,6 +32,7 @@
                 MdWebResource.class,
                 MaWebResource.class,
                 MepWebResource.class,
+                DeviceMepWebResource.class,
                 DmWebResource.class,
                 LmWebResource.class);
     }
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/rest/DeviceMepWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/rest/DeviceMepWebResource.java
new file mode 100644
index 0000000..5fbed6d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/rest/DeviceMepWebResource.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.rest;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collection;
+
+/**
+ * Layer 2 CFM Maintenance Association Endpoint (MEP) by Device web resource.
+ */
+@Path("device")
+public class DeviceMepWebResource extends AbstractWebResource {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * Get all MEPs by Device Id. The device should support Meps
+     *
+     * @param deviceId The id of a device.
+     * @return 200 OK with a list of MEPS or 500 on error
+     */
+    @GET
+    @Path("{device_id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response getAllMepsForDevice(@PathParam("device_id") String deviceId) {
+        DeviceId deviceIdObj = DeviceId.deviceId(deviceId);
+        log.debug("GET all Meps called for Device {}", deviceIdObj);
+        try {
+            Collection<Mep> mepCollection = get(CfmMepService.class)
+                    .getAllMepsByDevice(deviceIdObj);
+            ArrayNode an = mapper().createArrayNode();
+            an.add(codec(Mep.class).encode(mepCollection, this));
+            return ok(mapper().createObjectNode().set("meps", an)).build();
+        } catch (CfmConfigException e) {
+            log.error("Get all Meps on device {} failed because of exception",
+                    deviceIdObj, e);
+            return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+        }
+    }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/rest/MdWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/rest/MdWebResource.java
index c642f4a..0e523a7 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/rest/MdWebResource.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/rest/MdWebResource.java
@@ -82,6 +82,7 @@
         log.debug("GET called for MD {}", mdName);
         try {
             MaintenanceDomain md = get(CfmMdService.class)
+                    //FIXME Handle other types of name constructs e.g. DomainName
                     .getMaintenanceDomain(MdIdCharStr.asMdId(mdName))
                     .orElseThrow(() -> new IllegalArgumentException(
                             "MD " + mdName + " not Found"));
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/rest/MepWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/rest/MepWebResource.java
index fa8c728..52d4150 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/rest/MepWebResource.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/rest/MepWebResource.java
@@ -18,6 +18,7 @@
 import java.io.InputStream;
 import java.net.URI;
 import java.util.Collection;
+import java.util.Optional;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -145,7 +146,7 @@
             MdId mdId = MdIdCharStr.asMdId(mdName);
             MaIdShort maId = MaIdCharStr.asMaId(maName);
             boolean deleted = get(CfmMepService.class)
-                    .deleteMep(mdId, maId, MepId.valueOf(mepIdShort));
+                    .deleteMep(mdId, maId, MepId.valueOf(mepIdShort), Optional.empty());
             if (!deleted) {
                 return Response.notModified(mdName + "/" + maName + "/" +
                         mepIdShort + " did not exist").build();
@@ -187,8 +188,8 @@
 
             Mep mep = ((MepCodec) mepCodec).decode((ObjectNode) cfg, this, mdName, maName);
 
-            Boolean issuccess = get(CfmMepService.class).createMep(mdId, maId, mep);
-            if (!issuccess) {
+            Boolean didNotExist = get(CfmMepService.class).createMep(mdId, maId, mep);
+            if (!didNotExist) {
                 return Response.notModified(mdName + "/" + ma.maId() + "/" + mep.mepId() +
                         " already exists").build();
             }
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java
index 62be35d..6c3829f 100644
--- a/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java
@@ -124,10 +124,13 @@
                 builder = builder.addToComponentList(component);
             }
 
-            List<MepId> remoteMeps = (new RMepCodec()).decode(
-                    (ArrayNode) nullIsIllegal(maNode.get(RMEP_LIST), "rmep-list is required"), context);
-            for (MepId remoteMep:remoteMeps) {
-                builder = builder.addToRemoteMepIdList(remoteMep);
+            JsonNode rmepListJson = maNode.get(RMEP_LIST);
+            if (rmepListJson != null) {
+                List<MepId> remoteMeps = (new RMepCodec()).decode(
+                        (ArrayNode) rmepListJson, context);
+                for (MepId remoteMep:remoteMeps) {
+                    builder = builder.addToRemoteMepIdList(remoteMep);
+                }
             }
 
             return builder.build();
diff --git a/apps/cfm/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/cfm/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 5f53eba..fcd66a0 100644
--- a/apps/cfm/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/cfm/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -57,6 +57,18 @@
                 <ref component-id="maNameCompleter"/>
             </completers>
         </command>
+        <command>
+            <action class="org.onosproject.cfm.cli.CfmMepListCommand"/>
+            <completers>
+                <ref component-id="mepIdCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.cfm.cli.CfmMepListDeviceCommand"/>
+            <completers>
+                <ref component-id="mepDeviceIdCompleter"/>
+            </completers>
+        </command>
     </command-bundle>
 
     <bean id="placeholderCompleter" class="org.onosproject.cli.PlaceholderCompleter"/>
@@ -68,6 +80,8 @@
     <bean id="maCcmIntervalCompleter" class="org.onosproject.cfm.cli.completer.CfmMaCcmIntervalCompleter"/>
     <bean id="compTagTypeCompleter" class="org.onosproject.cfm.cli.completer.CfmCompTagTypeCompleter"/>
     <bean id="compMhfCompleter" class="org.onosproject.cfm.cli.completer.CfmCompMhfCompleter"/>
+    <bean id="mepIdCompleter" class="org.onosproject.cfm.cli.completer.CfmMepIdCompleter"/>
+    <bean id="mepDeviceIdCompleter" class="org.onosproject.cfm.cli.completer.CfmDeviceIdCompleter"/>
 
 </blueprint>
 
diff --git a/apps/cfm/src/main/resources/definitions/MaCreate.json b/apps/cfm/src/main/resources/definitions/MaCreate.json
index fea36db..5b6be27 100644
--- a/apps/cfm/src/main/resources/definitions/MaCreate.json
+++ b/apps/cfm/src/main/resources/definitions/MaCreate.json
@@ -133,7 +133,8 @@
               }
             }
           },
-          "example": [{"rmep": 10}, {"rmep": 20}]
+          "example": [{"rmep": 10}, {"rmep": 20}],
+          "description": "An optional set of Mep IDs that might be on equipment not managed by ONOS"
         }
       }
     }
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java
index fde5428..6a5dbca 100644
--- a/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java
@@ -185,7 +185,7 @@
     @Test
     public void testDeleteMepValid() throws CfmConfigException {
 
-        expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 1)))
+        expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 1), Optional.empty()))
                 .andReturn(true).anyTimes();
         replay(mepService);
 
@@ -199,7 +199,7 @@
     @Test
     public void testDeleteMepNotFound() throws CfmConfigException {
 
-        expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 2)))
+        expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 2), Optional.empty()))
                 .andReturn(false).anyTimes();
         replay(mepService);
 
diff --git a/drivers/microsemi/BUCK b/drivers/microsemi/BUCK
index 80ef2c8..210d76cc 100644
--- a/drivers/microsemi/BUCK
+++ b/drivers/microsemi/BUCK
@@ -15,7 +15,8 @@
     '//core/api:onos-api-tests',
     '//drivers/netconf:onos-drivers-netconf-tests',
     '//utils/osgi:onlab-osgi-tests',
-    '//incubator/net:onos-incubator-net'
+    '//incubator/net:onos-incubator-net',
+    '//incubator/net:onos-incubator-net-tests'
 ]
 
 APPS = [
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammable.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammable.java
index 143ee79..a5ff236 100755
--- a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammable.java
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammable.java
@@ -16,12 +16,17 @@
 package org.onosproject.drivers.microsemi;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.drivers.microsemi.yang.utils.MaNameUtil.getApiMaIdFromYangMaName;
+import static org.onosproject.drivers.microsemi.yang.utils.MdNameUtil.getApiMdIdFromYangMdName;
+import static org.onosproject.drivers.microsemi.yang.utils.MdNameUtil.getYangMdNameFromApiMdId;
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.NoSuchElementException;
+import java.util.Optional;
 
-import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onlab.util.HexString;
@@ -47,14 +52,12 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry.RemoteMepState;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
-import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
-import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
-import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
-import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
@@ -62,7 +65,6 @@
 import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
-import org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.ietfinettypes.DomainName;
 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;
@@ -83,11 +85,6 @@
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.ContinuityCheck;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.DefaultContinuityCheck;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.InterfaceEnum;
-import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultMacAddressAndUint;
-import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameCharacterString;
-import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameDomainName;
-import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameNone;
-import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.namedomainname.NameDomainNameUnion;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.remotemepstatetype.RemoteMepStateTypeEnum;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.targetaddressgroup.addresstype.DefaultMacAddress;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.targetaddressgroup.addresstype.DefaultMepId;
@@ -97,8 +94,6 @@
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitloopback.transmitloopbackinput.TargetAddress;
 import org.onosproject.yang.gen.v1.mseasoamfm.rev20160229.mseasoamfm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.AugmentedMseaCfmMaintenanceAssociationEndPoint;
 import org.onosproject.yang.gen.v1.mseasoamfm.rev20160229.mseasoamfm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.DefaultAugmentedMseaCfmMaintenanceAssociationEndPoint;
-import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
-import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.MacAddressAndUintStr;
 import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.MdLevelType;
 import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.MepIdType;
 import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.PriorityType;
@@ -128,46 +123,34 @@
     public boolean createMep(MdId mdName, MaIdShort maName, Mep mep)
             throws CfmConfigException {
         NetconfController controller = checkNotNull(handler().get(NetconfController.class));
-        NetconfSession session = controller.getDevicesMap()
-                        .get(handler().data().deviceId()).getSession();
+        NetconfSession session = checkNotNull(controller.getDevicesMap()
+                                .get(handler().data().deviceId()).getSession());
         MseaCfmNetconfService mseaCfmService =
                 checkNotNull(handler().get(MseaCfmNetconfService.class));
+        CfmMepService cfmMepService =
+                checkNotNull(handler().get(CfmMepService.class));
 
         MaintenanceAssociationEndPoint yangMep = buildYangMepFromApiMep(mep);
 
         CfmMdService cfmMdService = checkNotNull(handler().get(CfmMdService.class));
-        MaintenanceDomain md = cfmMdService.getMaintenanceDomain(mdName).get();
-        MaintenanceAssociation ma = cfmMdService.getMaintenanceAssociation(mdName, maName).get();
+        MseaCfmOpParam mseaCfmOpParam = getMaYangObject(cfmMdService, mdName, maName);
 
-        if (!ma.remoteMepIdList().contains(mep.mepId())) {
-            throw new CfmConfigException("Mep Id " + mep.mepId() +
-                    " is not present in the remote Mep list for MA " + ma.maId() +
-                    ". This is required for EA1000.");
-        } else if (md.mdNumericId() <= 0 || md.mdNumericId() > NUMERIC_ID_MAX) {
-            throw new CfmConfigException("Numeric id of MD " + mdName + " must"
-                    + " be between 1 and 64 inclusive for EA1000");
-        } else if (ma.maNumericId() <= 0 || ma.maNumericId() > NUMERIC_ID_MAX) {
-            throw new CfmConfigException("Numeric id of MA " + maName + " must"
-                    + " be between 1 and 64 inclusive for EA1000");
-        }
+        mseaCfmOpParam.mefCfm().maintenanceDomain().get(0)
+                .maintenanceAssociation().get(0).addToMaintenanceAssociationEndPoint(yangMep);
+        //Add this mepId to the list of remoteMeps on the device
+        mseaCfmOpParam.mefCfm().maintenanceDomain().get(0)
+                .maintenanceAssociation().get(0).addToRemoteMeps(MepIdType.of(mep.mepId().value()));
 
-        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
-        .MaintenanceAssociation yangMa = buildYangMaFromApiMa(ma);
-        yangMa.addToMaintenanceAssociationEndPoint(yangMep);
-
-        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm
-        .mefcfm.MaintenanceDomain yangMd = buildYangMdFromApiMd(md);
-        yangMd.addToMaintenanceAssociation(yangMa);
-
-        MefCfm mefCfm = new DefaultMefCfm();
-        mefCfm.addToMaintenanceDomain(yangMd);
-
-        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
-        mseaCfmOpParam.mefCfm(mefCfm);
+        //Add all of the existing meps on this MD/MA to the remote meps list
+        cfmMepService.getAllMeps(mdName, maName).forEach(m -> {
+            mseaCfmOpParam.mefCfm().maintenanceDomain().get(0)
+                    .maintenanceAssociation().get(0).addToRemoteMeps(MepIdType.of(m.mepId().value()));
+        });
         try {
             mseaCfmService.setMseaCfm(mseaCfmOpParam, session, DatastoreId.RUNNING);
             log.info("Created MEP {} on device {}", mdName + "/" + maName +
                     "/" + mep.mepId(), handler().data().deviceId());
+
             return true;
         } catch (NetconfException e) {
             log.error("Unable to create MEP {}/{}/{} on device {}",
@@ -177,11 +160,6 @@
     }
 
     @Override
-    public Collection<MepEntry> getAllMeps(MdId mdName, MaIdShort maName) throws CfmConfigException {
-        throw new UnsupportedOperationException("Not yet implemented");
-    }
-
-    @Override
     public MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId)
             throws CfmConfigException {
         NetconfController controller = checkNotNull(handler().get(NetconfController.class));
@@ -189,31 +167,20 @@
             throw new CfmConfigException("Device is not ready - connecting or "
                     + "disconnected for MEP " + mdName + "/" + maName + "/" + mepId);
         }
-        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        NetconfSession session = checkNotNull(controller.getDevicesMap()
+                                .get(handler().data().deviceId()).getSession());
         MseaCfmNetconfService mseaCfmService = checkNotNull(handler().get(MseaCfmNetconfService.class));
 
         try {
             MseaCfm mseacfm =
                     mseaCfmService.getMepFull(mdName, maName, mepId, session);
-            if (mseacfm != null && mseacfm.mefCfm() != null &&
-                    mseacfm.mefCfm().maintenanceDomain() != null) {
-                for (org.onosproject.yang.gen.v1.mseacfm.rev20160229.
-                        mseacfm.mefcfm.MaintenanceDomain replyMd :
-                                        mseacfm.mefCfm().maintenanceDomain()) {
-                    for (org.onosproject.yang.gen.v1.mseacfm.rev20160229.
-                            mseacfm.mefcfm.maintenancedomain.
-                            MaintenanceAssociation replyMa :
-                                            replyMd.maintenanceAssociation()) {
-                        for (MaintenanceAssociationEndPoint replyMep :
-                                    replyMa.maintenanceAssociationEndPoint()) {
-                            return buildApiMepEntryFromYangMep(
-                                    replyMep, handler().data().deviceId(), mdName, maName);
-                        }
-                    }
-                }
+            Collection<MepEntry> mepEntries = getMepEntriesFromYangResponse(mseacfm);
+            if (mepEntries == null || mepEntries.size() != 1) {
+                log.warn("Mep " + mepId + " not found on device " + handler().data().deviceId());
+                return null;
+            } else {
+                return mepEntries.stream().findFirst().get();
             }
-            log.warn("Mep " + mepId + " not found on device " + handler().data().deviceId());
-            return null;
         } catch (NetconfException e) {
             log.error("Unable to get MEP {}/{}/{} on device {}",
                     mdName, maName, mepId, handler().data().deviceId());
@@ -221,12 +188,37 @@
         }
     }
 
+    private Collection<MepEntry> getMepEntriesFromYangResponse(MseaCfm mseacfm)
+            throws CfmConfigException {
+
+        Collection<MepEntry> mepEntries = new ArrayList<>();
+        if (mseacfm == null || mseacfm.mefCfm() == null || mseacfm.mefCfm().maintenanceDomain() == null) {
+            return mepEntries;
+        }
+
+        for (org.onosproject.yang.gen.v1.mseacfm.rev20160229.
+                mseacfm.mefcfm.MaintenanceDomain replyMd:mseacfm.mefCfm().maintenanceDomain()) {
+            for (org.onosproject.yang.gen.v1.mseacfm.rev20160229.
+                    mseacfm.mefcfm.maintenancedomain.
+                    MaintenanceAssociation replyMa:replyMd.maintenanceAssociation()) {
+                for (MaintenanceAssociationEndPoint replyMep:replyMa.maintenanceAssociationEndPoint()) {
+                    mepEntries.add(buildApiMepEntryFromYangMep(
+                        replyMep, handler().data().deviceId(), replyMd, replyMa));
+                }
+            }
+        }
+        return mepEntries;
+    }
+
     @Override
-    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
+    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId,
+                    Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
 
         NetconfController controller = checkNotNull(handler().get(NetconfController.class));
-        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        NetconfSession session = checkNotNull(controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession());
         MseaCfmNetconfService mseaCfmService = checkNotNull(handler().get(MseaCfmNetconfService.class));
+        CfmMdService mdService = checkNotNull(handler().get(CfmMdService.class));
 
         MaintenanceAssociationEndPoint mep =
                 new DefaultMaintenanceAssociationEndPoint();
@@ -234,12 +226,34 @@
 
         org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
             .MaintenanceAssociation yangMa = new DefaultMaintenanceAssociation();
-        yangMa.maNameAndTypeCombo(MaNameUtil.getYangMaNameFromApiMaId(maName));
+        Short maNumericId = null;
+        try {
+            maNumericId =
+                    mdService.getMaintenanceAssociation(mdName, maName).get().maNumericId();
+            yangMa.id(maNumericId);
+        } catch (NoSuchElementException | IllegalArgumentException e) {
+            //The MA and/or MD have probably been deleted
+            // try to get numeric id values from oldMd
+            log.debug("Could not get MD/MA details from MD service during deletion of MEP {}." +
+                    "Continuing with values from event", new MepKeyId(mdName, maName, mepId));
+            yangMa.id(getMaNumericId(oldMd.get(), maName));
+        }
+
         yangMa.addToMaintenanceAssociationEndPoint(mep);
 
         org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.MaintenanceDomain yangMd =
             new DefaultMaintenanceDomain();
-        yangMd.mdNameAndTypeCombo(getYangMdNameFromApiMdId(mdName));
+        Short mdNumericId = null;
+        try {
+            mdNumericId = mdService.getMaintenanceDomain(mdName).get().mdNumericId();
+            yangMd.id(mdNumericId);
+        } catch (NoSuchElementException | IllegalArgumentException e) {
+            //The MD has probably been deleted
+            // try to get numeric id values from oldMd
+            log.debug("Could not get MD details from MD service during deletion of MEP {}." +
+                    "Continuing with values from event", new MepKeyId(mdName, maName, mepId));
+            yangMd.id(oldMd.get().mdNumericId());
+        }
         yangMd.addToMaintenanceAssociation(yangMa);
 
         MefCfm mefCfm = new DefaultMefCfm();
@@ -254,14 +268,281 @@
                     "/" + mepId, handler().data().deviceId());
             return true;
         } catch (NetconfException e) {
-            log.error("Unable to delete MEP {}/{}/{} on device {}",
-                    mdName, maName, mepId, handler().data().deviceId());
+            log.error("Unable to delete MEP {} ({}) on device {}",
+                    mdName + "/" + maName + "/" + mepId,
+                    mdNumericId + "/" + maNumericId, handler().data().deviceId(), e);
             throw new CfmConfigException("Unable to delete MEP :" + e.getMessage());
         }
 
     }
 
     @Override
+    public boolean createMdOnDevice(MdId mdId) throws CfmConfigException {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = checkNotNull(controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession());
+
+        CfmMdService cfmMdService = checkNotNull(handler().get(CfmMdService.class));
+        MaintenanceDomain md = cfmMdService.getMaintenanceDomain(mdId).get();
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm
+                .mefcfm.MaintenanceDomain yangMd = buildYangMdFromApiMd(md);
+
+        if (md.mdNumericId() <= 0 || md.mdNumericId() > NUMERIC_ID_MAX) {
+            throw new CfmConfigException("Numeric id of MD " + mdId + " must"
+                    + " be between 1 and 64 inclusive for EA1000");
+        }
+
+        for (MaintenanceAssociation ma:md.maintenanceAssociationList()) {
+            if (ma.maNumericId() <= 0 || ma.maNumericId() > NUMERIC_ID_MAX) {
+                throw new CfmConfigException("Numeric id of MA " + mdId + " must"
+                        + " be between 1 and 64 inclusive for EA1000");
+            }
+            org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
+                    .MaintenanceAssociation yangMa = buildYangMaFromApiMa(ma);
+            yangMd.addToMaintenanceAssociation(yangMa);
+        }
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(yangMd);
+
+        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
+        mseaCfmOpParam.mefCfm(mefCfm);
+
+        MseaCfmNetconfService mseaCfmService =
+                checkNotNull(handler().get(MseaCfmNetconfService.class));
+
+        try {
+            boolean created = mseaCfmService.setMseaCfm(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            log.info("Created MD {} on device {}", mdId.mdName(),
+                    handler().data().deviceId());
+            return created;
+        } catch (NetconfException e) {
+            log.error("Unable to create MD {} on device {}",
+                    mdId.mdName(), handler().data().deviceId());
+            throw new CfmConfigException("Unable to create MD :" + e.getMessage());
+        }
+    }
+
+    @Override
+    public boolean createMaOnDevice(MdId mdId, MaIdShort maId) throws CfmConfigException {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = checkNotNull(controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession());
+
+        CfmMdService mdService = checkNotNull(handler().get(CfmMdService.class));
+        MseaCfmOpParam mseaCfmOpParam = getMaYangObject(mdService, mdId, maId);
+        MseaCfmNetconfService mseaCfmService =
+                checkNotNull(handler().get(MseaCfmNetconfService.class));
+
+        try {
+            boolean created = mseaCfmService.setMseaCfm(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            log.info("Created MA {} on device {}", mdId.mdName() + "/" + maId.maName(),
+                    handler().data().deviceId());
+            return created;
+        } catch (NetconfException e) {
+            log.error("Unable to create MA {} on device {}",
+                    mdId.mdName() + "/" + maId.maName(), handler().data().deviceId());
+            throw new CfmConfigException("Unable to create MA :" + e.getMessage());
+        }
+    }
+
+    private static MseaCfmOpParam getMaYangObject(CfmMdService cfmMdService,
+                        MdId mdName, MaIdShort maName) throws CfmConfigException {
+        MaintenanceDomain md = cfmMdService.getMaintenanceDomain(mdName).get();
+        MaintenanceAssociation ma = cfmMdService.getMaintenanceAssociation(mdName, maName).get();
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
+                .MaintenanceAssociation yangMa = buildYangMaFromApiMa(ma);
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm
+                .mefcfm.MaintenanceDomain yangMd = buildYangMdFromApiMd(md);
+        yangMd.addToMaintenanceAssociation(yangMa);
+
+        if (md.mdNumericId() <= 0 || md.mdNumericId() > NUMERIC_ID_MAX) {
+            throw new CfmConfigException("Numeric id of MD " + mdName + " must"
+                    + " be between 1 and 64 inclusive for EA1000");
+        } else if (ma.maNumericId() <= 0 || ma.maNumericId() > NUMERIC_ID_MAX) {
+            throw new CfmConfigException("Numeric id of MA " + maName + " must"
+                    + " be between 1 and 64 inclusive for EA1000");
+        }
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(yangMd);
+
+        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
+        mseaCfmOpParam.mefCfm(mefCfm);
+
+        return mseaCfmOpParam;
+    }
+
+    @Override
+    public boolean deleteMdOnDevice(MdId mdId, Optional<MaintenanceDomain> oldMd)
+            throws CfmConfigException {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession();
+
+        //First check if this MD is known to ONOS if it is does it have MAs and
+        // do they have any Meps known to ONOS. If there are Meps throw an exception -
+        // the Meps should have been deleted first
+        //If there are none known to ONOS we do not check for Meps on the actual device
+        // - there might might be some orphaned ones down there - we want to delete these
+        //FIXME: When CfmMepService is extended to be persistent come back and enable check
+        CfmMdService mdService = checkNotNull(handler().get(CfmMdService.class));
+        MseaCfmNetconfService mseaCfmService =
+                checkNotNull(handler().get(MseaCfmNetconfService.class));
+
+        MdNameAndTypeCombo mdName = getYangMdNameFromApiMdId(mdId);
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.MaintenanceDomain yangMd =
+                new DefaultMaintenanceDomain();
+        Short mdNumericId = null;
+        try {
+            mdNumericId = mdService.getMaintenanceDomain(mdId).get().mdNumericId();
+            yangMd.id(mdNumericId);
+        } catch (NoSuchElementException e) {
+            yangMd.id(oldMd.get().mdNumericId());
+        }
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(yangMd);
+
+        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
+        mseaCfmOpParam.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMd(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            log.info("Deleted MD {} on device {}", mdName,
+                    handler().data().deviceId());
+            return deleted;
+        } catch (NetconfException e) {
+            log.error("Unable to delete MD {} ({}) on device {}",
+                    mdName, mdNumericId, handler().data().deviceId());
+            throw new CfmConfigException("Unable to delete MD :" + e.getMessage());
+        }
+
+    }
+
+    @Override
+    public boolean deleteMaOnDevice(MdId mdId, MaIdShort maId, Optional<MaintenanceDomain> oldMd)
+            throws CfmConfigException {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession();
+
+        CfmMdService mdService = checkNotNull(handler().get(CfmMdService.class));
+
+        MseaCfmNetconfService mseaCfmService =
+                checkNotNull(handler().get(MseaCfmNetconfService.class));
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
+                .MaintenanceAssociation yangMa = new DefaultMaintenanceAssociation();
+        Short maNumericId = null;
+        try {
+            maNumericId =
+                    mdService.getMaintenanceAssociation(mdId, maId).get().maNumericId();
+            yangMa.id(maNumericId);
+        } catch (NoSuchElementException e) {
+            yangMa.id(getMaNumericId(oldMd.get(), maId));
+        }
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.MaintenanceDomain yangMd =
+                new DefaultMaintenanceDomain();
+        Short mdNumericId = null;
+        try {
+            mdNumericId = mdService.getMaintenanceDomain(mdId).get().mdNumericId();
+            yangMd.id(mdNumericId);
+        } catch (NoSuchElementException e) {
+            yangMd.id(oldMd.get().mdNumericId());
+        }
+        yangMd.addToMaintenanceAssociation(yangMa);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(yangMd);
+
+        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
+        mseaCfmOpParam.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMa(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            log.info("Deleted MA {} ({})on device {}", mdId.mdName() + "/" + maId.maName(),
+                    mdNumericId + "/" + maNumericId, handler().data().deviceId());
+            return deleted;
+        } catch (NetconfException e) {
+            log.error("Unable to delete MA {} ({}) on device {}",
+                    mdId.mdName() + "/" + maId.maName(),
+                    mdNumericId + "/" + maNumericId, handler().data().deviceId());
+            throw new CfmConfigException("Unable to delete MA :" + e.getMessage());
+        }
+    }
+
+    @Override
+    public boolean createMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException {
+        return crDelMaRemoteMep(mdId, maId, remoteMep, true);
+    }
+
+    @Override
+    public boolean deleteMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException {
+        return crDelMaRemoteMep(mdId, maId, remoteMep, false);
+    }
+
+    private boolean crDelMaRemoteMep(MdId mdId, MaIdShort maId, MepId remoteMep,
+                                     boolean isCreate) throws CfmConfigException {
+        NetconfController controller =
+                checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap()
+                .get(handler().data().deviceId()).getSession();
+
+        CfmMdService mdService = checkNotNull(handler().get(CfmMdService.class));
+
+        Short mdNumericId = mdService.getMaintenanceDomain(mdId).get().mdNumericId();
+        Short maNumericId =
+                mdService.getMaintenanceAssociation(mdId, maId).get().maNumericId();
+
+        MseaCfmNetconfService mseaCfmService =
+                checkNotNull(handler().get(MseaCfmNetconfService.class));
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain
+                .MaintenanceAssociation yangMa = new DefaultMaintenanceAssociation();
+        yangMa.id(maNumericId);
+        yangMa.addToRemoteMeps(MepIdType.of(remoteMep.value()));
+
+        org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.MaintenanceDomain yangMd =
+                new DefaultMaintenanceDomain();
+        yangMd.id(mdNumericId);
+        yangMd.addToMaintenanceAssociation(yangMa);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(yangMd);
+
+        MseaCfmOpParam mseaCfmOpParam = new MseaCfmOpParam();
+        mseaCfmOpParam.mefCfm(mefCfm);
+
+        try {
+            boolean result = false;
+            if (isCreate) {
+                result = mseaCfmService.setMseaCfm(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            } else {
+                result = mseaCfmService.deleteMseaMaRMep(mseaCfmOpParam, session, DatastoreId.RUNNING);
+            }
+            log.info("{} Remote MEP {} in MA {} on device {}", isCreate ? "Created" : "Deleted",
+                    remoteMep, mdId.mdName() + "/" + maId.maName(), handler().data().deviceId());
+            return result;
+        } catch (NetconfException e) {
+            log.error("Unable to {} RemoteMep {} in MA {} on device {}",
+                    isCreate ? "create" : "delete", remoteMep, mdId.mdName() + "/" + maId.maName(),
+                    handler().data().deviceId());
+            throw new CfmConfigException("Unable to " + (isCreate ? "create" : "delete")
+                    + " Remote Mep:" + e.getMessage());
+        }
+    }
+
+
+    @Override
     public void transmitLoopback(MdId mdName, MaIdShort maName, MepId mepId,
             MepLbCreate lbCreate) throws CfmConfigException {
         NetconfController controller =
@@ -361,7 +642,7 @@
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
-    private org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm
+    private static org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm
             .MaintenanceDomain buildYangMdFromApiMd(MaintenanceDomain md)
             throws CfmConfigException {
         MdNameAndTypeCombo mdName = getYangMdNameFromApiMdId(md.mdId());
@@ -375,44 +656,7 @@
         return mdYang;
     }
 
-    protected static MdNameAndTypeCombo getYangMdNameFromApiMdId(MdId mdId)
-            throws CfmConfigException {
-        MdNameAndTypeCombo mdName;
-        if (mdId instanceof MdIdDomainName) {
-            boolean isIpAddr = false;
-            try {
-                if (IpAddress.valueOf(mdId.mdName()) != null) {
-                    isIpAddr = true;
-                }
-            } catch (IllegalArgumentException e) {
-                //continue
-            }
-            if (isIpAddr) {
-                mdName = new DefaultNameDomainName();
-                ((DefaultNameDomainName) mdName).nameDomainName(NameDomainNameUnion.of(
-                                org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.ietfinettypes.
-                                IpAddress.fromString(mdId.mdName())));
-            } else {
-                mdName = new DefaultNameDomainName();
-                ((DefaultNameDomainName) mdName).nameDomainName(NameDomainNameUnion
-                                    .of(DomainName.fromString(mdId.mdName())));
-            }
-        } else if (mdId instanceof MdIdMacUint) {
-            mdName = new DefaultMacAddressAndUint();
-            ((DefaultMacAddressAndUint) mdName).nameMacAddressAndUint(MacAddressAndUintStr.fromString(mdId.mdName()));
-        } else if (mdId instanceof MdIdNone) {
-            mdName = new DefaultNameNone();
-        } else if (mdId instanceof MdIdCharStr) {
-            mdName = new DefaultNameCharacterString();
-            ((DefaultNameCharacterString) mdName).name(Identifier45.fromString(mdId.mdName()));
-        } else {
-            throw new CfmConfigException("Unexpected error creating MD " +
-                    mdId.getClass().getSimpleName());
-        }
-        return mdName;
-    }
-
-    private org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm
+    private static org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm
             .maintenancedomain.MaintenanceAssociation buildYangMaFromApiMa(
                         MaintenanceAssociation apiMa) throws CfmConfigException {
 
@@ -422,12 +666,6 @@
                 .MaintenanceAssociation yamgMa = new DefaultMaintenanceAssociation();
         yamgMa.maNameAndTypeCombo(maName);
 
-        if (apiMa.remoteMepIdList() == null || apiMa.remoteMepIdList().size() < REMOTEMEPLIST_MIN_COUNT
-                || apiMa.remoteMepIdList().size() > REMOTEMEPLIST_MAX_COUNT) {
-            throw new CfmConfigException("EA1000 requires between " +
-                    REMOTEMEPLIST_MIN_COUNT + " and " + REMOTEMEPLIST_MAX_COUNT +
-                    " remote meps in an MA");
-        }
         for (MepId rmep:apiMa.remoteMepIdList()) {
             yamgMa.addToRemoteMeps(MepIdType.of(rmep.id()));
         }
@@ -486,7 +724,7 @@
         return yamgMa;
     }
 
-    private MaintenanceAssociationEndPoint buildYangMepFromApiMep(Mep mep)
+    private static MaintenanceAssociationEndPoint buildYangMepFromApiMep(Mep mep)
             throws CfmConfigException {
         MaintenanceAssociationEndPoint mepBuilder =
                                     new DefaultMaintenanceAssociationEndPoint();
@@ -515,14 +753,19 @@
 
     private MepEntry buildApiMepEntryFromYangMep(
             MaintenanceAssociationEndPoint yangMep, DeviceId deviceId,
-            MdId mdName, MaIdShort maName) throws CfmConfigException {
+            org.onosproject.yang.gen.v1.mseacfm.rev20160229.
+                    mseacfm.mefcfm.MaintenanceDomain replyMd,
+            org.onosproject.yang.gen.v1.mseacfm.rev20160229.
+                    mseacfm.mefcfm.maintenancedomain.MaintenanceAssociation replyMa)
+            throws CfmConfigException {
         MepId mepId = MepId.valueOf((short) yangMep.mepIdentifier().uint16());
         MepEntry.MepEntryBuilder builder = DefaultMepEntry.builder(mepId,
                 deviceId,
                 (yangMep.yangAutoPrefixInterface() == InterfaceEnum.ETH0) ?
                         PortNumber.portNumber(0) : PortNumber.portNumber(1),
                 MepDirection.DOWN_MEP, //Always down for EA1000
-                mdName, maName);
+                getApiMdIdFromYangMdName(replyMd.mdNameAndTypeCombo()),
+                getApiMaIdFromYangMaName(replyMa.maNameAndTypeCombo()));
 
         if (yangMep.loopback() != null) {
             MepLbEntryBuilder lbEntryBuilder = DefaultMepLbEntry.builder();
@@ -614,4 +857,10 @@
         }
         return rmepBuilder.build();
     }
+
+    private static short getMaNumericId(MaintenanceDomain md, MaIdShort maId) {
+        return md.maintenanceAssociationList().stream()
+                .filter(ma -> maId.equals(ma.maId()))
+                .findFirst().get().maNumericId();
+    }
 }
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
index 1bc32ca..cbe41ba 100644
--- 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
@@ -18,6 +18,7 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
 import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfException;
@@ -29,6 +30,8 @@
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitlinktrace.TransmitLinktraceOutput;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.transmitloopback.TransmitLoopbackInput;
 
+import java.util.Optional;
+
 /**
  * Extension of mseaCfmService to include NETCONF sessions.
  *
@@ -65,6 +68,19 @@
     MseaCfm getMepFull(MdId mdId, MaIdShort maId, MepId mepId,
             NetconfSession session) throws NetconfException;
 
+
+    /**
+     * Returns set of all MepIds from one Md or Ma or all.
+     *
+     * @param mdIdOptional An MdId to filter by, or empty to select all
+     * @param maIdOptional An MaId to filter by, or empty to select all
+     * @param session An active NETCONF session
+     * @param targetDs one of running, candidate or startup
+     * @return mseaCfm
+     * @throws NetconfException if the session has any error
+     */
+    MseaCfm getMepIds(Optional<MdId> mdIdOptional, Optional<MaIdShort> maIdOptional,
+                      NetconfSession session, DatastoreId targetDs) throws NetconfException;
     /**
      * Returns attributes of DM.
      *
@@ -102,10 +118,52 @@
      * @param targetDs one of running, candidate or startup
      * @return Boolean to indicate success or failure
      * @throws NetconfException if the session has any error
+     * @throws CfmConfigException if the Cfm config has any error
      */
     boolean deleteMseaMep(MseaCfmOpParam mseaCfm, NetconfSession session,
-                            DatastoreId targetDs) throws NetconfException;
+                            DatastoreId targetDs) throws NetconfException, CfmConfigException;
 
+    /**
+     * Deletes named Ma of mseaCfm.
+     * Expects to see a list of Mas
+     *
+     * @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
+     * @throws CfmConfigException if the Cfm config has any error
+     */
+    boolean deleteMseaMa(MseaCfmOpParam mseaCfm, NetconfSession session,
+                            DatastoreId targetDs) throws NetconfException, CfmConfigException;
+
+    /**
+     * Deletes a remote Mep from an MA.
+     * Expects one or more RMeps
+     *
+     * @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
+     * @throws CfmConfigException if the Cfm config has any error
+     */
+    boolean deleteMseaMaRMep(MseaCfmOpParam mseaCfm, NetconfSession session,
+                         DatastoreId targetDs) throws NetconfException, CfmConfigException;
+
+    /**
+     * Deletes named Md of mseaCfm.
+     * Expects to see a list of Mds
+     *
+     * @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
+     * @throws CfmConfigException if the Cfm config has any error
+     */
+    boolean deleteMseaMd(MseaCfmOpParam mseaCfm, NetconfSession session,
+                            DatastoreId targetDs) throws NetconfException, CfmConfigException;
 
     /**
      * Deletes named delay measurements of mseaCfm.
@@ -116,9 +174,10 @@
      * @param targetDs one of running, candidate or startup
      * @return Boolean to indicate success or failure
      * @throws NetconfException if the session has any error
+     * @throws CfmConfigException if the Cfm config has any error
      */
     boolean deleteMseaCfmDm(MseaCfmOpParam mseaCfm, NetconfSession session,
-                       DatastoreId targetDs) throws NetconfException;
+                       DatastoreId targetDs) throws NetconfException, CfmConfigException;
 
     /**
      * Service interface of transmitLoopback.
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
index c39625b..692e9a8 100644
--- 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
@@ -25,6 +25,7 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
 import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfException;
@@ -42,6 +43,7 @@
 import org.onosproject.yang.gen.v1.mseasoampm.rev20160229.mseasoampm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.AugmentedMseaCfmMaintenanceAssociationEndPoint;
 import org.onosproject.yang.gen.v1.mseasoampm.rev20160229.mseasoampm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.DefaultAugmentedMseaCfmMaintenanceAssociationEndPoint;
 import org.onosproject.yang.gen.v1.mseasoampm.rev20160229.mseasoampm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.augmentedmseacfmmaintenanceassociationendpoint.delaymeasurements.DelayMeasurement;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.MepIdType;
 import org.onosproject.yang.model.DefaultModelObjectData;
 import org.onosproject.yang.model.ModelConverter;
 import org.onosproject.yang.model.ModelObject;
@@ -54,6 +56,7 @@
 import org.onosproject.yang.runtime.DefaultCompositeStream;
 
 import java.io.ByteArrayInputStream;
+import java.util.Optional;
 import java.util.regex.Pattern;
 
 /**
@@ -77,6 +80,19 @@
     @Deprecated
     protected static final Pattern REGEX_EMPTY_LAST_DEFECT_SENT =
             Pattern.compile("(<msea-soam-fm:last-defect-sent)[ ]?(/>)", Pattern.DOTALL);
+    public static final String MEF_CFM = "mef-cfm";
+    public static final String MAINTENANCE_DOMAIN = "maintenance-domain";
+    public static final String ID = "id";
+    public static final String MAINTENANCE_ASSOCIATION = "maintenance-association";
+    public static final String TRANSMIT_LOOPBACK = "transmit-loopback";
+    public static final String ABORT_LOOPBACK = "abort-loopback";
+    public static final String MAINTENANCE_ASSOCIATION_END_POINT = "maintenance-association-end-point";
+    public static final String MEP_ID = "mep-id";
+    public static final String DELAY_MEASUREMENTS = "delay-measurements";
+    public static final String DELAY_MEASUREMENT = "delay-measurement";
+    public static final String DM_ID = "dm-id";
+    public static final String MEP_IDENTIFIER = "mep-identifier";
+    public static final String REMOTE_MEPS = "remote-meps";
 
     @Activate
     public void activate() {
@@ -153,6 +169,38 @@
     }
 
     @Override
+    public MseaCfm getMepIds(Optional<MdId> mdIdOptional, Optional<MaIdShort> maIdOptional,
+             NetconfSession session, DatastoreId targetDs) throws NetconfException {
+
+        ModelObjectData.Builder moQueryBldr = DefaultModelObjectData.builder();
+
+        ArrayList annotations = new ArrayList<AnnotatedNodeInfo>();
+        String xmlQueryStr = encodeMoToXmlStr(moQueryBldr.build(), annotations);
+
+        log.debug("Sending <get> for full MEP" +
+                " query on NETCONF session " + session.getSessionId() +
+                ":\n" + xmlQueryStr);
+
+        String xmlResult = session.get(xmlQueryStr, null);
+        xmlResult = removeRpcReplyData(xmlResult);
+        xmlResult = removeEmptyActiveDefects(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(MdId mdName, MaIdShort maName, MepId mepId,
                              SoamId dmId, DmEntryParts parts, NetconfSession session)
                     throws NetconfException {
@@ -190,7 +238,7 @@
 
     @Override
     public boolean deleteMseaCfmDm(MseaCfmOpParam mseaCfm, NetconfSession session,
-                            DatastoreId targetDs) throws NetconfException {
+                            DatastoreId targetDs) throws NetconfException, CfmConfigException {
 
         ModelObjectData mseCfmDmList = DefaultModelObjectData.builder()
                 .addModelObject((ModelObject) mseaCfm).build();
@@ -198,7 +246,13 @@
         ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
         if (mseaCfm != null && mseaCfm.mefCfm() != null) {
             for (MaintenanceDomain md:mseaCfm.mefCfm().maintenanceDomain()) {
+                if (md.id() == 0) {
+                    throw new CfmConfigException("An MD numeric ID must be given");
+                }
                 for (MaintenanceAssociation ma:md.maintenanceAssociation()) {
+                    if (ma.id() == 0) {
+                        throw new CfmConfigException("An MA numeric ID must be given");
+                    }
                     for (MaintenanceAssociationEndPoint mep:ma.maintenanceAssociationEndPoint()) {
                         AugmentedMseaCfmMaintenanceAssociationEndPoint mepAugment =
                             mep.augmentation(DefaultAugmentedMseaCfmMaintenanceAssociationEndPoint.class);
@@ -206,16 +260,16 @@
                             for (DelayMeasurement dms:mepAugment.delayMeasurements().delayMeasurement()) {
                                 ResourceId.Builder ridBuilder = ResourceId.builder()
                                         .addBranchPointSchema("/", null)
-                                        .addBranchPointSchema("mef-cfm", MSEA_CFM_NS)
-                                        .addBranchPointSchema("maintenance-domain", MSEA_CFM_NS)
-                                        .addKeyLeaf("id", MSEA_CFM_NS, md.id())
-                                        .addBranchPointSchema("maintenance-association", MSEA_CFM_NS)
-                                        .addKeyLeaf("id", MSEA_CFM_NS, ma.id())
-                                        .addBranchPointSchema("maintenance-association-end-point", MSEA_CFM_NS)
-                                        .addKeyLeaf("mep-id", MSEA_CFM_NS, mep.mepIdentifier())
-                                        .addBranchPointSchema("delay-measurements", MSEA_CFM_PM_NS)
-                                        .addBranchPointSchema("delay-measurement", MSEA_CFM_PM_NS)
-                                        .addKeyLeaf("dm-id", MSEA_CFM_PM_NS, mep.mepIdentifier());
+                                        .addBranchPointSchema(MEF_CFM, MSEA_CFM_NS)
+                                        .addBranchPointSchema(MAINTENANCE_DOMAIN, MSEA_CFM_NS)
+                                        .addKeyLeaf(ID, MSEA_CFM_NS, md.id())
+                                        .addBranchPointSchema(MAINTENANCE_ASSOCIATION, MSEA_CFM_NS)
+                                        .addKeyLeaf(ID, MSEA_CFM_NS, ma.id())
+                                        .addBranchPointSchema(MAINTENANCE_ASSOCIATION_END_POINT, MSEA_CFM_NS)
+                                        .addKeyLeaf(MEP_ID, MSEA_CFM_NS, mep.mepIdentifier())
+                                        .addBranchPointSchema(DELAY_MEASUREMENTS, MSEA_CFM_PM_NS)
+                                        .addBranchPointSchema(DELAY_MEASUREMENT, MSEA_CFM_PM_NS)
+                                        .addKeyLeaf(DM_ID, MSEA_CFM_PM_NS, mep.mepIdentifier());
                                 AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
                                         .resourceId(ridBuilder.build())
                                         .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
@@ -233,7 +287,7 @@
 
     @Override
     public boolean deleteMseaMep(MseaCfmOpParam mseaCfm, NetconfSession session,
-                                   DatastoreId targetDs) throws NetconfException {
+                                   DatastoreId targetDs) throws NetconfException, CfmConfigException {
 
         ModelObjectData mseCfmMepList = DefaultModelObjectData.builder()
                 .addModelObject((ModelObject) mseaCfm.mefCfm()).build();
@@ -241,15 +295,100 @@
         ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
         if (mseaCfm.mefCfm() != null) {
             for (MaintenanceDomain md:mseaCfm.mefCfm().maintenanceDomain()) {
+                if (md.id() == 0) {
+                    throw new CfmConfigException("An MD numeric ID must be given");
+                }
                 for (MaintenanceAssociation ma:md.maintenanceAssociation()) {
+                    if (ma.id() == 0) {
+                        throw new CfmConfigException("An MA numeric ID must be given");
+                    }
                     for (MaintenanceAssociationEndPoint mep:ma.maintenanceAssociationEndPoint()) {
                         ResourceId.Builder ridBuilder = ResourceId.builder()
                                 .addBranchPointSchema("/", null)
-                                .addBranchPointSchema("mef-cfm", MSEA_CFM_NS)
-                                .addBranchPointSchema("maintenance-domain", MSEA_CFM_NS)
-                                .addBranchPointSchema("maintenance-association", MSEA_CFM_NS)
-                                .addBranchPointSchema("maintenance-association-end-point", MSEA_CFM_NS)
-                                .addKeyLeaf("mep-identifier", MSEA_CFM_NS, mep.mepIdentifier().uint16());
+                                .addBranchPointSchema(MEF_CFM, MSEA_CFM_NS)
+                                .addBranchPointSchema(MAINTENANCE_DOMAIN, MSEA_CFM_NS)
+                                .addKeyLeaf(ID, MSEA_CFM_NS, md.id())
+                                .addBranchPointSchema(MAINTENANCE_ASSOCIATION, MSEA_CFM_NS)
+                                .addKeyLeaf(ID, MSEA_CFM_NS, ma.id())
+                                .addBranchPointSchema(MAINTENANCE_ASSOCIATION_END_POINT, MSEA_CFM_NS)
+                                .addKeyLeaf(MEP_IDENTIFIER, MSEA_CFM_NS, mep.mepIdentifier().uint16());
+                        AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                                .resourceId(ridBuilder.build())
+                                .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                                .build();
+                        anis.add(ani);
+                    }
+                }
+            }
+        }
+
+        return setNetconfObject(mseCfmMepList, session, targetDs, anis);
+    }
+
+    @Override
+    public boolean deleteMseaMa(MseaCfmOpParam mseaCfm, NetconfSession session,
+                                 DatastoreId targetDs) throws NetconfException, CfmConfigException {
+
+        ModelObjectData mseCfmMepList = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaCfm.mefCfm()).build();
+
+        ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
+        if (mseaCfm != null && mseaCfm.mefCfm() != null) {
+            for (MaintenanceDomain md:mseaCfm.mefCfm().maintenanceDomain()) {
+                if (md.id() == 0) {
+                    throw new CfmConfigException("An MD numeric ID must be given");
+                }
+                for (MaintenanceAssociation ma:md.maintenanceAssociation()) {
+                    if (ma.id() == 0) {
+                        throw new CfmConfigException("An MA numeric ID must be given");
+                    }
+                    ResourceId.Builder ridBuilder = ResourceId.builder()
+                            .addBranchPointSchema("/", null)
+                            .addBranchPointSchema(MEF_CFM, MSEA_CFM_NS)
+                            .addBranchPointSchema(MAINTENANCE_DOMAIN, MSEA_CFM_NS)
+                            .addKeyLeaf(ID, MSEA_CFM_NS, md.id())
+                            .addBranchPointSchema(MAINTENANCE_ASSOCIATION, MSEA_CFM_NS)
+                            .addKeyLeaf(ID, MSEA_CFM_NS, ma.id());
+
+                    AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                    .resourceId(ridBuilder.build())
+                    .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                    .build();
+                    anis.add(ani);
+                }
+            }
+        }
+
+        return setNetconfObject(mseCfmMepList, session, targetDs, anis);
+    }
+
+    @Override
+    public boolean deleteMseaMaRMep(MseaCfmOpParam mseaCfm, NetconfSession session,
+                                 DatastoreId targetDs) throws NetconfException, CfmConfigException {
+
+        ModelObjectData mseCfmMepList = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaCfm.mefCfm()).build();
+
+        ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
+        if (mseaCfm != null && mseaCfm.mefCfm() != null) {
+            for (MaintenanceDomain md:mseaCfm.mefCfm().maintenanceDomain()) {
+                if (md.id() == 0) {
+                    throw new CfmConfigException("An MD numeric ID must be given");
+                }
+                for (MaintenanceAssociation ma:md.maintenanceAssociation()) {
+                    if (ma.id() == 0) {
+                        throw new CfmConfigException("An MA numeric ID must be given");
+                    }
+                    for (MepIdType rmep:ma.remoteMeps()) {
+                        ResourceId.Builder ridBuilder = ResourceId.builder()
+                                .addBranchPointSchema("/", null)
+                                .addBranchPointSchema(MEF_CFM, MSEA_CFM_NS)
+                                .addBranchPointSchema(MAINTENANCE_DOMAIN, MSEA_CFM_NS)
+                                .addKeyLeaf(ID, MSEA_CFM_NS, md.id())
+                                .addBranchPointSchema(MAINTENANCE_ASSOCIATION, MSEA_CFM_NS)
+                                .addKeyLeaf(ID, MSEA_CFM_NS, ma.id())
+                                .addLeafListBranchPoint(REMOTE_MEPS, MSEA_CFM_NS,
+                                        Integer.valueOf(rmep.uint16()));
                         AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
                                 .resourceId(ridBuilder.build())
                                 .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
@@ -264,6 +403,35 @@
     }
 
 
+    @Override
+    public boolean deleteMseaMd(MseaCfmOpParam mseaCfm, NetconfSession session,
+                                DatastoreId targetDs) throws NetconfException, CfmConfigException {
+
+        ModelObjectData mseCfmMepList = DefaultModelObjectData.builder()
+                .addModelObject((ModelObject) mseaCfm.mefCfm()).build();
+
+        ArrayList anis = new ArrayList<AnnotatedNodeInfo>();
+        if (mseaCfm != null && mseaCfm.mefCfm() != null) {
+            for (MaintenanceDomain md:mseaCfm.mefCfm().maintenanceDomain()) {
+                if (md.id() == 0) {
+                    throw new CfmConfigException("An MD numeric ID must be given");
+                }
+                ResourceId.Builder ridBuilder = ResourceId.builder()
+                        .addBranchPointSchema("/", null)
+                        .addBranchPointSchema(MEF_CFM, MSEA_CFM_NS)
+                        .addBranchPointSchema(MAINTENANCE_DOMAIN, MSEA_CFM_NS)
+                        .addKeyLeaf(ID, MSEA_CFM_NS, md.id());
+                AnnotatedNodeInfo ani = DefaultAnnotatedNodeInfo.builder()
+                        .resourceId(ridBuilder.build())
+                        .addAnnotation(new DefaultAnnotation(NC_OPERATION, OP_DELETE))
+                        .build();
+                anis.add(ani);
+            }
+        }
+
+        return setNetconfObject(mseCfmMepList, session, targetDs, anis);
+    }
+
     /**
      * Call RPCs on the device through NETCONF.
      */
@@ -275,7 +443,7 @@
                 .addModelObject((ModelObject) inputVar).build();
 
         customRpcNetconf(transLoopbackMo,
-                "transmit-loopback", session);
+                TRANSMIT_LOOPBACK, session);
     }
 
     @Override
@@ -284,7 +452,7 @@
         ModelObjectData abortLoopbackMo = DefaultModelObjectData.builder()
                 .addModelObject((ModelObject) inputVar).build();
 
-        customRpcNetconf(abortLoopbackMo, "abort-loopback", session);
+        customRpcNetconf(abortLoopbackMo, ABORT_LOOPBACK, session);
     }
 
     @Override
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MaNameUtil.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MaNameUtil.java
index 16e9686..e18abe6 100644
--- a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MaNameUtil.java
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MaNameUtil.java
@@ -30,11 +30,14 @@
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.DefaultNameRfc2685VpnId;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.DefaultNameUint16;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.DefaultNameY1731Icc;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.NameCharacterString;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.nameprimaryvid.NamePrimaryVidUnion;
 import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
 
 /**
- * This is a workaround for Checkstyle issue.
+ * Utility for translating between Maintenance Association names in the CFM API model and the device YANG.
+ *
+ * This has to be in a separate file as a workaround for Checkstyle issue.
  * https://github.com/checkstyle/checkstyle/issues/3850
  * There are two types of DefaultNameCharacterString - one for MA and another for MD
  * Putting both together in a file means that the full path has to be given which
@@ -46,6 +49,12 @@
         //Hidden
     }
 
+    /**
+     * Convert CFM API MA identifier to the YANG model MA identifier.
+     * @param maId Maintenance Association ID in CFM API
+     * @return Maintenance Association ID in YANG API
+     * @throws CfmConfigException If there's a problem with the name
+     */
     public static MaNameAndTypeCombo getYangMaNameFromApiMaId(MaIdShort maId)
             throws CfmConfigException {
         MaNameAndTypeCombo maName;
@@ -70,4 +79,52 @@
         }
         return maName;
     }
+
+    /**
+     * Convert YANG API MA identifier to the CFM API MA identifier.
+     * @param nameAndTypeCombo Maintenance Association ID in YANG API
+     * @return Maintenance Association ID in CFM API
+     */
+    public static MaIdShort getApiMaIdFromYangMaName(MaNameAndTypeCombo nameAndTypeCombo) {
+        MaIdShort maId;
+        if (nameAndTypeCombo instanceof DefaultNameCharacterString) {
+            maId = MaIdCharStr.asMaId(
+                    ((DefaultNameCharacterString) nameAndTypeCombo).name().string());
+        } else if (nameAndTypeCombo instanceof DefaultNamePrimaryVid) {
+            if (((DefaultNamePrimaryVid) nameAndTypeCombo).namePrimaryVid().enumeration() != null) {
+                maId = MaIdPrimaryVid.asMaId(
+                        ((DefaultNamePrimaryVid) nameAndTypeCombo).namePrimaryVid().enumeration().name());
+            } else if (((DefaultNamePrimaryVid) nameAndTypeCombo).namePrimaryVid().vlanIdType() != null) {
+                maId = MaIdPrimaryVid.asMaId(
+                        ((DefaultNamePrimaryVid) nameAndTypeCombo).namePrimaryVid().vlanIdType().uint16());
+            } else {
+                throw new IllegalArgumentException("Unexpected primaryVid for " +
+                        "MaNameAndTypeCombo: " + nameAndTypeCombo.toString());
+            }
+        } else if (nameAndTypeCombo instanceof DefaultNameUint16) {
+            maId = MaId2Octet.asMaId(((DefaultNameUint16) nameAndTypeCombo).nameUint16());
+
+        } else if (nameAndTypeCombo instanceof DefaultNameRfc2685VpnId) {
+            maId = MaIdRfc2685VpnId.asMaIdHex(
+                    HexString.toHexString(
+                            ((DefaultNameRfc2685VpnId) nameAndTypeCombo).nameRfc2685VpnId()));
+        } else if (nameAndTypeCombo instanceof DefaultNameY1731Icc) {
+            maId = MaIdIccY1731.asMaId(((DefaultNameY1731Icc) nameAndTypeCombo).nameY1731Icc().string());
+
+        } else {
+            throw new IllegalArgumentException("Unexpected type for " +
+                    "MaNameAndTypeCombo: " + nameAndTypeCombo.toString());
+        }
+
+        return maId;
+    }
+
+    /**
+     * Cast the YANG generic type of MaNameAndTypeCombo specifically to char string.
+     * @param maName a YANG generic MaNameAndTypeCombo
+     * @return a YANG specific MaNameAndTypeCombo for Char string
+     */
+    public static NameCharacterString cast(MaNameAndTypeCombo maName) {
+        return (NameCharacterString) maName;
+    }
 }
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MdNameUtil.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MdNameUtil.java
new file mode 100644
index 0000000..ba0cc96
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/yang/utils/MdNameUtil.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onlab.packet.IpAddress;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.ietfinettypes.DomainName;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.MdNameAndTypeCombo;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultMacAddressAndUint;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameCharacterString;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameDomainName;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameNone;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.MacAddressAndUint;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.NameCharacterString;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.namedomainname.NameDomainNameUnion;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.MacAddressAndUintStr;
+
+/**
+ * Utility for translating between Maintenance Domain names in the CFM API model and the device YANG.
+ *
+ * This has to be in a separate file as a workaround for Checkstyle issue.
+ * https://github.com/checkstyle/checkstyle/issues/3850
+ * There are two types of DefaultNameCharacterString - one for MA and another for MD
+ * Putting both together in a file means that the full path has to be given which
+ * will then fail checkstyle
+ */
+public final class MdNameUtil {
+
+    private MdNameUtil() {
+        //Hidden
+    }
+
+    /**
+     * Convert CFM API MD identifier to the YANG model MD identifier.
+     * @param mdId Maintenance Domain ID in CFM API
+     * @return Maintenance Domain ID in YANG API
+     * @throws CfmConfigException If there's a problem with the name
+     */
+    public static MdNameAndTypeCombo getYangMdNameFromApiMdId(MdId mdId)
+            throws CfmConfigException {
+        MdNameAndTypeCombo mdName;
+        if (mdId instanceof MdIdDomainName) {
+            boolean isIpAddr = false;
+            try {
+                if (IpAddress.valueOf(mdId.mdName()) != null) {
+                    isIpAddr = true;
+                }
+            } catch (IllegalArgumentException e) {
+                //continue
+            }
+            if (isIpAddr) {
+                mdName = new DefaultNameDomainName();
+                ((DefaultNameDomainName) mdName).nameDomainName(NameDomainNameUnion.of(
+                        org.onosproject.yang.gen.v1.ietfinettypes.rev20130715.ietfinettypes.
+                                IpAddress.fromString(mdId.mdName())));
+            } else {
+                mdName = new DefaultNameDomainName();
+                ((DefaultNameDomainName) mdName).nameDomainName(NameDomainNameUnion
+                        .of(DomainName.fromString(mdId.mdName())));
+            }
+        } else if (mdId instanceof MdIdMacUint) {
+            mdName = new DefaultMacAddressAndUint();
+            ((DefaultMacAddressAndUint) mdName).nameMacAddressAndUint(MacAddressAndUintStr.fromString(mdId.mdName()));
+        } else if (mdId instanceof MdIdNone) {
+            mdName = new DefaultNameNone();
+        } else if (mdId instanceof MdIdCharStr) {
+            mdName = new DefaultNameCharacterString();
+            ((DefaultNameCharacterString) mdName).name(Identifier45.fromString(mdId.mdName()));
+        } else {
+            throw new CfmConfigException("Unexpected error creating MD " +
+                    mdId.getClass().getSimpleName());
+        }
+        return mdName;
+    }
+
+    /**
+     * Convert YANG API MD identifier to the CFM API MD identifier.
+     * @param nameAndTypeCombo Maintenance Domain ID in YANG API
+     * @return Maintenance Domain ID in CFM API
+     */
+    public static MdId getApiMdIdFromYangMdName(MdNameAndTypeCombo nameAndTypeCombo) {
+        MdId mdId;
+        if (nameAndTypeCombo instanceof DefaultNameDomainName) {
+            NameDomainNameUnion domainName =
+                    ((DefaultNameDomainName) nameAndTypeCombo).nameDomainName();
+            if (domainName.ipAddress() != null) {
+                mdId = MdIdDomainName.asMdId(domainName.ipAddress().toString());
+            } else if (domainName.domainName() != null) {
+                mdId = MdIdDomainName.asMdId(domainName.domainName().string());
+            } else {
+                throw new IllegalArgumentException("Unexpected domainName for " +
+                        "MdNameAndTypeCombo: " + nameAndTypeCombo.toString());
+            }
+        } else if (nameAndTypeCombo instanceof DefaultNameCharacterString) {
+            mdId = MdIdCharStr.asMdId(
+                    ((NameCharacterString) nameAndTypeCombo).name().string());
+
+        } else if (nameAndTypeCombo instanceof DefaultMacAddressAndUint) {
+            mdId = MdIdMacUint.asMdId(
+                    ((MacAddressAndUint) nameAndTypeCombo).nameMacAddressAndUint().string());
+
+        } else if (nameAndTypeCombo instanceof DefaultNameNone) {
+            mdId = MdIdNone.asMdId();
+        } else {
+            throw new IllegalArgumentException("Unexpected type for " +
+                    "MdNameAndTypeCombo: " + nameAndTypeCombo.toString());
+        }
+
+        return mdId;
+    }
+
+    /**
+     * Cast the YANG generic type of MdNameAndTypeCombo specifically to char string.
+     * @param maName a YANG generic MdNameAndTypeCombo
+     * @return a YANG specific MdNameAndTypeCombo for Char string
+     */
+    public static NameCharacterString cast(MdNameAndTypeCombo maName) {
+        return (NameCharacterString) maName;
+    }
+}
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammableTest.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammableTest.java
index 20e80a1..1f87634 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammableTest.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/EA1000CfmMepProgrammableTest.java
@@ -20,11 +20,13 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.onosproject.drivers.microsemi.yang.utils.MdNameUtil.getYangMdNameFromApiMdId;
 
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.onosproject.drivers.microsemi.yang.utils.MaNameUtil;
+import org.onosproject.drivers.microsemi.yang.utils.MdNameUtil;
 import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLbCreate;
 import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
@@ -38,21 +40,24 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.MdNameAndTypeCombo;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.MaNameAndTypeCombo;
 
 import java.util.BitSet;
+import java.util.Optional;
 
 /**
  * Test of the CFM implementation on EA1000 through the incubator/net/l2monitoring interface.
  */
 public class EA1000CfmMepProgrammableTest {
-    EA1000CfmMepProgrammable cfmProgrammable;
     public static final MdId MD_ID_1 = MdIdCharStr.asMdId("md-1");
     public static final MaIdShort MA_ID_11 = MaIdCharStr.asMaId("ma-1-1");
     public static final MepId MEP_111 = MepId.valueOf((short) 1);
     public static final MepId MEP_112 = MepId.valueOf((short) 2);
 
+    private CfmMepProgrammable cfmProgrammable;
+
     @Before
     public void setUp() throws Exception {
         cfmProgrammable = new EA1000CfmMepProgrammable();
@@ -67,12 +72,6 @@
         fail("Not yet implemented");
     }
 
-    @Ignore
-    @Test
-    public void testGetAllMeps() {
-        fail("Not yet implemented");
-    }
-
     @Test
     public void testGetMep() throws CfmConfigException {
         MepEntry mepEntry = cfmProgrammable.getMep(MD_ID_1, MA_ID_11, MEP_111);
@@ -143,7 +142,107 @@
      */
     @Test
     public void testDeleteMep() throws CfmConfigException {
-        assertTrue(cfmProgrammable.deleteMep(MD_ID_1, MA_ID_11, MEP_111));
+        assertTrue(cfmProgrammable.deleteMep(MD_ID_1, MA_ID_11, MEP_111, Optional.empty()));
+    }
+
+    /**
+     * Create the MD md-1 on the device.
+     * This will retrieve the MD from the MockCfmMdService and will create it
+     * and its MA on the device
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testCreateMaintenanceDomainOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.createMdOnDevice(MdIdCharStr.asMdId("md-1"));
+        assertTrue(success);
+    }
+
+    /**
+     * Create the MD md-2 on the device.
+     * This will retrieve the MD from the MockCfmMdService and will create it on
+     * the device. This MD has no MA
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testCreateMaintenanceDomainOnDevice2() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.createMdOnDevice(MdIdCharStr.asMdId("md-2"));
+        assertTrue(success);
+    }
+
+    /**
+     * Delete the MD md-1 on the device.
+     * This will retrieve the MD from the MockCfmMdService and will delete it on
+     * the device.
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testDeleteMaintenanceDomainOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.deleteMdOnDevice(MdIdCharStr.asMdId("md-1"), Optional.empty());
+        assertTrue(success);
+    }
+
+
+    /**
+     * Create the MA ma-1-1 on the device.
+     * This will retrieve the MA from the MockCfmMdService and will create it
+     * on the device under md-1
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testCreateMaintenanceAssociationOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.createMaOnDevice(
+                        MdIdCharStr.asMdId("md-1"), MaIdCharStr.asMaId("ma-1-1"));
+        assertTrue(success);
+    }
+
+    /**
+     * Delete the MD md-1 on the device.
+     * This will retrieve the MD from the MockCfmMdService and will delete it on
+     * the device.
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testDeleteMaintenanceAssociationOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.deleteMaOnDevice(
+                        MdIdCharStr.asMdId("md-1"),
+                        MaIdCharStr.asMaId("ma-1-1"),
+                        Optional.empty());
+        assertTrue(success);
+    }
+
+    /**
+     * Create the Remote Mep 10001 in ma-1-1 on the device.
+     * This will retrieve the MA from the MockCfmMdService and will create the
+     * new remote mep under it on the device
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testCreateRemoteMepOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.createMaRemoteMepOnDevice(
+                        MdIdCharStr.asMdId("md-1"), MaIdCharStr.asMaId("ma-1-1"),
+                        MepId.valueOf((short) 1001));
+        assertTrue(success);
+    }
+
+    /**
+     * Delete the Remote Mep 1002 in ma-1-1 on the device.
+     * This will retrieve the MA from the MockCfmMdService and will delete the
+     * existing remote mep under it on the device
+     * Depends on sampleXmlRegexCreateMseaCfmMa
+     */
+    @Test
+    public void testDeleteRemoteMepOnDevice() throws CfmConfigException {
+        boolean success =
+                cfmProgrammable.deleteMaRemoteMepOnDevice(
+                        MdIdCharStr.asMdId("md-1"), MaIdCharStr.asMaId("ma-1-1"),
+                        MepId.valueOf((short) 1001));
+        assertTrue(success);
     }
 
     /**
@@ -167,25 +266,21 @@
         cfmProgrammable.abortLoopback(MD_ID_1, MA_ID_11, MEP_111);
     }
 
-//    @Test
-//    public void testTransmitLinktrace() {
-//        fail("Not yet implemented");
-//    }
+    @Ignore
+    @Test
+    public void testTransmitLinktrace() {
+        fail("Not yet implemented");
+    }
 
     @Test
     public void testGetYangMdNameFromApiMdId() throws CfmConfigException {
-        MdNameAndTypeCombo name = EA1000CfmMepProgrammable
-                .getYangMdNameFromApiMdId(MdIdCharStr.asMdId("md-1"));
+        MdNameAndTypeCombo name = getYangMdNameFromApiMdId(MdIdCharStr.asMdId("md-1"));
 
         assertEquals(org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm
                 .maintenancedomain.mdnameandtypecombo
                 .DefaultNameCharacterString.class, name.getClass());
 
-//There's a problem with checkstyle for typecast on really long paths
-//        assertEquals("md-1", ((org.onosproject.yang.gen.v1.http.www.microsemi.com
-//                .microsemi.edge.assure.msea.cfm.rev20160229.mseacfm.mefcfm
-//                .maintenancedomain.mdnameandtypecombo
-//                .DefaultNameCharacterString) name).name().string());
+        assertEquals("md-1", MdNameUtil.cast(name).name().string());
     }
 
     @Test
@@ -196,11 +291,6 @@
                 .maintenancedomain.maintenanceassociation.manameandtypecombo
                 .DefaultNameCharacterString.class, name.getClass());
 
-//There's a problem with checkstyle for typecast on really long paths
-//        assertEquals("ma-1-1", ((org.onosproject.yang.gen.v1.http.www.microsemi.com
-//                .microsemi.edge.assure.msea.cfm.rev20160229.mseacfm.mefcfm
-//                .maintenancedomain.maintenanceassociation.manameandtypecombo
-//                .DefaultNameCharacterString) name).name().string());
+        assertEquals("ma-1-1", MaNameUtil.cast(name).name().string());
     }
-
 }
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java
index 58a8a5b..742f8c9 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java
@@ -20,6 +20,7 @@
 
 import org.onosproject.core.CoreService;
 import org.onosproject.drivers.microsemi.yang.MockCfmMdService;
+import org.onosproject.drivers.microsemi.yang.MockCfmMepService;
 import org.onosproject.drivers.microsemi.yang.MockMseaCfmManager;
 import org.onosproject.drivers.microsemi.yang.MockMseaSaFilteringManager;
 import org.onosproject.drivers.microsemi.yang.MockMseaUniEvcServiceManager;
@@ -31,6 +32,7 @@
 import org.onosproject.drivers.netconf.MockNetconfController;
 import org.onosproject.drivers.netconf.MockNetconfDevice;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.Behaviour;
 import org.onosproject.net.driver.DefaultDriver;
@@ -59,6 +61,7 @@
     private MockMseaUniEvcServiceManager mseaUniEvcService;
     private MockMseaCfmManager mseaCfmService;
     private MockCfmMdService mockMdService;
+    private MockCfmMepService mockMepService;
     private CoreService coreService;
 
     public MockEa1000DriverHandler() throws NetconfException {
@@ -92,6 +95,9 @@
         mockMdService = new MockCfmMdService();
         mockMdService.activate();
 
+        mockMepService = new MockCfmMepService();
+        mockMepService.activate();
+
         coreService = new MockCoreService();
         coreService.registerApplication(MICROSEMI_DRIVERS);
     }
@@ -131,6 +137,10 @@
 
         } else if (serviceClass.equals(CfmMdService.class)) {
             return (T) mockMdService;
+
+        } else if (serviceClass.equals(CfmMepService.class)) {
+            return (T) mockMepService;
+
         }
 
         return null;
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMdService.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMdService.java
index ba6d656..3d0fb5f 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMdService.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMdService.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.drivers.microsemi.yang;
 
+import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultComponent;
 import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
 import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
@@ -22,6 +24,7 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
 import org.onosproject.incubator.net.l2monitoring.cfm.impl.CfmMdManager;
 import static org.easymock.EasyMock.*;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
@@ -29,6 +32,9 @@
 
 import java.util.Optional;
 
+/**
+ * Supports testing of services that reply on the CfmMdService.
+ */
 public class MockCfmMdService extends CfmMdManager {
 
     @Override
@@ -40,6 +46,11 @@
                     .builder(MaIdCharStr.asMaId("ma-1-1"), 6)
                     .maNumericId((short) 1)
                     .ccmInterval(MaintenanceAssociation.CcmInterval.INTERVAL_3MS)
+                    .addToRemoteMepIdList(MepId.valueOf((short) 10))
+                    .addToRemoteMepIdList(MepId.valueOf((short) 20))
+                    .addToComponentList(
+                            DefaultComponent.builder(1)
+                                    .addToVidList(VlanId.vlanId((short) 101)).build())
                     .build();
 
             MdId md1Name = MdIdCharStr.asMdId("md-1");
@@ -50,14 +61,25 @@
                     .addToMaList(ma)
                     .build();
 
+            MdId md2Name = MdIdCharStr.asMdId("md-2");
+            MaintenanceDomain md2 = DefaultMaintenanceDomain
+                    .builder(md1Name)
+                    .mdNumericId((short) 2)
+                    .mdLevel(MaintenanceDomain.MdLevel.LEVEL2)
+                    .build();
+
             expect(store.createUpdateMaintenanceDomain(md1))
                     .andReturn(true);
+            expect(store.createUpdateMaintenanceDomain(md2))
+                    .andReturn(true);
             expect(store.getMaintenanceDomain(md1Name))
                     .andReturn(Optional.of(md1)).anyTimes();
+            expect(store.getMaintenanceDomain(md2Name))
+                    .andReturn(Optional.of(md2)).anyTimes();
             replay(store);
 
         } catch (CfmConfigException e) {
-            throw new IllegalArgumentException("Error creating Md md-1 for test");
+            throw new IllegalArgumentException("Error creating MDs for test", e);
         }
     }
 }
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMepService.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMepService.java
new file mode 100644
index 0000000..c00fc4e
--- /dev/null
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockCfmMepService.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.onlab.junit.TestUtils;
+import org.onlab.packet.ChassisId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
+import org.onosproject.incubator.net.l2monitoring.cfm.impl.CfmMdManager;
+import org.onosproject.incubator.net.l2monitoring.cfm.impl.CfmMepManager;
+import org.onosproject.incubator.net.l2monitoring.cfm.impl.TestCfmMepProgrammable;
+import org.onosproject.incubator.net.l2monitoring.cfm.impl.TestDeviceDiscoveryBehavior;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStore;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamDmProgrammable;
+import org.onosproject.incubator.net.l2monitoring.soam.impl.TestSoamDmProgrammable;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.DefaultDriver;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+/**
+ * Supports testing of services that reply on the CfmMepService.
+ */
+public class MockCfmMepService extends CfmMepManager {
+    private static final String TEST_MFR = "testMfr";
+    private static final String TEST_HW_VERSION = "testHwVersion";
+    private static final String TEST_SW_VERSION = "testSwVersion";
+    private static final String TEST_SN = "testSn";
+    private static final String TEST_DRIVER = "testDriver";
+    protected static final DeviceId DEVICE_ID1 = DeviceId.deviceId("netconf:1.2.3.4:830");
+
+
+    private final DriverService driverService = createMock(DriverService.class);
+
+    private Device device1;
+    private Driver testDriver;
+
+
+    @Override
+    public void activate() {
+        mepStore = createMock(MepStore.class);
+        cfmMdService = new MockCfmMdService();
+        deviceService = createMock(DeviceService.class);
+        ((CfmMdManager) cfmMdService).activate();
+
+        device1 = new DefaultDevice(
+                ProviderId.NONE, DEVICE_ID1, Device.Type.SWITCH,
+                TEST_MFR, TEST_HW_VERSION, TEST_SW_VERSION, TEST_SN,
+                new ChassisId(1),
+                DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, TEST_DRIVER).build());
+
+        Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours = new HashMap<>();
+        behaviours.put(DeviceDescriptionDiscovery.class, TestDeviceDiscoveryBehavior.class);
+        behaviours.put(CfmMepProgrammable.class, TestCfmMepProgrammable.class);
+        behaviours.put(SoamDmProgrammable.class, TestSoamDmProgrammable.class);
+
+        TestUtils.setField(this, "coreService", new TestCoreService());
+        TestUtils.setField(this, "deviceService", deviceService);
+        injectEventDispatcher(this, new TestEventDispatcher());
+
+        testDriver = new DefaultDriver(
+                TEST_DRIVER, new ArrayList<Driver>(),
+                TEST_MFR, TEST_HW_VERSION, TEST_SW_VERSION,
+                behaviours, new HashMap<>());
+
+        try {
+            Mep mep1 = DefaultMep.builder(
+                        MepId.valueOf((short) 10),
+                        DEVICE_ID1,
+                        PortNumber.P0,
+                        Mep.MepDirection.UP_MEP,
+                        MdIdCharStr.asMdId("md-1"),
+                        MaIdCharStr.asMaId("ma-1-1"))
+                    .build();
+
+            expect(mepStore.getMep(new MepKeyId(mep1))).andReturn(Optional.of(mep1)).anyTimes();
+        } catch (CfmConfigException e) {
+            throw new IllegalArgumentException("Error creating MEPs for test", e);
+        }
+    }
+
+    private class TestCoreService extends CoreServiceAdapter {
+
+        @Override
+        public IdGenerator getIdGenerator(String topic) {
+            return new IdGenerator() {
+                private AtomicLong counter = new AtomicLong(0);
+
+                @Override
+                public long getNewId() {
+                    return counter.getAndIncrement();
+                }
+            };
+        }
+    }
+}
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
index b9d4342..6bf67c0 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
@@ -478,11 +478,12 @@
                     + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
                     + "(<mef-cfm).*"
                     + "(<maintenance-domain>)\\R?"
-                    + "(<id/>)?\\R?"
-                    + "(<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>)\\R?"
+                    + "(<id>[0-9]{1,5}</id>)?\\R?"
+                    + "((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))?\\R?"
                     + "(<maintenance-association>)\\R?"
-                    + "(<id/>)?\\R?"
-                    + "(<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>)\\R?"
+                    + "(<id>[0-9]{1,5}</id>)?\\R?"
+                    + "((<name>[a-zA-Z0-9\\-:\\.]{1,48}</name>)|"
+                    + "(<name-primary-vid>[0-9]{1,4}</name-primary-vid>))?\\R?"
                     + "(<maintenance-association-end-point nc:operation=\"delete\">)\\R?"
                     + "(<mep-identifier>)[0-9]{1,4}(</mep-identifier>)\\R?"
                     + "(</maintenance-association-end-point>)\\R?"
@@ -492,6 +493,85 @@
                     + "(</config>)\\R?"
                     + "(</edit-config>)\\R?(</rpc>)\\R?(]]>){2}", Pattern.DOTALL);
 
+    //For testGetConfigMseaCfmEssentials
+    private Pattern sampleXmlRegexCreateMseaCfmMa =
+            Pattern.compile("(<\\?xml).*(<rpc).*(<edit-config>)\\R?"
+                    + "(<target>\\R?<running/>\\R?</target>)\\R?"
+                    + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<mef-cfm).*"
+                    + "(<maintenance-domain>)\\R?"
+                    + "(<id>)([0-9]){1,4}(</id>)\\R?"
+                    + "((<md-level>)([0-9]){1}(</md-level>))?\\R?"
+                    + "((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))?\\R?"
+                    + "((<maintenance-association>)\\R?"
+                    + "(<id>)([0-9]){1,4}(</id>)\\R?"
+                    + "((<ccm-interval>)(3.3ms)(</ccm-interval>))?\\R?"
+                    + "((<remote-meps>)([0-9]){1,4}(</remote-meps>))*\\R?"
+                    + "(((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))|"
+                    + "((<name-primary-vid>)([0-9]){1,4}(</name-primary-vid>)))?\\R?"
+                    + "((<component-list>)\\R?"
+                    + "(<vid>)([0-9]){1,4}(</vid>)\\R?"
+                    + "(</component-list>))?\\R?"
+                    + "(</maintenance-association>))*\\R?"
+                    + "(</maintenance-domain>)\\R?"
+                    + "(</mef-cfm>)\\R?"
+                    + "(</config>)\\R?"
+                    + "(</edit-config>)\\R?(</rpc>)\\R?(]]>){2}", Pattern.DOTALL);
+
+    //For testGetConfigMseaCfmEssentials
+    private Pattern sampleXmlRegexDeleteMseaCfmMa =
+            Pattern.compile("(<\\?xml).*(<rpc).*(<edit-config>)\\R?"
+                    + "(<target>\\R?<running/>\\R?</target>)\\R?"
+                    + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<mef-cfm).*"
+                    + "(<maintenance-domain>)\\R?"
+                    + "((<id/>)|((<id>)([0-9]){1,4}(</id>)))?\\R?"
+                    + "((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))?\\R?"
+                    + "(<maintenance-association nc:operation=\"delete\">)\\R?"
+                    + "((<id/>)|((<id>)([0-9]){1,4}(</id>)))?\\R?"
+                    + "(((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))|"
+                    + "((<name-primary-vid>)([0-9]){1,4}(</name-primary-vid>)))?\\R?"
+                    + "(</maintenance-association>)\\R?"
+                    + "(</maintenance-domain>)\\R?"
+                    + "(</mef-cfm>)\\R?"
+                    + "(</config>)\\R?"
+                    + "(</edit-config>)\\R?(</rpc>)\\R?(]]>){2}", Pattern.DOTALL);
+
+    //For testDeleteMseaMepRemoteMep
+    private Pattern sampleXmlRegexDeleteMseaCfmRmep =
+            Pattern.compile("(<\\?xml).*(<rpc).*(<edit-config>)\\R?"
+                    + "(<target>\\R?<running/>\\R?</target>)\\R?"
+                    + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<mef-cfm).*"
+                    + "(<maintenance-domain>)\\R?"
+                    + "((<id>)[0-9]{1,4}(</id>))?\\R?"
+                    + "((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))?\\R?"
+                    + "(<maintenance-association>)\\R?"
+                    + "((<id>)[0-9]{1,4}(</id>))?\\R?"
+                    + "((<remote-meps nc:operation=\"delete\">)([0-9]){1,4}(</remote-meps>))*\\R?"
+                    + "(((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))|"
+                    + "((<name-primary-vid>)([0-9]){1,4}(</name-primary-vid>)))?\\R?"
+                    + "(</maintenance-association>)\\R?"
+                    + "(</maintenance-domain>)\\R?"
+                    + "(</mef-cfm>)\\R?"
+                    + "(</config>)\\R?"
+                    + "(</edit-config>)\\R?(</rpc>)\\R?(]]>){2}", Pattern.DOTALL);
+
+    //For testDeleteMseaMd
+    private Pattern sampleXmlRegexDeleteMseaCfmMd =
+            Pattern.compile("(<\\?xml).*(<rpc).*(<edit-config>)\\R?"
+                    + "(<target>\\R?<running/>\\R?</target>)\\R?"
+                    + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<mef-cfm).*"
+                    + "(<maintenance-domain nc:operation=\"delete\">)\\R?"
+                    + "((<id/>)|(<id>([0-9]){1,4}(</id>)))?\\R?"
+                    + "(((<name>)([a-zA-Z0-9\\-:\\.]){1,48}(</name>))|\\R?"
+                    + "((<name-domain-name>)([a-zA-Z0-9\\-\\.]){1,48}(</name-domain-name>)))?\\R?"
+                    + "(</maintenance-domain>)\\R?"
+                    + "(</mef-cfm>)\\R?"
+                    + "(</config>)\\R?"
+                    + "(</edit-config>)\\R?(</rpc>)\\R?(]]>){2}", Pattern.DOTALL);
+
 
     private Pattern sampleXmlRegexTransmitLoopback =
             Pattern.compile("(<\\?xml).*(<rpc).*\\R?"
@@ -1310,6 +1390,18 @@
         } else if (sampleXmlRegexDeleteMseaCfmMep.matcher(request).matches()) {
             return SAMPLE_REPLY_OK;
 
+        } else if (sampleXmlRegexCreateMseaCfmMa.matcher(request).matches()) {
+            return SAMPLE_REPLY_OK;
+
+        } else if (sampleXmlRegexDeleteMseaCfmMa.matcher(request).matches()) {
+            return SAMPLE_REPLY_OK;
+
+        } else if (sampleXmlRegexDeleteMseaCfmRmep.matcher(request).matches()) {
+            return SAMPLE_REPLY_OK;
+
+        } else if (sampleXmlRegexDeleteMseaCfmMd.matcher(request).matches()) {
+            return SAMPLE_REPLY_OK;
+
         } else if (sampleXmlRegexGetMseaDelay.matcher(request).matches()) {
             return SAMPLE_MSEACFM_DELAY_MEASUREMENT_FULL_REPLY;
 
diff --git a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MseaCfmManagerTest.java b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MseaCfmManagerTest.java
index fe99bf3..bb65a4d 100644
--- a/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MseaCfmManagerTest.java
+++ b/drivers/microsemi/src/test/java/org/onosproject/drivers/microsemi/yang/MseaCfmManagerTest.java
@@ -36,20 +36,31 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
+import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfDeviceInfo;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
 import org.onosproject.yang.gen.v1.ietfyangtypes.rev20130715.ietfyangtypes.MacAddress;
 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.MefCfm;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.abortloopback.AbortLoopbackInput;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.abortloopback.DefaultAbortLoopbackInput;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.DefaultMaintenanceDomain;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.MaintenanceDomain;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.DefaultMaintenanceAssociation;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.MaintenanceAssociation;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.DefaultMaintenanceAssociationEndPoint;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.MaintenanceAssociationEndPoint;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.DefaultNamePrimaryVid;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.NamePrimaryVid;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.manameandtypecombo.nameprimaryvid.NamePrimaryVidUnion;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameCharacterString;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.DefaultNameDomainName;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.NameCharacterString;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.NameDomainName;
+import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.mdnameandtypecombo.namedomainname.NameDomainNameUnion;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.targetaddressgroup.AddressType;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.targetaddressgroup.addresstype.DefaultMacAddress;
 import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.targetaddressgroup.addresstype.DefaultMepId;
@@ -194,10 +205,173 @@
 //        mseaCfmService.setMseaCfm(mseaCfmOpParam, session, NcDsType.running);
     }
 
+    /**
+     * Using mep Id 10.
+     */
     @Test
+    public void testDeleteMseaMep() {
+        MaintenanceAssociationEndPoint mep10 = new DefaultMaintenanceAssociationEndPoint();
+        mep10.mepIdentifier(MepIdType.of(10));
+
+        MaintenanceAssociation ma1100 = new DefaultMaintenanceAssociation();
+        NamePrimaryVid pvid1100Name = new DefaultNamePrimaryVid();
+        pvid1100Name.namePrimaryVid(NamePrimaryVidUnion.fromString("1100"));
+        ma1100.maNameAndTypeCombo(pvid1100Name);
+        ma1100.id((short) 1100);
+        ma1100.addToMaintenanceAssociationEndPoint(mep10);
+
+        MaintenanceDomain md = new DefaultMaintenanceDomain();
+        NameCharacterString mdName = new DefaultNameCharacterString();
+        mdName.name(new Identifier45("md-1"));
+        md.mdNameAndTypeCombo(mdName);
+        md.id((short) 1);
+        md.addToMaintenanceAssociation(ma1100);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(md);
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        mseaCfm.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMep(mseaCfm, session, DatastoreId.RUNNING);
+            assertTrue(deleted);
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail();
+        } catch (CfmConfigException e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    /**
+     * Using mep Id 10.
+     */
+    @Test
+    public void testDeleteMseaMa() {
+        MaintenanceAssociation ma1300 = new DefaultMaintenanceAssociation();
+        NamePrimaryVid pvid1300Name = new DefaultNamePrimaryVid();
+        pvid1300Name.namePrimaryVid(NamePrimaryVidUnion.fromString("1300"));
+        ma1300.id((short) 1300);
+        ma1300.maNameAndTypeCombo(pvid1300Name);
+
+        MaintenanceDomain md = new DefaultMaintenanceDomain();
+        NameCharacterString mdName = new DefaultNameCharacterString();
+        mdName.name(new Identifier45("md-13"));
+        md.mdNameAndTypeCombo(mdName);
+        md.id((short) 13);
+        md.addToMaintenanceAssociation(ma1300);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(md);
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        mseaCfm.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMa(mseaCfm, session, DatastoreId.RUNNING);
+            assertTrue(deleted);
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail();
+        } catch (CfmConfigException e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testDeleteMseaRemoteMep() {
+        MaintenanceAssociation ma1100 = new DefaultMaintenanceAssociation();
+        NamePrimaryVid pvid1100Name = new DefaultNamePrimaryVid();
+        pvid1100Name.namePrimaryVid(NamePrimaryVidUnion.fromString("1100"));
+        ma1100.maNameAndTypeCombo(pvid1100Name);
+        ma1100.id((short) 1100);
+        ma1100.addToRemoteMeps(MepIdType.of(100));
+        ma1100.addToRemoteMeps(MepIdType.of(101));
+
+        MaintenanceDomain md = new DefaultMaintenanceDomain();
+        NameCharacterString mdName = new DefaultNameCharacterString();
+        mdName.name(new Identifier45("md-1"));
+        md.mdNameAndTypeCombo(mdName);
+        md.id((short) 1);
+        md.addToMaintenanceAssociation(ma1100);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(md);
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        mseaCfm.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMaRMep(mseaCfm, session, DatastoreId.RUNNING);
+            assertTrue(deleted);
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail();
+        } catch (CfmConfigException e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    /**
+     * Using mep Id 10.
+     */
+    @Test
+    public void testDeleteMseaMdById() {
+
+        MaintenanceDomain md = new DefaultMaintenanceDomain();
+        NameDomainName mdName = new DefaultNameDomainName();
+        mdName.nameDomainName(NameDomainNameUnion.fromString("www.opennetworking.org"));
+        md.mdNameAndTypeCombo(mdName);
+        md.id((short) 10);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(md);
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        mseaCfm.mefCfm(mefCfm);
+
+        try {
+            boolean deleted = mseaCfmService.deleteMseaMd(mseaCfm, session, DatastoreId.RUNNING);
+            assertTrue(deleted);
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail();
+        } catch (CfmConfigException e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    /**
+     * Using mep Id 10.
+     */
+    @Test
+    public void testDeleteMseaMdByName() {
+
+        MaintenanceDomain md = new DefaultMaintenanceDomain();
+        NameDomainName mdName = new DefaultNameDomainName();
+        mdName.nameDomainName(NameDomainNameUnion.fromString("www.opennetworking.org"));
+        md.mdNameAndTypeCombo(mdName);
+
+        MefCfm mefCfm = new DefaultMefCfm();
+        mefCfm.addToMaintenanceDomain(md);
+        MseaCfmOpParam mseaCfm = new MseaCfmOpParam();
+        mseaCfm.mefCfm(mefCfm);
+
+        try {
+            mseaCfmService.deleteMseaMd(mseaCfm, session, DatastoreId.RUNNING);
+            fail("Should not have succeeded as no numeric id was given");
+        } catch (NetconfException | CfmConfigException e) {
+            assertEquals("An MD numeric ID must be given", e.getMessage());
+        }
+    }
+
+
     /**
      * Using Remote remote MEP ID and all arguments.
      */
+    @Test
     public void testTransmitLoopback1() {
         TransmitLoopbackInput lbTr1 = new DefaultTransmitLoopbackInput();
         lbTr1.maintenanceDomain(Short.valueOf((short) 1));
@@ -221,10 +395,10 @@
         }
     }
 
-    @Test
     /**
      * Using Remote Mac address in place of remote MEP ID and fewer arguments.
      */
+    @Test
     public void testTransmitLoopback2() {
         TransmitLoopbackInput lbTr2 = new DefaultTransmitLoopbackInput();
 
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/DefaultMaintenanceAssociation.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/DefaultMaintenanceAssociation.java
index 5d827f6..38c3d6f 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/DefaultMaintenanceAssociation.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/DefaultMaintenanceAssociation.java
@@ -213,6 +213,12 @@
         }
 
         @Override
+        public MaBuilder removeFromRemoteMepIdList(MepId remoteMep) {
+            this.remoteMepIdList.remove(remoteMep);
+            return this;
+        }
+
+        @Override
         public MaBuilder ccmInterval(CcmInterval ccmInterval) {
             this.ccmInterval = ccmInterval;
             return this;
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/MaintenanceAssociation.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/MaintenanceAssociation.java
index f6e1f3c..37c1a84 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/MaintenanceAssociation.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/MaintenanceAssociation.java
@@ -113,6 +113,8 @@
 
         MaBuilder addToRemoteMepIdList(MepId remoteMep);
 
+        MaBuilder removeFromRemoteMepIdList(MepId remoteMep);
+
         MaBuilder addToComponentList(Component component);
 
         MaBuilder maNumericId(short maNumericId);
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/identifier/MepKeyId.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/identifier/MepKeyId.java
new file mode 100644
index 0000000..afb337b
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/identifier/MepKeyId.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.incubator.net.l2monitoring.cfm.identifier;
+
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+
+/**
+ * Immutable class to represent a unique identifier of a Mep.
+ */
+public class MepKeyId {
+    private MdId mdId;
+    private MaIdShort maId;
+    private MepId mepId;
+
+    public MepKeyId(MdId mdId, MaIdShort maId, MepId mepId) {
+        this.mdId = mdId;
+        this.maId = maId;
+        this.mepId = mepId;
+        if (mdId == null || maId == null || mepId == null) {
+            throw new IllegalArgumentException("Arguments to MepKeyId constructor cannot be null");
+        }
+    }
+
+    public MepKeyId(Mep mep) {
+        this.mdId = mep.mdId();
+        this.maId = mep.maId();
+        this.mepId = mep.mepId();
+    }
+
+    public MdId mdId() {
+        return mdId;
+    }
+
+    public MaIdShort maId() {
+        return maId;
+    }
+
+    public MepId mepId() {
+        return mepId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        MepKeyId mepKeyId = (MepKeyId) o;
+
+        if (mdId != null ? !mdId.equals(mepKeyId.mdId) : mepKeyId.mdId != null) {
+            return false;
+        }
+        if (maId != null ? !maId.equals(mepKeyId.maId) : mepKeyId.maId != null) {
+            return false;
+        }
+        return mepId != null ? mepId.equals(mepKeyId.mepId) : mepKeyId.mepId == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mdId != null ? mdId.hashCode() : 0;
+        result = 31 * result + (maId != null ? maId.hashCode() : 0);
+        result = 31 * result + (mepId != null ? mepId.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return mdId.mdName() + "/" + maId.maName() + "/" + mepId();
+    }
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMdService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMdService.java
index 9c9aa46..b495eb9 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMdService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMdService.java
@@ -18,6 +18,7 @@
 import java.util.Collection;
 import java.util.Optional;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
@@ -26,7 +27,7 @@
 /**
  * For the management of Maintenance Domains and Maintenance Associations.
  */
-public interface CfmMdService {
+public interface CfmMdService extends ListenerService<MdEvent, MdListener> {
 
     /**
      * Get a list of all of the Maintenance Domains on the system.
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepEvent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepEvent.java
index 26abc45..cb96b52 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepEvent.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepEvent.java
@@ -16,12 +16,12 @@
 package org.onosproject.incubator.net.l2monitoring.cfm.service;
 
 import org.onosproject.event.AbstractEvent;
-import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
 
 /**
  * Event related to the maintenance of CFM MEPs.
  */
-public class CfmMepEvent extends AbstractEvent<CfmMepEvent.Type, Mep> {
+public class CfmMepEvent extends AbstractEvent<CfmMepEvent.Type, MepKeyId> {
 
     /**
      * Type of Mep events.
@@ -52,10 +52,9 @@
      * Creates an event of a given type and for the specified Mep and the current time.
      *
      * @param type Mep event type
-     * @param mep event Mep subject
+     * @param mepKeyId event Mep subject
      */
-    protected CfmMepEvent(Type type, Mep mep) {
-        super(type, mep);
-        // TODO Auto-generated constructor stub
+    public CfmMepEvent(Type type, MepKeyId mepKeyId) {
+        super(type, mepKeyId);
     }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepProgrammable.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepProgrammable.java
index b92777b..1b902cb 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepProgrammable.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepProgrammable.java
@@ -15,14 +15,95 @@
  */
 package org.onosproject.incubator.net.l2monitoring.cfm.service;
 
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
 import org.onosproject.net.driver.HandlerBehaviour;
 
+import java.util.Optional;
+
 /**
  * Behaviour that allows Layer 2 Monitoring as defined in IEEE 802.1Q be implemented by devices.
  *
  * Has all of the same methods as
- * {@link org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService} so reuse that
+ * {@link CfmMepServiceBase} so reuse that
  */
-public interface CfmMepProgrammable extends HandlerBehaviour, CfmMepService {
+public interface CfmMepProgrammable extends HandlerBehaviour, CfmMepServiceBase {
+
+
+    /**
+     * Allows an MD and children MAs to be created on a device.
+     * A convenience method that allows an MD to be created on a device
+     * This is a preparation mechanism. If this was not called the MD would be created
+     * at the time of provisioning a MEP anyway
+     * @param mdId The ID of the MD to create - the details will be got from the CfmMdService
+     * @return true when created. false if it already existed
+     * @throws CfmConfigException If the MD already exists
+     */
+    boolean createMdOnDevice(MdId mdId) throws CfmConfigException;
+
+    /**
+     * Allows an MA to be created on an existing MD on a device.
+     * A convenience method that allows an MA to be created
+     * This is a preparation mechanism. If this was not called the MA would be created
+     * at the time of provisioning a MEP anyway. Also MAs can be created when they
+     * are contained in an MD using the createMdOnDevice method
+     * @param mdId The identifier of the MD to create the MA in
+     * @param maId The identifier of the MA to create - the details will be retrieved from the CfmMdService
+     * @return true when created. false if it already existed
+     * @throws CfmConfigException If the MD already exists
+     */
+    boolean createMaOnDevice(MdId mdId, MaIdShort maId) throws CfmConfigException;
+
+    /**
+     * Allows a MD and its MAs to be deleted from a device.
+     * A convenience method that allows an MD that has been provisioned on a
+     * device to be removed.
+     * All Meps must be removed first unless they are Meps unknown to ONOS.
+     * This is a cleanup mechanism. Deleting Meps in the normal way does not celan
+     * up MDs and MAs
+     * @param mdId The identifier of the MD
+     * @param oldMd The MaintenanceDomain that is being deleted
+     * @return true when deleted. false if it did not exist
+     * @throws CfmConfigException If the MD has any MAs that have MEPs then this will fail
+     */
+    boolean deleteMdOnDevice(MdId mdId, Optional<MaintenanceDomain> oldMd) throws CfmConfigException;
+
+    /**
+     * Allows an MA to be deleted from an MD on a device.
+     * A convenience method that allows an MA that has been provisioned on a
+     * device to be removed.
+     * All Meps must be removed first unless they are Meps unknown to ONOS.
+     * This is a cleanup mechanism. Deleting Meps in the normal way does not celan
+     * up MDs and MAs
+     * @param mdId The identifier of the MD
+     * @param maId The identifier of the MA
+     * @param oldMd The MaintenanceDomain from which the MA is being deleted
+     * @return true when deleted. false if it did not exist
+     * @throws CfmConfigException If the MA has any MEPs then this will fail
+     */
+    boolean deleteMaOnDevice(MdId mdId, MaIdShort maId,
+                             Optional<MaintenanceDomain> oldMd) throws CfmConfigException;
+
+    /**
+     * Creates a Remote Mep entry on an MA.
+     * @param mdId The identifier of the MD
+     * @param maId The identifier of the MA
+     * @param remoteMep The remote Mep Id to remove from the MA
+     * @return true when deleted. false if it did not exist
+     * @throws CfmConfigException If the MA does not exist this will fail
+     */
+    boolean createMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException;
+
+    /**
+     * Deletes a Remote Mep entry on an MA.
+     * @param mdId The identifier of the MD
+     * @param maId The identifier of the MA
+     * @param remoteMep The remote Mep Id to remove from the MA
+     * @return true when deleted. false if it did not exist
+     * @throws CfmConfigException If the MA does not exist this will fail
+     */
+    boolean deleteMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException;
 
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepService.java
index c0c2f92..c774c65 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepService.java
@@ -17,13 +17,12 @@
 
 import java.util.Collection;
 
+import org.onosproject.event.ListenerService;
 import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
-import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
-import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
-import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.net.DeviceId;
 
 /**
  * For the management of Maintenance Association Endpoints.
@@ -31,7 +30,8 @@
  * These are dependent on the Maintenance Domain service which maintains the
  * Maintenance Domain and Maintenance Associations
  */
-public interface CfmMepService {
+public interface CfmMepService
+        extends ListenerService<CfmMepEvent, CfmMepListener>, CfmMepServiceBase {
     /**
      * Retrieve all {@link org.onosproject.incubator.net.l2monitoring.cfm.MepEntry}(s) belonging to an MA.
      * @param mdName A Maintenance Domain
@@ -43,67 +43,13 @@
             throws CfmConfigException;
 
     /**
-     * Retrieve a named {@link org.onosproject.incubator.net.l2monitoring.cfm.MepEntry} belonging to an MA.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mepId A Mep Id
-     * @return A MEP Entry or null if none found
-     * @throws CfmConfigException If there a problem with the MD, MA or MEP
-     */
-    MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId)
-            throws CfmConfigException;
-
-    /**
-     * Delete a named {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep} belonging to an MA.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mepId A Mep Id
-     * @return true if the MEP was deleted successfully. false if it was not found
+     * Retrieve all {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep}(s) belonging to an MA.
+     * Note: This just returns the configuration part of the Mep, not the MepEntry
+     * which contains config and state
+     * @param deviceId A device id
+     * @return A collection of MEP Entries
      * @throws CfmConfigException If there a problem with the MD or MA
      */
-    boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId)
+    Collection<Mep> getAllMepsByDevice(DeviceId deviceId)
             throws CfmConfigException;
-
-    /**
-     * Create a named {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep} on an MA.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mep A Mep object
-     * @return False if it was created successfully. True if the object already exists.
-     * @throws CfmConfigException If there a problem with the MD, MA or MEP
-     */
-    boolean createMep(MdId mdName, MaIdShort maName, Mep mep)
-            throws CfmConfigException;
-
-    /**
-     * Create a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry Loopback} session on the named Mep.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mepId A Mep Id
-     * @param lbCreate The Loopback session details
-     * @throws CfmConfigException If there a problem with the MD, MA or MEP
-     */
-    void transmitLoopback(MdId mdName, MaIdShort maName, MepId mepId,
-            MepLbCreate lbCreate) throws CfmConfigException;
-
-    /**
-     * Abort a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry Loopback} session on the named Mep.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mepId A Mep Id
-     * @throws CfmConfigException If there a problem with the MD, MA or MEP
-     */
-    void abortLoopback(MdId mdName, MaIdShort maName, MepId mepId)
-            throws CfmConfigException;
-
-    /**
-     * Create a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLtEntry Linktrace} session on the named Mep.
-     * @param mdName A Maintenance Domain
-     * @param maName A Maintetance Association in the MD
-     * @param mepId A Mep Id
-     * @param ltCreate The Linktrace session details
-     * @throws CfmConfigException If there a problem with the MD, MA or MEP
-     */
-    void transmitLinktrace(MdId mdName, MaIdShort maName, MepId mepId,
-            MepLtCreate ltCreate) throws CfmConfigException;
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepServiceBase.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepServiceBase.java
new file mode 100644
index 0000000..71e5611
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/CfmMepServiceBase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.incubator.net.l2monitoring.cfm.service;
+
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+
+import java.util.Optional;
+
+public interface CfmMepServiceBase {
+    /**
+     * Retrieve a named {@link org.onosproject.incubator.net.l2monitoring.cfm.MepEntry} belonging to an MA.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mepId A Mep Id
+     * @return A MEP Entry or null if none found
+     * @throws CfmConfigException If there a problem with the MD, MA or MEP
+     */
+    MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId)
+            throws CfmConfigException;
+
+    /**
+     * Delete a named {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep} belonging to an MA.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mepId A Mep Id
+     * @param oldMd The MaintenanceDomain from which the MEP is being deleted
+     * @return true if the MEP was deleted successfully. false if it was not found
+     * @throws CfmConfigException If there a problem with the MD or MA
+     */
+    boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId, Optional<MaintenanceDomain> oldMd)
+            throws CfmConfigException;
+
+    /**
+     * Create a named {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep} on an MA.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mep A Mep object
+     * @return True if it was created successfully. False if the object already exists.
+     * @throws CfmConfigException If there a problem with the MD, MA or MEP
+     */
+    boolean createMep(MdId mdName, MaIdShort maName, Mep mep)
+            throws CfmConfigException;
+
+    /**
+     * Create a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry Loopback} session on the named Mep.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mepId A Mep Id
+     * @param lbCreate The Loopback session details
+     * @throws CfmConfigException If there a problem with the MD, MA or MEP
+     */
+    void transmitLoopback(MdId mdName, MaIdShort maName, MepId mepId,
+                          MepLbCreate lbCreate) throws CfmConfigException;
+
+    /**
+     * Abort a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry Loopback} session on the named Mep.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mepId A Mep Id
+     * @throws CfmConfigException If there a problem with the MD, MA or MEP
+     */
+    void abortLoopback(MdId mdName, MaIdShort maName, MepId mepId)
+            throws CfmConfigException;
+
+    /**
+     * Create a {@link org.onosproject.incubator.net.l2monitoring.cfm.MepLtEntry Linktrace} session on the named Mep.
+     * @param mdName A Maintenance Domain
+     * @param maName A Maintetance Association in the MD
+     * @param mepId A Mep Id
+     * @param ltCreate The Linktrace session details
+     * @throws CfmConfigException If there a problem with the MD, MA or MEP
+     */
+    void transmitLinktrace(MdId mdName, MaIdShort maName, MepId mepId,
+                           MepLtCreate ltCreate) throws CfmConfigException;
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MdEvent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MdEvent.java
index e3090f7..49023d4 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MdEvent.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MdEvent.java
@@ -15,24 +15,78 @@
  */
 package org.onosproject.incubator.net.l2monitoring.cfm.service;
 
+import com.google.common.base.MoreObjects;
+import org.onlab.util.Tools;
 import org.onosproject.event.AbstractEvent;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
 /**
  * Event related to the maintenance of CFM MDs.
  */
 public class MdEvent extends AbstractEvent<MdEvent.Type, MdId> {
 
+    private MaIdShort maId;
+    private MaintenanceDomain oldMd;
     /**
      * MD Event types supported.
      */
     public enum Type {
         MD_ADDED,
         MD_REMOVED,
-        MD_UPDATED
+        MD_UPDATED,
+        MA_ADDED,
+        MA_REMOVED
     }
 
     public MdEvent(Type type, MdId mdId) {
         super(type, mdId);
     }
+
+    /**
+     * Constructor that allows the MD to be held in the event.
+     * This is useful if the MD had been deleted - it will be the only way of
+     * retrieving some of its attributes
+     * @param type The type of the event
+     * @param mdId The ID of the MD
+     * @param md The whole MD
+     * @throws CfmConfigException if there's a problem copying MD
+     */
+    public MdEvent(Type type, MdId mdId, MaintenanceDomain md) throws CfmConfigException {
+        super(type, mdId);
+        this.oldMd = DefaultMaintenanceDomain.builder(md).build();
+    }
+
+    public MdEvent(Type type, MdId mdId, MaintenanceDomain md, MaIdShort maId)
+            throws CfmConfigException {
+        super(type, mdId);
+        this.maId = maId;
+        this.oldMd = DefaultMaintenanceDomain.builder(md).build();
+    }
+
+    public Optional<MaIdShort> maId() {
+        return maId == null ? Optional.empty() : Optional.of(maId);
+    }
+
+    public Optional<MaintenanceDomain> md() {
+        return oldMd == null ? Optional.empty() : Optional.of(oldMd);
+    }
+
+    @Override
+    public String toString() {
+        MoreObjects.ToStringHelper helper = toStringHelper(this)
+                .add("time", Tools.defaultOffsetDataTime(time()))
+                .add("type", type())
+                .add("subject", subject());
+        if (maId != null) {
+            helper = helper.add("subject2", maId);
+        }
+        return helper.toString();
+    }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStore.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStore.java
new file mode 100644
index 0000000..ed4bb35
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStore.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.l2monitoring.cfm.service;
+
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.store.Store;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * {@link org.onosproject.incubator.net.l2monitoring.cfm.Mep Maintenance Association Endpoint's} storage interface.
+ * Note: because the Mep is immutable if anything needs to be
+ * changed in it, then it must be replaced in the store.
+ */
+public interface MepStore extends Store<CfmMepEvent, MepStoreDelegate> {
+    /**
+     * Get a list of all of the Meps on the system.
+     * @return A collection Meps from the Mep Store.
+     */
+    Collection<Mep> getAllMeps();
+
+    /**
+     * Get all Meps by MD.
+     * @param mdName An identifier for the Maintenance Domain
+     * @return MEPs from the MEP Store. Empty if not found.
+     */
+    Collection<Mep> getMepsByMd(MdId mdName);
+
+    /**
+     * Get all Meps by MD, MA.
+     * @param mdName An identifier for the Maintenance Domain
+     * @param maName An identifier for the Maintenance Association
+     * @return MEPs from the MEP Store. Empty if not found.
+     */
+    Collection<Mep> getMepsByMdMa(MdId mdName, MaIdShort maName);
+
+    /**
+     * Get all Meps by DeviceId.
+     * @param deviceId An identifier for the Device
+     * @return MEPs from the MEP Store. Empty if not found.
+     */
+    Collection<Mep> getMepsByDeviceId(DeviceId deviceId);
+
+    /**
+     * Get a specific Mep by its Mep key id.
+     * @param mepKeyId An unique identifier for the MEP
+     * @return A MEP from the MEP Store. Empty if not found.
+     */
+    Optional<Mep> getMep(MepKeyId mepKeyId);
+
+    /**
+     * Delete a specific Mep by its identifier.
+     * @param mepKeyId An unique identifier for the MEP
+     * @return True if the Mep was found and deleted
+     */
+    boolean deleteMep(MepKeyId mepKeyId);
+
+    /**
+     * Create or replace a Mep.
+     * @param mepKeyId An unique identifier for the MEP
+     * @param mep The new MEP
+     * @return true if an Mep of this name already existed
+     */
+    boolean createUpdateMep(MepKeyId mepKeyId, Mep mep);
+
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStoreDelegate.java b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStoreDelegate.java
new file mode 100644
index 0000000..6d5dfd3
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/service/MepStoreDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.l2monitoring.cfm.service;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Delegate for MEP Store.
+ */
+public interface MepStoreDelegate extends StoreDelegate<CfmMepEvent> {
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManager.java
index 5a125f5..b18d2f6 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManager.java
@@ -65,10 +65,8 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication(APP_ID);
-
         eventDispatcher.addSink(MdEvent.class, listenerRegistry);
         store.setDelegate(delegate);
-
         log.info("CFM Service Started");
     }
 
@@ -163,9 +161,8 @@
     private class InternalStoreDelegate implements MdStoreDelegate {
         @Override
         public void notify(MdEvent event) {
-            log.debug("New MD event: {}", event.subject());
+            log.debug("New MD event: {}", event);
             eventDispatcher.post(event);
         }
     }
-
 }
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManager.java
index 5723466..e58a570 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManager.java
@@ -15,10 +15,21 @@
  */
 package org.onosproject.incubator.net.l2monitoring.cfm.impl;
 
+import static org.onlab.util.Tools.groupedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -29,6 +40,8 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.event.Event;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
 import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
@@ -36,12 +49,17 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepEvent;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepListener;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MdEvent;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MdListener;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStore;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStoreDelegate;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -61,7 +79,8 @@
 
     private final Logger log = getLogger(getClass());
 
-    private final DeviceListener deviceListener = new InternalDeviceListener();
+    private InternalDeviceListener deviceListener = null;
+    private InternalMdListener mdListener = null;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
@@ -78,22 +97,39 @@
     private static final int DEFAULT_POLL_FREQUENCY = 30;
     private int fallbackMepPollFrequency = DEFAULT_POLL_FREQUENCY;
 
+    private InternalEventHandler eventHandler = new InternalEventHandler();
+    private static final Object THREAD_SCHED_LOCK = new Object();
+    private static int numOfEventsQueued = 0;
+    private static int numOfEventsExecuted = 0;
+    private static int numOfHandlerExecution = 0;
+    private static int numOfHandlerScheduled = 0;
+
+    private ScheduledExecutorService executorService = Executors
+            .newScheduledThreadPool(1,
+                    groupedThreads("CfmMepManager", "event-%d", log));
+
+    @SuppressWarnings("unused")
+    private static ScheduledFuture<?> eventHandlerFuture = null;
+    @SuppressWarnings("rawtypes")
+    private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<>();
+
+
     private IdGenerator idGenerator;
 
-    //FIXME Get rid of this hack - we will use this in memory to emulate
-    // a store for the short term.
-    //Note: This is not distributed and will not work in a clustered system
-    //TODO Create a MepStore for this
-    private Collection<Mep> mepCollection;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MepStore mepStore;
 
+    protected final MepStoreDelegate delegate = new InternalStoreDelegate();
 
     @Activate
     public void activate() {
-        //FIXME Get rid of this local list
-        mepCollection = new ArrayList<>();
+        mepStore.setDelegate(delegate);
 
-        eventDispatcher.addSink(CfmMepEvent.class, listenerRegistry);
+        deviceListener = new InternalDeviceListener();
         deviceService.addListener(deviceListener);
+        mdListener = new InternalMdListener();
+        cfmMdService.addListener(mdListener);
+        eventDispatcher.addSink(CfmMepEvent.class, listenerRegistry);
         idGenerator = coreService.getIdGenerator("mep-ids");
         log.info("CFM MEP Manager Started");
     }
@@ -101,9 +137,12 @@
     @Deactivate
     public void deactivate() {
         deviceService.removeListener(deviceListener);
+        cfmMdService.removeListener(mdListener);
         eventDispatcher.removeSink(CfmMepEvent.class);
         log.info("CFM MEP Manager Stopped");
-        mepCollection.clear();
+        mepStore.unsetDelegate(delegate);
+        deviceListener = null;
+        mdListener = null;
     }
 
     @Override
@@ -112,27 +151,28 @@
         //Will throw IllegalArgumentException if ma does not exist
         cfmMdService.getMaintenanceAssociation(mdName, maName);
 
+        Collection<Mep> mepStoreCollection = mepStore.getAllMeps();
         Collection<MepEntry> mepEntryCollection = new ArrayList<>();
 
-        for (Mep mep:mepCollection) {
+        for (Mep mep : mepStoreCollection) {
             if (mep.mdId().equals(mdName) && mep.maId().equals(maName)) {
                 DeviceId mepDeviceId = mep.deviceId();
                 if (deviceService.getDevice(mepDeviceId) == null) {
                     log.warn("Device not found/available " + mepDeviceId +
-                        " for MEP: " + mdName + "/" + maName + "/" + mep.mepId());
+                            " for MEP: " + mdName + "/" + maName + "/" + mep.mepId());
                     continue;
                 } else if (!deviceService.getDevice(mepDeviceId)
-                                        .is(CfmMepProgrammable.class)) {
+                        .is(CfmMepProgrammable.class)) {
                     throw new CfmConfigException("Device " + mepDeviceId +
                             " does not support CfmMepProgrammable behaviour.");
                 }
 
                 log.debug("Retrieving MEP results for Mep {} in MD {}, MA {} "
-                    + "on Device {}", mep.mepId(), mdName, maName, mepDeviceId);
+                        + "on Device {}", mep.mepId(), mdName, maName, mepDeviceId);
                 mepEntryCollection.add(deviceService
-                                        .getDevice(mepDeviceId)
-                                        .as(CfmMepProgrammable.class)
-                                        .getMep(mdName, maName, mep.mepId()));
+                        .getDevice(mepDeviceId)
+                        .as(CfmMepProgrammable.class)
+                        .getMep(mdName, maName, mep.mepId()));
             }
         }
 
@@ -140,75 +180,116 @@
     }
 
     @Override
-    public MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
-        //Will throw IllegalArgumentException if ma does not exist
-        cfmMdService.getMaintenanceAssociation(mdName, maName);
-
-        for (Mep mep : mepCollection) {
-            if (mep.mdId().equals(mdName) && mep.maId().equals(maName)
-                    && mep.mepId().equals(mepId)) {
-
-                DeviceId mepDeviceId = mep.deviceId();
-                if (deviceService.getDevice(mepDeviceId) == null) {
-                    throw new CfmConfigException("Device not found " + mepDeviceId);
-                } else if (!deviceService.getDevice(mepDeviceId).is(CfmMepProgrammable.class)) {
-                    throw new CfmConfigException("Device " + mepDeviceId +
-                            " does not support CfmMepProgrammable behaviour.");
-                }
-
-                log.debug("Retrieving MEP reults for Mep {} in MD {}, MA {} on Device {}",
-                        mep.mepId(), mdName, maName, mepDeviceId);
-
-                return deviceService.getDevice(mepDeviceId)
-                        .as(CfmMepProgrammable.class).getMep(mdName, maName, mepId);
-            }
-        }
-        return null;
+    public Collection<Mep> getAllMepsByDevice(DeviceId deviceId) throws CfmConfigException {
+        return mepStore.getMepsByDeviceId(deviceId);
     }
 
     @Override
-    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
+    public MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
+        MepKeyId key = new MepKeyId(mdName, maName, mepId);
+
         //Will throw IllegalArgumentException if ma does not exist
         cfmMdService.getMaintenanceAssociation(mdName, maName);
 
-        for (Mep mep : mepCollection) {
-            if (mep.mdId().equals(mdName) && mep.maId().equals(maName)
-                    && mep.mepId().equals(mepId)) {
-                Device mepDevice = deviceService.getDevice(mep.deviceId());
-                if (mepDevice == null || !mepDevice.is(CfmMepProgrammable.class)) {
-                    throw new CfmConfigException("Unexpeced fault on device drier for "
-                            + mep.deviceId());
-                }
-                boolean deleted = false;
-                try {
-                     deleted = mepDevice.as(CfmMepProgrammable.class)
-                            .deleteMep(mdName, maName, mepId);
-                } catch (CfmConfigException e) {
-                    log.warn("MEP could not be deleted on device - perhaps it "
-                            + "does not exist. Continuing");
-                    mepCollection.remove(mep);
-                    return false;
-                }
-                if (deleted) {
-                    mepCollection.remove(mep);
-                    return true;
-                } else {
-                    return false;
+        Optional<Mep> mepOptional = mepStore.getMep(key);
+        if (mepOptional.isPresent()) {
+            Mep mep = mepOptional.get();
+            DeviceId mepDeviceId = mep.deviceId();
+            if (deviceService.getDevice(mepDeviceId) == null) {
+                throw new CfmConfigException("Device not found " + mepDeviceId);
+            } else if (!deviceService.getDevice(mepDeviceId).is(CfmMepProgrammable.class)) {
+                throw new CfmConfigException("Device " + mepDeviceId +
+                        " does not support CfmMepProgrammable behaviour.");
+            }
+
+            log.debug("Retrieving MEP reults for Mep {} in MD {}, MA {} on Device {}",
+                    mep.mepId(), mdName, maName, mepDeviceId);
+
+            return deviceService.getDevice(mepDeviceId)
+                    .as(CfmMepProgrammable.class).getMep(mdName, maName, mepId);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId,
+                             Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
+        MepKeyId key = new MepKeyId(mdName, maName, mepId);
+
+        //Will throw IllegalArgumentException if ma does not exist
+        cfmMdService.getMaintenanceAssociation(mdName, maName);
+
+        //Get the device ID from the MEP
+        Optional<Mep> deletedMep = mepStore.getMep(key);
+        if (!deletedMep.isPresent()) {
+            log.warn("MEP {} not found when deleting Mep", key);
+            return false;
+        }
+
+        DeviceId mepDeviceId = deletedMep.get().deviceId();
+        boolean deleted = mepStore.deleteMep(key);
+
+        Device mepDevice = deviceService.getDevice(mepDeviceId);
+        if (mepDevice == null || !mepDevice.is(CfmMepProgrammable.class)) {
+            throw new CfmConfigException("Unexpeced fault on device driver for "
+                    + mepDeviceId);
+        }
+        try {
+            deleted = mepDevice.as(CfmMepProgrammable.class)
+                    .deleteMep(mdName, maName, mepId, oldMd);
+        } catch (CfmConfigException e) {
+            log.warn("MEP could not be deleted on device - perhaps it "
+                    + "does not exist. Continuing");
+        }
+
+        //Iterate through all other devices and remove as a Remote Mep
+        int mepsOnMdCount = 0;
+        int mepsOnMaCount = 0;
+        for (Mep mep : mepStore.getAllMeps()) {
+            if (mep.deviceId().equals(mepDeviceId) && mdName.equals(mep.mdId())) {
+                mepsOnMdCount++;
+                if (maName.equals(mep.maId())) {
+                    mepsOnMaCount++;
                 }
             }
+            List<DeviceId> alreadyHandledDevices = new ArrayList<>();
+            if (mep.deviceId().equals(mepDeviceId) || !mep.mdId().equals(mdName) ||
+                    !mep.maId().equals(maName) ||
+                    alreadyHandledDevices.contains(mep.deviceId())) {
+                continue;
+            }
+            deviceService.getDevice(mep.deviceId())
+                    .as(CfmMepProgrammable.class)
+                    .deleteMaRemoteMepOnDevice(mdName, maName, mepId);
+            alreadyHandledDevices.add(mep.deviceId());
+            log.info("Deleted RMep entry on {} on device {}",
+                    mdName.mdName() + "/" + maName.maName(), mep.deviceId());
         }
-        return false;
+
+        //Also if this is the last MEP in this MA then delete this MA from device
+        //If this is the last MA in this MD on device, then delete the MD from the device
+        if (mepsOnMdCount == 0) {
+            boolean deletedMd = deviceService.getDevice(mepDeviceId)
+                    .as(CfmMepProgrammable.class).deleteMdOnDevice(mdName, oldMd);
+            log.info("Deleted MD {} from Device {}", mdName.mdName(), mepDeviceId);
+        } else if (mepsOnMaCount == 0) {
+            boolean deletedMa = deviceService.getDevice(mepDeviceId)
+                    .as(CfmMepProgrammable.class).deleteMaOnDevice(mdName, maName, oldMd);
+            log.info("Deleted MA {} from Device {}",
+                    mdName.mdName() + "/" + maName.maName(), mepDeviceId);
+        }
+
+        return deleted;
     }
 
     @Override
     public boolean createMep(MdId mdName, MaIdShort maName, Mep newMep) throws CfmConfigException {
+        MepKeyId key = new MepKeyId(mdName, maName, newMep.mepId());
         log.debug("Creating MEP " + newMep.mepId() + " on MD {}, MA {} on Device {}",
                 mdName, maName, newMep.deviceId().toString());
-        for (Mep mep : mepCollection) {
-            if (mep.mdId().equals(mdName) && mep.maId().equals(maName)
-                    && mep.mepId().equals(newMep.mepId())) {
-                return false;
-            }
+        if (mepStore.getMep(key).isPresent()) {
+            return false;
         }
 
         //Will throw IllegalArgumentException if ma does not exist
@@ -225,7 +306,24 @@
                 deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class).createMep(mdName, maName, newMep);
         log.debug("MEP created on {}", mepDeviceId);
         if (deviceResult) {
-            return mepCollection.add(newMep);
+            boolean alreadyExisted = mepStore.createUpdateMep(key, newMep);
+
+            //Add to other Remote Mep List on other devices
+            for (Mep mep:mepStore.getMepsByMdMa(mdName, maName)) {
+                List<DeviceId> alreadyHandledDevices = new ArrayList<>();
+                if (mep.deviceId().equals(mepDeviceId) ||
+                        alreadyHandledDevices.contains(mep.deviceId())) {
+                    continue;
+                }
+                boolean created = deviceService.getDevice(mep.deviceId())
+                        .as(CfmMepProgrammable.class)
+                        .createMaRemoteMepOnDevice(mdName, maName, newMep.mepId());
+                alreadyHandledDevices.add(mep.deviceId());
+                log.info("Created RMep entry on {} on device {}",
+                        mdName.mdName() + "/" + maName.maName(), mep.deviceId());
+            }
+
+            return !alreadyExisted;
         } else {
             return deviceResult;
         }
@@ -233,60 +331,253 @@
 
     @Override
     public void transmitLoopback(MdId mdName, MaIdShort maName,
-            MepId mepId, MepLbCreate lbCreate) throws CfmConfigException {
-        for (Mep mep : mepCollection) {
-            if (mep.mdId().equals(mdName) && mep.maId().equals(maName)
-                    && mep.mepId().equals(mepId)) {
-                log.debug("Transmitting Loopback on MEP {}/{}/{} on Device {}",
-                        mdName, maName, mepId, mep.deviceId());
-                deviceService.getDevice(mep.deviceId())
-                    .as(CfmMepProgrammable.class)
-                    .transmitLoopback(mdName, maName, mepId, lbCreate);
-                return;
-            }
-        }
-        throw new CfmConfigException("Mep " + mdName + "/" + maName + "/"
-                + mepId + " not found when calling Transmit Loopback");
+                                 MepId mepId, MepLbCreate lbCreate) throws CfmConfigException {
+        MepKeyId key = new MepKeyId(mdName, maName, mepId);
+        Mep mep = mepStore.getMep(key)
+                .orElseThrow(() -> new CfmConfigException("Mep " + mdName + "/" + maName + "/"
+                + mepId + " not found when calling Transmit Loopback"));
+
+        log.debug("Transmitting Loopback on MEP {} on Device {}",
+                key, mep.deviceId());
+        deviceService.getDevice(mep.deviceId())
+                .as(CfmMepProgrammable.class)
+                .transmitLoopback(mdName, maName, mepId, lbCreate);
     }
 
     @Override
     public void abortLoopback(MdId mdName, MaIdShort maName, MepId mepId)
             throws CfmConfigException {
-        for (Mep mep : mepCollection) {
-            if (mep.mdId().equals(mdName) && mep.maId().equals(maName)
-                    && mep.mepId().equals(mepId)) {
-                log.debug("Aborting Loopback on MEP {}/{}/{} on Device {}",
-                        mdName, maName, mepId, mep.deviceId());
-                deviceService.getDevice(mep.deviceId())
-                    .as(CfmMepProgrammable.class)
-                    .abortLoopback(mdName, maName, mepId);
-                return;
-            }
-        }
-        throw new CfmConfigException("Mep " + mdName + "/" + maName + "/"
-                + mepId + " not found when calling Transmit Loopback");
+
+        MepKeyId key = new MepKeyId(mdName, maName, mepId);
+        Mep mep = mepStore.getMep(key)
+                .orElseThrow(() -> new CfmConfigException("Mep " + mdName + "/" + maName + "/"
+                        + mepId + " not found when calling Aborting Loopback"));
+
+        log.debug("Aborting Loopback on MEP {} on Device {}",
+                key, mep.deviceId());
+        deviceService.getDevice(mep.deviceId())
+                .as(CfmMepProgrammable.class)
+                .abortLoopback(mdName, maName, mepId);
     }
 
     @Override
     public void transmitLinktrace(MdId mdName, MaIdShort maName, MepId mepId,
-            MepLtCreate ltCreate) {
+                                  MepLtCreate ltCreate) {
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
+    private class InternalMdListener implements MdListener {
+        @Override
+        public boolean isRelevant(MdEvent event) {
+            return event.type().equals(MdEvent.Type.MD_REMOVED) ||
+                    event.type().equals(MdEvent.Type.MA_REMOVED);
+        }
+
+        @Override
+        public void event(MdEvent event) {
+            MdId mdName = event.subject();
+            switch (event.type()) {
+                case MA_REMOVED:
+                case MD_REMOVED:
+                    log.trace("Event {} receieved from MD Service for {}", event.type(), mdName);
+                    scheduleEventHandlerIfNotScheduled(event);
+                    break;
+                default:
+                    log.warn("Unhandled Event {} received from MD Service", event.type());
+                    break;
+            }
+        }
+    }
+
     private class InternalDeviceListener implements DeviceListener {
         @Override
+        public boolean isRelevant(DeviceEvent event) {
+            return event.type().equals(DeviceEvent.Type.DEVICE_REMOVED);
+        }
+
+        @Override
         public void event(DeviceEvent event) {
+            DeviceId deviceId = event.subject().id();
             switch (event.type()) {
+                case DEVICE_ADDED:
+                case PORT_UPDATED:
+                case PORT_ADDED:
+                case DEVICE_UPDATED:
                 case DEVICE_REMOVED:
                 case DEVICE_AVAILABILITY_CHANGED:
-                    DeviceId deviceId = event.subject().id();
-                    if (!deviceService.isAvailable(deviceId)) {
-                        log.warn("Device {} has been removed or changed", deviceId);
-                    }
+                    log.trace("Event {} received from Device Service", event.type());
+                    scheduleEventHandlerIfNotScheduled(event);
                     break;
                 default:
+                    log.warn("Unhandled Event {} received from Device Service", event.type());
                     break;
             }
         }
     }
+
+    @SuppressWarnings("rawtypes")
+    private void scheduleEventHandlerIfNotScheduled(Event event) {
+        synchronized (THREAD_SCHED_LOCK) {
+            eventQueue.add(event);
+            numOfEventsQueued++;
+
+            if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
+                //No pending scheduled event handling threads. So start a new one.
+                eventHandlerFuture = executorService
+                        .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
+                numOfHandlerScheduled++;
+            }
+            log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
+                    numOfEventsQueued,
+                    numOfHandlerScheduled);
+        }
+    }
+
+    private class InternalEventHandler implements Runnable {
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    @SuppressWarnings("rawtypes")
+                    Event event;
+                    synchronized (THREAD_SCHED_LOCK) {
+                        if (!eventQueue.isEmpty()) {
+                            event = eventQueue.poll();
+                            numOfEventsExecuted++;
+                        } else {
+                            numOfHandlerExecution++;
+                            log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
+                                    numOfHandlerExecution, numOfEventsExecuted);
+                            break;
+                        }
+                    }
+                    if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) {
+                        DeviceId deviceId = ((Device) event.subject()).id();
+                        log.info("Processing device removal event for unavailable device {}",
+                                deviceId);
+                        processDeviceRemoved((Device) event.subject());
+                    } else if (event.type() == MdEvent.Type.MD_REMOVED) {
+                        MdId mdName = (MdId) event.subject();
+                        log.info("Processing MD removal event for MD {}",
+                                mdName);
+                        processMdRemoved(mdName, ((MdEvent) event).md().get());
+                    } else if (event.type() == MdEvent.Type.MA_REMOVED) {
+                        MdId mdName = (MdId) event.subject();
+                        MaIdShort maName = ((MdEvent) event).maId().get();
+                        log.info("Processing MA removal event for MA {}",
+                                mdName.mdName() + "/" + maName.maName());
+                        processMaRemoved(mdName, maName, ((MdEvent) event).md().get());
+                    }
+                }
+            } catch (Exception e) {
+                log.error("CfmMepService event handler "
+                        + "thread thrown an exception: {}", e);
+            }
+        }
+    }
+
+    /**
+     * This removes a MEP from the internal list of Meps, and updates remote meps list on other Meps.
+     * Note: This does not call the device's CfmMepProgrammable, because there
+     * would be no point as the device has already been removed from ONOS.
+     * The configuration for this MEP may still be present on the actual device, and
+     * any future config would have to be careful to wipe the Mep from the device
+     * before applying a Mep again
+     * @param removedDevice The device that has been removed
+     */
+    protected void processDeviceRemoved(Device removedDevice) {
+        log.warn("Remove Mep(s) associated with Device: " + removedDevice.id());
+        Collection<Mep> mepListForDevice = mepStore.getMepsByDeviceId(removedDevice.id());
+
+
+        for (Mep mep:mepStore.getAllMeps()) {
+            for (Mep mepForDevice:mepListForDevice) {
+                if (mep.mdId().equals(mepForDevice.mdId()) && mep.maId().equals(mepForDevice.maId())) {
+                    Device mepDevice = deviceService.getDevice(mep.deviceId());
+                    log.info("Removing Remote Mep {} from MA{} on device {}",
+                            mepForDevice.mepId(),
+                            mep.mdId().mdName() + "/" + mep.maId().maName(),
+                            mepDevice.id());
+                    try {
+                        mepDevice.as(CfmMepProgrammable.class)
+                                .deleteMaRemoteMepOnDevice(mep.mdId(), mep.maId(), mepForDevice.mepId());
+                    } catch (CfmConfigException e) {
+                        log.error("Error when removing Remote Mep {} from MA {}. Continuing.",
+                                mep.mdId().mdName() + "/" + mep.maId().maName(),
+                                mepForDevice.mepId());
+                    }
+                }
+            }
+        }
+
+        for (Iterator<Mep> iter = mepListForDevice.iterator(); iter.hasNext();) {
+            mepStore.deleteMep(new MepKeyId(iter.next()));
+        }
+    }
+
+    protected void processMaRemoved(MdId mdId, MaIdShort maId, MaintenanceDomain oldMd) {
+        Set<DeviceId> deviceIdsRemoved = new HashSet<>();
+
+        for (Iterator<Mep> iter = mepStore.getMepsByMdMa(mdId, maId).iterator(); iter.hasNext();) {
+            Mep mepForMdMa = iter.next();
+            DeviceId mepDeviceId = mepForMdMa.deviceId();
+            try {
+                deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class)
+                        .deleteMep(mdId, maId, mepForMdMa.mepId(), Optional.of(oldMd));
+                deviceIdsRemoved.add(mepDeviceId);
+            } catch (CfmConfigException e) {
+                log.warn("Could not delete MEP {} from Device {}", mepForMdMa.mepId(), mepDeviceId, e);
+            }
+            iter.remove();
+
+            log.info("Removed MEP {} from Device {} because MA {} was deleted",
+                    mepForMdMa.mepId(), mepDeviceId, mdId.mdName() + "/" + maId.maName());
+        }
+
+        deviceIdsRemoved.forEach(deviceId -> {
+            try {
+                deviceService.getDevice(deviceId).as(CfmMepProgrammable.class)
+                        .deleteMaOnDevice(mdId, maId, Optional.of(oldMd));
+            } catch (CfmConfigException e) {
+                log.warn("Could not delete MA {} from Device {}",
+                        mdId.mdName() + "/" + maId.maName(), deviceId, e);
+            }
+        });
+    }
+
+    protected void processMdRemoved(MdId mdId, MaintenanceDomain oldMd) {
+        Set<DeviceId> deviceIdsRemoved = new HashSet<>();
+        for (Iterator<Mep> iter = mepStore.getMepsByMd(mdId).iterator(); iter.hasNext();) {
+            Mep mep = iter.next();
+            DeviceId mepDeviceId = mep.deviceId();
+            try {
+                deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class)
+                        .deleteMep(mdId, mep.maId(), mep.mepId(), Optional.of(oldMd));
+                deviceIdsRemoved.add(mepDeviceId);
+            } catch (CfmConfigException e) {
+                log.warn("Could not delete MEP {} from Device {}", mep.mepId(), mepDeviceId, e);
+            }
+            iter.remove();
+            log.info("Removed MEP {} from Device {} because MD {} was deleted",
+                    mep.mepId(), mepDeviceId, mdId.mdName());
+        }
+
+        deviceIdsRemoved.forEach(deviceId -> {
+            try {
+                deviceService.getDevice(deviceId).as(CfmMepProgrammable.class)
+                        .deleteMdOnDevice(mdId, Optional.of(oldMd));
+            } catch (CfmConfigException e) {
+                log.warn("Could not delete MD {} from Device {}",
+                        mdId.mdName(), deviceId, e);
+            }
+        });
+    }
+
+    private class InternalStoreDelegate implements MepStoreDelegate {
+        @Override
+        public void notify(CfmMepEvent event) {
+            log.debug("New Mep event: {}", event);
+            eventDispatcher.post(event);
+        }
+    }
 }
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMdStore.java b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMdStore.java
index 964a56a..82c550d 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMdStore.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMdStore.java
@@ -19,6 +19,7 @@
 import org.apache.commons.lang3.tuple.ImmutablePair;
 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;
@@ -42,6 +43,7 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.MdEvent;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.MdStore;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.MdStoreDelegate;
@@ -58,6 +60,8 @@
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Maintenance Domain Store implementation backed by consistent map.
@@ -75,7 +79,7 @@
     private ConsistentMap<MdId, MaintenanceDomain> maintenanceDomainConsistentMap;
     private Map<MdId, MaintenanceDomain> maintenanceDomainMap;
 
-    private final InternalMdListener listener = new InternalMdListener();
+    private MapEventListener<MdId, MaintenanceDomain> mapListener = null;
 
     @Activate
     public void activate() {
@@ -112,8 +116,17 @@
                                             .cfm.Component.TagType.class)
                         .build("md")))
                 .build();
+        mapListener = new InternalMdListener();
+        maintenanceDomainConsistentMap.addListener(mapListener);
 
         maintenanceDomainMap = maintenanceDomainConsistentMap.asJavaMap();
+        log.info("MDStore started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        maintenanceDomainConsistentMap.removeListener(mapListener);
+        log.info("Stopped");
     }
 
     @Override
@@ -141,19 +154,65 @@
         @Override
         public void event(MapEvent<MdId, MaintenanceDomain> mapEvent) {
             final MdEvent.Type type;
+            MaIdShort maId = null;
             switch (mapEvent.type()) {
                 case INSERT:
                     type = MdEvent.Type.MD_ADDED;
                     break;
                 case UPDATE:
-                    type = MdEvent.Type.MD_UPDATED;
+                    // Examine the diff to see if it was a removal or addition of an MA caused it
+                    if (mapEvent.oldValue().value().maintenanceAssociationList().size() >
+                            mapEvent.newValue().value().maintenanceAssociationList().size()) {
+                        Set<MaIdShort> newMaIds = mapEvent.newValue().value().maintenanceAssociationList()
+                                .stream()
+                                .map(MaintenanceAssociation::maId)
+                                .collect(Collectors.toSet());
+                        Optional<MaintenanceAssociation> removedMa =
+                                mapEvent.oldValue().value().maintenanceAssociationList()
+                                        .stream()
+                                        .filter(maOld -> !newMaIds.contains(maOld.maId())).findFirst();
+                        if (removedMa.isPresent()) {
+                            maId = removedMa.get().maId();
+                        }
+                        type = MdEvent.Type.MA_REMOVED;
+                    } else if (mapEvent.oldValue().value().maintenanceAssociationList().size() <
+                        mapEvent.newValue().value().maintenanceAssociationList().size()) {
+                        Set<MaIdShort> oldMaIds = mapEvent.oldValue().value().maintenanceAssociationList()
+                                .stream()
+                                .map(MaintenanceAssociation::maId)
+                                .collect(Collectors.toSet());
+                        Optional<MaintenanceAssociation> addedMa =
+                                mapEvent.newValue().value().maintenanceAssociationList()
+                                        .stream()
+                                        .filter(maNew -> !oldMaIds.contains(maNew.maId())).findFirst();
+                        if (addedMa.isPresent()) {
+                            maId = addedMa.get().maId();
+                        }
+                        type = MdEvent.Type.MA_ADDED;
+                    } else {
+                        type = MdEvent.Type.MD_UPDATED;
+                    }
                     break;
                 case REMOVE:
                 default:
                     type = MdEvent.Type.MD_REMOVED;
                     break;
             }
-            notifyDelegate(new MdEvent(type, mapEvent.key()));
+            if (mapEvent.oldValue() != null && mapEvent.oldValue().value() != null) {
+                MaintenanceDomain oldMd = mapEvent.oldValue().value();
+                try {
+                    if (maId != null) {
+                        notifyDelegate(new MdEvent(type, mapEvent.key(), oldMd, maId));
+                    } else {
+                        notifyDelegate(new MdEvent(type, mapEvent.key(), oldMd));
+                    }
+                } catch (CfmConfigException e) {
+                    log.warn("Unable to copy MD {}", oldMd);
+                    notifyDelegate(new MdEvent(type, mapEvent.key()));
+                }
+            } else {
+                notifyDelegate(new MdEvent(type, mapEvent.key()));
+            }
         }
     }
 }
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMepStore.java b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMepStore.java
new file mode 100644
index 0000000..c21166a
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/DistributedMepStore.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.incubator.net.l2monitoring.cfm.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.VlanId;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepEvent;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStore;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStoreDelegate;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetworkResource;
+import org.onosproject.net.PortNumber;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * MEP Store implementation backed by consistent map.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedMepStore extends AbstractStore<CfmMepEvent, MepStoreDelegate>
+    implements MepStore {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    private ConsistentMap<MepKeyId, Mep> mepConsistentMap;
+    private Map<MepKeyId, Mep> mepMap;
+
+    private MapEventListener<MepKeyId, Mep> mapListener = null;
+
+    @Activate
+    public void activate() {
+        mepConsistentMap = storageService
+                .<MepKeyId, Mep>consistentMapBuilder()
+                .withName("onos-cfm-mep-map")
+                .withSerializer(Serializer.using(new KryoNamespace.Builder()
+                        .register(KryoNamespaces.API)
+                        .register(DefaultMep.class)
+                        .register(MepId.class)
+                        .register(MepKeyId.class)
+                        .register(NetworkResource.class)
+                        .register(DeviceId.class)
+                        .register(PortNumber.class)
+                        .register(Mep.MepDirection.class)
+                        .register(VlanId.class)
+                        .register(Mep.Priority.class)
+                        .register(Mep.FngAddress.class)
+                        .register(Mep.FngAddressType.class)
+                        .register(IpAddress.class)
+                        .register(Mep.LowestFaultDefect.class)
+                        .register(Duration.class)
+                        .register(MdIdCharStr.class)
+                        .register(MdIdDomainName.class)
+                        .register(MdIdMacUint.class)
+                        .register(MdIdNone.class)
+                        .register(MaIdCharStr.class)
+                        .register(MaIdShort.class)
+                        .register(MaId2Octet.class)
+                        .register(MaIdIccY1731.class)
+                        .register(MaIdPrimaryVid.class)
+                        .register(MaIdRfc2685VpnId.class)
+                        .build("mep")))
+                .build();
+        mapListener = new InternalMepListener();
+        mepConsistentMap.addListener(mapListener);
+
+        mepMap = mepConsistentMap.asJavaMap();
+        log.info("MepStore started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        mepConsistentMap.removeListener(mapListener);
+        log.info("MepStore stopped");
+    }
+
+    @Override
+    public Collection<Mep> getAllMeps() {
+        return mepMap.values();
+    }
+
+    @Override
+    public Collection<Mep> getMepsByMd(MdId mdName) {
+        return mepMap.values().stream()
+                .filter(mep -> mep.mdId().equals(mdName))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Collection<Mep> getMepsByMdMa(MdId mdName, MaIdShort maName) {
+        return mepMap.values().stream()
+                .filter(mep -> mep.mdId().equals(mdName) && mep.maId().equals(maName))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Collection<Mep> getMepsByDeviceId(DeviceId deviceId) {
+        return mepMap.values().stream()
+                .filter(mep -> mep.deviceId().equals(deviceId))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Optional<Mep> getMep(MepKeyId mepKeyId) {
+        return mepMap.values().stream()
+                .filter(mep -> mep.mdId().equals(mepKeyId.mdId()) &&
+                        mep.maId().equals(mepKeyId.maId()) &&
+                        mep.mepId().equals(mepKeyId.mepId()))
+                .findFirst();
+    }
+
+    @Override
+    public boolean deleteMep(MepKeyId mepKeyId) {
+        return mepMap.remove(mepKeyId) == null ? false : true;
+    }
+
+    @Override
+    public boolean createUpdateMep(MepKeyId mepKeyId, Mep mep) {
+        return mepMap.put(mepKeyId, mep) == null ? false : true;
+    }
+
+    private class InternalMepListener implements MapEventListener<MepKeyId, Mep> {
+
+        @Override
+        public void event(MapEvent<MepKeyId, Mep> mapEvent) {
+            final CfmMepEvent.Type type;
+
+            switch (mapEvent.type()) {
+                case INSERT:
+                    type = CfmMepEvent.Type.MEP_ADDED;
+                    break;
+                case UPDATE:
+                    type = CfmMepEvent.Type.MEP_UPDATED;
+                    break;
+                default:
+                case REMOVE:
+                    type = CfmMepEvent.Type.MEP_REMOVED;
+            }
+            notifyDelegate(new CfmMepEvent(type, mapEvent.key()));
+        }
+    }
+}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManagerTest.java
index a0de513..fa79546 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMdManagerTest.java
@@ -36,10 +36,13 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
 import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
 import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.net.DeviceId;
 import org.onosproject.store.service.TestStorageService;
@@ -50,6 +53,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import static junit.framework.TestCase.assertFalse;
+import static org.easymock.EasyMock.createMock;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -61,6 +65,11 @@
 public class CfmMdManagerTest {
     private static final NodeId NID_LOCAL = new NodeId("local");
     private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
+    private static final MaIdShort MA_ID_1_1 = MaIdCharStr.asMaId("test-ma-1-1");
+    private static final MaIdShort MA_ID_1_2 = MaIdCharStr.asMaId("test-ma-1-2");
+    private static final MdId MD_ID_1 = MdIdCharStr.asMdId("test-md-1");
+
+    private final CfmMepService mepService = createMock(CfmMepService.class);
 
     private DistributedMdStore mdStore;
     private CfmMdService service;
@@ -71,7 +80,7 @@
         mdStore = new DistributedMdStore();
 
         MaintenanceAssociation maTest11 = DefaultMaintenanceAssociation
-                .builder(MaIdCharStr.asMaId("test-ma-1-1"), 9)
+                .builder(MA_ID_1_1, MD_ID_1.getNameLength())
                 .ccmInterval(MaintenanceAssociation.CcmInterval.INTERVAL_10MIN)
                 .maNumericId((short) 1)
                 .addToRemoteMepIdList(MepId.valueOf((short) 101))
@@ -83,7 +92,7 @@
                 .build();
 
         MaintenanceAssociation maTest12 = DefaultMaintenanceAssociation
-                .builder(MaIdCharStr.asMaId("test-ma-1-2"), 9)
+                .builder(MA_ID_1_2, MD_ID_1.getNameLength())
                 .ccmInterval(MaintenanceAssociation.CcmInterval.INTERVAL_10MIN)
                 .maNumericId((short) 2)
                 .addToRemoteMepIdList(MepId.valueOf((short) 201))
@@ -95,7 +104,7 @@
                 .build();
 
         MaintenanceDomain mdTest1 = DefaultMaintenanceDomain
-                .builder(MdIdCharStr.asMdId("test-md-1"))
+                .builder(MD_ID_1)
                 .mdLevel(MaintenanceDomain.MdLevel.LEVEL1)
                 .mdNumericId((short) 1)
                 .addToMaList(maTest11)
@@ -105,6 +114,7 @@
         TestUtils.setField(mdStore, "storageService", new TestStorageService());
         TestUtils.setField(mdStore, "clusterService", new CfmMdManagerTest.TestClusterService());
         TestUtils.setField(mdStore, "mastershipService", new CfmMdManagerTest.TestMastershipService());
+
         mdStore.activate();
         mdStore.createUpdateMaintenanceDomain(mdTest1);
 
@@ -113,6 +123,7 @@
         service = manager;
         TestUtils.setField(manager, "storageService", new TestStorageService());
         TestUtils.setField(manager, "coreService", new TestCoreService());
+        TestUtils.setField(manager, "mepService", mepService);
         injectEventDispatcher(manager, new TestEventDispatcher());
 
         manager.appId = new CfmMdManagerTest.TestApplicationId(0, "CfmMdManagerTest");
@@ -339,7 +350,6 @@
                 MdIdCharStr.asMdId("test-md-1")).size());
     }
 
-
     public class TestApplicationId extends DefaultApplicationId {
         public TestApplicationId(int id, String name) {
             super(id, name);
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
index a825858..5941f6f 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
@@ -37,10 +37,12 @@
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
 import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
 import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStore;
 import org.onosproject.incubator.net.l2monitoring.soam.SoamDmProgrammable;
 import org.onosproject.incubator.net.l2monitoring.soam.impl.TestSoamDmProgrammable;
 import org.onosproject.net.AbstractProjectableModel;
@@ -57,21 +59,30 @@
 import org.onosproject.net.driver.Driver;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.service.AsyncDocumentTree;
+import org.onosproject.store.service.DocumentTreeBuilder;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.TestAsyncDocumentTree;
+import org.onosproject.store.service.TestStorageService;
+import org.onosproject.store.service.TestTopic;
+import org.onosproject.store.service.Topic;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicLong;
 
-import static junit.framework.TestCase.fail;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 
 /**
@@ -91,18 +102,32 @@
 
     private CfmMepService mepService;
     private CfmMepManager mepManager;
+    private MepStore mepStore;
+    private StorageService storageService;
 
     protected static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+    protected static final MdId MDNAME2 = MdIdCharStr.asMdId("md-2");
     protected static final MaIdShort MANAME1 = MaIdCharStr.asMaId("ma-1-1");
+    protected static final MaIdShort MANAME2 = MaIdCharStr.asMaId("ma-2-2");
 
     private MaintenanceAssociation ma1;
+    private MaintenanceAssociation ma2;
     protected static final MepId MEPID1 = MepId.valueOf((short) 10);
+    protected static final MepId MEPID11 = MepId.valueOf((short) 11);
+    protected static final MepId MEPID12 = MepId.valueOf((short) 12);
     protected static final MepId MEPID2 = MepId.valueOf((short) 20);
+    protected static final MepId MEPID21 = MepId.valueOf((short) 21);
+    protected static final MepId MEPID22 = MepId.valueOf((short) 22);
+
     protected static final DeviceId DEVICE_ID1 = DeviceId.deviceId("netconf:1.2.3.4:830");
     protected static final DeviceId DEVICE_ID2 = DeviceId.deviceId("netconf:2.2.3.4:830");
 
     private Mep mep1;
+    private Mep mep11;
+    private Mep mep12;
     private Mep mep2;
+    private Mep mep21;
+    private Mep mep22;
 
     private Device device1;
     private Device device2;
@@ -112,12 +137,19 @@
     @Before
     public void setup() throws CfmConfigException {
         mepManager = new CfmMepManager();
+        mepStore = new DistributedMepStore();
+        storageService = new MockStorageService();
 
         ma1 = DefaultMaintenanceAssociation.builder(MANAME1, MDNAME1.getNameLength()).build();
+        ma2 = DefaultMaintenanceAssociation.builder(MANAME2, MDNAME2.getNameLength()).build();
+
+        TestUtils.setField(mepStore, "storageService", storageService);
+        ((DistributedMepStore) mepStore).activate();
 
         TestUtils.setField(mepManager, "coreService", new TestCoreService());
         TestUtils.setField(mepManager, "deviceService", deviceService);
         TestUtils.setField(mepManager, "cfmMdService", mdService);
+        TestUtils.setField(mepManager, "mepStore", mepStore);
         injectEventDispatcher(mepManager, new TestEventDispatcher());
 
         mepService = mepManager;
@@ -125,12 +157,27 @@
 
         mep1 = DefaultMep.builder(MEPID1, DEVICE_ID1, PortNumber.P0,
                 Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
+        mepStore.createUpdateMep(new MepKeyId(MDNAME1, MANAME1, MEPID1), mep1);
+
+        mep11 = DefaultMep.builder(MEPID11, DEVICE_ID1, PortNumber.P0,
+                Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
+        mepStore.createUpdateMep(new MepKeyId(MDNAME1, MANAME1, MEPID11), mep11);
+
+        mep12 = DefaultMep.builder(MEPID12, DEVICE_ID1, PortNumber.P0,
+                Mep.MepDirection.UP_MEP, MDNAME2, MANAME2).build();
+        mepStore.createUpdateMep(new MepKeyId(MDNAME2, MANAME2, MEPID12), mep12);
+
         mep2 = DefaultMep.builder(MEPID2, DEVICE_ID2, PortNumber.portNumber(2),
                 Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
-        List<Mep> mepList = new ArrayList<>();
-        mepList.add(mep1);
-        mepList.add(mep2);
-        TestUtils.setField(mepManager, "mepCollection", mepList);
+        mepStore.createUpdateMep(new MepKeyId(MDNAME1, MANAME1, MEPID2), mep2);
+
+        mep21 = DefaultMep.builder(MEPID21, DEVICE_ID2, PortNumber.portNumber(2),
+                Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
+        mepStore.createUpdateMep(new MepKeyId(MDNAME1, MANAME1, MEPID21), mep21);
+
+        mep22 = DefaultMep.builder(MEPID22, DEVICE_ID2, PortNumber.portNumber(2),
+                Mep.MepDirection.UP_MEP, MDNAME2, MANAME2).build();
+        mepStore.createUpdateMep(new MepKeyId(MDNAME2, MANAME2, MEPID22), mep22);
 
         device1 = new DefaultDevice(
                 ProviderId.NONE, DEVICE_ID1, Device.Type.SWITCH,
@@ -180,7 +227,7 @@
 
         Collection<MepEntry> mepEntries = mepManager.getAllMeps(MDNAME1, MANAME1);
 
-        assertEquals(2, mepEntries.size());
+        assertEquals(4, mepEntries.size());
     }
 
     @Test
@@ -232,12 +279,13 @@
         replay(mdService);
 
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
+        expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
         expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
-        assertTrue(mepManager.deleteMep(MDNAME1, MANAME1, MEPID1));
+        assertTrue(mepManager.deleteMep(MDNAME1, MANAME1, MEPID1, Optional.empty()));
     }
 
     @Test
@@ -248,6 +296,7 @@
         replay(mdService);
 
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
+        expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
         expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
@@ -257,6 +306,7 @@
         Mep mep3 = DefaultMep.builder(mepId3, DEVICE_ID1, PortNumber.portNumber(1),
                 Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
 
+        //Expecting false - since it was not found
         assertTrue(mepManager.createMep(MDNAME1, MANAME1, mep3));
     }
 
@@ -364,6 +414,56 @@
         }
     }
 
+    @Test
+    public void testDeviceRemoved() throws CfmConfigException {
+        expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+                .andReturn(Optional.ofNullable(ma1))
+                .anyTimes();
+        expect(mdService.getMaintenanceAssociation(MDNAME2, MANAME2))
+                .andReturn(Optional.ofNullable(ma2))
+                .anyTimes();
+        replay(mdService);
+
+        expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
+        expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
+        replay(deviceService);
+
+        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        replay(driverService);
+
+//        This is arranged like
+//        device1                             device2
+//        /       \                           /       \
+//    md-1        md-2                     md-1      md-2
+//      |           |                         |        |
+//    ma-1-1      ma-2-2                   ma-1-1    ma-2-2
+//    /    \         |                      /   \        \
+//  mep1  mep11   mep12                  mep2 mep21     mep22
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID1));
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID11));
+        assertNotNull(mepService.getMep(MDNAME2, MANAME2, MEPID12));
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID2));
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID21));
+        assertNotNull(mepService.getMep(MDNAME2, MANAME2, MEPID22));
+
+        //By deleting Device2 we expect Mep2,21,22 to have been deleted but Mep1,11,12 to remain
+        ((CfmMepManager) mepService).processDeviceRemoved(device2);
+
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID1));
+        assertNotNull(mepService.getMep(MDNAME1, MANAME1, MEPID11));
+        assertNotNull(mepService.getMep(MDNAME2, MANAME2, MEPID12));
+        //The device 2 related ones are gone
+        assertNull(mepService.getMep(MDNAME1, MANAME1, MEPID2));
+        assertNull(mepService.getMep(MDNAME1, MANAME1, MEPID21));
+        assertNull(mepService.getMep(MDNAME2, MANAME2, MEPID22));
+
+        //Now delete device1
+        ((CfmMepManager) mepService).processDeviceRemoved(device1);
+        assertNull(mepService.getMep(MDNAME1, MANAME1, MEPID1));
+        assertNull(mepService.getMep(MDNAME1, MANAME1, MEPID11));
+        assertNull(mepService.getMep(MDNAME2, MANAME2, MEPID12));
+    }
+
     private class TestCoreService extends CoreServiceAdapter {
 
         @Override
@@ -378,4 +478,27 @@
             };
         }
     }
+
+    private static class MockStorageService extends TestStorageService {
+        @Override
+        public <V> DocumentTreeBuilder<V> documentTreeBuilder() {
+            return new DocumentTreeBuilder<V>() {
+                @Override
+                public AsyncDocumentTree<V> buildDocumentTree() {
+                    return build();
+                }
+
+                @Override
+                @SuppressWarnings("unchecked")
+                public AsyncDocumentTree<V> build() {
+                    return new TestAsyncDocumentTree<>(name());
+                }
+            };
+        }
+
+        @Override
+        public <T> Topic<T> getTopic(String name, Serializer serializer) {
+            return new TestTopic<>(name);
+        }
+    }
 }
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/TestCfmMepProgrammable.java b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/TestCfmMepProgrammable.java
index 8d0f765..3f4be0e 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/TestCfmMepProgrammable.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/TestCfmMepProgrammable.java
@@ -17,6 +17,7 @@
 
 import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMep;
 import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
 import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
 import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
@@ -30,8 +31,8 @@
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
+import java.util.Optional;
 
 import static org.onosproject.incubator.net.l2monitoring.cfm.impl.CfmMepManagerTest.*;
 
@@ -47,13 +48,16 @@
 
         deviceMepList.add(DefaultMep.builder(MEPID1, DEVICE_ID1, PortNumber.P0,
                 Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build());
+        deviceMepList.add(DefaultMep.builder(MEPID11, DEVICE_ID1, PortNumber.P0,
+                Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build());
+        deviceMepList.add(DefaultMep.builder(MEPID12, DEVICE_ID1, PortNumber.P0,
+                Mep.MepDirection.UP_MEP, MDNAME2, MANAME2).build());
         deviceMepList.add(DefaultMep.builder(MEPID2, DEVICE_ID2, PortNumber.portNumber(2),
                 Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build());
-    }
-
-    @Override
-    public Collection<MepEntry> getAllMeps(MdId mdName, MaIdShort maName) throws CfmConfigException {
-        return null;
+        deviceMepList.add(DefaultMep.builder(MEPID21, DEVICE_ID2, PortNumber.portNumber(2),
+                Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build());
+        deviceMepList.add(DefaultMep.builder(MEPID22, DEVICE_ID2, PortNumber.portNumber(2),
+                Mep.MepDirection.UP_MEP, MDNAME2, MANAME2).build());
     }
 
     @Override
@@ -67,7 +71,8 @@
     }
 
     @Override
-    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
+    public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId,
+                             Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
         return true;
     }
 
@@ -77,6 +82,37 @@
     }
 
     @Override
+    public boolean deleteMdOnDevice(MdId mdId, Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
+    public boolean deleteMaOnDevice(MdId mdId, MaIdShort maId,
+                                    Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
+    public boolean createMdOnDevice(MdId mdId) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
+    public boolean createMaOnDevice(MdId mdId, MaIdShort maId) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
+    public boolean createMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
+    public boolean deleteMaRemoteMepOnDevice(MdId mdId, MaIdShort maId, MepId remoteMep) throws CfmConfigException {
+        return false;
+    }
+
+    @Override
     public void transmitLoopback(MdId mdName, MaIdShort maName, MepId mepId, MepLbCreate lbCreate)
             throws CfmConfigException {