2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14 import static org.opendaylight.infrautils.utils.concurrent.LoggingFutures.addErrorLogging;
15 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
17 import com.google.common.base.Optional;
18 import com.google.common.base.Preconditions;
19 import com.google.common.collect.Lists;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import java.math.BigInteger;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
28 import java.util.Queue;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.locks.ReentrantLock;
34 import javax.annotation.PostConstruct;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37 import org.apache.commons.lang3.StringUtils;
38 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
39 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
40 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
41 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
42 import org.opendaylight.genius.infra.Datastore.Configuration;
43 import org.opendaylight.genius.infra.Datastore.Operational;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.genius.infra.TransactionAdapter;
47 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
48 import org.opendaylight.genius.infra.TypedWriteTransaction;
49 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
50 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
51 import org.opendaylight.genius.itm.globals.ITMConstants;
52 import org.opendaylight.genius.mdsalutil.FlowEntity;
53 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
54 import org.opendaylight.genius.mdsalutil.InstructionInfo;
55 import org.opendaylight.genius.mdsalutil.MDSALUtil;
56 import org.opendaylight.genius.mdsalutil.MatchInfo;
57 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
58 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
59 import org.opendaylight.genius.mdsalutil.NwConstants;
60 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
61 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
62 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
63 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
64 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
65 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
66 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
67 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
68 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
69 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
70 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
71 import org.opendaylight.genius.utils.JvmGlobalLocks;
72 import org.opendaylight.genius.utils.ServiceIndex;
73 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
74 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
75 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
76 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
77 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
78 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
79 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
80 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
81 import org.opendaylight.netvirt.elan.utils.ElanConstants;
82 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
83 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
84 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
85 import org.opendaylight.netvirt.elan.utils.ElanUtils;
86 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
87 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
88 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
89 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
90 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
91 import org.opendaylight.serviceutils.srm.RecoverableListener;
92 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
93 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
94 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
95 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
142 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
143 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
144 import org.opendaylight.yangtools.yang.common.Uint32;
145 import org.opendaylight.yangtools.yang.common.Uint64;
146 import org.slf4j.Logger;
147 import org.slf4j.LoggerFactory;
150 * Class in charge of handling creations, modifications and removals of
153 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
156 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
157 implements RecoverableListener {
158 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
159 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("NetvirtEventLogger");
160 public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
161 private static final boolean SH_FLAG_SET = true;
162 private static final boolean SH_FLAG_UNSET = false;
164 private final DataBroker broker;
165 private final ManagedNewTransactionRunner txRunner;
166 private final IMdsalApiManager mdsalManager;
167 private final IInterfaceManager interfaceManager;
168 private final IdManagerService idManager;
169 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
170 private final INeutronVpnManager neutronVpnManager;
171 private final ElanItmUtils elanItmUtils;
172 private final ElanEtreeUtils elanEtreeUtils;
173 private final ElanL2GatewayUtils elanL2GatewayUtils;
174 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
175 private final ElanUtils elanUtils;
176 private final JobCoordinator jobCoordinator;
177 private final ElanInstanceCache elanInstanceCache;
178 private final ElanInterfaceCache elanInterfaceCache;
179 private final ElanGroupCache elanGroupCache;
181 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
182 unProcessedElanInterfaces = new ConcurrentHashMap<>();
185 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
186 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
187 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
188 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
189 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
190 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
191 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
192 final ElanInstanceCache elanInstanceCache,
193 final ElanInterfaceCache elanInterfaceCache,
194 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
195 ElanGroupCache elanGroupCache,
196 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
197 super(ElanInterface.class, ElanInterfaceManager.class);
198 this.broker = dataBroker;
199 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
200 this.idManager = managerService;
201 this.mdsalManager = mdsalApiManager;
202 this.interfaceManager = interfaceManager;
203 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
204 this.neutronVpnManager = neutronVpnManager;
205 this.elanItmUtils = elanItmUtils;
206 this.elanEtreeUtils = elanEtreeUtils;
207 this.elanL2GatewayUtils = elanL2GatewayUtils;
208 this.elanUtils = elanUtils;
209 this.jobCoordinator = jobCoordinator;
210 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
211 this.elanInstanceCache = elanInstanceCache;
212 this.elanInterfaceCache = elanInterfaceCache;
213 this.elanGroupCache = elanGroupCache;
214 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
224 public void registerListener() {
225 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
229 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
230 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
234 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
235 String interfaceName = del.getName();
236 String elanInstanceName = del.getElanInstanceName();
237 EVENT_LOGGER.debug("ELAN-Interface, REMOVE {} Instance {}", interfaceName, elanInstanceName);
238 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
239 if (elanInterfaces != null && elanInterfaces.contains(del)) {
240 elanInterfaces.remove(del);
241 if (elanInterfaces.isEmpty()) {
242 unProcessedElanInterfaces.remove(elanInstanceName);
245 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
247 * Handling in case the elan instance is deleted.If the Elan instance is
248 * deleted, there is no need to explicitly delete the elan interfaces
250 if (elanInfo == null) {
253 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
254 if (interfaceInfo == null && elanInfo.isExternal()) {
255 // In deleting external network, the underlying ietf Inteface might have been removed
256 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
257 // from Operational DS instead
258 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
260 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
261 interfaceName, interfaceInfo, this);
262 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
265 private static class RemoveElanInterfaceHolder {
266 boolean isLastElanInterface = false;
270 @SuppressWarnings("checkstyle:ForbidCertainMethod")
271 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
272 InterfaceInfo interfaceInfo) {
273 String elanName = elanInfo.getElanInstanceName();
274 EVENT_LOGGER.debug("ELAN-InterfaceState, REMOVE {} Instance {}", interfaceName, elanName);
275 Uint32 elanTag = elanInfo.getElanTag();
276 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
277 List<ListenableFuture<Void>> futures = new ArrayList<>();
278 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
279 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
280 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
281 if (elanState == null) {
284 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
285 List<String> elanInterfaces = elanState.getElanInterfaces();
286 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
287 holder.isLastElanInterface = true;
289 if (interfaceInfo != null) {
290 holder.dpId = interfaceInfo.getDpId();
291 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
292 interfaceName, elanTag, interfaceTx);
294 * If there are not elan ports, remove the unknown dmac, terminating
295 * service table flows, remote/local bc group
297 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
298 || dpnInterfaces.getInterfaces().isEmpty()) {
299 // No more Elan Interfaces in this DPN
300 EVENT_LOGGER.debug("ELAN-Flows, REMOVE {} Instance {}", interfaceName, elanName);
301 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
303 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
304 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag().toJava());
306 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag().toJava());
307 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
308 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
309 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
310 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
311 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
312 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
313 elanUtils.removeTerminatingServiceAction(holder.dpId,
314 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
316 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
319 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
324 futures.forEach(ElanUtils::waitForTransactionToComplete);
326 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
327 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
328 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
329 ElanConstants.JOB_MAX_RETRIES);
334 private void removeEtreeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
335 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
336 throws ExecutionException, InterruptedException {
337 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag().toJava());
338 if (etreeLeafTag != null) {
339 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
340 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
344 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
345 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
346 throws ExecutionException, InterruptedException {
347 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
348 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
351 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
352 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
353 throws ExecutionException, InterruptedException {
354 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
355 if (etreeInstance != null) {
356 Uint64 dpnId = interfaceInfo.getDpId();
357 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue().toJava());
358 LOG.trace("deleted the localBroadCast Group:{}", groupId);
359 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
363 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
364 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
365 throws ExecutionException, InterruptedException {
366 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
367 if (etreeInstance != null) {
368 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
369 Uint64 dpnId = interfaceInfo.getDpId();
370 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
371 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
372 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
376 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
377 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
378 String elanName = elanInfo.getElanInstanceName();
379 Elan elanState = ElanUtils.getElanByName(tx, elanName);
380 if (elanState == null) {
383 List<String> existingElanInterfaces = elanState.getElanInterfaces();
384 List<String> elanInterfaces = new ArrayList<>();
385 if (existingElanInterfaces != null) {
386 elanInterfaces.addAll(existingElanInterfaces);
388 boolean isRemoved = elanInterfaces.remove(interfaceName);
393 if (elanInterfaces.isEmpty()) {
394 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
395 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
396 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
397 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
399 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
400 .withKey(new ElanKey(elanName)).build();
401 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
406 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
407 throws ReadFailedException {
408 // removing the ElanInterface from the config data_store if interface is
409 // not present in Interface config DS
410 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
411 interfaceName) == null
412 && elanInterfaceCache.get(interfaceName).isPresent()) {
413 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
417 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
418 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
419 String elanName = elanInfo.getElanInstanceName();
420 EVENT_LOGGER.debug("ELAN-InterfaceEntries, REMOVE {} Instance {}", interfaceName, elanName);
421 List<ListenableFuture<Void>> futures = new ArrayList<>();
422 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
423 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
424 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
425 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
426 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
427 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
428 if (interfaceInfo != null) {
429 if (existingElanInterfaceMac.isPresent()) {
430 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
431 if (existingMacEntries != null) {
432 List<PhysAddress> macAddresses = new ArrayList<>();
433 for (MacEntry macEntry : existingMacEntries) {
434 PhysAddress macAddress = macEntry.getMacAddress();
435 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
436 macAddress.getValue(), interfaceName);
437 Optional<MacEntry> macEntryOptional =
438 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
439 if (!isLastElanInterface && macEntryOptional.isPresent()) {
440 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
442 EVENT_LOGGER.debug("ELAN-MacFlows, REMOVE {} Instance {} Mac {}",
443 interfaceName, elanName, macAddress);
444 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
445 macAddresses.add(macAddress);
448 // Removing all those MACs from External Devices belonging
450 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
451 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
455 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
456 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
457 } else if (existingElanInterfaceMac.isPresent()) {
458 // Interface does not exist in ConfigDS, so lets remove everything
459 // about that interface related to Elan
460 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
461 if (macEntries != null) {
462 for (MacEntry macEntry : macEntries) {
463 PhysAddress macAddress = macEntry.getMacAddress();
464 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
465 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
470 if (existingElanInterfaceMac.isPresent()) {
471 interfaceTx.delete(elanInterfaceId);
473 unbindService(interfaceName, flowTx);
474 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
480 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, Uint64 dpId,
481 String interfaceName, Uint32 elanTag,
482 TypedReadWriteTransaction<Operational> tx)
483 throws ExecutionException, InterruptedException {
484 // FIXME: pass in and use ElanInstanceKey instead?
485 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
488 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
489 if (dpnInterfaces != null) {
490 List<String> interfaceLists = null;
491 if (dpnInterfaces.getInterfaces() != null) {
492 interfaceLists = new ArrayList<>(dpnInterfaces.getInterfaces());
494 if (interfaceLists != null) {
495 interfaceLists.remove(interfaceName);
498 if (interfaceLists == null || interfaceLists.isEmpty()) {
499 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
500 deleteElanDpnInterface(elanName, dpId, tx);
502 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
505 return dpnInterfaces;
511 private void deleteAllRemoteMacsInADpn(String elanName, Uint64 dpId, Uint32 elanTag) {
512 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
513 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
514 for (DpnInterfaces dpnInterface : dpnInterfaces) {
515 Uint64 currentDpId = dpnInterface.getDpId();
516 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
517 for (String elanInterface : dpnInterface.getInterfaces()) {
518 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
519 if (macs == null || macs.getMacEntry() == null) {
522 for (MacEntry mac : macs.getMacEntry()) {
523 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
524 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
529 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
532 private void removeEtreeMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, Uint64 currentDpId, MacEntry mac,
533 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
534 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
535 if (etreeLeafTag != null) {
536 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(),
537 currentDpId, mac, confTx);
541 private void removeTheMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, Uint64 currentDpId, MacEntry mac,
542 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
544 .removeFlow(confTx, dpId,
545 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
546 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
547 mac.getMacAddress().getValue(), elanTag)));
551 * Possible Scenarios for update
552 * a. if orig={1,2,3,4} and updated=null or updated={}
553 then all {1,2,3,4} should be removed
555 b. if orig=null or orig={} and updated ={1,2,3,4}
556 then all {1,2,3,4} should be added
558 c. if orig = {1,2,3,4} updated={2,3,4}
559 then 1 should be removed
561 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
562 then we should just add 5
564 e. if orig = {1,2,3,4} updated={2,3,4,5}
565 then 1 should be removed , 5 should be added
567 @SuppressWarnings("checkstyle:ForbidCertainMethod")
569 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
570 // updating the static-Mac Entries for the existing elanInterface
571 String elanName = update.getElanInstanceName();
572 String interfaceName = update.getName();
573 LOG.info("Update static mac entries for elan interface {} in elan instance {}", interfaceName, elanName);
574 EVENT_LOGGER.debug("ELAN-Interface, UPDATE {} Instance {}", original.getName(), elanName);
576 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
577 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
578 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
579 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
581 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
582 deletedEntry.getMacAddress()));
584 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
585 * Hence add the macentries for the same.*/
586 for (StaticMacEntries staticMacEntry : updatedEntries) {
587 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
588 staticMacEntry.getMacAddress());
589 addErrorLogging(ElanUtils.waitForTransactionToComplete(
590 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
591 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
592 if (existingMacEntry.isPresent()) {
593 LOG.debug("updating elan interface forwarding table for mac entry {} elan instance {}",
594 existingMacEntry.get(), elanName);
595 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
596 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
599 LOG.info("Adding elan interface forwarding table for mac entry {} elan interface"
600 + " {} elan instance {}.", staticMacEntry.getMacAddress(), interfaceName, elanName);
601 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
602 elanName, interfaceName, staticMacEntry, tx);
604 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
609 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
610 LOG.info("Init for ELAN interface Add {}", elanInterfaceAdded);
611 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
612 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
613 String interfaceName = elanInterfaceAdded.getName();
614 EVENT_LOGGER.debug("ELAN-Interface, ADD {} Instance {}", interfaceName, elanInstanceName);
615 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
616 if (interfaceInfo == null) {
617 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
620 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
622 if (elanInstance == null) {
623 // Add the ElanInstance in the Configuration data-store
624 List<String> elanInterfaces = new ArrayList<>();
625 elanInterfaces.add(interfaceName);
626 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
627 confTx -> ElanUtils.updateOperationalDataStore(idManager,
628 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
629 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
632 Uint32 elanTag = elanInstance.getElanTag();
633 // If elan tag is not updated, then put the elan interface into
634 // unprocessed entry map and entry. Let entries
635 // in this map get processed during ELAN update DCN.
636 if (elanTag == null || elanTag.longValue() == 0L) {
637 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
638 if (elanInterfaces == null) {
639 elanInterfaces = new ConcurrentLinkedQueue<>();
641 if (!elanInterfaces.contains(elanInterfaceAdded)) {
642 elanInterfaces.add(elanInterfaceAdded);
644 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
647 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
648 interfaceInfo, elanInstance, this);
649 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
650 }), LOG, "Error processing added ELAN interface");
653 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
654 LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName());
655 List<ListenableFuture<Void>> futures = new ArrayList<>();
656 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
657 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
660 for (ElanInterface elanInterface : elanInterfaces) {
661 String interfaceName = elanInterface.getName();
662 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
663 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
665 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
666 LOG.info("Unprocessed elan interfaces for elan instance {} has been removed.",
667 elanInstance.getElanInstanceName());
671 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
672 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
673 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
674 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
675 List<DpnInterfaces> dpnInterfaceLists = null;
676 if (elanDpnInterfacesList != null) {
677 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
679 if (dpnInterfaceLists == null) {
680 dpnInterfaceLists = new ArrayList<>();
682 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
683 Uint64 dstDpId = interfaceInfo.getDpId();
684 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
687 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
688 for (String remoteIf : remoteElanInterfaces) {
689 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
690 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
691 if (elanIfMac == null || remoteInterface == null) {
694 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
695 if (remoteMacEntries != null) {
696 for (MacEntry macEntry : remoteMacEntries) {
697 String macAddress = macEntry.getMacAddress().getValue();
698 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
699 dstDpId, elanInstance.getElanInstanceName());
700 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
701 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
702 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
709 private static class AddElanInterfaceHolder {
710 private DpnInterfaces dpnInterfaces = null;
711 private boolean isFirstInterfaceInDpn = false;
715 @SuppressWarnings("checkstyle:ForbidCertainMethod")
716 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
717 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
718 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
719 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
720 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
722 String interfaceName = elanInterface.getName();
723 String elanInstanceName = elanInterface.getElanInstanceName();
724 LOG.trace("Adding elan interface: interface name {} , instance name {}", interfaceName, elanInstanceName);
725 EVENT_LOGGER.debug("ELAN-InterfaceState, ADD {} Instance {}", interfaceName, elanInstanceName);
727 List<ListenableFuture<Void>> futures = new ArrayList<>();
728 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
729 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
730 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
731 if (elanInfo == null) {
732 LOG.trace("elanInfo is null for elan instance: {}", elanInstanceName);
733 List<String> elanInterfaces = new ArrayList<>();
734 elanInterfaces.add(interfaceName);
735 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
736 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
739 createElanStateList(elanInstanceName, interfaceName, operTx);
741 // Specific actions to the DPN where the ElanInterface has been added,
742 // for example, programming the
743 // External tunnel table if needed or adding the ElanInterface to the
744 // DpnInterfaces in the operational DS.
745 holder.dpId = interfaceInfo.getDpId();
746 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
747 // FIXME: use elanInstaince.key() instead?
748 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
751 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
752 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
753 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
754 if (ElanUtils.isVlan(elanInstance)) {
755 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
756 elanInstanceName, existingElanDpnInterfaces);
758 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
760 if (holder.isFirstInterfaceInDpn) {
761 // ELAN's 1st ElanInterface added to this DPN
762 if (!existingElanDpnInterfaces.isPresent()) {
763 holder.dpnInterfaces =
764 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
766 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
767 List<String> elanInterfaces =
768 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
769 elanInterfaces.add(interfaceName);
770 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
771 elanInterfaces, operTx);
773 LOG.debug("1st interface {} for elan {} is added to dpn {}",
774 interfaceName, elanInstanceName, holder.dpId);
775 // The 1st ElanInterface in a DPN must program the Ext Tunnel
776 // table, but only if Elan has VNI
777 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
778 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
779 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
781 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
784 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
785 List<String> elanInterfaces =
786 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
787 elanInterfaces.add(interfaceName);
788 if (elanInterfaces.size() == 1) { // 1st dpn interface
789 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
792 holder.dpnInterfaces =
793 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
794 LOG.debug("Interface {} for elan {} is added to dpn {}",
795 interfaceName, elanInstanceName, holder.dpId);
802 // add code to install Local/Remote BC group, unknow DMAC entry,
803 // terminating service table flow entry
804 // call bindservice of interfacemanager to create ingress table flow
806 // Add interface to the ElanInterfaceForwardingEntires Container
807 createElanInterfaceTablesList(interfaceName, operTx);
809 futures.forEach(ElanUtils::waitForTransactionToComplete);
811 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
812 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
813 holder.isFirstInterfaceInDpn, confTx))));
815 // add the vlan provider interface to remote BC group for the elan
816 // for internal vlan networks
817 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
818 if (interfaceManager.isExternalInterface(interfaceName)) {
819 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
820 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
823 if (holder.isFirstInterfaceInDpn) {
824 // ELAN's 1st ElanInterface added to this DPN
825 LOG.debug("Adding dpn into operational dpn list {}", holder.dpId);
826 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
827 operTx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId),
828 holder.dpnInterfaces, CREATE_MISSING_PARENTS);
831 LOG.debug("Updated dpn into operational dpn list {}", holder.dpId);
834 scheduleElanInterfaceWorkerAfterRemoteBcGroup(elanInstance, interfaceInfo, holder.dpnInterfaces,
835 holder.isFirstInterfaceInDpn, elanInterface);
839 @SuppressWarnings("checkstyle:ForbidCertainMethod")
840 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
841 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
842 String elanInstanceName = elanInstance.getElanInstanceName();
843 String interfaceName = elanInterface.getName();
844 List<ListenableFuture<Void>> futures = new ArrayList<>();
845 Uint64 dpId = interfaceInfo.getDpId();
846 boolean isInterfaceOperational = isOperational(interfaceInfo);
847 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
848 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
849 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
850 isFirstInterfaceInDpn, confTx);
852 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
853 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
855 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
856 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
857 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
858 staticMacEntry.getMacAddress());
859 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
860 LogicalDatastoreType.OPERATIONAL, macId);
861 if (existingMacEntry.isPresent()) {
862 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
863 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
864 existingMacEntry.get(), operTx);
866 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
867 interfaceName, staticMacEntry, operTx);
870 if (isInterfaceOperational) {
871 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
873 String macAddress = staticMacEntry.getMacAddress().getValue();
875 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
877 macAddress, elanInstanceName, interfaceName);
878 EVENT_LOGGER.debug("ELAN-MacFlows, ADD {} Instance {} Mac {}",
879 interfaceName, elanInstanceName, macAddress);
880 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
881 staticMacEntry.getMacAddress().getValue(), true, confTx);
885 if (isInterfaceOperational) {
886 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
888 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
889 staticMacAddresses.add(staticMacEntry.getMacAddress());
891 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
897 futures.forEach(ElanUtils::waitForTransactionToComplete);
898 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
899 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
901 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
902 if (neutronPort != null) {
903 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
905 } catch (IllegalArgumentException ex) {
906 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
912 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
913 PhysAddress physAddress) {
914 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
915 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
916 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
917 LogicalDatastoreType.OPERATIONAL, macId);
919 if (!existingMacEntry.isPresent()) {
923 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
924 .withKey(new MacEntryKey(physAddress)).build();
925 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
926 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
929 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
930 Optional<DpnInterfaces> existingElanDpnInterfaces) {
931 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
932 if (!existingElanDpnInterfaces.isPresent()) {
935 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
938 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
939 int dummyInterfaceCount = 0;
940 List<String> interfaces = dpnInterfaces.getInterfaces();
941 if (interfaces == null) {
944 if (interfaces.contains(routerPortUuid)) {
945 dummyInterfaceCount++;
947 if (interfaces.contains(elanInstanceName)) {
948 dummyInterfaceCount++;
950 return interfaces.size() == dummyInterfaceCount;
953 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
954 PhysAddress physAddress) {
955 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
956 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
959 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
960 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
961 if (!isOperational(interfaceInfo)) {
962 LOG.warn("Interface {} is not operational", elanInterface.getName());
963 EVENT_LOGGER.debug("ELAN-InterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
964 elanInterface.getName(), elanInstance.getElanInstanceName(), interfaceInfo.getOpState());
967 Uint64 dpId = interfaceInfo.getDpId();
968 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
969 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
971 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
972 if (isFirstInterfaceInDpn) {
973 // Terminating Service , UnknownDMAC Table.
974 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
975 // for ELAN Instance is VxLAN
976 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
977 setupTerminateServiceTable(elanInstance, dpId, confTx);
979 setupUnknownDMacTable(elanInstance, dpId, confTx);
981 * Install remote DMAC flow. This is required since this DPN is
982 * added later to the elan instance and remote DMACs of other
983 * interfaces in this elan instance are not present in the current
986 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
987 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
988 elanInstance.getElanInstanceName());
989 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
992 // bind the Elan service to the Interface
993 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
996 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
997 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
998 if (!isOperational(interfaceInfo)) {
999 LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational",
1000 dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName());
1001 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
1002 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1005 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {}",
1006 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
1007 // LocalBroadcast Group creation with elan-Interfaces
1008 LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(),
1009 dpnInterfaces.getDpId());
1010 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
1011 if (isFirstInterfaceInDpn) {
1012 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
1014 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1015 } catch (InterruptedException e1) {
1016 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
1021 public InstanceIdentifier<Group> getGroupIid(ElanInstance elanInfo, Uint64 dpnId) {
1022 long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1023 return InstanceIdentifier.builder(Nodes.class)
1024 .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight
1025 .inventory.rev130819.NodeId("openflow:" + dpnId.toString())))
1026 .augmentation(FlowCapableNode.class)
1027 .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build();
1030 public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo,
1031 InterfaceInfo interfaceInfo,
1032 DpnInterfaces dpnInterfaces,
1033 boolean isFirstInterfaceInDpn,
1034 ElanInterface elanInterface) {
1035 if (!isOperational(interfaceInfo)) {
1036 LOG.debug("Interface {} is not operational", elanInterface.getName());
1039 String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName());
1040 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey,
1041 elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this);
1042 InstanceIdentifier<Group> groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId());
1043 elanGroupCache.addJobToWaitList(groupInstanceId, () -> {
1044 jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
1048 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1049 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1050 int ifTag = interfaceInfo.getInterfaceTag();
1051 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1052 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 11, elanInfo.getElanInstanceName(),
1053 0, 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1054 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
1055 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
1057 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
1058 LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}",
1059 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1061 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1062 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 12, elanInfo.getElanInstanceName(), 0,
1063 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1064 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1066 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
1067 LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}",
1068 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1071 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1072 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1073 int ifTag = interfaceInfo.getInterfaceTag();
1074 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1075 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1077 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1079 Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1080 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"));
1082 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1085 private static List<MatchInfo> buildMatchesForVni(Uint64 vni) {
1086 List<MatchInfo> mkMatches = new ArrayList<>();
1087 MatchInfo match = new MatchTunnelId(vni);
1088 mkMatches.add(match);
1092 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1093 List<InstructionInfo> mkInstructions = new ArrayList<>();
1094 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1095 return mkInstructions;
1098 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1099 List<MatchInfo> mkMatches = new ArrayList<>();
1100 // Matching metadata
1101 mkMatches.add(new MatchMetadata(
1102 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1107 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1108 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1111 * elanTag to be written in metadata when flow is selected
1112 * @return the instructions ready to be installed in a flow
1114 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Uint32 elanTag) {
1115 List<InstructionInfo> mkInstructions = new ArrayList<>();
1116 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
1117 ElanHelper.getElanMetadataMask()));
1118 /* applicable for EXTERNAL_TUNNEL_TABLE only
1119 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1121 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1122 return mkInstructions;
1125 // Install DMAC entry on dst DPN
1126 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1128 String interfaceName = interfaceInfo.getInterfaceName();
1129 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1130 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1131 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1132 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1133 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1134 for (MacEntry macEntry : macEntries) {
1135 String macAddress = macEntry.getMacAddress().getValue();
1136 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1138 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress,
1139 interfaceInfo.getDpId())) {
1140 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1142 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1150 private static void createDropBucket(List<Bucket> listBucket) {
1151 List<Action> actionsInfos = new ArrayList<>();
1152 actionsInfos.add(new ActionDrop().buildAction());
1153 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1154 MDSALUtil.WATCH_GROUP);
1155 listBucket.add(dropBucket);
1158 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1159 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1160 if (!isOperational(interfaceInfo)) {
1161 EVENT_LOGGER.debug("ELAN-LBG, ADD {} Instance {} Interface Status {}, returning",
1162 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1165 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1166 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1169 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1170 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1171 List<Bucket> listBucket = new ArrayList<>();
1173 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1175 List<String> interfaces = new ArrayList<>();
1176 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1177 interfaces = newDpnInterface.getInterfaces();
1179 for (String ifName : interfaces) {
1180 // In case if there is a InterfacePort in the cache which is not in
1181 // operational state, skip processing it
1182 InterfaceInfo ifInfo = interfaceManager
1183 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1184 if (!isOperational(ifInfo)) {
1188 if (!interfaceManager.isExternalInterface(ifName)) {
1189 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1190 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1195 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1196 MDSALUtil.buildBucketLists(listBucket));
1197 LOG.trace("installing the localBroadCast Group:{}", group);
1198 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1201 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1202 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1203 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1204 if (etreeInstance != null) {
1205 List<Bucket> listBucket = new ArrayList<>();
1208 List<String> interfaces = new ArrayList<>();
1209 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1210 interfaces = newDpnInterface.getInterfaces();
1212 for (String ifName : interfaces) {
1213 // In case if there is a InterfacePort in the cache which is not
1215 // operational state, skip processing it
1216 InterfaceInfo ifInfo = interfaceManager
1217 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1218 if (!isOperational(ifInfo)) {
1222 if (!interfaceManager.isExternalInterface(ifName)) {
1223 // only add root interfaces
1224 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1228 if (listBucket.isEmpty()) { // No Buckets
1229 createDropBucket(listBucket);
1232 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
1233 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1234 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1235 MDSALUtil.buildBucketLists(listBucket));
1236 LOG.trace("installing the localBroadCast Group:{}", group);
1237 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1241 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1242 InterfaceInfo ifInfo) {
1243 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1244 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1245 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1246 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1252 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1253 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1254 throws ExecutionException, InterruptedException {
1255 Uint64 dpnId = interfaceInfo.getDpId();
1256 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1257 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1258 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1261 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1262 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1263 throws ExecutionException, InterruptedException {
1264 Uint64 dpnId = interfaceInfo.getDpId();
1265 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1266 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1267 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1271 * Installs a flow in the External Tunnel table consisting in translating
1272 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1273 * elanTag that will be used later in the ELANs pipeline.
1274 * @param dpnId the dpn id
1276 private void setExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1277 TypedWriteTransaction<Configuration> confTx) {
1278 Uint32 elanTag = elanInfo.getElanTag();
1279 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1280 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag.longValue()), 5, // prio
1281 elanInfo.getElanInstanceName(), // flowName
1284 Uint64.valueOf(ITMConstants.COOKIE_ITM_EXTERNAL.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1285 buildMatchesForVni(Uint64.valueOf(ElanUtils.getVxlanSegmentationId(elanInfo).longValue())),
1286 getInstructionsIntOrExtTunnelTable(elanTag));
1288 mdsalManager.addFlow(confTx, flowEntity);
1292 * Removes, from External Tunnel table, the flow that translates from VNI to
1293 * elanTag. Important: ensure this method is only called whenever there is
1294 * no other ElanInterface in the specified DPN
1296 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1298 private void unsetExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1299 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1300 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1301 // last ElanInstance plus
1302 // adding a new one does (almost at the same time) are executed in that
1305 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag().toJava());
1306 FlowEntity flowEntity = new FlowEntityBuilder()
1308 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1311 mdsalManager.removeFlow(confTx, flowEntity);
1314 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1315 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1316 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1317 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1320 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, Uint32 elanTag,
1321 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1322 List<? extends MatchInfoBase> listMatchInfoBase;
1323 List<InstructionInfo> instructionInfos;
1325 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1326 serviceId = elanTag;
1327 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId(elanTag);
1328 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue()));
1330 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1331 listMatchInfoBase = buildMatchesForVni(Uint64.valueOf(serviceId));
1332 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1334 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1335 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId.longValue()), 5,
1336 String.format("%s:%s", "ITM Flow Entry ", elanTag.toString()), 0, 0,
1337 Uint64.valueOf(ITMConstants.COOKIE_ITM.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1338 listMatchInfoBase, instructionInfos);
1339 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1340 LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId,
1341 elanInfo.getElanInstanceName(), elanTag);
1344 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1345 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1346 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1347 if (etreeInstance != null) {
1348 setupTerminateServiceTable(elanInfo, dpId,
1349 etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1353 public void setupUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId,
1354 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1355 long elanTag = elanInfo.getElanTag().toJava();
1356 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1357 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1358 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1361 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1362 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1363 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1364 if (etreeLeafTag != null) {
1365 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
1366 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1367 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1371 private void installLocalUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1372 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1373 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1374 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1375 5, elanInfo.getElanInstanceName(), 0, 0,
1376 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1377 getMatchesForElanTag(elanTag, /* SH flag */false),
1378 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1380 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1381 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}",
1382 dpId, elanInfo.getElanInstanceName(), elanTag);
1385 private void installRemoteUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1386 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1387 // only if ELAN can connect to external network, perform the following
1389 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1390 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1391 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1392 5, elanInfo.getElanInstanceName(), 0, 0,
1393 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1394 getMatchesForElanTag(elanTag, /* SH flag */true),
1395 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1396 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1397 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to "
1398 + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag);
1403 private void removeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
1404 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1405 throws ExecutionException, InterruptedException {
1406 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1407 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1408 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1410 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1411 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1412 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1414 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1418 private void removeDefaultTermFlow(Uint64 dpId, long elanTag) {
1419 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1422 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1423 TypedWriteTransaction<Configuration> tx) {
1424 if (isStandardElanService(elanInterface)) {
1425 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(),
1426 elanInterface.getName(), lportTag, tx);
1427 } else { // Etree service
1428 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1432 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1433 TypedWriteTransaction<Configuration> tx) {
1434 int instructionKey = 0;
1435 List<Instruction> instructions = new ArrayList<>();
1436 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1437 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1439 List<Action> actions = new ArrayList<>();
1440 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1441 lportTag).buildAction());
1442 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1443 elanTag).buildAction());
1444 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1446 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1449 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1450 BoundServices serviceInfo = ElanUtils.getBoundServices(
1451 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1452 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1453 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1454 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1456 if (!existingElanService.isPresent()) {
1457 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1458 LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName);
1462 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1463 TypedWriteTransaction<Configuration> tx) {
1464 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1465 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1468 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1469 if (etreeInstance == null) {
1470 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1471 elanInterface.getName(), elanInfo.getElanInstanceName());
1473 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue().toJava(), elanInfo.getElanInstanceName(),
1474 elanInterface.getName(), lportTag, tx);
1479 private static boolean isStandardElanService(ElanInterface elanInterface) {
1480 return elanInterface.augmentation(EtreeInterface.class) == null;
1483 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1484 throws ExecutionException, InterruptedException {
1485 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1486 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1487 if (tx.read(bindServiceId).get().isPresent()) {
1488 tx.delete(bindServiceId);
1492 private static String getFlowRef(long tableId, long elanTag) {
1493 return String.valueOf(tableId) + elanTag;
1496 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1497 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1498 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1501 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1502 return String.valueOf(tableId) + elanTag + shFlag;
1505 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1506 List<Action> listAction = new ArrayList<>();
1509 new ActionSetFieldTunnelId(Uint64.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1511 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1515 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, Uint64 dpId,
1516 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1517 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1518 .withKey(new DpnInterfacesKey(dpId)).build();
1519 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1520 CREATE_MISSING_PARENTS);
1521 LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName,
1523 return dpnInterface;
1527 * Delete elan dpn interface from operational DS.
1529 * @param elanInstanceName
1530 * the elan instance name
1534 private static void deleteElanDpnInterface(String elanInstanceName, Uint64 dpId,
1535 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1536 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1537 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1538 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1539 if (dpnInterfaces.isPresent()) {
1540 tx.delete(dpnInterfacesId);
1544 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1545 Uint64 dpId, TypedWriteTransaction<Operational> tx) {
1546 List<String> interfaceNames = new ArrayList<>();
1547 interfaceNames.add(interfaceName);
1548 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1549 .withKey(new DpnInterfacesKey(dpId)).build();
1550 return dpnInterface;
1553 private static void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1554 throws ExecutionException, InterruptedException {
1555 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1556 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1557 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1558 // Adding new Elan Interface Port to the operational DataStore without
1559 // Static-Mac Entries..
1560 if (!interfaceMacTables.isPresent()) {
1561 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1562 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1563 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1564 CREATE_MISSING_PARENTS);
1565 LOG.trace("Created interface MAC table for interface: {}", interfaceName);
1569 private static void createElanStateList(String elanInstanceName, String interfaceName,
1570 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1571 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1572 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1573 // Adding new Elan Interface Port to the operational DataStore without
1574 // Static-Mac Entries..
1575 if (elanInterfaceLists.isPresent()) {
1576 List<String> interfaceLists = new ArrayList<>();
1577 interfaceLists.add(interfaceName);
1578 List<String> existingInterfaceLists = elanInterfaceLists.get().getElanInterfaces();
1579 if (existingInterfaceLists != null && !existingInterfaceLists.isEmpty()) {
1580 existingInterfaceLists.forEach(iface -> interfaceLists.add(iface));
1583 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1584 .withKey(new ElanKey(elanInstanceName)).build();
1585 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1586 LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName,
1591 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1592 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1595 @SuppressWarnings("checkstyle:IllegalCatch")
1596 public void handleInternalTunnelStateEvent(Uint64 srcDpId, Uint64 dstDpId) {
1597 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1598 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1599 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1600 if (dpnInterfaceLists == null) {
1603 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1604 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1606 String elanName = elanDpns.getElanInstanceName();
1607 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1608 if (elanInfo == null) {
1609 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1610 + "skipping this ELAN for tunnel handling", elanName);
1613 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1614 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1617 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1618 if (dpnInterfaces == null) {
1621 DpnInterfaces dstDpnIf = null;
1622 for (DpnInterfaces dpnIf : dpnInterfaces) {
1623 Uint64 dpnIfDpId = dpnIf.getDpId();
1624 if (Objects.equals(dpnIfDpId, srcDpId)) {
1626 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1632 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1633 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1634 jobCoordinator.enqueueJob(elanName, () -> {
1635 // update Remote BC Group
1636 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1638 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1639 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1641 } catch (RuntimeException e) {
1642 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1644 Set<String> interfaceLists = new HashSet<>();
1645 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1646 for (String ifName : interfaceLists) {
1647 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1648 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1649 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1650 if (isOperational(interfaceInfo)) {
1651 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1654 }, ElanConstants.JOB_MAX_RETRIES);
1657 }, ElanConstants.JOB_MAX_RETRIES);
1664 * Handle external tunnel state event.
1666 * @param externalTunnel
1667 * the external tunnel
1671 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1672 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1675 // dpId/externalNodeId will be available either in source or destination
1676 // based on the tunnel end point
1678 NodeId externalNodeId = null;
1679 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1680 dpId = Uint64.valueOf(externalTunnel.getSourceDevice());
1681 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1682 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1683 dpId = Uint64.valueOf(externalTunnel.getDestinationDevice());
1684 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1686 if (dpId == null || externalNodeId == null) {
1687 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1691 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1692 if (dpnInterfaceLists == null) {
1695 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1696 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1697 String elanName = elanDpns.getElanInstanceName();
1698 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1700 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1701 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1702 || dpnInterfaces.getInterfaces().isEmpty()) {
1705 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1707 final Uint64 finalDpId = dpId;
1708 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1709 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1710 "Error setting up ELAN BGs");
1711 // install L2gwDevices local macs in dpn.
1712 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1713 // Install dpn macs on external device
1714 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1717 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1721 * Installs dpn macs in external device. first it checks if the physical
1722 * locator towards this dpn tep is present or not if the physical locator is
1723 * present go ahead and add the ucast macs otherwise update the mcast mac
1724 * entry to include this dpn tep ip and schedule the job to put ucast macs
1725 * once the physical locator is programmed in device
1729 * @param lstElanInterfaceNames
1730 * the lst Elan interface names
1733 * @param externalNodeId
1734 * the external node id
1736 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, Uint64 dpnId,
1737 NodeId externalNodeId) {
1738 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1739 externalNodeId.getValue());
1740 if (elanL2GwDevice == null) {
1741 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1744 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1745 if (dpnTepIp == null) {
1746 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1751 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1752 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1753 LogicalDatastoreType.OPERATIONAL);
1754 boolean phyLocAlreadyExists =
1755 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1757 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1758 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1759 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1761 if (phyLocAlreadyExists) {
1762 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1765 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1766 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1770 * Validate external tunnel state event.
1772 * @param externalTunnel
1773 * the external tunnel
1776 * @return true, if successful
1778 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1779 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1780 String srcDevice = externalTunnel.getDestinationDevice();
1781 String destDevice = externalTunnel.getSourceDevice();
1782 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1783 LogicalDatastoreType.CONFIGURATION);
1784 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1785 otherEndPointExtTunnel);
1786 if (otherEndPointExtTunnel != null) {
1787 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1788 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1789 if (otherEndPointInterfaceOperational) {
1792 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1793 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1800 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1801 List<MatchInfo> mkMatches = new ArrayList<>();
1802 // Matching metadata
1804 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1805 mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag)));
1810 protected ElanInterfaceManager getDataTreeChangeListener() {
1814 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1816 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1817 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1818 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1819 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1821 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1822 } catch (InterruptedException e) {
1823 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);