Initial import of Microsemi Driver

Change-Id: I431d5f2c18e0b66a84c36273c3d9f0b84f223841

Added in BUCK files for building driver

Change-Id: I70681327f5b89f67e904c45d5974ab393652d51f

Corrected some syntax errors

Change-Id: I11150cc499c212005f80619e3900e747f1c23d96

Updated pom file to clean build

Change-Id: I6613ddc9e6802aa882e716cf04df210249870835

Added in utility functions for EA1000 Init

Change-Id: I51ffe0cf0daf9ffcea0e2479ee9982fcd1755440

Added YMS code to Microsemi Driver

Change-Id: I6f2a14e454c6909bf9e9f6025321c74c98c13c72

Updated driver to work with YMS and YCH

Change-Id: If7dbe3cd5bd1b6f902d09d6b2dc3895605d70f70

Implemented IetfSystemManager as a service and call on YMS as a service

Change-Id: If1c5e8482b1f53f578a3b0b770accd50024111cf

Moved YMS calls over in to Yang Service implementation

Change-Id: I044aad06f1ef7452bc48e88987787a683666cd72

improved unit test for IetfSystemManager

Change-Id: I48fbf831e7e5ca0e1ef3de8288e56da1b5ebb7a4

Major changes to IetfSystemManager to work in live system

Change-Id: I6e3aa118ba422151f314b9a666860d90905c9929

Added in retry mechanism for DeviceDescription to wait for YCH

Change-Id: If8e0f2c2f315ffd6db15627a11382a00217dd262

Added in implementation of MseaSaFiltering and unit tests

Change-Id: I34bf888e0e732bd4664d1fb8ef5abb679b1506fe

Updated driver with unit tests for MseaSaFiltering

Change-Id: I7ea2407a546622ff55d1ab21610c45697546d632

Modified removeFlowRules of Ea1000FlowRuleProgrammable

Change-Id: Ibb4a555f61887a8e6e42af588bb42f7b70f58efb

Added in manager for MseaUniEvc service with unit tests

Change-Id: Idc5853f46051548973f52a0659f7f88982ff960c

Implemented getFlowEntries() for EVCs from EA1000

Change-Id: Ie85dadfa7760f0b30a9bdf6ccd09cca9f097fff9

Added in translation of FlowRules in to EVC on EA1000

Change-Id: Icfb65171c3300c96b3ca4e18cbd327f0ed2190be

Added in handling of FlowRule deletion including complex ceVlanMaps

Change-Id: I7fd0bb0ef04d1b40e4b7d6a6db7f7ee662329780

Updated Service entries for new onos-yang-tools

Change-Id: I44e655202f3a45073e1e16f83737caed6e01afa8

Revert "Updated Service entries for new onos-yang-tools"

This reverts commit 642b550ef1de12ed59bad2eaa3a2da414d2e5e59.

Improved timeout mechanism for YANG model loading

Change-Id: If744ecd206372e822edf2b736c83226321a12256

Minor edits of EVC creation

Change-Id: Ib0a4763deaf6dce37625ba77f5095b39cd98272d

Added in CustomEvc and supporting classes

Change-Id: Iad60eb1bcd48d2aec55b894b2d419b51852c3b2f

Created CeVlanUtils to resolve loading problem

Change-Id: I0d63931ad2c5ad2725861ebc7dccc4d5fe7b9298

Modified startup check

Change-Id: I6e6bcfa7e615044cb08fe7ee2f8a6c8b89aabb21

Modified handlin of flow rules

Change-Id: I965a79c23298866122aeb94c6d9d584aafee3bd5

Fixed problem with ceVlanMap

Change-Id: If1458c35d0b95b5b25b6636f098292f9e91c06c6

Minor Pom edits

Change-Id: I5cefb18674aa04b1f50bd7e2306260c1c3ad3814

Commented out extension references in YANG files to avoid onos-yang-tools problems

Change-Id: I32fdb34c4f476f495fe28e75d0f410aaf14e2ec1

Corrected error in removing 0 in CeVlanMapUtils

Change-Id: I8cd1fd02788b81c2613364d5639ef6e090057f80

Changes in YMS to accomodate EA1000 driver

