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.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
16 import com.google.common.base.Optional;
17 import com.google.common.base.Preconditions;
18 import com.google.common.collect.Lists;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashSet;
24 import java.util.List;
26 import java.util.Objects;
27 import java.util.Queue;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentLinkedQueue;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.locks.ReentrantLock;
33 import javax.annotation.Nullable;
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.ListenableFutures;
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 @Nullable 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()));
385 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
386 .withKey(new ElanKey(elanName)).build();
387 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
392 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
393 throws ReadFailedException {
394 // removing the ElanInterface from the config data_store if interface is
395 // not present in Interface config DS
396 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
397 interfaceName) == null
398 && elanInterfaceCache.get(interfaceName).isPresent()) {
399 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
403 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
404 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
405 String elanName = elanInfo.getElanInstanceName();
406 List<ListenableFuture<Void>> futures = new ArrayList<>();
407 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
408 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
409 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
410 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
411 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
412 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
413 if (interfaceInfo != null) {
414 if (existingElanInterfaceMac.isPresent()) {
415 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
416 if (existingMacEntries != null) {
417 List<PhysAddress> macAddresses = new ArrayList<>();
418 for (MacEntry macEntry : existingMacEntries) {
419 PhysAddress macAddress = macEntry.getMacAddress();
420 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
421 macAddress.getValue(), interfaceName);
422 Optional<MacEntry> macEntryOptional =
423 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
424 if (!isLastElanInterface && macEntryOptional.isPresent()) {
425 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
427 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
428 macAddresses.add(macAddress);
431 // Removing all those MACs from External Devices belonging
433 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
434 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
438 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
439 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
440 } else if (existingElanInterfaceMac.isPresent()) {
441 // Interface does not exist in ConfigDS, so lets remove everything
442 // about that interface related to Elan
443 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
444 if (macEntries != null) {
445 for (MacEntry macEntry : macEntries) {
446 PhysAddress macAddress = macEntry.getMacAddress();
447 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
448 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
453 if (existingElanInterfaceMac.isPresent()) {
454 interfaceTx.delete(elanInterfaceId);
456 unbindService(interfaceName, flowTx);
457 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
463 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
464 String interfaceName, long elanTag,
465 TypedReadWriteTransaction<Operational> tx)
466 throws ExecutionException, InterruptedException {
467 // FIXME: pass in and use ElanInstanceKey instead?
468 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
471 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
472 if (dpnInterfaces != null) {
473 List<String> interfaceLists = dpnInterfaces.getInterfaces();
474 if (interfaceLists != null) {
475 interfaceLists.remove(interfaceName);
478 if (interfaceLists == null || interfaceLists.isEmpty()) {
479 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
480 deleteElanDpnInterface(elanName, dpId, tx);
482 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
485 return dpnInterfaces;
491 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
492 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
493 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
494 for (DpnInterfaces dpnInterface : dpnInterfaces) {
495 BigInteger currentDpId = dpnInterface.getDpId();
496 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
497 for (String elanInterface : dpnInterface.getInterfaces()) {
498 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
499 if (macs == null || macs.getMacEntry() == null) {
502 for (MacEntry mac : macs.getMacEntry()) {
503 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
504 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
509 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
512 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
513 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
514 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
515 if (etreeLeafTag != null) {
516 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac, confTx);
520 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
521 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
523 .removeFlow(confTx, dpId,
524 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
525 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
526 mac.getMacAddress().getValue(), elanTag)));
530 * Possible Scenarios for update
531 * a. if orig={1,2,3,4} and updated=null or updated={}
532 then all {1,2,3,4} should be removed
534 b. if orig=null or orig={} and updated ={1,2,3,4}
535 then all {1,2,3,4} should be added
537 c. if orig = {1,2,3,4} updated={2,3,4}
538 then 1 should be removed
540 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
541 then we should just add 5
543 e. if orig = {1,2,3,4} updated={2,3,4,5}
544 then 1 should be removed , 5 should be added
546 @SuppressWarnings("checkstyle:ForbidCertainMethod")
548 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
549 // updating the static-Mac Entries for the existing elanInterface
550 String elanName = update.getElanInstanceName();
551 String interfaceName = update.getName();
553 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
554 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
555 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
556 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
558 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
559 deletedEntry.getMacAddress()));
561 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
562 * Hence add the macentries for the same.*/
563 for (StaticMacEntries staticMacEntry : updatedEntries) {
564 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
565 staticMacEntry.getMacAddress());
566 ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(
567 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
568 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
569 if (existingMacEntry.isPresent()) {
570 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
571 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
574 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
575 elanName, interfaceName, staticMacEntry, tx);
577 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
582 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
583 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
584 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
585 String interfaceName = elanInterfaceAdded.getName();
586 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
587 if (interfaceInfo == null) {
588 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
591 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
593 if (elanInstance == null) {
594 // Add the ElanInstance in the Configuration data-store
595 List<String> elanInterfaces = new ArrayList<>();
596 elanInterfaces.add(interfaceName);
597 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
598 confTx -> ElanUtils.updateOperationalDataStore(idManager,
599 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
600 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
603 Long elanTag = elanInstance.getElanTag();
604 // If elan tag is not updated, then put the elan interface into
605 // unprocessed entry map and entry. Let entries
606 // in this map get processed during ELAN update DCN.
607 if (elanTag == null || elanTag == 0L) {
608 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
609 if (elanInterfaces == null) {
610 elanInterfaces = new ConcurrentLinkedQueue<>();
612 if (!elanInterfaces.contains(elanInterfaceAdded)) {
613 elanInterfaces.add(elanInterfaceAdded);
615 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
618 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
619 interfaceInfo, elanInstance, this);
620 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
621 }), LOG, "Error processing added ELAN interface");
624 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
625 List<ListenableFuture<Void>> futures = new ArrayList<>();
626 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
627 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
630 for (ElanInterface elanInterface : elanInterfaces) {
631 String interfaceName = elanInterface.getName();
632 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
633 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
635 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
639 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
640 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
641 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
642 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
643 List<DpnInterfaces> dpnInterfaceLists = null;
644 if (elanDpnInterfacesList != null) {
645 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
647 if (dpnInterfaceLists == null) {
648 dpnInterfaceLists = new ArrayList<>();
650 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
651 BigInteger dstDpId = interfaceInfo.getDpId();
652 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
655 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
656 for (String remoteIf : remoteElanInterfaces) {
657 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
658 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
659 if (elanIfMac == null || remoteInterface == null) {
662 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
663 if (remoteMacEntries != null) {
664 for (MacEntry macEntry : remoteMacEntries) {
665 String macAddress = macEntry.getMacAddress().getValue();
666 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
667 dstDpId, elanInstance.getElanInstanceName());
668 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
669 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
670 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
677 private static class AddElanInterfaceHolder {
678 private DpnInterfaces dpnInterfaces = null;
679 private boolean isFirstInterfaceInDpn = false;
680 private BigInteger dpId;
683 @SuppressWarnings("checkstyle:ForbidCertainMethod")
684 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
685 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
686 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
687 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
688 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
690 String interfaceName = elanInterface.getName();
691 String elanInstanceName = elanInterface.getElanInstanceName();
693 List<ListenableFuture<Void>> futures = new ArrayList<>();
694 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
695 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
696 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
697 if (elanInfo == null) {
698 List<String> elanInterfaces = new ArrayList<>();
699 elanInterfaces.add(interfaceName);
700 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
701 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
704 createElanStateList(elanInstanceName, interfaceName, operTx);
706 // Specific actions to the DPN where the ElanInterface has been added,
707 // for example, programming the
708 // External tunnel table if needed or adding the ElanInterface to the
709 // DpnInterfaces in the operational DS.
710 holder.dpId = interfaceInfo.getDpId();
711 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
712 // FIXME: use elanInstaince.key() instead?
713 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
716 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
717 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
718 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
719 if (ElanUtils.isVlan(elanInstance)) {
720 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
721 elanInstanceName, existingElanDpnInterfaces);
723 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
725 if (holder.isFirstInterfaceInDpn) {
726 // ELAN's 1st ElanInterface added to this DPN
727 if (!existingElanDpnInterfaces.isPresent()) {
728 holder.dpnInterfaces =
729 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
731 @Nullable List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
732 List<String> elanInterfaces =
733 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
734 elanInterfaces.add(interfaceName);
735 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
736 elanInterfaces, operTx);
738 // The 1st ElanInterface in a DPN must program the Ext Tunnel
739 // table, but only if Elan has VNI
740 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
741 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
742 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
744 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
747 @Nullable List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
748 List<String> elanInterfaces =
749 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
750 elanInterfaces.add(interfaceName);
751 if (elanInterfaces.size() == 1) { // 1st dpn interface
752 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
755 holder.dpnInterfaces =
756 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
763 // add code to install Local/Remote BC group, unknow DMAC entry,
764 // terminating service table flow entry
765 // call bindservice of interfacemanager to create ingress table flow
767 // Add interface to the ElanInterfaceForwardingEntires Container
768 createElanInterfaceTablesList(interfaceName, operTx);
770 futures.forEach(ElanUtils::waitForTransactionToComplete);
772 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
773 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
774 holder.isFirstInterfaceInDpn, confTx))));
776 // add the vlan provider interface to remote BC group for the elan
777 // for internal vlan networks
778 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
779 if (interfaceManager.isExternalInterface(interfaceName)) {
780 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
781 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
785 if (holder.isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
786 //update the remote-DPNs remoteBC group entry with Tunnels
787 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance,
790 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
791 confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInstance, holder.dpId, confTx))));
794 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
795 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
796 elanInterface, interfaceInfo, elanInstance, holder.isFirstInterfaceInDpn, this);
797 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
801 @SuppressWarnings("checkstyle:ForbidCertainMethod")
802 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
803 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
804 String elanInstanceName = elanInstance.getElanInstanceName();
805 String interfaceName = elanInterface.getName();
806 List<ListenableFuture<Void>> futures = new ArrayList<>();
807 BigInteger dpId = interfaceInfo.getDpId();
808 boolean isInterfaceOperational = isOperational(interfaceInfo);
809 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
810 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
811 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
812 isFirstInterfaceInDpn, confTx);
814 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
815 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
817 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
818 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
819 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
820 staticMacEntry.getMacAddress());
821 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
822 LogicalDatastoreType.OPERATIONAL, macId);
823 if (existingMacEntry.isPresent()) {
824 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
825 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
826 existingMacEntry.get(), operTx);
828 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
829 interfaceName, staticMacEntry, operTx);
832 if (isInterfaceOperational) {
833 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
835 String macAddress = staticMacEntry.getMacAddress().getValue();
837 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
839 macAddress, elanInstanceName, interfaceName);
840 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
841 staticMacEntry.getMacAddress().getValue(), true, confTx);
845 if (isInterfaceOperational) {
846 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
848 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
849 staticMacAddresses.add(staticMacEntry.getMacAddress());
851 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
857 futures.forEach(ElanUtils::waitForTransactionToComplete);
858 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
859 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
861 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
862 if (neutronPort != null) {
863 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
865 } catch (IllegalArgumentException ex) {
866 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
872 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
873 PhysAddress physAddress) {
874 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
875 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
876 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
877 LogicalDatastoreType.OPERATIONAL, macId);
879 if (!existingMacEntry.isPresent()) {
883 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
884 .withKey(new MacEntryKey(physAddress)).build();
885 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
886 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
889 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
890 Optional<DpnInterfaces> existingElanDpnInterfaces) {
891 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
892 if (!existingElanDpnInterfaces.isPresent()) {
895 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
898 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
899 int dummyInterfaceCount = 0;
900 List<String> interfaces = dpnInterfaces.getInterfaces();
901 if (interfaces == null) {
904 if (interfaces.contains(routerPortUuid)) {
905 dummyInterfaceCount++;
907 if (interfaces.contains(elanInstanceName)) {
908 dummyInterfaceCount++;
910 return interfaces.size() == dummyInterfaceCount;
913 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
914 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
915 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
918 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
919 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
920 if (!isOperational(interfaceInfo)) {
923 BigInteger dpId = interfaceInfo.getDpId();
924 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
925 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
927 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
928 if (isFirstInterfaceInDpn) {
929 // Terminating Service , UnknownDMAC Table.
930 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
931 // for ELAN Instance is VxLAN
932 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
933 setupTerminateServiceTable(elanInstance, dpId, confTx);
935 setupUnknownDMacTable(elanInstance, dpId, confTx);
937 * Install remote DMAC flow. This is required since this DPN is
938 * added later to the elan instance and remote DMACs of other
939 * interfaces in this elan instance are not present in the current
942 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
943 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
944 elanInstance.getElanInstanceName());
945 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
948 // bind the Elan service to the Interface
949 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
952 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
953 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
954 if (!isOperational(interfaceInfo)) {
957 // LocalBroadcast Group creation with elan-Interfaces
958 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
959 if (isFirstInterfaceInDpn) {
960 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
961 BigInteger dpId = interfaceInfo.getDpId();
962 // RemoteBroadcast Group creation
964 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
965 } catch (InterruptedException e1) {
966 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
968 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId, confTx);
970 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
971 } catch (InterruptedException e1) {
972 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
977 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
978 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
979 int ifTag = interfaceInfo.getInterfaceTag();
980 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
981 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
982 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
983 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
984 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
986 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
988 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
989 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
990 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
991 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
993 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
996 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
997 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
998 int ifTag = interfaceInfo.getInterfaceTag();
999 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1000 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1002 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1004 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1005 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1006 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1007 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1009 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1012 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId,
1013 TypedWriteTransaction<Configuration> confTx) {
1014 int elanTag = elanInfo.getElanTag().intValue();
1015 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1016 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId, confTx);
1017 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1018 if (etreeInstance != null) {
1019 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
1020 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1021 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId, confTx);
1025 @SuppressWarnings("checkstyle:IllegalCatch")
1026 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId,
1027 TypedWriteTransaction<Configuration> confTx) {
1029 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1030 if (elanDpns != null) {
1031 List<DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1032 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1033 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1034 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1035 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1036 List<Action> listAction = new ArrayList<>();
1038 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1039 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1040 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1042 for (DpnInterfaces otherFes : dpnInterfaces) {
1043 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1044 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1045 && !otherFes.getInterfaces().isEmpty()) {
1047 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1048 dpnInterface.getDpId(), otherFes.getDpId(),
1049 elanUtils.isOpenstackVniSemanticsEnforced()
1050 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1051 if (!remoteListActionInfo.isEmpty()) {
1052 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1053 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1056 } catch (Exception ex) {
1057 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1058 + "Logical Group Interface not found between source Dpn - {}, "
1059 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1064 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1065 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1066 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1068 if (remoteListBucketInfo.isEmpty()) {
1069 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1072 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1073 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1074 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1075 mdsalManager.addGroup(confTx, dpnInterface.getDpId(), group);
1079 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1080 } catch (InterruptedException e1) {
1081 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1086 private List<MatchInfo> buildMatchesForVni(Long vni) {
1087 List<MatchInfo> mkMatches = new ArrayList<>();
1088 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1089 mkMatches.add(match);
1093 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1094 List<InstructionInfo> mkInstructions = new ArrayList<>();
1095 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1096 return mkInstructions;
1099 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1100 List<MatchInfo> mkMatches = new ArrayList<>();
1101 // Matching metadata
1102 mkMatches.add(new MatchMetadata(
1103 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1108 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1109 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1112 * elanTag to be written in metadata when flow is selected
1113 * @return the instructions ready to be installed in a flow
1115 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1116 List<InstructionInfo> mkInstructions = new ArrayList<>();
1117 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1118 .getElanMetadataMask()));
1119 /* applicable for EXTERNAL_TUNNEL_TABLE only
1120 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1122 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1123 return mkInstructions;
1126 // Install DMAC entry on dst DPN
1127 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1128 BigInteger dstDpId) {
1129 String interfaceName = interfaceInfo.getInterfaceName();
1130 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1131 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1132 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1133 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1134 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1135 for (MacEntry macEntry : macEntries) {
1136 String macAddress = macEntry.getMacAddress().getValue();
1137 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1139 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1140 interfaceInfo.getDpId())) {
1141 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1143 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1151 private void createDropBucket(List<Bucket> listBucket) {
1152 List<Action> actionsInfos = new ArrayList<>();
1153 actionsInfos.add(new ActionDrop().buildAction());
1154 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1155 MDSALUtil.WATCH_GROUP);
1156 listBucket.add(dropBucket);
1159 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1160 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1161 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1162 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1165 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1166 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1167 List<Bucket> listBucket = new ArrayList<>();
1169 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1171 List<String> interfaces = new ArrayList<>();
1172 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1173 interfaces = newDpnInterface.getInterfaces();
1175 for (String ifName : interfaces) {
1176 // In case if there is a InterfacePort in the cache which is not in
1177 // operational state, skip processing it
1178 InterfaceInfo ifInfo = interfaceManager
1179 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1180 if (!isOperational(ifInfo)) {
1184 if (!interfaceManager.isExternalInterface(ifName)) {
1185 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1186 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1191 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1192 MDSALUtil.buildBucketLists(listBucket));
1193 LOG.trace("installing the localBroadCast Group:{}", group);
1194 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1197 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1198 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1199 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1200 if (etreeInstance != null) {
1201 List<Bucket> listBucket = new ArrayList<>();
1204 List<String> interfaces = new ArrayList<>();
1205 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1206 interfaces = newDpnInterface.getInterfaces();
1208 for (String ifName : interfaces) {
1209 // In case if there is a InterfacePort in the cache which is not
1211 // operational state, skip processing it
1212 InterfaceInfo ifInfo = interfaceManager
1213 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1214 if (!isOperational(ifInfo)) {
1218 if (!interfaceManager.isExternalInterface(ifName)) {
1219 // only add root interfaces
1220 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1224 if (listBucket.isEmpty()) { // No Buckets
1225 createDropBucket(listBucket);
1228 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1229 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1230 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1231 MDSALUtil.buildBucketLists(listBucket));
1232 LOG.trace("installing the localBroadCast Group:{}", group);
1233 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1237 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1238 InterfaceInfo ifInfo) {
1239 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1240 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1241 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1242 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1248 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1249 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1250 throws ExecutionException, InterruptedException {
1251 BigInteger dpnId = interfaceInfo.getDpId();
1252 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1253 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1254 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1257 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1258 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1259 throws ExecutionException, InterruptedException {
1260 BigInteger dpnId = interfaceInfo.getDpId();
1261 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1262 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1263 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1267 * Installs a flow in the External Tunnel table consisting in translating
1268 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1269 * elanTag that will be used later in the ELANs pipeline.
1270 * @param dpnId the dpn id
1272 private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1273 TypedWriteTransaction<Configuration> confTx) {
1274 long elanTag = elanInfo.getElanTag();
1275 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1276 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1277 elanInfo.getElanInstanceName(), // flowName
1280 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1281 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1282 getInstructionsIntOrExtTunnelTable(elanTag));
1284 mdsalManager.addFlow(confTx, flowEntity);
1288 * Removes, from External Tunnel table, the flow that translates from VNI to
1289 * elanTag. Important: ensure this method is only called whenever there is
1290 * no other ElanInterface in the specified DPN
1292 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1294 private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1295 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1296 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1297 // last ElanInstance plus
1298 // adding a new one does (almost at the same time) are executed in that
1301 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1302 FlowEntity flowEntity = new FlowEntityBuilder()
1304 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1307 mdsalManager.removeFlow(confTx, flowEntity);
1310 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1311 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1312 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1313 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1316 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1317 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1318 List<? extends MatchInfoBase> listMatchInfoBase;
1319 List<InstructionInfo> instructionInfos;
1321 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1322 serviceId = elanTag;
1323 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1324 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1326 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1327 listMatchInfoBase = buildMatchesForVni(serviceId);
1328 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1330 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1331 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1332 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1334 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1337 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1338 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1339 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1340 if (etreeInstance != null) {
1341 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1345 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
1346 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1347 long elanTag = elanInfo.getElanTag();
1348 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1349 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1350 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1353 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1354 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1355 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1356 if (etreeLeafTag != null) {
1357 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1358 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1359 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1363 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1364 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1365 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1366 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1367 5, elanInfo.getElanInstanceName(), 0, 0,
1368 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1369 getMatchesForElanTag(elanTag, /* SH flag */false),
1370 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1372 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1375 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1376 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1377 // only if ELAN can connect to external network, perform the following
1379 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1380 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1381 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1382 5, elanInfo.getElanInstanceName(), 0, 0,
1383 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1384 getMatchesForElanTag(elanTag, /* SH flag */true),
1385 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1386 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1391 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
1392 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1393 throws ExecutionException, InterruptedException {
1394 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1395 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1396 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1398 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1399 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1400 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1402 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1406 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1407 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1410 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1411 TypedWriteTransaction<Configuration> tx) {
1412 if (isStandardElanService(elanInterface)) {
1413 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1414 elanInterface.getName(), lportTag, tx);
1415 } else { // Etree service
1416 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1420 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1421 TypedWriteTransaction<Configuration> tx) {
1422 int instructionKey = 0;
1423 List<Instruction> instructions = new ArrayList<>();
1424 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1425 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1427 List<Action> actions = new ArrayList<>();
1428 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1429 lportTag).buildAction());
1430 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1431 elanTag).buildAction());
1432 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1434 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1437 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1438 BoundServices serviceInfo = ElanUtils.getBoundServices(
1439 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1440 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1441 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1442 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1444 if (!existingElanService.isPresent()) {
1445 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1449 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1450 TypedWriteTransaction<Configuration> tx) {
1451 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1452 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1455 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1456 if (etreeInstance == null) {
1457 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1458 elanInterface.getName(), elanInfo.getElanInstanceName());
1460 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1461 elanInterface.getName(), lportTag, tx);
1466 private boolean isStandardElanService(ElanInterface elanInterface) {
1467 return elanInterface.augmentation(EtreeInterface.class) == null;
1470 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1471 throws ExecutionException, InterruptedException {
1472 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1473 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1474 if (tx.read(bindServiceId).get().isPresent()) {
1475 tx.delete(bindServiceId);
1479 private String getFlowRef(long tableId, long elanTag) {
1480 return String.valueOf(tableId) + elanTag;
1483 private String getFlowRef(long tableId, long elanTag, String flowName) {
1484 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1485 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1488 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1489 return String.valueOf(tableId) + elanTag + shFlag;
1492 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1493 List<Action> listAction = new ArrayList<>();
1496 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1498 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1502 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1503 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1504 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1505 .withKey(new DpnInterfacesKey(dpId)).build();
1506 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1507 CREATE_MISSING_PARENTS);
1508 return dpnInterface;
1512 * Delete elan dpn interface from operational DS.
1514 * @param elanInstanceName
1515 * the elan instance name
1519 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
1520 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1521 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1522 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1523 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1524 if (dpnInterfaces.isPresent()) {
1525 tx.delete(dpnInterfacesId);
1529 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1530 TypedWriteTransaction<Operational> tx) {
1531 List<String> interfaceNames = new ArrayList<>();
1532 interfaceNames.add(interfaceName);
1533 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1534 .withKey(new DpnInterfacesKey(dpId)).build();
1535 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1536 CREATE_MISSING_PARENTS);
1537 return dpnInterface;
1540 private void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1541 throws ExecutionException, InterruptedException {
1542 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1543 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1544 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1545 // Adding new Elan Interface Port to the operational DataStore without
1546 // Static-Mac Entries..
1547 if (!interfaceMacTables.isPresent()) {
1548 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1549 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1550 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1551 CREATE_MISSING_PARENTS);
1555 private void createElanStateList(String elanInstanceName, String interfaceName,
1556 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1557 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1558 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1559 // Adding new Elan Interface Port to the operational DataStore without
1560 // Static-Mac Entries..
1561 if (elanInterfaceLists.isPresent()) {
1562 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1563 if (interfaceLists == null) {
1564 interfaceLists = new ArrayList<>();
1566 interfaceLists.add(interfaceName);
1567 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1568 .withKey(new ElanKey(elanInstanceName)).build();
1569 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1573 private boolean isOperational(InterfaceInfo interfaceInfo) {
1574 if (interfaceInfo == null) {
1577 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1580 @SuppressWarnings("checkstyle:IllegalCatch")
1581 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1582 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1583 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1584 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1585 if (dpnInterfaceLists == null) {
1588 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1589 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1591 String elanName = elanDpns.getElanInstanceName();
1592 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1593 if (elanInfo == null) {
1594 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1595 + "skipping this ELAN for tunnel handling", elanName);
1598 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1599 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1602 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1603 if (dpnInterfaces == null) {
1606 DpnInterfaces dstDpnIf = null;
1607 for (DpnInterfaces dpnIf : dpnInterfaces) {
1608 BigInteger dpnIfDpId = dpnIf.getDpId();
1609 if (Objects.equals(dpnIfDpId, srcDpId)) {
1611 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1617 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1618 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1619 jobCoordinator.enqueueJob(elanName, () -> {
1620 // update Remote BC Group
1621 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1623 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1624 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1626 } catch (RuntimeException e) {
1627 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1629 Set<String> interfaceLists = new HashSet<>();
1630 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1631 for (String ifName : interfaceLists) {
1632 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1633 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1634 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1635 if (isOperational(interfaceInfo)) {
1636 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1639 }, ElanConstants.JOB_MAX_RETRIES);
1642 }, ElanConstants.JOB_MAX_RETRIES);
1649 * Handle external tunnel state event.
1651 * @param externalTunnel
1652 * the external tunnel
1656 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1657 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1660 // dpId/externalNodeId will be available either in source or destination
1661 // based on the tunnel end point
1662 BigInteger dpId = null;
1663 NodeId externalNodeId = null;
1664 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1665 dpId = new BigInteger(externalTunnel.getSourceDevice());
1666 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1667 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1668 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1669 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1671 if (dpId == null || externalNodeId == null) {
1672 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1676 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1677 if (dpnInterfaceLists == null) {
1680 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1681 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1682 String elanName = elanDpns.getElanInstanceName();
1683 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1685 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1686 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1687 || dpnInterfaces.getInterfaces().isEmpty()) {
1690 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1692 final BigInteger finalDpId = dpId;
1693 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1694 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1695 "Error setting up ELAN BGs");
1696 // install L2gwDevices local macs in dpn.
1697 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1698 // Install dpn macs on external device
1699 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1702 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1706 * Installs dpn macs in external device. first it checks if the physical
1707 * locator towards this dpn tep is present or not if the physical locator is
1708 * present go ahead and add the ucast macs otherwise update the mcast mac
1709 * entry to include this dpn tep ip and schedule the job to put ucast macs
1710 * once the physical locator is programmed in device
1714 * @param lstElanInterfaceNames
1715 * the lst Elan interface names
1718 * @param externalNodeId
1719 * the external node id
1721 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1722 NodeId externalNodeId) {
1723 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1724 externalNodeId.getValue());
1725 if (elanL2GwDevice == null) {
1726 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1729 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1730 if (dpnTepIp == null) {
1731 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1736 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1737 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1738 LogicalDatastoreType.OPERATIONAL);
1739 boolean phyLocAlreadyExists =
1740 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1742 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1743 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1744 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1746 if (phyLocAlreadyExists) {
1747 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1750 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1751 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1755 * Validate external tunnel state event.
1757 * @param externalTunnel
1758 * the external tunnel
1761 * @return true, if successful
1763 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1764 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1765 String srcDevice = externalTunnel.getDestinationDevice();
1766 String destDevice = externalTunnel.getSourceDevice();
1767 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1768 LogicalDatastoreType.CONFIGURATION);
1769 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1770 otherEndPointExtTunnel);
1771 if (otherEndPointExtTunnel != null) {
1772 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1773 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1774 if (otherEndPointInterfaceOperational) {
1777 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1778 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1785 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1786 List<MatchInfo> mkMatches = new ArrayList<>();
1787 // Matching metadata
1789 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1790 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1795 protected ElanInterfaceManager getDataTreeChangeListener() {
1799 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1801 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1802 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1803 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1804 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1806 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1807 } catch (InterruptedException e) {
1808 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);