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.slf4j.Logger;
145 import org.slf4j.LoggerFactory;
148 * Class in charge of handling creations, modifications and removals of
151 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
154 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
155 implements RecoverableListener {
156 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
157 public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
158 private static final boolean SH_FLAG_SET = true;
159 private static final boolean SH_FLAG_UNSET = false;
161 private final DataBroker broker;
162 private final ManagedNewTransactionRunner txRunner;
163 private final IMdsalApiManager mdsalManager;
164 private final IInterfaceManager interfaceManager;
165 private final IdManagerService idManager;
166 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
167 private final INeutronVpnManager neutronVpnManager;
168 private final ElanItmUtils elanItmUtils;
169 private final ElanEtreeUtils elanEtreeUtils;
170 private final ElanL2GatewayUtils elanL2GatewayUtils;
171 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
172 private final ElanUtils elanUtils;
173 private final JobCoordinator jobCoordinator;
174 private final ElanInstanceCache elanInstanceCache;
175 private final ElanInterfaceCache elanInterfaceCache;
176 private final ElanGroupCache elanGroupCache;
178 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
179 unProcessedElanInterfaces = new ConcurrentHashMap<>();
182 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
183 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
184 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
185 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
186 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
187 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
188 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
189 final ElanInstanceCache elanInstanceCache,
190 final ElanInterfaceCache elanInterfaceCache,
191 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
192 ElanGroupCache elanGroupCache,
193 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
194 super(ElanInterface.class, ElanInterfaceManager.class);
195 this.broker = dataBroker;
196 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
197 this.idManager = managerService;
198 this.mdsalManager = mdsalApiManager;
199 this.interfaceManager = interfaceManager;
200 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
201 this.neutronVpnManager = neutronVpnManager;
202 this.elanItmUtils = elanItmUtils;
203 this.elanEtreeUtils = elanEtreeUtils;
204 this.elanL2GatewayUtils = elanL2GatewayUtils;
205 this.elanUtils = elanUtils;
206 this.jobCoordinator = jobCoordinator;
207 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
208 this.elanInstanceCache = elanInstanceCache;
209 this.elanInterfaceCache = elanInterfaceCache;
210 this.elanGroupCache = elanGroupCache;
211 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
221 public void registerListener() {
222 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
226 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
227 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
231 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
232 String interfaceName = del.getName();
233 String elanInstanceName = del.getElanInstanceName();
234 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
235 if (elanInterfaces != null && elanInterfaces.contains(del)) {
236 elanInterfaces.remove(del);
237 if (elanInterfaces.isEmpty()) {
238 unProcessedElanInterfaces.remove(elanInstanceName);
241 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
243 * Handling in case the elan instance is deleted.If the Elan instance is
244 * deleted, there is no need to explicitly delete the elan interfaces
246 if (elanInfo == null) {
249 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
250 if (interfaceInfo == null && elanInfo.isExternal()) {
251 // In deleting external network, the underlying ietf Inteface might have been removed
252 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
253 // from Operational DS instead
254 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
256 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
257 interfaceName, interfaceInfo, this);
258 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
261 private static class RemoveElanInterfaceHolder {
262 boolean isLastElanInterface = false;
263 BigInteger dpId = null;
266 @SuppressWarnings("checkstyle:ForbidCertainMethod")
267 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
268 InterfaceInfo interfaceInfo) {
269 String elanName = elanInfo.getElanInstanceName();
270 long elanTag = elanInfo.getElanTag();
271 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
272 List<ListenableFuture<Void>> futures = new ArrayList<>();
273 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
274 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
275 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
276 if (elanState == null) {
279 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
280 List<String> elanInterfaces = elanState.getElanInterfaces();
281 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
282 holder.isLastElanInterface = true;
284 if (interfaceInfo != null) {
285 holder.dpId = interfaceInfo.getDpId();
286 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
287 interfaceName, elanTag, interfaceTx);
289 * If there are not elan ports, remove the unknown dmac, terminating
290 * service table flows, remote/local bc group
292 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
293 || dpnInterfaces.getInterfaces().isEmpty()) {
294 // No more Elan Interfaces in this DPN
295 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
297 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
298 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag());
300 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag());
301 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
302 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
303 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
304 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
305 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
306 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
307 elanUtils.removeTerminatingServiceAction(holder.dpId,
308 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
310 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
313 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
318 futures.forEach(ElanUtils::waitForTransactionToComplete);
320 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
321 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
322 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
323 ElanConstants.JOB_MAX_RETRIES);
328 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
329 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
330 throws ExecutionException, InterruptedException {
331 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
332 if (etreeLeafTag != null) {
333 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
334 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
338 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
339 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
340 throws ExecutionException, InterruptedException {
341 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
342 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
345 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
346 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
347 throws ExecutionException, InterruptedException {
348 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
349 if (etreeInstance != null) {
350 BigInteger dpnId = interfaceInfo.getDpId();
351 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
352 LOG.trace("deleted the localBroadCast Group:{}", groupId);
353 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
357 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
358 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
359 throws ExecutionException, InterruptedException {
360 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
361 if (etreeInstance != null) {
362 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
363 BigInteger dpnId = interfaceInfo.getDpId();
364 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
365 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
366 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
370 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
371 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
372 String elanName = elanInfo.getElanInstanceName();
373 Elan elanState = ElanUtils.getElanByName(tx, elanName);
374 if (elanState == null) {
377 List<String> elanInterfaces = elanState.getElanInterfaces();
378 boolean isRemoved = elanInterfaces != null && elanInterfaces.remove(interfaceName);
383 if (elanInterfaces.isEmpty()) {
384 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
385 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
386 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
387 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
389 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
390 .withKey(new ElanKey(elanName)).build();
391 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
396 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
397 throws ReadFailedException {
398 // removing the ElanInterface from the config data_store if interface is
399 // not present in Interface config DS
400 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
401 interfaceName) == null
402 && elanInterfaceCache.get(interfaceName).isPresent()) {
403 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
407 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
408 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
409 String elanName = elanInfo.getElanInstanceName();
410 List<ListenableFuture<Void>> futures = new ArrayList<>();
411 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
412 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
413 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
414 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
415 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
416 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
417 if (interfaceInfo != null) {
418 if (existingElanInterfaceMac.isPresent()) {
419 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
420 if (existingMacEntries != null) {
421 List<PhysAddress> macAddresses = new ArrayList<>();
422 for (MacEntry macEntry : existingMacEntries) {
423 PhysAddress macAddress = macEntry.getMacAddress();
424 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
425 macAddress.getValue(), interfaceName);
426 Optional<MacEntry> macEntryOptional =
427 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
428 if (!isLastElanInterface && macEntryOptional.isPresent()) {
429 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
431 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
432 macAddresses.add(macAddress);
435 // Removing all those MACs from External Devices belonging
437 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
438 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
442 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
443 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
444 } else if (existingElanInterfaceMac.isPresent()) {
445 // Interface does not exist in ConfigDS, so lets remove everything
446 // about that interface related to Elan
447 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
448 if (macEntries != null) {
449 for (MacEntry macEntry : macEntries) {
450 PhysAddress macAddress = macEntry.getMacAddress();
451 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
452 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
457 if (existingElanInterfaceMac.isPresent()) {
458 interfaceTx.delete(elanInterfaceId);
460 unbindService(interfaceName, flowTx);
461 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
467 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
468 String interfaceName, long elanTag,
469 TypedReadWriteTransaction<Operational> tx)
470 throws ExecutionException, InterruptedException {
471 // FIXME: pass in and use ElanInstanceKey instead?
472 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
475 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
476 if (dpnInterfaces != null) {
477 List<String> interfaceLists = dpnInterfaces.getInterfaces();
478 if (interfaceLists != null) {
479 interfaceLists.remove(interfaceName);
482 if (interfaceLists == null || interfaceLists.isEmpty()) {
483 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
484 deleteElanDpnInterface(elanName, dpId, tx);
486 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
489 return dpnInterfaces;
495 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
496 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
497 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
498 for (DpnInterfaces dpnInterface : dpnInterfaces) {
499 BigInteger currentDpId = dpnInterface.getDpId();
500 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
501 for (String elanInterface : dpnInterface.getInterfaces()) {
502 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
503 if (macs == null || macs.getMacEntry() == null) {
506 for (MacEntry mac : macs.getMacEntry()) {
507 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
508 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
513 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
516 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
517 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
518 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
519 if (etreeLeafTag != null) {
520 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac, confTx);
524 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
525 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
527 .removeFlow(confTx, dpId,
528 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
529 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
530 mac.getMacAddress().getValue(), elanTag)));
534 * Possible Scenarios for update
535 * a. if orig={1,2,3,4} and updated=null or updated={}
536 then all {1,2,3,4} should be removed
538 b. if orig=null or orig={} and updated ={1,2,3,4}
539 then all {1,2,3,4} should be added
541 c. if orig = {1,2,3,4} updated={2,3,4}
542 then 1 should be removed
544 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
545 then we should just add 5
547 e. if orig = {1,2,3,4} updated={2,3,4,5}
548 then 1 should be removed , 5 should be added
550 @SuppressWarnings("checkstyle:ForbidCertainMethod")
552 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
553 // updating the static-Mac Entries for the existing elanInterface
554 String elanName = update.getElanInstanceName();
555 String interfaceName = update.getName();
556 LOG.info("Update static mac entries for elan interface {} in elan instance {}", interfaceName, elanName);
558 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
559 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
560 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
561 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
563 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
564 deletedEntry.getMacAddress()));
566 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
567 * Hence add the macentries for the same.*/
568 for (StaticMacEntries staticMacEntry : updatedEntries) {
569 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
570 staticMacEntry.getMacAddress());
571 addErrorLogging(ElanUtils.waitForTransactionToComplete(
572 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
573 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
574 if (existingMacEntry.isPresent()) {
575 LOG.debug("updating elan interface forwarding table for mac entry {} elan instance {}",
576 existingMacEntry.get(), elanName);
577 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
578 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
581 LOG.info("Adding elan interface forwarding table for mac entry {} elan interface"
582 + " {} elan instance {}.", staticMacEntry.getMacAddress(), interfaceName, elanName);
583 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
584 elanName, interfaceName, staticMacEntry, tx);
586 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
591 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
592 LOG.info("Init for ELAN interface Add {}", elanInterfaceAdded);
593 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
594 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
595 String interfaceName = elanInterfaceAdded.getName();
596 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
597 if (interfaceInfo == null) {
598 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
601 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
603 if (elanInstance == null) {
604 // Add the ElanInstance in the Configuration data-store
605 List<String> elanInterfaces = new ArrayList<>();
606 elanInterfaces.add(interfaceName);
607 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
608 confTx -> ElanUtils.updateOperationalDataStore(idManager,
609 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
610 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
613 Long elanTag = elanInstance.getElanTag();
614 // If elan tag is not updated, then put the elan interface into
615 // unprocessed entry map and entry. Let entries
616 // in this map get processed during ELAN update DCN.
617 if (elanTag == null || elanTag == 0L) {
618 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
619 if (elanInterfaces == null) {
620 elanInterfaces = new ConcurrentLinkedQueue<>();
622 if (!elanInterfaces.contains(elanInterfaceAdded)) {
623 elanInterfaces.add(elanInterfaceAdded);
625 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
628 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
629 interfaceInfo, elanInstance, this);
630 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
631 }), LOG, "Error processing added ELAN interface");
634 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
635 LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName());
636 List<ListenableFuture<Void>> futures = new ArrayList<>();
637 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
638 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
641 for (ElanInterface elanInterface : elanInterfaces) {
642 String interfaceName = elanInterface.getName();
643 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
644 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
646 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
647 LOG.info("Unprocessed elan interfaces for elan instance {} has been removed.",
648 elanInstance.getElanInstanceName());
652 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
653 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
654 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
655 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
656 List<DpnInterfaces> dpnInterfaceLists = null;
657 if (elanDpnInterfacesList != null) {
658 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
660 if (dpnInterfaceLists == null) {
661 dpnInterfaceLists = new ArrayList<>();
663 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
664 BigInteger dstDpId = interfaceInfo.getDpId();
665 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
668 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
669 for (String remoteIf : remoteElanInterfaces) {
670 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
671 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
672 if (elanIfMac == null || remoteInterface == null) {
675 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
676 if (remoteMacEntries != null) {
677 for (MacEntry macEntry : remoteMacEntries) {
678 String macAddress = macEntry.getMacAddress().getValue();
679 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
680 dstDpId, elanInstance.getElanInstanceName());
681 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
682 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
683 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
690 private static class AddElanInterfaceHolder {
691 private DpnInterfaces dpnInterfaces = null;
692 private boolean isFirstInterfaceInDpn = false;
693 private BigInteger dpId;
696 @SuppressWarnings("checkstyle:ForbidCertainMethod")
697 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
698 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
699 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
700 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
701 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
703 String interfaceName = elanInterface.getName();
704 String elanInstanceName = elanInterface.getElanInstanceName();
705 LOG.trace("Adding elan interface: interface name {} , instance name {}", interfaceName, elanInstanceName);
707 List<ListenableFuture<Void>> futures = new ArrayList<>();
708 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
709 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
710 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
711 if (elanInfo == null) {
712 LOG.trace("elanInfo is null for elan instance: {}", elanInstanceName);
713 List<String> elanInterfaces = new ArrayList<>();
714 elanInterfaces.add(interfaceName);
715 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
716 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
719 createElanStateList(elanInstanceName, interfaceName, operTx);
721 // Specific actions to the DPN where the ElanInterface has been added,
722 // for example, programming the
723 // External tunnel table if needed or adding the ElanInterface to the
724 // DpnInterfaces in the operational DS.
725 holder.dpId = interfaceInfo.getDpId();
726 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
727 // FIXME: use elanInstaince.key() instead?
728 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
731 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
732 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
733 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
734 if (ElanUtils.isVlan(elanInstance)) {
735 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
736 elanInstanceName, existingElanDpnInterfaces);
738 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
740 if (holder.isFirstInterfaceInDpn) {
741 // ELAN's 1st ElanInterface added to this DPN
742 if (!existingElanDpnInterfaces.isPresent()) {
743 holder.dpnInterfaces =
744 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
746 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
747 List<String> elanInterfaces =
748 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
749 elanInterfaces.add(interfaceName);
750 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
751 elanInterfaces, operTx);
753 LOG.debug("1st interface {} for elan {} is added to dpn {}",
754 interfaceName, elanInstanceName, holder.dpId);
755 // The 1st ElanInterface in a DPN must program the Ext Tunnel
756 // table, but only if Elan has VNI
757 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
758 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
759 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
761 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
764 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
765 List<String> elanInterfaces =
766 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
767 elanInterfaces.add(interfaceName);
768 if (elanInterfaces.size() == 1) { // 1st dpn interface
769 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
772 holder.dpnInterfaces =
773 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
774 LOG.debug("Interface {} for elan {} is added to dpn {}",
775 interfaceName, elanInstanceName, holder.dpId);
782 // add code to install Local/Remote BC group, unknow DMAC entry,
783 // terminating service table flow entry
784 // call bindservice of interfacemanager to create ingress table flow
786 // Add interface to the ElanInterfaceForwardingEntires Container
787 createElanInterfaceTablesList(interfaceName, operTx);
789 futures.forEach(ElanUtils::waitForTransactionToComplete);
791 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
792 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
793 holder.isFirstInterfaceInDpn, confTx))));
795 // add the vlan provider interface to remote BC group for the elan
796 // for internal vlan networks
797 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
798 if (interfaceManager.isExternalInterface(interfaceName)) {
799 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
800 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
803 if (holder.isFirstInterfaceInDpn) {
804 // ELAN's 1st ElanInterface added to this DPN
805 LOG.debug("Adding dpn into operational dpn list {}", holder.dpId);
806 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
807 operTx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId),
808 holder.dpnInterfaces, CREATE_MISSING_PARENTS);
811 LOG.debug("Updated dpn into operational dpn list {}", holder.dpId);
814 scheduleElanInterfaceWorkerAfterRemoteBcGroup(elanInstance, interfaceInfo, holder.dpnInterfaces,
815 holder.isFirstInterfaceInDpn, elanInterface);
819 @SuppressWarnings("checkstyle:ForbidCertainMethod")
820 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
821 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
822 String elanInstanceName = elanInstance.getElanInstanceName();
823 String interfaceName = elanInterface.getName();
824 List<ListenableFuture<Void>> futures = new ArrayList<>();
825 BigInteger dpId = interfaceInfo.getDpId();
826 boolean isInterfaceOperational = isOperational(interfaceInfo);
827 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
828 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
829 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
830 isFirstInterfaceInDpn, confTx);
832 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
833 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
835 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
836 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
837 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
838 staticMacEntry.getMacAddress());
839 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
840 LogicalDatastoreType.OPERATIONAL, macId);
841 if (existingMacEntry.isPresent()) {
842 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
843 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
844 existingMacEntry.get(), operTx);
846 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
847 interfaceName, staticMacEntry, operTx);
850 if (isInterfaceOperational) {
851 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
853 String macAddress = staticMacEntry.getMacAddress().getValue();
855 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
857 macAddress, elanInstanceName, interfaceName);
858 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
859 staticMacEntry.getMacAddress().getValue(), true, confTx);
863 if (isInterfaceOperational) {
864 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
866 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
867 staticMacAddresses.add(staticMacEntry.getMacAddress());
869 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
875 futures.forEach(ElanUtils::waitForTransactionToComplete);
876 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
877 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
879 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
880 if (neutronPort != null) {
881 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
883 } catch (IllegalArgumentException ex) {
884 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
890 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
891 PhysAddress physAddress) {
892 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
893 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
894 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
895 LogicalDatastoreType.OPERATIONAL, macId);
897 if (!existingMacEntry.isPresent()) {
901 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
902 .withKey(new MacEntryKey(physAddress)).build();
903 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
904 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
907 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
908 Optional<DpnInterfaces> existingElanDpnInterfaces) {
909 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
910 if (!existingElanDpnInterfaces.isPresent()) {
913 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
916 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
917 int dummyInterfaceCount = 0;
918 List<String> interfaces = dpnInterfaces.getInterfaces();
919 if (interfaces == null) {
922 if (interfaces.contains(routerPortUuid)) {
923 dummyInterfaceCount++;
925 if (interfaces.contains(elanInstanceName)) {
926 dummyInterfaceCount++;
928 return interfaces.size() == dummyInterfaceCount;
931 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
932 PhysAddress physAddress) {
933 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
934 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
937 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
938 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
939 if (!isOperational(interfaceInfo)) {
940 LOG.warn("Interface {} is not operational", elanInterface.getName());
943 BigInteger dpId = interfaceInfo.getDpId();
944 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
945 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
947 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
948 if (isFirstInterfaceInDpn) {
949 // Terminating Service , UnknownDMAC Table.
950 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
951 // for ELAN Instance is VxLAN
952 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
953 setupTerminateServiceTable(elanInstance, dpId, confTx);
955 setupUnknownDMacTable(elanInstance, dpId, confTx);
957 * Install remote DMAC flow. This is required since this DPN is
958 * added later to the elan instance and remote DMACs of other
959 * interfaces in this elan instance are not present in the current
962 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
963 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
964 elanInstance.getElanInstanceName());
965 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
968 // bind the Elan service to the Interface
969 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
972 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
973 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
974 if (!isOperational(interfaceInfo)) {
975 LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational",
976 dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName());
979 // LocalBroadcast Group creation with elan-Interfaces
980 LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(),
981 dpnInterfaces.getDpId());
982 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
983 if (isFirstInterfaceInDpn) {
984 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
986 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
987 } catch (InterruptedException e1) {
988 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
993 public InstanceIdentifier<Group> getGroupIid(ElanInstance elanInfo, BigInteger dpnId) {
994 long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
995 return InstanceIdentifier.builder(Nodes.class)
996 .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight
997 .inventory.rev130819.NodeId("openflow:" + dpnId.toString())))
998 .augmentation(FlowCapableNode.class)
999 .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build();
1002 public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo,
1003 InterfaceInfo interfaceInfo,
1004 DpnInterfaces dpnInterfaces,
1005 boolean isFirstInterfaceInDpn,
1006 ElanInterface elanInterface) {
1007 if (!isOperational(interfaceInfo)) {
1008 LOG.debug("Interface {} is not operational", elanInterface.getName());
1011 String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName());
1012 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey,
1013 elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this);
1014 InstanceIdentifier<Group> groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId());
1015 elanGroupCache.addJobToWaitList(groupInstanceId, () -> {
1016 jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
1020 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1021 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1022 int ifTag = interfaceInfo.getInterfaceTag();
1023 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1024 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
1025 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1026 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
1027 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
1029 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
1030 LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}",
1031 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1033 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1034 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1035 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1036 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1038 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
1039 LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}",
1040 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1043 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1044 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1045 int ifTag = interfaceInfo.getInterfaceTag();
1046 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1047 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1049 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1051 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1052 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
1053 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
1054 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1056 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1059 private static List<MatchInfo> buildMatchesForVni(Long vni) {
1060 List<MatchInfo> mkMatches = new ArrayList<>();
1061 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1062 mkMatches.add(match);
1066 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1067 List<InstructionInfo> mkInstructions = new ArrayList<>();
1068 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1069 return mkInstructions;
1072 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1073 List<MatchInfo> mkMatches = new ArrayList<>();
1074 // Matching metadata
1075 mkMatches.add(new MatchMetadata(
1076 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1081 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1082 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1085 * elanTag to be written in metadata when flow is selected
1086 * @return the instructions ready to be installed in a flow
1088 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1089 List<InstructionInfo> mkInstructions = new ArrayList<>();
1090 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1091 .getElanMetadataMask()));
1092 /* applicable for EXTERNAL_TUNNEL_TABLE only
1093 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1095 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1096 return mkInstructions;
1099 // Install DMAC entry on dst DPN
1100 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1101 BigInteger dstDpId) {
1102 String interfaceName = interfaceInfo.getInterfaceName();
1103 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1104 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1105 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1106 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1107 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1108 for (MacEntry macEntry : macEntries) {
1109 String macAddress = macEntry.getMacAddress().getValue();
1110 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1112 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag(), macAddress,
1113 interfaceInfo.getDpId())) {
1114 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1116 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1124 private static void createDropBucket(List<Bucket> listBucket) {
1125 List<Action> actionsInfos = new ArrayList<>();
1126 actionsInfos.add(new ActionDrop().buildAction());
1127 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1128 MDSALUtil.WATCH_GROUP);
1129 listBucket.add(dropBucket);
1132 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1133 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1134 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1135 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1138 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1139 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1140 List<Bucket> listBucket = new ArrayList<>();
1142 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1144 List<String> interfaces = new ArrayList<>();
1145 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1146 interfaces = newDpnInterface.getInterfaces();
1148 for (String ifName : interfaces) {
1149 // In case if there is a InterfacePort in the cache which is not in
1150 // operational state, skip processing it
1151 InterfaceInfo ifInfo = interfaceManager
1152 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1153 if (!isOperational(ifInfo)) {
1157 if (!interfaceManager.isExternalInterface(ifName)) {
1158 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1159 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1164 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1165 MDSALUtil.buildBucketLists(listBucket));
1166 LOG.trace("installing the localBroadCast Group:{}", group);
1167 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1170 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1171 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1172 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1173 if (etreeInstance != null) {
1174 List<Bucket> listBucket = new ArrayList<>();
1177 List<String> interfaces = new ArrayList<>();
1178 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1179 interfaces = newDpnInterface.getInterfaces();
1181 for (String ifName : interfaces) {
1182 // In case if there is a InterfacePort in the cache which is not
1184 // operational state, skip processing it
1185 InterfaceInfo ifInfo = interfaceManager
1186 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1187 if (!isOperational(ifInfo)) {
1191 if (!interfaceManager.isExternalInterface(ifName)) {
1192 // only add root interfaces
1193 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1197 if (listBucket.isEmpty()) { // No Buckets
1198 createDropBucket(listBucket);
1201 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1202 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1203 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1204 MDSALUtil.buildBucketLists(listBucket));
1205 LOG.trace("installing the localBroadCast Group:{}", group);
1206 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1210 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1211 InterfaceInfo ifInfo) {
1212 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1213 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1214 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1215 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1221 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1222 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1223 throws ExecutionException, InterruptedException {
1224 BigInteger dpnId = interfaceInfo.getDpId();
1225 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1226 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1227 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1230 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1231 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1232 throws ExecutionException, InterruptedException {
1233 BigInteger dpnId = interfaceInfo.getDpId();
1234 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1235 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1236 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1240 * Installs a flow in the External Tunnel table consisting in translating
1241 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1242 * elanTag that will be used later in the ELANs pipeline.
1243 * @param dpnId the dpn id
1245 private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1246 TypedWriteTransaction<Configuration> confTx) {
1247 long elanTag = elanInfo.getElanTag();
1248 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1249 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1250 elanInfo.getElanInstanceName(), // flowName
1253 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1254 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1255 getInstructionsIntOrExtTunnelTable(elanTag));
1257 mdsalManager.addFlow(confTx, flowEntity);
1261 * Removes, from External Tunnel table, the flow that translates from VNI to
1262 * elanTag. Important: ensure this method is only called whenever there is
1263 * no other ElanInterface in the specified DPN
1265 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1267 private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
1268 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1269 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1270 // last ElanInstance plus
1271 // adding a new one does (almost at the same time) are executed in that
1274 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1275 FlowEntity flowEntity = new FlowEntityBuilder()
1277 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1280 mdsalManager.removeFlow(confTx, flowEntity);
1283 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1284 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1285 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1286 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1289 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1290 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1291 List<? extends MatchInfoBase> listMatchInfoBase;
1292 List<InstructionInfo> instructionInfos;
1294 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1295 serviceId = elanTag;
1296 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1297 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1299 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1300 listMatchInfoBase = buildMatchesForVni(serviceId);
1301 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1303 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1304 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1305 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1307 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1308 LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId,
1309 elanInfo.getElanInstanceName(), elanTag);
1312 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1313 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1314 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1315 if (etreeInstance != null) {
1316 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1320 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
1321 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1322 long elanTag = elanInfo.getElanTag();
1323 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1324 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1325 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1328 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1329 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1330 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1331 if (etreeLeafTag != null) {
1332 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1333 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1334 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1338 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1339 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1340 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1341 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1342 5, elanInfo.getElanInstanceName(), 0, 0,
1343 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1344 getMatchesForElanTag(elanTag, /* SH flag */false),
1345 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1347 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1348 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}",
1349 dpId, elanInfo.getElanInstanceName(), elanTag);
1352 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1353 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1354 // only if ELAN can connect to external network, perform the following
1356 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1357 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1358 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1359 5, elanInfo.getElanInstanceName(), 0, 0,
1360 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1361 getMatchesForElanTag(elanTag, /* SH flag */true),
1362 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1363 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1364 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to "
1365 + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag);
1370 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
1371 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1372 throws ExecutionException, InterruptedException {
1373 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1374 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1375 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1377 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1378 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1379 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1381 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1385 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1386 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1389 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1390 TypedWriteTransaction<Configuration> tx) {
1391 if (isStandardElanService(elanInterface)) {
1392 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1393 elanInterface.getName(), lportTag, tx);
1394 } else { // Etree service
1395 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1399 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1400 TypedWriteTransaction<Configuration> tx) {
1401 int instructionKey = 0;
1402 List<Instruction> instructions = new ArrayList<>();
1403 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1404 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1406 List<Action> actions = new ArrayList<>();
1407 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1408 lportTag).buildAction());
1409 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1410 elanTag).buildAction());
1411 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1413 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1416 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1417 BoundServices serviceInfo = ElanUtils.getBoundServices(
1418 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1419 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1420 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1421 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1423 if (!existingElanService.isPresent()) {
1424 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1425 LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName);
1429 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1430 TypedWriteTransaction<Configuration> tx) {
1431 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1432 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1435 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1436 if (etreeInstance == null) {
1437 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1438 elanInterface.getName(), elanInfo.getElanInstanceName());
1440 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1441 elanInterface.getName(), lportTag, tx);
1446 private static boolean isStandardElanService(ElanInterface elanInterface) {
1447 return elanInterface.augmentation(EtreeInterface.class) == null;
1450 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1451 throws ExecutionException, InterruptedException {
1452 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1453 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1454 if (tx.read(bindServiceId).get().isPresent()) {
1455 tx.delete(bindServiceId);
1459 private static String getFlowRef(long tableId, long elanTag) {
1460 return String.valueOf(tableId) + elanTag;
1463 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1464 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1465 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1468 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1469 return String.valueOf(tableId) + elanTag + shFlag;
1472 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1473 List<Action> listAction = new ArrayList<>();
1476 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1478 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1482 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1483 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1484 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1485 .withKey(new DpnInterfacesKey(dpId)).build();
1486 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1487 CREATE_MISSING_PARENTS);
1488 LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName,
1490 return dpnInterface;
1494 * Delete elan dpn interface from operational DS.
1496 * @param elanInstanceName
1497 * the elan instance name
1501 private static void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
1502 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1503 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1504 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1505 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1506 if (dpnInterfaces.isPresent()) {
1507 tx.delete(dpnInterfacesId);
1511 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1512 BigInteger dpId, TypedWriteTransaction<Operational> tx) {
1513 List<String> interfaceNames = new ArrayList<>();
1514 interfaceNames.add(interfaceName);
1515 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1516 .withKey(new DpnInterfacesKey(dpId)).build();
1517 return dpnInterface;
1520 private static void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
1521 throws ExecutionException, InterruptedException {
1522 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1523 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1524 Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
1525 // Adding new Elan Interface Port to the operational DataStore without
1526 // Static-Mac Entries..
1527 if (!interfaceMacTables.isPresent()) {
1528 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1529 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1530 tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1531 CREATE_MISSING_PARENTS);
1532 LOG.trace("Created interface MAC table for interface: {}", interfaceName);
1536 private static void createElanStateList(String elanInstanceName, String interfaceName,
1537 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1538 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1539 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1540 // Adding new Elan Interface Port to the operational DataStore without
1541 // Static-Mac Entries..
1542 if (elanInterfaceLists.isPresent()) {
1543 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1544 if (interfaceLists == null) {
1545 interfaceLists = new ArrayList<>();
1547 interfaceLists.add(interfaceName);
1548 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1549 .withKey(new ElanKey(elanInstanceName)).build();
1550 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1551 LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName,
1556 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1557 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1560 @SuppressWarnings("checkstyle:IllegalCatch")
1561 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1562 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1563 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1564 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1565 if (dpnInterfaceLists == null) {
1568 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1569 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1571 String elanName = elanDpns.getElanInstanceName();
1572 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1573 if (elanInfo == null) {
1574 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1575 + "skipping this ELAN for tunnel handling", elanName);
1578 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1579 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1582 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1583 if (dpnInterfaces == null) {
1586 DpnInterfaces dstDpnIf = null;
1587 for (DpnInterfaces dpnIf : dpnInterfaces) {
1588 BigInteger dpnIfDpId = dpnIf.getDpId();
1589 if (Objects.equals(dpnIfDpId, srcDpId)) {
1591 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1597 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1598 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1599 jobCoordinator.enqueueJob(elanName, () -> {
1600 // update Remote BC Group
1601 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1603 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1604 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1606 } catch (RuntimeException e) {
1607 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1609 Set<String> interfaceLists = new HashSet<>();
1610 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1611 for (String ifName : interfaceLists) {
1612 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1613 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1614 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1615 if (isOperational(interfaceInfo)) {
1616 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1619 }, ElanConstants.JOB_MAX_RETRIES);
1622 }, ElanConstants.JOB_MAX_RETRIES);
1629 * Handle external tunnel state event.
1631 * @param externalTunnel
1632 * the external tunnel
1636 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1637 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1640 // dpId/externalNodeId will be available either in source or destination
1641 // based on the tunnel end point
1642 BigInteger dpId = null;
1643 NodeId externalNodeId = null;
1644 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1645 dpId = new BigInteger(externalTunnel.getSourceDevice());
1646 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1647 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1648 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1649 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1651 if (dpId == null || externalNodeId == null) {
1652 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1656 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1657 if (dpnInterfaceLists == null) {
1660 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1661 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1662 String elanName = elanDpns.getElanInstanceName();
1663 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1665 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1666 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1667 || dpnInterfaces.getInterfaces().isEmpty()) {
1670 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1672 final BigInteger finalDpId = dpId;
1673 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1674 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1675 "Error setting up ELAN BGs");
1676 // install L2gwDevices local macs in dpn.
1677 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1678 // Install dpn macs on external device
1679 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1682 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1686 * Installs dpn macs in external device. first it checks if the physical
1687 * locator towards this dpn tep is present or not if the physical locator is
1688 * present go ahead and add the ucast macs otherwise update the mcast mac
1689 * entry to include this dpn tep ip and schedule the job to put ucast macs
1690 * once the physical locator is programmed in device
1694 * @param lstElanInterfaceNames
1695 * the lst Elan interface names
1698 * @param externalNodeId
1699 * the external node id
1701 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1702 NodeId externalNodeId) {
1703 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1704 externalNodeId.getValue());
1705 if (elanL2GwDevice == null) {
1706 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1709 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1710 if (dpnTepIp == null) {
1711 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1716 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1717 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1718 LogicalDatastoreType.OPERATIONAL);
1719 boolean phyLocAlreadyExists =
1720 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1722 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1723 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1724 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1726 if (phyLocAlreadyExists) {
1727 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1730 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1731 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1735 * Validate external tunnel state event.
1737 * @param externalTunnel
1738 * the external tunnel
1741 * @return true, if successful
1743 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1744 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1745 String srcDevice = externalTunnel.getDestinationDevice();
1746 String destDevice = externalTunnel.getSourceDevice();
1747 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1748 LogicalDatastoreType.CONFIGURATION);
1749 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1750 otherEndPointExtTunnel);
1751 if (otherEndPointExtTunnel != null) {
1752 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1753 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1754 if (otherEndPointInterfaceOperational) {
1757 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1758 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1765 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1766 List<MatchInfo> mkMatches = new ArrayList<>();
1767 // Matching metadata
1769 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1770 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1775 protected ElanInterfaceManager getDataTreeChangeListener() {
1779 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1781 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1782 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1783 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1784 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1786 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1787 } catch (InterruptedException e) {
1788 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);