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.infrautils.utils.concurrent.LoggingFutures.addErrorLogging;
12 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
13 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
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.interfacemanager.globals.InterfaceInfo;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.itm.globals.ITMConstants;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
44 import org.opendaylight.genius.mdsalutil.InstructionInfo;
45 import org.opendaylight.genius.mdsalutil.MDSALUtil;
46 import org.opendaylight.genius.mdsalutil.MatchInfo;
47 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
48 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
49 import org.opendaylight.genius.mdsalutil.NwConstants;
50 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
51 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
52 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
53 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
54 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
58 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
59 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
60 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
61 import org.opendaylight.genius.utils.JvmGlobalLocks;
62 import org.opendaylight.genius.utils.ServiceIndex;
63 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
64 import org.opendaylight.infrautils.utils.concurrent.Executors;
65 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
66 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
67 import org.opendaylight.mdsal.binding.api.DataBroker;
68 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
69 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
70 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
71 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
72 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
73 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
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<?>> 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<?>> 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<?>> 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<?>> 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<?>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
668 LOG.trace("Handling unprocessed elan interfaces for elan instance {}", elanInstance.getElanInstanceName());
669 List<ListenableFuture<?>> 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<?>> 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<?>> 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<?>> setupEntriesForElanInterface(ElanInstance elanInstance,
858 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
859 String elanInstanceName = elanInstance.getElanInstanceName();
860 String interfaceName = elanInterface.getName();
861 List<ListenableFuture<?>> 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);
868 Map<StaticMacEntriesKey, StaticMacEntries> staticMacEntriesMap =
869 elanInterface.nonnullStaticMacEntries();
870 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
871 if (ElanUtils.isNotEmpty(staticMacEntriesMap.values())) {
872 for (StaticMacEntries staticMacEntry : staticMacEntriesMap.values()) {
873 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
874 staticMacEntry.getMacAddress());
875 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
876 LogicalDatastoreType.OPERATIONAL, macId);
877 if (existingMacEntry.isPresent()) {
878 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
879 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
880 existingMacEntry.get(), operTx);
882 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
883 interfaceName, staticMacEntry, operTx);
886 if (isInterfaceOperational) {
887 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
889 String macAddress = staticMacEntry.getMacAddress().getValue();
891 "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
893 macAddress, elanInstanceName, interfaceName);
894 EVENT_LOGGER.debug("ELAN-MacFlows, ADD {} Instance {} Mac {}",
895 interfaceName, elanInstanceName, macAddress);
896 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
897 staticMacEntry.getMacAddress().getValue(), true, confTx);
901 if (isInterfaceOperational) {
902 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
904 for (StaticMacEntries staticMacEntry : staticMacEntriesMap.values()) {
905 staticMacAddresses.add(staticMacEntry.getMacAddress());
907 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
913 futures.forEach(ElanUtils::waitForTransactionToComplete);
914 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
915 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
917 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
918 if (neutronPort != null) {
919 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
921 } catch (IllegalArgumentException ex) {
922 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
928 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
929 PhysAddress physAddress) {
930 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
931 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
932 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
933 LogicalDatastoreType.OPERATIONAL, macId);
935 if (!existingMacEntry.isPresent()) {
939 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
940 .withKey(new MacEntryKey(physAddress)).build();
941 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
942 elanInstanceCache.get(elanInstanceName).orElse(null), interfaceInfo, macEntry);
945 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
946 Optional<DpnInterfaces> existingElanDpnInterfaces) {
947 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
948 if (!existingElanDpnInterfaces.isPresent()) {
951 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
954 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
955 int dummyInterfaceCount = 0;
956 List<String> interfaces = dpnInterfaces.getInterfaces();
957 if (interfaces == null) {
960 if (interfaces.contains(routerPortUuid)) {
961 dummyInterfaceCount++;
963 if (interfaces.contains(elanInstanceName)) {
964 dummyInterfaceCount++;
966 return interfaces.size() == dummyInterfaceCount;
969 private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
970 PhysAddress physAddress) {
971 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
972 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
975 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
976 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
977 if (!isOperational(interfaceInfo)) {
978 LOG.warn("Interface {} is not operational", elanInterface.getName());
979 EVENT_LOGGER.debug("ELAN-InterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
980 elanInterface.getName(), elanInstance.getElanInstanceName(), interfaceInfo.getOpState());
983 Uint64 dpId = interfaceInfo.getDpId();
984 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
985 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
987 setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
988 if (isFirstInterfaceInDpn) {
989 // Terminating Service , UnknownDMAC Table.
990 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
991 // for ELAN Instance is VxLAN
992 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
993 setupTerminateServiceTable(elanInstance, dpId, confTx);
995 setupUnknownDMacTable(elanInstance, dpId, confTx);
997 * Install remote DMAC flow. This is required since this DPN is
998 * added later to the elan instance and remote DMACs of other
999 * interfaces in this elan instance are not present in the current
1002 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
1003 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
1004 elanInstance.getElanInstanceName());
1005 programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
1008 // bind the Elan service to the Interface
1009 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
1012 private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1013 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
1014 if (!isOperational(interfaceInfo)) {
1015 LOG.warn("Entries for interface on dpn {} not installed since interface {} is not operational",
1016 dpnInterfaces.getDpId(), interfaceInfo.getInterfaceName());
1017 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {} Interface Status {}, returning",
1018 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1021 EVENT_LOGGER.debug("ELAN-1stInterfaceEntries, ADD {} Instance {}",
1022 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
1023 // LocalBroadcast Group creation with elan-Interfaces
1024 LOG.info("Installing entries for interface {} on dpn {}", interfaceInfo.getInterfaceName(),
1025 dpnInterfaces.getDpId());
1026 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
1027 if (isFirstInterfaceInDpn) {
1028 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
1030 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1031 } catch (InterruptedException e1) {
1032 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
1037 public InstanceIdentifier<Group> getGroupIid(ElanInstance elanInfo, Uint64 dpnId) {
1038 long remoteBcGroupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1039 return InstanceIdentifier.builder(Nodes.class)
1040 .child(Node.class, new NodeKey(new org.opendaylight.yang.gen.v1.urn.opendaylight
1041 .inventory.rev130819.NodeId("openflow:" + dpnId.toString())))
1042 .augmentation(FlowCapableNode.class)
1043 .child(Group.class, new GroupKey(new GroupId(remoteBcGroupId))).build();
1046 public void scheduleElanInterfaceWorkerAfterRemoteBcGroup(ElanInstance elanInfo,
1047 InterfaceInfo interfaceInfo,
1048 DpnInterfaces dpnInterfaces,
1049 boolean isFirstInterfaceInDpn,
1050 ElanInterface elanInterface) {
1051 if (!isOperational(interfaceInfo)) {
1052 LOG.debug("Interface {} is not operational", elanInterface.getName());
1055 String elanInterfaceJobKey = ElanUtils.getElanInterfaceJobKey(interfaceInfo.getInterfaceName());
1056 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(elanInterfaceJobKey,
1057 elanInterface, interfaceInfo, elanInfo, isFirstInterfaceInDpn, this);
1058 InstanceIdentifier<Group> groupInstanceId = getGroupIid(elanInfo, dpnInterfaces.getDpId());
1059 elanGroupCache.addJobToWaitList(groupInstanceId, () -> {
1060 jobCoordinator.enqueueJob(elanInterfaceJobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
1064 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1065 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1066 int ifTag = interfaceInfo.getInterfaceTag();
1067 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1068 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 11, elanInfo.getElanInstanceName(),
1069 0, 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1070 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
1071 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
1073 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
1074 LOG.trace("Filter equals table(55) flow entry created on dpn: {} for interface port: {}",
1075 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1076 Map<InstructionKey, Instruction> customInstructionsMap = new HashMap<InstructionKey, Instruction>();
1077 int instructionKey = 0;
1078 for (Instruction instructionObj : MDSALUtil.buildInstructionsDrop()) {
1079 customInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
1082 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1083 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 12, elanInfo.getElanInstanceName(), 0,
1084 0, Uint64.valueOf(ElanConstants.COOKIE_ELAN_FILTER_EQUALS.toJava().add(BigInteger.valueOf(ifTag))),
1085 getMatchesForFilterEqualsLPortTag(ifTag), customInstructionsMap);
1087 mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
1088 LOG.trace("Filter equals table(55) drop flow entry created on dpn: {} for interface port: {}",
1089 interfaceInfo.getDpId(), interfaceInfo.getPortName());
1092 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1093 TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
1094 int ifTag = interfaceInfo.getInterfaceTag();
1095 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1096 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
1098 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
1100 Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
1101 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"));
1103 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
1106 private static List<MatchInfo> buildMatchesForVni(Uint64 vni) {
1107 List<MatchInfo> mkMatches = new ArrayList<>();
1108 MatchInfo match = new MatchTunnelId(vni);
1109 mkMatches.add(match);
1113 private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1114 List<InstructionInfo> mkInstructions = new ArrayList<>();
1115 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1116 return mkInstructions;
1119 private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1120 List<MatchInfo> mkMatches = new ArrayList<>();
1121 // Matching metadata
1122 mkMatches.add(new MatchMetadata(
1123 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1128 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1129 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1132 * elanTag to be written in metadata when flow is selected
1133 * @return the instructions ready to be installed in a flow
1135 private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Uint32 elanTag) {
1136 List<InstructionInfo> mkInstructions = new ArrayList<>();
1137 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
1138 ElanHelper.getElanMetadataMask()));
1139 /* applicable for EXTERNAL_TUNNEL_TABLE only
1140 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1142 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1143 return mkInstructions;
1146 // Install DMAC entry on dst DPN
1147 public List<ListenableFuture<?>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1149 String interfaceName = interfaceInfo.getInterfaceName();
1150 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1151 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1152 Map<MacEntryKey, MacEntry> macEntries = elanInterfaceMac.nonnullMacEntry();
1153 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
1154 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1155 for (MacEntry macEntry : macEntries.values()) {
1156 String macAddress = macEntry.getMacAddress().getValue();
1157 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
1159 try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag().toJava(), macAddress,
1160 interfaceInfo.getDpId())) {
1161 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
1163 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
1171 private static void createDropBucket(List<Bucket> listBucket) {
1172 List<Action> actionsInfos = new ArrayList<>();
1173 actionsInfos.add(new ActionDrop().buildAction());
1174 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1175 MDSALUtil.WATCH_GROUP);
1176 listBucket.add(dropBucket);
1179 private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1180 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1181 if (!isOperational(interfaceInfo)) {
1182 EVENT_LOGGER.debug("ELAN-LBG, ADD {} Instance {} Interface Status {}, returning",
1183 interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName(), interfaceInfo.getOpState());
1186 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1187 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
1190 private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1191 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1192 List<Bucket> listBucket = new ArrayList<>();
1194 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1196 List<String> interfaces = new ArrayList<>();
1197 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1198 interfaces = newDpnInterface.getInterfaces();
1200 for (String ifName : interfaces) {
1201 // In case if there is a InterfacePort in the cache which is not in
1202 // operational state, skip processing it
1203 InterfaceInfo ifInfo = interfaceManager
1204 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1205 if (!isOperational(ifInfo)) {
1209 if (!interfaceManager.isExternalInterface(ifName)) {
1210 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1211 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1216 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1217 MDSALUtil.buildBucketLists(listBucket));
1218 LOG.trace("installing the localBroadCast Group:{}", group);
1219 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1222 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1223 InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
1224 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1225 if (etreeInstance != null) {
1226 List<Bucket> listBucket = new ArrayList<>();
1229 List<String> interfaces = new ArrayList<>();
1230 if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
1231 interfaces = newDpnInterface.getInterfaces();
1233 for (String ifName : interfaces) {
1234 // In case if there is a InterfacePort in the cache which is not
1236 // operational state, skip processing it
1237 InterfaceInfo ifInfo = interfaceManager
1238 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1239 if (!isOperational(ifInfo)) {
1243 if (!interfaceManager.isExternalInterface(ifName)) {
1244 // only add root interfaces
1245 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1249 if (listBucket.isEmpty()) { // No Buckets
1250 createDropBucket(listBucket);
1253 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
1254 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1255 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1256 MDSALUtil.buildBucketLists(listBucket));
1257 LOG.trace("installing the localBroadCast Group:{}", group);
1258 mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
1262 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1263 InterfaceInfo ifInfo) {
1264 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1265 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1266 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1267 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1273 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1274 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1275 throws ExecutionException, InterruptedException {
1276 Uint64 dpnId = interfaceInfo.getDpId();
1277 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag().toJava());
1278 LOG.trace("deleted the localBroadCast Group:{}", groupId);
1279 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1282 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1283 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
1284 throws ExecutionException, InterruptedException {
1285 Uint64 dpnId = interfaceInfo.getDpId();
1286 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag().toJava());
1287 LOG.trace("deleting the remoteBroadCast group:{}", groupId);
1288 mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
1292 * Installs a flow in the External Tunnel table consisting in translating
1293 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1294 * elanTag that will be used later in the ELANs pipeline.
1295 * @param dpnId the dpn id
1297 private void setExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1298 TypedWriteTransaction<Configuration> confTx) {
1299 Uint32 elanTag = elanInfo.getElanTag();
1300 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1301 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag.longValue()), 5, // prio
1302 elanInfo.getElanInstanceName(), // flowName
1305 Uint64.valueOf(ITMConstants.COOKIE_ITM_EXTERNAL.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1306 buildMatchesForVni(Uint64.valueOf(ElanUtils.getVxlanSegmentationId(elanInfo).longValue())),
1307 getInstructionsIntOrExtTunnelTable(elanTag));
1309 mdsalManager.addFlow(confTx, flowEntity);
1313 * Removes, from External Tunnel table, the flow that translates from VNI to
1314 * elanTag. Important: ensure this method is only called whenever there is
1315 * no other ElanInterface in the specified DPN
1317 * @param dpnId DPN whose Ext Tunnel table is going to be modified
1319 private void unsetExternalTunnelTable(Uint64 dpnId, ElanInstance elanInfo,
1320 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
1321 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1322 // last ElanInstance plus
1323 // adding a new one does (almost at the same time) are executed in that
1326 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag().toJava());
1327 FlowEntity flowEntity = new FlowEntityBuilder()
1329 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1332 mdsalManager.removeFlow(confTx, flowEntity);
1335 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1336 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1337 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1338 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1341 public void setupTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId, Uint32 elanTag,
1342 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1343 List<? extends MatchInfoBase> listMatchInfoBase;
1344 List<InstructionInfo> instructionInfos;
1346 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1347 serviceId = elanTag;
1348 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId(elanTag);
1349 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue()));
1351 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1352 listMatchInfoBase = buildMatchesForVni(Uint64.valueOf(serviceId));
1353 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1355 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1356 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId.longValue()), 5,
1357 String.format("%s:%s", "ITM Flow Entry ", elanTag.toString()), 0, 0,
1358 Uint64.valueOf(ITMConstants.COOKIE_ITM.toJava().add(BigInteger.valueOf(elanTag.longValue()))),
1359 listMatchInfoBase, instructionInfos);
1360 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1361 LOG.info("Installed internal tunnel table (36) flow entry on dpn: {} for elan: {}, tag: {}", dpId,
1362 elanInfo.getElanInstanceName(), elanTag);
1365 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, Uint64 dpId,
1366 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1367 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1368 if (etreeInstance != null) {
1369 setupTerminateServiceTable(elanInfo, dpId,
1370 etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1374 public void setupUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId,
1375 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1376 long elanTag = elanInfo.getElanTag().toJava();
1377 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1378 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1379 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1382 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1383 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1384 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1385 if (etreeLeafTag != null) {
1386 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue().toJava();
1387 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1388 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1392 private void installLocalUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1393 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1394 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1395 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1396 5, elanInfo.getElanInstanceName(), 0, 0,
1397 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1398 getMatchesForElanTag(elanTag, /* SH flag */false),
1399 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1401 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1402 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan: {}, tag: {}",
1403 dpId, elanInfo.getElanInstanceName(), elanTag);
1406 private void installRemoteUnknownFlow(ElanInstance elanInfo, Uint64 dpId, long elanTag,
1407 TypedWriteTransaction<Configuration> writeFlowGroupTx) {
1408 // only if ELAN can connect to external network, perform the following
1410 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1411 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1412 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1413 5, elanInfo.getElanInstanceName(), 0, 0,
1414 Uint64.valueOf(ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.toJava().add(BigInteger.valueOf(elanTag))),
1415 getMatchesForElanTag(elanTag, /* SH flag */true),
1416 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1417 mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
1418 LOG.trace("Installed unknown dmac table (53) flow entry on dpn: {} for elan connected to "
1419 + "external network: {}, tag: {}", dpId, elanInfo.getElanInstanceName(), elanTag);
1424 private void removeUnknownDmacFlow(Uint64 dpId, ElanInstance elanInfo,
1425 TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
1426 throws ExecutionException, InterruptedException {
1427 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1428 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1429 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
1431 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1432 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1433 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1435 mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
1439 private void removeDefaultTermFlow(Uint64 dpId, long elanTag) {
1440 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1443 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1444 TypedWriteTransaction<Configuration> tx) {
1445 if (isStandardElanService(elanInterface)) {
1446 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(),
1447 elanInterface.getName(), lportTag, tx);
1448 } else { // Etree service
1449 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1453 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1454 TypedWriteTransaction<Configuration> tx) {
1455 int instructionKey = 0;
1456 List<Instruction> instructions = new ArrayList<>();
1457 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1458 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1460 List<Action> actions = new ArrayList<>();
1461 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1462 lportTag).buildAction());
1463 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1464 elanTag).buildAction());
1465 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1467 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1470 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1471 BoundServices serviceInfo = ElanUtils.getBoundServices(
1472 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1473 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1474 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1475 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1477 if (!existingElanService.isPresent()) {
1478 tx.mergeParentStructurePut(bindServiceId, serviceInfo);
1479 LOG.trace("Done binding elan service for elan: {} for interface: {}", elanInstanceName, interfaceName);
1483 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1484 TypedWriteTransaction<Configuration> tx) {
1485 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1486 bindElanService(elanInfo.getElanTag().toJava(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1489 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1490 if (etreeInstance == null) {
1491 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1492 elanInterface.getName(), elanInfo.getElanInstanceName());
1494 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue().toJava(), elanInfo.getElanInstanceName(),
1495 elanInterface.getName(), lportTag, tx);
1500 private static boolean isStandardElanService(ElanInterface elanInterface) {
1501 return elanInterface.augmentation(EtreeInterface.class) == null;
1504 protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
1505 throws ExecutionException, InterruptedException {
1506 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1507 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1508 if (tx.read(bindServiceId).get().isPresent()) {
1509 tx.delete(bindServiceId);
1513 private static String getFlowRef(long tableId, long elanTag) {
1514 return String.valueOf(tableId) + elanTag;
1517 private static String getFlowRef(long tableId, long elanTag, String flowName) {
1518 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1519 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1522 private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1523 return String.valueOf(tableId) + elanTag + shFlag;
1526 private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1527 List<Action> listAction = new ArrayList<>();
1530 new ActionSetFieldTunnelId(Uint64.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1532 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1536 private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, Uint64 dpId,
1537 List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
1538 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1539 .withKey(new DpnInterfacesKey(dpId)).build();
1540 tx.mergeParentStructurePut(ElanUtils
1541 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface);
1542 LOG.trace("Updated operational dpn interfaces for elan: {} with interfaces: {}", elanInstanceName,
1544 return dpnInterface;
1548 * Delete elan dpn interface from operational DS.
1550 * @param elanInstanceName
1551 * the elan instance name
1555 private static void deleteElanDpnInterface(String elanInstanceName, Uint64 dpId,
1556 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1557 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1558 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1559 Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
1560 if (dpnInterfaces.isPresent()) {
1561 tx.delete(dpnInterfacesId);
1565 private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
1566 Uint64 dpId, TypedWriteTransaction<Operational> tx) {
1567 List<String> interfaceNames = new ArrayList<>();
1568 interfaceNames.add(interfaceName);
1569 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1570 .withKey(new DpnInterfacesKey(dpId)).build();
1571 return dpnInterface;
1574 private static void createElanStateList(String elanInstanceName, String interfaceName,
1575 TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
1576 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1577 Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
1578 // Adding new Elan Interface Port to the operational DataStore without
1579 // Static-Mac Entries..
1580 if (elanInterfaceLists.isPresent()) {
1581 List<String> interfaceLists = new ArrayList<>();
1582 interfaceLists.add(interfaceName);
1583 List<String> existingInterfaceLists = elanInterfaceLists.get().getElanInterfaces();
1584 if (existingInterfaceLists != null && !existingInterfaceLists.isEmpty()) {
1585 existingInterfaceLists.forEach(iface -> interfaceLists.add(iface));
1588 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1589 .withKey(new ElanKey(elanInstanceName)).build();
1590 tx.mergeParentStructurePut(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState);
1591 LOG.trace("Updated operational elan state for elan: {} with interfaces: {}", elanInstanceName,
1596 private static boolean isOperational(InterfaceInfo interfaceInfo) {
1597 return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1600 @SuppressWarnings("checkstyle:IllegalCatch")
1601 public void handleInternalTunnelStateEvent(Uint64 srcDpId, Uint64 dstDpId) {
1602 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1603 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1604 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1605 if (dpnInterfaceLists == null) {
1608 Map<ElanDpnInterfacesListKey, ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists
1609 .nonnullElanDpnInterfacesList();
1610 for (ElanDpnInterfacesList elanDpns : elanDpnIf.values()) {
1612 String elanName = elanDpns.getElanInstanceName();
1613 ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null);
1614 if (elanInfo == null) {
1615 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1616 + "skipping this ELAN for tunnel handling", elanName);
1619 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1620 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1623 Map<DpnInterfacesKey, DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
1624 if (dpnInterfaces == null) {
1627 DpnInterfaces dstDpnIf = null;
1628 for (DpnInterfaces dpnIf : dpnInterfaces.values()) {
1629 Uint64 dpnIfDpId = dpnIf.getDpId();
1630 if (Objects.equals(dpnIfDpId, srcDpId)) {
1632 } else if (Objects.equals(dpnIfDpId, dstDpId)) {
1638 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1639 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1640 jobCoordinator.enqueueJob(elanName, () -> {
1641 // update Remote BC Group
1642 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1644 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1645 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
1647 } catch (RuntimeException e) {
1648 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1650 Set<String> interfaceLists = new HashSet<>();
1651 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1652 for (String ifName : interfaceLists) {
1653 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1654 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1655 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1656 if (isOperational(interfaceInfo)) {
1657 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1660 }, ElanConstants.JOB_MAX_RETRIES);
1663 }, ElanConstants.JOB_MAX_RETRIES);
1670 * Handle external tunnel state event.
1672 * @param externalTunnel
1673 * the external tunnel
1677 void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1678 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1681 // dpId/externalNodeId will be available either in source or destination
1682 // based on the tunnel end point
1684 NodeId externalNodeId = null;
1685 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1686 dpId = Uint64.valueOf(externalTunnel.getSourceDevice());
1687 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1688 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1689 dpId = Uint64.valueOf(externalTunnel.getDestinationDevice());
1690 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1692 if (dpId == null || externalNodeId == null) {
1693 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1697 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1698 if (dpnInterfaceLists == null) {
1701 Map<ElanDpnInterfacesListKey, ElanDpnInterfacesList> elanDpnIf
1702 = dpnInterfaceLists.nonnullElanDpnInterfacesList();
1703 for (ElanDpnInterfacesList elanDpns : elanDpnIf.values()) {
1704 String elanName = elanDpns.getElanInstanceName();
1705 ElanInstance elanInfo = elanInstanceCache.get(elanName).orElse(null);
1707 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1708 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1709 || dpnInterfaces.getInterfaces().isEmpty()) {
1712 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1714 final Uint64 finalDpId = dpId;
1715 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1716 confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
1717 "Error setting up ELAN BGs");
1718 // install L2gwDevices local macs in dpn.
1719 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1720 // Install dpn macs on external device
1721 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1724 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1728 * Installs dpn macs in external device. first it checks if the physical
1729 * locator towards this dpn tep is present or not if the physical locator is
1730 * present go ahead and add the ucast macs otherwise update the mcast mac
1731 * entry to include this dpn tep ip and schedule the job to put ucast macs
1732 * once the physical locator is programmed in device
1736 * @param lstElanInterfaceNames
1737 * the lst Elan interface names
1740 * @param externalNodeId
1741 * the external node id
1743 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, Uint64 dpnId,
1744 NodeId externalNodeId) {
1745 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1746 externalNodeId.getValue());
1747 if (elanL2GwDevice == null) {
1748 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1751 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1752 if (dpnTepIp == null) {
1753 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1758 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1759 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1760 LogicalDatastoreType.OPERATIONAL);
1761 boolean phyLocAlreadyExists =
1762 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1764 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1765 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1766 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1768 if (phyLocAlreadyExists) {
1769 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1772 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1773 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1777 * Validate external tunnel state event.
1779 * @param externalTunnel
1780 * the external tunnel
1783 * @return true, if successful
1785 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1786 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1787 String srcDevice = externalTunnel.getDestinationDevice();
1788 String destDevice = externalTunnel.getSourceDevice();
1789 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1790 LogicalDatastoreType.CONFIGURATION);
1791 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1792 otherEndPointExtTunnel);
1793 if (otherEndPointExtTunnel != null) {
1794 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1795 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1796 if (otherEndPointInterfaceOperational) {
1799 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1800 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1807 private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1808 List<MatchInfo> mkMatches = new ArrayList<>();
1809 // Matching metadata
1811 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1812 mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag)));
1816 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1818 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1819 addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1820 confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
1821 confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
1823 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1824 } catch (InterruptedException e) {
1825 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);