Change-Id: I6ae2b9bd2be49eae8d4ad2f929dfe3214c514550
diff --git a/drivers/microsemi/ea1000driver/BUCK.ignore b/drivers/microsemi/ea1000driver/BUCK.ignore
new file mode 100644
index 0000000..bee66fb
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/BUCK.ignore
@@ -0,0 +1,41 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//drivers/utilities:onos-drivers-utilities',
+    '//protocols/netconf/api:onos-protocols-netconf-api',
+    '//protocols/netconf/ctl:onos-protocols-netconf-ctl',
+    '//drivers/microsemi/ea1000yang:onos-drivers-microsemi-ea1000yang',
+    '//drivers/microsemi/ea1000yang:onos-drivers-microsemi-ea1000yang-gen',
+    '//lib:org.apache.karaf.shell.console',
+    '//cli:onos-cli',
+    '//incubator/api:onos-incubator-api',
+]
+
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS',
+    '//core/api:onos-api-tests',
+    '//drivers/netconf:onos-drivers-netconf-tests',
+    '//drivers/microsemi/ea1000yang:onos-drivers-microsemi-ea1000yang-tests',
+]
+
+BUNDLES = [
+    '//drivers/utilities:onos-drivers-utilities',
+    '//drivers/microsemi/ea1000yang:onos-drivers-microsemi-ea1000yang',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+    srcs = glob(['src/main/java/**/*.java']),
+    resources_root = 'src/main/resources',
+    resources = glob(['src/main/resources/**']),
+)
+
+onos_app (
+    app_name = 'org.onosproject.drivers.microsemi',
+    title = 'Microsemi device drivers',
+    category = 'Drivers',
+    url = 'http://onosproject.org',
+    description = 'ONOS Microsemi device drivers application.',
+    included_bundles = BUNDLES,
+    required_apps = [ 'org.onosproject.netconf', 'org.onosproject.yms' ],
+)
diff --git a/drivers/microsemi/ea1000driver/README.md b/drivers/microsemi/ea1000driver/README.md
new file mode 100755
index 0000000..4187039
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/README.md
@@ -0,0 +1,363 @@
+#Microsemi Edge Assure 1000 SFP-NID
+This driver allows connection to the Microsemi Edge Assure 1000 SFP-NID
+[EdgeAssure 1000 Product Page](https://www.microsemi.com/existing-parts/parts/137346)
+
+The User Guide for this product is available on request from Microsemi, and gives a full explanation of the theory of operation, functionality and how all functions can be accessed through the NETCONF interface only.<br/>
+
+Currently only a subset of it's functionality is supported through ONOS, but this will expand to full functionality in future releases.
+
+#Compile and Installation
+Currently this driver is **not** built using BUCK (because it depends on an older version of onos-yang-tools, while BUCK points to the newer version of the onos-yang-tools)<br/>
+
+Before this driver can work successfully one problem with the Yang Management System (YMS) App has to be taken in to account. This is that the Yang Codec Handler (YCH) part needs to be built in Maven (when compiled in Buck something is not configured properly).<br/>
+
+To build YMS with Maven:
+1. Change directory to onos/apps/yms/app
+2. Run the command "mvn clean install" (or use the shortcut 'mci')
+3. With onos running, **reinstall** the generated OAR file for YMS on the target machine (could be localhost - replace {bracketed} values with real values)
+    * onos-app {onos-server} reinstall! target/onos-app-yms-{version}.oar
+
+
+Then this Microsemi driver has to be built using Maven and installed. To build it:
+1. Change directory to onos/drivers/microsemi
+2. Run the command "mvn clean install" (or use the shortcut 'mci')
+3. With onos running, install the 2 generated OAR files on the target machine (could be localhost - replace {bracketed} values with real values)
+    * onos-app {onos-server} install ea1000yang/target/onos-drivers-microsemi-ea1000yang-{version}.oar
+    * onos-app {onos-server} install ea1000driver/target/onos-drivers-microsemi-ea1000-{version}.oar
+4. Verify that they are installed by calling **apps -s | grep microsemi** at the onos> prompt
+5. Activate the modules at the onos prompt
+    * onos:app activate org.onosproject.drivers.netconf org.onosproject.drivers.microsemi.yang org.onosproject.drivers.microsemi
+
+#Change NETCONF default connection timeout
+Connection timeouts need to be increased from default values when using EA1000. At ONOS command line run
+
+`onos:cfg set org.onosproject.netconf.ctl.NetconfControllerImpl netconfConnectTimeout 150`<br/>
+`onos:cfg set org.onosproject.netconf.ctl.NetconfControllerImpl netconfReplyTimeout 150`<br/>
+
+#Creating Devices
+EA1000 Devices will not be automatically discovered at present in ONOS. They have to be created through the network/configuration REST interface in ONOS.
+
+* The name must follow the format **netconf:<ipaddr>:<port>**
+* The **ip** and **port** must correspond to the ip and port in the name (above).
+
+`{`<br/>
+`&nbsp;"devices": {`<br/>
+`&nbsp;&nbsp;"netconf:192.168.56.10:830": {`<br/>
+`&nbsp;&nbsp;&nbsp;"netconf": {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"username": "admin",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password": "admin",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"ip": "192.168.56.10",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"port": "830"`<br/>
+`&nbsp;&nbsp;&nbsp;},`<br/>
+`&nbsp;&nbsp;&nbsp;"basic": {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"driver": "microsemi-netconf",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"type": "SWITCH",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"manufacturer": "Microsemi",`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"hwVersion": "EA1000"`<br/>
+`&nbsp;&nbsp;&nbsp;}`<br/>
+`&nbsp;&nbsp;}`<br/>
+`&nbsp;}`<br/>
+`}`<br/>
+
+
+
+#Connected Device
+When the EA1000 is configured and connected is should be visible in ONOS through the **devices** command.
+
+`onos> devices`<br/>
+`id=netconf:192.168.56.10:830, available=true, local-status=connected 33s ago, role=MASTER, type=SWITCH, mfr=Microsemi, hw=EA1000, sw=4.4.0-53-generic, serial=Eagle Simulator., driver=microsemi-netconf, ipaddress=192.168.56.10, latitude=51.8865467, locType=geo, longitude=-8.4040440, name=netconf:192.168.56.10:830, port=830, protocol=NETCONF`
+
+Note how the
+* software version (sw=**4.4.0-53-generic**)
+* serial number (serial=**Eagle Simulator.**)
+* latitude (latitude=**51.8865467**) and
+* longitude (longitude=**-8.4040440**)
+are all retrieved from the device on initial handshake.
+
+In addition the time on the device is checked at this stage, and if it wrong by more than 1 day (it defaults to 1-1-1970 on startup if no NTP server is configured), then the current time is written to it at this stage. This will persist on the device until next reboot.
+
+Also the ports of the device will be visible after connection. There are 2 ports
+* Port 0 - The **Optics** port - this is a single mode 1000LX 1310nm optical connection
+* Port 1 - The **Host** port - this is a 1GB Ethernet Copper connection in to an SFP Port
+
+`onos> ports`<br/>
+`id=netconf:192.168.56.10:830, available=true, local-status=connected 15s ago, role=MASTER, type=SWITCH, mfr=Microsemi, hw=EA1000, sw=4.4.0-53-generic, serial=Eagle Simulator., driver=microsemi-netconf, ipaddress=192.168.56.10, latitude=51.8865467, locType=geo, longitude=-8.4040440, name=netconf:192.168.56.10:830, port=830, protocol=NETCONF`<br/>
+`&nbsp;port=0, state=enabled, type=fiber, speed=1000, portName=Optics`<br/>
+`&nbsp;port=1, state=enabled, type=copper, speed=1000, portName=Host`<br/>
+
+
+#OpenFlow Emulation
+Currently the EA1000 supports only a limited set of OpenFlow rules through the Flows REST API and the Flow Objective API.
+
+##IP Source Address filtering
+A feature of the EA1000 that may be configured through Flow Rules is IP Source Address Filtering. This can only be activated on Port 0 (the optics Port). An example of this kind of flow is
+
+`POST /onos/v1/flows/ HTTP/1.1`<br/>
+`{`<br/>
+`&nbsp;"flows": [`<br/>
+`&nbsp;&nbsp;{`<br/>
+`&nbsp;&nbsp;&nbsp;"priority": 40000,`<br/>
+`&nbsp;&nbsp;&nbsp;"timeout": 0,`<br/>
+`&nbsp;&nbsp;&nbsp;"isPermanent": true,`<br/>
+`&nbsp;&nbsp;&nbsp;"deviceId": "netconf:192.168.56.10:830",`<br/>
+`&nbsp;&nbsp;&nbsp;"tableId": 8,`<br/>
+`&nbsp;&nbsp;&nbsp;"treatment": {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"instructions": [  {"type": "NOACTION"} ],`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"deferred": []`<br/>
+`&nbsp;&nbsp;&nbsp;},`<br/>
+`&nbsp;&nbsp;&nbsp;"selector": {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;"criteria": [  {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"type": "IPV4_SRC", "ip": "192.168.8.0/24"`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;},{`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"type": "IN_PORT", "port": "0"`<br/>
+`} ] } } ] }`<br/>
+
+## Vlan Tag Manipulation
+**Note: Before Vlan Tag manipulation can be done the mode of the interface on the EA1000 has to be changed to be compatible with the type of tags that are being received. If this is not done, once an EVC is created the packets that have the Vlan tagged on will be treated as untagged by EA1000, and dropped if there is no EVC present corresponding to the interface PVID. See the section below on the "Setting EA1000 Interface Tagging Mode"**
+
+Flows that Push, Pop or Overwrite VLAN tags are implemented in EA1000 and are treated as MEF Carrier Ethernet EVCs. Both CTags and STags can be pushed on to matching Ethernet packets at network Layer 2.
+
+`POST /onos/v1/flows/ HTTP/1.1`<br/>
+`{`<br/>
+`  "flows": [`<br/>
+`    {`<br/>
+`      "priority": 50000,`<br/>
+`      "timeout": 0,`<br/>
+`      "isPermanent": true,`<br/>
+`      "tableId": 6,` --This sets the EVC id  - this first flow is configuring the customer side - UNI-C<br/>
+`      "deviceId": "netconf:192.168.56.10:830",`<br/>
+`      "treatment": {`<br/>
+`        "instructions": [`<br/>
+`          {`<br/>
+`            "type": "L2MODIFICATION",`<br/>
+`            "subtype": "VLAN_PUSH",` --This pushes a VLAN on<br/>
+`            "ethernetType": "0x88a8"`  --The pushed VLAN type is QinQ<br/>
+`          },{`<br/>
+`            "type": "L2MODIFICATION",`<br/>
+`            "subtype": "VLAN_ID",`<br/>
+`            "vlanId": "200"`  --The pushed VLAN id is 200<br/>
+`          }`<br/>
+`        ],`<br/>
+`        "deferred": []`<br/>
+`      },`<br/>
+`      "selector": {`<br/>
+`        "criteria": [`<br/>
+`         {`<br/>
+`          "type": "VLAN_VID",`<br/>
+`          "vlanId": "100"` -- Applies only to packets already tagged with VLAN 100..<br/>
+`         },{`<br/>
+`          "type": "IN_PORT",`<br/>
+`          "port": "1"`  -- ..that are coming in on the Host port<br/>
+`         }`<br/>
+`        ]`<br/>
+`      }`<br/>
+`    },{`<br/>
+`      "priority": 50000,`<br/>
+`      "timeout": 0,`<br/>
+`      "isPermanent": true,`<br/>
+`      "tableId": 6,`  -- The same EVC, but now we are configuring another VLAN<br/>
+`      "deviceId": "netconf:192.168.56.10:830",`<br/>
+`      "treatment": {`<br/>
+`       "instructions": [`<br/>
+`         {`<br/>
+`          "type": "L2MODIFICATION",`<br/>
+`          "subtype": "VLAN_PUSH",`  -- Push again<br/>
+`          "ethernetType": "0x88a8"`  -- QinQ again<br/>
+`         },{`
+`          "type": "L2MODIFICATION",`<br/>
+`          "subtype": "VLAN_ID",`<br/>
+`          "vlanId": "200"`  -- VLAN 200 again<br/>
+`         }`<br/>
+`        ],`<br/>
+`        "deferred": []`<br/>
+`      },`<br/>
+`      "selector": {`<br/>
+`        "criteria": [`<br/>
+`         {`<br/>
+`          "type": "VLAN_VID",`<br/>
+`          "vlanId": "101"`  -- Applies only to packets already tagged with VLAN 101..<br/>
+`         },{`<br/>
+`          "type": "IN_PORT",`<br/>
+`          "port": "1"`  -- ..that are coming in on the Host port<br/>
+`         }`<br/>
+`        ]`<br/>
+`      }`<br/>
+`    },{`<br/>
+`      "priority": 50000,`<br/>
+`      "timeout": 0,`<br/>
+`      "isPermanent": true,`<br/>
+`      "tableId": 6,`  -- The same EVC, but now we are configuring the opposite side<br/>
+`      "deviceId": "netconf:192.168.56.10:830",`<br/>
+`      "treatment": {`<br/>
+`       "instructions": [`<br/>
+`         {`<br/>
+`          "type": "L2MODIFICATION",`<br/>
+`          "subtype": "VLAN_POP"`  -- Here we are popping the top level tag<br/>
+`         }`<br/>
+`       ],`<br/>
+`       "deferred": []`<br/>
+`      },`<br/>
+`      "selector": {`<br/>
+`       "criteria": [`<br/>
+`        {`<br/>
+`         "type": "VLAN_VID",`  -- Applies only to packets tagged with VLAN 200<br/>
+`         "vlanId": "200"`<br/>
+`        },{`<br/>
+`         "type": "IN_PORT",`<br/>
+`         "port": "0"`  -- That are coming in on the Optics Port<br/>
+`        }`<br/>
+`      ] } } ] }`<br/>
+
+##Setting EA1000 Interface Tagging Mode
+The Interface of the EA1000 has an attribute **frame_format** that must be set to either:
+* none (default)
+* ctag
+* stag
+to correspond to the type of tagging that will be applied to packets received at that port.
+
+For instance if Port 0 of an EA1000 is to receive and process S-Tags, the the frame-format of the interface *eth0* should be set to **stag** in advance.
+
+This should be made a permanent setting in the NETCONF *startup* datastore, so that it will be active if the device reboots.
+
+Likewise the opposite port should be set to *ctag*.<br/>
+
+This changes are not made done through the ONOS Driver, and currently only possible to make this change through a NETCONF CLI client such as *yangcli-pro* or *netopeer-cli*;
+
+See the EA1000 User Guide for details on how to use *yangcli-pro* to access the EA1000.
+
+On an EA1000 accessed through *yangcli-pro* the following commands can be used to make these changes:<br/>
+`admin@192.168.2.234> discard-changes`<br/>
+`admin@192.168.2.234> copy-config source=startup target=candidate`<br/>
+`admin@192.168.2.234> merge /interfaces/interface[name='eth0']/frame-format --value='stag'`<br/>
+`admin@192.168.2.234> merge /interfaces/interface[name='eth1']/frame-format --value='ctag'`<br/>
+`admin@192.168.2.234> commit`<br/>
+`admin@192.168.2.234> copy-config source=running target=startup`<br/>
+
+
+#ONOS Carrier Ethernet Application
+The ONOS [Carrier Ethernet](https://wiki.onosproject.org/display/ONOS/Carrier+Ethernet+Application) application allows EVCs to be created between UNIs that are linked together in ONOS. This is translated down to OpenFlow switches by converting the **ce-evc-create** commands in to Flow Rules similar to those shown above.
+
+While EA1000 is not an OpenFlow switch, it's driver can convert these flows in to NETCONF which can be used to configure EVCs on the EA1000. Because EA1000 is just a 2 port device it represents only 1 UNI (conventionally on switches each port represnts a UNI).
+
+When an EA1000 device is configured in ONOS the Carrier Ethernet Application considers both of its ports to be UNIs, as can be seen in the listing below:
+
+`onos> ce-uni-list`<br/>
+`CarrierEthernetUni{id=netconf:192.168.56.10:830/0, cfgId=netconf:192.168.56.10:830/0, role=null, refCount=0, ceVlanIds=[], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[]}`<br/>
+`CarrierEthernetUni{id=netconf:192.168.56.10:830/1, cfgId=netconf:192.168.56.10:830/1, role=null, refCount=0, ceVlanIds=[], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[]}`<br/>
+
+This mismatch is handled in the driver - both side appear to be separate here but they will apply to the same single UNI on the EA1000 in opposite directions.
+
+For an EVC to be created there has to an ONOS 'link' between 2 UNIs for a POINT-TO-POINT connection - an Ethernet Virtual Private Line (**EVPL**). There has to be more than 2 UNIs to create a MULTIPOINT-TO-MULTIPOINT link - an E-Lan.
+
+##Links
+In a simple scenario that has 2 EA1000s (netconf:192.168.56.10:830 and netconf:192.168.56.20:830) configured in ONOS, the two might be linked together through their optics ports (port 0). The following result is expected for a bi-directional link:
+
+`onos> links`<br/>
+`src=netconf:192.168.56.10:830/0, dst=netconf:192.168.56.20:830/0, type=DIRECT, state=ACTIVE, expected=false`<br/>
+`src=netconf:192.168.56.20:830/0, dst=netconf:192.168.56.10:830/0, type=DIRECT, state=ACTIVE, expected=false`<br/>
+
+This will not exist by default since Link Discovery is not yet a feature of the EA1000 driver. These have to be created manually - through the network/configuration REST API.
+
+`POST /onos/v1/network/configuration/ HTTP/1.1`<br/>
+`{`<br/>
+`  "links": {`<br/>
+`  "netconf:192.168.56.10:830/0-netconf:192.168.56.20:830/0" : {`  -- 10 to 20<br/>
+`    "basic" : {`<br/>
+`      "type" : "DIRECT"`<br/>
+`    }`<br/>
+`  },`<br/>
+`  "netconf:192.168.56.20:830/0-netconf:192.168.56.10:830/0" : {`  -- and reverse<br/>
+`    "basic" : {`<br/>
+`      "type" : "DIRECT"`<br/>
+`    } } } }`<br/>
+
+##EVPL Creation
+To create a simple EVPL the following command can be used at the ONOS CLI:<br/>
+
+`onos>ce-evc-create --cevlan 101 evpl1 POINT_TO_POINT netconf:192.168.57.10:830/0 netconf:192.168.57.20:830/0`<br/>
+
+This returns without any message. Tailing through the ONOS logs will reveal any error that might have occurred.<br/>
+
+This EVC can be viewed only through the command line:<br/>
+`onos> ce-evc-list`<br/>
+`  CarrierEthernetVirtualConnection{id=EP-Line-1, cfgId=evpl1, type=POINT_TO_POINT, state=ACTIVE,`<br/>
+`UNIs=[`<br/>
+`CarrierEthernetUni{id=netconf:192.168.56.10:830/0, cfgId=netconf:192.168.56.10:830/0, role=Root, refCount=0, ceVlanIds=[101], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[CarrierEthernetBandwidthProfile{id=FC-1, type=EVC, cir=0.0, cbs=0, eir=0.0, ebs=0}]}, `<br/>
+`CarrierEthernetUni{id=netconf:192.168.56.20:830/0, cfgId=netconf:192.168.56.20:830/0, role=Root, refCount=0, ceVlanIds=[101], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[CarrierEthernetBandwidthProfile{id=FC-1, type=EVC, cir=0.0, cbs=0, eir=0.0, ebs=0}]}], `<br/>
+`FCs=[CarrierEthernetForwardingConstruct{id=FC-1, cfgId=null, type=POINT_TO_POINT, vlanId=1, metroConnectId=null, refCount=1, `<br/>
+`LTPs=[`<br/>
+`CarrierEthernetLogicalTerminationPoint{id=netconf:192.168.56.10:830/0, cfgId=netconf:192.168.56.10:830/0, role=Root, ni=CarrierEthernetUni{id=netconf:192.168.56.10:830/0, cfgId=netconf:192.168.56.10:830/0, role=Root, refCount=0, ceVlanIds=[101], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[CarrierEthernetBandwidthProfile{id=FC-1, type=EVC, cir=0.0, cbs=0, eir=0.0, ebs=0}]}},`   `CarrierEthernetLogicalTerminationPoint{id=netconf:192.168.56.20:830/0, cfgId=netconf:192.168.56.20:830/0, role=Root, ni=CarrierEthernetUni{id=netconf:192.168.56.20:830/0, cfgId=netconf:192.168.56.20:830/0, role=Root, refCount=0, ceVlanIds=[101], capacity=1000000000, usedCapacity=0.0, bandwidthProfiles=[CarrierEthernetBandwidthProfile{id=FC-1, type=EVC, cir=0.0, cbs=0, eir=0.0, ebs=0}]}}]}]}`<br/>
+
+##EVPL flows
+This creates a set of flows in ONOS that are pushed down to the two EA1000s through NETCONF to configure the EVCs
+
+`onos> flows`<br/>
+`deviceId=netconf:192.168.56.10:830, flowRuleCount=2`<br/>
+`    id=71000050d21dd5, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=50000, tableId=1, appId=org.onosproject.ecord.carrierethernet, payLoad=null, selector=[IN_PORT:0, VLAN_VID:1], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP], deferred=[], transition=None, meter=None, cleared=false, metadata=null}`  -- This represents ingress on the Optics port 0 on device A and POPs off the S-Tag<br/>
+`    id=710000b5c1f057, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=50000, tableId=1, appId=org.onosproject.ecord.carrierethernet, payLoad=null, selector=[IN_PORT:1, VLAN_VID:101], treatment=DefaultTrafficTreatment{immediate=[VLAN_PUSH:qinq, VLAN_ID:1], deferred=[], transition=TABLE:0, meter=None, cleared=false, metadata=null}`  -- This represents ingress on the Host port 1 on device A and pushes on the S-Tag 1<br/>
+
+`deviceId=netconf:192.168.56.20:830, flowRuleCount=2`<br/>
+`    id=710000613c8252, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=50000, tableId=1, appId=org.onosproject.ecord.carrierethernet, payLoad=null, selector=[IN_PORT:0, VLAN_VID:1], treatment=DefaultTrafficTreatment{immediate=[VLAN_POP], deferred=[], transition=None, meter=None, cleared=false, metadata=null}`  -- This represents ingress on the Optics port 0 on device B and POPs off the S-Tag 1<br/>
+`    id=7100006ca2573f, state=ADDED, bytes=0, packets=0, duration=0, liveType=UNKNOWN, priority=50000, tableId=1, appId=org.onosproject.ecord.carrierethernet, payLoad=null, selector=[IN_PORT:1, VLAN_VID:101], treatment=DefaultTrafficTreatment{immediate=[VLAN_PUSH:qinq, VLAN_ID:1], deferred=[], transition=TABLE:0, meter=None, cleared=false, metadata=null}`  -- This represents ingress on the Host port 1 on device B and pushes on the S-Tag 1<br/>
+
+Through these flows it's clear that the CE-VLAN on the UNI-C side is 101 and that the S-Tag that is being pushed on is VLAN 1. Packets coming back in on the UNI-N on port 0 have their S-Tag popped off. In this scenario this will create evc-1 on both of the EA1000s.<br/>
+
+On the actual EA1000 itself using a NETCONF CLI Client like yangcli-pro, the result is:
+
+`admin@192.168.56.10> sget-config /mef-services/uni source=running`<br/>
+`rpc-reply {`<br/>
+`&nbsp;data {`<br/>
+`&nbsp;&nbsp;mef-services {`<br/>
+`&nbsp;&nbsp;&nbsp;uni {`  -- There is only one UNI on the EA1000<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;name Uni-on-192.168.56.10:830`  -- Automatically assigned<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;evc  1 {`  -- From the VLAN 1 from CE app<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;evc-index 1`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name EVC-1`  -- Automatically assigned<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;evc-per-uni {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;evc-per-uni-c {`  -- The UNI-C side<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ce-vlan-map 101`  -- Could be a range of values<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flow-mapping {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ce-vlan-id 101`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flow-id 31243725464268887`  -- For tracking with ONOS<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ingress-bwp-group-index 0`  -- No meters<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tag-push {`  -- Push on an a VLAN<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push-tag-type pushStag`  -- Push type is S-TAG<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outer-tag-vlan 1`  -- Push value is 1<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;evc-per-uni-n {`  -- For the UNI-N side<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ce-vlan-map 1`  -- The VLAN to match for egress on this side<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flow-mapping {`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ce-vlan-id 1`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flow-id 31243723770830293`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ingress-bwp-group-index 0`<br/>
+`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tag-pop {`  -- Pop off the S-TAG<br/>
+`} } } } } } } }`<br/>
+`admin@192.168.56.10>`<br/>
+
+##CIR and EIR as OpenFlow Meters
+** Note: The meters created by Carrier Ethernet are not compatible with Open vSwitch at present.They will disrupt the configuration of the EA1000 if there are Open VSwitch based OpenFlow switches between the UNIs **<br/>
+
+To create limits on how the EVPL can transport data the CIR, EIR and CBS and EBS values can be specified:
+
+`onos> ce-evc-create --cevlan 102 -c 400 -e 200 -cbs 3000 -ebs 2000 evpl2 POINT_TO_POINT netconf:192.168.56.10:830/0 netconf:192.168.56.20:830/0`<br/>
+
+* -c 400 means Commit Information Rate is 400 MB/s
+* -e 200 means Excess information Rate is 200 MB/s
+* -cbs 3000 is Committed Burst Size of 3000 **Bytes**
+* -ebs 2000 is Excess Burst Rate of 2000 **Bytes**
+
+These will be created as meters in Open Flow.
+
+`onos> meters`<br/>
+` DefaultMeter{device=netconf:192.168.56.20:830, id=1, appId=org.onosproject.ecord.carrierethernet, unit=KB_PER_SEC, isBurst=true, state=PENDING_ADD, bands=[DefaultBand{rate=50000, burst-size=3000, type=REMARK, drop-precedence=0}, DefaultBand{rate=75000, burst-size=5000, type=DROP, drop-precedence=null}]}`<br/>
+` DefaultMeter{device=netconf:192.168.56.10:830, id=1, appId=org.onosproject.ecord.carrierethernet, unit=KB_PER_SEC, isBurst=true, state=PENDING_ADD, bands=[DefaultBand{rate=75000, burst-size=5000, type=DROP, drop-precedence=null}, DefaultBand{rate=50000, burst-size=3000, type=REMARK, drop-precedence=0}]}`<br/>
+
+Here the rates is shown as Bands. For each device the Bands are
+*  REMARK for CIR and CBS - the REMARK applies to any packets that exceed the CIR in kB/s (400Mb/s = 50000kB/s) and the burst size 3000 Bytes
+*  DROP for EIR and EBS - the DROP applies to any packets that exceed the sum of CIR and EIR in kB/s (400Mb/s + 200Mb/s = 75000kB/s) and a burst in excess of CBS and EBS (3000 + 2000 = 5000 Bytes)
+
+##EVC Deletion
+EVCs can be deleted individually with **ce-evc-remove <evc-id>** or all together with **ce-evc-remove-all**.
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/pom.xml b/drivers/microsemi/ea1000driver/pom.xml
new file mode 100644
index 0000000..28221a2
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/pom.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2016 Open Networking Laboratory ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>onos-drivers-microsemi</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.10.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-drivers-microsemi-ea1000</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>Microsemi EA1000 device drivers for ONOS</description>
+    <url>http://www.microsemi.com</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <onos.version>1.10.0-SNAPSHOT</onos.version>
+        <onos.app.name>org.onosproject.drivers.microsemi</onos.app.name>
+        <onos.app.title>Microsemi Device Drivers</onos.app.title>
+        <onos.app.origin>Microsemi, Inc.</onos.app.origin>
+        <onos.app.category>Drivers</onos.app.category>
+        <onos.app.url>http://onosproject.org</onos.app.url>
+        <onos.app.readme>For various Microsemi Devices including EdgeAssure
+            1000 SFP-NID</onos.app.readme>
+        <onos.app.requires>org.onosproject.netconf</onos.app.requires>
+        <onos.app.requires>org.onosproject.drivers.netconf</onos.app.requires>
+        <onos.app.requires>org.onosproject.yms</onos.app.requires>
+        <onos.app.requires>org.onosproject.drivers.microsemi.yang</onos.app.requires>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-netconf-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-drivers-microsemi-ea1000yang</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-drivers-microsemi-ea1000yang</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-yms-api</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-yms</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-drivers-netconf</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
new file mode 100644
index 0000000..3c593d6
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
@@ -0,0 +1,942 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.stream.Collectors;
+
+import org.onlab.packet.EthType;
+import org.onlab.packet.EthType.EtherType;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.drivers.microsemi.yang.UniSide;
+import org.onosproject.drivers.microsemi.yang.utils.CeVlanMapUtils;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanHeaderInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.netconf.TargetConfig;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.MseaSaFilteringOpParam;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.DefaultSourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.SourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.sourceipaddressfiltering.DefaultInterfaceEth0;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.sourceipaddressfiltering.InterfaceEth0;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.DefaultSourceAddressRange;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.FilterAdminStateEnum;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.sa.filtering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.Identifier45;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.ServiceListType;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.VlanIdType;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.DefaultMefServices;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.DefaultFlowMapping;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagOverwrite;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPop;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPush;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagOverwrite;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPop;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPush;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.tagpush.tagpush.PushTagTypeEnum;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.DefaultUni;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.Profiles;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.Uni;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.CustomEvc;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.DefaultEvc;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.Evc;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.DefaultEvcPerUni;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.EvcPerUni;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.CustomEvcPerUnic;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.CustomEvcPerUnin;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.DefaultEvcPerUnic.EvcPerUnicBuilder;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.DefaultEvcPerUnin.EvcPerUninBuilder;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnic;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnin;
+import org.slf4j.Logger;
+
+/**
+ * An implementation of the FlowRuleProgrammable behaviour for the EA10000 device.
+ *
+ * This device is not a native Open Flow device. It has only a NETCONF interface for configuration
+ * status retrieval and notifications. It supports only a small subset of OpenFlow rules.<br>
+ *
+ * The device supports only:<br>
+ * 1) Open flow rules that blocks certain IP address ranges, but only those incoming on Port 0
+ *    and has a limit of 10 such rules<br>
+ * 2) Open flow rules that PUSH, POP and OVERWRITE VLAN tags on both ports. This can push and overwrite
+ *    both C-TAGs (0x8100) and S-TAGs (0x88a8).
+ */
+public class EA1000FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+    protected final Logger log = getLogger(getClass());
+    public static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
+    public static final int PRIORITY_DEFAULT = 50000;
+    //To protect the NETCONF session from concurrent access across flow addition and removal
+    static Semaphore sessionMutex = new Semaphore(1);
+
+    /**
+     * Get the flow entries that are present on the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are retrieved from 2 configuration
+     * areas on the EA1000 NETCONF model - from SA filtering YANG model and from EVC UNI YANG model.<br>
+     * The flow entries must match exactly the FlowRule entries in the ONOS store. If they are not an
+     * exact match the device will be requested to remove those flows and the FlowRule will stay in a
+     * PENDING_ADD state.
+     * @return A collection of Flow Entries
+     */
+    @Override
+    public Collection<FlowEntry> getFlowEntries() {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        CoreService coreService = checkNotNull(handler().get(CoreService.class));
+        ApplicationId appId = coreService.getAppId(MICROSEMI_DRIVERS);
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        log.debug("getFlowEntries() called on EA1000FlowRuleProgrammable");
+
+        //First get the MseaSaFiltering rules
+        SourceIpaddressFiltering.SourceIpaddressFilteringBuilder sipBuilder =
+                new DefaultSourceIpaddressFiltering.SourceIpaddressFilteringBuilder();
+
+        MseaSaFilteringOpParam.MseaSaFilteringBuilder opBuilder =
+                new MseaSaFilteringOpParam.MseaSaFilteringBuilder();
+        MseaSaFilteringOpParam mseaSaFilteringFilter =
+                (MseaSaFilteringOpParam) opBuilder
+                .sourceIpaddressFiltering(sipBuilder.build())
+                .build();
+        try {
+            MseaSaFiltering saFilteringCurrent =
+                    mseaSaFilteringService.getMseaSaFiltering(mseaSaFilteringFilter, session);
+            if (saFilteringCurrent != null) {
+                flowEntryCollection.addAll(
+                        convertSaFilteringToFlowRules(saFilteringCurrent, appId));
+            }
+        } catch (NetconfException e) {
+            log.warn("Unexpected error on getFlowEntries", e);
+        }
+
+
+        //Then get the EVCs - there will be a flow entry per EVC
+        Uni.UniBuilder uniBuilder = new DefaultUni.UniBuilder();
+
+        MefServices.MefServicesBuilder mefBuilder = new DefaultMefServices.MefServicesBuilder();
+        MefServices mefServices = mefBuilder.uni(uniBuilder.build()).build();
+
+        MseaUniEvcService.MseaUniEvcServiceBuilder evcUniBuilder =
+                new MseaUniEvcServiceOpParam.MseaUniEvcServiceBuilder();
+
+        MseaUniEvcServiceOpParam mseaUniEvcServiceFilter =
+                (MseaUniEvcServiceOpParam) evcUniBuilder.mefServices(mefServices).build();
+        try {
+            MseaUniEvcService uniEvcCurrent =
+                    mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
+                            session, TargetConfig.RUNNING);
+
+            flowEntryCollection.addAll(
+                    convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
+
+        } catch (NetconfException e) {
+            log.warn("Unexpected error on getFlowEntries", e);
+        }
+
+
+        return flowEntryCollection;
+    }
+
+    /**
+     * Apply the flow entries to the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+     * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
+     * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
+     * will not be in the returned set.
+     *
+     * @param rules A collection of Flow Rules to be applied to the EA1000
+     * @return A collection of the Flow Rules that have been added.
+     */
+    @Override
+    public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+        Collection<FlowRule> frAdded = new HashSet<FlowRule>();
+        if (rules == null || rules.size() == 0) {
+            return rules;
+        }
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
+        // FIXME: Change this so it's dynamically driven
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+
+        List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+        Map<Integer, Evc> evcMap = new HashMap<>();
+
+        //Retrieve the list of actual EVCs and the CeVlanMaps from device
+        List<Evc> activeEvcs = new ArrayList<>();
+        try {
+            sessionMutex.acquire();
+            MseaUniEvcService evcResponse =
+                    mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, TargetConfig.RUNNING);
+            //There could be zero or more EVCs
+            if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+                activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+            }
+        } catch (NetconfException | InterruptedException e1) {
+            log.warn("Unexpected error on applyFlowRules", e1);
+        }
+
+        for (FlowRule fr : rules) {
+
+            // IP SA Filtering can only apply to Port 0 optics
+            if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
+                    fr.selector().getCriterion(Type.IN_PORT) != null &&
+                    ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+                parseFrForSaRange(frAdded, saRangeList, fr);
+
+            // EVCs will be defined by Flow Rules relating to VIDs
+            } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
+                    fr.selector().getCriterion(Type.IN_PORT) != null) {
+                //There could be many Flow Rules for one EVC depending on the ceVlanMap
+                //Cannot build up the EVC until we know the details - the key is the tableID and port
+                parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
+            } else {
+                log.info("Unexpected Flow Rule type applied: " + fr);
+            }
+        }
+
+        //If there are IPv4 Flow Rules created commit them now through the
+        //MseaSaFiltering service
+        if (saRangeList.size() > 0) {
+            try {
+                mseaSaFilteringService.setMseaSaFiltering(
+                            buildSaFilteringObject(saRangeList), session, TargetConfig.RUNNING);
+            } catch (NetconfException e) {
+                log.error("Error applying Flow Rules to SA Filtering - will try again: " + e.getMessage());
+                sessionMutex.release();
+                return frAdded;
+            }
+        }
+        //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
+        if (evcMap.size() > 0) {
+            List<Evc> evcList = evcMap.entrySet().stream()
+                    .map(x -> x.getValue())
+                    .collect(Collectors.toList());
+            Uni.UniBuilder uniBuilder = new DefaultUni.UniBuilder();
+            URI deviceName = handler().data().deviceId().uri();
+            Uni uni = uniBuilder.name(new Identifier45("Uni-on-"
+                    + deviceName.getSchemeSpecificPart())).evc(evcList).build();
+
+            List<BwpGroup> bwpGroupList = new ArrayList<BwpGroup>();
+            BwpGroup.BwpGroupBuilder bwpGrpBuilder = new DefaultBwpGroup.BwpGroupBuilder();
+            bwpGroupList.add(bwpGrpBuilder.groupIndex((short) 0).build());
+            Profiles profiles = (new DefaultProfiles.ProfilesBuilder()).bwpGroup(bwpGroupList).build();
+
+            MefServices.MefServicesBuilder mefBuilder = new DefaultMefServices.MefServicesBuilder();
+            MefServices mefServices = mefBuilder.uni(uni).profiles(profiles).build();
+
+            MseaUniEvcService.MseaUniEvcServiceBuilder evcUniBuilder =
+                    new MseaUniEvcServiceOpParam.MseaUniEvcServiceBuilder();
+
+            MseaUniEvcServiceOpParam mseaUniEvcServiceFilter =
+                    (MseaUniEvcServiceOpParam) evcUniBuilder.mefServices(mefServices).build();
+            try {
+                mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, TargetConfig.RUNNING);
+            } catch (NetconfException e) {
+                log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage());
+                sessionMutex.release();
+                return frAdded;
+            }
+        }
+        sessionMutex.release();
+        return frAdded;
+    }
+
+    /**
+     * Remove flow rules from the EA1000.
+     * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+     * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
+     *
+     * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
+     * @return A collection of the Flow Rules that have been removed.
+     */
+    @Override
+    public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        MseaSaFilteringNetconfService mseaSaFilteringService =
+                (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+        MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+                (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+        UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+        log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
+
+        if (rulesToRemove.size() == 0) {
+            return rulesToRemove;
+        }
+
+        //Retrieve the list of actual EVCs and the CeVlanMaps from device
+        List<Evc> activeEvcs = new ArrayList<>();
+        try {
+            sessionMutex.acquire();
+            MseaUniEvcService evcResponse =
+                    mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, TargetConfig.RUNNING);
+            //There could be zero or more EVCs
+            if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+                activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+            }
+        } catch (NetconfException | InterruptedException e1) {
+            log.warn("Error on removeFlowRules.", e1);
+        }
+
+        List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+        Map<Integer, String> ceVlanMapMap = new HashMap<>();
+        Map<Integer, List<Short>> flowIdMap = new HashMap<>();
+
+        Collection<FlowRule> rulesRemoved = new HashSet<FlowRule>();
+        for (FlowRule ruleToRemove : rulesToRemove) {
+            // IP SA Filtering can only apply to Port 0 optics
+            if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
+                    ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
+                    ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+                SourceAddressRange.SourceAddressRangeBuilder saBuilder =
+                        new DefaultSourceAddressRange.SourceAddressRangeBuilder();
+                SourceAddressRange sar = saBuilder
+                        .rangeId((short) ruleToRemove.tableId())
+                        .yangSourceAddressRangeOpType(org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.
+                                edge.assure.msea.sa.filtering.rev20160412.MseaSaFiltering.OnosYangOpType.DELETE)
+                        .build();
+
+                rulesRemoved.add(ruleToRemove);
+                saRangeList.add(sar);
+
+            } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
+                    ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
+                PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
+                VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
+                int evcId = ruleToRemove.tableId();
+                int evcKey = (evcId << 2) + (int) portNumber.toLong();
+                String activeCeVlanMap = "";
+                //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
+                // from the ceVlanMap and not the whole EVC
+                if (!ceVlanMapMap.containsKey(evcKey)) {
+                    for (Evc activeEvc:activeEvcs) {
+                        if (activeEvc.evcIndex() == evcId) {
+                            if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+                                    UniSide.CUSTOMER) {
+                                activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
+                            } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+                                    UniSide.NETWORK) {
+                                activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
+                            }
+                        }
+                    }
+                }
+
+                ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
+                if (!flowIdMap.containsKey(evcKey)) {
+                    flowIdMap.put(evcKey, new ArrayList<>());
+                }
+                flowIdMap.get(evcKey).add(vlanId.id());
+                rulesRemoved.add(ruleToRemove);
+
+            } else {
+                log.info("Unexpected Flow Rule type removal: " + ruleToRemove);
+            }
+        }
+
+        //If there are IPv4 Flow Rules created commit them now through the
+        //MseaSaFiltering service
+        if (saRangeList.size() > 0) {
+            try {
+                mseaSaFilteringService.setMseaSaFiltering(
+                        buildSaFilteringObject(saRangeList), session, TargetConfig.RUNNING);
+            } catch (NetconfException e) {
+                log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
+                        + "it may already have been deleted: " + e.getMessage());
+            }
+        }
+
+        if (ceVlanMapMap.size() > 0) {
+            try {
+                mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
+                        session, TargetConfig.RUNNING, portAssignment);
+            } catch (NetconfException e) {
+                log.warn("Remove FlowRule on MseaUniEvcService could not delete EVC - "
+                        + "it may already have been deleted: " + e.getMessage());
+            }
+        }
+
+        sessionMutex.release();
+        return rulesRemoved;
+    }
+
+    /**
+     * An internal method for extracting one EVC from a list and returning its ceVlanMap.
+     *
+     * @param evcList - the list of known EVCs
+     * @param evcIndex - the index of the EVC we're looking for
+     * @param side - the side of the UNI
+     * @return - the CEVlanMap we're looking for
+     */
+    private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
+        if (evcList != null && evcList.size() > 0) {
+            for (Evc evc:evcList) {
+                if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
+                    if (side == UniSide.CUSTOMER &&
+                        evc.evcPerUni().evcPerUnic() != null &&
+                        evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
+                        return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
+                    } else if (side == UniSide.NETWORK &&
+                        evc.evcPerUni().evcPerUnin() != null &&
+                        evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
+                        return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
+                    }
+                }
+            }
+        }
+
+        return ""; //The EVC required was not in the list
+    }
+
+    /**
+     * An internal method to convert from a FlowRule to SARange.
+     *
+     * @param frList A collection of flow rules
+     * @param saRangeList A list of SARanges
+     * @param fr A flow rule
+     */
+    private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
+        String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
+        log.debug("Applying IP address to " + ipAddrStr
+                + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
+
+        SourceAddressRange.SourceAddressRangeBuilder saBuilder =
+                new DefaultSourceAddressRange.SourceAddressRangeBuilder();
+
+        SourceAddressRange sar = saBuilder
+                .rangeId((short) fr.tableId())
+                .name("Flow:" + fr.id().toString())
+                .ipv4AddressPrefix(ipAddrStr)
+                .build();
+
+        frList.add(fr);
+        saRangeList.add(sar);
+    }
+
+    private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
+            List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
+        //There could be many Flow Rules for one EVC depending on the ceVlanMap
+        //Cannot build up the EVC until we know the details - the key is the tableID and port
+        Ea1000Port port = Ea1000Port.fromNum(
+                ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
+        Integer evcKey = (fr.tableId() << 2) + port.portNum();
+        VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
+        FlowMapping.FlowMappingBuilder fmBuilder =
+                DefaultFlowMapping.builder()
+                .ceVlanId(VlanIdType.of(sourceVid.id()))
+                .flowId(BigInteger.valueOf(fr.id().value()));
+        if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
+            //Replace ceVlanMap
+            evcMap.put(evcKey, CustomEvc.builder(evcMap.get(evcKey))
+                    .addToCeVlanMap(new ServiceListType(sourceVid.toString()), port.nOrC(portAssignment))
+                    .addToFlowMapping(fmBuilder.build(), port.nOrC(portAssignment))
+                    .build());
+
+        } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
+            TagManipulation tm = getTagManipulation(fr);
+            if (port.nOrC(portAssignment) == UniSide.NETWORK) {
+                EvcPerUnin epun = CustomEvcPerUnin.builder(evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin())
+                        .addToCeVlanMap(new ServiceListType(sourceVid.toString()))
+                        .tagManipulation(tm)
+                        .addToFlowMapping(fmBuilder.build())
+                        .ingressBwpGroupIndex(getMeterId(fr.treatment()))
+                        .build();
+                evcMap.put((evcKey ^ 1), CustomEvc.builder(evcMap.get((evcKey ^ 1))).addUniN(epun).build());
+            } else {
+                EvcPerUnic epuc = CustomEvcPerUnic.builder(evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic())
+                        .addToCeVlanMap(new ServiceListType(sourceVid.toString()))
+                        .tagManipulation(tm)
+                        .addToFlowMapping(fmBuilder.build())
+                        .ingressBwpGroupIndex(getMeterId(fr.treatment()))
+                        .build();
+                evcMap.put((evcKey ^ 1), CustomEvc.builder(evcMap.get((evcKey ^ 1))).addUniC(epuc).build());
+            }
+        } else {
+            Evc.EvcBuilder evcBuilder = new DefaultEvc.EvcBuilder();
+            EvcPerUninBuilder epunBuilder = new CustomEvcPerUnin.EvcPerUninBuilder();
+            EvcPerUnicBuilder epucBuilder = new CustomEvcPerUnic.EvcPerUnicBuilder();
+            TagManipulation tm = getTagManipulation(fr);
+
+            UniSide side = port.nOrC(portAssignment);
+            String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
+            String newCeVlanMap =
+                    CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
+            String oppositeCeVlanMap =
+                    getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
+                            port.opposite().nOrC(portAssignment));
+            oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
+            if (side == UniSide.NETWORK) {
+                epunBuilder
+                    .ceVlanMap(new ServiceListType(newCeVlanMap))
+                    .tagManipulation(tm)
+                    .addToFlowMapping(fmBuilder.build())
+                    .ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+                epucBuilder.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+            } else {
+                epucBuilder
+                    .ceVlanMap(new ServiceListType(newCeVlanMap))
+                    .tagManipulation(tm)
+                    .addToFlowMapping(fmBuilder.build())
+                    .ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+                epunBuilder.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+            }
+
+            evcBuilder
+                    .evcIndex(fr.tableId())
+                    .name(new Identifier45("EVC-" + String.valueOf(fr.tableId())))
+                    .evcPerUni(new DefaultEvcPerUni.EvcPerUniBuilder()
+                            .evcPerUnin(epunBuilder.build())
+                            .evcPerUnic(epucBuilder.build())
+                            .build());
+            evcMap.put(evcKey, evcBuilder.build());
+        }
+
+        frList.add(fr);
+    }
+
+
+    private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
+        InterfaceEth0.InterfaceEth0Builder ifBuilder = new DefaultInterfaceEth0.InterfaceEth0Builder();
+        for (SourceAddressRange sa:saRangeList) {
+            ifBuilder = ifBuilder.addToSourceAddressRange(sa);
+        }
+        InterfaceEth0 saIf = ifBuilder.filterAdminState(FilterAdminStateEnum.BLACKLIST).build();
+
+        SourceIpaddressFiltering.SourceIpaddressFilteringBuilder saFilterBuilder =
+                new DefaultSourceIpaddressFiltering.SourceIpaddressFilteringBuilder();
+        SourceIpaddressFiltering saFilter = saFilterBuilder.interfaceEth0(saIf).build();
+
+        MseaSaFilteringOpParam.MseaSaFilteringBuilder opBuilder =
+                new MseaSaFilteringOpParam.MseaSaFilteringBuilder();
+        MseaSaFilteringOpParam mseaSaFiltering =
+                (MseaSaFilteringOpParam) opBuilder.sourceIpaddressFiltering(saFilter).build();
+
+        return mseaSaFiltering;
+    }
+
+    private Collection<FlowEntry> convertSaFilteringToFlowRules(
+            MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        List<SourceAddressRange> saRangelist =
+                saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
+        Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
+        TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+        for (SourceAddressRange sa:saRangelist) {
+            Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
+
+            TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
+
+            TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+            TrafficTreatment treatment = trBuilder.drop().build();
+
+            FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
+            if (sa.name() != null && sa.name().startsWith("Flow:")) {
+                String[] nameParts = sa.name().split(":");
+                Long cookie = Long.valueOf(nameParts[1], 16);
+                feBuilder = feBuilder.withCookie(cookie);
+            } else {
+                feBuilder = feBuilder.fromApp(appId);
+            }
+
+            FlowRule fr = feBuilder
+                .forDevice(handler().data().deviceId())
+                .withSelector(selector)
+                .withTreatment(treatment)
+                .forTable(sa.rangeId())
+                .makePermanent()
+                .withPriority(PRIORITY_DEFAULT)
+                .build();
+
+            flowEntryCollection.add(new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
+        }
+
+        return flowEntryCollection;
+    }
+
+
+    private Collection<FlowEntry> convertEvcUniToFlowRules(
+            MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
+        Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+        if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
+                uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
+            log.info("No EVC's found when getting flow rules");
+            return flowEntryCollection;
+        }
+
+        for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
+            FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
+            TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+            TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
+            //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+            Short[] vlanIdsUniN =
+                    CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
+            for (Short vlanId:vlanIdsUniN) {
+                if (vlanId == 0) {
+                    continue;
+                }
+                Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
+                TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
+                long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
+
+                FlowRule frUniN = frBuilder
+                    .forDevice(handler().data().deviceId())
+                    .withSelector(tsUniN)
+                    .withTreatment(uniNTreatment)
+                    .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+                    .makePermanent()
+                    .withPriority(PRIORITY_DEFAULT)
+                    .withCookie(flowId)
+                    .build();
+                flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
+            }
+
+            TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
+            //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+            Short[] vlanIdsUniC =
+                    CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
+            if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
+                for (Short vlanId:vlanIdsUniC) {
+                    if (vlanId == 0) {
+                        continue;
+                    }
+                    Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
+                    TrafficSelector tsUniC =
+                            tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
+                    long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
+
+                    FlowRule frUniC = frBuilder
+                            .forDevice(handler().data().deviceId())
+                            .withSelector(tsUniC)
+                            .withTreatment(uniCTreatment)
+                            .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+                            .makePermanent()
+                            .withPriority(PRIORITY_DEFAULT)
+                            .withCookie(flowId)
+                            .build();
+                    flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
+                }
+            }
+        }
+
+        return flowEntryCollection;
+    }
+
+    private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
+        if (fmList == null || vlanId == null) {
+            log.warn("Flow Mapping list is null when reading EVCs");
+            return -1L;
+        }
+        for (FlowMapping fm:fmList) {
+            if (fm.ceVlanId().uint16() == vlanId.intValue()) {
+                return fm.flowId().longValue();
+            }
+        }
+        return 0L;
+    }
+
+    private String ceVlanMapForUniSide(
+            EvcPerUni evcPerUni, boolean portN) {
+        if (portN) {
+            return evcPerUni.evcPerUnin().ceVlanMap().string();
+        } else {
+            return evcPerUni.evcPerUnic().ceVlanMap().string();
+        }
+    }
+
+    private Criterion criterionPortForUniSide(
+            UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
+        boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
+        int portNum = ((cOnOptics && portN) || (!cOnOptics && !portN)) ? 1 : 0;
+        return Criteria.matchInPort(PortNumber.portNumber(portNum));
+    }
+
+    private TrafficTreatment treatmentForUniSde(
+            EvcPerUni evcPerUni, boolean portN) {
+        TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+
+        TagManipulation tm = null;
+        short meterId = 0;
+        if (portN) {
+            tm = evcPerUni.evcPerUnin().tagManipulation();
+            meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
+        } else {
+            tm = evcPerUni.evcPerUnic().tagManipulation();
+            meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
+        }
+
+        if (meterId > 0L) {
+            trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
+//            trBuilder = trBuilder.meter(MeterId.meterId(meterId)).transition(0);
+        }
+
+        if (tm == null) {
+            return trBuilder.build(); //no tag manipulation found
+        }
+
+        if (tm.getClass().equals(DefaultTagPush.class)) {
+            VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
+            PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
+            //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
+            // to be an exactMatch. See DefaultFlowRule.exactMatch()
+            trBuilder = trBuilder
+                    .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
+                            EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
+                    .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
+
+        } else if (tm.getClass().equals(DefaultTagPop.class)) {
+            trBuilder = trBuilder.popVlan();
+
+        } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
+            TagOverwrite to = (TagOverwrite) tm;
+            VlanId ovrVlanNum = VlanId
+                    .vlanId((short) (
+                            //There are 2 classes TagOverwrite - the other one is already imported
+                            to
+                            .tagOverwrite()
+                            .outerTagVlan()
+                            .uint16()));
+            trBuilder = trBuilder.setVlanId(ovrVlanNum);
+
+        }
+
+        return trBuilder.build();
+    }
+
+    private static TagManipulation getTagManipulation(FlowRule fr) {
+        boolean isPop = false;
+        boolean isPush = false;
+        VlanId vlanId = null;
+        EthType ethType = EtherType.VLAN.ethType(); //Default
+        for (Instruction inst:fr.treatment().allInstructions()) {
+            if (inst.type() == Instruction.Type.L2MODIFICATION) {
+                L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
+                if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
+                    isPop = true;
+                } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                    isPush = true;
+                    ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
+                } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
+                    vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
+                }
+            }
+        }
+
+        if (isPop) {
+            //The should be no vlanId in this case
+            TagPop.TagPopBuilder popBuilder = new DefaultTagPop.TagPopBuilder();
+            org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc
+                .service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation
+                .tagpop.TagPop.TagPopBuilder popInnerBuilder =
+                    new org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea
+                        .uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagpop.DefaultTagPop.TagPopBuilder();
+            return popBuilder
+                    .tagPop(popInnerBuilder.build())
+                    .build();
+
+        } else if (isPush && vlanId != null) {
+            TagPush.TagPushBuilder pushBuilder = new DefaultTagPush.TagPushBuilder();
+            org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc
+                .service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation
+                .tagpush.TagPush.TagPushBuilder pushInnerBuilder =
+                    new org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea
+                        .uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagpush.DefaultTagPush.TagPushBuilder();
+            return pushBuilder
+                .tagPush(pushInnerBuilder
+                        .outerTagVlan(new VlanIdType(vlanId.id()))
+                        .pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
+                                PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG)
+                        .build())
+                .build();
+
+        } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
+            TagOverwrite.TagOverwriteBuilder ovrBuilder = new DefaultTagOverwrite.TagOverwriteBuilder();
+            org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc
+                .service.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation
+                .tagoverwrite.TagOverwrite.TagOverwriteBuilder ovrInnerBuilder =
+                    new org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea
+                        .uni.evc.service.rev20160317.mseaunievcservice.evcperuniextensionattributes
+                        .tagmanipulation.tagoverwrite.DefaultTagOverwrite.TagOverwriteBuilder();
+            return ovrBuilder.
+                    tagOverwrite(ovrInnerBuilder
+                            .outerTagVlan(new VlanIdType(vlanId.id()))
+                            .build())
+                    .build();
+        }
+
+        return null;
+    }
+
+    private static long getMeterId(TrafficTreatment treatment) {
+        return (treatment.metered() != null && treatment.metered().meterId() != null)
+                ? treatment.metered().meterId().id() : 0L;
+    }
+
+    /**
+     * An enumerated type that characterises the 2 port layout of the EA1000 device.
+     * The device is in an SFP package and has only 2 ports, the HOST port which
+     * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
+     */
+    public enum Ea1000Port {
+        HOST(1),
+        OPTICS(0);
+
+        private int num = 0;
+        private Ea1000Port(int num) {
+            this.num = num;
+        }
+
+        /**
+         * The numerical assignment of this port.
+         * @return The port number
+         */
+        public int portNum() {
+            return num;
+        }
+
+        /**
+         * Return the enumerated value from a port number.
+         * @param num The port number
+         * @return An enumerated value
+         */
+        public static Ea1000Port fromNum(long num) {
+            for (Ea1000Port a:Ea1000Port.values()) {
+                if (a.num == num) {
+                    return a;
+                }
+            }
+            return HOST;
+        }
+
+        /**
+         * Get the port that the UNI-N is present on.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value
+         */
+        public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
+            if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+                return OPTICS;
+            } else {
+                return HOST;
+            }
+        }
+
+        /**
+         * Get the port that the UNI-C is present on.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value
+         */
+        public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
+            if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+                return HOST;
+            } else {
+                return OPTICS;
+            }
+        }
+
+        /**
+         * Get the port opposite the current port.
+         * @return An enumerated value for the opposite side
+         */
+        public Ea1000Port opposite() {
+            if (this.equals(HOST)) {
+                return OPTICS;
+            } else {
+                return HOST;
+            }
+        }
+
+        /**
+         * Evaluate which side of the UNI on the EA1000 device this port refers to.
+         * @param side The assignment of UNI-side to port
+         * @return An enumerated value representing the UniSide
+         */
+        public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
+            if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
+                    (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
+                return UniSide.CUSTOMER;
+            } else {
+                return UniSide.NETWORK;
+            }
+        }
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
new file mode 100644
index 0000000..2ecc70f
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000MeterProvider.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi;
+
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.Meter.Unit;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperations;
+import org.onosproject.net.meter.MeterProvider;
+import org.onosproject.net.meter.MeterProviderRegistry;
+import org.onosproject.net.meter.MeterProviderService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.netconf.TargetConfig;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.CosColorType;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.PriorityType;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.types.rev20160229.mseatypes.coscolortype.CosColorTypeEnum;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.MseaUniEvcService.OnosYangOpType;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.DefaultMefServices;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.DefaultProfiles.ProfilesBuilder;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.Cos;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.DefaultCos;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.bwpgroup.Bwp;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.bwpgroup.DefaultBwp;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.DefaultEvcCosTypeEvcColorId;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.evccostypeevccolorid.DefaultEvcCosTypeAll8PrioTo1EvcColor;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.uni.evc.service.rev20160317.mseaunievcservice.mefservices.profiles.cos.costypechoice.evccostypeevccolorid.EvcCosTypeAll8PrioTo1EvcColor;
+import org.slf4j.Logger;
+
+/**
+ * Provider which uses an NETCONF controller to handle meters.
+ */
+@Component(immediate = true, enabled = true)
+public class EA1000MeterProvider extends AbstractProvider implements MeterProvider {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetconfController controller;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MeterProviderRegistry providerRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc;
+
+    private MeterProviderService providerService;
+
+    private static final int COS_INDEX_1 = 1;
+    private static final short DEFAULT_OUTGOING_PRIO = 3;
+
+    /**
+     * Creates a OpenFlow meter provider.
+     */
+    public EA1000MeterProvider() {
+        super(new ProviderId("netconf", "org.onosproject.provider.meter.microsemi"));
+    }
+
+    @Activate
+    public void activate() {
+        providerService = providerRegistry.register(this);
+
+    }
+
+    @Deactivate
+    public void deactivate() {
+        providerRegistry.unregister(this);
+
+        providerService = null;
+    }
+
+    @Override
+    public void performMeterOperation(DeviceId deviceId, MeterOperations meterOps) {
+        log.debug("Adding meterOps to Microsemi Meter Store");
+    }
+
+    @Override
+    public void performMeterOperation(DeviceId deviceId, MeterOperation meterOp) {
+        if (meterOp == null || deviceId == null) {
+            log.warn("Missing argument for performMeterOperation()");
+            return;
+        }
+        log.debug("{} meterOp {} to Microsemi Meter Store", meterOp.type(), meterOp);
+
+        long meterId = meterOp.meter().id().id();
+        String deviceName = deviceId.uri().getSchemeSpecificPart();
+        Unit unit = meterOp.meter().unit();
+
+        ProfilesBuilder profilesBuilder = DefaultProfiles.builder();
+        if (meterOp.type() == MeterOperation.Type.ADD || meterOp.type() == MeterOperation.Type.MODIFY) {
+            Bwp.BwpBuilder bwpBuilder = DefaultBwp.builder()
+                    .cosIndex(COS_INDEX_1)
+                    .name("BWP-" + String.valueOf(meterId) + "-" + deviceName);
+
+            long cirRateKbps = 0L;
+            long cbsRateKbps = 0L;
+            long eirRateKbps = 0L;
+            long ebsRateKbps = 0L;
+            for (Band band:meterOp.meter().bands()) {
+                if (band.type() == Band.Type.REMARK) {
+                    //This relates to CIR/CBS
+                    cirRateKbps = toBitsPerSec(band.rate(), unit);
+                    cbsRateKbps = band.burst(); //Already in kbps
+                } else if (band.type() == Band.Type.DROP) {
+                    //This relates to EIR/EBS
+                    eirRateKbps = toBitsPerSec(band.rate(), unit);
+                    ebsRateKbps = band.burst(); //Already in kbps
+                }
+            }
+            bwpBuilder.committedInformationRate(cirRateKbps).excessInformationRate(eirRateKbps - cirRateKbps);
+            if (meterOp.meter().isBurst()) {
+                bwpBuilder.committedBurstSize(cbsRateKbps).excessBurstSize(ebsRateKbps - cbsRateKbps);
+            }
+
+            BwpGroup.BwpGroupBuilder bwpgBuilder =
+                    DefaultBwpGroup.builder()
+                    .groupIndex((short) meterId)
+                    .addToBwp(bwpBuilder.build());
+
+            //Create cos-1 as referenced above - we only support 1 at the moment
+            Cos.CosBuilder cosBuilder = DefaultCos.builder()
+                    .cosIndex(COS_INDEX_1)
+                    .name("COS-1")
+                    .outgoingCosValue(PriorityType.of(DEFAULT_OUTGOING_PRIO))
+                    .colorAware(true)
+                    .colorForward(true);
+            EvcCosTypeAll8PrioTo1EvcColor ect =
+                    DefaultEvcCosTypeAll8PrioTo1EvcColor.builder()
+                        .evcAll8ColorTo(CosColorType.of(CosColorTypeEnum.GREEN)).build();
+            profilesBuilder
+                    .addToBwpGroup(bwpgBuilder.build())
+                    .addToCos(cosBuilder.cosTypeChoice(
+                                    DefaultEvcCosTypeEvcColorId.builder()
+                                    .evcCosTypeAll8PrioTo1EvcColor(ect).build()).build())
+                    .build();
+        } else if (meterOp.type() == MeterOperation.Type.REMOVE) {
+            BwpGroup.BwpGroupBuilder bwpgBuilder =
+                    DefaultBwpGroup.builder()
+                    .groupIndex((short) meterId)
+                    .yangBwpGroupOpType(OnosYangOpType.DELETE);
+
+            profilesBuilder.addToBwpGroup(bwpgBuilder.build()).build();
+        }
+
+        MefServices mefServices = DefaultMefServices.builder().profiles(profilesBuilder.build()).build();
+
+        MseaUniEvcService.MseaUniEvcServiceBuilder evcUniBuilder =
+                new MseaUniEvcServiceOpParam.MseaUniEvcServiceBuilder();
+
+        MseaUniEvcServiceOpParam mseaUniEvcServiceFilter =
+                (MseaUniEvcServiceOpParam) evcUniBuilder.mefServices(mefServices).build();
+        NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
+        try {
+            mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, TargetConfig.RUNNING);
+        } catch (NetconfException e) {
+            //This can fail if the BWP Group is deleted before the EVC that is dependent on it
+            //The delete of the EVC will be called on a separate thread to that should proceed
+            //within a few seconds after which we should try again
+            AtomicInteger retry = new AtomicInteger(4);
+            if (meterOp.type() == MeterOperation.Type.REMOVE &&
+                    e.getMessage().startsWith("Failed to run edit-config through NETCONF")) {
+                while (retry.getAndDecrement() > 0) {
+                    try {
+                        Thread.sleep(1000L);
+                        log.debug("Retrying deletion of Bandwith Profile Group {}", String.valueOf(meterId));
+                        mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter,
+                                session, TargetConfig.RUNNING);
+                        return; //If it did not throw an exception
+                    } catch (InterruptedException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    } catch (NetconfException e1) {
+                        log.debug("NETCONF failed to delete profile - trying again in 1 sec");
+                        e1.printStackTrace();
+                    }
+                }
+                log.error("Error deleting BWPGroup {} from {} after 4 tries: {}", meterId, deviceId, e.getMessage());
+            } else {
+                log.error("Error adding BWPGroup {} from {}: {}", meterId, deviceId, e.getMessage());
+                throw new UnsupportedOperationException(e);
+            }
+            e.printStackTrace();
+        }
+    }
+
+    private static long toBitsPerSec(long rate, Unit unit) {
+        if (unit == Unit.KB_PER_SEC) {
+            return rate * 8;
+        } else {
+            return -1;
+        }
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java
new file mode 100644
index 0000000..308bdff
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/EA1000Pipeliner.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.drivers.microsemi.EA1000FlowRuleProgrammable.Ea1000Port;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.slf4j.Logger;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalCause;
+import com.google.common.cache.RemovalNotification;
+
+/**
+ * Support for FlowObjectives in the EA1000.
+ *
+ * Used with the CarrierEthernet App
+ *
+ */
+public class EA1000Pipeliner extends AbstractHandlerBehaviour implements Pipeliner {
+
+    protected final Logger log = getLogger(getClass());
+    protected ServiceDirectory serviceDirectory;
+    protected FlowRuleService flowRuleService;
+    protected DeviceId deviceId;
+    protected Cache<Integer, NextObjective> pendingNext;
+    protected Integer evcIdBase = 1;
+
+    @Override
+    public void init(DeviceId deviceId, PipelinerContext context) {
+        this.serviceDirectory = context.directory();
+        this.deviceId = deviceId;
+
+        flowRuleService = serviceDirectory.get(FlowRuleService.class);
+
+        pendingNext = CacheBuilder.newBuilder()
+                .expireAfterWrite(20, TimeUnit.SECONDS)
+                .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
+                    if (notification.getCause() == RemovalCause.EXPIRED) {
+                        notification.getValue().context()
+                                .ifPresent(c -> c.onError(notification.getValue(),
+                                        ObjectiveError.FLOWINSTALLATIONFAILED));
+                    }
+                }).build();
+
+        log.debug("Loaded handler behaviour EA1000Pipeliner for " + handler().data().deviceId().uri());
+    }
+
+    @Override
+    public void filter(FilteringObjective filterObjective) {
+        TrafficTreatment.Builder actions;
+        boolean oppositePort = false;
+        int evcId = -1;
+        switch (filterObjective.type()) {
+            case PERMIT:
+                if (filterObjective.meta() == null) {
+                    actions = DefaultTrafficTreatment.builder().add(Instructions.popVlan());
+                } else {
+                    oppositePort = true; //Experimental - push happens on the opposite port
+                    actions = DefaultTrafficTreatment.builder(filterObjective.meta());
+                    if (filterObjective.meta().metered() != null) {
+                        actions.meter(filterObjective.meta().metered().meterId());
+                    }
+                    actions.transition(0);
+                    boolean isPush = false;
+                    int vid = 0;
+                    for (Instruction inst:filterObjective.meta().immediate()) {
+                        if (inst.type() == Instruction.Type.L2MODIFICATION) {
+                            L2ModificationInstruction l2mod = (L2ModificationInstruction) inst;
+                            if (l2mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                                isPush = true;
+                            } else if (l2mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
+                                vid = ((ModVlanIdInstruction) l2mod).vlanId().id();
+                            }
+                        }
+                    }
+                    if (isPush && vid > 0) {
+                        evcId = vid;
+                    }
+                }
+                break;
+            case DENY:
+                actions = (filterObjective.meta() == null) ?
+                        DefaultTrafficTreatment.builder() :
+                        DefaultTrafficTreatment.builder(filterObjective.meta());
+                actions.drop();
+                break;
+            default:
+                log.warn("Unknown filter type: {}", filterObjective.type());
+                actions = DefaultTrafficTreatment.builder().drop();
+        }
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        for (Criterion c:filterObjective.conditions()) {
+            if (c.type() == Type.VLAN_VID && evcId == -1) {
+                evcId = ((VlanIdCriterion) c).vlanId().id();
+            }
+            selector.add(c);
+        }
+
+        if (filterObjective.key() != null) {
+            if (oppositePort) {
+                //Experimental
+                Ea1000Port port = Ea1000Port.fromNum(((PortCriterion) filterObjective.key()).port().toLong());
+                selector.matchInPort(PortNumber.portNumber(port.opposite().portNum()));
+            } else {
+                selector.add(filterObjective.key());
+            }
+        }
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(actions.build())
+                .fromApp(filterObjective.appId())
+                .forTable(evcId)
+                .withPriority(filterObjective.priority());
+
+        if (filterObjective.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(filterObjective.timeout());
+        }
+
+        installObjective(ruleBuilder, filterObjective);
+
+        log.debug("filter() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + filterObjective);
+    }
+
+    @Override
+    public void forward(ForwardingObjective forwardObjective) {
+        TrafficSelector selector = forwardObjective.selector();
+
+        if (forwardObjective.treatment() != null) {
+            List<Instruction> instructions = forwardObjective.treatment().immediate();
+            if (instructions != null && instructions.size() == 1
+                    && instructions.get(0).type() == Instruction.Type.OUTPUT
+                    && ((OutputInstruction) instructions.get(0)).port() == PortNumber.CONTROLLER) {
+                Set<Criterion> criteria = forwardObjective.selector().criteria();
+                log.info("EA1000 does not yet implement forwarding to CONTROLLER for flow objective for: "
+                        + handler().data().deviceId().uri()
+                        + ". "
+                        + forwardObjective);
+                return;
+            } else {
+                FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                        .forDevice(deviceId)
+                        .withSelector(selector)
+                        .fromApp(forwardObjective.appId())
+                        .withPriority(forwardObjective.priority())
+                        .withTreatment(forwardObjective.treatment());
+
+                if (forwardObjective.permanent()) {
+                    ruleBuilder.makePermanent();
+                } else {
+                    ruleBuilder.makeTemporary(forwardObjective.timeout());
+                }
+                installObjective(ruleBuilder, forwardObjective);
+            }
+        } else {
+            NextObjective nextObjective = pendingNext.getIfPresent(forwardObjective.nextId());
+            if (nextObjective != null) {
+                pendingNext.invalidate(forwardObjective.nextId());
+                nextObjective.next().forEach(treat -> {
+                    FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                            .forDevice(deviceId)
+                            .withSelector(selector)
+                            .fromApp(forwardObjective.appId())
+                            .withPriority(forwardObjective.priority())
+                            .withTreatment(treat);
+
+                    if (forwardObjective.permanent()) {
+                        ruleBuilder.makePermanent();
+                    } else {
+                        ruleBuilder.makeTemporary(forwardObjective.timeout());
+                    }
+                    installObjective(ruleBuilder, forwardObjective);
+                });
+            } else {
+                forwardObjective.context().ifPresent(c -> c.onError(forwardObjective,
+                        ObjectiveError.GROUPMISSING));
+            }
+        }
+        log.debug("EA1000: Unhandled Forwarding Objective for: "
+                + handler().data().deviceId().uri()
+                + ". "
+                + forwardObjective);
+    }
+
+    @Override
+    public void next(NextObjective nextObjective) {
+        pendingNext.put(nextObjective.id(), nextObjective);
+        nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
+
+        log.debug("next() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + nextObjective);
+    }
+
+    @Override
+    public List<String> getNextMappings(NextGroup nextGroup) {
+        log.debug("getNextMappings() of EA1000Pipeliner called for "
+                + handler().data().deviceId().uri()
+                + ". Objective: " + nextGroup);
+        return new ArrayList<String>();
+    }
+
+    protected void installObjective(FlowRule.Builder ruleBuilder, Objective objective) {
+        FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
+        switch (objective.op()) {
+
+            case ADD:
+                flowBuilder.add(ruleBuilder.build());
+                break;
+            case REMOVE:
+                flowBuilder.remove(ruleBuilder.build());
+                break;
+            default:
+                log.warn("Unknown operation {}", objective.op());
+        }
+
+        flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                objective.context().ifPresent(context -> context.onSuccess(objective));
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                objective.context()
+                        .ifPresent(context -> context.onError(objective, ObjectiveError.FLOWINSTALLATIONFAILED));
+            }
+        }));
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
new file mode 100644
index 0000000..ec43833
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/Ea1000DeviceDescription.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.microsemi.yang.IetfSystemNetconfService;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.system.rev20160505.ietfsystemmicrosemi.system.AugmentedSysSystem;
+import org.onosproject.yang.gen.v1.http.www.microsemi.com.microsemi.edge.assure.msea.system.rev20160505.ietfsystemmicrosemi.systemstate.platform.AugmentedSysPlatform;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.system.rev20140806.IetfSystem;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev20130715.ietfyangtypes.DateAndTime;
+import org.slf4j.Logger;
+
+public class Ea1000DeviceDescription extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery {
+
+    private String serialNumber = "unavailable";
+    private String swVersion = "unavailable";
+    private String longitudeStr = null;
+    private String latitudeStr = null;
+    private final Logger log = getLogger(getClass());
+
+    public Ea1000DeviceDescription() {
+        log.info("Loaded handler behaviour Ea1000DeviceDescription.");
+    }
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+        log.info("Adding description for EA1000 device");
+
+        NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+        NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+        IetfSystemNetconfService ietfSystemService =
+                (IetfSystemNetconfService) checkNotNull(handler().get(IetfSystemNetconfService.class));
+
+        try {
+            IetfSystem system = ietfSystemService.getIetfSystemInit(session);
+            if (system != null && system.systemState() != null) {
+                swVersion = system.systemState().platform().osRelease();
+                AugmentedSysPlatform augmentedSysPlatform =
+                        (AugmentedSysPlatform) system.systemState()
+                        .platform().yangAugmentedInfo(AugmentedSysPlatform.class);
+                serialNumber = augmentedSysPlatform.deviceIdentification().serialNumber();
+                DateAndTime deviceDateAndTime = system.systemState().clock().currentDatetime();
+                OffsetDateTime odt =
+                        OffsetDateTime.parse(deviceDateAndTime.string(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+                if (odt.getYear() < OffsetDateTime.now(ZoneId.of("UTC")).getYear()) {
+                    OffsetDateTime nowUtc = OffsetDateTime.now(ZoneId.of("UTC"));
+                    log.warn("Date on device is in the past: {}. Setting it to {}", odt.toString(), nowUtc);
+                    ietfSystemService.setCurrentDatetime(nowUtc, session);
+                }
+            }
+
+            if (system != null && system.system() != null) {
+                AugmentedSysSystem augmentedSystem =
+                        (AugmentedSysSystem) system.system().yangAugmentedInfo(AugmentedSysSystem.class);
+                longitudeStr = augmentedSystem.longitude().toPlainString();
+                latitudeStr = augmentedSystem.latitude().toPlainString();
+            }
+        } catch (NetconfException e) {
+            log.error("Unable to retrieve init data from device: " + handler().data().deviceId().toString()
+                    + " Error: " + e.getMessage());
+            e.printStackTrace();
+        }
+
+        DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
+        DeviceId deviceId = handler().data().deviceId();
+        Device device = deviceService.getDevice(deviceId);
+        DefaultAnnotations.Builder annotationsBuilder = DefaultAnnotations.builder();
+        if (longitudeStr != null && latitudeStr != null) {
+            annotationsBuilder.set(AnnotationKeys.LONGITUDE, longitudeStr)
+                    .set(AnnotationKeys.LATITUDE, latitudeStr).build();
+        } else {
+            log.warn("Longitude and latitude could not be retrieved from device " + deviceId);
+        }
+
+        return new DefaultDeviceDescription(device.id().uri(), Device.Type.OTHER, "Microsemi", "EA1000", swVersion,
+                serialNumber, new ChassisId(), annotationsBuilder.build());
+    }
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+
+        List<PortDescription> ports = new ArrayList<PortDescription>();
+
+        DefaultAnnotations annotationOptics = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "Optics")
+                .build();
+        PortDescription optics = new DefaultPortDescription(PortNumber.portNumber(0), true, Port.Type.FIBER, 1000,
+                annotationOptics);
+        ports.add(optics);
+
+        DefaultAnnotations annotationHost = DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "Host").build();
+        PortDescription host = new DefaultPortDescription(PortNumber.portNumber(1), true, Port.Type.COPPER, 1000,
+                annotationHost);
+        ports.add(host);
+
+        return ports;
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java
new file mode 100644
index 0000000..724792e
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/FullMetersAvailable.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.onosproject.net.behaviour.MeterQuery;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+
+/**
+ * Driver which always responds that all Meters are available for the Device.
+ */
+public class FullMetersAvailable extends AbstractHandlerBehaviour implements MeterQuery {
+
+    private static final long MAX_METER = 0x00000FFF;
+
+    @Override
+    public long getMaxMeters() {
+        return MAX_METER;
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java
new file mode 100644
index 0000000..b7f0e68
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoader.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.apache.felix.scr.annotations.Component;
+import org.onosproject.net.driver.AbstractDriverLoader;
+
+/**
+ * Loader for Microsemi device drivers.
+ */
+@Component(immediate = true)
+public class MicrosemiDriversLoader extends AbstractDriverLoader {
+
+    public MicrosemiDriversLoader() {
+        super("/microsemi-drivers.xml");
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java
new file mode 100644
index 0000000..53151bb
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/NetconfConfigGetter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.drivers.microsemi;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ConfigGetter;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.netconf.NetconfController;
+import org.slf4j.Logger;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Used with the onos:device-configuration CLI command.
+ *
+ * This allows the full configuration to be retrieved from the device
+ */
+public class NetconfConfigGetter extends AbstractHandlerBehaviour implements ConfigGetter {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    private PacketProcessor testProcessor;
+
+    // FIXME the error string should be universal for all implementations of
+    // ConfigGetter
+    public static final String UNABLE_TO_READ_CONFIG = "config retrieval error";
+
+    @Override
+    public String getConfiguration(String type) {
+        DriverHandler handler = handler();
+        NetconfController controller = handler.get(NetconfController.class);
+
+        DeviceId ofDeviceId = handler.data().deviceId();
+        Preconditions.checkNotNull(controller, "Netconf controller is null");
+        if (type == null ||
+                (!type.equalsIgnoreCase("running")
+                        && !type.equalsIgnoreCase("candidate")
+                        && !type.equalsIgnoreCase("startup"))) {
+            log.error("Configuration type must be either 'running', 'startup' or 'candidate'. '{}' is invalid", type);
+            return UNABLE_TO_READ_CONFIG;
+        }
+        try {
+            return controller.getDevicesMap().get(ofDeviceId).getSession().getConfig(type.replace("cfgType=", ""));
+        } catch (IOException e) {
+            log.error("Configuration could not be retrieved {}", e.getMessage());
+        }
+        return UNABLE_TO_READ_CONFIG;
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java
new file mode 100644
index 0000000..7589ea7
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/RpcResultParser.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+public final class RpcResultParser {
+
+    private RpcResultParser() {
+        //Not called
+    }
+
+    public static String parseXml(final String deviceDescriptionResponse, final String keyWord) {
+
+        int end = deviceDescriptionResponse.lastIndexOf(keyWord);
+        end = deviceDescriptionResponse.lastIndexOf('<', end);
+        int start = deviceDescriptionResponse.lastIndexOf('>', end);
+        if (start > 1 && end > start) {
+            return deviceDescriptionResponse.substring(start + 1, end);
+        } else {
+            return null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/package-info.java b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/package-info.java
new file mode 100644
index 0000000..de883d1
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/java/org/onosproject/drivers/microsemi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package for Microsemi device drivers.
+ */
+package org.onosproject.drivers.microsemi;
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/main/resources/microsemi-drivers.xml b/drivers/microsemi/ea1000driver/src/main/resources/microsemi-drivers.xml
new file mode 100644
index 0000000..988ac9a
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/main/resources/microsemi-drivers.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<drivers>
+	<driver name="microsemi-netconf" extends="netconf" manufacturer="Microsemi"
+		hwVersion="EA1000">
+		<behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
+			impl="org.onosproject.drivers.microsemi.Ea1000DeviceDescription" />
+		<behaviour api="org.onosproject.net.behaviour.ConfigGetter"
+			impl="org.onosproject.drivers.microsemi.NetconfConfigGetter" />
+		<behaviour api="org.onosproject.net.behaviour.Pipeliner"
+			impl="org.onosproject.drivers.microsemi.EA1000Pipeliner" />
+		<behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
+			impl="org.onosproject.drivers.microsemi.EA1000FlowRuleProgrammable" />
+		<behaviour api="org.onosproject.net.behaviour.MeterQuery"
+			impl="org.onosproject.drivers.microsemi.FullMetersAvailable" />
+<!--         <behaviour api="org.onosproject.incubator.net.l2monitoring.cfm.CfmMepProgrammable" -->
+<!--             impl="org.onosproject.drivers.microsemi.EA1000CfmMepProgrammable"/> -->
+<!--         <behaviour api="org.onosproject.incubator.net.l2monitoring.soam.SoamDmProgrammable" -->
+<!--             impl="org.onosproject.drivers.microsemi.EA1000SoamDmProgrammable"/> -->
+	</driver>
+</drivers>
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammableTest.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammableTest.java
new file mode 100644
index 0000000..24aad06
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammableTest.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.EthType.EtherType;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public class EA1000FlowRuleProgrammableTest {
+    EA1000FlowRuleProgrammable frProgramable;
+
+    @Before
+    public void setUp() throws Exception {
+        frProgramable = new EA1000FlowRuleProgrammable();
+        frProgramable.setHandler(new MockEa1000DriverHandler());
+        assertNotNull(frProgramable.handler().data().deviceId());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    @Test
+    public void testGetFlowEntries() {
+        //From MockNetconfSession sample of MseaSaFiltering
+        Collection<FlowEntry> flowEntries = frProgramable.getFlowEntries();
+
+        assertNotNull(flowEntries);
+        //There will be 12 flow entries
+        // 2 for IP Src Address filtering
+        // 2 for EVC 7 - one each port
+        // 8 for EVC 8 - one for host port, 7 on optics port because of ceVlanMap 12:14,20:22,25
+        assertEquals(12, flowEntries.size());
+
+        //Test the first Flow Entry
+        Iterator<FlowEntry> feIter = flowEntries.iterator();
+        while (feIter.hasNext()) {
+            FlowEntry fe = feIter.next();
+            assertTrue(fe.isPermanent());
+            assertEquals(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT, fe.priority());
+
+            Set<Criterion> criteria = fe.selector().criteria();
+            IPCriterion ipCr = null;
+            PortNumber port = null;
+            for (Criterion cr:criteria.toArray(new Criterion[criteria.size()])) {
+                if (cr.type() == Criterion.Type.IPV4_SRC) {
+                    ipCr = (IPCriterion) cr;
+                } else if (cr.type() == Criterion.Type.IN_PORT) {
+                    port = ((PortCriterion) cr).port();
+                } else if (cr.type() == Criterion.Type.VLAN_VID) {
+                    VlanId vid = ((VlanIdCriterion) cr).vlanId();
+                } else {
+                    fail("Unexpected Criterion type: " + cr.type().toString());
+                }
+            }
+            if (ipCr != null && (port == null || port.toLong() != 0L)) {
+                fail("Port number not equal 0 when IP Src Address filter is present");
+            }
+
+            List<Instruction> instructions = fe.treatment().allInstructions();
+
+            if (fe.tableId() == 1) {
+                //Note that in MockNetconf session 10.10.10.10/16 was entered
+                //but it has been corrected to the following by the OF implementation
+                assertEquals("10.10.0.0/16", ipCr.ip().toString());
+                assertEquals(FlowEntryState.ADDED, fe.state());
+            } else if (fe.tableId() == 2) {
+                //Likewise 20.30.40.50 has been truncated because of the 18 bit mask
+                assertEquals("20.30.0.0/18", ipCr.ip().toString());
+                assertEquals(FlowEntryState.ADDED, fe.state());
+            } else if (fe.tableId() == 7 || fe.tableId() == 8) {
+                // 7 and 8 are EVC entries - 2 elements - IN_PORT and VLAN_ID
+                assertEquals(2, fe.selector().criteria().size());
+                //In MockNetconfSession we're rigged it so that the last two chars of the
+                //flow id is the same as the VlanId
+                short vlanId = ((VlanIdCriterion) fe.selector().getCriterion(Type.VLAN_VID)).vlanId().toShort();
+                long flowId = fe.id().id();
+                String flowIdStr = String.valueOf(flowId).substring(String.valueOf(flowId).length() - 2);
+                assertEquals(flowIdStr, String.valueOf(vlanId));
+                if (((PortCriterion) fe.selector().getCriterion(Type.IN_PORT)).port().toLong() == 1L) {
+                    assertEquals(Instruction.Type.L2MODIFICATION, instructions.get(0).type());
+                }
+            } else {
+                fail("Unexpected Flow Entry Rule " + fe.tableId());
+            }
+        }
+    }
+
+    @Test
+    public void testSetFlowEntries() {
+        Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
+
+        TrafficTreatment treatmentDrop = DefaultTrafficTreatment.builder().drop().build();
+
+        Collection<FlowRule> frAddedList = new HashSet<FlowRule>();
+
+        FlowRule fr4 = new DefaultFlowRule.Builder()
+            .forDevice(frProgramable.handler().data().deviceId())
+            .forTable(4)
+            .withSelector(DefaultTrafficSelector.builder()
+                    .matchIPSrc(IpPrefix.valueOf("192.168.60.0/22"))
+                    .add(matchInPort).build())
+            .withTreatment(treatmentDrop)
+            .fromApp(new DefaultApplicationId(4, "Filter4"))
+            .makePermanent()
+            .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+            .build();
+        frAddedList.add(fr4);
+
+        FlowRule fr5 = new DefaultFlowRule.Builder()
+                .forDevice(frProgramable.handler().data().deviceId())
+                .forTable(5)
+                .withSelector(DefaultTrafficSelector.builder()
+                        .matchIPSrc(IpPrefix.valueOf("192.168.50.0/23"))
+                        .add(matchInPort).build())
+                .withTreatment(treatmentDrop)
+                .withCookie(Long.valueOf("5e0000abaa2772", 16))
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frAddedList.add(fr5);
+
+        //Add in some EVCs - especially with complex ceVlanMaps
+        FlowRule frEvc1Vid19P0 = new DefaultFlowRule.Builder()
+                .forDevice(frProgramable.handler().data().deviceId())
+                .forTable(1)
+                .withSelector(DefaultTrafficSelector.builder()
+                        .matchInPort(PortNumber.portNumber(0L))
+                        .matchVlanId(VlanId.vlanId((short) 19))
+                        .build())
+                .withTreatment(DefaultTrafficTreatment.builder()
+                        .popVlan()
+                        .build())
+                .withCookie(Long.valueOf("1e0000abaa0019", 16))
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frAddedList.add(frEvc1Vid19P0);
+
+        FlowRule frEvc1Vid20P0 = new DefaultFlowRule.Builder()
+                .forDevice(frProgramable.handler().data().deviceId())
+                .forTable(1)
+                .withSelector(DefaultTrafficSelector.builder()
+                        .matchInPort(PortNumber.portNumber(0L))
+                        .matchVlanId(VlanId.vlanId((short) 20))
+                        .build())
+                .withTreatment(DefaultTrafficTreatment.builder()
+                        .popVlan()
+                        .build())
+                .withCookie(Long.valueOf("1e0000abaa0020", 16))
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frAddedList.add(frEvc1Vid20P0);
+
+        FlowRule frEvc1Vid21P1 = new DefaultFlowRule.Builder()
+                .forDevice(frProgramable.handler().data().deviceId())
+                .forTable(1)
+                .withSelector(DefaultTrafficSelector.builder()
+                        .matchInPort(PortNumber.portNumber(1L))
+                        .matchVlanId(VlanId.vlanId((short) 21))
+                        .build())
+                .withTreatment(DefaultTrafficTreatment.builder()
+                        .setVlanId(VlanId.vlanId((short) 250))
+                        .pushVlan(EtherType.QINQ.ethType())
+                        .build())
+                .withCookie(Long.valueOf("1e0000abaa0121", 16))
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frAddedList.add(frEvc1Vid21P1);
+
+        FlowRule frEvc1Vid22P1 = new DefaultFlowRule.Builder()
+                .forDevice(frProgramable.handler().data().deviceId())
+                .forTable(1)
+                .withSelector(DefaultTrafficSelector.builder()
+                        .matchInPort(PortNumber.portNumber(1L))
+                        .matchVlanId(VlanId.vlanId((short) 22))
+                        .build())
+                .withTreatment(DefaultTrafficTreatment.builder()
+                        .setVlanId(VlanId.vlanId((short) 250))
+                        .pushVlan(EtherType.QINQ.ethType())
+                        .build())
+                .withCookie(Long.valueOf("1e0000abaa0122", 16))
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frAddedList.add(frEvc1Vid22P1);
+
+        Collection<FlowRule> returnedFrList = frProgramable.applyFlowRules(frAddedList);
+
+        assertNotNull(returnedFrList);
+        assertEquals(6, returnedFrList.size());
+
+        //Test the scenario like in FlowRuleManager$InternalFlowRuleProviderService.pushFlowMetricsInternal()
+        Map<FlowEntry, FlowEntry> storedRules = Maps.newHashMap();
+        frAddedList.forEach(f -> storedRules.put(new DefaultFlowEntry(f), new DefaultFlowEntry(f)));
+        List<FlowEntry> feList = Lists.newArrayList();
+        returnedFrList.forEach(f -> feList.add(new DefaultFlowEntry(f)));
+
+        for (FlowEntry rule : feList) {
+            FlowEntry fer = storedRules.remove(rule);
+            assertNotNull(fer);
+            assertTrue(fer.exactMatch(rule));
+        }
+
+        for (FlowRule fr:returnedFrList.toArray(new FlowRule[2])) {
+            if (fr.tableId() == 4) {
+                assertEquals("IPV4_SRC:192.168.60.0/22",
+                        ((IPCriterion) fr.selector().getCriterion(Type.IPV4_SRC)).toString());
+            } else if (fr.tableId() == 5) {
+                assertEquals("IPV4_SRC:192.168.50.0/23",
+                        ((IPCriterion) fr.selector().getCriterion(Type.IPV4_SRC)).toString());
+                assertEquals(Long.valueOf("5e0000abaa2772", 16), fr.id().id());
+            } else if (fr.tableId() == 1) {
+                //TODO add in tests
+            } else {
+                fail("Unexpected flow rule " + fr.tableId() + " in test");
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveFlowEntries() {
+        TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+        Criterion matchInPort0 = Criteria.matchInPort(PortNumber.portNumber(0));
+        Criterion matchInPort1 = Criteria.matchInPort(PortNumber.portNumber(1));
+
+        TrafficTreatment.Builder trDropBuilder = DefaultTrafficTreatment.builder();
+        TrafficTreatment treatmentDrop = trDropBuilder.drop().build();
+
+        Collection<FlowRule> frRemoveList = new HashSet<FlowRule>();
+        ApplicationId app = new DefaultApplicationId(1, "org.onosproject.rest");
+
+        Criterion matchIpSrc1 = Criteria.matchIPSrc(IpPrefix.valueOf("10.10.10.10/16"));
+        TrafficSelector selector1 = tsBuilder.add(matchIpSrc1).add(matchInPort0).build();
+        FlowRule.Builder frBuilder1 = new DefaultFlowRule.Builder();
+        frBuilder1.forDevice(frProgramable.handler().data().deviceId())
+                .withSelector(selector1)
+                .withTreatment(treatmentDrop)
+                .forTable(2)
+                .fromApp(app)
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT);
+        frRemoveList.add(frBuilder1.build());
+
+        Criterion matchIpSrc2 = Criteria.matchIPSrc(IpPrefix.valueOf("10.30.10.10/16"));
+        TrafficSelector selector2 = tsBuilder.add(matchIpSrc2).add(matchInPort0).build();
+        FlowRule.Builder frBuilder2 = new DefaultFlowRule.Builder();
+        frBuilder2.forDevice(frProgramable.handler().data().deviceId())
+                .withSelector(selector2)
+                .withTreatment(treatmentDrop)
+                .forTable(3)
+                .fromApp(app)
+                .makePermanent()
+                .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+                .build();
+        frRemoveList.add(frBuilder2.build());
+
+
+        TrafficTreatment.Builder trVlanPopBuilder = DefaultTrafficTreatment.builder();
+        TrafficTreatment treatmentVlanPop = trVlanPopBuilder.popVlan().build();
+
+
+        Criterion matchVlan710 = Criteria.matchVlanId(VlanId.vlanId((short) 710));
+        TrafficSelector selector3 = DefaultTrafficSelector.builder().add(matchVlan710).add(matchInPort1).build();
+        FlowRule.Builder frBuilder3 = new DefaultFlowRule.Builder();
+        frBuilder3.forDevice(frProgramable.handler().data().deviceId())
+            .withSelector(selector3)
+            .withTreatment(treatmentVlanPop)
+            .forTable(7)
+            .fromApp(app)
+            .makePermanent()
+            .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+            .build();
+        frRemoveList.add(frBuilder3.build());
+
+
+        Criterion matchVlan101 = Criteria.matchVlanId(VlanId.vlanId((short) 101));
+        TrafficSelector selector4 = DefaultTrafficSelector.builder().add(matchVlan101).add(matchInPort1).build();
+        FlowRule.Builder frBuilder4 = new DefaultFlowRule.Builder();
+        frBuilder4.forDevice(frProgramable.handler().data().deviceId())
+            .withSelector(selector4)
+            .withTreatment(treatmentVlanPop)
+            .forTable(1)
+            .fromApp(app)
+            .makePermanent()
+            .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+            .build();
+        frRemoveList.add(frBuilder4.build());
+
+        Criterion matchVlan102 = Criteria.matchVlanId(VlanId.vlanId((short) 102));
+        TrafficSelector selector5 = DefaultTrafficSelector.builder().add(matchVlan102).add(matchInPort0).build();
+        FlowRule.Builder frBuilder5 = new DefaultFlowRule.Builder();
+        frBuilder5.forDevice(frProgramable.handler().data().deviceId())
+            .withSelector(selector5)
+            .withTreatment(treatmentVlanPop)
+            .forTable(1)
+            .fromApp(app)
+            .makePermanent()
+            .withPriority(EA1000FlowRuleProgrammable.PRIORITY_DEFAULT)
+            .build();
+        frRemoveList.add(frBuilder5.build());
+
+        Collection<FlowRule> removedFrList = frProgramable.removeFlowRules(frRemoveList);
+        assertNotNull(removedFrList);
+        assertEquals(5, removedFrList.size());
+
+        for (FlowRule frRemoved:removedFrList) {
+            assertNotNull(frRemoved);
+        }
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000MeterProviderTest.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000MeterProviderTest.java
new file mode 100644
index 0000000..b00b321
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/EA1000MeterProviderTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import java.util.HashSet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.drivers.microsemi.yang.MockMseaUniEvcServiceManager;
+import org.onosproject.drivers.microsemi.yang.MockNetconfSessionEa1000;
+import org.onosproject.drivers.netconf.MockNetconfController;
+import org.onosproject.drivers.netconf.MockNetconfDevice;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeter;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.Meter.Unit;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperation.Type;
+import org.onosproject.netconf.NetconfController;
+
+public class EA1000MeterProviderTest {
+
+    private EA1000MeterProvider meterProvider;
+    private NetconfController controller;
+    private DeviceId mockDeviceId;
+    private MockMseaUniEvcServiceManager mseaUniEvcServiceSvc;
+
+    @Before
+    public void setUp() throws Exception {
+        mockDeviceId = DeviceId.deviceId("netconf:1.2.3.4:830");
+        controller = new MockNetconfController();
+        MockNetconfDevice device = (MockNetconfDevice) controller.connectDevice(mockDeviceId);
+        device.setNcSessionImpl(MockNetconfSessionEa1000.class);
+        mseaUniEvcServiceSvc = new MockMseaUniEvcServiceManager();
+        mseaUniEvcServiceSvc.activate();
+        meterProvider = new TestEA1000MeterProvider(controller, mseaUniEvcServiceSvc);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    @Test
+    public void testPerformMeterOperationDeviceIdMeterAdd() {
+        DeviceId mockDeviceId = DeviceId.deviceId("netconf:1.2.3.4:830");
+
+        Band cbsBand = DefaultBand.builder()
+                .ofType(Band.Type.REMARK) //Committed - CIR & CBS
+                .withRate(37500L)
+                .burstSize(2000)
+                .dropPrecedence((short) 0)
+                .build();
+
+        Band ebsBand = DefaultBand.builder()
+                .ofType(Band.Type.DROP) //Excess - EIR & EBS
+                .withRate(50000L) //The rate at which we drop - for EA 1000 subtract CIR to get EIR
+                .burstSize(3000) //The burst rate to drop at
+                .build();
+
+        Meter.Builder mBuilder = DefaultMeter.builder()
+                .forDevice(mockDeviceId)
+                .withId(MeterId.meterId(1))
+                .fromApp(new DefaultApplicationId(101, "unit.test"))
+                .burst()
+                .withUnit(Unit.KB_PER_SEC)
+                .withBands(new HashSet<Band>() { { add(cbsBand); add(ebsBand); } });
+
+        MeterOperation meterOp = new MeterOperation(mBuilder.build(), Type.ADD);
+
+        meterProvider.performMeterOperation(mockDeviceId, meterOp);
+        //The NETCONF XML generated by this matches the pattern
+        // sampleXmlRegexEditConfigBwpGroup1
+        // in MockNetconfSession
+    }
+
+    @Test
+    public void testPerformMeterOperationDeviceIdMeterRemove() {
+        DeviceId mockDeviceId = DeviceId.deviceId("netconf:1.2.3.4:830");
+
+        Band cbsBand = DefaultBand.builder()
+                .ofType(Band.Type.REMARK) //Committed - CIR & CBS
+                .withRate(37500L)
+                .burstSize(2000)
+                .dropPrecedence((short) 0)
+                .build();
+
+        Meter.Builder mBuilder = DefaultMeter.builder()
+                .forDevice(mockDeviceId)
+                .withId(MeterId.meterId(1))
+                .fromApp(new DefaultApplicationId(101, "unit.test"))
+                .burst()
+                .withBands(new HashSet<Band>() { { add(cbsBand); } });
+
+        MeterOperation meterOp = new MeterOperation(mBuilder.build(), Type.REMOVE);
+
+        meterProvider.performMeterOperation(mockDeviceId, meterOp);
+        //The NETCONF XML generated by this matches the pattern
+        // sampleXmlRegexEditConfigBwpGroup1
+        // in MockNetconfSession
+    }
+
+}
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoaderTest.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoaderTest.java
new file mode 100644
index 0000000..a53c6e3
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MicrosemiDriversLoaderTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.junit.Before;
+import org.onosproject.net.driver.AbstractDriverLoaderTest;
+
+
+/**
+ * Microsemi drivers loader test.
+ */
+public class MicrosemiDriversLoaderTest extends AbstractDriverLoaderTest {
+
+    @Before
+    public void setUp() {
+        loader = new MicrosemiDriversLoader();
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java
new file mode 100644
index 0000000..78a9d32
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/MockEa1000DriverHandler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MockMseaSaFilteringManager;
+import org.onosproject.drivers.microsemi.yang.MockMseaUniEvcServiceManager;
+import org.onosproject.drivers.microsemi.yang.MockNetconfSessionEa1000;
+import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.drivers.netconf.MockCoreService;
+import org.onosproject.drivers.netconf.MockNetconfController;
+import org.onosproject.drivers.netconf.MockNetconfDevice;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.DefaultDriver;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfException;
+
+/**
+ * A Mock implementation of the DriverHandler to facilitate unit tests.
+ *
+ * This brings in the implementations of MockMseaSaFilteringManager, MockMseaUniEvcServiceManager,
+ * MockCoreService, MockNetconfDevice and MockNetconfSessionEa1000
+ */
+public class MockEa1000DriverHandler implements DriverHandler {
+
+    private static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
+
+    private DriverData mockDriverData;
+
+    private NetconfController ncc;
+    private MockMseaSaFilteringManager mseaSaFilteringService;
+    private MockMseaUniEvcServiceManager mseaUniEvcService;
+    private CoreService coreService;
+
+    public MockEa1000DriverHandler() throws NetconfException {
+        Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
+                new HashMap<Class<? extends Behaviour>, Class<? extends Behaviour>>();
+        behaviours.put(FlowRuleProgrammable.class, FlowRuleProgrammable.class);
+
+        Map<String, String> properties = new HashMap<String, String>();
+
+        Driver mockDriver =
+                new DefaultDriver("mockDriver", null, "ONOSProject", "1.0.0", "1.0.0", behaviours, properties);
+        DeviceId mockDeviceId = DeviceId.deviceId("netconf:1.2.3.4:830");
+        mockDriverData = new DefaultDriverData(mockDriver, mockDeviceId);
+
+
+        ncc = new MockNetconfController();
+        MockNetconfDevice device = (MockNetconfDevice) ncc.connectDevice(mockDeviceId);
+        device.setNcSessionImpl(MockNetconfSessionEa1000.class);
+
+        mseaSaFilteringService = new MockMseaSaFilteringManager();
+        mseaSaFilteringService.activate();
+
+        mseaUniEvcService = new MockMseaUniEvcServiceManager();
+        mseaUniEvcService.activate();
+
+        coreService = new MockCoreService();
+        coreService.registerApplication(MICROSEMI_DRIVERS);
+    }
+
+    @Override
+    public Driver driver() {
+        return mockDriverData.driver();
+    }
+
+    @Override
+    public DriverData data() {
+        return mockDriverData;
+    }
+
+    @Override
+    public <T extends Behaviour> T behaviour(Class<T> behaviourClass) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public <T> T get(Class<T> serviceClass) {
+        if (serviceClass.equals(NetconfController.class)) {
+            return (T) ncc;
+
+        } else if (serviceClass.equals(MseaSaFilteringNetconfService.class)) {
+            return (T) mseaSaFilteringService;
+
+        } else if (serviceClass.equals(MseaUniEvcServiceNetconfService.class)) {
+            return (T) mseaUniEvcService;
+
+        } else if (serviceClass.equals(CoreService.class)) {
+            return (T) coreService;
+
+        }
+
+        return null;
+    }
+
+}
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/RpcResultParserTest.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/RpcResultParserTest.java
new file mode 100644
index 0000000..64dd80e
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/RpcResultParserTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static org.junit.Assert.*;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.junit.Test;
+
+public class RpcResultParserTest {
+
+    private static final String SAMPLE1_XML = "/systemReply-Sample1.xml";
+    private static final String SAMPLE2_XML = "/systemReply-Sample2.xml";
+
+    @Test
+    public void testSerialNumber1() {
+        String serialNumberReply = loadXml(SAMPLE1_XML);
+        String serialNumber = RpcResultParser.parseXml(serialNumberReply, "serial-number");
+        assertEquals("Eagle Simulator.", serialNumber);
+    }
+
+    @Test
+    public void testSerialNumber2() {
+        String serialNumberReply = loadXml(SAMPLE2_XML);
+        String serialNumber = RpcResultParser.parseXml(serialNumberReply, "serial-number");
+        assertEquals(null, serialNumber);
+    }
+
+    @Test
+    public void testOsRelease1() {
+        String osReleaseReply = loadXml(SAMPLE1_XML);
+        String osRelease = RpcResultParser.parseXml(osReleaseReply, "os-release");
+        assertEquals("2.6.33-arm1-MSEA1000--00326-g643be76.x.0.0.212", osRelease);
+    }
+
+    @Test
+    public void testOsRelease2() {
+        String osReleaseReply = loadXml(SAMPLE2_XML);
+        String osRelease = RpcResultParser.parseXml(osReleaseReply, "os-release");
+        assertEquals(null, osRelease);
+    }
+
+    @Test
+    public void testLongitude() {
+        String longitudeReply = loadXml(SAMPLE1_XML);
+        String longitudeStr = RpcResultParser.parseXml(longitudeReply, "longitude");
+        assertEquals("-8.4683990", longitudeStr);
+    }
+
+    @Test
+    public void testLatitude() {
+        String latitudeReply = loadXml(SAMPLE1_XML);
+        String latitudeStr = RpcResultParser.parseXml(latitudeReply, "latitude");
+        assertEquals("51.9036140", latitudeStr);
+    }
+
+
+    private static String loadXml(final String fileName) {
+
+        InputStream inputStream = RpcResultParserTest.class.getResourceAsStream(fileName);
+        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+        StringBuilder result = new StringBuilder();
+        try {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return result.toString();
+    }
+}
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/TestEA1000MeterProvider.java b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/TestEA1000MeterProvider.java
new file mode 100644
index 0000000..e56e121
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/java/org/onosproject/drivers/microsemi/TestEA1000MeterProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.netconf.NetconfController;
+
+public class TestEA1000MeterProvider extends EA1000MeterProvider {
+
+    public TestEA1000MeterProvider(NetconfController controller,
+            MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc) {
+        this.controller = controller;
+        this.mseaUniEvcServiceSvc = mseaUniEvcServiceSvc;
+    }
+}
diff --git a/drivers/microsemi/ea1000driver/src/test/resources/CarrierEthernetFeature-sampleEvcConfig1.txt b/drivers/microsemi/ea1000driver/src/test/resources/CarrierEthernetFeature-sampleEvcConfig1.txt
new file mode 100644
index 0000000..04db8030
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/resources/CarrierEthernetFeature-sampleEvcConfig1.txt
@@ -0,0 +1,85 @@
+onos> ce-evc-list
+CarrierEthernetVirtualConnection{
+    id=EP-Line-1, cfgId=evpl1, type=POINT_TO_POINT, state=ACTIVE,
+    UNIs=[
+        CarrierEthernetUni{
+            id=netconf:192.168.56.10:830/0,
+            cfgId=netconf:192.168.56.10:830/0,
+            role=Root,
+            refCount=0,
+            ceVlanIds=[100],
+            capacity=1000000000,
+            usedCapacity=3.0E8,
+            bandwidthProfiles=[
+                CarrierEthernetBandwidthProfile{
+                    id=FC-1,
+                    type=EVC,
+                    cir=3.0E8,
+                    cbs=2000,
+                    eir=0.0,
+                    ebs=0}]},
+        CarrierEthernetUni{
+            id=netconf:192.168.56.20:830/0,
+            cfgId=netconf:192.168.56.20:830/0,
+            role=Root,
+            refCount=0,
+            ceVlanIds=[100],
+            capacity=1000000000,
+            usedCapacity=3.0E8,
+            bandwidthProfiles=[
+                CarrierEthernetBandwidthProfile{
+                    id=FC-1,
+                    type=EVC,
+                    cir=3.0E8,
+                    cbs=2000,
+                    eir=0.0,
+                    ebs=0}]}],
+    FCs=[
+        CarrierEthernetForwardingConstruct{
+            id=FC-1,
+            cfgId=null,
+            type=POINT_TO_POINT,
+            vlanId=1,
+            metroConnectId=null,
+            refCount=1,
+            LTPs=[
+                CarrierEthernetLogicalTerminationPoint{
+                    id=netconf:192.168.56.10:830/0,
+                    cfgId=netconf:192.168.56.10:830/0,
+                    role=Root,
+                    ni=CarrierEthernetUni{
+                        id=netconf:192.168.56.10:830/0,
+                        cfgId=netconf:192.168.56.10:830/0,
+                        role=Root,
+                        refCount=0,
+                        ceVlanIds=[100],
+                        capacity=1000000000,
+                        usedCapacity=3.0E8,
+                        bandwidthProfiles=[
+                            CarrierEthernetBandwidthProfile{
+                                id=FC-1,
+                                type=EVC,
+                                cir=3.0E8,
+                                cbs=2000,
+                                eir=0.0,
+                                ebs=0}]}},
+                CarrierEthernetLogicalTerminationPoint{
+                    id=netconf:192.168.56.20:830/0,
+                    cfgId=netconf:192.168.56.20:830/0,
+                    role=Root,
+                    ni=CarrierEthernetUni{
+                        id=netconf:192.168.56.20:830/0,
+                        cfgId=netconf:192.168.56.20:830/0,
+                        role=Root,
+                        refCount=0,
+                        ceVlanIds=[100],
+                        capacity=1000000000,
+                        usedCapacity=3.0E8,
+                        bandwidthProfiles=[
+                            CarrierEthernetBandwidthProfile{
+                                id=FC-1,
+                                type=EVC,
+                                cir=3.0E8,
+                                cbs=2000,
+                                eir=0.0,
+                                ebs=0}]}}]}]}
diff --git a/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFiltering.xml b/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFiltering.xml
new file mode 100644
index 0000000..53bfe46
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFiltering.xml
@@ -0,0 +1,11 @@
+<rpc message-id="101"
+     xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <get-config>
+        <source>
+            <running/>
+        </source>
+        <filter type="subtree">
+            <source-ipaddress-filtering xmlns="http://www.microsemi.com/microsemi-edge-assure/msea-sa-filtering"/>
+        </filter>
+    </get-config>
+</rpc>
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFilteringReply.xml b/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFilteringReply.xml
new file mode 100644
index 0000000..6e1e040
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/resources/getConfigSaFilteringReply.xml
@@ -0,0 +1,14 @@
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="7">
+    <data>
+        <source-ipaddress-filtering xmlns="http://www.microsemi.com/microsemi-edge-assure/msea-sa-filtering">
+            <interface-eth0>
+                <source-address-range>
+                    <range-id>1</range-id>
+                    <ipv4-address-prefix>10.10.10.10/16</ipv4-address-prefix>
+                    <name>Filter1</name>
+                </source-address-range>
+                <filter-admin-state>inactive</filter-admin-state>
+            </interface-eth0>
+        </source-ipaddress-filtering>
+    </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample1.xml b/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample1.xml
new file mode 100644
index 0000000..206bf45
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample1.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
+    <data>
+        <system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
+            <longitude xmlns="http://www.microsemi.com/microsemi-edge-assure/msea-system">-8.4683990</longitude>
+            <latitude xmlns="http://www.microsemi.com/microsemi-edge-assure/msea-system">51.9036140</latitude>
+        </system>
+        <system-state xmlns="urn:ietf:params:xml:ns:yang:ietf-system" xmlns:sysms="http://www.microsemi.com/microsemi-edge-assure/msea-system">
+            <platform>
+                <os-release>2.6.33-arm1-MSEA1000--00326-g643be76.x.0.0.212</os-release>
+                <sysms:device-identification>
+                    <sysms:serial-number>Eagle Simulator.</sysms:serial-number>
+                </sysms:device-identification>
+            </platform>
+        </system-state>
+    </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample2.xml b/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample2.xml
new file mode 100644
index 0000000..9592538
--- /dev/null
+++ b/drivers/microsemi/ea1000driver/src/test/resources/systemReply-Sample2.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
+  <data>
+    <system-state xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
+      <platform/>
+    </system-state>
+  </data>
+</rpc-reply>
\ No newline at end of file