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 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 InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
915 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
916 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
919 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
920 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
921 if (!isOperational(interfaceInfo)) {
924 BigInteger dpId = interfaceInfo.getDpId();
925 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
926 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
928 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
929 if (isFirstInterfaceInDpn) {
930 // Terminating Service , UnknownDMAC Table.
931 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
932 // for ELAN Instance is VxLAN
933 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
934 setupTerminateServiceTable(elanInstance, dpId, confTx);
936 setupUnknownDMacTable(elanInstance, dpId, confTx);
938 * Install remote DMAC flow. This is required since this DPN is
939 * added later to the elan instance and remote DMACs of other
940 * interfaces in this elan instance are not present in the current
943 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
944 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
945 elanInstance.getElanInstanceName());
946 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
949 // bind the Elan service to the Interface
950 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
953 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
954 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
955 if (!isOperational(interfaceInfo)) {
958 // LocalBroadcast Group creation with elan-Interfaces
959 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
960 if (isFirstInterfaceInDpn) {
961 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
962 BigInteger dpId = interfaceInfo.getDpId();
963 // RemoteBroadcast Group creation
965 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
966 } catch (InterruptedException e1) {
967 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
969 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId, confTx);
971 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
972 } catch (InterruptedException e1) {
973 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
978 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
979 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
980 int ifTag = interfaceInfo.getInterfaceTag();
981 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
982 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
983 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
984 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
985 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
987 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
989 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
990 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
991 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
992 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
994 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
997 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
998 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
999 int ifTag = interfaceInfo.getInterfaceTag();
1000 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1001 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1003 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1005 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1006 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1007 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1008 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1010 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1013 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId,
1014 TypedWriteTransaction<Configuration> confTx) {
1015 int elanTag = elanInfo.getElanTag().intValue();
1016 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1017 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId, confTx);
1018 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1019 if (etreeInstance != null) {
1020 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
1021 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1022 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId, confTx);
1026 @SuppressWarnings("checkstyle:IllegalCatch")
1027 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId,
1028 TypedWriteTransaction<Configuration> confTx) {
1030 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1031 if (elanDpns != null) {
1032 List<DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1033 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1034 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1035 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1036 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1037 List<Action> listAction = new ArrayList<>();
1039 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1040 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1041 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1043 for (DpnInterfaces otherFes : dpnInterfaces) {
1044 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1045 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1046 && !otherFes.getInterfaces().isEmpty()) {
1048 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1049 dpnInterface.getDpId(), otherFes.getDpId(),
1050 elanUtils.isOpenstackVniSemanticsEnforced()
1051 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1052 if (!remoteListActionInfo.isEmpty()) {
1053 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1054 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1057 } catch (Exception ex) {
1058 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1059 + "Logical Group Interface not found between source Dpn - {}, "
1060 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1065 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1066 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1067 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1069 if (remoteListBucketInfo.isEmpty()) {
1070 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1073 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1074 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1075 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1076 mdsalManager.addGroup(confTx, dpnInterface.getDpId(), group);
1080 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1081 } catch (InterruptedException e1) {
1082 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1087 private List<MatchInfo> buildMatchesForVni(Long vni) {
1088 List<MatchInfo> mkMatches = new ArrayList<>();
1089 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1090 mkMatches.add(match);
1094 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1095 List<InstructionInfo> mkInstructions = new ArrayList<>();
1096 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1097 return mkInstructions;
1100 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1101 List<MatchInfo> mkMatches = new ArrayList<>();
1102 // Matching metadata
1103 mkMatches.add(new MatchMetadata(
1104 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1109 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1110 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1113 * elanTag to be written in metadata when flow is selected
1114 * @return the instructions ready to be installed in a flow
1116 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1117 List<InstructionInfo> mkInstructions = new ArrayList<>();
1118 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1119 .getElanMetadataMask()));
1120 /* applicable for EXTERNAL_TUNNEL_TABLE only
1121 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1123 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1124 return mkInstructions;
1127 // Install DMAC entry on dst DPN
1128 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1129 BigInteger dstDpId) {
1130 String interfaceName = interfaceInfo.getInterfaceName();
1131 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1132 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1133 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1134 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1135 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1136 for (MacEntry macEntry : macEntries) {
1137 String macAddress = macEntry.getMacAddress().getValue();
1138 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1140 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1141 interfaceInfo.getDpId())) {
1142 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1144 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1152 private void createDropBucket(List<Bucket> listBucket) {
1153 List<Action> actionsInfos = new ArrayList<>();
1154 actionsInfos.add(new ActionDrop().buildAction());
1155 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1156 MDSALUtil.WATCH_GROUP);
1157 listBucket.add(dropBucket);
1160 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1161 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1162 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1163 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1166 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1167 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1168 List<Bucket> listBucket = new ArrayList<>();
1170 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1172 List<String> interfaces = new ArrayList<>();
1173 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1174 interfaces = newDpnInterface.getInterfaces();
1176 for (String ifName : interfaces) {
1177 // In case if there is a InterfacePort in the cache which is not in
1178 // operational state, skip processing it
1179 InterfaceInfo ifInfo = interfaceManager
1180 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1181 if (!isOperational(ifInfo)) {
1185 if (!interfaceManager.isExternalInterface(ifName)) {
1186 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1187 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1192 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1193 MDSALUtil.buildBucketLists(listBucket));
1194 LOG.trace("installing the localBroadCast Group:{}", group);
1195 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1198 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1199 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1200 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1201 if (etreeInstance != null) {
1202 List<Bucket> listBucket = new ArrayList<>();
1205 List<String> interfaces = new ArrayList<>();
1206 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1207 interfaces = newDpnInterface.getInterfaces();
1209 for (String ifName : interfaces) {
1210 // In case if there is a InterfacePort in the cache which is not
1212 // operational state, skip processing it
1213 InterfaceInfo ifInfo = interfaceManager
1214 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1215 if (!isOperational(ifInfo)) {
1219 if (!interfaceManager.isExternalInterface(ifName)) {
1220 // only add root interfaces
1221 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1225 if (listBucket.isEmpty()) { // No Buckets
1226 createDropBucket(listBucket);
1229 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1230 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1231 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1232 MDSALUtil.buildBucketLists(listBucket));
1233 LOG.trace("installing the localBroadCast Group:{}", group);
1234 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1238 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1239 InterfaceInfo ifInfo) {
1240 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1241 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1242 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1243 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1249 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1250 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1251 throws ExecutionException, InterruptedException {
1252 BigInteger dpnId = interfaceInfo.getDpId();
1253 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1254 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1255 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1258 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1259 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1260 throws ExecutionException, InterruptedException {
1261 BigInteger dpnId = interfaceInfo.getDpId();
1262 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1263 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1264 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1268 * Installs a flow in the External Tunnel table consisting in translating
1269 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1270 * elanTag that will be used later in the ELANs pipeline.
1271 * @param dpnId the dpn id
1273 private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1274 TypedWriteTransaction<Configuration> confTx) {
1275 long elanTag = elanInfo.getElanTag();
1276 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1277 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1278 elanInfo.getElanInstanceName(), // flowName
1281 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1282 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1283 getInstructionsIntOrExtTunnelTable(elanTag));
1285 mdsalManager.addFlow(confTx, flowEntity);
1289 * Removes, from External Tunnel table, the flow that translates from VNI to
1290 * elanTag. Important: ensure this method is only called whenever there is
1291 * no other ElanInterface in the specified DPN
1293 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1295 private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1296 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1297 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1298 // last ElanInstance plus
1299 // adding a new one does (almost at the same time) are executed in that
1302 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1303 FlowEntity flowEntity = new FlowEntityBuilder()
1305 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1308 mdsalManager.removeFlow(confTx, flowEntity);
1311 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1312 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1313 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1314 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1317 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1318 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1319 List<? extends MatchInfoBase> listMatchInfoBase;
1320 List<InstructionInfo> instructionInfos;
1322 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1323 serviceId = elanTag;
1324 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1325 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1327 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1328 listMatchInfoBase = buildMatchesForVni(serviceId);
1329 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1331 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1332 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1333 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1335 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1338 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1339 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1340 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1341 if (etreeInstance != null) {
1342 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1346 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
1347 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1348 long elanTag = elanInfo.getElanTag();
1349 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1350 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1351 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1354 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1355 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1356 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1357 if (etreeLeafTag != null) {
1358 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1359 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1360 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1364 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1365 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1366 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1367 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1368 5, elanInfo.getElanInstanceName(), 0, 0,
1369 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1370 getMatchesForElanTag(elanTag, /* SH flag */false),
1371 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1373 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1376 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1377 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1378 // only if ELAN can connect to external network, perform the following
1380 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1381 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1382 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1383 5, elanInfo.getElanInstanceName(), 0, 0,
1384 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1385 getMatchesForElanTag(elanTag, /* SH flag */true),
1386 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1387 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1392 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
1393 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1394 throws ExecutionException, InterruptedException {
1395 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1396 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1397 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1399 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1400 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1401 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1403 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1407 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1408 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1411 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1412 TypedWriteTransaction<Configuration> tx) {
1413 if (isStandardElanService(elanInterface)) {
1414 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1415 elanInterface.getName(), lportTag, tx);
1416 } else { // Etree service
1417 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1421 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1422 TypedWriteTransaction<Configuration> tx) {
1423 int instructionKey = 0;
1424 List<Instruction> instructions = new ArrayList<>();
1425 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1426 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1428 List<Action> actions = new ArrayList<>();
1429 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1430 lportTag).buildAction());
1431 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1432 elanTag).buildAction());
1433 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1435 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1438 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1439 BoundServices serviceInfo = ElanUtils.getBoundServices(
1440 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1441 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1442 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1443 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1445 if (!existingElanService.isPresent()) {
1446 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1450 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1451 TypedWriteTransaction<Configuration> tx) {
1452 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1453 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1456 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1457 if (etreeInstance == null) {
1458 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1459 elanInterface.getName(), elanInfo.getElanInstanceName());
1461 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1462 elanInterface.getName(), lportTag, tx);
1467 private boolean isStandardElanService(ElanInterface elanInterface) {
1468 return elanInterface.augmentation(EtreeInterface.class) == null;
1471 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1472 throws ExecutionException, InterruptedException {
1473 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1474 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1475 if (tx.read(bindServiceId).get().isPresent()) {
1476 tx.delete(bindServiceId);
1480 private String getFlowRef(long tableId, long elanTag) {
1481 return String.valueOf(tableId) + elanTag;
1484 private String getFlowRef(long tableId, long elanTag, String flowName) {
1485 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1486 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1489 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1490 return String.valueOf(tableId) + elanTag + shFlag;
1493 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1494 List<Action> listAction = new ArrayList<>();
1497 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1499 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1503 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1504 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1505 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1506 .withKey(new DpnInterfacesKey(dpId)).build();
1507 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1508 CREATE_MISSING_PARENTS);
1509 return dpnInterface;
1513 * Delete elan dpn interface from operational DS.
1515 * @param elanInstanceName
1516 * the elan instance name
1520 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
1521 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1522 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1523 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1524 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1525 if (dpnInterfaces.isPresent()) {
1526 tx.delete(dpnInterfacesId);
1530 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1531 TypedWriteTransaction<Operational> tx) {
1532 List<String> interfaceNames = new ArrayList<>();
1533 interfaceNames.add(interfaceName);
1534 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1535 .withKey(new DpnInterfacesKey(dpId)).build();
1536 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1537 CREATE_MISSING_PARENTS);
1538 return dpnInterface;
1541 private void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1542 throws ExecutionException, InterruptedException {
1543 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1544 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1545 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1546 // Adding new Elan Interface Port to the operational DataStore without
1547 // Static-Mac Entries..
1548 if (!interfaceMacTables.isPresent()) {
1549 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1550 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1551 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1552 CREATE_MISSING_PARENTS);
1556 private void createElanStateList(String elanInstanceName, String interfaceName,
1557 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1558 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1559 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1560 // Adding new Elan Interface Port to the operational DataStore without
1561 // Static-Mac Entries..
1562 if (elanInterfaceLists.isPresent()) {
1563 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1564 if (interfaceLists == null) {
1565 interfaceLists = new ArrayList<>();
1567 interfaceLists.add(interfaceName);
1568 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1569 .withKey(new ElanKey(elanInstanceName)).build();
1570 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1574 private boolean isOperational(InterfaceInfo interfaceInfo) {
1575 if (interfaceInfo == null) {
1578 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1581 @SuppressWarnings("checkstyle:IllegalCatch")
1582 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1583 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1584 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1585 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1586 if (dpnInterfaceLists == null) {
1589 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1590 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1592 String elanName = elanDpns.getElanInstanceName();
1593 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1594 if (elanInfo == null) {
1595 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1596 + "skipping this ELAN for tunnel handling", elanName);
1599 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1600 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1603 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1604 if (dpnInterfaces == null) {
1607 DpnInterfaces dstDpnIf = null;
1608 for (DpnInterfaces dpnIf : dpnInterfaces) {
1609 BigInteger dpnIfDpId = dpnIf.getDpId();
1610 if (Objects.equals(dpnIfDpId, srcDpId)) {
1612 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1618 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1619 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1620 jobCoordinator.enqueueJob(elanName, () -> {
1621 // update Remote BC Group
1622 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1624 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1625 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1627 } catch (RuntimeException e) {
1628 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1630 Set<String> interfaceLists = new HashSet<>();
1631 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1632 for (String ifName : interfaceLists) {
1633 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1634 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1635 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1636 if (isOperational(interfaceInfo)) {
1637 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1640 }, ElanConstants.JOB_MAX_RETRIES);
1643 }, ElanConstants.JOB_MAX_RETRIES);
1650 * Handle external tunnel state event.
1652 * @param externalTunnel
1653 * the external tunnel
1657 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1658 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1661 // dpId/externalNodeId will be available either in source or destination
1662 // based on the tunnel end point
1663 BigInteger dpId = null;
1664 NodeId externalNodeId = null;
1665 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1666 dpId = new BigInteger(externalTunnel.getSourceDevice());
1667 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1668 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1669 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1670 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1672 if (dpId == null || externalNodeId == null) {
1673 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1677 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1678 if (dpnInterfaceLists == null) {
1681 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1682 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1683 String elanName = elanDpns.getElanInstanceName();
1684 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1686 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1687 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1688 || dpnInterfaces.getInterfaces().isEmpty()) {
1691 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1693 final BigInteger finalDpId = dpId;
1694 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1695 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1696 "Error setting up ELAN BGs");
1697 // install L2gwDevices local macs in dpn.
1698 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1699 // Install dpn macs on external device
1700 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1703 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1707 * Installs dpn macs in external device. first it checks if the physical
1708 * locator towards this dpn tep is present or not if the physical locator is
1709 * present go ahead and add the ucast macs otherwise update the mcast mac
1710 * entry to include this dpn tep ip and schedule the job to put ucast macs
1711 * once the physical locator is programmed in device
1715 * @param lstElanInterfaceNames
1716 * the lst Elan interface names
1719 * @param externalNodeId
1720 * the external node id
1722 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1723 NodeId externalNodeId) {
1724 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1725 externalNodeId.getValue());
1726 if (elanL2GwDevice == null) {
1727 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1730 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1731 if (dpnTepIp == null) {
1732 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1737 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1738 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1739 LogicalDatastoreType.OPERATIONAL);
1740 boolean phyLocAlreadyExists =
1741 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1743 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1744 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1745 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1747 if (phyLocAlreadyExists) {
1748 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1751 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1752 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1756 * Validate external tunnel state event.
1758 * @param externalTunnel
1759 * the external tunnel
1762 * @return true, if successful
1764 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1765 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1766 String srcDevice = externalTunnel.getDestinationDevice();
1767 String destDevice = externalTunnel.getSourceDevice();
1768 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1769 LogicalDatastoreType.CONFIGURATION);
1770 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1771 otherEndPointExtTunnel);
1772 if (otherEndPointExtTunnel != null) {
1773 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1774 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1775 if (otherEndPointInterfaceOperational) {
1778 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1779 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1786 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1787 List<MatchInfo> mkMatches = new ArrayList<>();
1788 // Matching metadata
1790 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1791 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1796 protected ElanInterfaceManager getDataTreeChangeListener() {
1800 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1802 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1803 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1804 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1805 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1807 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1808 } catch (InterruptedException e) {
1809 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);