2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14 import static org.opendaylight.infrautils.utils.concurrent.LoggingFutures.addErrorLogging;
15 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
17 import com.google.common.base.Optional;
18 import com.google.common.base.Preconditions;
19 import com.google.common.collect.Lists;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import java.math.BigInteger;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
28 import java.util.Queue;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.locks.ReentrantLock;
34 import javax.annotation.PostConstruct;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37 import org.apache.commons.lang3.StringUtils;
38 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
39 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
40 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
41 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
42 import org.opendaylight.genius.infra.Datastore.Configuration;
43 import org.opendaylight.genius.infra.Datastore.Operational;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.genius.infra.TransactionAdapter;
47 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
48 import org.opendaylight.genius.infra.TypedWriteTransaction;
49 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
50 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
51 import org.opendaylight.genius.itm.globals.ITMConstants;
52 import org.opendaylight.genius.mdsalutil.FlowEntity;
53 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
54 import org.opendaylight.genius.mdsalutil.InstructionInfo;
55 import org.opendaylight.genius.mdsalutil.MDSALUtil;
56 import org.opendaylight.genius.mdsalutil.MatchInfo;
57 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
58 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
59 import org.opendaylight.genius.mdsalutil.NwConstants;
60 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
61 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
62 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
63 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
64 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
65 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
66 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
67 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
68 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
69 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
70 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
71 import org.opendaylight.genius.utils.JvmGlobalLocks;
72 import org.opendaylight.genius.utils.ServiceIndex;
73 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
74 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
75 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
76 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
77 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
78 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
79 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
80 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
81 import org.opendaylight.netvirt.elan.utils.ElanConstants;
82 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
83 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
84 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
85 import org.opendaylight.netvirt.elan.utils.ElanUtils;
86 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
87 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
88 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
89 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
90 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
91 import org.opendaylight.serviceutils.srm.RecoverableListener;
92 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
93 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
94 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
95 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
136 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
137 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
138 import org.slf4j.Logger;
139 import org.slf4j.LoggerFactory;
142 * Class in charge of handling creations, modifications and removals of
145 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
148 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
149 implements RecoverableListener {
150 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
151 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
152 private static final boolean SH_FLAG_SET = true;
153 private static final boolean SH_FLAG_UNSET = false;
155 private final DataBroker broker;
156 private final ManagedNewTransactionRunner txRunner;
157 private final IMdsalApiManager mdsalManager;
158 private final IInterfaceManager interfaceManager;
159 private final IdManagerService idManager;
160 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
161 private final INeutronVpnManager neutronVpnManager;
162 private final ElanItmUtils elanItmUtils;
163 private final ElanEtreeUtils elanEtreeUtils;
164 private final ElanL2GatewayUtils elanL2GatewayUtils;
165 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
166 private final ElanUtils elanUtils;
167 private final JobCoordinator jobCoordinator;
168 private final ElanInstanceCache elanInstanceCache;
169 private final ElanInterfaceCache elanInterfaceCache;
171 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
172 unProcessedElanInterfaces = new ConcurrentHashMap<>();
175 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
176 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
177 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
178 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
179 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
180 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
181 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
182 final ElanInstanceCache elanInstanceCache,
183 final ElanInterfaceCache elanInterfaceCache,
184 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
185 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
186 super(ElanInterface.class, ElanInterfaceManager.class);
187 this.broker = dataBroker;
188 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
189 this.idManager = managerService;
190 this.mdsalManager = mdsalApiManager;
191 this.interfaceManager = interfaceManager;
192 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
193 this.neutronVpnManager = neutronVpnManager;
194 this.elanItmUtils = elanItmUtils;
195 this.elanEtreeUtils = elanEtreeUtils;
196 this.elanL2GatewayUtils = elanL2GatewayUtils;
197 this.elanUtils = elanUtils;
198 this.jobCoordinator = jobCoordinator;
199 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
200 this.elanInstanceCache = elanInstanceCache;
201 this.elanInterfaceCache = elanInterfaceCache;
202 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
212 public void registerListener() {
213 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
217 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
218 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
222 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
223 String interfaceName = del.getName();
224 String elanInstanceName = del.getElanInstanceName();
225 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
226 if (elanInterfaces != null && elanInterfaces.contains(del)) {
227 elanInterfaces.remove(del);
228 if (elanInterfaces.isEmpty()) {
229 unProcessedElanInterfaces.remove(elanInstanceName);
232 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
234 * Handling in case the elan instance is deleted.If the Elan instance is
235 * deleted, there is no need to explicitly delete the elan interfaces
237 if (elanInfo == null) {
240 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
241 if (interfaceInfo == null && elanInfo.isExternal()) {
242 // In deleting external network, the underlying ietf Inteface might have been removed
243 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
244 // from Operational DS instead
245 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
247 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
248 interfaceName, interfaceInfo, this);
249 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
252 private static class RemoveElanInterfaceHolder {
253 boolean isLastElanInterface = false;
254 boolean isLastInterfaceOnDpn = false;
255 BigInteger dpId = null;
258 @SuppressWarnings("checkstyle:ForbidCertainMethod")
259 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
260 InterfaceInfo interfaceInfo) {
261 String elanName = elanInfo.getElanInstanceName();
262 long elanTag = elanInfo.getElanTag();
263 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
264 List<ListenableFuture<Void>> futures = new ArrayList<>();
265 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
266 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
267 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
268 if (elanState == null) {
271 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
272 List<String> elanInterfaces = elanState.getElanInterfaces();
273 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
274 holder.isLastElanInterface = true;
276 if (interfaceInfo != null) {
277 holder.dpId = interfaceInfo.getDpId();
278 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
279 interfaceName, elanTag, interfaceTx);
281 * If there are not elan ports, remove the unknown dmac, terminating
282 * service table flows, remote/local bc group
284 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
285 || dpnInterfaces.getInterfaces().isEmpty()) {
286 // No more Elan Interfaces in this DPN
287 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
289 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
290 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag());
292 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag());
293 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
294 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
295 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
296 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
297 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
298 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
299 elanUtils.removeTerminatingServiceAction(holder.dpId,
300 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
302 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
304 holder.isLastInterfaceOnDpn = true;
306 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
311 futures.forEach(ElanUtils::waitForTransactionToComplete);
313 if (holder.isLastInterfaceOnDpn && holder.dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
315 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
316 confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInfo, holder.dpId, confTx))));
318 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
319 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
320 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
321 ElanConstants.JOB_MAX_RETRIES);
326 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
327 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
328 throws ExecutionException, InterruptedException {
329 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
330 if (etreeLeafTag != null) {
331 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
332 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
336 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
337 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
338 throws ExecutionException, InterruptedException {
339 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
340 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
343 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
344 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
345 throws ExecutionException, InterruptedException {
346 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
347 if (etreeInstance != null) {
348 BigInteger dpnId = interfaceInfo.getDpId();
349 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
350 LOG.trace("deleted the localBroadCast Group:{}", groupId);
351 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
355 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
356 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
357 throws ExecutionException, InterruptedException {
358 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
359 if (etreeInstance != null) {
360 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
361 BigInteger dpnId = interfaceInfo.getDpId();
362 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
363 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
364 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
368 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
369 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
370 String elanName = elanInfo.getElanInstanceName();
371 Elan elanState = ElanUtils.getElanByName(tx, elanName);
372 if (elanState == null) {
375 List<String> elanInterfaces = elanState.getElanInterfaces();
376 boolean isRemoved = elanInterfaces != null && elanInterfaces.remove(interfaceName);
381 if (elanInterfaces.isEmpty()) {
382 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
383 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
384 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
385 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
387 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
388 .withKey(new ElanKey(elanName)).build();
389 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
394 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
395 throws ReadFailedException {
396 // removing the ElanInterface from the config data_store if interface is
397 // not present in Interface config DS
398 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
399 interfaceName) == null
400 && elanInterfaceCache.get(interfaceName).isPresent()) {
401 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
405 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
406 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
407 String elanName = elanInfo.getElanInstanceName();
408 List<ListenableFuture<Void>> futures = new ArrayList<>();
409 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
410 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
411 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
412 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
413 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
414 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
415 if (interfaceInfo != null) {
416 if (existingElanInterfaceMac.isPresent()) {
417 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
418 if (existingMacEntries != null) {
419 List<PhysAddress> macAddresses = new ArrayList<>();
420 for (MacEntry macEntry : existingMacEntries) {
421 PhysAddress macAddress = macEntry.getMacAddress();
422 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
423 macAddress.getValue(), interfaceName);
424 Optional<MacEntry> macEntryOptional =
425 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
426 if (!isLastElanInterface && macEntryOptional.isPresent()) {
427 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
429 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
430 macAddresses.add(macAddress);
433 // Removing all those MACs from External Devices belonging
435 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
436 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
440 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
441 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
442 } else if (existingElanInterfaceMac.isPresent()) {
443 // Interface does not exist in ConfigDS, so lets remove everything
444 // about that interface related to Elan
445 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
446 if (macEntries != null) {
447 for (MacEntry macEntry : macEntries) {
448 PhysAddress macAddress = macEntry.getMacAddress();
449 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
450 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
455 if (existingElanInterfaceMac.isPresent()) {
456 interfaceTx.delete(elanInterfaceId);
458 unbindService(interfaceName, flowTx);
459 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
465 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
466 String interfaceName, long elanTag,
467 TypedReadWriteTransaction<Operational> tx)
468 throws ExecutionException, InterruptedException {
469 // FIXME: pass in and use ElanInstanceKey instead?
470 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
473 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
474 if (dpnInterfaces != null) {
475 List<String> interfaceLists = dpnInterfaces.getInterfaces();
476 if (interfaceLists != null) {
477 interfaceLists.remove(interfaceName);
480 if (interfaceLists == null || interfaceLists.isEmpty()) {
481 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
482 deleteElanDpnInterface(elanName, dpId, tx);
484 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
487 return dpnInterfaces;
493 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
494 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
495 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
496 for (DpnInterfaces dpnInterface : dpnInterfaces) {
497 BigInteger currentDpId = dpnInterface.getDpId();
498 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
499 for (String elanInterface : dpnInterface.getInterfaces()) {
500 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
501 if (macs == null || macs.getMacEntry() == null) {
504 for (MacEntry mac : macs.getMacEntry()) {
505 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
506 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
511 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
514 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
515 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
516 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
517 if (etreeLeafTag != null) {
518 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac, confTx);
522 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
523 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
525 .removeFlow(confTx, dpId,
526 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
527 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
528 mac.getMacAddress().getValue(), elanTag)));
532 * Possible Scenarios for update
533 * a. if orig={1,2,3,4} and updated=null or updated={}
534 then all {1,2,3,4} should be removed
536 b. if orig=null or orig={} and updated ={1,2,3,4}
537 then all {1,2,3,4} should be added
539 c. if orig = {1,2,3,4} updated={2,3,4}
540 then 1 should be removed
542 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
543 then we should just add 5
545 e. if orig = {1,2,3,4} updated={2,3,4,5}
546 then 1 should be removed , 5 should be added
548 @SuppressWarnings("checkstyle:ForbidCertainMethod")
550 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
551 // updating the static-Mac Entries for the existing elanInterface
552 String elanName = update.getElanInstanceName();
553 String interfaceName = update.getName();
555 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
556 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
557 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
558 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
560 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
561 deletedEntry.getMacAddress()));
563 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
564 * Hence add the macentries for the same.*/
565 for (StaticMacEntries staticMacEntry : updatedEntries) {
566 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
567 staticMacEntry.getMacAddress());
568 addErrorLogging(ElanUtils.waitForTransactionToComplete(
569 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
570 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
571 if (existingMacEntry.isPresent()) {
572 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
573 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
576 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
577 elanName, interfaceName, staticMacEntry, tx);
579 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
584 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
585 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
586 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
587 String interfaceName = elanInterfaceAdded.getName();
588 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
589 if (interfaceInfo == null) {
590 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
593 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
595 if (elanInstance == null) {
596 // Add the ElanInstance in the Configuration data-store
597 List<String> elanInterfaces = new ArrayList<>();
598 elanInterfaces.add(interfaceName);
599 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
600 confTx -> ElanUtils.updateOperationalDataStore(idManager,
601 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
602 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
605 Long elanTag = elanInstance.getElanTag();
606 // If elan tag is not updated, then put the elan interface into
607 // unprocessed entry map and entry. Let entries
608 // in this map get processed during ELAN update DCN.
609 if (elanTag == null || elanTag == 0L) {
610 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
611 if (elanInterfaces == null) {
612 elanInterfaces = new ConcurrentLinkedQueue<>();
614 if (!elanInterfaces.contains(elanInterfaceAdded)) {
615 elanInterfaces.add(elanInterfaceAdded);
617 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
620 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
621 interfaceInfo, elanInstance, this);
622 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
623 }), LOG, "Error processing added ELAN interface");
626 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
627 List<ListenableFuture<Void>> futures = new ArrayList<>();
628 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
629 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
632 for (ElanInterface elanInterface : elanInterfaces) {
633 String interfaceName = elanInterface.getName();
634 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
635 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
637 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
641 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
642 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
643 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
644 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
645 List<DpnInterfaces> dpnInterfaceLists = null;
646 if (elanDpnInterfacesList != null) {
647 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
649 if (dpnInterfaceLists == null) {
650 dpnInterfaceLists = new ArrayList<>();
652 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
653 BigInteger dstDpId = interfaceInfo.getDpId();
654 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
657 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
658 for (String remoteIf : remoteElanInterfaces) {
659 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
660 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
661 if (elanIfMac == null || remoteInterface == null) {
664 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
665 if (remoteMacEntries != null) {
666 for (MacEntry macEntry : remoteMacEntries) {
667 String macAddress = macEntry.getMacAddress().getValue();
668 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
669 dstDpId, elanInstance.getElanInstanceName());
670 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
671 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
672 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
679 private static class AddElanInterfaceHolder {
680 private DpnInterfaces dpnInterfaces = null;
681 private boolean isFirstInterfaceInDpn = false;
682 private BigInteger dpId;
685 @SuppressWarnings("checkstyle:ForbidCertainMethod")
686 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
687 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
688 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
689 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
690 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
692 String interfaceName = elanInterface.getName();
693 String elanInstanceName = elanInterface.getElanInstanceName();
695 List<ListenableFuture<Void>> futures = new ArrayList<>();
696 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
697 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
698 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
699 if (elanInfo == null) {
700 List<String> elanInterfaces = new ArrayList<>();
701 elanInterfaces.add(interfaceName);
702 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
703 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
706 createElanStateList(elanInstanceName, interfaceName, operTx);
708 // Specific actions to the DPN where the ElanInterface has been added,
709 // for example, programming the
710 // External tunnel table if needed or adding the ElanInterface to the
711 // DpnInterfaces in the operational DS.
712 holder.dpId = interfaceInfo.getDpId();
713 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
714 // FIXME: use elanInstaince.key() instead?
715 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
718 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
719 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
720 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
721 if (ElanUtils.isVlan(elanInstance)) {
722 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
723 elanInstanceName, existingElanDpnInterfaces);
725 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
727 if (holder.isFirstInterfaceInDpn) {
728 // ELAN's 1st ElanInterface added to this DPN
729 if (!existingElanDpnInterfaces.isPresent()) {
730 holder.dpnInterfaces =
731 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
733 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
734 List<String> elanInterfaces =
735 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
736 elanInterfaces.add(interfaceName);
737 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
738 elanInterfaces, operTx);
740 // The 1st ElanInterface in a DPN must program the Ext Tunnel
741 // table, but only if Elan has VNI
742 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
743 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
744 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
746 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
749 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
750 List<String> elanInterfaces =
751 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
752 elanInterfaces.add(interfaceName);
753 if (elanInterfaces.size() == 1) { // 1st dpn interface
754 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
757 holder.dpnInterfaces =
758 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
765 // add code to install Local/Remote BC group, unknow DMAC entry,
766 // terminating service table flow entry
767 // call bindservice of interfacemanager to create ingress table flow
769 // Add interface to the ElanInterfaceForwardingEntires Container
770 createElanInterfaceTablesList(interfaceName, operTx);
772 futures.forEach(ElanUtils::waitForTransactionToComplete);
774 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
775 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
776 holder.isFirstInterfaceInDpn, confTx))));
778 // add the vlan provider interface to remote BC group for the elan
779 // for internal vlan networks
780 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
781 if (interfaceManager.isExternalInterface(interfaceName)) {
782 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
783 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
787 if (holder.isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
788 //update the remote-DPNs remoteBC group entry with Tunnels
789 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance,
792 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
793 confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInstance, holder.dpId, confTx))));
796 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
797 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
798 elanInterface, interfaceInfo, elanInstance, holder.isFirstInterfaceInDpn, this);
799 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
803 @SuppressWarnings("checkstyle:ForbidCertainMethod")
804 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
805 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
806 String elanInstanceName = elanInstance.getElanInstanceName();
807 String interfaceName = elanInterface.getName();
808 List<ListenableFuture<Void>> futures = new ArrayList<>();
809 BigInteger dpId = interfaceInfo.getDpId();
810 boolean isInterfaceOperational = isOperational(interfaceInfo);
811 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
812 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
813 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
814 isFirstInterfaceInDpn, confTx);
816 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
817 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
819 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
820 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
821 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
822 staticMacEntry.getMacAddress());
823 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
824 LogicalDatastoreType.OPERATIONAL, macId);
825 if (existingMacEntry.isPresent()) {
826 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
827 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
828 existingMacEntry.get(), operTx);
830 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
831 interfaceName, staticMacEntry, operTx);
834 if (isInterfaceOperational) {
835 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
837 String macAddress = staticMacEntry.getMacAddress().getValue();
839 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
841 macAddress, elanInstanceName, interfaceName);
842 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
843 staticMacEntry.getMacAddress().getValue(), true, confTx);
847 if (isInterfaceOperational) {
848 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
850 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
851 staticMacAddresses.add(staticMacEntry.getMacAddress());
853 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
859 futures.forEach(ElanUtils::waitForTransactionToComplete);
860 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
861 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
863 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
864 if (neutronPort != null) {
865 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
867 } catch (IllegalArgumentException ex) {
868 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
874 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
875 PhysAddress physAddress) {
876 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
877 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
878 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
879 LogicalDatastoreType.OPERATIONAL, macId);
881 if (!existingMacEntry.isPresent()) {
885 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
886 .withKey(new MacEntryKey(physAddress)).build();
887 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
888 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
891 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
892 Optional<DpnInterfaces> existingElanDpnInterfaces) {
893 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
894 if (!existingElanDpnInterfaces.isPresent()) {
897 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
900 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
901 int dummyInterfaceCount = 0;
902 List<String> interfaces = dpnInterfaces.getInterfaces();
903 if (interfaces == null) {
906 if (interfaces.contains(routerPortUuid)) {
907 dummyInterfaceCount++;
909 if (interfaces.contains(elanInstanceName)) {
910 dummyInterfaceCount++;
912 return interfaces.size() == dummyInterfaceCount;
915 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
916 PhysAddress physAddress) {
917 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
918 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
921 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
922 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
923 if (!isOperational(interfaceInfo)) {
926 BigInteger dpId = interfaceInfo.getDpId();
927 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
928 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
930 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
931 if (isFirstInterfaceInDpn) {
932 // Terminating Service , UnknownDMAC Table.
933 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
934 // for ELAN Instance is VxLAN
935 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
936 setupTerminateServiceTable(elanInstance, dpId, confTx);
938 setupUnknownDMacTable(elanInstance, dpId, confTx);
940 * Install remote DMAC flow. This is required since this DPN is
941 * added later to the elan instance and remote DMACs of other
942 * interfaces in this elan instance are not present in the current
945 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
946 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
947 elanInstance.getElanInstanceName());
948 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
951 // bind the Elan service to the Interface
952 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
955 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
956 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
957 if (!isOperational(interfaceInfo)) {
960 // LocalBroadcast Group creation with elan-Interfaces
961 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
962 if (isFirstInterfaceInDpn) {
963 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
964 BigInteger dpId = interfaceInfo.getDpId();
965 // RemoteBroadcast Group creation
967 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
968 } catch (InterruptedException e1) {
969 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
971 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId, confTx);
973 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
974 } catch (InterruptedException e1) {
975 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
980 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
981 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
982 int ifTag = interfaceInfo.getInterfaceTag();
983 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
984 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
985 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
986 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
987 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
989 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
991 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
992 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
993 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
994 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
996 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
999 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1000 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1001 int ifTag = interfaceInfo.getInterfaceTag();
1002 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1003 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1005 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1007 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1008 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1009 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1010 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1012 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1015 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId,
1016 TypedWriteTransaction<Configuration> confTx) {
1017 int elanTag = elanInfo.getElanTag().intValue();
1018 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1019 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId, confTx);
1020 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1021 if (etreeInstance != null) {
1022 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
1023 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1024 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId, confTx);
1028 @SuppressWarnings("checkstyle:IllegalCatch")
1029 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId,
1030 TypedWriteTransaction<Configuration> confTx) {
1032 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1033 if (elanDpns != null) {
1034 List<DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1035 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1036 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1037 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1038 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1039 List<Action> listAction = new ArrayList<>();
1041 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1042 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1043 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1045 for (DpnInterfaces otherFes : dpnInterfaces) {
1046 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1047 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1048 && !otherFes.getInterfaces().isEmpty()) {
1050 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1051 dpnInterface.getDpId(), otherFes.getDpId(),
1052 elanUtils.isOpenstackVniSemanticsEnforced()
1053 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1054 if (!remoteListActionInfo.isEmpty()) {
1055 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1056 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1059 } catch (Exception ex) {
1060 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1061 + "Logical Group Interface not found between source Dpn - {}, "
1062 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1067 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1068 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1069 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1071 if (remoteListBucketInfo.isEmpty()) {
1072 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1075 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1076 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1077 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1078 mdsalManager.addGroup(confTx, dpnInterface.getDpId(), group);
1082 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1083 } catch (InterruptedException e1) {
1084 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1089 private static List<MatchInfo> buildMatchesForVni(Long vni) {
1090 List<MatchInfo> mkMatches = new ArrayList<>();
1091 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1092 mkMatches.add(match);
1096 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1097 List<InstructionInfo> mkInstructions = new ArrayList<>();
1098 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1099 return mkInstructions;
1102 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1103 List<MatchInfo> mkMatches = new ArrayList<>();
1104 // Matching metadata
1105 mkMatches.add(new MatchMetadata(
1106 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1111 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1112 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1115 * elanTag to be written in metadata when flow is selected
1116 * @return the instructions ready to be installed in a flow
1118 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1119 List<InstructionInfo> mkInstructions = new ArrayList<>();
1120 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1121 .getElanMetadataMask()));
1122 /* applicable for EXTERNAL_TUNNEL_TABLE only
1123 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1125 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1126 return mkInstructions;
1129 // Install DMAC entry on dst DPN
1130 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1131 BigInteger dstDpId) {
1132 String interfaceName = interfaceInfo.getInterfaceName();
1133 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1134 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1135 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1136 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1137 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1138 for (MacEntry macEntry : macEntries) {
1139 String macAddress = macEntry.getMacAddress().getValue();
1140 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1142 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag(), macAddress,
1143 interfaceInfo.getDpId())) {
1144 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1146 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1154 private static void createDropBucket(List<Bucket> listBucket) {
1155 List<Action> actionsInfos = new ArrayList<>();
1156 actionsInfos.add(new ActionDrop().buildAction());
1157 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1158 MDSALUtil.WATCH_GROUP);
1159 listBucket.add(dropBucket);
1162 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1163 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1164 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1165 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1168 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1169 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1170 List<Bucket> listBucket = new ArrayList<>();
1172 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1174 List<String> interfaces = new ArrayList<>();
1175 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1176 interfaces = newDpnInterface.getInterfaces();
1178 for (String ifName : interfaces) {
1179 // In case if there is a InterfacePort in the cache which is not in
1180 // operational state, skip processing it
1181 InterfaceInfo ifInfo = interfaceManager
1182 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1183 if (!isOperational(ifInfo)) {
1187 if (!interfaceManager.isExternalInterface(ifName)) {
1188 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1189 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1194 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1195 MDSALUtil.buildBucketLists(listBucket));
1196 LOG.trace("installing the localBroadCast Group:{}", group);
1197 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1200 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1201 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1202 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1203 if (etreeInstance != null) {
1204 List<Bucket> listBucket = new ArrayList<>();
1207 List<String> interfaces = new ArrayList<>();
1208 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1209 interfaces = newDpnInterface.getInterfaces();
1211 for (String ifName : interfaces) {
1212 // In case if there is a InterfacePort in the cache which is not
1214 // operational state, skip processing it
1215 InterfaceInfo ifInfo = interfaceManager
1216 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1217 if (!isOperational(ifInfo)) {
1221 if (!interfaceManager.isExternalInterface(ifName)) {
1222 // only add root interfaces
1223 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1227 if (listBucket.isEmpty()) { // No Buckets
1228 createDropBucket(listBucket);
1231 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1232 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1233 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1234 MDSALUtil.buildBucketLists(listBucket));
1235 LOG.trace("installing the localBroadCast Group:{}", group);
1236 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1240 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1241 InterfaceInfo ifInfo) {
1242 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1243 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1244 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1245 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1251 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1252 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1253 throws ExecutionException, InterruptedException {
1254 BigInteger dpnId = interfaceInfo.getDpId();
1255 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1256 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1257 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1260 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1261 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1262 throws ExecutionException, InterruptedException {
1263 BigInteger dpnId = interfaceInfo.getDpId();
1264 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1265 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1266 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1270 * Installs a flow in the External Tunnel table consisting in translating
1271 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1272 * elanTag that will be used later in the ELANs pipeline.
1273 * @param dpnId the dpn id
1275 private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1276 TypedWriteTransaction<Configuration> confTx) {
1277 long elanTag = elanInfo.getElanTag();
1278 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1279 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1280 elanInfo.getElanInstanceName(), // flowName
1283 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1284 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1285 getInstructionsIntOrExtTunnelTable(elanTag));
1287 mdsalManager.addFlow(confTx, flowEntity);
1291 * Removes, from External Tunnel table, the flow that translates from VNI to
1292 * elanTag. Important: ensure this method is only called whenever there is
1293 * no other ElanInterface in the specified DPN
1295 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1297 private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1298 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1299 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1300 // last ElanInstance plus
1301 // adding a new one does (almost at the same time) are executed in that
1304 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1305 FlowEntity flowEntity = new FlowEntityBuilder()
1307 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1310 mdsalManager.removeFlow(confTx, flowEntity);
1313 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1314 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1315 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1316 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1319 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1320 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1321 List<? extends MatchInfoBase> listMatchInfoBase;
1322 List<InstructionInfo> instructionInfos;
1324 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1325 serviceId = elanTag;
1326 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1327 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1329 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1330 listMatchInfoBase = buildMatchesForVni(serviceId);
1331 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1333 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1334 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1335 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1337 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1340 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1341 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1342 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1343 if (etreeInstance != null) {
1344 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1348 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
1349 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1350 long elanTag = elanInfo.getElanTag();
1351 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1352 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1353 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1356 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1357 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1358 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1359 if (etreeLeafTag != null) {
1360 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1361 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1362 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1366 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1367 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1368 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1369 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1370 5, elanInfo.getElanInstanceName(), 0, 0,
1371 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1372 getMatchesForElanTag(elanTag, /* SH flag */false),
1373 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1375 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1378 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1379 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1380 // only if ELAN can connect to external network, perform the following
1382 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1383 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1384 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1385 5, elanInfo.getElanInstanceName(), 0, 0,
1386 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1387 getMatchesForElanTag(elanTag, /* SH flag */true),
1388 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1389 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1394 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
1395 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1396 throws ExecutionException, InterruptedException {
1397 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1398 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1399 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1401 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1402 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1403 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1405 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1409 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1410 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1413 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1414 TypedWriteTransaction<Configuration> tx) {
1415 if (isStandardElanService(elanInterface)) {
1416 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1417 elanInterface.getName(), lportTag, tx);
1418 } else { // Etree service
1419 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1423 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1424 TypedWriteTransaction<Configuration> tx) {
1425 int instructionKey = 0;
1426 List<Instruction> instructions = new ArrayList<>();
1427 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1428 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1430 List<Action> actions = new ArrayList<>();
1431 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1432 lportTag).buildAction());
1433 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1434 elanTag).buildAction());
1435 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1437 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1440 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1441 BoundServices serviceInfo = ElanUtils.getBoundServices(
1442 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1443 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1444 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1445 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1447 if (!existingElanService.isPresent()) {
1448 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1452 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1453 TypedWriteTransaction<Configuration> tx) {
1454 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1455 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1458 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1459 if (etreeInstance == null) {
1460 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1461 elanInterface.getName(), elanInfo.getElanInstanceName());
1463 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1464 elanInterface.getName(), lportTag, tx);
1469 private static boolean isStandardElanService(ElanInterface elanInterface) {
1470 return elanInterface.augmentation(EtreeInterface.class) == null;
1473 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1474 throws ExecutionException, InterruptedException {
1475 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1476 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1477 if (tx.read(bindServiceId).get().isPresent()) {
1478 tx.delete(bindServiceId);
1482 private static String getFlowRef(long tableId, long elanTag) {
1483 return String.valueOf(tableId) + elanTag;
1486 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1487 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1488 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1491 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1492 return String.valueOf(tableId) + elanTag + shFlag;
1495 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1496 List<Action> listAction = new ArrayList<>();
1499 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1501 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1505 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1506 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1507 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1508 .withKey(new DpnInterfacesKey(dpId)).build();
1509 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1510 CREATE_MISSING_PARENTS);
1511 return dpnInterface;
1515 * Delete elan dpn interface from operational DS.
1517 * @param elanInstanceName
1518 * the elan instance name
1522 private static void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
1523 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1524 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1525 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1526 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1527 if (dpnInterfaces.isPresent()) {
1528 tx.delete(dpnInterfacesId);
1532 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1533 BigInteger dpId, TypedWriteTransaction<Operational> tx) {
1534 List<String> interfaceNames = new ArrayList<>();
1535 interfaceNames.add(interfaceName);
1536 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1537 .withKey(new DpnInterfacesKey(dpId)).build();
1538 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1539 CREATE_MISSING_PARENTS);
1540 return dpnInterface;
1543 private static void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1544 throws ExecutionException, InterruptedException {
1545 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1546 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1547 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1548 // Adding new Elan Interface Port to the operational DataStore without
1549 // Static-Mac Entries..
1550 if (!interfaceMacTables.isPresent()) {
1551 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1552 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1553 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1554 CREATE_MISSING_PARENTS);
1558 private static void createElanStateList(String elanInstanceName, String interfaceName,
1559 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1560 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1561 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1562 // Adding new Elan Interface Port to the operational DataStore without
1563 // Static-Mac Entries..
1564 if (elanInterfaceLists.isPresent()) {
1565 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1566 if (interfaceLists == null) {
1567 interfaceLists = new ArrayList<>();
1569 interfaceLists.add(interfaceName);
1570 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1571 .withKey(new ElanKey(elanInstanceName)).build();
1572 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1576 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1577 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1580 @SuppressWarnings("checkstyle:IllegalCatch")
1581 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1582 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1583 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1584 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1585 if (dpnInterfaceLists == null) {
1588 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1589 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1591 String elanName = elanDpns.getElanInstanceName();
1592 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1593 if (elanInfo == null) {
1594 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1595 + "skipping this ELAN for tunnel handling", elanName);
1598 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1599 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1602 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1603 if (dpnInterfaces == null) {
1606 DpnInterfaces dstDpnIf = null;
1607 for (DpnInterfaces dpnIf : dpnInterfaces) {
1608 BigInteger dpnIfDpId = dpnIf.getDpId();
1609 if (Objects.equals(dpnIfDpId, srcDpId)) {
1611 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1617 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1618 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1619 jobCoordinator.enqueueJob(elanName, () -> {
1620 // update Remote BC Group
1621 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1623 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1624 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1626 } catch (RuntimeException e) {
1627 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1629 Set<String> interfaceLists = new HashSet<>();
1630 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1631 for (String ifName : interfaceLists) {
1632 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1633 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1634 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1635 if (isOperational(interfaceInfo)) {
1636 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1639 }, ElanConstants.JOB_MAX_RETRIES);
1642 }, ElanConstants.JOB_MAX_RETRIES);
1649 * Handle external tunnel state event.
1651 * @param externalTunnel
1652 * the external tunnel
1656 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1657 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1660 // dpId/externalNodeId will be available either in source or destination
1661 // based on the tunnel end point
1662 BigInteger dpId = null;
1663 NodeId externalNodeId = null;
1664 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1665 dpId = new BigInteger(externalTunnel.getSourceDevice());
1666 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1667 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1668 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1669 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1671 if (dpId == null || externalNodeId == null) {
1672 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1676 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1677 if (dpnInterfaceLists == null) {
1680 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1681 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1682 String elanName = elanDpns.getElanInstanceName();
1683 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1685 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1686 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1687 || dpnInterfaces.getInterfaces().isEmpty()) {
1690 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1692 final BigInteger finalDpId = dpId;
1693 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1694 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1695 "Error setting up ELAN BGs");
1696 // install L2gwDevices local macs in dpn.
1697 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1698 // Install dpn macs on external device
1699 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1702 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1706 * Installs dpn macs in external device. first it checks if the physical
1707 * locator towards this dpn tep is present or not if the physical locator is
1708 * present go ahead and add the ucast macs otherwise update the mcast mac
1709 * entry to include this dpn tep ip and schedule the job to put ucast macs
1710 * once the physical locator is programmed in device
1714 * @param lstElanInterfaceNames
1715 * the lst Elan interface names
1718 * @param externalNodeId
1719 * the external node id
1721 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1722 NodeId externalNodeId) {
1723 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1724 externalNodeId.getValue());
1725 if (elanL2GwDevice == null) {
1726 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1729 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1730 if (dpnTepIp == null) {
1731 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1736 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1737 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1738 LogicalDatastoreType.OPERATIONAL);
1739 boolean phyLocAlreadyExists =
1740 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1742 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1743 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1744 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1746 if (phyLocAlreadyExists) {
1747 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1750 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1751 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1755 * Validate external tunnel state event.
1757 * @param externalTunnel
1758 * the external tunnel
1761 * @return true, if successful
1763 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1764 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1765 String srcDevice = externalTunnel.getDestinationDevice();
1766 String destDevice = externalTunnel.getSourceDevice();
1767 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1768 LogicalDatastoreType.CONFIGURATION);
1769 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1770 otherEndPointExtTunnel);
1771 if (otherEndPointExtTunnel != null) {
1772 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1773 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1774 if (otherEndPointInterfaceOperational) {
1777 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1778 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1785 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1786 List<MatchInfo> mkMatches = new ArrayList<>();
1787 // Matching metadata
1789 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1790 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1795 protected ElanInterfaceManager getDataTreeChangeListener() {
1799 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1801 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1802 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1803 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1804 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1806 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1807 } catch (InterruptedException e) {
1808 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);