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/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