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.dpn.interfaces.ElanDpnInterfacesList;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
140 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
141 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
142 import org.opendaylight.yangtools.yang.common.Uint32;
143 import org.opendaylight.yangtools.yang.common.Uint64;
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 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("NetvirtEventLogger");
158 public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
159 private static final boolean SH_FLAG_SET = true;
160 private static final boolean SH_FLAG_UNSET = false;
162 private final DataBroker broker;
163 private final ManagedNewTransactionRunner txRunner;
164 private final IMdsalApiManager mdsalManager;
165 private final IInterfaceManager interfaceManager;
166 private final IdManagerService idManager;
167 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
168 private final INeutronVpnManager neutronVpnManager;
169 private final ElanItmUtils elanItmUtils;
170 private final ElanEtreeUtils elanEtreeUtils;
171 private final ElanL2GatewayUtils elanL2GatewayUtils;
172 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
173 private final ElanUtils elanUtils;
174 private final JobCoordinator jobCoordinator;
175 private final ElanInstanceCache elanInstanceCache;
176 private final ElanInterfaceCache elanInterfaceCache;
177 private final ElanGroupCache elanGroupCache;
179 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
180 unProcessedElanInterfaces = new ConcurrentHashMap<>();
183 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
184 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
185 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
186 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
187 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
188 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
189 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
190 final ElanInstanceCache elanInstanceCache,
191 final ElanInterfaceCache elanInterfaceCache,
192 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
193 ElanGroupCache elanGroupCache,
194 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
195 super(ElanInterface.class, ElanInterfaceManager.class);
196 this.broker = dataBroker;
197 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
198 this.idManager = managerService;
199 this.mdsalManager = mdsalApiManager;
200 this.interfaceManager = interfaceManager;
201 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
202 this.neutronVpnManager = neutronVpnManager;
203 this.elanItmUtils = elanItmUtils;
204 this.elanEtreeUtils = elanEtreeUtils;
205 this.elanL2GatewayUtils = elanL2GatewayUtils;
206 this.elanUtils = elanUtils;
207 this.jobCoordinator = jobCoordinator;
208 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
209 this.elanInstanceCache = elanInstanceCache;
210 this.elanInterfaceCache = elanInterfaceCache;
211 this.elanGroupCache = elanGroupCache;
212 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
222 public void registerListener() {
223 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
227 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
228 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
232 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
233 String interfaceName = del.getName();
234 String elanInstanceName = del.getElanInstanceName();
235 EVENT_LOGGER.debug("ELAN-Interface, REMOVE {} Instance {}", interfaceName, elanInstanceName);
236 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
237 if (elanInterfaces != null && elanInterfaces.contains(del)) {
238 elanInterfaces.remove(del);
239 if (elanInterfaces.isEmpty()) {
240 unProcessedElanInterfaces.remove(elanInstanceName);
243 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
245 * Handling in case the elan instance is deleted.If the Elan instance is
246 * deleted, there is no need to explicitly delete the elan interfaces
248 if (elanInfo == null) {
251 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
252 if (interfaceInfo == null && elanInfo.isExternal()) {
253 // In deleting external network, the underlying ietf Inteface might have been removed
254 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
255 // from Operational DS instead
256 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
258 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
259 interfaceName, interfaceInfo, this);
260 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
263 private static class RemoveElanInterfaceHolder {
264 boolean isLastElanInterface = false;
268 @SuppressWarnings("checkstyle:ForbidCertainMethod")
269 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
270 InterfaceInfo interfaceInfo) {
271 String elanName = elanInfo.getElanInstanceName();
272 EVENT_LOGGER.debug("ELAN-InterfaceState, REMOVE {} Instance {}", interfaceName, elanName);
273 Uint32 elanTag = elanInfo.getElanTag();
274 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
275 List<ListenableFuture<Void>> futures = new ArrayList<>();
276 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
277 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
278 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
279 if (elanState == null) {
282 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
283 List<String> elanInterfaces = elanState.getElanInterfaces();
284 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
285 holder.isLastElanInterface = true;
287 if (interfaceInfo != null) {
288 holder.dpId = interfaceInfo.getDpId();
289 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
290 interfaceName, elanTag, interfaceTx);
292 * If there are not elan ports, remove the unknown dmac, terminating
293 * service table flows, remote/local bc group
295 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
296 || dpnInterfaces.getInterfaces().isEmpty()) {
297 // No more Elan Interfaces in this DPN
298 EVENT_LOGGER.debug("ELAN-Flows, REMOVE {} Instance {}", interfaceName, elanName);
299 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
301 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
302 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag().toJava());
304 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag().toJava());
305 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
306 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
307 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
308 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
309 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
310 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
311 elanUtils.removeTerminatingServiceAction(holder.dpId,
312 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
314 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
317 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
322 futures.forEach(ElanUtils::waitForTransactionToComplete);
324 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
325 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
326 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
327 ElanConstants.JOB_MAX_RETRIES);
332 private void removeEtreeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
333 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
334 throws ExecutionException, InterruptedException {
335 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag().toJava());
336 if (etreeLeafTag != null) {
337 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
338 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
342 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
343 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
344 throws ExecutionException, InterruptedException {
345 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
346 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
349 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
350 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
351 throws ExecutionException, InterruptedException {
352 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
353 if (etreeInstance != null) {
354 Uint64 dpnId = interfaceInfo.getDpId();
355 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue().toJava());
356 LOG.trace("deleted the localBroadCast Group:{}", groupId);
357 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
361 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
362 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
363 throws ExecutionException, InterruptedException {
364 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
365 if (etreeInstance != null) {
366 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
367 Uint64 dpnId = interfaceInfo.getDpId();
368 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
369 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
370 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
374 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
375 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
376 String elanName = elanInfo.getElanInstanceName();
377 Elan elanState = ElanUtils.getElanByName(tx, elanName);
378 if (elanState == null) {
381 List<String> existingElanInterfaces = elanState.getElanInterfaces();
382 List<String> elanInterfaces = new ArrayList<>();
383 if (existingElanInterfaces != null) {
384 elanInterfaces.addAll(existingElanInterfaces);
386 boolean isRemoved = elanInterfaces.remove(interfaceName);
391 if (elanInterfaces.isEmpty()) {
392 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
393 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
394 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
395 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
397 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
398 .withKey(new ElanKey(elanName)).build();
399 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
404 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
405 throws ReadFailedException {
406 // removing the ElanInterface from the config data_store if interface is
407 // not present in Interface config DS
408 if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
409 interfaceName) == null
410 && elanInterfaceCache.get(interfaceName).isPresent()) {
411 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
415 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
416 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
417 String elanName = elanInfo.getElanInstanceName();
418 EVENT_LOGGER.debug("ELAN-InterfaceEntries, REMOVE {} Instance {}", interfaceName, elanName);
419 List<ListenableFuture<Void>> futures = new ArrayList<>();
420 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
421 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
422 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
423 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
424 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
425 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
426 if (interfaceInfo != null) {
427 if (existingElanInterfaceMac.isPresent()) {
428 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
429 if (existingMacEntries != null) {
430 List<PhysAddress> macAddresses = new ArrayList<>();
431 for (MacEntry macEntry : existingMacEntries) {
432 PhysAddress macAddress = macEntry.getMacAddress();
433 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
434 macAddress.getValue(), interfaceName);
435 Optional<MacEntry> macEntryOptional =
436 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
437 if (!isLastElanInterface && macEntryOptional.isPresent()) {
438 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
440 EVENT_LOGGER.debug("ELAN-MacFlows, REMOVE {} Instance {} Mac {}",
441 interfaceName, elanName, macAddress);
442 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
443 macAddresses.add(macAddress);
446 // Removing all those MACs from External Devices belonging
448 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
449 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
453 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
454 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
455 } else if (existingElanInterfaceMac.isPresent()) {
456 // Interface does not exist in ConfigDS, so lets remove everything
457 // about that interface related to Elan
458 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
459 if (macEntries != null) {
460 for (MacEntry macEntry : macEntries) {
461 PhysAddress macAddress = macEntry.getMacAddress();
462 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
463 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
468 if (existingElanInterfaceMac.isPresent()) {
469 interfaceTx.delete(elanInterfaceId);
471 unbindService(interfaceName, flowTx);
472 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
478 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, Uint64 dpId,
479 String interfaceName, Uint32 elanTag,
480 TypedReadWriteTransaction<Operational> tx)
481 throws ExecutionException, InterruptedException {
482 // FIXME: pass in and use ElanInstanceKey instead?
483 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
486 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
487 if (dpnInterfaces != null) {
488 List<String> interfaceLists = null;
489 if (dpnInterfaces.getInterfaces() != null) {
490 interfaceLists = new ArrayList<>(dpnInterfaces.getInterfaces());
492 if (interfaceLists != null) {
493 interfaceLists.remove(interfaceName);
496 if (interfaceLists == null || interfaceLists.isEmpty()) {
497 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
498 deleteElanDpnInterface(elanName, dpId, tx);
500 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
503 return dpnInterfaces;
509 private void deleteAllRemoteMacsInADpn(String elanName, Uint64 dpId, Uint32 elanTag) {
510 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
511 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
512 for (DpnInterfaces dpnInterface : dpnInterfaces) {
513 Uint64 currentDpId = dpnInterface.getDpId();
514 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
515 for (String elanInterface : dpnInterface.getInterfaces()) {
516 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
517 if (macs == null || macs.getMacEntry() == null) {
520 for (MacEntry mac : macs.getMacEntry()) {
521 removeTheMacFlowInTheDPN(dpId, elanTag, mac, confTx);
522 removeEtreeMacFlowInTheDPN(dpId, elanTag, mac, confTx);
527 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
530 private void removeEtreeMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac,
531 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
532 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
533 if (etreeLeafTag != null) {
534 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), mac, confTx);
538 private void removeTheMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac,
539 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
541 .removeFlow(confTx, dpId,
542 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
543 ElanUtils.getKnownDynamicmacFlowRef(elanTag, mac.getMacAddress().getValue())));
547 * Possible Scenarios for update
548 * a. if orig={1,2,3,4} and updated=null or updated={}
549 then all {1,2,3,4} should be removed
551 b. if orig=null or orig={} and updated ={1,2,3,4}
552 then all {1,2,3,4} should be added
554 c. if orig = {1,2,3,4} updated={2,3,4}
555 then 1 should be removed
557 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
558 then we should just add 5
560 e. if orig = {1,2,3,4} updated={2,3,4,5}
561 then 1 should be removed , 5 should be added
563 @SuppressWarnings("checkstyle:ForbidCertainMethod")
565 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
566 // updating the static-Mac Entries for the existing elanInterface
567 String elanName = update.getElanInstanceName();
568 String interfaceName = update.getName();
569 LOG.info("Update static mac entries for elan interface {} in elan instance {}", interfaceName, elanName);
570 EVENT_LOGGER.debug("ELAN-Interface, UPDATE {} Instance {}", original.getName(), elanName);
572 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
573 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
574 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
575 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
577 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
578 deletedEntry.getMacAddress()));
580 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
581 * Hence add the macentries for the same.*/
582 for (StaticMacEntries staticMacEntry : updatedEntries) {
583 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
584 staticMacEntry.getMacAddress());
585 addErrorLogging(ElanUtils.waitForTransactionToComplete(
586 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
587 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
588 if (existingMacEntry.isPresent()) {
589 LOG.debug("updating elan interface forwarding table for mac entry {} elan instance {}",
590 existingMacEntry.get(), elanName);
591 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
592 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
595 LOG.info("Adding elan interface forwarding table for mac entry {} elan interface"
596 + " {} elan instance {}.", staticMacEntry.getMacAddress(), interfaceName, elanName);
597 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
598 elanName, interfaceName, staticMacEntry, tx);
600 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
605 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
606 LOG.info("Init for ELAN interface Add {}", elanInterfaceAdded);
607 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
608 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
609 String interfaceName = elanInterfaceAdded.getName();
610 EVENT_LOGGER.debug("ELAN-Interface, ADD {} Instance {}", interfaceName, elanInstanceName);
611 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
612 if (interfaceInfo == null) {
613 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
616 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
618 if (elanInstance == null) {
619 // Add the ElanInstance in the Configuration data-store
620 List<String> elanInterfaces = new ArrayList<>();
621 elanInterfaces.add(interfaceName);
622 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
623 confTx -> ElanUtils.updateOperationalDataStore(idManager,
624 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
625 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
628 Uint32 elanTag = elanInstance.getElanTag();
629 // If elan tag is not updated, then put the elan interface into
630 // unprocessed entry map and entry. Let entries
631 // in this map get processed during ELAN update DCN.
632 if (elanTag == null || elanTag.longValue() == 0L) {
633 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
634 if (elanInterfaces == null) {
635 elanInterfaces = new ConcurrentLinkedQueue<>();
637 if (!elanInterfaces.contains(elanInterfaceAdded)) {
638 elanInterfaces.add(elanInterfaceAdded);
640 LOG.error("ELAN tag for instance {} is not created. Adding it to unprocessed list."
641 + " Recreate the network if this message is seen multiple times", elanInstanceName);
642 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
645 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
646 interfaceInfo, elanInstance, this);
647 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
648 }), LOG, "Error processing added ELAN interface");
651 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
652 LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName());
653 List<ListenableFuture<Void>> futures = new ArrayList<>();
654 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
655 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
658 for (ElanInterface elanInterface : elanInterfaces) {
659 String interfaceName = elanInterface.getName();
660 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
661 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
663 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
664 LOG.info("Unprocessed elan interfaces for elan instance {} has been removed.",
665 elanInstance.getElanInstanceName());
669 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
670 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
671 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
672 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
673 List<DpnInterfaces> dpnInterfaceLists = null;
674 if (elanDpnInterfacesList != null) {
675 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
677 if (dpnInterfaceLists != null && !dpnInterfaceLists.isEmpty()) {
678 Uint64 dstDpId = interfaceInfo.getDpId();
679 processRemoteDmacFlowForInterface(dstDpId, elanInstance, dpnInterfaceLists, writeFlowGroupTx);
683 private void processRemoteDmacFlowForInterface(Uint64 dstDpId, ElanInstance elanInstance,
684 List<DpnInterfaces> dpnInterfaceLists, TypedWriteTransaction<Configuration> writeFlowGroupTx) {
685 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
686 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
689 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
690 if (remoteElanInterfaces == null || remoteElanInterfaces.isEmpty()) {
693 for (String remoteIf : remoteElanInterfaces) {
694 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
695 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
696 if (elanIfMac == null || remoteInterface == null) {
699 List<MacEntry> remoteMacEntries = elanIfMac.nonnullMacEntry();
700 for (MacEntry macEntry : remoteMacEntries) {
701 String macAddress = macEntry.getMacAddress().getValue();
702 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
703 dstDpId, elanInstance.getElanInstanceName());
704 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
705 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
706 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
712 private static class AddElanInterfaceHolder {
713 private DpnInterfaces dpnInterfaces = null;
714 private boolean isFirstInterfaceInDpn = false;
718 @SuppressWarnings("checkstyle:ForbidCertainMethod")
719 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
720 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
721 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
722 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
723 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
725 String interfaceName = elanInterface.getName();
726 String elanInstanceName = elanInterface.getElanInstanceName();
727 LOG.trace("Adding elan interface: interface name {} , instance name {}", interfaceName, elanInstanceName);
728 EVENT_LOGGER.debug("ELAN-InterfaceState, ADD {} Instance {}", interfaceName, elanInstanceName);
730 List<ListenableFuture<Void>> futures = new ArrayList<>();
731 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
732 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
733 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
734 if (elanInfo == null) {
735 LOG.trace("elanInfo is null for elan instance: {}", elanInstanceName);
736 List<String> elanInterfaces = new ArrayList<>();
737 elanInterfaces.add(interfaceName);
738 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
739 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
742 createElanStateList(elanInstanceName, interfaceName, operTx);
744 // Specific actions to the DPN where the ElanInterface has been added,
745 // for example, programming the
746 // External tunnel table if needed or adding the ElanInterface to the
747 // DpnInterfaces in the operational DS.
748 holder.dpId = interfaceInfo.getDpId();
749 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
750 // FIXME: use elanInstaince.key() instead?
751 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
754 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
755 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
756 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
757 if (ElanUtils.isVlan(elanInstance)) {
758 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
759 elanInstanceName, existingElanDpnInterfaces);
761 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
763 if (holder.isFirstInterfaceInDpn) {
764 // ELAN's 1st ElanInterface added to this DPN
765 if (!existingElanDpnInterfaces.isPresent()) {
766 holder.dpnInterfaces =
767 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
769 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
770 List<String> elanInterfaces =
771 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
772 elanInterfaces.add(interfaceName);
773 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
774 elanInterfaces, operTx);
776 LOG.debug("1st interface {} for elan {} is added to dpn {}",
777 interfaceName, elanInstanceName, holder.dpId);
778 // The 1st ElanInterface in a DPN must program the Ext Tunnel
779 // table, but only if Elan has VNI
780 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
781 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
782 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
784 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
787 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
788 List<String> elanInterfaces =
789 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
790 elanInterfaces.add(interfaceName);
791 if (elanInterfaces.size() == 1) { // 1st dpn interface
792 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
795 holder.dpnInterfaces =
796 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
797 LOG.debug("Interface {} for elan {} is added to dpn {}",
798 interfaceName, elanInstanceName, holder.dpId);
805 // add code to install Local/Remote BC group, unknow DMAC entry,
806 // terminating service table flow entry
807 // call bindservice of interfacemanager to create ingress table flow
810 futures.forEach(ElanUtils::waitForTransactionToComplete);
812 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
813 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
814 holder.isFirstInterfaceInDpn, confTx))));
816 // add the vlan provider interface to remote BC group for the elan
817 // for internal vlan networks
818 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
819 if (interfaceManager.isExternalInterface(interfaceName)) {
820 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
821 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
824 if (holder.isFirstInterfaceInDpn) {
825 // ELAN's 1st ElanInterface added to this DPN
826 LOG.debug("Adding dpn into operational dpn list {}", holder.dpId);
827 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
828 operTx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId),
829 holder.dpnInterfaces, CREATE_MISSING_PARENTS);
832 LOG.debug("Updated dpn into operational dpn list {}", holder.dpId);
835 scheduleElanInterfaceWorkerAfterRemoteBcGroup(elanInstance, interfaceInfo, holder.dpnInterfaces,
836 holder.isFirstInterfaceInDpn, elanInterface);
840 @SuppressWarnings("checkstyle:ForbidCertainMethod")
841 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
842 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
843 String elanInstanceName = elanInstance.getElanInstanceName();
844 String interfaceName = elanInterface.getName();
845 List<ListenableFuture<Void>> futures = new ArrayList<>();
846 Uint64 dpId = interfaceInfo.getDpId();
847 boolean isInterfaceOperational = isOperational(interfaceInfo);
848 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
849 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
850 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
851 isFirstInterfaceInDpn, confTx);
853 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
854 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
856 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
857 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
858 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
859 staticMacEntry.getMacAddress());
860 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
861 LogicalDatastoreType.OPERATIONAL, macId);
862 if (existingMacEntry.isPresent()) {
863 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
864 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
865 existingMacEntry.get(), operTx);
867 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
868 interfaceName, staticMacEntry, operTx);
871 if (isInterfaceOperational) {
872 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
874 String macAddress = staticMacEntry.getMacAddress().getValue();
876 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
878 macAddress, elanInstanceName, interfaceName);
879 EVENT_LOGGER.debug("ELAN-MacFlows, ADD {} Instance {} Mac {}",
880 interfaceName, elanInstanceName, macAddress);
881 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
882 staticMacEntry.getMacAddress().getValue(), true, confTx);
886 if (isInterfaceOperational) {
887 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
889 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
890 staticMacAddresses.add(staticMacEntry.getMacAddress());
892 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
898 futures.forEach(ElanUtils::waitForTransactionToComplete);
899 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
900 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
902 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
903 if (neutronPort != null) {
904 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
906 } catch (IllegalArgumentException ex) {
907 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
913 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
914 PhysAddress physAddress) {
915 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
916 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
917 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
918 LogicalDatastoreType.OPERATIONAL, macId);
920 if (!existingMacEntry.isPresent()) {
924 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
925 .withKey(new MacEntryKey(physAddress)).build();
926 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
927 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
930 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
931 Optional<DpnInterfaces> existingElanDpnInterfaces) {
932 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
933 if (!existingElanDpnInterfaces.isPresent()) {
936 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
939 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
940 int dummyInterfaceCount = 0;
941 List<String> interfaces = dpnInterfaces.getInterfaces();
942 if (interfaces == null) {
945 if (interfaces.contains(routerPortUuid)) {
946 dummyInterfaceCount++;
948 if (interfaces.contains(elanInstanceName)) {
949 dummyInterfaceCount++;
951 return interfaces.size() == dummyInterfaceCount;
954 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
955 PhysAddress physAddress) {
956 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
957 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
960 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
961 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
962 if (!isOperational(interfaceInfo)) {
963 LOG.warn("Interface {} is not operational", elanInterface.getName());
964 EVENT_LOGGER.debug("ELAN-InterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
965 elanInterface.getName(), elanInstance.getElanInstanceName(), interfaceInfo.getOpState());
968 Uint64 dpId = interfaceInfo.getDpId();
969 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
970 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
972 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
973 if (isFirstInterfaceInDpn) {
974 // Terminating Service , UnknownDMAC Table.
975 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
976 // for ELAN Instance is VxLAN
977 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
978 setupTerminateServiceTable(elanInstance, dpId, confTx);
980 setupUnknownDMacTable(elanInstance, dpId, confTx);
982 * Install remote DMAC flow. This is required since this DPN is
983 * added later to the elan instance and remote DMACs of other
984 * interfaces in this elan instance are not present in the current
987 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
988 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
989 elanInstance.getElanInstanceName());
990 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
993 // bind the Elan service to the Interface
994 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
997 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
998 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
999 if (!isOperational(interfaceInfo)) {
1000 LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational",
1001 dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName());
1002 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
1003 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1006 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {}",
1007 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
1008 // LocalBroadcast Group creation with elan-Interfaces
1009 LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(),
1010 dpnInterfaces.getDpId());
1011 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
1012 if (isFirstInterfaceInDpn) {
1013 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
1015 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1016 } catch (InterruptedException e1) {
1017 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
1022 public InstanceIdentifier<Group> getGroupIid(ElanInstance elanInfo, Uint64 dpnId) {
1023 long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1024 return InstanceIdentifier.builder(Nodes.class)
1025 .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight
1026 .inventory.rev130819.NodeId("openflow:" + dpnId.toString())))
1027 .augmentation(FlowCapableNode.class)
1028 .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build();
1031 public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo,
1032 InterfaceInfo interfaceInfo,
1033 DpnInterfaces dpnInterfaces,
1034 boolean isFirstInterfaceInDpn,
1035 ElanInterface elanInterface) {
1036 if (!isOperational(interfaceInfo)) {
1037 LOG.debug("Interface {} is not operational", elanInterface.getName());
1040 String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName());
1041 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey,
1042 elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this);
1043 InstanceIdentifier<Group> groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId());
1044 elanGroupCache.addJobToWaitList(groupInstanceId, () -> {
1045 jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
1049 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1050 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1051 int ifTag = interfaceInfo.getInterfaceTag();
1052 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1053 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 11, elanInfo.getElanInstanceName(),
1054 0, 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1055 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
1056 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
1058 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
1059 LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}",
1060 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1062 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1063 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 12, elanInfo.getElanInstanceName(), 0,
1064 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1065 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
1067 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
1068 LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}",
1069 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1072 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1073 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1074 int ifTag = interfaceInfo.getInterfaceTag();
1075 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1076 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1078 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1080 Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1081 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"));
1083 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1086 private static List<MatchInfo> buildMatchesForVni(Uint64 vni) {
1087 List<MatchInfo> mkMatches = new ArrayList<>();
1088 MatchInfo match = new MatchTunnelId(vni);
1089 mkMatches.add(match);
1093 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1094 List<InstructionInfo> mkInstructions = new ArrayList<>();
1095 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1096 return mkInstructions;
1099 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1100 List<MatchInfo> mkMatches = new ArrayList<>();
1101 // Matching metadata
1102 mkMatches.add(new MatchMetadata(
1103 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1108 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1109 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1112 * elanTag to be written in metadata when flow is selected
1113 * @return the instructions ready to be installed in a flow
1115 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Uint32 elanTag) {
1116 List<InstructionInfo> mkInstructions = new ArrayList<>();
1117 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
1118 ElanHelper.getElanMetadataMask()));
1119 /* applicable for EXTERNAL_TUNNEL_TABLE only
1120 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1122 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1123 return mkInstructions;
1126 // Install DMAC entry on dst DPN
1127 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1129 String interfaceName = interfaceInfo.getInterfaceName();
1130 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1131 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1132 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1133 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1134 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1135 for (MacEntry macEntry : macEntries) {
1136 String macAddress = macEntry.getMacAddress().getValue();
1137 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1139 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress,
1140 interfaceInfo.getDpId())) {
1141 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1143 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1151 private static void createDropBucket(List<Bucket> listBucket) {
1152 List<Action> actionsInfos = new ArrayList<>();
1153 actionsInfos.add(new ActionDrop().buildAction());
1154 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1155 MDSALUtil.WATCH_GROUP);
1156 listBucket.add(dropBucket);
1159 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1160 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1161 if (!isOperational(interfaceInfo)) {
1162 EVENT_LOGGER.debug("ELAN-LBG, ADD {} Instance {} Interface Status {}, returning",
1163 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1166 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1167 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1170 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1171 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1172 List<Bucket> listBucket = new ArrayList<>();
1174 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1176 List<String> interfaces = new ArrayList<>();
1177 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1178 interfaces = newDpnInterface.getInterfaces();
1180 for (String ifName : interfaces) {
1181 // In case if there is a InterfacePort in the cache which is not in
1182 // operational state, skip processing it
1183 InterfaceInfo ifInfo = interfaceManager
1184 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1185 if (!isOperational(ifInfo)) {
1189 if (!interfaceManager.isExternalInterface(ifName)) {
1190 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1191 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1196 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1197 MDSALUtil.buildBucketLists(listBucket));
1198 LOG.trace("installing the localBroadCast Group:{}", group);
1199 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1202 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1203 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1204 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1205 if (etreeInstance != null) {
1206 List<Bucket> listBucket = new ArrayList<>();
1209 List<String> interfaces = new ArrayList<>();
1210 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1211 interfaces = newDpnInterface.getInterfaces();
1213 for (String ifName : interfaces) {
1214 // In case if there is a InterfacePort in the cache which is not
1216 // operational state, skip processing it
1217 InterfaceInfo ifInfo = interfaceManager
1218 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1219 if (!isOperational(ifInfo)) {
1223 if (!interfaceManager.isExternalInterface(ifName)) {
1224 // only add root interfaces
1225 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1229 if (listBucket.isEmpty()) { // No Buckets
1230 createDropBucket(listBucket);
1233 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
1234 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1235 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1236 MDSALUtil.buildBucketLists(listBucket));
1237 LOG.trace("installing the localBroadCast Group:{}", group);
1238 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1242 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1243 InterfaceInfo ifInfo) {
1244 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1245 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1246 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1247 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1253 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1254 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1255 throws ExecutionException, InterruptedException {
1256 Uint64 dpnId = interfaceInfo.getDpId();
1257 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1258 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1259 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1262 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1263 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1264 throws ExecutionException, InterruptedException {
1265 Uint64 dpnId = interfaceInfo.getDpId();
1266 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1267 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1268 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1272 * Installs a flow in the External Tunnel table consisting in translating
1273 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1274 * elanTag that will be used later in the ELANs pipeline.
1275 * @param dpnId the dpn id
1277 private void setExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1278 TypedWriteTransaction<Configuration> confTx) {
1279 Uint32 elanTag = elanInfo.getElanTag();
1280 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1281 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag.longValue()), 5, // prio
1282 elanInfo.getElanInstanceName(), // flowName
1285 Uint64.valueOf(ITMConstants.COOKIE_ITM_EXTERNAL.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1286 buildMatchesForVni(Uint64.valueOf(ElanUtils.getVxlanSegmentationId(elanInfo).longValue())),
1287 getInstructionsIntOrExtTunnelTable(elanTag));
1289 mdsalManager.addFlow(confTx, flowEntity);
1293 * Removes, from External Tunnel table, the flow that translates from VNI to
1294 * elanTag. Important: ensure this method is only called whenever there is
1295 * no other ElanInterface in the specified DPN
1297 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1299 private void unsetExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1300 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1301 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1302 // last ElanInstance plus
1303 // adding a new one does (almost at the same time) are executed in that
1306 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag().toJava());
1307 FlowEntity flowEntity = new FlowEntityBuilder()
1309 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1312 mdsalManager.removeFlow(confTx, flowEntity);
1315 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1316 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1317 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1318 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1321 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, Uint32 elanTag,
1322 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1323 List<? extends MatchInfoBase> listMatchInfoBase;
1324 List<InstructionInfo> instructionInfos;
1326 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1327 serviceId = elanTag;
1328 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId(elanTag);
1329 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue()));
1331 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1332 listMatchInfoBase = buildMatchesForVni(Uint64.valueOf(serviceId));
1333 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1335 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1336 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId.longValue()), 5,
1337 String.format("%s:%s", "ITM Flow Entry ", elanTag.toString()), 0, 0,
1338 Uint64.valueOf(ITMConstants.COOKIE_ITM.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1339 listMatchInfoBase, instructionInfos);
1340 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1341 LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId,
1342 elanInfo.getElanInstanceName(), elanTag);
1345 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1346 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1347 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1348 if (etreeInstance != null) {
1349 setupTerminateServiceTable(elanInfo, dpId,
1350 etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1354 public void setupUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId,
1355 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1356 long elanTag = elanInfo.getElanTag().toJava();
1357 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1358 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1359 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1362 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1363 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1364 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1365 if (etreeLeafTag != null) {
1366 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
1367 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1368 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1372 private void installLocalUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1373 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1374 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1375 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1376 5, elanInfo.getElanInstanceName(), 0, 0,
1377 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1378 getMatchesForElanTag(elanTag, /* SH flag */false),
1379 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1381 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1382 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}",
1383 dpId, elanInfo.getElanInstanceName(), elanTag);
1386 private void installRemoteUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1387 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1388 // only if ELAN can connect to external network, perform the following
1390 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1391 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1392 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1393 5, elanInfo.getElanInstanceName(), 0, 0,
1394 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1395 getMatchesForElanTag(elanTag, /* SH flag */true),
1396 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1397 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1398 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to "
1399 + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag);
1404 private void removeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
1405 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1406 throws ExecutionException, InterruptedException {
1407 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1408 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1409 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1411 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1412 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1413 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1415 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1419 private void removeDefaultTermFlow(Uint64 dpId, long elanTag) {
1420 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1423 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1424 TypedWriteTransaction<Configuration> tx) {
1425 if (isStandardElanService(elanInterface)) {
1426 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(),
1427 elanInterface.getName(), lportTag, tx);
1428 } else { // Etree service
1429 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1433 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1434 TypedWriteTransaction<Configuration> tx) {
1435 int instructionKey = 0;
1436 List<Instruction> instructions = new ArrayList<>();
1437 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1438 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1440 List<Action> actions = new ArrayList<>();
1441 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1442 lportTag).buildAction());
1443 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1444 elanTag).buildAction());
1445 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1447 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1450 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1451 BoundServices serviceInfo = ElanUtils.getBoundServices(
1452 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1453 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1454 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1455 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1457 if (!existingElanService.isPresent()) {
1458 tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
1459 LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName);
1463 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1464 TypedWriteTransaction<Configuration> tx) {
1465 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1466 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1469 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1470 if (etreeInstance == null) {
1471 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1472 elanInterface.getName(), elanInfo.getElanInstanceName());
1474 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue().toJava(), elanInfo.getElanInstanceName(),
1475 elanInterface.getName(), lportTag, tx);
1480 private static boolean isStandardElanService(ElanInterface elanInterface) {
1481 return elanInterface.augmentation(EtreeInterface.class) == null;
1484 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1485 throws ExecutionException, InterruptedException {
1486 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1487 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1488 if (tx.read(bindServiceId).get().isPresent()) {
1489 tx.delete(bindServiceId);
1493 private static String getFlowRef(long tableId, long elanTag) {
1494 return String.valueOf(tableId) + elanTag;
1497 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1498 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1499 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1502 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1503 return String.valueOf(tableId) + elanTag + shFlag;
1506 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1507 List<Action> listAction = new ArrayList<>();
1510 new ActionSetFieldTunnelId(Uint64.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1512 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1516 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, Uint64 dpId,
1517 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1518 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1519 .withKey(new DpnInterfacesKey(dpId)).build();
1520 tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1521 CREATE_MISSING_PARENTS);
1522 LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName,
1524 return dpnInterface;
1528 * Delete elan dpn interface from operational DS.
1530 * @param elanInstanceName
1531 * the elan instance name
1535 private static void deleteElanDpnInterface(String elanInstanceName, Uint64 dpId,
1536 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1537 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1538 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1539 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1540 if (dpnInterfaces.isPresent()) {
1541 tx.delete(dpnInterfacesId);
1545 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1546 Uint64 dpId, TypedWriteTransaction<Operational> tx) {
1547 List<String> interfaceNames = new ArrayList<>();
1548 interfaceNames.add(interfaceName);
1549 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1550 .withKey(new DpnInterfacesKey(dpId)).build();
1551 return dpnInterface;
1554 private static void createElanStateList(String elanInstanceName, String interfaceName,
1555 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1556 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1557 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1558 // Adding new Elan Interface Port to the operational DataStore without
1559 // Static-Mac Entries..
1560 if (elanInterfaceLists.isPresent()) {
1561 List<String> interfaceLists = new ArrayList<>();
1562 interfaceLists.add(interfaceName);
1563 List<String> existingInterfaceLists = elanInterfaceLists.get().getElanInterfaces();
1564 if (existingInterfaceLists != null && !existingInterfaceLists.isEmpty()) {
1565 existingInterfaceLists.forEach(iface -> interfaceLists.add(iface));
1568 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1569 .withKey(new ElanKey(elanInstanceName)).build();
1570 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
1571 LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName,
1576 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1577 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1580 @SuppressWarnings("checkstyle:IllegalCatch")
1581 public void handleInternalTunnelStateEvent(Uint64 srcDpId, Uint64 dstDpId) {
1582 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1583 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1584 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1585 if (dpnInterfaceLists == null) {
1588 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1589 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1591 String elanName = elanDpns.getElanInstanceName();
1592 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1593 if (elanInfo == null) {
1594 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1595 + "skipping this ELAN for tunnel handling", elanName);
1598 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1599 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1602 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1603 if (dpnInterfaces == null) {
1606 DpnInterfaces dstDpnIf = null;
1607 for (DpnInterfaces dpnIf : dpnInterfaces) {
1608 Uint64 dpnIfDpId = dpnIf.getDpId();
1609 if (Objects.equals(dpnIfDpId, srcDpId)) {
1611 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1617 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1618 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1619 jobCoordinator.enqueueJob(elanName, () -> {
1620 // update Remote BC Group
1621 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1623 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1624 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1626 } catch (RuntimeException e) {
1627 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1629 Set<String> interfaceLists = new HashSet<>();
1630 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1631 for (String ifName : interfaceLists) {
1632 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1633 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1634 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1635 if (isOperational(interfaceInfo)) {
1636 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1639 }, ElanConstants.JOB_MAX_RETRIES);
1642 }, ElanConstants.JOB_MAX_RETRIES);
1649 * Handle external tunnel state event.
1651 * @param externalTunnel
1652 * the external tunnel
1656 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1657 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1660 // dpId/externalNodeId will be available either in source or destination
1661 // based on the tunnel end point
1663 NodeId externalNodeId = null;
1664 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1665 dpId = Uint64.valueOf(externalTunnel.getSourceDevice());
1666 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1667 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1668 dpId = Uint64.valueOf(externalTunnel.getDestinationDevice());
1669 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1671 if (dpId == null || externalNodeId == null) {
1672 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1676 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1677 if (dpnInterfaceLists == null) {
1680 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1681 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1682 String elanName = elanDpns.getElanInstanceName();
1683 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1685 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1686 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1687 || dpnInterfaces.getInterfaces().isEmpty()) {
1690 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1692 final Uint64 finalDpId = dpId;
1693 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1694 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1695 "Error setting up ELAN BGs");
1696 // install L2gwDevices local macs in dpn.
1697 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1698 // Install dpn macs on external device
1699 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1702 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1706 * Installs dpn macs in external device. first it checks if the physical
1707 * locator towards this dpn tep is present or not if the physical locator is
1708 * present go ahead and add the ucast macs otherwise update the mcast mac
1709 * entry to include this dpn tep ip and schedule the job to put ucast macs
1710 * once the physical locator is programmed in device
1714 * @param lstElanInterfaceNames
1715 * the lst Elan interface names
1718 * @param externalNodeId
1719 * the external node id
1721 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, Uint64 dpnId,
1722 NodeId externalNodeId) {
1723 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1724 externalNodeId.getValue());
1725 if (elanL2GwDevice == null) {
1726 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1729 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1730 if (dpnTepIp == null) {
1731 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1736 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1737 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1738 LogicalDatastoreType.OPERATIONAL);
1739 boolean phyLocAlreadyExists =
1740 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1742 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1743 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1744 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1746 if (phyLocAlreadyExists) {
1747 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1750 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1751 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1755 * Validate external tunnel state event.
1757 * @param externalTunnel
1758 * the external tunnel
1761 * @return true, if successful
1763 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1764 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1765 String srcDevice = externalTunnel.getDestinationDevice();
1766 String destDevice = externalTunnel.getSourceDevice();
1767 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1768 LogicalDatastoreType.CONFIGURATION);
1769 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1770 otherEndPointExtTunnel);
1771 if (otherEndPointExtTunnel != null) {
1772 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1773 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1774 if (otherEndPointInterfaceOperational) {
1777 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1778 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1785 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1786 List<MatchInfo> mkMatches = new ArrayList<>();
1787 // Matching metadata
1789 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1790 mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag)));
1795 protected ElanInterfaceManager getDataTreeChangeListener() {
1799 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1801 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1802 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1803 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1804 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1806 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1807 } catch (InterruptedException e) {
1808 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);