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.netvirt.elan.cache.ElanInstanceCache;
76 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
77 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
78 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
79 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
80 import org.opendaylight.netvirt.elan.utils.ElanConstants;
81 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
82 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
83 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
84 import org.opendaylight.netvirt.elan.utils.ElanUtils;
85 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
86 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
87 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
88 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
89 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
90 import org.opendaylight.serviceutils.srm.RecoverableListener;
91 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
92 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
93 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
94 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
135 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
136 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
137 import org.slf4j.Logger;
138 import org.slf4j.LoggerFactory;
141 * Class in charge of handling creations, modifications and removals of
144 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
147 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
148 implements RecoverableListener {
149 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
150 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
151 private static final boolean SH_FLAG_SET = true;
152 private static final boolean SH_FLAG_UNSET = false;
154 private final DataBroker broker;
155 private final ManagedNewTransactionRunner txRunner;
156 private final IMdsalApiManager mdsalManager;
157 private final IInterfaceManager interfaceManager;
158 private final IdManagerService idManager;
159 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
160 private final INeutronVpnManager neutronVpnManager;
161 private final ElanItmUtils elanItmUtils;
162 private final ElanEtreeUtils elanEtreeUtils;
163 private final ElanL2GatewayUtils elanL2GatewayUtils;
164 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
165 private final ElanUtils elanUtils;
166 private final JobCoordinator jobCoordinator;
167 private final ElanInstanceCache elanInstanceCache;
168 private final ElanInterfaceCache elanInterfaceCache;
170 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
171 unProcessedElanInterfaces = new ConcurrentHashMap<>();
174 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
175 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
176 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
177 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
178 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
179 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
180 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
181 final ElanInstanceCache elanInstanceCache,
182 final ElanInterfaceCache elanInterfaceCache,
183 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
184 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
185 super(ElanInterface.class, ElanInterfaceManager.class);
186 this.broker = dataBroker;
187 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
188 this.idManager = managerService;
189 this.mdsalManager = mdsalApiManager;
190 this.interfaceManager = interfaceManager;
191 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
192 this.neutronVpnManager = neutronVpnManager;
193 this.elanItmUtils = elanItmUtils;
194 this.elanEtreeUtils = elanEtreeUtils;
195 this.elanL2GatewayUtils = elanL2GatewayUtils;
196 this.elanUtils = elanUtils;
197 this.jobCoordinator = jobCoordinator;
198 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
199 this.elanInstanceCache = elanInstanceCache;
200 this.elanInterfaceCache = elanInterfaceCache;
201 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
211 public void registerListener() {
212 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
216 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
217 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
221 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
222 String interfaceName = del.getName();
223 String elanInstanceName = del.getElanInstanceName();
224 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
225 if (elanInterfaces != null && elanInterfaces.contains(del)) {
226 elanInterfaces.remove(del);
227 if (elanInterfaces.isEmpty()) {
228 unProcessedElanInterfaces.remove(elanInstanceName);
231 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
233 * Handling in case the elan instance is deleted.If the Elan instance is
234 * deleted, there is no need to explicitly delete the elan interfaces
236 if (elanInfo == null) {
239 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
240 if (interfaceInfo == null && elanInfo.isExternal()) {
241 // In deleting external network, the underlying ietf Inteface might have been removed
242 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
243 // from Operational DS instead
244 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
246 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
247 interfaceName, interfaceInfo, this);
248 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
251 private static class RemoveElanInterfaceHolder {
252 boolean isLastElanInterface = false;
253 boolean isLastInterfaceOnDpn = false;
254 BigInteger dpId = null;
257 @SuppressWarnings("checkstyle:ForbidCertainMethod")
258 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
259 InterfaceInfo interfaceInfo) {
260 String elanName = elanInfo.getElanInstanceName();
261 long elanTag = elanInfo.getElanTag();
262 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
263 List<ListenableFuture<Void>> futures = new ArrayList<>();
264 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
265 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
266 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
267 if (elanState == null) {
270 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
271 List<String> elanInterfaces = elanState.getElanInterfaces();
272 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
273 holder.isLastElanInterface = true;
275 if (interfaceInfo != null) {
276 holder.dpId = interfaceInfo.getDpId();
277 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
278 interfaceName, elanTag, interfaceTx);
280 * If there are not elan ports, remove the unknown dmac, terminating
281 * service table flows, remote/local bc group
283 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
284 || dpnInterfaces.getInterfaces().isEmpty()) {
285 // No more Elan Interfaces in this DPN
286 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
288 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
289 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag());
291 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag());
292 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
293 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
294 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
295 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
296 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
297 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
298 elanUtils.removeTerminatingServiceAction(holder.dpId,
299 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
301 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
303 holder.isLastInterfaceOnDpn = true;
305 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
310 futures.forEach(ElanUtils::waitForTransactionToComplete);
312 if (holder.isLastInterfaceOnDpn && holder.dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
314 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
315 confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInfo, holder.dpId, confTx))));
317 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
318 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
319 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
320 ElanConstants.JOB_MAX_RETRIES);
325 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
326 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
327 throws ExecutionException, InterruptedException {
328 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
329 if (etreeLeafTag != null) {
330 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
331 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
335 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
336 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
337 throws ExecutionException, InterruptedException {
338 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
339 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
342 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
343 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
344 throws ExecutionException, InterruptedException {
345 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
346 if (etreeInstance != null) {
347 BigInteger dpnId = interfaceInfo.getDpId();
348 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
349 LOG.trace("deleted the localBroadCast Group:{}", groupId);
350 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
354 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
355 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
356 throws ExecutionException, InterruptedException {
357 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
358 if (etreeInstance != null) {
359 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
360 BigInteger dpnId = interfaceInfo.getDpId();
361 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
362 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
363 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
367 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
368 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
369 String elanName = elanInfo.getElanInstanceName();
370 Elan elanState = ElanUtils.getElanByName(tx, elanName);
371 if (elanState == null) {
374 List<String> elanInterfaces = elanState.getElanInterfaces();
375 boolean isRemoved = elanInterfaces != null && elanInterfaces.remove(interfaceName);
380 if (elanInterfaces.isEmpty()) {
381 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
382 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
383 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
384 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
386 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
387 .withKey(new ElanKey(elanName)).build();
388 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
393 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
394 throws ReadFailedException {
395 // removing the ElanInterface from the config data_store if interface is
396 // not present in Interface config DS
397 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
398 interfaceName) == null
399 && elanInterfaceCache.get(interfaceName).isPresent()) {
400 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
404 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
405 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
406 String elanName = elanInfo.getElanInstanceName();
407 List<ListenableFuture<Void>> futures = new ArrayList<>();
408 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
409 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
410 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
411 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
412 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
413 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
414 if (interfaceInfo != null) {
415 if (existingElanInterfaceMac.isPresent()) {
416 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
417 if (existingMacEntries != null) {
418 List<PhysAddress> macAddresses = new ArrayList<>();
419 for (MacEntry macEntry : existingMacEntries) {
420 PhysAddress macAddress = macEntry.getMacAddress();
421 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
422 macAddress.getValue(), interfaceName);
423 Optional<MacEntry> macEntryOptional =
424 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
425 if (!isLastElanInterface && macEntryOptional.isPresent()) {
426 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
428 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
429 macAddresses.add(macAddress);
432 // Removing all those MACs from External Devices belonging
434 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
435 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
439 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
440 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
441 } else if (existingElanInterfaceMac.isPresent()) {
442 // Interface does not exist in ConfigDS, so lets remove everything
443 // about that interface related to Elan
444 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
445 if (macEntries != null) {
446 for (MacEntry macEntry : macEntries) {
447 PhysAddress macAddress = macEntry.getMacAddress();
448 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
449 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
454 if (existingElanInterfaceMac.isPresent()) {
455 interfaceTx.delete(elanInterfaceId);
457 unbindService(interfaceName, flowTx);
458 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
464 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
465 String interfaceName, long elanTag,
466 TypedReadWriteTransaction<Operational> tx)
467 throws ExecutionException, InterruptedException {
468 // FIXME: pass in and use ElanInstanceKey instead?
469 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
472 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
473 if (dpnInterfaces != null) {
474 List<String> interfaceLists = dpnInterfaces.getInterfaces();
475 if (interfaceLists != null) {
476 interfaceLists.remove(interfaceName);
479 if (interfaceLists == null || interfaceLists.isEmpty()) {
480 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
481 deleteElanDpnInterface(elanName, dpId, tx);
483 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
486 return dpnInterfaces;
492 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
493 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
494 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
495 for (DpnInterfaces dpnInterface : dpnInterfaces) {
496 BigInteger currentDpId = dpnInterface.getDpId();
497 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
498 for (String elanInterface : dpnInterface.getInterfaces()) {
499 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
500 if (macs == null || macs.getMacEntry() == null) {
503 for (MacEntry mac : macs.getMacEntry()) {
504 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
505 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
510 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
513 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
514 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
515 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
516 if (etreeLeafTag != null) {
517 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac, confTx);
521 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
522 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
524 .removeFlow(confTx, dpId,
525 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
526 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
527 mac.getMacAddress().getValue(), elanTag)));
531 * Possible Scenarios for update
532 * a. if orig={1,2,3,4} and updated=null or updated={}
533 then all {1,2,3,4} should be removed
535 b. if orig=null or orig={} and updated ={1,2,3,4}
536 then all {1,2,3,4} should be added
538 c. if orig = {1,2,3,4} updated={2,3,4}
539 then 1 should be removed
541 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
542 then we should just add 5
544 e. if orig = {1,2,3,4} updated={2,3,4,5}
545 then 1 should be removed , 5 should be added
547 @SuppressWarnings("checkstyle:ForbidCertainMethod")
549 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
550 // updating the static-Mac Entries for the existing elanInterface
551 String elanName = update.getElanInstanceName();
552 String interfaceName = update.getName();
554 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
555 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
556 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
557 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
559 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
560 deletedEntry.getMacAddress()));
562 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
563 * Hence add the macentries for the same.*/
564 for (StaticMacEntries staticMacEntry : updatedEntries) {
565 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
566 staticMacEntry.getMacAddress());
567 addErrorLogging(ElanUtils.waitForTransactionToComplete(
568 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
569 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
570 if (existingMacEntry.isPresent()) {
571 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
572 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
575 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
576 elanName, interfaceName, staticMacEntry, tx);
578 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
583 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
584 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
585 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
586 String interfaceName = elanInterfaceAdded.getName();
587 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
588 if (interfaceInfo == null) {
589 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
592 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
594 if (elanInstance == null) {
595 // Add the ElanInstance in the Configuration data-store
596 List<String> elanInterfaces = new ArrayList<>();
597 elanInterfaces.add(interfaceName);
598 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
599 confTx -> ElanUtils.updateOperationalDataStore(idManager,
600 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
601 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
604 Long elanTag = elanInstance.getElanTag();
605 // If elan tag is not updated, then put the elan interface into
606 // unprocessed entry map and entry. Let entries
607 // in this map get processed during ELAN update DCN.
608 if (elanTag == null || elanTag == 0L) {
609 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
610 if (elanInterfaces == null) {
611 elanInterfaces = new ConcurrentLinkedQueue<>();
613 if (!elanInterfaces.contains(elanInterfaceAdded)) {
614 elanInterfaces.add(elanInterfaceAdded);
616 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
619 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
620 interfaceInfo, elanInstance, this);
621 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
622 }), LOG, "Error processing added ELAN interface");
625 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
626 List<ListenableFuture<Void>> futures = new ArrayList<>();
627 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
628 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
631 for (ElanInterface elanInterface : elanInterfaces) {
632 String interfaceName = elanInterface.getName();
633 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
634 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
636 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
640 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
641 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
642 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
643 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
644 List<DpnInterfaces> dpnInterfaceLists = null;
645 if (elanDpnInterfacesList != null) {
646 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
648 if (dpnInterfaceLists == null) {
649 dpnInterfaceLists = new ArrayList<>();
651 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
652 BigInteger dstDpId = interfaceInfo.getDpId();
653 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
656 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
657 for (String remoteIf : remoteElanInterfaces) {
658 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
659 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
660 if (elanIfMac == null || remoteInterface == null) {
663 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
664 if (remoteMacEntries != null) {
665 for (MacEntry macEntry : remoteMacEntries) {
666 String macAddress = macEntry.getMacAddress().getValue();
667 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
668 dstDpId, elanInstance.getElanInstanceName());
669 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
670 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
671 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
678 private static class AddElanInterfaceHolder {
679 private DpnInterfaces dpnInterfaces = null;
680 private boolean isFirstInterfaceInDpn = false;
681 private BigInteger dpId;
684 @SuppressWarnings("checkstyle:ForbidCertainMethod")
685 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
686 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
687 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
688 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
689 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
691 String interfaceName = elanInterface.getName();
692 String elanInstanceName = elanInterface.getElanInstanceName();
694 List<ListenableFuture<Void>> futures = new ArrayList<>();
695 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
696 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
697 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
698 if (elanInfo == null) {
699 List<String> elanInterfaces = new ArrayList<>();
700 elanInterfaces.add(interfaceName);
701 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
702 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
705 createElanStateList(elanInstanceName, interfaceName, operTx);
707 // Specific actions to the DPN where the ElanInterface has been added,
708 // for example, programming the
709 // External tunnel table if needed or adding the ElanInterface to the
710 // DpnInterfaces in the operational DS.
711 holder.dpId = interfaceInfo.getDpId();
712 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
713 // FIXME: use elanInstaince.key() instead?
714 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
717 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
718 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
719 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
720 if (ElanUtils.isVlan(elanInstance)) {
721 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
722 elanInstanceName, existingElanDpnInterfaces);
724 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
726 if (holder.isFirstInterfaceInDpn) {
727 // ELAN's 1st ElanInterface added to this DPN
728 if (!existingElanDpnInterfaces.isPresent()) {
729 holder.dpnInterfaces =
730 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
732 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
733 List<String> elanInterfaces =
734 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
735 elanInterfaces.add(interfaceName);
736 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
737 elanInterfaces, operTx);
739 // The 1st ElanInterface in a DPN must program the Ext Tunnel
740 // table, but only if Elan has VNI
741 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
742 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
743 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
745 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
748 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
749 List<String> elanInterfaces =
750 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
751 elanInterfaces.add(interfaceName);
752 if (elanInterfaces.size() == 1) { // 1st dpn interface
753 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
756 holder.dpnInterfaces =
757 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
764 // add code to install Local/Remote BC group, unknow DMAC entry,
765 // terminating service table flow entry
766 // call bindservice of interfacemanager to create ingress table flow
768 // Add interface to the ElanInterfaceForwardingEntires Container
769 createElanInterfaceTablesList(interfaceName, operTx);
771 futures.forEach(ElanUtils::waitForTransactionToComplete);
773 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
774 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
775 holder.isFirstInterfaceInDpn, confTx))));
777 // add the vlan provider interface to remote BC group for the elan
778 // for internal vlan networks
779 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
780 if (interfaceManager.isExternalInterface(interfaceName)) {
781 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
782 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
786 if (holder.isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
787 //update the remote-DPNs remoteBC group entry with Tunnels
788 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance,
791 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
792 confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInstance, holder.dpId, confTx))));
795 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
796 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
797 elanInterface, interfaceInfo, elanInstance, holder.isFirstInterfaceInDpn, this);
798 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
802 @SuppressWarnings("checkstyle:ForbidCertainMethod")
803 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
804 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
805 String elanInstanceName = elanInstance.getElanInstanceName();
806 String interfaceName = elanInterface.getName();
807 List<ListenableFuture<Void>> futures = new ArrayList<>();
808 BigInteger dpId = interfaceInfo.getDpId();
809 boolean isInterfaceOperational = isOperational(interfaceInfo);
810 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
811 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
812 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
813 isFirstInterfaceInDpn, confTx);
815 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
816 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
818 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
819 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
820 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
821 staticMacEntry.getMacAddress());
822 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
823 LogicalDatastoreType.OPERATIONAL, macId);
824 if (existingMacEntry.isPresent()) {
825 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
826 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
827 existingMacEntry.get(), operTx);
829 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
830 interfaceName, staticMacEntry, operTx);
833 if (isInterfaceOperational) {
834 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
836 String macAddress = staticMacEntry.getMacAddress().getValue();
838 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
840 macAddress, elanInstanceName, interfaceName);
841 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
842 staticMacEntry.getMacAddress().getValue(), true, confTx);
846 if (isInterfaceOperational) {
847 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
849 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
850 staticMacAddresses.add(staticMacEntry.getMacAddress());
852 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
858 futures.forEach(ElanUtils::waitForTransactionToComplete);
859 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
860 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
862 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
863 if (neutronPort != null) {
864 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
866 } catch (IllegalArgumentException ex) {
867 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
873 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
874 PhysAddress physAddress) {
875 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
876 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
877 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
878 LogicalDatastoreType.OPERATIONAL, macId);
880 if (!existingMacEntry.isPresent()) {
884 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
885 .withKey(new MacEntryKey(physAddress)).build();
886 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
887 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
890 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
891 Optional<DpnInterfaces> existingElanDpnInterfaces) {
892 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
893 if (!existingElanDpnInterfaces.isPresent()) {
896 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
899 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
900 int dummyInterfaceCount = 0;
901 List<String> interfaces = dpnInterfaces.getInterfaces();
902 if (interfaces == null) {
905 if (interfaces.contains(routerPortUuid)) {
906 dummyInterfaceCount++;
908 if (interfaces.contains(elanInstanceName)) {
909 dummyInterfaceCount++;
911 return interfaces.size() == dummyInterfaceCount;
914 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
915 PhysAddress physAddress) {
916 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
917 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
920 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
921 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
922 if (!isOperational(interfaceInfo)) {
925 BigInteger dpId = interfaceInfo.getDpId();
926 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
927 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
929 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
930 if (isFirstInterfaceInDpn) {
931 // Terminating Service , UnknownDMAC Table.
932 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
933 // for ELAN Instance is VxLAN
934 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
935 setupTerminateServiceTable(elanInstance, dpId, confTx);
937 setupUnknownDMacTable(elanInstance, dpId, confTx);
939 * Install remote DMAC flow. This is required since this DPN is
940 * added later to the elan instance and remote DMACs of other
941 * interfaces in this elan instance are not present in the current
944 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
945 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
946 elanInstance.getElanInstanceName());
947 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
950 // bind the Elan service to the Interface
951 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
954 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
955 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
956 if (!isOperational(interfaceInfo)) {
959 // LocalBroadcast Group creation with elan-Interfaces
960 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
961 if (isFirstInterfaceInDpn) {
962 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
963 BigInteger dpId = interfaceInfo.getDpId();
964 // RemoteBroadcast Group creation
966 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
967 } catch (InterruptedException e1) {
968 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
970 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId, confTx);
972 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
973 } catch (InterruptedException e1) {
974 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
979 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
980 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
981 int ifTag = interfaceInfo.getInterfaceTag();
982 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
983 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
984 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
985 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
986 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
988 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
990 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
991 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
992 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
993 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
995 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
998 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
999 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1000 int ifTag = interfaceInfo.getInterfaceTag();
1001 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1002 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1004 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1006 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1007 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1008 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1009 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1011 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1014 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId,
1015 TypedWriteTransaction<Configuration> confTx) {
1016 int elanTag = elanInfo.getElanTag().intValue();
1017 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1018 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId, confTx);
1019 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1020 if (etreeInstance != null) {
1021 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
1022 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1023 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId, confTx);
1027 @SuppressWarnings("checkstyle:IllegalCatch")
1028 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId,
1029 TypedWriteTransaction<Configuration> confTx) {
1031 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1032 if (elanDpns != null) {
1033 List<DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1034 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1035 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1036 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1037 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1038 List<Action> listAction = new ArrayList<>();
1040 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1041 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1042 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1044 for (DpnInterfaces otherFes : dpnInterfaces) {
1045 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1046 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1047 && !otherFes.getInterfaces().isEmpty()) {
1049 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1050 dpnInterface.getDpId(), otherFes.getDpId(),
1051 elanUtils.isOpenstackVniSemanticsEnforced()
1052 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1053 if (!remoteListActionInfo.isEmpty()) {
1054 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1055 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1058 } catch (Exception ex) {
1059 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1060 + "Logical Group Interface not found between source Dpn - {}, "
1061 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1066 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1067 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1068 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1070 if (remoteListBucketInfo.isEmpty()) {
1071 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1074 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1075 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1076 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1077 mdsalManager.addGroup(confTx, dpnInterface.getDpId(), group);
1081 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1082 } catch (InterruptedException e1) {
1083 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1088 private static List<MatchInfo> buildMatchesForVni(Long vni) {
1089 List<MatchInfo> mkMatches = new ArrayList<>();
1090 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1091 mkMatches.add(match);
1095 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1096 List<InstructionInfo> mkInstructions = new ArrayList<>();
1097 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1098 return mkInstructions;
1101 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1102 List<MatchInfo> mkMatches = new ArrayList<>();
1103 // Matching metadata
1104 mkMatches.add(new MatchMetadata(
1105 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1110 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1111 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1114 * elanTag to be written in metadata when flow is selected
1115 * @return the instructions ready to be installed in a flow
1117 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1118 List<InstructionInfo> mkInstructions = new ArrayList<>();
1119 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1120 .getElanMetadataMask()));
1121 /* applicable for EXTERNAL_TUNNEL_TABLE only
1122 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1124 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1125 return mkInstructions;
1128 // Install DMAC entry on dst DPN
1129 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1130 BigInteger dstDpId) {
1131 String interfaceName = interfaceInfo.getInterfaceName();
1132 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1133 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1134 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1135 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1136 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1137 for (MacEntry macEntry : macEntries) {
1138 String macAddress = macEntry.getMacAddress().getValue();
1139 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1141 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1142 interfaceInfo.getDpId())) {
1143 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1145 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1153 private static void createDropBucket(List<Bucket> listBucket) {
1154 List<Action> actionsInfos = new ArrayList<>();
1155 actionsInfos.add(new ActionDrop().buildAction());
1156 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1157 MDSALUtil.WATCH_GROUP);
1158 listBucket.add(dropBucket);
1161 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1162 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1163 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1164 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1167 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1168 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1169 List<Bucket> listBucket = new ArrayList<>();
1171 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1173 List<String> interfaces = new ArrayList<>();
1174 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1175 interfaces = newDpnInterface.getInterfaces();
1177 for (String ifName : interfaces) {
1178 // In case if there is a InterfacePort in the cache which is not in
1179 // operational state, skip processing it
1180 InterfaceInfo ifInfo = interfaceManager
1181 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1182 if (!isOperational(ifInfo)) {
1186 if (!interfaceManager.isExternalInterface(ifName)) {
1187 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1188 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1193 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1194 MDSALUtil.buildBucketLists(listBucket));
1195 LOG.trace("installing the localBroadCast Group:{}", group);
1196 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1199 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1200 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1201 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1202 if (etreeInstance != null) {
1203 List<Bucket> listBucket = new ArrayList<>();
1206 List<String> interfaces = new ArrayList<>();
1207 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1208 interfaces = newDpnInterface.getInterfaces();
1210 for (String ifName : interfaces) {
1211 // In case if there is a InterfacePort in the cache which is not
1213 // operational state, skip processing it
1214 InterfaceInfo ifInfo = interfaceManager
1215 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1216 if (!isOperational(ifInfo)) {
1220 if (!interfaceManager.isExternalInterface(ifName)) {
1221 // only add root interfaces
1222 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1226 if (listBucket.isEmpty()) { // No Buckets
1227 createDropBucket(listBucket);
1230 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1231 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1232 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1233 MDSALUtil.buildBucketLists(listBucket));
1234 LOG.trace("installing the localBroadCast Group:{}", group);
1235 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1239 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1240 InterfaceInfo ifInfo) {
1241 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1242 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1243 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1244 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1250 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1251 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1252 throws ExecutionException, InterruptedException {
1253 BigInteger dpnId = interfaceInfo.getDpId();
1254 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1255 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1256 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1259 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1260 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1261 throws ExecutionException, InterruptedException {
1262 BigInteger dpnId = interfaceInfo.getDpId();
1263 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1264 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1265 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1269 * Installs a flow in the External Tunnel table consisting in translating
1270 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1271 * elanTag that will be used later in the ELANs pipeline.
1272 * @param dpnId the dpn id
1274 private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1275 TypedWriteTransaction<Configuration> confTx) {
1276 long elanTag = elanInfo.getElanTag();
1277 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1278 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1279 elanInfo.getElanInstanceName(), // flowName
1282 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1283 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1284 getInstructionsIntOrExtTunnelTable(elanTag));
1286 mdsalManager.addFlow(confTx, flowEntity);
1290 * Removes, from External Tunnel table, the flow that translates from VNI to
1291 * elanTag. Important: ensure this method is only called whenever there is
1292 * no other ElanInterface in the specified DPN
1294 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1296 private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1297 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1298 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1299 // last ElanInstance plus
1300 // adding a new one does (almost at the same time) are executed in that
1303 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1304 FlowEntity flowEntity = new FlowEntityBuilder()
1306 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1309 mdsalManager.removeFlow(confTx, flowEntity);
1312 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1313 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1314 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1315 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1318 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1319 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1320 List<? extends MatchInfoBase> listMatchInfoBase;
1321 List<InstructionInfo> instructionInfos;
1323 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1324 serviceId = elanTag;
1325 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1326 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1328 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1329 listMatchInfoBase = buildMatchesForVni(serviceId);
1330 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1332 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1333 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1334 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1336 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1339 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1340 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1341 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1342 if (etreeInstance != null) {
1343 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1347 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
1348 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1349 long elanTag = elanInfo.getElanTag();
1350 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1351 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1352 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1355 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1356 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1357 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1358 if (etreeLeafTag != null) {
1359 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1360 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1361 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1365 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1366 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1367 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1368 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1369 5, elanInfo.getElanInstanceName(), 0, 0,
1370 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1371 getMatchesForElanTag(elanTag, /* SH flag */false),
1372 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1374 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1377 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1378 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1379 // only if ELAN can connect to external network, perform the following
1381 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1382 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1383 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1384 5, elanInfo.getElanInstanceName(), 0, 0,
1385 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1386 getMatchesForElanTag(elanTag, /* SH flag */true),
1387 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1388 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1393 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
1394 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1395 throws ExecutionException, InterruptedException {
1396 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1397 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1398 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1400 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1401 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1402 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1404 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1408 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1409 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1412 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1413 TypedWriteTransaction<Configuration> tx) {
1414 if (isStandardElanService(elanInterface)) {
1415 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1416 elanInterface.getName(), lportTag, tx);
1417 } else { // Etree service
1418 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1422 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1423 TypedWriteTransaction<Configuration> tx) {
1424 int instructionKey = 0;
1425 List<Instruction> instructions = new ArrayList<>();
1426 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1427 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1429 List<Action> actions = new ArrayList<>();
1430 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1431 lportTag).buildAction());
1432 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1433 elanTag).buildAction());
1434 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1436 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1439 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1440 BoundServices serviceInfo = ElanUtils.getBoundServices(
1441 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1442 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1443 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1444 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1446 if (!existingElanService.isPresent()) {
1447 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1451 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1452 TypedWriteTransaction<Configuration> tx) {
1453 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1454 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1457 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1458 if (etreeInstance == null) {
1459 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1460 elanInterface.getName(), elanInfo.getElanInstanceName());
1462 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1463 elanInterface.getName(), lportTag, tx);
1468 private static boolean isStandardElanService(ElanInterface elanInterface) {
1469 return elanInterface.augmentation(EtreeInterface.class) == null;
1472 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1473 throws ExecutionException, InterruptedException {
1474 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1475 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1476 if (tx.read(bindServiceId).get().isPresent()) {
1477 tx.delete(bindServiceId);
1481 private static String getFlowRef(long tableId, long elanTag) {
1482 return String.valueOf(tableId) + elanTag;
1485 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1486 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1487 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1490 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1491 return String.valueOf(tableId) + elanTag + shFlag;
1494 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1495 List<Action> listAction = new ArrayList<>();
1498 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1500 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1504 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1505 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1506 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1507 .withKey(new DpnInterfacesKey(dpId)).build();
1508 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1509 CREATE_MISSING_PARENTS);
1510 return dpnInterface;
1514 * Delete elan dpn interface from operational DS.
1516 * @param elanInstanceName
1517 * the elan instance name
1521 private static void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
1522 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1523 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1524 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1525 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1526 if (dpnInterfaces.isPresent()) {
1527 tx.delete(dpnInterfacesId);
1531 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1532 BigInteger dpId, TypedWriteTransaction<Operational> tx) {
1533 List<String> interfaceNames = new ArrayList<>();
1534 interfaceNames.add(interfaceName);
1535 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1536 .withKey(new DpnInterfacesKey(dpId)).build();
1537 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1538 CREATE_MISSING_PARENTS);
1539 return dpnInterface;
1542 private static void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1543 throws ExecutionException, InterruptedException {
1544 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1545 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1546 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1547 // Adding new Elan Interface Port to the operational DataStore without
1548 // Static-Mac Entries..
1549 if (!interfaceMacTables.isPresent()) {
1550 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1551 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1552 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1553 CREATE_MISSING_PARENTS);
1557 private static void createElanStateList(String elanInstanceName, String interfaceName,
1558 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1559 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1560 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1561 // Adding new Elan Interface Port to the operational DataStore without
1562 // Static-Mac Entries..
1563 if (elanInterfaceLists.isPresent()) {
1564 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1565 if (interfaceLists == null) {
1566 interfaceLists = new ArrayList<>();
1568 interfaceLists.add(interfaceName);
1569 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1570 .withKey(new ElanKey(elanInstanceName)).build();
1571 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1575 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1576 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1579 @SuppressWarnings("checkstyle:IllegalCatch")
1580 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1581 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1582 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1583 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1584 if (dpnInterfaceLists == null) {
1587 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1588 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1590 String elanName = elanDpns.getElanInstanceName();
1591 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1592 if (elanInfo == null) {
1593 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1594 + "skipping this ELAN for tunnel handling", elanName);
1597 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1598 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1601 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1602 if (dpnInterfaces == null) {
1605 DpnInterfaces dstDpnIf = null;
1606 for (DpnInterfaces dpnIf : dpnInterfaces) {
1607 BigInteger dpnIfDpId = dpnIf.getDpId();
1608 if (Objects.equals(dpnIfDpId, srcDpId)) {
1610 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1616 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1617 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1618 jobCoordinator.enqueueJob(elanName, () -> {
1619 // update Remote BC Group
1620 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1622 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1623 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1625 } catch (RuntimeException e) {
1626 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1628 Set<String> interfaceLists = new HashSet<>();
1629 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1630 for (String ifName : interfaceLists) {
1631 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1632 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1633 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1634 if (isOperational(interfaceInfo)) {
1635 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1638 }, ElanConstants.JOB_MAX_RETRIES);
1641 }, ElanConstants.JOB_MAX_RETRIES);
1648 * Handle external tunnel state event.
1650 * @param externalTunnel
1651 * the external tunnel
1655 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1656 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1659 // dpId/externalNodeId will be available either in source or destination
1660 // based on the tunnel end point
1661 BigInteger dpId = null;
1662 NodeId externalNodeId = null;
1663 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1664 dpId = new BigInteger(externalTunnel.getSourceDevice());
1665 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1666 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1667 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1668 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1670 if (dpId == null || externalNodeId == null) {
1671 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1675 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1676 if (dpnInterfaceLists == null) {
1679 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1680 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1681 String elanName = elanDpns.getElanInstanceName();
1682 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1684 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1685 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1686 || dpnInterfaces.getInterfaces().isEmpty()) {
1689 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1691 final BigInteger finalDpId = dpId;
1692 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1693 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1694 "Error setting up ELAN BGs");
1695 // install L2gwDevices local macs in dpn.
1696 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1697 // Install dpn macs on external device
1698 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1701 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1705 * Installs dpn macs in external device. first it checks if the physical
1706 * locator towards this dpn tep is present or not if the physical locator is
1707 * present go ahead and add the ucast macs otherwise update the mcast mac
1708 * entry to include this dpn tep ip and schedule the job to put ucast macs
1709 * once the physical locator is programmed in device
1713 * @param lstElanInterfaceNames
1714 * the lst Elan interface names
1717 * @param externalNodeId
1718 * the external node id
1720 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1721 NodeId externalNodeId) {
1722 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1723 externalNodeId.getValue());
1724 if (elanL2GwDevice == null) {
1725 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1728 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1729 if (dpnTepIp == null) {
1730 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1735 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1736 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1737 LogicalDatastoreType.OPERATIONAL);
1738 boolean phyLocAlreadyExists =
1739 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1741 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1742 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1743 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1745 if (phyLocAlreadyExists) {
1746 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1749 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1750 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1754 * Validate external tunnel state event.
1756 * @param externalTunnel
1757 * the external tunnel
1760 * @return true, if successful
1762 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1763 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1764 String srcDevice = externalTunnel.getDestinationDevice();
1765 String destDevice = externalTunnel.getSourceDevice();
1766 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1767 LogicalDatastoreType.CONFIGURATION);
1768 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1769 otherEndPointExtTunnel);
1770 if (otherEndPointExtTunnel != null) {
1771 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1772 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1773 if (otherEndPointInterfaceOperational) {
1776 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1777 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1784 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1785 List<MatchInfo> mkMatches = new ArrayList<>();
1786 // Matching metadata
1788 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1789 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1794 protected ElanInterfaceManager getDataTreeChangeListener() {
1798 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1800 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1801 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1802 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1803 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1805 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1806 } catch (InterruptedException e) {
1807 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);