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 org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.List;
24 import java.util.Objects;
25 import java.util.Queue;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentLinkedQueue;
29 import javax.annotation.PostConstruct;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.apache.commons.lang3.StringUtils;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
38 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
39 import org.opendaylight.genius.infra.Datastore.Configuration;
40 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
41 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
42 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
43 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
44 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
45 import org.opendaylight.genius.itm.globals.ITMConstants;
46 import org.opendaylight.genius.mdsalutil.FlowEntity;
47 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
48 import org.opendaylight.genius.mdsalutil.InstructionInfo;
49 import org.opendaylight.genius.mdsalutil.MDSALUtil;
50 import org.opendaylight.genius.mdsalutil.MatchInfo;
51 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
52 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
53 import org.opendaylight.genius.mdsalutil.NwConstants;
54 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
55 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
56 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
57 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
58 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
59 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
60 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
61 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
62 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
63 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
64 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
65 import org.opendaylight.genius.utils.ServiceIndex;
66 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
67 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
68 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
69 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
70 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
71 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
72 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
73 import org.opendaylight.netvirt.elan.utils.ElanConstants;
74 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
75 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
76 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
77 import org.opendaylight.netvirt.elan.utils.ElanUtils;
78 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
79 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
80 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
81 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
82 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
83 import org.opendaylight.serviceutils.srm.RecoverableListener;
84 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
85 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
86 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
87 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
128 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
129 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
130 import org.slf4j.Logger;
131 import org.slf4j.LoggerFactory;
134 * Class in charge of handling creations, modifications and removals of
137 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
140 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
141 implements RecoverableListener {
142 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
143 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
144 private static final boolean SH_FLAG_SET = true;
145 private static final boolean SH_FLAG_UNSET = false;
147 private final DataBroker broker;
148 private final ManagedNewTransactionRunner txRunner;
149 private final IMdsalApiManager mdsalManager;
150 private final IInterfaceManager interfaceManager;
151 private final IdManagerService idManager;
152 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
153 private final INeutronVpnManager neutronVpnManager;
154 private final ElanItmUtils elanItmUtils;
155 private final ElanEtreeUtils elanEtreeUtils;
156 private final ElanL2GatewayUtils elanL2GatewayUtils;
157 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
158 private final ElanUtils elanUtils;
159 private final JobCoordinator jobCoordinator;
160 private final ElanInstanceCache elanInstanceCache;
161 private final ElanInterfaceCache elanInterfaceCache;
163 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
164 unProcessedElanInterfaces = new ConcurrentHashMap<>();
167 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
168 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
169 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
170 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
171 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
172 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
173 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
174 final ElanInstanceCache elanInstanceCache,
175 final ElanInterfaceCache elanInterfaceCache,
176 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
177 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
178 super(ElanInterface.class, ElanInterfaceManager.class);
179 this.broker = dataBroker;
180 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
181 this.idManager = managerService;
182 this.mdsalManager = mdsalApiManager;
183 this.interfaceManager = interfaceManager;
184 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
185 this.neutronVpnManager = neutronVpnManager;
186 this.elanItmUtils = elanItmUtils;
187 this.elanEtreeUtils = elanEtreeUtils;
188 this.elanL2GatewayUtils = elanL2GatewayUtils;
189 this.elanUtils = elanUtils;
190 this.jobCoordinator = jobCoordinator;
191 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
192 this.elanInstanceCache = elanInstanceCache;
193 this.elanInterfaceCache = elanInterfaceCache;
194 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
204 public void registerListener() {
205 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
209 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
210 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
214 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
215 String interfaceName = del.getName();
216 String elanInstanceName = del.getElanInstanceName();
217 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
218 if (elanInterfaces != null && elanInterfaces.contains(del)) {
219 elanInterfaces.remove(del);
220 if (elanInterfaces.isEmpty()) {
221 unProcessedElanInterfaces.remove(elanInstanceName);
224 ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
226 * Handling in case the elan instance is deleted.If the Elan instance is
227 * deleted, there is no need to explicitly delete the elan interfaces
229 if (elanInfo == null) {
232 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
233 if (interfaceInfo == null && elanInfo.isExternal()) {
234 // In deleting external network, the underlying ietf Inteface might have been removed
235 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
236 // from Operational DS instead
237 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
239 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
240 interfaceName, interfaceInfo, this);
241 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
244 @SuppressWarnings("checkstyle:ForbidCertainMethod")
245 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
246 InterfaceInfo interfaceInfo) {
247 String elanName = elanInfo.getElanInstanceName();
248 boolean isLastElanInterface = false;
249 boolean isLastInterfaceOnDpn = false;
250 BigInteger dpId = null;
251 long elanTag = elanInfo.getElanTag();
252 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
253 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
254 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
255 if (elanState == null) {
256 interfaceTx.cancel();
257 return Collections.emptyList();
259 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
260 List<String> elanInterfaces = elanState.getElanInterfaces();
261 if (elanInterfaces.isEmpty()) {
262 isLastElanInterface = true;
264 if (interfaceInfo != null) {
265 dpId = interfaceInfo.getDpId();
266 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
267 interfaceName, elanTag, interfaceTx);
269 * If there are not elan ports, remove the unknown dmac, terminating
270 * service table flows, remote/local bc group
272 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
273 || dpnInterfaces.getInterfaces().isEmpty()) {
274 // No more Elan Interfaces in this DPN
275 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
276 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
277 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
279 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
280 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
281 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
282 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
283 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
284 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
285 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
286 elanUtils.removeTerminatingServiceAction(dpId,
287 ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
289 unsetExternalTunnelTable(dpId, elanInfo);
291 isLastInterfaceOnDpn = true;
293 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
297 List<ListenableFuture<Void>> futures = new ArrayList<>();
298 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
299 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
301 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
302 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
304 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
305 interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
306 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
307 ElanConstants.JOB_MAX_RETRIES);
312 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
313 WriteTransaction deleteFlowGroupTx) {
314 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
315 if (etreeLeafTag != null) {
316 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
317 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
321 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
322 WriteTransaction deleteFlowGroupTx) {
323 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
324 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
327 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
328 WriteTransaction deleteFlowGroupTx) {
329 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
330 if (etreeInstance != null) {
331 BigInteger dpnId = interfaceInfo.getDpId();
332 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
333 List<Bucket> listBuckets = new ArrayList<>();
335 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
336 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
337 MDSALUtil.buildBucketLists(listBuckets));
338 LOG.trace("deleted the localBroadCast Group:{}", group);
339 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
343 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
344 WriteTransaction deleteFlowGroupTx) {
345 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
346 if (etreeInstance != null) {
347 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
350 List<Bucket> listBuckets = new ArrayList<>();
351 List<Action> listAction = new ArrayList<>();
352 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
353 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
354 MDSALUtil.WATCH_GROUP));
356 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
357 BigInteger dpnId = interfaceInfo.getDpId();
358 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
359 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
360 MDSALUtil.buildBucketLists(listBuckets));
361 LOG.trace("deleting the remoteBroadCast group:{}", group);
362 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
366 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
367 String elanName = elanInfo.getElanInstanceName();
368 Elan elanState = ElanUtils.getElanByName(broker, elanName);
369 if (elanState == null) {
372 List<String> elanInterfaces = elanState.getElanInterfaces();
373 boolean isRemoved = elanInterfaces.remove(interfaceName);
378 if (elanInterfaces.isEmpty()) {
379 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
380 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
381 tx.delete(LogicalDatastoreType.OPERATIONAL,
382 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
384 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
385 .withKey(new ElanKey(elanName)).build();
386 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
392 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
393 // removing the ElanInterface from the config data_store if interface is
394 // not present in Interface config DS
395 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
396 && elanInterfaceCache.get(interfaceName).isPresent()) {
397 tx.delete(LogicalDatastoreType.CONFIGURATION,
398 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
402 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
403 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
404 String elanName = elanInfo.getElanInstanceName();
405 List<ListenableFuture<Void>> futures = new ArrayList<>();
406 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
407 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> {
408 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
409 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
410 Optional<ElanInterfaceMac> existingElanInterfaceMac =
411 interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet();
412 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
413 if (interfaceInfo != null) {
414 if (existingElanInterfaceMac.isPresent()) {
415 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
416 if (existingMacEntries != null) {
417 List<PhysAddress> macAddresses = new ArrayList<>();
418 for (MacEntry macEntry : existingMacEntries) {
419 PhysAddress macAddress = macEntry.getMacAddress();
420 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
421 macAddress.getValue(), interfaceName);
422 Optional<MacEntry> macEntryOptional =
423 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
424 if (!isLastElanInterface && macEntryOptional.isPresent()) {
425 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
426 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
428 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
429 macAddresses.add(macAddress);
432 // Removing all those MACs from External Devices belonging
434 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
435 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
439 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
440 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
441 } else if (existingElanInterfaceMac.isPresent()) {
442 // Interface does not exist in ConfigDS, so lets remove everything
443 // about that interface related to Elan
444 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
445 if (macEntries != null) {
446 for (MacEntry macEntry : macEntries) {
447 PhysAddress macAddress = macEntry.getMacAddress();
448 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
449 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
450 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
455 if (existingElanInterfaceMac.isPresent()) {
456 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
458 unbindService(interfaceName, interfaceTx);
459 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
465 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
466 String interfaceName, long elanTag,
467 WriteTransaction tx) {
468 synchronized (elanName.intern()) {
470 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
471 if (dpnInterfaces != null) {
472 List<String> interfaceLists = dpnInterfaces.getInterfaces();
473 if (interfaceLists != null) {
474 interfaceLists.remove(interfaceName);
477 if (interfaceLists == null || interfaceLists.isEmpty()) {
478 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
479 deleteElanDpnInterface(elanName, dpId, tx);
481 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
484 return dpnInterfaces;
488 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
489 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
490 for (DpnInterfaces dpnInterface : dpnInterfaces) {
491 BigInteger currentDpId = dpnInterface.getDpId();
492 if (!currentDpId.equals(dpId)) {
493 for (String elanInterface : dpnInterface.getInterfaces()) {
494 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
495 if (macs == null || macs.getMacEntry() == null) {
498 for (MacEntry mac : macs.getMacEntry()) {
499 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
500 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
507 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
508 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
509 if (etreeLeafTag != null) {
510 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
514 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
517 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
518 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
519 mac.getMacAddress().getValue(), elanTag)));
523 * Possible Scenarios for update
524 * a. if orig={1,2,3,4} and updated=null or updated={}
525 then all {1,2,3,4} should be removed
527 b. if orig=null or orig={} and updated ={1,2,3,4}
528 then all {1,2,3,4} should be added
530 c. if orig = {1,2,3,4} updated={2,3,4}
531 then 1 should be removed
533 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
534 then we should just add 5
536 e. if orig = {1,2,3,4} updated={2,3,4,5}
537 then 1 should be removed , 5 should be added
539 @SuppressWarnings("checkstyle:ForbidCertainMethod")
541 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
542 // updating the static-Mac Entries for the existing elanInterface
543 String elanName = update.getElanInstanceName();
544 String interfaceName = update.getName();
546 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
547 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
548 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
549 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
551 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
552 deletedEntry.getMacAddress()));
554 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
555 * Hence add the macentries for the same.*/
556 for (StaticMacEntries staticMacEntry : updatedEntries) {
557 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
558 staticMacEntry.getMacAddress());
559 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
560 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
561 WriteTransaction tx = broker.newWriteOnlyTransaction();
562 if (existingMacEntry.isPresent()) {
563 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
564 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
567 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
568 elanName, interfaceName, staticMacEntry, tx);
570 ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(tx), LOG,
571 "Error in update: identifier={}, original={}, update={}", identifier, original, update);
576 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
577 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
578 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
579 String interfaceName = elanInterfaceAdded.getName();
580 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
581 if (interfaceInfo == null) {
582 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
585 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
587 if (elanInstance == null) {
588 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
589 .setDescription(elanInterfaceAdded.getDescription()).build();
590 // Add the ElanInstance in the Configuration data-store
591 List<String> elanInterfaces = new ArrayList<>();
592 elanInterfaces.add(interfaceName);
593 elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
596 Long elanTag = elanInstance.getElanTag();
597 // If elan tag is not updated, then put the elan interface into
598 // unprocessed entry map and entry. Let entries
599 // in this map get processed during ELAN update DCN.
600 if (elanTag == null || elanTag == 0L) {
601 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
602 if (elanInterfaces == null) {
603 elanInterfaces = new ConcurrentLinkedQueue<>();
605 if (!elanInterfaces.contains(elanInterfaceAdded)) {
606 elanInterfaces.add(elanInterfaceAdded);
608 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
611 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
612 interfaceInfo, elanInstance, this);
613 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
614 }), LOG, "Error procedding added ELAN interface");
617 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
618 List<ListenableFuture<Void>> futures = new ArrayList<>();
619 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
620 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
623 for (ElanInterface elanInterface : elanInterfaces) {
624 String interfaceName = elanInterface.getName();
625 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
626 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
628 unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
632 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
633 WriteTransaction writeFlowGroupTx) {
634 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
635 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
636 List<DpnInterfaces> dpnInterfaceLists = null;
637 if (elanDpnInterfacesList != null) {
638 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
640 if (dpnInterfaceLists == null) {
641 dpnInterfaceLists = new ArrayList<>();
643 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
644 BigInteger dstDpId = interfaceInfo.getDpId();
645 if (dpnInterfaces.getDpId().equals(dstDpId)) {
648 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
649 for (String remoteIf : remoteElanInterfaces) {
650 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
651 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
652 if (elanIfMac == null || remoteInterface == null) {
655 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
656 if (remoteMacEntries != null) {
657 for (MacEntry macEntry : remoteMacEntries) {
658 String macAddress = macEntry.getMacAddress().getValue();
659 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
660 dstDpId, elanInstance.getElanInstanceName());
661 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
662 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
663 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
670 @SuppressWarnings("checkstyle:ForbidCertainMethod")
671 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
672 InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
673 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
674 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
675 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
677 String interfaceName = elanInterface.getName();
678 String elanInstanceName = elanInterface.getElanInstanceName();
680 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
681 WriteTransaction tx = broker.newWriteOnlyTransaction();
682 if (elanInfo == null) {
683 List<String> elanInterfaces = new ArrayList<>();
684 elanInterfaces.add(interfaceName);
685 ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
687 createElanStateList(elanInstanceName, interfaceName, tx);
689 boolean isFirstInterfaceInDpn = false;
690 // Specific actions to the DPN where the ElanInterface has been added,
691 // for example, programming the
692 // External tunnel table if needed or adding the ElanInterface to the
693 // DpnInterfaces in the operational DS.
694 BigInteger dpId = interfaceInfo.getDpId();
695 DpnInterfaces dpnInterfaces = null;
696 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
697 synchronized (elanInstanceName.intern()) {
698 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
699 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
700 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
701 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
702 if (ElanUtils.isVlan(elanInstance)) {
703 isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
704 elanInstanceName, existingElanDpnInterfaces);
706 isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
708 if (isFirstInterfaceInDpn) {
709 // ELAN's 1st ElanInterface added to this DPN
710 if (!existingElanDpnInterfaces.isPresent()) {
711 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
713 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
714 elanInterfaces.add(interfaceName);
715 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
718 // The 1st ElanInterface in a DPN must program the Ext Tunnel
719 // table, but only if Elan has VNI
720 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
721 setExternalTunnelTable(dpId, elanInstance);
723 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
725 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
726 elanInterfaces.add(interfaceName);
727 if (elanInterfaces.size() == 1) { // 1st dpn interface
728 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
730 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
735 // add code to install Local/Remote BC group, unknow DMAC entry,
736 // terminating service table flow entry
737 // call bindservice of interfacemanager to create ingress table flow
739 // Add interface to the ElanInterfaceForwardingEntires Container
740 createElanInterfaceTablesList(interfaceName, tx);
741 List<ListenableFuture<Void>> futures = new ArrayList<>();
742 futures.add(ElanUtils.waitForTransactionToComplete(tx));
743 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
745 // add the vlan provider interface to remote BC group for the elan
746 // for internal vlan networks
747 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
748 if (interfaceManager.isExternalInterface(interfaceName)) {
749 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
750 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
754 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
755 //update the remote-DPNs remoteBC group entry with Tunnels
756 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
757 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
760 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
761 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
762 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
763 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
767 @SuppressWarnings("checkstyle:ForbidCertainMethod")
768 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
769 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
770 String elanInstanceName = elanInstance.getElanInstanceName();
771 String interfaceName = elanInterface.getName();
772 WriteTransaction tx = broker.newWriteOnlyTransaction();
773 BigInteger dpId = interfaceInfo.getDpId();
774 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
775 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
776 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
778 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
779 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
781 boolean isInterfaceOperational = isOperational(interfaceInfo);
782 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
783 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
784 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
785 staticMacEntry.getMacAddress());
786 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
787 LogicalDatastoreType.OPERATIONAL, macId);
788 if (existingMacEntry.isPresent()) {
789 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
790 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
791 existingMacEntry.get(), tx);
793 elanForwardingEntriesHandler
794 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
797 if (isInterfaceOperational) {
798 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
800 String macAddress = staticMacEntry.getMacAddress().getValue();
801 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
802 macAddress, elanInstanceName, interfaceName);
803 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
804 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
808 if (isInterfaceOperational) {
809 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
811 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
812 staticMacAddresses.add(staticMacEntry.getMacAddress());
814 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
818 List<ListenableFuture<Void>> futures = new ArrayList<>();
819 futures.add(ElanUtils.waitForTransactionToComplete(tx));
820 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
821 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
822 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
824 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
825 if (neutronPort != null) {
826 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
828 } catch (IllegalArgumentException ex) {
829 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
835 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
836 PhysAddress physAddress) {
837 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
838 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
839 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
840 LogicalDatastoreType.OPERATIONAL, macId);
842 if (!existingMacEntry.isPresent()) {
846 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
847 .withKey(new MacEntryKey(physAddress)).build();
848 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
849 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
852 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
853 Optional<DpnInterfaces> existingElanDpnInterfaces) {
854 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
855 if (!existingElanDpnInterfaces.isPresent()) {
858 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
861 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
862 int dummyInterfaceCount = 0;
863 if (dpnInterfaces.getInterfaces().contains(routerPortUuid)) {
864 dummyInterfaceCount++;
866 if (dpnInterfaces.getInterfaces().contains(elanInstanceName)) {
867 dummyInterfaceCount++;
869 if (dpnInterfaces.getInterfaces().size() - dummyInterfaceCount == 0) {
875 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
876 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
877 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
880 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
881 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
882 WriteTransaction writeFlowGroupTx) {
883 if (!isOperational(interfaceInfo)) {
886 BigInteger dpId = interfaceInfo.getDpId();
887 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
888 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
890 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
891 if (isFirstInterfaceInDpn) {
892 // Terminating Service , UnknownDMAC Table.
893 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
894 // for ELAN Instance is VxLAN
895 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
896 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
898 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
900 * Install remote DMAC flow. This is required since this DPN is
901 * added later to the elan instance and remote DMACs of other
902 * interfaces in this elan instance are not present in the current
905 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
906 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
907 elanInstance.getElanInstanceName());
908 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
911 // bind the Elan service to the Interface
912 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
915 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
916 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
917 if (!isOperational(interfaceInfo)) {
920 // LocalBroadcast Group creation with elan-Interfaces
921 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
922 if (isFirstInterfaceInDpn) {
923 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
924 BigInteger dpId = interfaceInfo.getDpId();
925 // RemoteBroadcast Group creation
927 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
928 } catch (InterruptedException e1) {
929 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
931 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
933 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
934 } catch (InterruptedException e1) {
935 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
940 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
941 WriteTransaction writeFlowGroupTx) {
942 int ifTag = interfaceInfo.getInterfaceTag();
943 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
944 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
945 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
946 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
947 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
949 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
951 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
952 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
953 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
954 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
956 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
959 // TODO skitt Fix the exception handling here
960 @SuppressWarnings("checkstyle:IllegalCatch")
961 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
962 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
963 TypedReadWriteTransaction<Configuration> flowTx) {
965 int ifTag = interfaceInfo.getInterfaceTag();
966 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
967 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
969 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
971 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
972 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
973 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
974 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
976 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
977 } catch (Exception e) {
978 LOG.error("Error removing flow", e);
979 throw new RuntimeException("Error removing flow", e);
983 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
984 InterfaceInfo interfaceInfo, long elanTag) {
985 return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
986 bucketKeyStart, elanTag);
989 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
990 int elanTag = elanInfo.getElanTag().intValue();
991 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
992 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
993 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
994 if (etreeInstance != null) {
995 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
996 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
997 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
1001 @SuppressWarnings("checkstyle:IllegalCatch")
1002 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
1004 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1005 if (elanDpns != null) {
1006 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1007 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1008 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1009 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1010 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1011 List<Action> listAction = new ArrayList<>();
1013 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1014 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1015 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1017 for (DpnInterfaces otherFes : dpnInterfaces) {
1018 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1019 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1020 && !otherFes.getInterfaces().isEmpty()) {
1022 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1023 dpnInterface.getDpId(), otherFes.getDpId(),
1024 elanUtils.isOpenstackVniSemanticsEnforced()
1025 ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1026 if (!remoteListActionInfo.isEmpty()) {
1027 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1028 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1031 } catch (Exception ex) {
1032 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1033 + "Logical Group Interface not found between source Dpn - {}, "
1034 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1039 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1040 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1041 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1043 if (remoteListBucketInfo.isEmpty()) {
1044 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1047 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1048 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1049 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1050 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
1054 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1055 } catch (InterruptedException e1) {
1056 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1062 * Returns the bucket info with the given interface as the only bucket.
1064 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
1065 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
1066 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
1069 private List<MatchInfo> buildMatchesForVni(Long vni) {
1070 List<MatchInfo> mkMatches = new ArrayList<>();
1071 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1072 mkMatches.add(match);
1076 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1077 List<InstructionInfo> mkInstructions = new ArrayList<>();
1078 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1079 return mkInstructions;
1082 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1083 List<MatchInfo> mkMatches = new ArrayList<>();
1084 // Matching metadata
1085 mkMatches.add(new MatchMetadata(
1086 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1091 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1092 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1095 * elanTag to be written in metadata when flow is selected
1096 * @return the instructions ready to be installed in a flow
1098 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1099 List<InstructionInfo> mkInstructions = new ArrayList<>();
1100 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1101 .getElanMetadataMask()));
1102 /* applicable for EXTERNAL_TUNNEL_TABLE only
1103 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1105 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1106 return mkInstructions;
1109 // Install DMAC entry on dst DPN
1110 @SuppressWarnings("checkstyle:ForbidCertainMethod")
1111 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1112 BigInteger dstDpId) {
1113 String interfaceName = interfaceInfo.getInterfaceName();
1114 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1115 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1116 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1117 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1118 for (MacEntry macEntry : macEntries) {
1119 String macAddress = macEntry.getMacAddress().getValue();
1120 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1121 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1122 interfaceInfo.getDpId())) {
1123 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress);
1124 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1128 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1130 return Collections.emptyList();
1133 private void createDropBucket(List<Bucket> listBucket) {
1134 List<Action> actionsInfos = new ArrayList<>();
1135 actionsInfos.add(new ActionDrop().buildAction());
1136 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1137 MDSALUtil.WATCH_GROUP);
1138 listBucket.add(dropBucket);
1141 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1142 InterfaceInfo interfaceInfo) {
1143 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1144 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1147 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1148 InterfaceInfo interfaceInfo) {
1149 List<Bucket> listBucket = new ArrayList<>();
1151 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1153 List<String> interfaces = new ArrayList<>();
1154 if (newDpnInterface != null) {
1155 interfaces = newDpnInterface.getInterfaces();
1157 for (String ifName : interfaces) {
1158 // In case if there is a InterfacePort in the cache which is not in
1159 // operational state, skip processing it
1160 InterfaceInfo ifInfo = interfaceManager
1161 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1162 if (!isOperational(ifInfo)) {
1166 if (!interfaceManager.isExternalInterface(ifName)) {
1167 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1168 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1173 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1174 MDSALUtil.buildBucketLists(listBucket));
1175 LOG.trace("installing the localBroadCast Group:{}", group);
1176 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1179 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1180 InterfaceInfo interfaceInfo) {
1181 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1182 if (etreeInstance != null) {
1183 List<Bucket> listBucket = new ArrayList<>();
1186 List<String> interfaces = new ArrayList<>();
1187 if (newDpnInterface != null) {
1188 interfaces = newDpnInterface.getInterfaces();
1190 for (String ifName : interfaces) {
1191 // In case if there is a InterfacePort in the cache which is not
1193 // operational state, skip processing it
1194 InterfaceInfo ifInfo = interfaceManager
1195 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1196 if (!isOperational(ifInfo)) {
1200 if (!interfaceManager.isExternalInterface(ifName)) {
1201 // only add root interfaces
1202 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1206 if (listBucket.isEmpty()) { // No Buckets
1207 createDropBucket(listBucket);
1210 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1211 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1212 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1213 MDSALUtil.buildBucketLists(listBucket));
1214 LOG.trace("installing the localBroadCast Group:{}", group);
1215 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1219 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1220 InterfaceInfo ifInfo) {
1221 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1222 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1223 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1224 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1230 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1231 WriteTransaction deleteFlowGroupTx) {
1232 BigInteger dpnId = interfaceInfo.getDpId();
1233 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1234 List<Bucket> listBuckets = new ArrayList<>();
1236 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1237 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1239 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1240 MDSALUtil.buildBucketLists(listBuckets));
1241 LOG.trace("deleted the localBroadCast Group:{}", group);
1242 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1245 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1246 WriteTransaction deleteFlowGroupTx) {
1249 Long elanTag = elanInfo.getElanTag();
1250 List<Bucket> listBuckets = new ArrayList<>();
1251 List<Action> listAction = new ArrayList<>();
1252 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1253 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1254 MDSALUtil.WATCH_GROUP));
1256 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1257 BigInteger dpnId = interfaceInfo.getDpId();
1258 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1259 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1260 MDSALUtil.buildBucketLists(listBuckets));
1261 LOG.trace("deleting the remoteBroadCast group:{}", group);
1262 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1266 * Installs a flow in the External Tunnel table consisting in translating
1267 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1268 * elanTag that will be used later in the ELANs pipeline.
1275 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1276 long elanTag = elanInfo.getElanTag();
1277 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1278 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1279 elanInfo.getElanInstanceName(), // flowName
1282 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1283 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1284 getInstructionsIntOrExtTunnelTable(elanTag));
1286 mdsalManager.installFlow(flowEntity);
1290 * Removes, from External Tunnel table, the flow that translates from VNI to
1291 * elanTag. Important: ensure this method is only called whenever there is
1292 * no other ElanInterface in the specified DPN
1295 * DPN whose Ext Tunnel table is going to be modified
1297 * holds the elanTag needed for selecting the flow to be removed
1299 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1300 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1301 // last ElanInstance plus
1302 // adding a new one does (almost at the same time) are executed in that
1305 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1306 FlowEntity flowEntity = new FlowEntityBuilder()
1308 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1311 mdsalManager.removeFlow(flowEntity);
1314 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1315 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1316 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1319 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1320 WriteTransaction writeFlowGroupTx) {
1321 List<? extends MatchInfoBase> listMatchInfoBase;
1322 List<InstructionInfo> instructionInfos;
1324 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1325 serviceId = elanTag;
1326 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1327 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1329 serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
1330 listMatchInfoBase = buildMatchesForVni(serviceId);
1331 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1333 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1334 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1335 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1337 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1340 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1341 WriteTransaction writeFlowGroupTx) {
1342 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1343 if (etreeInstance != null) {
1344 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1348 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1349 long elanTag = elanInfo.getElanTag();
1350 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1351 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1352 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1355 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1356 WriteTransaction writeFlowGroupTx) {
1357 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1358 if (etreeLeafTag != null) {
1359 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1360 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1361 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1365 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1366 WriteTransaction writeFlowGroupTx) {
1367 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1368 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1369 5, elanInfo.getElanInstanceName(), 0, 0,
1370 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1371 getMatchesForElanTag(elanTag, /* SH flag */false),
1372 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1374 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1377 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1378 WriteTransaction writeFlowGroupTx) {
1379 // only if ELAN can connect to external network, perform the following
1381 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1382 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1383 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1384 5, elanInfo.getElanInstanceName(), 0, 0,
1385 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1386 getMatchesForElanTag(elanTag, /* SH flag */true),
1387 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1388 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1393 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1395 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1396 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1397 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1399 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1400 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1401 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1403 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1407 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1408 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1411 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1412 if (isStandardElanService(elanInterface)) {
1413 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1414 elanInterface.getName(), lportTag, tx);
1415 } else { // Etree service
1416 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1420 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1421 WriteTransaction tx) {
1422 int instructionKey = 0;
1423 List<Instruction> instructions = new ArrayList<>();
1424 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1425 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1427 List<Action> actions = new ArrayList<>();
1428 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1429 lportTag).buildAction());
1430 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1431 elanTag).buildAction());
1432 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1434 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1437 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1438 BoundServices serviceInfo = ElanUtils.getBoundServices(
1439 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1440 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1441 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1442 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1444 if (!existingElanService.isPresent()) {
1445 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1446 WriteTransaction.CREATE_MISSING_PARENTS);
1450 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1451 WriteTransaction tx) {
1452 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1453 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1456 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1457 if (etreeInstance == null) {
1458 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1459 elanInterface.getName(), elanInfo.getElanInstanceName());
1461 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1462 elanInterface.getName(), lportTag, tx);
1467 private boolean isStandardElanService(ElanInterface elanInterface) {
1468 return elanInterface.augmentation(EtreeInterface.class) == null;
1471 protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
1472 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1473 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1474 if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
1475 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1479 private String getFlowRef(long tableId, long elanTag) {
1480 return String.valueOf(tableId) + elanTag;
1483 private String getFlowRef(long tableId, long elanTag, String flowName) {
1484 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1485 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1488 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1489 return String.valueOf(tableId) + elanTag + shFlag;
1492 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1493 List<Action> listAction = new ArrayList<>();
1496 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1498 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1502 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1503 List<String> interfaceNames, WriteTransaction tx) {
1504 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1505 .withKey(new DpnInterfacesKey(dpId)).build();
1506 tx.put(LogicalDatastoreType.OPERATIONAL,
1507 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1508 WriteTransaction.CREATE_MISSING_PARENTS);
1509 return dpnInterface;
1513 * Delete elan dpn interface from operational DS.
1515 * @param elanInstanceName
1516 * the elan instance name
1520 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1521 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1522 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1523 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1524 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1525 if (dpnInterfaces.isPresent()) {
1526 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1530 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1531 WriteTransaction tx) {
1532 List<String> interfaceNames = new ArrayList<>();
1533 interfaceNames.add(interfaceName);
1534 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1535 .withKey(new DpnInterfacesKey(dpId)).build();
1536 tx.put(LogicalDatastoreType.OPERATIONAL,
1537 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1538 WriteTransaction.CREATE_MISSING_PARENTS);
1539 return dpnInterface;
1542 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1543 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1544 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1545 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1546 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1547 // Adding new Elan Interface Port to the operational DataStore without
1548 // Static-Mac Entries..
1549 if (!interfaceMacTables.isPresent()) {
1550 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1551 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1552 tx.put(LogicalDatastoreType.OPERATIONAL,
1553 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1554 WriteTransaction.CREATE_MISSING_PARENTS);
1558 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1559 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1560 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1561 LogicalDatastoreType.OPERATIONAL, elanInstance);
1562 // Adding new Elan Interface Port to the operational DataStore without
1563 // Static-Mac Entries..
1564 if (elanInterfaceLists.isPresent()) {
1565 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1566 if (interfaceLists == null) {
1567 interfaceLists = new ArrayList<>();
1569 interfaceLists.add(interfaceName);
1570 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1571 .withKey(new ElanKey(elanInstanceName)).build();
1572 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1573 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1577 private boolean isOperational(InterfaceInfo interfaceInfo) {
1578 if (interfaceInfo == null) {
1581 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1584 @SuppressWarnings("checkstyle:IllegalCatch")
1585 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1586 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1587 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1588 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1589 if (dpnInterfaceLists == null) {
1592 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1593 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1595 String elanName = elanDpns.getElanInstanceName();
1596 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1597 if (elanInfo == null) {
1598 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1599 + "skipping this ELAN for tunnel handling", elanName);
1602 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1603 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1606 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1607 if (dpnInterfaces == null) {
1610 DpnInterfaces dstDpnIf = null;
1611 for (DpnInterfaces dpnIf : dpnInterfaces) {
1612 BigInteger dpnIfDpId = dpnIf.getDpId();
1613 if (dpnIfDpId.equals(srcDpId)) {
1615 } else if (dpnIfDpId.equals(dstDpId)) {
1621 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1622 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1623 jobCoordinator.enqueueJob(elanName, () -> {
1624 // update Remote BC Group
1625 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1627 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1628 } catch (RuntimeException e) {
1629 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1631 Set<String> interfaceLists = new HashSet<>();
1632 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1633 for (String ifName : interfaceLists) {
1634 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1635 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1636 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1637 if (isOperational(interfaceInfo)) {
1638 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1640 return Collections.emptyList();
1641 }, ElanConstants.JOB_MAX_RETRIES);
1643 return Collections.emptyList();
1644 }, ElanConstants.JOB_MAX_RETRIES);
1651 * Handle external tunnel state event.
1653 * @param externalTunnel
1654 * the external tunnel
1658 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1659 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1662 // dpId/externalNodeId will be available either in source or destination
1663 // based on the tunnel end point
1664 BigInteger dpId = null;
1665 NodeId externalNodeId = null;
1666 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1667 dpId = new BigInteger(externalTunnel.getSourceDevice());
1668 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1669 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1670 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1671 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1673 if (dpId == null || externalNodeId == null) {
1674 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1678 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1679 if (dpnInterfaceLists == null) {
1682 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1683 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1684 String elanName = elanDpns.getElanInstanceName();
1685 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1687 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1688 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1689 || dpnInterfaces.getInterfaces().isEmpty()) {
1692 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1694 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1695 // install L2gwDevices local macs in dpn.
1696 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1697 // Install dpn macs on external device
1698 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1701 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1705 * Installs dpn macs in external device. first it checks if the physical
1706 * locator towards this dpn tep is present or not if the physical locator is
1707 * present go ahead and add the ucast macs otherwise update the mcast mac
1708 * entry to include this dpn tep ip and schedule the job to put ucast macs
1709 * once the physical locator is programmed in device
1713 * @param lstElanInterfaceNames
1714 * the lst Elan interface names
1717 * @param externalNodeId
1718 * the external node id
1720 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1721 NodeId externalNodeId) {
1722 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1723 externalNodeId.getValue());
1724 if (elanL2GwDevice == null) {
1725 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1728 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1729 if (dpnTepIp == null) {
1730 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1735 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1736 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1737 LogicalDatastoreType.OPERATIONAL);
1738 boolean phyLocAlreadyExists =
1739 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1741 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1742 phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
1743 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1745 if (phyLocAlreadyExists) {
1746 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1749 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1750 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1754 * Validate external tunnel state event.
1756 * @param externalTunnel
1757 * the external tunnel
1760 * @return true, if successful
1762 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1763 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1764 String srcDevice = externalTunnel.getDestinationDevice();
1765 String destDevice = externalTunnel.getSourceDevice();
1766 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1767 LogicalDatastoreType.CONFIGURATION);
1768 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1769 otherEndPointExtTunnel);
1770 if (otherEndPointExtTunnel != null) {
1771 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1772 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1773 if (otherEndPointInterfaceOperational) {
1776 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1777 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1784 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1785 List<MatchInfo> mkMatches = new ArrayList<>();
1786 // Matching metadata
1788 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1789 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1794 protected ElanInterfaceManager getDataTreeChangeListener() {
1798 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1800 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1801 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1803 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1804 } catch (InterruptedException e) {
1805 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);