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.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13 import static org.opendaylight.infrautils.utils.concurrent.LoggingFutures.addErrorLogging;
14 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
16 import com.google.common.base.Preconditions;
17 import com.google.common.collect.Lists;
18 import com.google.common.util.concurrent.FluentFuture;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Queue;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentLinkedQueue;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.locks.ReentrantLock;
35 import javax.annotation.PreDestroy;
36 import javax.inject.Inject;
37 import javax.inject.Singleton;
38 import org.apache.commons.lang3.StringUtils;
39 import org.opendaylight.genius.infra.Datastore.Configuration;
40 import org.opendaylight.genius.infra.Datastore.Operational;
41 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
42 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
43 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
44 import org.opendaylight.genius.infra.TypedWriteTransaction;
45 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
46 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
47 import org.opendaylight.genius.itm.globals.ITMConstants;
48 import org.opendaylight.genius.mdsalutil.FlowEntity;
49 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
50 import org.opendaylight.genius.mdsalutil.InstructionInfo;
51 import org.opendaylight.genius.mdsalutil.MDSALUtil;
52 import org.opendaylight.genius.mdsalutil.MatchInfo;
53 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
54 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
55 import org.opendaylight.genius.mdsalutil.NwConstants;
56 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
57 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
58 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
59 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
60 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
61 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
62 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
63 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
64 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
65 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
66 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
67 import org.opendaylight.genius.utils.JvmGlobalLocks;
68 import org.opendaylight.genius.utils.ServiceIndex;
69 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
70 import org.opendaylight.infrautils.utils.concurrent.Executors;
71 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
72 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
73 import org.opendaylight.mdsal.binding.api.DataBroker;
74 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
75 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
76 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
77 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
78 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
79 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
80 import org.opendaylight.netvirt.elan.utils.ElanConstants;
81 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
82 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
83 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
84 import org.opendaylight.netvirt.elan.utils.ElanUtils;
85 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
86 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
87 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
88 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
89 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
90 import org.opendaylight.serviceutils.srm.RecoverableListener;
91 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
92 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
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.flow.types.rev131026.instruction.list.InstructionKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
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.interfaces.elan._interface.StaticMacEntriesKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
143 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
144 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
145 import org.opendaylight.yangtools.yang.common.Uint32;
146 import org.opendaylight.yangtools.yang.common.Uint64;
147 import org.slf4j.Logger;
148 import org.slf4j.LoggerFactory;
151 * Class in charge of handling creations, modifications and removals of
154 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
157 public class ElanInterfaceManager extends AbstractAsyncDataTreeChangeListener<ElanInterface>
158 implements RecoverableListener {
159 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
160 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("NetvirtEventLogger");
161 public static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
162 private static final boolean SH_FLAG_SET = true;
163 private static final boolean SH_FLAG_UNSET = false;
165 private final DataBroker broker;
166 private final ManagedNewTransactionRunner txRunner;
167 private final IMdsalApiManager mdsalManager;
168 private final IInterfaceManager interfaceManager;
169 private final IdManagerService idManager;
170 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
171 private final INeutronVpnManager neutronVpnManager;
172 private final ElanItmUtils elanItmUtils;
173 private final ElanEtreeUtils elanEtreeUtils;
174 private final ElanL2GatewayUtils elanL2GatewayUtils;
175 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
176 private final ElanUtils elanUtils;
177 private final JobCoordinator jobCoordinator;
178 private final ElanInstanceCache elanInstanceCache;
179 private final ElanInterfaceCache elanInterfaceCache;
180 private final ElanGroupCache elanGroupCache;
182 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
183 unProcessedElanInterfaces = new ConcurrentHashMap<>();
186 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
187 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
188 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
189 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
190 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
191 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
192 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
193 final ElanInstanceCache elanInstanceCache,
194 final ElanInterfaceCache elanInterfaceCache,
195 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
196 ElanGroupCache elanGroupCache,
197 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
198 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(ElanInterfaces.class)
199 .child(ElanInterface.class),
200 Executors.newListeningSingleThreadExecutor("ElanInterfaceManager", LOG));
201 this.broker = dataBroker;
202 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
203 this.idManager = managerService;
204 this.mdsalManager = mdsalApiManager;
205 this.interfaceManager = interfaceManager;
206 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
207 this.neutronVpnManager = neutronVpnManager;
208 this.elanItmUtils = elanItmUtils;
209 this.elanEtreeUtils = elanEtreeUtils;
210 this.elanL2GatewayUtils = elanL2GatewayUtils;
211 this.elanUtils = elanUtils;
212 this.jobCoordinator = jobCoordinator;
213 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
214 this.elanInstanceCache = elanInstanceCache;
215 this.elanInterfaceCache = elanInterfaceCache;
216 this.elanGroupCache = elanGroupCache;
217 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
221 LOG.info("{} registered", getClass().getSimpleName());
225 public void registerListener() {
227 LOG.info("Registering ElanInterfaceManager");
231 public void deregisterListener() {
233 LOG.info("Deregistering ElanInterfaceManager");
238 public void close() {
240 Executors.shutdownAndAwaitTermination(getExecutorService());
244 public void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
245 String interfaceName = del.getName();
246 String elanInstanceName = del.getElanInstanceName();
247 EVENT_LOGGER.debug("ELAN-Interface, REMOVE {} Instance {}", interfaceName, elanInstanceName);
248 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
249 if (elanInterfaces != null && elanInterfaces.contains(del)) {
250 elanInterfaces.remove(del);
251 if (elanInterfaces.isEmpty()) {
252 unProcessedElanInterfaces.remove(elanInstanceName);
255 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orElse(null);
257 * Handling in case the elan instance is deleted.If the Elan instance is
258 * deleted, there is no need to explicitly delete the elan interfaces
260 if (elanInfo == null) {
263 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
264 if (interfaceInfo == null && elanInfo.isExternal()) {
265 // In deleting external network, the underlying ietf Inteface might have been removed
266 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
267 // from Operational DS instead
268 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
270 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
271 interfaceName, interfaceInfo, this);
272 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
275 private static class RemoveElanInterfaceHolder {
276 boolean isLastElanInterface = false;
280 @SuppressWarnings("checkstyle:ForbidCertainMethod")
281 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
282 InterfaceInfo interfaceInfo) {
283 String elanName = elanInfo.getElanInstanceName();
284 EVENT_LOGGER.debug("ELAN-InterfaceState, REMOVE {} Instance {}", interfaceName, elanName);
285 Uint32 elanTag = elanInfo.getElanTag();
286 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
287 List<ListenableFuture<Void>> futures = new ArrayList<>();
288 RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
289 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
290 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
291 if (elanState == null) {
294 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
295 List<String> elanInterfaces = elanState.getElanInterfaces();
296 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
297 holder.isLastElanInterface = true;
299 if (interfaceInfo != null) {
300 holder.dpId = interfaceInfo.getDpId();
301 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
302 interfaceName, elanTag, interfaceTx);
304 * If there are not elan ports, remove the unknown dmac, terminating
305 * service table flows, remote/local bc group
307 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
308 || dpnInterfaces.getInterfaces().isEmpty()) {
309 // No more Elan Interfaces in this DPN
310 EVENT_LOGGER.debug("ELAN-Flows, REMOVE {} Instance {}", interfaceName, elanName);
311 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
313 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
314 removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag().toJava());
316 removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag().toJava());
317 removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
318 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
319 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
320 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
321 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
322 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
323 elanUtils.removeTerminatingServiceAction(holder.dpId,
324 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
326 unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
329 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
334 futures.forEach(ElanUtils::waitForTransactionToComplete);
336 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
337 interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
338 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
339 ElanConstants.JOB_MAX_RETRIES);
344 private void removeEtreeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
345 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
346 throws ExecutionException, InterruptedException {
347 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag().toJava());
348 if (etreeLeafTag != null) {
349 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
350 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
354 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
355 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
356 throws ExecutionException, InterruptedException {
357 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
358 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
361 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
362 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
363 throws ExecutionException, InterruptedException {
364 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
365 if (etreeInstance != null) {
366 Uint64 dpnId = interfaceInfo.getDpId();
367 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue().toJava());
368 LOG.trace("deleted the localBroadCast Group:{}", groupId);
369 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
373 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
374 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
375 throws ExecutionException, InterruptedException {
376 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
377 if (etreeInstance != null) {
378 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
379 Uint64 dpnId = interfaceInfo.getDpId();
380 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
381 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
382 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
386 private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
387 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
388 String elanName = elanInfo.getElanInstanceName();
389 Elan elanState = ElanUtils.getElanByName(tx, elanName);
390 if (elanState == null) {
393 List<String> existingElanInterfaces = elanState.getElanInterfaces();
394 List<String> elanInterfaces = new ArrayList<>();
395 if (existingElanInterfaces != null) {
396 elanInterfaces.addAll(existingElanInterfaces);
398 boolean isRemoved = elanInterfaces.remove(interfaceName);
403 if (elanInterfaces.isEmpty()) {
404 tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
405 tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
406 tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
407 tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
409 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
410 .withKey(new ElanKey(elanName)).build();
411 tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
416 private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
417 throws ExecutionException, InterruptedException {
418 // removing the ElanInterface from the config data_store if interface is
419 // not present in Interface config DS
420 InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils
421 .getElanInterfaceConfigurationDataPathId(interfaceName);
422 FluentFuture<Optional<ElanInterface>> interfaceOptional = tx.read(elanInterfaceId);
423 if (!interfaceOptional.get().isPresent() && elanInterfaceCache.get(interfaceName).isPresent()) {
424 tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
428 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
429 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
430 String elanName = elanInfo.getElanInstanceName();
431 EVENT_LOGGER.debug("ELAN-InterfaceEntries, REMOVE {} Instance {}", interfaceName, elanName);
432 List<ListenableFuture<Void>> futures = new ArrayList<>();
433 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
434 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
435 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
436 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
437 Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
438 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
439 if (interfaceInfo != null) {
440 if (existingElanInterfaceMac.isPresent()) {
441 Map<MacEntryKey, MacEntry> existingMacEntries =
442 existingElanInterfaceMac.get().nonnullMacEntry();
443 if (existingMacEntries != null) {
444 List<PhysAddress> macAddresses = new ArrayList<>();
445 for (MacEntry macEntry : existingMacEntries.values()) {
446 PhysAddress macAddress = macEntry.getMacAddress();
447 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
448 macAddress.getValue(), interfaceName);
449 Optional<MacEntry> macEntryOptional =
450 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
451 if (!isLastElanInterface && macEntryOptional.isPresent()) {
452 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
454 EVENT_LOGGER.debug("ELAN-MacFlows, REMOVE {} Instance {} Mac {}",
455 interfaceName, elanName, macAddress);
456 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
457 macAddresses.add(macAddress);
460 // Removing all those MACs from External Devices belonging
462 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
463 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
467 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
468 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
469 } else if (existingElanInterfaceMac.isPresent()) {
470 // Interface does not exist in ConfigDS, so lets remove everything
471 // about that interface related to Elan
472 Map<MacEntryKey, MacEntry> macEntries = existingElanInterfaceMac.get().nonnullMacEntry();
473 if (macEntries != null) {
474 for (MacEntry macEntry : macEntries.values()) {
475 PhysAddress macAddress = macEntry.getMacAddress();
476 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
477 interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
482 if (existingElanInterfaceMac.isPresent()) {
483 interfaceTx.delete(elanInterfaceId);
485 unbindService(interfaceName, flowTx);
486 deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
492 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, Uint64 dpId,
493 String interfaceName, Uint32 elanTag,
494 TypedReadWriteTransaction<Operational> tx)
495 throws ExecutionException, InterruptedException {
496 // FIXME: pass in and use ElanInstanceKey instead?
497 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
500 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
501 if (dpnInterfaces != null) {
502 List<String> interfaceLists = null;
503 if (dpnInterfaces.getInterfaces() != null) {
504 interfaceLists = new ArrayList<>(dpnInterfaces.getInterfaces());
506 if (interfaceLists != null) {
507 interfaceLists.remove(interfaceName);
510 if (interfaceLists == null || interfaceLists.isEmpty()) {
511 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
512 deleteElanDpnInterface(elanName, dpId, tx);
514 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
517 return dpnInterfaces;
523 private void deleteAllRemoteMacsInADpn(String elanName, Uint64 dpId, Uint32 elanTag) {
524 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
525 addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
526 for (DpnInterfaces dpnInterface : dpnInterfaces) {
527 Uint64 currentDpId = dpnInterface.getDpId();
528 if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
529 for (String elanInterface : dpnInterface.getInterfaces()) {
530 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
531 if (macs == null || macs.getMacEntry() == null) {
534 for (MacEntry mac : new ArrayList<MacEntry>(macs.nonnullMacEntry().values())) {
535 removeTheMacFlowInTheDPN(dpId, elanTag, mac, confTx);
536 removeEtreeMacFlowInTheDPN(dpId, elanTag, mac, confTx);
541 }), LOG, "Error deleting remote MACs in DPN {}", dpId);
544 private void removeEtreeMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac,
545 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
546 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
547 if (etreeLeafTag != null) {
548 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), mac, confTx);
552 private void removeTheMacFlowInTheDPN(Uint64 dpId, Uint32 elanTag, MacEntry mac,
553 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
555 .removeFlow(confTx, dpId,
556 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
557 ElanUtils.getKnownDynamicmacFlowRef(elanTag, mac.getMacAddress().getValue())));
561 * Possible Scenarios for update
562 * a. if orig={1,2,3,4} and updated=null or updated={}
563 then all {1,2,3,4} should be removed
565 b. if orig=null or orig={} and updated ={1,2,3,4}
566 then all {1,2,3,4} should be added
568 c. if orig = {1,2,3,4} updated={2,3,4}
569 then 1 should be removed
571 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
572 then we should just add 5
574 e. if orig = {1,2,3,4} updated={2,3,4,5}
575 then 1 should be removed , 5 should be added
577 @SuppressWarnings("checkstyle:ForbidCertainMethod")
579 public void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
580 // updating the static-Mac Entries for the existing elanInterface
581 String elanName = update.getElanInstanceName();
582 String interfaceName = update.getName();
583 LOG.info("Update static mac entries for elan interface {} in elan instance {}", interfaceName, elanName);
584 EVENT_LOGGER.debug("ELAN-Interface, UPDATE {} Instance {}", original.getName(), elanName);
586 List<StaticMacEntries> originalStaticMacEntries = new ArrayList<StaticMacEntries>(original
587 .nonnullStaticMacEntries().values());
588 List<StaticMacEntries> updatedStaticMacEntries = new ArrayList<StaticMacEntries>(update
589 .nonnullStaticMacEntries().values());
590 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
591 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
593 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
594 deletedEntry.getMacAddress()));
596 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
597 * Hence add the macentries for the same.*/
598 for (StaticMacEntries staticMacEntry : updatedEntries) {
599 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
600 staticMacEntry.getMacAddress());
601 addErrorLogging(ElanUtils.waitForTransactionToComplete(
602 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
603 Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
604 if (existingMacEntry.isPresent()) {
605 LOG.debug("updating elan interface forwarding table for mac entry {} elan instance {}",
606 existingMacEntry.get(), elanName);
607 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
608 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
611 LOG.info("Adding elan interface forwarding table for mac entry {} elan interface"
612 + " {} elan instance {}.", staticMacEntry.getMacAddress(), interfaceName, elanName);
613 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
614 elanName, interfaceName, staticMacEntry, tx);
616 })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
621 public void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
622 LOG.info("Init for ELAN interface Add {}", elanInterfaceAdded);
623 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
624 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
625 String interfaceName = elanInterfaceAdded.getName();
626 EVENT_LOGGER.debug("ELAN-Interface, ADD {} Instance {}", interfaceName, elanInstanceName);
627 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
628 if (interfaceInfo == null) {
629 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
632 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orElse(null);
634 if (elanInstance == null) {
635 // Add the ElanInstance in the Configuration data-store
636 List<String> elanInterfaces = new ArrayList<>();
637 elanInterfaces.add(interfaceName);
638 elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
639 confTx -> ElanUtils.updateOperationalDataStore(idManager,
640 new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
641 elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
644 Uint32 elanTag = elanInstance.getElanTag();
645 // If elan tag is not updated, then put the elan interface into
646 // unprocessed entry map and entry. Let entries
647 // in this map get processed during ELAN update DCN.
648 if (elanTag == null || elanTag.longValue() == 0L) {
649 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
650 if (elanInterfaces == null) {
651 elanInterfaces = new ConcurrentLinkedQueue<>();
653 if (!elanInterfaces.contains(elanInterfaceAdded)) {
654 elanInterfaces.add(elanInterfaceAdded);
656 LOG.error("ELAN tag for instance {} is not created. Adding it to unprocessed list."
657 + " Recreate the network if this message is seen multiple times", elanInstanceName);
658 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
661 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
662 interfaceInfo, elanInstance, this);
663 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
664 }), LOG, "Error processing added ELAN interface");
667 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
668 LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName());
669 List<ListenableFuture<Void>> futures = new ArrayList<>();
670 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
671 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
674 for (ElanInterface elanInterface : elanInterfaces) {
675 String interfaceName = elanInterface.getName();
676 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
677 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
679 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
680 LOG.info("Unprocessed elan interfaces for elan instance {} has been removed.",
681 elanInstance.getElanInstanceName());
685 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
686 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
687 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
688 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
689 List<DpnInterfaces> dpnInterfaceLists = null;
690 if (elanDpnInterfacesList != null) {
691 dpnInterfaceLists = new ArrayList<DpnInterfaces>(elanDpnInterfacesList.nonnullDpnInterfaces().values());
693 if (dpnInterfaceLists != null && !dpnInterfaceLists.isEmpty()) {
694 Uint64 dstDpId = interfaceInfo.getDpId();
695 processRemoteDmacFlowForInterface(dstDpId, elanInstance, dpnInterfaceLists, writeFlowGroupTx);
699 private void processRemoteDmacFlowForInterface(Uint64 dstDpId, ElanInstance elanInstance,
700 List<DpnInterfaces> dpnInterfaceLists, TypedWriteTransaction<Configuration> writeFlowGroupTx) {
701 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
702 if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
705 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
706 if (remoteElanInterfaces == null || remoteElanInterfaces.isEmpty()) {
709 for (String remoteIf : remoteElanInterfaces) {
710 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
711 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
712 if (elanIfMac == null || remoteInterface == null) {
715 Map<MacEntryKey, MacEntry> remoteMacEntries = elanIfMac.nonnullMacEntry();
716 for (MacEntry macEntry : remoteMacEntries.values()) {
717 String macAddress = macEntry.getMacAddress().getValue();
718 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
719 dstDpId, elanInstance.getElanInstanceName());
720 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
721 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
722 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
728 private static class AddElanInterfaceHolder {
729 private DpnInterfaces dpnInterfaces = null;
730 private boolean isFirstInterfaceInDpn = false;
734 @SuppressWarnings("checkstyle:ForbidCertainMethod")
735 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
736 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
737 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
738 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
739 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
741 String interfaceName = elanInterface.getName();
742 String elanInstanceName = elanInterface.getElanInstanceName();
743 LOG.trace("Adding elan interface: interface name {} , instance name {}", interfaceName, elanInstanceName);
744 EVENT_LOGGER.debug("ELAN-InterfaceState, ADD {} Instance {}", interfaceName, elanInstanceName);
746 List<ListenableFuture<Void>> futures = new ArrayList<>();
747 AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
748 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
749 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
750 if (elanInfo == null) {
751 LOG.trace("elanInfo is null for elan instance: {}", elanInstanceName);
752 List<String> elanInterfaces = new ArrayList<>();
753 elanInterfaces.add(interfaceName);
754 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
755 confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
758 createElanStateList(elanInstanceName, interfaceName, operTx);
760 // Specific actions to the DPN where the ElanInterface has been added,
761 // for example, programming the
762 // External tunnel table if needed or adding the ElanInterface to the
763 // DpnInterfaces in the operational DS.
764 holder.dpId = interfaceInfo.getDpId();
765 if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
766 // FIXME: use elanInstaince.key() instead?
767 final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
770 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
771 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
772 Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
773 if (ElanUtils.isVlan(elanInstance)) {
774 holder.isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
775 elanInstanceName, existingElanDpnInterfaces);
777 holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
779 if (holder.isFirstInterfaceInDpn) {
780 // ELAN's 1st ElanInterface added to this DPN
781 if (!existingElanDpnInterfaces.isPresent()) {
782 holder.dpnInterfaces =
783 createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
785 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
786 List<String> elanInterfaces =
787 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
788 elanInterfaces.add(interfaceName);
789 holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
790 elanInterfaces, operTx);
792 LOG.debug("1st interface {} for elan {} is added to dpn {}",
793 interfaceName, elanInstanceName, holder.dpId);
794 // The 1st ElanInterface in a DPN must program the Ext Tunnel
795 // table, but only if Elan has VNI
796 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
797 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
798 confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
800 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
803 List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
804 List<String> elanInterfaces =
805 existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
806 elanInterfaces.add(interfaceName);
807 if (elanInterfaces.size() == 1) { // 1st dpn interface
808 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
811 holder.dpnInterfaces =
812 updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
813 LOG.debug("Interface {} for elan {} is added to dpn {}",
814 interfaceName, elanInstanceName, holder.dpId);
821 // add code to install Local/Remote BC group, unknow DMAC entry,
822 // terminating service table flow entry
823 // call bindservice of interfacemanager to create ingress table flow
826 futures.forEach(ElanUtils::waitForTransactionToComplete);
828 ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
829 confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
830 holder.isFirstInterfaceInDpn, confTx))));
832 // add the vlan provider interface to remote BC group for the elan
833 // for internal vlan networks
834 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
835 if (interfaceManager.isExternalInterface(interfaceName)) {
836 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
837 handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
840 if (holder.isFirstInterfaceInDpn) {
841 // ELAN's 1st ElanInterface added to this DPN
842 LOG.debug("Adding dpn into operational dpn list {}", holder.dpId);
843 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
844 operTx.mergeParentStructurePut(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName,
845 holder.dpId), holder.dpnInterfaces);
848 LOG.debug("Updated dpn into operational dpn list {}", holder.dpId);
851 scheduleElanInterfaceWorkerAfterRemoteBcGroup(elanInstance, interfaceInfo, holder.dpnInterfaces,
852 holder.isFirstInterfaceInDpn, elanInterface);
856 @SuppressWarnings("checkstyle:ForbidCertainMethod")
857 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
858 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
859 String elanInstanceName = elanInstance.getElanInstanceName();
860 String interfaceName = elanInterface.getName();
861 List<ListenableFuture<Void>> futures = new ArrayList<>();
862 Uint64 dpId = interfaceInfo.getDpId();
863 boolean isInterfaceOperational = isOperational(interfaceInfo);
864 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
865 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
866 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
867 isFirstInterfaceInDpn, confTx);
869 Map<StaticMacEntriesKey, StaticMacEntries> staticMacEntriesList =
870 elanInterface.nonnullStaticMacEntries();
871 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
873 if (ElanUtils.isNotEmpty(staticMacEntriesList.values())) {
874 for (StaticMacEntries staticMacEntry : staticMacEntriesList.values()) {
875 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
876 staticMacEntry.getMacAddress());
877 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
878 LogicalDatastoreType.OPERATIONAL, macId);
879 if (existingMacEntry.isPresent()) {
880 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
881 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
882 existingMacEntry.get(), operTx);
884 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
885 interfaceName, staticMacEntry, operTx);
888 if (isInterfaceOperational) {
889 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
891 String macAddress = staticMacEntry.getMacAddress().getValue();
893 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
895 macAddress, elanInstanceName, interfaceName);
896 EVENT_LOGGER.debug("ELAN-MacFlows, ADD {} Instance {} Mac {}",
897 interfaceName, elanInstanceName, macAddress);
898 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
899 staticMacEntry.getMacAddress().getValue(), true, confTx);
903 if (isInterfaceOperational) {
904 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
906 for (StaticMacEntries staticMacEntry : staticMacEntriesList.values()) {
907 staticMacAddresses.add(staticMacEntry.getMacAddress());
909 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
915 futures.forEach(ElanUtils::waitForTransactionToComplete);
916 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
917 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
919 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
920 if (neutronPort != null) {
921 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
923 } catch (IllegalArgumentException ex) {
924 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
930 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
931 PhysAddress physAddress) {
932 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
933 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
934 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
935 LogicalDatastoreType.OPERATIONAL, macId);
937 if (!existingMacEntry.isPresent()) {
941 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
942 .withKey(new MacEntryKey(physAddress)).build();
943 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
944 elanInstanceCache.get(elanInstanceName).orElse(null), interfaceInfo, macEntry);
947 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
948 Optional<DpnInterfaces> existingElanDpnInterfaces) {
949 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
950 if (!existingElanDpnInterfaces.isPresent()) {
953 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
956 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
957 int dummyInterfaceCount = 0;
958 List<String> interfaces = dpnInterfaces.getInterfaces();
959 if (interfaces == null) {
962 if (interfaces.contains(routerPortUuid)) {
963 dummyInterfaceCount++;
965 if (interfaces.contains(elanInstanceName)) {
966 dummyInterfaceCount++;
968 return interfaces.size() == dummyInterfaceCount;
971 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
972 PhysAddress physAddress) {
973 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
974 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
977 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
978 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
979 if (!isOperational(interfaceInfo)) {
980 LOG.warn("Interface {} is not operational", elanInterface.getName());
981 EVENT_LOGGER.debug("ELAN-InterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
982 elanInterface.getName(), elanInstance.getElanInstanceName(), interfaceInfo.getOpState());
985 Uint64 dpId = interfaceInfo.getDpId();
986 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
987 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
989 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
990 if (isFirstInterfaceInDpn) {
991 // Terminating Service , UnknownDMAC Table.
992 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
993 // for ELAN Instance is VxLAN
994 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
995 setupTerminateServiceTable(elanInstance, dpId, confTx);
997 setupUnknownDMacTable(elanInstance, dpId, confTx);
999 * Install remote DMAC flow. This is required since this DPN is
1000 * added later to the elan instance and remote DMACs of other
1001 * interfaces in this elan instance are not present in the current
1004 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
1005 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
1006 elanInstance.getElanInstanceName());
1007 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
1010 // bind the Elan service to the Interface
1011 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
1014 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1015 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
1016 if (!isOperational(interfaceInfo)) {
1017 LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational",
1018 dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName());
1019 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
1020 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1023 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {}",
1024 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
1025 // LocalBroadcast Group creation with elan-Interfaces
1026 LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(),
1027 dpnInterfaces.getDpId());
1028 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
1029 if (isFirstInterfaceInDpn) {
1030 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
1032 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1033 } catch (InterruptedException e1) {
1034 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
1039 public InstanceIdentifier<Group> getGroupIid(ElanInstance elanInfo, Uint64 dpnId) {
1040 long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1041 return InstanceIdentifier.builder(Nodes.class)
1042 .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight
1043 .inventory.rev130819.NodeId("openflow:" + dpnId.toString())))
1044 .augmentation(FlowCapableNode.class)
1045 .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build();
1048 public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo,
1049 InterfaceInfo interfaceInfo,
1050 DpnInterfaces dpnInterfaces,
1051 boolean isFirstInterfaceInDpn,
1052 ElanInterface elanInterface) {
1053 if (!isOperational(interfaceInfo)) {
1054 LOG.debug("Interface {} is not operational", elanInterface.getName());
1057 String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName());
1058 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey,
1059 elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this);
1060 InstanceIdentifier<Group> groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId());
1061 elanGroupCache.addJobToWaitList(groupInstanceId, () -> {
1062 jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
1066 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1067 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1068 int ifTag = interfaceInfo.getInterfaceTag();
1069 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1070 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 11, elanInfo.getElanInstanceName(),
1071 0, 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1072 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
1073 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
1075 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
1076 LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}",
1077 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1078 Map<InstructionKey, Instruction> customInstructionsMap = new HashMap<InstructionKey, Instruction>();
1079 int instructionKey = 0;
1080 for (Instruction instructionObj : MDSALUtil.buildInstructionsDrop()) {
1081 customInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
1084 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1085 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 12, elanInfo.getElanInstanceName(), 0,
1086 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1087 getMatchesForFilterEqualsLPortTag(ifTag), customInstructionsMap);
1089 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
1090 LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}",
1091 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1094 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1095 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1096 int ifTag = interfaceInfo.getInterfaceTag();
1097 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1098 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1100 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1102 Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1103 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"));
1105 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1108 private static List<MatchInfo> buildMatchesForVni(Uint64 vni) {
1109 List<MatchInfo> mkMatches = new ArrayList<>();
1110 MatchInfo match = new MatchTunnelId(vni);
1111 mkMatches.add(match);
1115 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1116 List<InstructionInfo> mkInstructions = new ArrayList<>();
1117 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1118 return mkInstructions;
1121 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1122 List<MatchInfo> mkMatches = new ArrayList<>();
1123 // Matching metadata
1124 mkMatches.add(new MatchMetadata(
1125 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1130 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1131 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1134 * elanTag to be written in metadata when flow is selected
1135 * @return the instructions ready to be installed in a flow
1137 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Uint32 elanTag) {
1138 List<InstructionInfo> mkInstructions = new ArrayList<>();
1139 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
1140 ElanHelper.getElanMetadataMask()));
1141 /* applicable for EXTERNAL_TUNNEL_TABLE only
1142 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1144 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1145 return mkInstructions;
1148 // Install DMAC entry on dst DPN
1149 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1151 String interfaceName = interfaceInfo.getInterfaceName();
1152 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1153 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1154 Map<MacEntryKey, MacEntry> macEntries = elanInterfaceMac.nonnullMacEntry();
1155 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1156 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1157 for (MacEntry macEntry : macEntries.values()) {
1158 String macAddress = macEntry.getMacAddress().getValue();
1159 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1161 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress,
1162 interfaceInfo.getDpId())) {
1163 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1165 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1173 private static void createDropBucket(List<Bucket> listBucket) {
1174 List<Action> actionsInfos = new ArrayList<>();
1175 actionsInfos.add(new ActionDrop().buildAction());
1176 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1177 MDSALUtil.WATCH_GROUP);
1178 listBucket.add(dropBucket);
1181 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1182 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1183 if (!isOperational(interfaceInfo)) {
1184 EVENT_LOGGER.debug("ELAN-LBG, ADD {} Instance {} Interface Status {}, returning",
1185 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1188 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1189 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1192 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1193 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1194 List<Bucket> listBucket = new ArrayList<>();
1196 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1198 List<String> interfaces = new ArrayList<>();
1199 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1200 interfaces = newDpnInterface.getInterfaces();
1202 for (String ifName : interfaces) {
1203 // In case if there is a InterfacePort in the cache which is not in
1204 // operational state, skip processing it
1205 InterfaceInfo ifInfo = interfaceManager
1206 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1207 if (!isOperational(ifInfo)) {
1211 if (!interfaceManager.isExternalInterface(ifName)) {
1212 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1213 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1218 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1219 MDSALUtil.buildBucketLists(listBucket));
1220 LOG.trace("installing the localBroadCast Group:{}", group);
1221 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1224 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1225 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1226 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1227 if (etreeInstance != null) {
1228 List<Bucket> listBucket = new ArrayList<>();
1231 List<String> interfaces = new ArrayList<>();
1232 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1233 interfaces = newDpnInterface.getInterfaces();
1235 for (String ifName : interfaces) {
1236 // In case if there is a InterfacePort in the cache which is not
1238 // operational state, skip processing it
1239 InterfaceInfo ifInfo = interfaceManager
1240 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1241 if (!isOperational(ifInfo)) {
1245 if (!interfaceManager.isExternalInterface(ifName)) {
1246 // only add root interfaces
1247 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1251 if (listBucket.isEmpty()) { // No Buckets
1252 createDropBucket(listBucket);
1255 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
1256 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1257 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1258 MDSALUtil.buildBucketLists(listBucket));
1259 LOG.trace("installing the localBroadCast Group:{}", group);
1260 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1264 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1265 InterfaceInfo ifInfo) {
1266 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1267 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1268 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1269 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1275 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1276 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1277 throws ExecutionException, InterruptedException {
1278 Uint64 dpnId = interfaceInfo.getDpId();
1279 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1280 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1281 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1284 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1285 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1286 throws ExecutionException, InterruptedException {
1287 Uint64 dpnId = interfaceInfo.getDpId();
1288 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1289 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1290 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1294 * Installs a flow in the External Tunnel table consisting in translating
1295 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1296 * elanTag that will be used later in the ELANs pipeline.
1297 * @param dpnId the dpn id
1299 private void setExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1300 TypedWriteTransaction<Configuration> confTx) {
1301 Uint32 elanTag = elanInfo.getElanTag();
1302 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1303 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag.longValue()), 5, // prio
1304 elanInfo.getElanInstanceName(), // flowName
1307 Uint64.valueOf(ITMConstants.COOKIE_ITM_EXTERNAL.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1308 buildMatchesForVni(Uint64.valueOf(ElanUtils.getVxlanSegmentationId(elanInfo).longValue())),
1309 getInstructionsIntOrExtTunnelTable(elanTag));
1311 mdsalManager.addFlow(confTx, flowEntity);
1315 * Removes, from External Tunnel table, the flow that translates from VNI to
1316 * elanTag. Important: ensure this method is only called whenever there is
1317 * no other ElanInterface in the specified DPN
1319 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1321 private void unsetExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1322 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1323 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1324 // last ElanInstance plus
1325 // adding a new one does (almost at the same time) are executed in that
1328 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag().toJava());
1329 FlowEntity flowEntity = new FlowEntityBuilder()
1331 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1334 mdsalManager.removeFlow(confTx, flowEntity);
1337 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1338 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1339 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1340 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1343 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, Uint32 elanTag,
1344 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1345 List<? extends MatchInfoBase> listMatchInfoBase;
1346 List<InstructionInfo> instructionInfos;
1348 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1349 serviceId = elanTag;
1350 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId(elanTag);
1351 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue()));
1353 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1354 listMatchInfoBase = buildMatchesForVni(Uint64.valueOf(serviceId));
1355 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1357 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1358 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId.longValue()), 5,
1359 String.format("%s:%s", "ITM Flow Entry ", elanTag.toString()), 0, 0,
1360 Uint64.valueOf(ITMConstants.COOKIE_ITM.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1361 listMatchInfoBase, instructionInfos);
1362 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1363 LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId,
1364 elanInfo.getElanInstanceName(), elanTag);
1367 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1368 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1369 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1370 if (etreeInstance != null) {
1371 setupTerminateServiceTable(elanInfo, dpId,
1372 etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1376 public void setupUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId,
1377 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1378 long elanTag = elanInfo.getElanTag().toJava();
1379 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1380 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1381 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1384 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1385 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1386 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1387 if (etreeLeafTag != null) {
1388 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
1389 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1390 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1394 private void installLocalUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1395 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1396 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1397 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1398 5, elanInfo.getElanInstanceName(), 0, 0,
1399 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1400 getMatchesForElanTag(elanTag, /* SH flag */false),
1401 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1403 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1404 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}",
1405 dpId, elanInfo.getElanInstanceName(), elanTag);
1408 private void installRemoteUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1409 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1410 // only if ELAN can connect to external network, perform the following
1412 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1413 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1414 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1415 5, elanInfo.getElanInstanceName(), 0, 0,
1416 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1417 getMatchesForElanTag(elanTag, /* SH flag */true),
1418 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1419 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1420 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to "
1421 + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag);
1426 private void removeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
1427 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1428 throws ExecutionException, InterruptedException {
1429 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1430 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1431 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1433 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1434 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1435 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1437 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1441 private void removeDefaultTermFlow(Uint64 dpId, long elanTag) {
1442 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1445 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1446 TypedWriteTransaction<Configuration> tx) {
1447 if (isStandardElanService(elanInterface)) {
1448 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(),
1449 elanInterface.getName(), lportTag, tx);
1450 } else { // Etree service
1451 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1455 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1456 TypedWriteTransaction<Configuration> tx) {
1457 int instructionKey = 0;
1458 List<Instruction> instructions = new ArrayList<>();
1459 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1460 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1462 List<Action> actions = new ArrayList<>();
1463 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1464 lportTag).buildAction());
1465 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1466 elanTag).buildAction());
1467 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1469 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1472 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1473 BoundServices serviceInfo = ElanUtils.getBoundServices(
1474 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1475 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1476 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1477 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1479 if (!existingElanService.isPresent()) {
1480 tx.mergeParentStructurePut(bindServiceId, serviceInfo);
1481 LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName);
1485 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1486 TypedWriteTransaction<Configuration> tx) {
1487 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1488 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1491 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1492 if (etreeInstance == null) {
1493 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1494 elanInterface.getName(), elanInfo.getElanInstanceName());
1496 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue().toJava(), elanInfo.getElanInstanceName(),
1497 elanInterface.getName(), lportTag, tx);
1502 private static boolean isStandardElanService(ElanInterface elanInterface) {
1503 return elanInterface.augmentation(EtreeInterface.class) == null;
1506 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1507 throws ExecutionException, InterruptedException {
1508 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1509 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1510 if (tx.read(bindServiceId).get().isPresent()) {
1511 tx.delete(bindServiceId);
1515 private static String getFlowRef(long tableId, long elanTag) {
1516 return String.valueOf(tableId) + elanTag;
1519 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1520 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1521 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1524 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1525 return String.valueOf(tableId) + elanTag + shFlag;
1528 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1529 List<Action> listAction = new ArrayList<>();
1532 new ActionSetFieldTunnelId(Uint64.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1534 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1538 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, Uint64 dpId,
1539 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1540 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1541 .withKey(new DpnInterfacesKey(dpId)).build();
1542 tx.mergeParentStructurePut(ElanUtils
1543 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface);
1544 LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName,
1546 return dpnInterface;
1550 * Delete elan dpn interface from operational DS.
1552 * @param elanInstanceName
1553 * the elan instance name
1557 private static void deleteElanDpnInterface(String elanInstanceName, Uint64 dpId,
1558 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1559 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1560 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1561 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1562 if (dpnInterfaces.isPresent()) {
1563 tx.delete(dpnInterfacesId);
1567 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1568 Uint64 dpId, TypedWriteTransaction<Operational> tx) {
1569 List<String> interfaceNames = new ArrayList<>();
1570 interfaceNames.add(interfaceName);
1571 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1572 .withKey(new DpnInterfacesKey(dpId)).build();
1573 return dpnInterface;
1576 private static void createElanStateList(String elanInstanceName, String interfaceName,
1577 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1578 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1579 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1580 // Adding new Elan Interface Port to the operational DataStore without
1581 // Static-Mac Entries..
1582 if (elanInterfaceLists.isPresent()) {
1583 List<String> interfaceLists = new ArrayList<>();
1584 interfaceLists.add(interfaceName);
1585 List<String> existingInterfaceLists = elanInterfaceLists.get().getElanInterfaces();
1586 if (existingInterfaceLists != null && !existingInterfaceLists.isEmpty()) {
1587 existingInterfaceLists.forEach(iface -> interfaceLists.add(iface));
1590 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1591 .withKey(new ElanKey(elanInstanceName)).build();
1592 tx.mergeParentStructurePut(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState);
1593 LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName,
1598 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1599 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1602 @SuppressWarnings("checkstyle:IllegalCatch")
1603 public void handleInternalTunnelStateEvent(Uint64 srcDpId, Uint64 dstDpId) {
1604 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1605 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1606 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1607 if (dpnInterfaceLists == null) {
1610 Map<ElanDpnInterfacesListKey, ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists
1611 .nonnullElanDpnInterfacesList();
1612 for (ElanDpnInterfacesList elanDpns : elanDpnIf.values()) {
1614 String elanName = elanDpns.getElanInstanceName();
1615 ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null);
1616 if (elanInfo == null) {
1617 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1618 + "skipping this ELAN for tunnel handling", elanName);
1621 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1622 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1625 Map<DpnInterfacesKey, DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1626 if (dpnInterfaces == null) {
1629 DpnInterfaces dstDpnIf = null;
1630 for (DpnInterfaces dpnIf : dpnInterfaces.values()) {
1631 Uint64 dpnIfDpId = dpnIf.getDpId();
1632 if (Objects.equals(dpnIfDpId, srcDpId)) {
1634 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1640 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1641 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1642 jobCoordinator.enqueueJob(elanName, () -> {
1643 // update Remote BC Group
1644 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1646 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1647 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1649 } catch (RuntimeException e) {
1650 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1652 Set<String> interfaceLists = new HashSet<>();
1653 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1654 for (String ifName : interfaceLists) {
1655 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1656 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1657 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1658 if (isOperational(interfaceInfo)) {
1659 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1662 }, ElanConstants.JOB_MAX_RETRIES);
1665 }, ElanConstants.JOB_MAX_RETRIES);
1672 * Handle external tunnel state event.
1674 * @param externalTunnel
1675 * the external tunnel
1679 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1680 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1683 // dpId/externalNodeId will be available either in source or destination
1684 // based on the tunnel end point
1686 NodeId externalNodeId = null;
1687 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1688 dpId = Uint64.valueOf(externalTunnel.getSourceDevice());
1689 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1690 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1691 dpId = Uint64.valueOf(externalTunnel.getDestinationDevice());
1692 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1694 if (dpId == null || externalNodeId == null) {
1695 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1699 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1700 if (dpnInterfaceLists == null) {
1703 Map<ElanDpnInterfacesListKey, ElanDpnInterfacesList> elanDpnIf
1704 = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1705 for (ElanDpnInterfacesList elanDpns : elanDpnIf.values()) {
1706 String elanName = elanDpns.getElanInstanceName();
1707 ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null);
1709 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1710 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1711 || dpnInterfaces.getInterfaces().isEmpty()) {
1714 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1716 final Uint64 finalDpId = dpId;
1717 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1718 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1719 "Error setting up ELAN BGs");
1720 // install L2gwDevices local macs in dpn.
1721 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1722 // Install dpn macs on external device
1723 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1726 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1730 * Installs dpn macs in external device. first it checks if the physical
1731 * locator towards this dpn tep is present or not if the physical locator is
1732 * present go ahead and add the ucast macs otherwise update the mcast mac
1733 * entry to include this dpn tep ip and schedule the job to put ucast macs
1734 * once the physical locator is programmed in device
1738 * @param lstElanInterfaceNames
1739 * the lst Elan interface names
1742 * @param externalNodeId
1743 * the external node id
1745 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, Uint64 dpnId,
1746 NodeId externalNodeId) {
1747 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1748 externalNodeId.getValue());
1749 if (elanL2GwDevice == null) {
1750 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1753 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1754 if (dpnTepIp == null) {
1755 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1760 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1761 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1762 LogicalDatastoreType.OPERATIONAL);
1763 boolean phyLocAlreadyExists =
1764 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1766 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1767 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1768 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1770 if (phyLocAlreadyExists) {
1771 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1774 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1775 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1779 * Validate external tunnel state event.
1781 * @param externalTunnel
1782 * the external tunnel
1785 * @return true, if successful
1787 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1788 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1789 String srcDevice = externalTunnel.getDestinationDevice();
1790 String destDevice = externalTunnel.getSourceDevice();
1791 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1792 LogicalDatastoreType.CONFIGURATION);
1793 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1794 otherEndPointExtTunnel);
1795 if (otherEndPointExtTunnel != null) {
1796 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1797 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1798 if (otherEndPointInterfaceOperational) {
1801 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1802 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1809 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1810 List<MatchInfo> mkMatches = new ArrayList<>();
1811 // Matching metadata
1813 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1814 mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag)));
1818 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1820 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1821 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1822 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1823 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1825 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1826 } catch (InterruptedException e) {
1827 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);