X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=vpnservice%2Felanmanager%2Felanmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Felan%2Futils%2FElanUtils.java;h=40e107ce69396ed597dbc4f1157ed087596d5736;hb=refs%2Fchanges%2F80%2F65880%2F14;hp=ba55cf6e3bb9340c475e2277cd3611217c393f97;hpb=3dc5b44adc72819d759cd8c5194c65d2bfd518f4;p=netvirt.git diff --git a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java old mode 100644 new mode 100755 index ba55cf6e3b..40e107ce69 --- a/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java +++ b/vpnservice/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -8,61 +8,80 @@ package org.opendaylight.netvirt.elan.utils; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.primitives.Ints; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.genius.interfacemanager.globals.IfmConstants; import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo; import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.itm.globals.ITMConstants; +import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.FlowEntity; +import org.opendaylight.genius.mdsalutil.FlowEntityBuilder; import org.opendaylight.genius.mdsalutil.InstructionInfo; -import org.opendaylight.genius.mdsalutil.InstructionType; import org.opendaylight.genius.mdsalutil.MDSALUtil; -import org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp; -import org.opendaylight.genius.mdsalutil.MatchFieldType; import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.MetaDataUtil; +import org.opendaylight.genius.mdsalutil.NWUtil; import org.opendaylight.genius.mdsalutil.NwConstants; +import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit; +import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions; +import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; -import org.opendaylight.genius.utils.ServiceIndex; +import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination; +import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource; +import org.opendaylight.genius.mdsalutil.matches.MatchMetadata; +import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; +import org.opendaylight.genius.mdsalutil.packet.ARP; +import org.opendaylight.genius.mdsalutil.packet.Ethernet; +import org.opendaylight.genius.mdsalutil.packet.IPv4; +import org.opendaylight.infrautils.utils.concurrent.JdkFutures; import org.opendaylight.netvirt.elan.ElanException; -import org.opendaylight.netvirt.elan.internal.ElanBridgeManager; -import org.opendaylight.netvirt.elan.internal.ElanInstanceManager; -import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager; -import org.opendaylight.netvirt.elan.internal.ElanServiceProvider; -import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils; -import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils; -import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil; +import org.opendaylight.netvirt.elanmanager.api.ElanHelper; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; @@ -73,11 +92,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406. import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput; @@ -93,24 +111,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface; @@ -139,9 +150,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey; @@ -158,22 +172,24 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@Singleton public class ElanUtils { private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class); private static Map elanInstanceLocalCache = new ConcurrentHashMap<>(); private static Map elanInterfaceLocalCache = new ConcurrentHashMap<>(); + private static Map> elanInstancToDpnsCache = new ConcurrentHashMap<>(); + private static Map> elanInstanceToInterfacesCache = new ConcurrentHashMap<>(); private final DataBroker broker; private final IMdsalApiManager mdsalManager; - private final ElanInstanceManager elanInstanceManager; private final OdlInterfaceRpcService interfaceManagerRpcService; private final ItmRpcService itmRpcService; - private ElanL2GatewayUtils elanL2GatewayUtils; - private ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils; - private L2GatewayConnectionUtils l2GatewayConnectionUtils; - private ElanBridgeManager bridgeManager; + private final IInterfaceManager interfaceManager; + private final ElanConfig elanConfig; + private final ElanItmUtils elanItmUtils; + private final ElanEtreeUtils elanEtreeUtils; public static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @Override @@ -187,35 +203,23 @@ public class ElanUtils { } }; - public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanInstanceManager elanInstanceManager, - OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, - ElanInterfaceManager elanInterfaceManager, - EntityOwnershipService entityOwnershipService, ElanBridgeManager bridgeManager) { + @Inject + public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, + OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, ElanConfig elanConfig, + IInterfaceManager interfaceManager, ElanEtreeUtils elanEtreeUtils, ElanItmUtils elanItmUtils) { this.broker = dataBroker; this.mdsalManager = mdsalManager; - this.elanInstanceManager = elanInstanceManager; this.interfaceManagerRpcService = interfaceManagerRpcService; this.itmRpcService = itmRpcService; - this.bridgeManager = bridgeManager; - - elanL2GatewayMulticastUtils = - new ElanL2GatewayMulticastUtils(broker, elanInstanceManager, elanInterfaceManager, this); - elanL2GatewayUtils = new ElanL2GatewayUtils(broker, itmRpcService, this, - entityOwnershipService, elanL2GatewayMulticastUtils); - l2GatewayConnectionUtils = new L2GatewayConnectionUtils(broker, - elanInstanceManager, entityOwnershipService, this); - } - - public ElanL2GatewayUtils getElanL2GatewayUtils() { - return elanL2GatewayUtils; - } - - public ElanL2GatewayMulticastUtils getElanL2GatewayMulticastUtils() { - return elanL2GatewayMulticastUtils; + this.interfaceManager = interfaceManager; + this.elanConfig = elanConfig; + this.elanEtreeUtils = elanEtreeUtils; + this.elanItmUtils = elanItmUtils; } - public L2GatewayConnectionUtils getL2GatewayConnectionUtils() { - return l2GatewayConnectionUtils; + public final Boolean isOpenstackVniSemanticsEnforced() { + return elanConfig.isOpenstackVniSemanticsEnforced() != null + ? elanConfig.isOpenstackVniSemanticsEnforced() : false; } public static void addElanInstanceIntoCache(String elanInstanceName, ElanInstance elanInstance) { @@ -230,6 +234,10 @@ public class ElanUtils { return elanInstanceLocalCache.get(elanInstanceName); } + public static Set getAllElanNames() { + return elanInstanceLocalCache.keySet(); + } + public static void addElanInterfaceIntoCache(String interfaceName, ElanInterface elanInterface) { elanInterfaceLocalCache.put(interfaceName, elanInterface); } @@ -260,7 +268,7 @@ public class ElanUtils { Future> result = idManager.allocateId(getIdInput); RpcResult rpcResult = result.get(); if (rpcResult.isSuccessful()) { - return rpcResult.getResult().getIdValue().longValue(); + return rpcResult.getResult().getIdValue(); } else { LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors()); } @@ -272,7 +280,7 @@ public class ElanUtils { public static void releaseId(IdManagerService idManager, String poolName, String idKey) { ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build(); - Future> result = idManager.releaseId(releaseIdInput); + JdkFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id"); } /** @@ -283,31 +291,20 @@ public class ElanUtils { */ @Deprecated @SuppressWarnings("checkstyle:IllegalCatch") - public Optional read(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - ReadOnlyTransaction tx = broker != null ? broker.newReadOnlyTransaction() - : this.broker.newReadOnlyTransaction(); - Optional result = Optional.absent(); - try { - CheckedFuture, ReadFailedException> checkedFuture = tx.read(datastoreType, path); - result = checkedFuture.get(); + public static Optional read(@Nonnull DataBroker broker, + LogicalDatastoreType datastoreType, InstanceIdentifier path) { + try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) { + return tx.read(datastoreType, path).get(); } catch (Exception e) { throw new RuntimeException(e); - } finally { - tx.close(); } - - return result; } public Optional read2(LogicalDatastoreType datastoreType, InstanceIdentifier path) throws ReadFailedException { - ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); - try { + try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) { CheckedFuture, ReadFailedException> checkedFuture = tx.read(datastoreType, path); return checkedFuture.checkedGet(); - } finally { - tx.close(); } } @@ -315,14 +312,14 @@ public class ElanUtils { InstanceIdentifier path) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), DEFAULT_CALLBACK); + Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor()); } public static void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier path, FutureCallback callback) { WriteTransaction tx = broker.newWriteOnlyTransaction(); tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), callback); + Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor()); } public static InstanceIdentifier getElanInstanceIdentifier() { @@ -330,23 +327,15 @@ public class ElanUtils { } // elan-instances config container + @Nullable public static ElanInstance getElanInstanceByName(DataBroker broker, String elanInstanceName) { ElanInstance elanObj = getElanInstanceFromCache(elanInstanceName); if (elanObj != null) { return elanObj; } - InstanceIdentifier elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName); - Optional elanInstance = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, - elanIdentifierId); - if (elanInstance.isPresent()) { - return elanInstance.get(); - } - return null; - } - - public static InstanceIdentifier getElanInstanceConfigurationDataPath(String elanInstanceName) { - return InstanceIdentifier.builder(ElanInstances.class) - .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build(); + InstanceIdentifier elanIdentifierId = + ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName); + return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull(); } // elan-interfaces Config Container @@ -356,17 +345,16 @@ public class ElanUtils { return elanInterfaceObj; } InstanceIdentifier elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName); - Optional existingElanInterface = MDSALUtil.read(broker, - LogicalDatastoreType.CONFIGURATION, elanInterfaceId); - if (existingElanInterface.isPresent()) { - return existingElanInterface.get(); - } - return null; + return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId).orNull(); } public static EtreeInterface getEtreeInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) { ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(broker, elanInterfaceName); - return elanInterface.getAugmentation(EtreeInterface.class); + if (elanInterface == null) { + return null; + } else { + return elanInterface.getAugmentation(EtreeInterface.class); + } } public static InstanceIdentifier getElanInterfaceConfigurationDataPathId(String interfaceName) { @@ -377,12 +365,7 @@ public class ElanUtils { // elan-state Operational container public static Elan getElanByName(DataBroker broker, String elanInstanceName) { InstanceIdentifier elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName); - Optional elanInstance = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, - elanIdentifier); - if (elanInstance.isPresent()) { - return elanInstance.get(); - } - return null; + return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull(); } public static InstanceIdentifier getElanInstanceOperationalDataPath(String elanInstanceName) { @@ -393,21 +376,13 @@ public class ElanUtils { public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) { InstanceIdentifier existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath( interfaceName, physAddress); - Optional existingInterfaceMacEntry = read(broker, - LogicalDatastoreType.OPERATIONAL, existingMacEntryId); - if (existingInterfaceMacEntry.isPresent()) { - return existingInterfaceMacEntry.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull(); } public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) { Optional existingInterfaceMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, identifier); - if (existingInterfaceMacEntry.isPresent()) { - return existingInterfaceMacEntry.get(); - } - return null; + return existingInterfaceMacEntry.orNull(); } public static InstanceIdentifier getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName, @@ -419,23 +394,15 @@ public class ElanUtils { } // elan-forwarding-tables Operational container - public MacEntry getMacTableByElanName(String elanName, PhysAddress physAddress) { + public Optional getMacEntryForElanInstance(String elanName, PhysAddress physAddress) { InstanceIdentifier macId = getMacEntryOperationalDataPath(elanName, physAddress); - Optional existingElanMacEntry = read(broker, - LogicalDatastoreType.OPERATIONAL, macId); - if (existingElanMacEntry.isPresent()) { - return existingElanMacEntry.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, macId); } public MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) { Optional existingInterfaceMacEntry = read(broker, LogicalDatastoreType.OPERATIONAL, identifier); - if (existingInterfaceMacEntry.isPresent()) { - return existingInterfaceMacEntry.get(); - } - return null; + return existingInterfaceMacEntry.orNull(); } public static InstanceIdentifier getMacEntryOperationalDataPath(String elanName, @@ -451,14 +418,14 @@ public class ElanUtils { // elan-interface-forwarding-entries Operational container public ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) { + return getElanInterfaceMacByInterfaceName(broker, interfaceName); + } + + @Nullable + public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) { InstanceIdentifier elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath( interfaceName); - Optional existingElanInterface = read(broker, - LogicalDatastoreType.OPERATIONAL, elanInterfaceId); - if (existingElanInterface.isPresent()) { - return existingElanInterface.get(); - } - return null; + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull(); } /** @@ -499,12 +466,7 @@ public class ElanUtils { public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) { InstanceIdentifier elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId); - Optional elanDpnInterfaces = read(broker, - LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId); - if (elanDpnInterfaces.isPresent()) { - return elanDpnInterfaces.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull(); } /** @@ -530,22 +492,7 @@ public class ElanUtils { InstanceIdentifier elanId = getElanInfoEntriesOperationalDataPath(elanTag); Optional existingElanInfo = read(broker, LogicalDatastoreType.OPERATIONAL, elanId); - if (existingElanInfo.isPresent()) { - return existingElanInfo.get(); - } - return null; - } - - public EtreeLeafTagName getEtreeLeafTagByElanTag(long elanTag) { - InstanceIdentifier elanId = getElanInfoEntriesOperationalDataPath(elanTag); - Optional existingElanInfo = read(broker, - LogicalDatastoreType.OPERATIONAL, elanId); - if (existingElanInfo.isPresent()) { - ElanTagName elanTagName = existingElanInfo.get(); - EtreeLeafTagName etreeAugmentation = elanTagName.getAugmentation(EtreeLeafTagName.class); - return etreeAugmentation; - } - return null; + return existingElanInfo.orNull(); } public static InstanceIdentifier getElanInfoEntriesOperationalDataPath(long elanTag) { @@ -571,23 +518,13 @@ public class ElanUtils { public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) { InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanName); - Optional existingElanDpnInterfaces = read(broker, - LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); - if (existingElanDpnInterfaces.isPresent()) { - return existingElanDpnInterfaces.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull(); } public ElanDpnInterfaces getElanDpnInterfacesList() { InstanceIdentifier elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class) .build(); - Optional existingElanDpnInterfaces = read(broker, - LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); - if (existingElanDpnInterfaces.isPresent()) { - return existingElanDpnInterfaces.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull(); } /** @@ -599,7 +536,8 @@ public class ElanUtils { * the elan instance name * @return list of dpIds */ - public List getParticipatingDPNsInElanInstance(String elanInstanceName) { + @Nonnull + public List getParticipatingDpnsInElanInstance(String elanInstanceName) { List dpIds = new ArrayList<>(); InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName); Optional existingElanDpnInterfaces = read(broker, @@ -626,32 +564,29 @@ public class ElanUtils { * @return true if dpId is already present, otherwise return false */ public boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) { - boolean isDpIdPresent = false; InstanceIdentifier elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName); Optional existingElanDpnInterfaces = read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId); if (!existingElanDpnInterfaces.isPresent()) { - return isDpIdPresent; + return false; } List dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces(); for (DpnInterfaces dpnInterface : dpnInterfaces) { if (dpnInterface.getDpId().equals(dpId)) { - isDpIdPresent = true; - break; + return true; } } - return isDpIdPresent; + return false; } public ElanForwardingTables getElanForwardingList() { InstanceIdentifier elanForwardingTableId = InstanceIdentifier .builder(ElanForwardingTables.class).build(); - Optional existingElanForwardingList = read(broker, - LogicalDatastoreType.OPERATIONAL, elanForwardingTableId); - if (existingElanForwardingList.isPresent()) { - return existingElanForwardingList.get(); - } - return null; + return read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId).orNull(); + } + + public static long getElanRemoteBroadCastGroupID(long elanTag) { + return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2; } /** @@ -662,13 +597,13 @@ public class ElanUtils { * @return the elan mac table */ public MacTable getElanMacTable(String elanName) { + return getElanMacTable(broker, elanName); + } + + @Nullable + public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) { InstanceIdentifier elanMacTableId = getElanMacTableOperationalDataPath(elanName); - Optional existingElanMacTable = read(broker, - LogicalDatastoreType.OPERATIONAL, elanMacTableId); - if (existingElanMacTable.isPresent()) { - return existingElanMacTable.get(); - } - return null; + return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull(); } public static long getElanLocalBCGId(long elanTag) { @@ -687,25 +622,13 @@ public class ElanUtils { return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2; } - public static BigInteger getElanMetadataLabel(long elanTag) { - return BigInteger.valueOf(elanTag).shiftLeft(24); - } - public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) { int shBit = isSHFlagSet ? 1 : 0; return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit)); } - public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) { - return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag)); - } - - public static BigInteger getElanMetadataMask() { - return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG); - } - /** - * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs. + * Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs. * * @param elanInfo * the elan info @@ -721,43 +644,25 @@ public class ElanUtils { * the flow group tx * @throws ElanException in case of issues creating the flow objects */ - public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, - String macAddress, boolean configureRemoteFlows, WriteTransaction writeFlowGroupTx) throws ElanException { - synchronized (macAddress) { - LOG.debug("Acquired lock for mac : " + macAddress + ". Proceeding with install operation."); + public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, + long macTimeout, String macAddress, boolean configureRemoteFlows, + WriteTransaction writeFlowGroupTx) throws ElanException { + synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager, - writeFlowGroupTx); + writeFlowGroupTx); setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager, - broker, writeFlowGroupTx); + broker, writeFlowGroupTx); } } - /** - * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and on other DPNs. - * - * @param elanInfo - * the elan info - * @param interfaceInfo - * the interface info - * @param macTimeout - * the mac timeout - * @param macAddress - * the mac address - * @param writeFlowGroupTx - * the flow group tx - * @throws ElanException in case of issues creating the flow objects - */ - public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, - String macAddress, WriteTransaction writeFlowGroupTx) throws ElanException { - setupMacFlows(elanInfo, interfaceInfo, macTimeout, macAddress, true, writeFlowGroupTx); - } - - public void setupDMacFlowonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, - String macAddress, WriteTransaction writeFlowTx) throws ElanException { - synchronized (macAddress) { - LOG.debug("Acquired lock for mac : " + macAddress + ". Proceeding with install operation."); - setupOrigDmacFlowsonRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, writeFlowTx); - } + public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, + String macAddress, WriteTransaction writeFlowTx) throws ElanException { + String elanInstanceName = elanInfo.getElanInstanceName(); + setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(), + macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo); + LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and" + + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), + macAddress, dstDpId); } /** @@ -768,10 +673,8 @@ public class ElanUtils { String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) { FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress); mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx); - if (LOG.isDebugEnabled()) { - LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}", - elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress); - } + LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}", + elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress); } public FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, @@ -779,25 +682,28 @@ public class ElanUtils { int lportTag = interfaceInfo.getInterfaceTag(); // Matching metadata and eth_src fields List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { - getElanMetadataLabel(elanInfo.getElanTag(), lportTag), getElanMetadataMask() })); - mkMatches.add(new MatchInfo(MatchFieldType.eth_src, new String[] { macAddress })); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag), + ElanHelper.getElanMetadataMask())); + mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); - mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.ELAN_DMAC_TABLE })); - + mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE)); BigInteger dpId = interfaceInfo.getDpId(); long elanTag = getElanTag(broker, elanInfo, interfaceInfo); - FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_SMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag), 20, - elanInfo.getDescription(), (int) macTimeout, 0, - ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - flowEntity.setStrictFlag(true); - flowEntity.setSendFlowRemFlag(macTimeout != 0); // If Mac timeout is 0, - // the flow wont be - // deleted - // automatically, so no - // need to get notified - return flowEntity; + return new FlowEntityBuilder() + .setDpnId(dpId) + .setTableId(NwConstants.ELAN_SMAC_TABLE) + .setFlowId(getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag)) + .setPriority(20) + .setFlowName(elanInfo.getDescription()) + .setIdleTimeOut((int) macTimeout) + .setHardTimeOut(0) + .setCookie(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag))) + .setMatchInfoList(mkMatches) + .setInstructionInfoList(mkInstructions) + .setStrictFlag(true) + // If Mac timeout is 0, the flow won't be deleted automatically, so no need to get notified + .setSendFlowRemFlag(macTimeout != 0) + .build(); } private static Long getElanTag(DataBroker broker, ElanInstance elanInfo, InterfaceInfo interfaceInfo) { @@ -807,8 +713,8 @@ public class ElanUtils { } else { // Leaf EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class); if (etreeInstance == null) { - LOG.warn("EtreeInterface " + interfaceInfo.getInterfaceName() + " is connected to a non-Etree network: " - + elanInfo.getElanInstanceName()); + LOG.warn("EtreeInterface {} is connected to a non-Etree network: {}", + interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName()); return elanInfo.getElanTag(); } else { return etreeInstance.getEtreeLeafTagVal().getValue(); @@ -829,7 +735,7 @@ public class ElanUtils { * the writeFLowGroup tx */ public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager, - WriteTransaction writeFlowGroupTx) { + WriteTransaction writeFlowGroupTx) { BigInteger dpId = interfaceInfo.getDpId(); int lportTag = interfaceInfo.getInterfaceTag(); Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, @@ -839,10 +745,8 @@ public class ElanUtils { getTunnelIdMatchForFilterEqualsLPortTag(lportTag), getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName())); mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx); - if (LOG.isDebugEnabled()) { - LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId, - interfaceInfo.getPortName()); - } + LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId, + interfaceInfo.getPortName()); } /** @@ -870,7 +774,7 @@ public class ElanUtils { public static List getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) { List mkMatches = new ArrayList<>(); // Matching metadata - mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(lportTag) })); + mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag))); return mkMatches; } @@ -905,6 +809,7 @@ public class ElanUtils { * the tunnel key * @return the egress actions for interface */ + @SuppressWarnings("checkstyle:IllegalCatch") public List getEgressActionsForInterface(String ifName, Long tunnelKey) { List listAction = new ArrayList<>(); try { @@ -914,13 +819,13 @@ public class ElanUtils { .getEgressActionsForInterface(getEgressActionInput); RpcResult rpcResult = result.get(); if (!rpcResult.isSuccessful()) { - LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, + LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors()); } else { List actions = rpcResult.getResult().getAction(); listAction = actions; } - } catch (InterruptedException | ExecutionException e) { + } catch (Exception e) { LOG.warn("Exception when egress actions for interface {}", ifName, e); } return listAction; @@ -935,9 +840,9 @@ public class ElanUtils { long ifTag = interfaceInfo.getInterfaceTag(); String elanInstanceName = elanInfo.getElanInstanceName(); - Long elanTag = getElanTag(broker, elanInfo, interfaceInfo); + Long elanTag = elanInfo.getElanTag(); - setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInstanceName, mdsalApiManager, ifTag, + setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag, writeFlowGroupTx); LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} mand mac address:{} " + "on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId); @@ -947,10 +852,6 @@ public class ElanUtils { } List elanDpns = getInvolvedDpnsInElan(elanInstanceName); - if (elanDpns == null) { - return; - } - for (DpnInterfaces elanDpn : elanDpns) { if (elanDpn.getDpId().equals(dpId)) { @@ -962,72 +863,54 @@ public class ElanUtils { continue; } - // For remote DPNs a flow is needed to indicate that - // packets of this ELAN going to this MAC - // need to be forwarded through the appropiated ITM - // tunnel + // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC need to be + // forwarded through the appropriate ITM tunnel setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the remote DPN in this case) dpId, // dstDpn (the local DPN) interfaceInfo.getInterfaceTag(), // lportTag of the local interface - elanTag, // identifier of the Elan + elanTag, // identifier of the Elan macAddress, // MAC to be programmed in remote DPN - elanInstanceName, writeFlowGroupTx, ifName, elanInfo); - LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on" + elanInstanceName, writeFlowGroupTx, ifName, elanInfo + ); + LOG.debug("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on" + " dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId()); } // TODO: Make sure that the same is performed against the ElanDevices. } - private void setupOrigDmacFlowsonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, - BigInteger dstDpId, String macAddress, WriteTransaction writeFlowTx) throws ElanException { - BigInteger dpId = interfaceInfo.getDpId(); - String elanInstanceName = elanInfo.getElanInstanceName(); - List remoteFEs = getInvolvedDpnsInElan(elanInstanceName); - for (DpnInterfaces remoteFE : remoteFEs) { - Long elanTag = elanInfo.getElanTag(); - if (remoteFE.getDpId().equals(dstDpId)) { - // Check for the Remote DPN present in Inventory Manager - setupRemoteDmacFlow(dstDpId, dpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress, - elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo); - if (LOG.isDebugEnabled()) { - LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address {} on" - + " dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, remoteFE.getDpId()); - } - break; - } - } + @Nonnull + public List getInvolvedDpnsInElan(String elanName) { + return getElanDPNByName(elanName); } - @SuppressWarnings("unchecked") - public List getInvolvedDpnsInElan(String elanName) { - List dpns = elanInstanceManager.getElanDPNByName(elanName); - if (dpns == null) { - return Collections.emptyList(); - } - return dpns; + @Nonnull + public List getElanDPNByName(String elanInstanceName) { + InstanceIdentifier elanIdentifier = getElanDpnOperationDataPath(elanInstanceName); + return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map( + ElanDpnInterfacesList::getDpnInterfaces).orElse(Collections.emptyList()); } private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, - String displayName, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) { - Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, displayName, ifTag); + ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) { + Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag); mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx); - installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, displayName, mdsalApiManager, ifTag, - writeFlowGroupTx); + installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, + mdsalApiManager, ifTag, writeFlowGroupTx); } private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress, - String displayName, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) { + ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) { EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, ifName); if (etreeInterface != null) { if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeTagName == null) { - LOG.warn("Interface " + ifName + " seems like it belongs to Etree but etreeTagName from elanTag " - + elanTag + " is null."); + LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null", + ifName, elanTag); } else { Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName, - macAddress, displayName, ifTag); + macAddress, elanInfo, ifTag); mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx); } } @@ -1046,7 +929,11 @@ public class ElanUtils { .toString(); } - private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId, + public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, String macAddress, long elanTag) { + return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(macAddress).toString(); + } + + public static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId, String dstMacAddress, long elanTag, boolean shFlag) { return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId).append(extDeviceNodeId) .append(dstMacAddress).append(shFlag).toString(); @@ -1068,52 +955,64 @@ public class ElanUtils { * the if name * @param macAddress * the mac address - * @param displayName - * the display name + * @param elanInfo + * the elan info * @param ifTag * the if tag * @return the flow */ public Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress, - String displayName, long ifTag) { + ElanInstance elanInfo, long ifTag) { + List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchInfo(MatchFieldType.metadata, - new BigInteger[] { getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE })); - mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress })); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); List actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null); mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20, - displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, - mkInstructions); + elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add( + BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); return flow; } - public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, - String macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance elanInstance) - throws ElanException { - Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName, elanInstance); + public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String + macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance + elanInstance) throws ElanException { + if (interfaceManager.isExternalInterface(interfaceName)) { + LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}", + macAddress, interfaceName, elanInstance.getElanInstanceName()); + return; + } + Flow flowEntity; + // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider + // networks, 0 otherwise + long lportTagOrVni = !isOpenstackVniSemanticsEnforced() ? lportTag : isVxlan(elanInstance) + ? elanInstance.getSegmentationId() : 0; + flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, + elanInstance); mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); - setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName, interfaceName, + setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName, writeFlowGroupTx, elanInstance); } - private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, - String macAddress, String displayName, String interfaceName, - WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) throws ElanException { + private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, + String macAddress, String displayName, String interfaceName, + WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) + throws ElanException { Flow flowEntity; EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); if (etreeInterface != null) { if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - EtreeLeafTagName etreeTagName = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeTagName == null) { LOG.warn("Interface " + interfaceName + " seems like it belongs to Etree but etreeTagName from elanTag " + elanTag + " is null."); } else { - flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, + flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance); mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx); } @@ -1124,15 +1023,15 @@ public class ElanUtils { /** * Builds a Flow to be programmed in a remote DPN's DMAC table. This flow * consists in: Match: + elanTag in packet's metadata + packet going to a - * MAC known to be located in another DPN Actions: + set_tunnel_id(lportTag) + * MAC known to be located in another DPN Actions: + set_tunnel_id * + output ITM internal tunnel interface with the other DPN * * @param srcDpId * the src Dpn Id * @param destDpId * dest Dp Id - * @param lportTag - * lport Tag + * @param lportTagOrVni + * lportTag or network VNI * @param elanTag * elan Tag * @param macAddress @@ -1143,31 +1042,31 @@ public class ElanUtils { * @throws ElanException in case of issues creating the flow objects */ @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, + public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag, String macAddress, String displayName, ElanInstance elanInstance) throws ElanException { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchInfo(MatchFieldType.metadata, - new BigInteger[] { getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE })); - mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress })); + mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress))); List mkInstructions = new ArrayList<>(); // List of Action for the provided Source and Destination DPIDs try { List actions = null; - if(isVlan(elanInstance) || isFlat(elanInstance)) { + if (isVlan(elanInstance) || isFlat(elanInstance)) { String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId); if (null == interfaceName) { - LOG.error("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId, elanInstance); + LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId, + elanInstance); } actions = getEgressActionsForInterface(interfaceName, null); - } else { - actions = getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTag); + } else if (isVxlan(elanInstance)) { + actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni); } mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); } catch (Exception e) { LOG.error("Could not get egress actions to add to flow for srcDpId=" + srcDpId + ", destDpId=" + destDpId - + ", lportTag=" + lportTag, e); + + ", lportTag/VNI=" + lportTagOrVni, e); } Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, @@ -1187,8 +1086,7 @@ public class ElanUtils { return; } String macAddress = macEntry.getMacAddress().getValue(); - synchronized (macAddress) { - LOG.debug("Acquired lock for mac : " + macAddress + ". Proceeding with remove operation."); + synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) { deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx); } } @@ -1217,7 +1115,7 @@ public class ElanUtils { private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId, WriteTransaction deleteFlowGroupTx) { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); + EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag); if (etreeLeafTag != null) { executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx); @@ -1237,10 +1135,8 @@ public class ElanUtils { MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef( NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)), deleteFlowGroupTx); - if (LOG.isDebugEnabled()) { - LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", - elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId); - } + LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", + elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId); } return isFlowsRemovedInSrcDpn; } @@ -1262,10 +1158,8 @@ public class ElanUtils { MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)), deleteFlowGroupTx); - if (LOG.isDebugEnabled()) { - LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} " - + "on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId); - } + LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}", + elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId); } /** @@ -1295,18 +1189,19 @@ public class ElanUtils { // Add the ElanState in the elan-state operational data-store tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName), - elanInfo, true); + elanInfo, WriteTransaction.CREATE_MISSING_PARENTS); // Add the ElanMacTable in the elan-mac-table operational data-store MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build(); tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName), - elanMacTable, true); + elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS); ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag) .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName); long etreeLeafTag = -1; if (isEtreeInstance(elanInstanceAdded)) { - etreeLeafTag = retrieveNewElanTag(idManager, elanInstanceName + ElanConstants.LEAVES_POSTFIX); + etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants + .LEAVES_POSTFIX); EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder() .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build(); elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName); @@ -1323,8 +1218,8 @@ public class ElanUtils { // elanTag ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName) .setDescription(elanInstanceAdded.getDescription()) - .setMacTimeout(elanInstanceAdded.getMacTimeout() == null ? ElanConstants.DEFAULT_MAC_TIME_OUT - : elanInstanceAdded.getMacTimeout()) + .setMacTimeout(elanInstanceAdded.getMacTimeout() == null + ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout()) .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag); if (isEtreeInstance(elanInstanceAdded)) { EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag)) @@ -1332,7 +1227,7 @@ public class ElanUtils { elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance); } ElanInstance elanInstanceWithTag = elanInstanceBuilder.build(); - tx.merge(LogicalDatastoreType.CONFIGURATION, getElanInstanceConfigurationDataPath(elanInstanceName), + tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag, true); } @@ -1354,36 +1249,16 @@ public class ElanUtils { InstanceIdentifier node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId)) .build(); - Optional nodePresent = read(broker, LogicalDatastoreType.OPERATIONAL, node); - return nodePresent.isPresent(); + return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent(); } - public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) { - int priority = ElanConstants.ELAN_SERVICE_PRIORITY; - int instructionKey = 0; - List instructions = new ArrayList<>(); - instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(getElanMetadataLabel(elanTag), - MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey)); - instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey)); - - short serviceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX); - ServicesInfo serviceInfo = InterfaceServiceUtil.buildServiceInfo( - String.format("%s.%s", elanInstanceName, interfaceName), serviceIndex, priority, - NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions); - return serviceInfo; + public static ServicesInfo getServiceInfo(String elanInstanceName, String interfaceName) { + return InterfaceServiceUtil.buildServiceInfo(elanInstanceName + "." + interfaceName, + ElanConstants.ELAN_SERVICE_PRIORITY); } - public static void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - CheckedFuture futures = tx.submit(); - try { - futures.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data); - throw new RuntimeException(e.getMessage()); - } + public static String getElanServiceName(String elanName, String interfaceName) { + return "elan." + elanName + interfaceName; } public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority, @@ -1395,161 +1270,16 @@ public class ElanUtils { .addAugmentation(StypeOpenflow.class, augBuilder.build()).build(); } - public static InstanceIdentifier buildServiceId(String vpnInterfaceName, short serviceIndex) { + public static InstanceIdentifier buildServiceId(String interfaceName, short serviceIndex) { return InstanceIdentifier.builder(ServiceBindings.class) - .child(ServicesInfo.class, new ServicesInfoKey(vpnInterfaceName, ServiceModeIngress.class)) + .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class)) .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build(); } - /** - * Builds the list of actions to be taken when sending the packet over a - * VxLan Tunnel Interface, such as setting the tunnel_id field, the vlanId - * if proceeds and output the packet over the right port. - * - * @param tunnelIfaceName - * the tunnel iface name - * @param tunnelKey - * the tunnel key - * @return the list - */ - public List buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey) { - if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) { - return buildItmEgressActions(tunnelIfaceName, tunnelKey); - } - - return Collections.emptyList(); - } - - /** - * Builds the list of actions to be taken when sending the packet over - * external port such as tunnel, physical port etc. - * - * @param interfaceName - * the interface name - * @param tunnelKey - * can be VNI for VxLAN tunnel interfaces, Gre Key for GRE - * tunnels, etc. - * @return the list - */ - public List buildItmEgressActions(String interfaceName, Long tunnelKey) { - List result = Collections.emptyList(); - GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder() - .setIntfName(interfaceName).setTunnelKey(tunnelKey).build(); - - Future> egressActionsOutputFuture = interfaceManagerRpcService - .getEgressActionsForInterface(getEgressActInput); - try { - if (egressActionsOutputFuture.get().isSuccessful()) { - GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult(); - result = egressActionsOutput.getAction(); - } - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call getEgressActionsForInterface {}", e); - } - - if (result == null || result.size() == 0) { - LOG.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey); - } - return result; - } - - /** - * Builds the list of actions to be taken when sending the packet over an - * external VxLan tunnel interface, such as stamping the VNI on the VxLAN - * header, setting the vlanId if it proceeds and output the packet over the - * right port. - * - * @param srcDpnId - * Dpn where the tunnelInterface is located - * @param torNode - * NodeId of the ExternalDevice where the packet must be sent to. - * @param vni - * Vni to be stamped on the VxLAN Header. - * @return the external itm egress action - */ - public List getExternalTunnelItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni) { - List result = Collections.emptyList(); - - GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder() - .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()) - .setTunnelType(TunnelTypeVxlan.class).build(); - Future> output = itmRpcService - .getExternalTunnelInterfaceName(input); - try { - if (output.get().isSuccessful()) { - GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult(); - String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName(); - if (LOG.isDebugEnabled()) { - LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName); - } - - result = buildTunnelItmEgressActions(tunnelIfaceName, vni); - } - - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call getTunnelInterfaceName {}", e); - } - - return result; - } - - /** - * Builds the list of actions to be taken when sending the packet over an - * internal VxLan tunnel interface, such as setting the serviceTag on the - * VNI field of the VxLAN header, setting the vlanId if it proceeds and - * output the packet over the right port. - * - * @param sourceDpnId - * Dpn where the tunnelInterface is located - * @param destinationDpnId - * Dpn where the packet must be sent to. It is used here in order - * to select the right tunnel interface. - * @param serviceTag - * serviceId to be sent on the VxLAN header. - * @return the internal itm egress action - */ - public List getInternalTunnelItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId, - long serviceTag) { - List result = Collections.emptyList(); - - LOG.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}", sourceDpnId, - destinationDpnId, serviceTag); - Class tunType = TunnelTypeVxlan.class; - GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder() - .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build(); - Future> output = itmRpcService - .getTunnelInterfaceName(input); - try { - if (output.get().isSuccessful()) { - GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult(); - String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName(); - LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName); - - result = buildTunnelItmEgressActions(tunnelIfaceName, serviceTag); - } - } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call getTunnelInterfaceName {}", e); - } - - return result; - } - - /** - * Build the list of actions to be taken when sending the packet to external - * (physical) port. - * - * @param interfaceName - * Interface name - * @return the external port itm egress actions - */ - public List getExternalPortItmEgressAction(String interfaceName) { - return buildItmEgressActions(interfaceName, null); - } - public static List getTunnelMatchesForServiceId(int elanTag) { List mkMatches = new ArrayList<>(); // Matching metadata - mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(elanTag) })); + mkMatches.add(new MatchTunnelId(BigInteger.valueOf(elanTag))); return mkMatches; } @@ -1557,38 +1287,20 @@ public class ElanUtils { public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) { RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder() .setDpnId(destDpId).setServiceId(serviceId).build(); - Future> futureObject = itmRpcService - .removeTerminatingServiceActions(input); + Future> futureObject = itmRpcService.removeTerminatingServiceActions(input); try { RpcResult result = futureObject.get(); if (result.isSuccessful()) { - LOG.debug("Successfully completed removeTerminatingServiceActions"); + LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on " + + "dpn {}", serviceId, destDpId); } else { - LOG.debug("Failure in removeTerminatingServiceAction RPC call"); + LOG.debug("Failure in removeTerminatingServiceAction RPC call for ELAN with serviceId {} on " + + "dpn {}", serviceId, destDpId); } } catch (InterruptedException | ExecutionException e) { - LOG.error("Error in RPC call removeTerminatingServiceActions {}", e); - } - } - - public void createTerminatingServiceActions(BigInteger destDpId, int serviceId, List actions) { - List mkInstructions = new ArrayList<>(); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - CreateTerminatingServiceActionsInput input = new CreateTerminatingServiceActionsInputBuilder() - .setDpnId(destDpId).setServiceId(serviceId).setInstruction(mkInstructions).build(); - - itmRpcService.createTerminatingServiceActions(input); - } - - public static TunnelList buildInternalTunnel(DataBroker broker) { - InstanceIdentifier tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class) - .build(); - Optional tunnelList = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, - tunnelListInstanceIdentifier); - if (tunnelList.isPresent()) { - return tunnelList.get(); + LOG.error("Error in RPC call removeTerminatingServiceActions for ELAN with serviceId {} on " + + "dpn {}: {}", serviceId, destDpId, e); } - return null; } /** @@ -1604,15 +1316,10 @@ public class ElanUtils { */ public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice, LogicalDatastoreType datastoreType) { - ExternalTunnel externalTunnel = null; Class tunType = TunnelTypeVxlan.class; InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class) .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build(); - Optional tunnelList = read(broker, datastoreType, iid); - if (tunnelList.isPresent()) { - externalTunnel = tunnelList.get(); - } - return externalTunnel; + return read(broker, datastoreType, iid).orNull(); } /** @@ -1644,377 +1351,19 @@ public class ElanUtils { * @return the all external tunnels */ public List getAllExternalTunnels(LogicalDatastoreType datastoreType) { - List result = null; InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class).build(); - Optional tunnelList = read(broker, datastoreType, iid); - if (tunnelList.isPresent()) { - result = tunnelList.get().getExternalTunnel(); - } - if (result == null) { - result = Collections.emptyList(); - } - return result; - } - - /** - * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is - * connected remotely in another CSS and accessible through an internal - * tunnel. It also installs the flow for dropping the packet if it came over - * an ITM tunnel (that is, if the Split-Horizon flag is set) - * - * @param localDpId - * Id of the DPN where the MAC Addr is accessible locally - * @param remoteDpId - * Id of the DPN where the flow must be installed - * @param lportTag - * lportTag of the interface where the mac is connected to. - * @param elanTag - * Identifier of the ELAN - * @param macAddress - * MAC to be installed in remoteDpId's DMAC table - * @param displayName - * the display name - * @throws ElanException in case of issues creating the flow objects - */ - public void installDmacFlowsToInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag, - long elanTag, String macAddress, String displayName) throws ElanException { - Flow flow = buildDmacFlowForInternalRemoteMac(localDpId, remoteDpId, lportTag, elanTag, macAddress, - displayName); - mdsalManager.installFlow(remoteDpId, flow); - } - - /** - * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC - * that is connected remotely in an External Device (TOR) and that is - * accessible through an external tunnel. It also installs the flow for - * dropping the packet if it came over an ITM tunnel (that is, if the - * Split-Horizon flag is set) - * - * @param dpnId - * Id of the DPN where the flow must be installed - * @param extDeviceNodeId - * the ext device node id - * @param elanTag - * the elan tag - * @param vni - * the vni - * @param macAddress - * the mac address - * @param displayName - * the display name - * @param interfaceName - * the interface name - * - * @return the dmac flows - * @throws ElanException in case of issues creating the flow objects - */ - public List> installDmacFlowsToExternalRemoteMac(BigInteger dpnId, - String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName, - String interfaceName) throws ElanException { - List> futures = new ArrayList<>(); - synchronized (macAddress) { - Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, - displayName); - futures.add(mdsalManager.installFlow(dpnId, flow)); - - Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress); - futures.add(mdsalManager.installFlow(dpnId, dropFlow)); - installEtreeDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName, - interfaceName, futures); - } - return futures; - } - - private void installEtreeDmacFlowsToExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long elanTag, - Long vni, String macAddress, String displayName, String interfaceName, - List> futures) throws ElanException { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); - if (etreeLeafTag != null) { - buildEtreeDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress, futures, - etreeLeafTag); - buildEtreeDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName, - futures, etreeLeafTag); - } - } - - private void buildEtreeDmacFlowForExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long vni, - String macAddress, String displayName, String interfaceName, List> futures, - EtreeLeafTagName etreeLeafTag) throws ElanException { - boolean isRoot = false; - if (interfaceName == null) { - isRoot = true; - } else { - EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); - if (etreeInterface != null) { - if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - isRoot = true; - } - } - } - if (isRoot) { - Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, - etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName); - futures.add(mdsalManager.installFlow(dpnId, flow)); - } - } - - private void buildEtreeDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId, - Long elanTag, String macAddress, List> futures, EtreeLeafTagName etreeLeafTag) { - if (etreeLeafTag != null) { - Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, - etreeLeafTag.getEtreeLeafTag().getValue(), macAddress); - futures.add(mdsalManager.installFlow(dpnId, dropFlow)); - } + return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse( + Collections.emptyList()); } public static List buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) { List mkMatches = new ArrayList<>(); - mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { - getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG })); - mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddr })); - + mkMatches.add( + new MatchMetadata(getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG)); + mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddr))); return mkMatches; } - /** - * Builds a Flow to be programmed in a DPN's DMAC table. This method must be - * used when the MAC is located in an External Device (TOR). The flow - * matches on the specified MAC and 1) sends the packet over the CSS-TOR - * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means - * the packet came from an external tunnel) - * - * @param dpId - * DPN whose DMAC table is going to be modified - * @param extDeviceNodeId - * Hwvtep node where the mac is attached to - * @param elanTag - * ElanId to which the MAC is being added to - * @param vni - * the vni - * @param dstMacAddress - * The mac address to be programmed - * @param displayName - * the display name - * @return the flow - * @throws ElanException in case of issues creating the flow objects - */ - @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag, - Long vni, String dstMacAddress, String displayName) throws ElanException { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress); - List mkInstructions = new ArrayList<>(); - try { - List actions = getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - } catch (Exception e) { - LOG.error("Could not get Egress Actions for DpId=" + dpId + ", externalNode=" + extDeviceNodeId, e); - } - - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag, - false), - 20, /* prio */ - displayName, 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - } - - /** - * Builds the flow that drops the packet if it came through an external - * tunnel, that is, if the Split-Horizon flag is set. - * - * @param dpnId - * DPN whose DMAC table is going to be modified - * @param extDeviceNodeId - * Hwvtep node where the mac is attached to - * @param elanTag - * ElanId to which the MAC is being added to - * @param dstMacAddress - * The mac address to be programmed - */ - private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId, - Long elanTag, String dstMacAddress) { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ true, dstMacAddress); - List mkInstructions = MDSALUtil.buildInstructionsDrop(); - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress, - elanTag, true); - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */ - "Drop", 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - } - - private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) { - return new StringBuilder(NwConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop") - .toString(); - } - - /** - * Builds a Flow to be programmed in a remote DPN's DMAC table. This method - * must be used when the MAC is located in another CSS. - * - *

This flow consists in: Match: + elanTag in packet's metadata + packet - * going to a MAC known to be located in another DPN Actions: + - * set_tunnel_id(lportTag) + output on ITM internal tunnel interface with - * the other DPN - * - * @param localDpId - * the local dp id - * @param remoteDpId - * the remote dp id - * @param lportTag - * the lport tag - * @param elanTag - * the elan tag - * @param macAddress - * the mac address - * @param displayName - * the display name - * @return the flow - * @throws ElanException in case of issues creating the flow objects - */ - @SuppressWarnings("checkstyle:IllegalCatch") - public Flow buildDmacFlowForInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag, - long elanTag, String macAddress, String displayName) throws ElanException { - List mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, macAddress); - - List mkInstructions = new ArrayList<>(); - - try { - // List of Action for the provided Source and Destination DPIDs - List actions = getInternalTunnelItmEgressAction(localDpId, remoteDpId, lportTag); - mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions)); - } catch (Exception e) { - LOG.error("Could not get Egress Actions for localDpId=" + localDpId + ", remoteDpId=" - + remoteDpId + ", lportTag=" + lportTag, e); - } - - Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, - getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, localDpId, remoteDpId, macAddress, elanTag), - 20, /* prio */ - displayName, 0, /* idleTimeout */ - 0, /* hardTimeout */ - ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions); - - return flow; - - } - - /** - * Installs or removes flows in DMAC table for MACs that are/were located in - * an external Elan Device. - * - * @param dpId - * Id of the DPN where the DMAC table is going to be modified - * @param extNodeId - * Id of the External Device where the MAC is located - * @param elanTag - * Id of the ELAN - * @param vni - * VNI of the LogicalSwitch to which the MAC belongs to, and that - * is associated with the ELAN - * @param macAddress - * the mac address - * @param elanInstanceName - * the elan instance name - * @param addOrRemove - * Indicates if flows must be installed or removed. - * @param interfaceName - * the interface name - * @throws ElanException in case of issues creating the flow objects - * @see org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp - */ - public void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni, - String macAddress, String elanInstanceName, MdsalOp addOrRemove, String interfaceName) - throws ElanException { - if (addOrRemove == MdsalOp.CREATION_OP) { - installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName, - interfaceName); - } else if (addOrRemove == MdsalOp.REMOVAL_OP) { - deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress); - } - } - - /** - * Delete dmac flows to external mac. - * - * @param elanTag - * the elan tag - * @param dpId - * the dp id - * @param extDeviceNodeId - * the ext device node id - * @param macToRemove - * the mac to remove - * @return dmac flow - */ - public List> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId, - String extDeviceNodeId, String macToRemove) { - List> futures = new ArrayList<>(); - synchronized (macToRemove) { - // Removing the flows that sends the packet on an external tunnel - removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - - // And now removing the drop flow - removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - - deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove, futures); - } - return futures; - } - - private void deleteEtreeDmacFlowsToExternalMac(long elanTag, BigInteger dpId, String extDeviceNodeId, - String macToRemove, List> futures) { - EtreeLeafTagName etreeLeafTag = getEtreeLeafTagByElanTag(elanTag); - if (etreeLeafTag != null) { - removeFlowThatSendsThePacketOnAnExternalTunnel(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, - extDeviceNodeId, macToRemove, futures); - removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove, futures); - } - } - - private void removeTheDropFlow(long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove, - List> futures) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove, - elanTag, true); - Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build(); - futures.add(mdsalManager.removeFlow(dpId, flowToRemove)); - } - - private void removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId, - String extDeviceNodeId, String macToRemove, List> futures) { - String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove, - elanTag, false); - Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build(); - futures.add(mdsalManager.removeFlow(dpId, flowToRemove)); - } - - /** - * Gets the dpid from interface. - * - * @param interfaceName - * the interface name - * @return the dpid from interface - */ - public BigInteger getDpidFromInterface(String interfaceName) { - BigInteger dpId = null; - Future> output = interfaceManagerRpcService - .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build()); - try { - RpcResult rpcResult = output.get(); - if (rpcResult.isSuccessful()) { - dpId = rpcResult.getResult().getDpid(); - } - } catch (NullPointerException | InterruptedException | ExecutionException e) { - LOG.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e); - } - return dpId; - } - /** * Checks if is interface operational. * @@ -2050,36 +1399,7 @@ public class ElanUtils { InstanceIdentifier ifStateId = createInterfaceStateInstanceIdentifier( interfaceName); - Optional ifStateOptional = MDSALUtil - .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId); - if (ifStateOptional.isPresent()) { - return ifStateOptional.get(); - } - return null; - } - - /** - * Gets the interface from config ds. - * - * @param interfaceName - * the interface name - * @param dataBroker - * the data broker - * @return the interface from config ds - */ - public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang - .ietf.interfaces.rev140508.interfaces.Interface getInterfaceFromConfigDS( - String interfaceName, DataBroker dataBroker) { - InstanceIdentifier ifaceId = createInterfaceInstanceIdentifier(interfaceName); - Optional iface = MDSALUtil - .read(dataBroker, LogicalDatastoreType.CONFIGURATION, ifaceId); - if (iface.isPresent()) { - return iface.get(); - } - return null; + return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId).orNull(); } /** @@ -2103,27 +1423,6 @@ public class ElanUtils { return idBuilder.build(); } - /** - * Creates the interface instance identifier. - * - * @param interfaceName - * the interface name - * @return the instance identifier - */ - public static InstanceIdentifier createInterfaceInstanceIdentifier( - String interfaceName) { - InstanceIdentifierBuilder idBuilder = InstanceIdentifier - .builder(Interfaces.class) - .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang - .ietf.interfaces.rev140508.interfaces.Interface.class, - new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang - .ietf.interfaces.rev140508.interfaces.InterfaceKey( - interfaceName)); - return idBuilder.build(); - } - public static CheckedFuture waitForTransactionToComplete( WriteTransaction tx) { CheckedFuture futures = tx.submit(); @@ -2135,16 +1434,63 @@ public class ElanUtils { return futures; } + public static boolean isVxlanNetwork(DataBroker broker, String elanInstanceName) { + ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName); + return elanInstance != null && isVxlan(elanInstance); + } + public static boolean isVxlan(ElanInstance elanInstance) { return elanInstance != null && elanInstance.getSegmentType() != null && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) - && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0; + && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0; + } + + private static boolean isVxlanSegment(ElanInstance elanInstance) { + if (elanInstance != null) { + List elanSegments = elanInstance.getElanSegments(); + if (elanSegments != null) { + for (ElanSegments segment : elanSegments) { + if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) + && segment.getSegmentationId() != null + && segment.getSegmentationId().longValue() != 0) { + return true; + } + } + } + } + return false; + } + + public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) { + return isVxlan(elanInstance) || isVxlanSegment(elanInstance); + } + + public static Long getVxlanSegmentationId(ElanInstance elanInstance) { + Long segmentationId = 0L; + if (elanInstance == null) { + return segmentationId; + } + + if (elanInstance.getSegmentType() != null + && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) + && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) { + segmentationId = elanInstance.getSegmentationId(); + } else { + for (ElanSegments segment: elanInstance.getElanSegments()) { + if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class) + && segment.getSegmentationId() != null + && segment.getSegmentationId().longValue() != 0) { + segmentationId = segment.getSegmentationId(); + } + } + } + return segmentationId; } public static boolean isVlan(ElanInstance elanInstance) { return elanInstance != null && elanInstance.getSegmentType() != null && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class) - && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0; + && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0; } public static boolean isFlat(ElanInstance elanInstance) { @@ -2152,27 +1498,38 @@ public class ElanUtils { && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class); } - public boolean isExternal(String interfaceName) { - return isExternal(getInterfaceFromConfigDS(interfaceName, broker)); + public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName, + String macAddress, List dpnIds) { + for (BigInteger dpId : dpnIds) { + WriteTransaction writeTx = broker.newWriteOnlyTransaction(); + mdsalManager.addFlowToTx(buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag), + writeTx); + writeTx.submit(); + } } - public static boolean isExternal( - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang - .ietf.interfaces.rev140508.interfaces.Interface iface) { - if (iface == null) { - return false; + public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List dpnIds) { + for (BigInteger dpId : dpnIds) { + String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag); + mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId)); } - - IfExternal ifExternal = iface.getAugmentation(IfExternal.class); - return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal()); } - public static boolean isEtreeRootInterfaceByInterfaceName(DataBroker broker, String interfaceName) { - EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName); - if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) { - return true; - } - return false; + public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress, + String displayName, long elanTag) { + List matches = new ArrayList<>(); + matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE)); + matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress))); + List instructions = new ArrayList<>(); + List actions = new ArrayList<>(); + actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)); + + instructions.add(new InstructionApplyActions(actions)); + String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag); + FlowEntity flow = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0, + ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), + matches, instructions); + return flow; } /** @@ -2180,7 +1537,7 @@ public class ElanUtils { * Install SMAC and DMAC flows. */ public void addMacEntryToDsAndSetupFlows(IInterfaceManager interfaceManager, String interfaceName, - String macAddress, String elanName, WriteTransaction tx, WriteTransaction flowWritetx, int macTimeOut) + String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx, int macTimeOut) throws ElanException { LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and " + "ElanForwardingTables DS", macAddress, interfaceName); @@ -2191,12 +1548,12 @@ public class ElanUtils { .setIsStaticAddress(false).build(); InstanceIdentifier macEntryId = ElanUtils .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress); - tx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry); + interfaceTx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry); InstanceIdentifier elanMacEntryId = ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress); - tx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry); + interfaceTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry); ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName); - setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, - flowWritetx); + setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, true, + flowTx); } /** @@ -2204,18 +1561,18 @@ public class ElanUtils { * Remove SMAC and DMAC flows. */ public void deleteMacEntryFromDsAndRemoveFlows(IInterfaceManager interfaceManager, String interfaceName, - String macAddress, String elanName, WriteTransaction tx, WriteTransaction deleteFlowTx) { + String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx) { LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries " + "and ElanForwardingTables DS", macAddress, interfaceName); PhysAddress physAddress = new PhysAddress(macAddress); MacEntry macEntry = getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress); InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName); if (macEntry != null && interfaceInfo != null) { - deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, deleteFlowTx); + deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, flowTx); } - tx.delete(LogicalDatastoreType.OPERATIONAL, + interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress)); - tx.delete(LogicalDatastoreType.OPERATIONAL, + interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress)); } @@ -2227,7 +1584,7 @@ public class ElanUtils { } for (String dpnInterface : dpnInterfaces.getInterfaces()) { - if (isExternal(dpnInterface)) { + if (interfaceManager.isExternalInterface(dpnInterface)) { return dpnInterface; } } @@ -2235,4 +1592,213 @@ public class ElanUtils { LOG.trace("Elan {} does not have any external interace attached to DPN {}", elanInstanceName, dpnId); return null; } + + public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) { + String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId; + return elanMacDmacDpnKey.intern(); + } + + public static String getElanMacKey(long elanTag, String macAddress) { + String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag; + return elanMacKey.intern(); + } + + // TODO This should return a collection of futures + public static void addToListenableFutureIfTxException(RuntimeException exception, + List> futures) { + Throwable cause = exception.getCause(); + if (cause != null && cause instanceof TransactionCommitFailedException) { + futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause)); + } + } + + public static List getPhysAddress(List macAddress) { + Preconditions.checkNotNull(macAddress, "macAddress cannot be null"); + List physAddresses = new ArrayList<>(); + for (String mac : macAddress) { + physAddresses.add(new PhysAddress(mac)); + } + return physAddresses; + } + + public static List getStaticMacEntries(List staticMacAddresses) { + if (isEmpty(staticMacAddresses)) { + return Collections.EMPTY_LIST; + } + StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder(); + List staticMacEntries = new ArrayList<>(); + List physAddressList = getPhysAddress(staticMacAddresses); + for (PhysAddress physAddress : physAddressList) { + staticMacEntries.add(staticMacEntriesBuilder.setMacAddress(physAddress).build()); + } + return staticMacEntries; + } + + public static InstanceIdentifier getStaticMacEntriesCfgDataPathIdentifier(String interfaceName, + String macAddress) { + return InstanceIdentifier.builder(ElanInterfaces.class) + .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).child(StaticMacEntries.class, + new StaticMacEntriesKey(new PhysAddress(macAddress))).build(); + } + + public static List getDeletedEntries(List originalStaticMacEntries, + List updatedStaticMacEntries) { + if (isEmpty(originalStaticMacEntries)) { + return Collections.EMPTY_LIST; + } + List deleted = Lists.newArrayList(originalStaticMacEntries); + if (isNotEmpty(updatedStaticMacEntries)) { + deleted.removeAll(updatedStaticMacEntries); + } + return deleted; + } + + public static List diffOf(List orig, List updated) { + if (isEmpty(orig)) { + return Collections.EMPTY_LIST; + } + List diff = Lists.newArrayList(orig); + if (isNotEmpty(updated)) { + diff.removeAll(updated); + } + return diff; + } + + public static void segregateToBeDeletedAndAddEntries(List originalStaticMacEntries, + List updatedStaticMacEntries) { + if (isNotEmpty(updatedStaticMacEntries)) { + List existingClonedStaticMacEntries = new ArrayList<>(); + if (isNotEmpty(originalStaticMacEntries)) { + existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries); + originalStaticMacEntries.removeAll(updatedStaticMacEntries); + updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries); + } + } + } + + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + public static boolean isNotEmpty(Collection collection) { + return !isEmpty(collection); + } + + public static void setElanInstancToDpnsCache(Map> elanInstancToDpnsCache) { + ElanUtils.elanInstancToDpnsCache = elanInstancToDpnsCache; + } + + public static Set getElanInvolvedDPNsFromCache(String elanName) { + return elanInstancToDpnsCache.get(elanName); + } + + public static void addDPNInterfaceToElanInCache(String elanName, DpnInterfaces dpnInterfaces) { + elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).add(dpnInterfaces); + } + + public static void removeDPNInterfaceFromElanInCache(String elanName, DpnInterfaces dpnInterfaces) { + elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).remove(dpnInterfaces); + } + + public Optional getSourceIpAddress(Ethernet ethernet) { + Optional srcIpAddress = Optional.absent(); + if (ethernet.getPayload() == null) { + return srcIpAddress; + } + byte[] ipAddrBytes = null; + if (ethernet.getPayload() instanceof IPv4) { + IPv4 ipv4 = (IPv4) ethernet.getPayload(); + ipAddrBytes = Ints.toByteArray(ipv4.getSourceAddress()); + } else if (ethernet.getPayload() instanceof ARP) { + ipAddrBytes = ((ARP) ethernet.getPayload()).getSenderProtocolAddress(); + } + if (ipAddrBytes != null) { + String ipAddr = NWUtil.toStringIpAddress(ipAddrBytes); + return Optional.of(IpAddressBuilder.getDefaultInstance(ipAddr)); + } + return srcIpAddress; + } + + public List getElanMacEntries(String elanName) { + MacTable macTable = getElanMacTable(elanName); + if (macTable == null) { + return Collections.emptyList(); + } + return macTable.getMacEntry(); + } + + public boolean isTunnelInLogicalGroup(String interfaceName, DataBroker broker) { + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang + .ietf.interfaces.rev140508.interfaces.Interface configIface = + interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName); + IfTunnel ifTunnel = configIface.getAugmentation(IfTunnel.class); + if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) { + ParentRefs refs = configIface.getAugmentation(ParentRefs.class); + if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) { + return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated + } + } + return false; + } + + public static void addElanInterfaceToElanInstanceCache(String elanInstanceName, String elanInterfaceName) { + elanInstanceToInterfacesCache.computeIfAbsent(elanInstanceName, key -> new HashSet<>()).add(elanInterfaceName); + } + + public static void removeElanInterfaceToElanInstanceCache(String elanInstanceName, String interfaceName) { + Set elanInterfaces = elanInstanceToInterfacesCache.get(elanInstanceName); + if (elanInterfaces == null || elanInterfaces.isEmpty()) { + return; + } + elanInterfaces.remove(interfaceName); + } + + @Nonnull public static Set removeAndGetElanInterfaces(String elanInstanceName) { + Set removed = elanInstanceToInterfacesCache.remove(elanInstanceName); + return removed != null ? removed : Collections.emptySet(); + } + + public static InstanceIdentifier getFlowIid(Flow flow, BigInteger dpnId) { + FlowKey flowKey = new FlowKey(new FlowId(flow.getId())); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId = + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId); + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn = + new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build(); + return InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeDpn.getKey()).augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build(); + } + + public static String getElanInterfaceJobKey(String interfaceName) { + return "elaninterface-" + interfaceName; + } + + public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress, + int lportTag, List instructions) { + LOG.info("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId, + ingressInterfaceName, macAddress, ipAddress); + ElanInterface elanIface = getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName); + ElanInstance elanInstance = getElanInstanceByName(broker, elanIface.getElanInstanceName()); + if (elanInstance == null) { + LOG.debug("addArpResponderFlow: elanInstance is null, Failed to install arp responder flow for Interface {}" + + " with MAC {} & IP {}", dpnId, + ingressInterfaceName, macAddress, ipAddress); + return; + } + String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress); + ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY, + ArpResponderUtil.generateCookie(lportTag, ipAddress), + ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress), instructions); + LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName); + } + + public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, + int lportTag) { + LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName, + ipAddress); + ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress)); + } } + +