Updating Microsemi Driver to onos-yang-tools 2.x
Change-Id: I80e3348087518a8f9a742c813b6238371a3f8f97
diff --git a/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
new file mode 100644
index 0000000..4df22ec
--- /dev/null
+++ b/drivers/microsemi/src/main/java/org/onosproject/drivers/microsemi/EA1000FlowRuleProgrammable.java
@@ -0,0 +1,974 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.drivers.microsemi;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+import org.onlab.packet.EthType;
+import org.onlab.packet.EthType.EtherType;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
+import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
+import org.onosproject.drivers.microsemi.yang.UniSide;
+import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnic;
+import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnin;
+import org.onosproject.drivers.microsemi.yang.utils.CeVlanMapUtils;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleProgrammable;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanHeaderInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFilteringOpParam;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.DefaultSourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.SourceIpaddressFiltering;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.DefaultInterfaceEth0;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.InterfaceEth0;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.DefaultSourceAddressRange;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.FilterAdminStateEnum;
+import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.ServiceListType;
+import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.VlanIdType;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.DefaultMefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.MefServices;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.DefaultFlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagOverwrite;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPop;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPush;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagOverwrite;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPop;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPush;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.tagpush.tagpush.PushTagTypeEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Profiles;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Uni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.DefaultEvc;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.Evc;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.DefaultEvcPerUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.EvcPerUni;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnic;
+import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnin;
+import org.slf4j.Logger;
+
+/**
+ * An implementation of the FlowRuleProgrammable behaviour for the EA10000 device.
+ *
+ * This device is not a native Open Flow device. It has only a NETCONF interface for configuration
+ * status retrieval and notifications. It supports only a small subset of OpenFlow rules.<br>
+ *
+ * The device supports only:<br>
+ * 1) Open flow rules that blocks certain IP address ranges, but only those incoming on Port 0
+ * and has a limit of 10 such rules<br>
+ * 2) Open flow rules that PUSH, POP and OVERWRITE VLAN tags on both ports. This can push and overwrite
+ * both C-TAGs (0x8100) and S-TAGs (0x88a8).
+ */
+public class EA1000FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+ protected final Logger log = getLogger(getClass());
+ public static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
+ public static final int PRIORITY_DEFAULT = 50000;
+ //To protect the NETCONF session from concurrent access across flow addition and removal
+ static Semaphore sessionMutex = new Semaphore(1);
+
+ /**
+ * Get the flow entries that are present on the EA1000.
+ * Since the EA1000 does not have any 'real' flow entries these are retrieved from 2 configuration
+ * areas on the EA1000 NETCONF model - from SA filtering YANG model and from EVC UNI YANG model.<br>
+ * The flow entries must match exactly the FlowRule entries in the ONOS store. If they are not an
+ * exact match the device will be requested to remove those flows and the FlowRule will stay in a
+ * PENDING_ADD state.
+ * @return A collection of Flow Entries
+ */
+ @Override
+ public Collection<FlowEntry> getFlowEntries() {
+ Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+ UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+ NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+ NetconfDevice ncDevice = controller.getDevicesMap().get(handler().data().deviceId());
+ if (ncDevice == null) {
+ log.error("Internal ONOS Error. Device has been marked as reachable, " +
+ "but deviceID {} is not in Devices Map. Continuing with empty description",
+ handler().data().deviceId());
+ return flowEntryCollection;
+ }
+ NetconfSession session = ncDevice.getSession();
+ CoreService coreService = checkNotNull(handler().get(CoreService.class));
+ ApplicationId appId = coreService.getAppId(MICROSEMI_DRIVERS);
+ MseaSaFilteringNetconfService mseaSaFilteringService =
+ (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+ MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+ (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+ log.debug("getFlowEntries() called on EA1000FlowRuleProgrammable");
+
+ //First get the MseaSaFiltering rules
+ SourceIpaddressFiltering sip =
+ new DefaultSourceIpaddressFiltering();
+
+ MseaSaFilteringOpParam op =
+ new MseaSaFilteringOpParam();
+ op.sourceIpaddressFiltering(sip);
+
+ try {
+ MseaSaFiltering saFilteringCurrent =
+ mseaSaFilteringService.getMseaSaFiltering(op, session);
+ if (saFilteringCurrent != null &&
+ saFilteringCurrent.sourceIpaddressFiltering() != null) {
+ flowEntryCollection.addAll(
+ convertSaFilteringToFlowRules(saFilteringCurrent, appId));
+ }
+ } catch (NetconfException e) {
+ if (e.getCause() instanceof TimeoutException) {
+ log.warn("Timeout exception getting SA Filt Flow Entries from {}",
+ handler().data().deviceId());
+ return flowEntryCollection;
+ } else {
+ log.error("Unexpected error on SA Filt getFlowEntries on {}",
+ handler().data().deviceId(), e);
+ }
+ }
+
+
+ //Then get the EVCs - there will be a flow entry per EVC
+ MefServices mefServices = new DefaultMefServices();
+ mefServices.uni(new DefaultUni());
+
+ MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
+ mseaUniEvcServiceFilter.mefServices(mefServices);
+ try {
+ MseaUniEvcService uniEvcCurrent =
+ mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
+ session, DatastoreId.RUNNING);
+
+ flowEntryCollection.addAll(
+ convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
+
+ } catch (NetconfException e) {
+ if (e.getCause() instanceof TimeoutException) {
+ log.warn("Timeout exception getting EVC Flow Entries from {}",
+ handler().data().deviceId());
+ return flowEntryCollection;
+ } else {
+ log.error("Unexpected error on EVC getFlowEntries on {}",
+ handler().data().deviceId(), e);
+ }
+ }
+
+ return flowEntryCollection;
+ }
+
+ /**
+ * Apply the flow entries to the EA1000.
+ * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+ * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
+ * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
+ * will not be in the returned set.
+ *
+ * @param rules A collection of Flow Rules to be applied to the EA1000
+ * @return A collection of the Flow Rules that have been added.
+ */
+ @Override
+ public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+ Collection<FlowRule> frAdded = new HashSet<FlowRule>();
+ if (rules == null || rules.size() == 0) {
+ return rules;
+ }
+ NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+ NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+ MseaSaFilteringNetconfService mseaSaFilteringService =
+ (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+ MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+ (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+ log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
+ // FIXME: Change this so it's dynamically driven
+ UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+
+ List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+ Map<Integer, Evc> evcMap = new HashMap<>();
+
+ //Retrieve the list of actual EVCs and the CeVlanMaps from device
+ List<Evc> activeEvcs = new ArrayList<>();
+ try {
+ sessionMutex.acquire();
+ MseaUniEvcService evcResponse =
+ mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
+ //There could be zero or more EVCs
+ if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+ activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+ }
+ } catch (NetconfException | InterruptedException e1) {
+ log.warn("Unexpected error on applyFlowRules", e1);
+ }
+
+ for (FlowRule fr : rules) {
+
+ // IP SA Filtering can only apply to Port 0 optics
+ if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
+ fr.selector().getCriterion(Type.IN_PORT) != null &&
+ ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+ parseFrForSaRange(frAdded, saRangeList, fr);
+
+ // EVCs will be defined by Flow Rules relating to VIDs
+ } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
+ fr.selector().getCriterion(Type.IN_PORT) != null) {
+ //There could be many Flow Rules for one EVC depending on the ceVlanMap
+ //Cannot build up the EVC until we know the details - the key is the tableID and port
+ parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
+ } else {
+ log.info("Unexpected Flow Rule type applied: " + fr);
+ }
+ }
+
+ //If there are IPv4 Flow Rules created commit them now through the
+ //MseaSaFiltering service
+ if (saRangeList.size() > 0) {
+ try {
+ mseaSaFilteringService.setMseaSaFiltering(
+ buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
+ } catch (NetconfException e) {
+ log.error("Error applying Flow Rules to SA Filtering - will try again: " + e.getMessage());
+ sessionMutex.release();
+ return frAdded;
+ }
+ }
+ //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
+ if (evcMap.size() > 0) {
+ List<Evc> evcList = evcMap.entrySet().stream()
+ .map(x -> x.getValue())
+ .collect(Collectors.toList());
+ Uni uni = new DefaultUni();
+ URI deviceName = handler().data().deviceId().uri();
+ uni.name(new Identifier45("Uni-on-"
+ + deviceName.getSchemeSpecificPart()));
+ uni.evc(evcList);
+
+ List<BwpGroup> bwpGroupList = new ArrayList<BwpGroup>();
+ BwpGroup bwpGrp = new DefaultBwpGroup();
+ bwpGrp.groupIndex((short) 0);
+ bwpGroupList.add(bwpGrp);
+ Profiles profiles = new DefaultProfiles();
+ profiles.bwpGroup(bwpGroupList);
+
+ MefServices mefServices = new DefaultMefServices();
+ mefServices.uni(uni);
+ mefServices.profiles(profiles);
+
+ MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
+ mseaUniEvcServiceFilter.mefServices(mefServices);
+ try {
+ mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, DatastoreId.RUNNING);
+ } catch (NetconfException e) {
+ log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage());
+ sessionMutex.release();
+ return frAdded;
+ }
+ }
+ sessionMutex.release();
+ return frAdded;
+ }
+
+ /**
+ * Remove flow rules from the EA1000.
+ * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
+ * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
+ *
+ * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
+ * @return A collection of the Flow Rules that have been removed.
+ */
+ @Override
+ public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
+ NetconfController controller = checkNotNull(handler().get(NetconfController.class));
+ NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
+ MseaSaFilteringNetconfService mseaSaFilteringService =
+ (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
+ MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
+ (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
+ UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
+ log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
+
+ if (rulesToRemove.size() == 0) {
+ return rulesToRemove;
+ }
+
+ //Retrieve the list of actual EVCs and the CeVlanMaps from device
+ List<Evc> activeEvcs = new ArrayList<>();
+ List<Short> acvtiveFiltRanges = new ArrayList<>();
+ try {
+ sessionMutex.acquire();
+ MseaUniEvcService evcResponse =
+ mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
+ //There could be zero or more EVCs
+ if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
+ activeEvcs.addAll(evcResponse.mefServices().uni().evc());
+ }
+ mseaSaFilteringService.getConfigMseaSaFilterIds(session).forEach(
+ r -> acvtiveFiltRanges.add(r.rangeId()));
+
+ } catch (NetconfException | InterruptedException e1) {
+ log.warn("Error on removeFlowRules.", e1);
+ }
+
+ List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
+ Map<Integer, String> ceVlanMapMap = new HashMap<>();
+ Map<Integer, List<Short>> flowIdMap = new HashMap<>();
+
+ Collection<FlowRule> rulesRemoved = new HashSet<FlowRule>();
+ for (FlowRule ruleToRemove : rulesToRemove) {
+ // IP SA Filtering can only apply to Port 0 optics
+ if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
+ ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
+ ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
+ SourceAddressRange sar = new DefaultSourceAddressRange();
+ sar.rangeId((short) ruleToRemove.tableId());
+ acvtiveFiltRanges.remove(Short.valueOf((short) ruleToRemove.tableId()));
+ rulesRemoved.add(ruleToRemove);
+ saRangeList.add(sar);
+
+ } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
+ ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
+ PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
+ VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
+ int evcId = ruleToRemove.tableId();
+ int evcKey = (evcId << 2) + (int) portNumber.toLong();
+ String activeCeVlanMap = "";
+ //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
+ // from the ceVlanMap and not the whole EVC
+ if (!ceVlanMapMap.containsKey(evcKey)) {
+ for (Evc activeEvc:activeEvcs) {
+ if (activeEvc.evcIndex() == evcId) {
+ if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+ UniSide.CUSTOMER) {
+ activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
+ } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
+ UniSide.NETWORK) {
+ activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
+ }
+ }
+ }
+ }
+
+ ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
+ if (!flowIdMap.containsKey(evcKey)) {
+ flowIdMap.put(evcKey, new ArrayList<>());
+ }
+ flowIdMap.get(evcKey).add(vlanId.id());
+ rulesRemoved.add(ruleToRemove);
+
+ } else {
+ log.info("Unexpected Flow Rule type removal: " + ruleToRemove);
+ }
+ }
+
+ //If there are IPv4 Flow Rules created commit them now through the
+ //MseaSaFiltering service
+ if (saRangeList.size() > 0 && acvtiveFiltRanges.size() == 0) {
+ try {
+ SourceIpaddressFiltering saFilter =
+ new DefaultSourceIpaddressFiltering();
+ MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
+ mseaSaFiltering.sourceIpaddressFiltering(saFilter);
+
+ mseaSaFilteringService.deleteMseaSaFilteringRange(
+ mseaSaFiltering, session, DatastoreId.RUNNING);
+ } catch (NetconfException e) {
+ log.warn("Remove FlowRule on MseaSaFilteringService could not delete all SARules - "
+ + "they may already have been deleted: " + e.getMessage());
+ }
+ } else if (saRangeList.size() > 0) {
+ try {
+ mseaSaFilteringService.deleteMseaSaFilteringRange(
+ buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
+ } catch (NetconfException e) {
+ log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
+ + "it may already have been deleted: " + e.getMessage());
+ }
+ }
+
+ if (ceVlanMapMap.size() > 0) {
+ try {
+ mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
+ session, DatastoreId.RUNNING, portAssignment);
+ } catch (NetconfException e) {
+ log.warn("Remove FlowRule on MseaUniEvcService could not delete EVC - "
+ + "it may already have been deleted: " + e.getMessage());
+ }
+ }
+
+ sessionMutex.release();
+ return rulesRemoved;
+ }
+
+ /**
+ * An internal method for extracting one EVC from a list and returning its ceVlanMap.
+ *
+ * @param evcList - the list of known EVCs
+ * @param evcIndex - the index of the EVC we're looking for
+ * @param side - the side of the UNI
+ * @return - the CEVlanMap we're looking for
+ */
+ private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
+ if (evcList != null && evcList.size() > 0) {
+ for (Evc evc:evcList) {
+ if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
+ if (side == UniSide.CUSTOMER &&
+ evc.evcPerUni().evcPerUnic() != null &&
+ evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
+ return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
+ } else if (side == UniSide.NETWORK &&
+ evc.evcPerUni().evcPerUnin() != null &&
+ evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
+ return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
+ }
+ }
+ }
+ }
+
+ return ""; //The EVC required was not in the list
+ }
+
+ /**
+ * An internal method to convert from a FlowRule to SARange.
+ *
+ * @param frList A collection of flow rules
+ * @param saRangeList A list of SARanges
+ * @param fr A flow rule
+ */
+ private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
+ String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
+ log.debug("Applying IP address to " + ipAddrStr
+ + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
+
+ SourceAddressRange sar =
+ new DefaultSourceAddressRange();
+
+ sar.rangeId((short) fr.tableId());
+ sar.name("Flow:" + fr.id().toString());
+ sar.ipv4AddressPrefix(ipAddrStr);
+
+ frList.add(fr);
+ saRangeList.add(sar);
+ }
+
+ private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
+ List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
+ //There could be many Flow Rules for one EVC depending on the ceVlanMap
+ //Cannot build up the EVC until we know the details - the key is the tableID and port
+ Ea1000Port port = Ea1000Port.fromNum(
+ ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
+ Integer evcKey = (fr.tableId() << 2) + port.portNum();
+ VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
+ FlowMapping fm = new DefaultFlowMapping();
+ fm.ceVlanId(VlanIdType.of(sourceVid.id()));
+ fm.flowId(BigInteger.valueOf(fr.id().value()));
+
+ if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
+ //Replace ceVlanMap
+ if (port.nOrC(portAssignment) == UniSide.CUSTOMER) {
+ evcMap.get(evcKey).evcPerUni().evcPerUnic().addToFlowMapping(fm);
+ ServiceListType newCeVlanMap = new ServiceListType(
+ CeVlanMapUtils.addtoCeVlanMap(
+ evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap().toString(),
+ sourceVid.toShort()));
+ evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
+ } else {
+ evcMap.get(evcKey).evcPerUni().evcPerUnin().addToFlowMapping(fm);
+ ServiceListType newCeVlanMap = new ServiceListType(
+ CeVlanMapUtils.addtoCeVlanMap(
+ evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap().toString(),
+ sourceVid.toShort()));
+ evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
+ }
+ } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
+ TagManipulation tm = getTagManipulation(fr);
+ if (port.nOrC(portAssignment) == UniSide.NETWORK) {
+ ServiceListType newCeVlanMap = new ServiceListType(
+ CeVlanMapUtils.addtoCeVlanMap(
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap().toString(),
+ sourceVid.toShort()));
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().tagManipulation(tm);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().addToFlowMapping(fm);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ingressBwpGroupIndex(getMeterId(fr.treatment()));
+ } else {
+ ServiceListType newCeVlanMap = new ServiceListType(
+ CeVlanMapUtils.addtoCeVlanMap(
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap().toString(),
+ sourceVid.toShort()));
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().tagManipulation(tm);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().addToFlowMapping(fm);
+ evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ingressBwpGroupIndex(getMeterId(fr.treatment()));
+ }
+ } else {
+ Evc evc = new DefaultEvc();
+ EvcPerUnin epun = new CustomEvcPerUnin();
+ EvcPerUnic epuc = new CustomEvcPerUnic();
+ TagManipulation tm = getTagManipulation(fr);
+
+ UniSide side = port.nOrC(portAssignment);
+ String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
+ String newCeVlanMap =
+ CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
+ String oppositeCeVlanMap =
+ getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
+ port.opposite().nOrC(portAssignment));
+ oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
+ if (side == UniSide.NETWORK) {
+ epun.ceVlanMap(new ServiceListType(newCeVlanMap));
+ epun.tagManipulation(tm);
+ epun.addToFlowMapping(fm);
+ epun.ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+ epuc.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+ epuc.ingressBwpGroupIndex(new Long(0));
+ } else {
+ epuc.ceVlanMap(new ServiceListType(newCeVlanMap));
+ epuc.tagManipulation(tm);
+ epuc.addToFlowMapping(fm);
+ epuc.ingressBwpGroupIndex(getMeterId(fr.treatment()));
+
+ epun.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
+ epun.ingressBwpGroupIndex(new Long(0));
+ }
+
+ evc.evcIndex(fr.tableId());
+ evc.name(new Identifier45("EVC-" + String.valueOf(fr.tableId())));
+
+ DefaultEvcPerUni epu = new DefaultEvcPerUni();
+ epu.evcPerUnin(epun);
+ epu.evcPerUnic(epuc);
+ evc.evcPerUni(epu);
+
+ evcMap.put(evcKey, evc);
+ }
+
+ frList.add(fr);
+ }
+
+
+ private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
+ InterfaceEth0 saIf = new DefaultInterfaceEth0();
+ for (SourceAddressRange sa:saRangeList) {
+ saIf.addToSourceAddressRange(sa);
+ }
+ saIf.filterAdminState(FilterAdminStateEnum.BLACKLIST);
+
+ SourceIpaddressFiltering saFilter =
+ new DefaultSourceIpaddressFiltering();
+ saFilter.interfaceEth0(saIf);
+
+ MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
+ mseaSaFiltering.sourceIpaddressFiltering(saFilter);
+
+ return mseaSaFiltering;
+ }
+
+ private Collection<FlowEntry> convertSaFilteringToFlowRules(
+ MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
+ Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+ List<SourceAddressRange> saRangelist =
+ saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
+ Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
+ TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+ if (saRangelist != null) {
+ for (SourceAddressRange sa : saRangelist) {
+ Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
+
+ TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
+
+ TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+ TrafficTreatment treatment = trBuilder.drop().build();
+
+ FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
+ if (sa.name() != null && sa.name().startsWith("Flow:")) {
+ String[] nameParts = sa.name().split(":");
+ Long cookie = Long.valueOf(nameParts[1], 16);
+ feBuilder = feBuilder.withCookie(cookie);
+ } else {
+ feBuilder = feBuilder.fromApp(appId);
+ }
+
+ FlowRule fr = feBuilder
+ .forDevice(handler().data().deviceId())
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .forTable(sa.rangeId())
+ .makePermanent()
+ .withPriority(PRIORITY_DEFAULT)
+ .build();
+
+ flowEntryCollection.add(
+ new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
+ }
+ }
+ return flowEntryCollection;
+ }
+
+
+ private Collection<FlowEntry> convertEvcUniToFlowRules(
+ MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
+ Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
+
+ if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
+ uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
+ log.info("No EVC's found when getting flow rules");
+ return flowEntryCollection;
+ }
+
+ for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
+ FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
+ TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
+
+ TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
+ //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+ Short[] vlanIdsUniN =
+ CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
+ for (Short vlanId:vlanIdsUniN) {
+ if (vlanId == 0) {
+ continue;
+ }
+ Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
+ TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
+ long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
+
+ FlowRule frUniN = frBuilder
+ .forDevice(handler().data().deviceId())
+ .withSelector(tsUniN)
+ .withTreatment(uniNTreatment)
+ .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+ .makePermanent()
+ .withPriority(PRIORITY_DEFAULT)
+ .withCookie(flowId)
+ .build();
+ flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
+ }
+
+ TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
+ //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
+ Short[] vlanIdsUniC =
+ CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
+ if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
+ for (Short vlanId:vlanIdsUniC) {
+ if (vlanId == 0) {
+ continue;
+ }
+ Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
+ TrafficSelector tsUniC =
+ tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
+ long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
+
+ FlowRule frUniC = frBuilder
+ .forDevice(handler().data().deviceId())
+ .withSelector(tsUniC)
+ .withTreatment(uniCTreatment)
+ .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
+ .makePermanent()
+ .withPriority(PRIORITY_DEFAULT)
+ .withCookie(flowId)
+ .build();
+ flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
+ }
+ }
+ }
+
+ return flowEntryCollection;
+ }
+
+ private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
+ if (fmList == null || vlanId == null) {
+ log.warn("Flow Mapping list is null when reading EVCs");
+ return -1L;
+ }
+ for (FlowMapping fm:fmList) {
+ if (fm.ceVlanId().uint16() == vlanId.intValue()) {
+ return fm.flowId().longValue();
+ }
+ }
+ return 0L;
+ }
+
+ private String ceVlanMapForUniSide(
+ EvcPerUni evcPerUni, boolean portN) {
+ if (portN) {
+ return evcPerUni.evcPerUnin().ceVlanMap().string();
+ } else {
+ return evcPerUni.evcPerUnic().ceVlanMap().string();
+ }
+ }
+
+ private Criterion criterionPortForUniSide(
+ UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
+ boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
+ int portNum = ((cOnOptics && portN) || (!cOnOptics && !portN)) ? 1 : 0;
+ return Criteria.matchInPort(PortNumber.portNumber(portNum));
+ }
+
+ private TrafficTreatment treatmentForUniSde(
+ EvcPerUni evcPerUni, boolean portN) {
+ TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
+
+ TagManipulation tm = null;
+ short meterId = 0;
+ if (portN) {
+ tm = evcPerUni.evcPerUnin().tagManipulation();
+ meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
+ } else {
+ tm = evcPerUni.evcPerUnic().tagManipulation();
+ meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
+ }
+
+ if (meterId > 0L) {
+ trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
+// trBuilder = trBuilder.meter(MeterId.meterId(meterId)).transition(0);
+ }
+
+ if (tm == null) {
+ return trBuilder.build(); //no tag manipulation found
+ }
+
+ if (tm.getClass().equals(DefaultTagPush.class)) {
+ VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
+ PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
+ //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
+ // to be an exactMatch. See DefaultFlowRule.exactMatch()
+ trBuilder = trBuilder
+ .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
+ EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
+ .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
+
+ } else if (tm.getClass().equals(DefaultTagPop.class)) {
+ trBuilder = trBuilder.popVlan();
+
+ } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
+ TagOverwrite to = (TagOverwrite) tm;
+ VlanId ovrVlanNum = VlanId
+ .vlanId((short) (
+ //There are 2 classes TagOverwrite - the other one is already imported
+ to
+ .tagOverwrite()
+ .outerTagVlan()
+ .uint16()));
+ trBuilder = trBuilder.setVlanId(ovrVlanNum);
+
+ }
+
+ return trBuilder.build();
+ }
+
+ private static TagManipulation getTagManipulation(FlowRule fr) {
+ boolean isPop = false;
+ boolean isPush = false;
+ VlanId vlanId = null;
+ EthType ethType = EtherType.VLAN.ethType(); //Default
+ for (Instruction inst:fr.treatment().allInstructions()) {
+ if (inst.type() == Instruction.Type.L2MODIFICATION) {
+ L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
+ if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
+ isPop = true;
+ } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+ isPush = true;
+ ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
+ } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
+ vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
+ }
+ }
+ }
+
+ if (isPop) {
+ //The should be no vlanId in this case
+ TagPop pop = new DefaultTagPop();
+ org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+ .evcperuniextensionattributes.tagmanipulation
+ .tagpop.TagPop popInner =
+ new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+ .mseaunievcservice.evcperuniextensionattributes
+ .tagmanipulation.tagpop.DefaultTagPop();
+ pop.tagPop(popInner);
+ return pop;
+
+ } else if (isPush && vlanId != null) {
+ TagPush push = new DefaultTagPush();
+ org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+ .evcperuniextensionattributes.tagmanipulation
+ .tagpush.TagPush pushInner =
+ new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+ .mseaunievcservice.evcperuniextensionattributes
+ .tagmanipulation.tagpush.DefaultTagPush();
+ pushInner.outerTagVlan(new VlanIdType(vlanId.id()));
+ pushInner.pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
+ PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG);
+ push.tagPush(pushInner);
+ return push;
+
+ } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
+ TagOverwrite ovr = new DefaultTagOverwrite();
+ org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
+ .evcperuniextensionattributes.tagmanipulation
+ .tagoverwrite.TagOverwrite ovrInner =
+ new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
+ .mseaunievcservice.evcperuniextensionattributes
+ .tagmanipulation.tagoverwrite.DefaultTagOverwrite();
+ ovrInner.outerTagVlan(new VlanIdType(vlanId.id()));
+ ovr.tagOverwrite(ovrInner);
+ return ovr;
+ }
+
+ return null;
+ }
+
+ private static long getMeterId(TrafficTreatment treatment) {
+ return (treatment.metered() != null && treatment.metered().meterId() != null)
+ ? treatment.metered().meterId().id() : 0L;
+ }
+
+ /**
+ * An enumerated type that characterises the 2 port layout of the EA1000 device.
+ * The device is in an SFP package and has only 2 ports, the HOST port which
+ * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
+ */
+ public enum Ea1000Port {
+ HOST(1),
+ OPTICS(0);
+
+ private int num = 0;
+ private Ea1000Port(int num) {
+ this.num = num;
+ }
+
+ /**
+ * The numerical assignment of this port.
+ * @return The port number
+ */
+ public int portNum() {
+ return num;
+ }
+
+ /**
+ * Return the enumerated value from a port number.
+ * @param num The port number
+ * @return An enumerated value
+ */
+ public static Ea1000Port fromNum(long num) {
+ for (Ea1000Port a:Ea1000Port.values()) {
+ if (a.num == num) {
+ return a;
+ }
+ }
+ return HOST;
+ }
+
+ /**
+ * Get the port that the UNI-N is present on.
+ * @param side The assignment of UNI-side to port
+ * @return An enumerated value
+ */
+ public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
+ if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+ return OPTICS;
+ } else {
+ return HOST;
+ }
+ }
+
+ /**
+ * Get the port that the UNI-C is present on.
+ * @param side The assignment of UNI-side to port
+ * @return An enumerated value
+ */
+ public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
+ if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
+ return HOST;
+ } else {
+ return OPTICS;
+ }
+ }
+
+ /**
+ * Get the port opposite the current port.
+ * @return An enumerated value for the opposite side
+ */
+ public Ea1000Port opposite() {
+ if (this.equals(HOST)) {
+ return OPTICS;
+ } else {
+ return HOST;
+ }
+ }
+
+ /**
+ * Evaluate which side of the UNI on the EA1000 device this port refers to.
+ * @param side The assignment of UNI-side to port
+ * @return An enumerated value representing the UniSide
+ */
+ public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
+ if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
+ (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
+ return UniSide.CUSTOMER;
+ } else {
+ return UniSide.NETWORK;
+ }
+ }
+ }
+}