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.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Lists;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.Objects;
23 import java.util.Queue;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentLinkedQueue;
27 import javax.annotation.PostConstruct;
28 import javax.inject.Inject;
29 import javax.inject.Singleton;
30 import org.apache.commons.lang3.StringUtils;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
33 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
36 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
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.srm.RecoverableListener;
62 import org.opendaylight.genius.srm.ServiceRecoveryRegistry;
63 import org.opendaylight.genius.utils.ServiceIndex;
64 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
65 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
66 import org.opendaylight.netvirt.elan.ElanException;
67 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
68 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
69 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
70 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
71 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
72 import org.opendaylight.netvirt.elan.utils.ElanConstants;
73 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
74 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
75 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
76 import org.opendaylight.netvirt.elan.utils.ElanUtils;
77 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
78 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
79 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
80 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
81 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
82 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
83 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
84 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
125 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
126 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
127 import org.slf4j.Logger;
128 import org.slf4j.LoggerFactory;
131 * Class in charge of handling creations, modifications and removals of
134 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
137 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
138 implements RecoverableListener {
139 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
140 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
141 private static final boolean SH_FLAG_SET = true;
142 private static final boolean SH_FLAG_UNSET = false;
144 private final DataBroker broker;
145 private final ManagedNewTransactionRunner txRunner;
146 private final IMdsalApiManager mdsalManager;
147 private final IInterfaceManager interfaceManager;
148 private final IdManagerService idManager;
149 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
150 private final INeutronVpnManager neutronVpnManager;
151 private final ElanItmUtils elanItmUtils;
152 private final ElanEtreeUtils elanEtreeUtils;
153 private final ElanL2GatewayUtils elanL2GatewayUtils;
154 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
155 private final ElanUtils elanUtils;
156 private final JobCoordinator jobCoordinator;
157 private final ElanInstanceCache elanInstanceCache;
158 private final ElanInterfaceCache elanInterfaceCache;
160 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
161 unProcessedElanInterfaces = new ConcurrentHashMap<>();
164 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
165 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
166 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
167 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
168 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
169 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
170 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
171 final ElanInstanceCache elanInstanceCache,
172 final ElanInterfaceCache elanInterfaceCache,
173 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
174 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
175 super(ElanInterface.class, ElanInterfaceManager.class);
176 this.broker = dataBroker;
177 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
178 this.idManager = managerService;
179 this.mdsalManager = mdsalApiManager;
180 this.interfaceManager = interfaceManager;
181 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
182 this.neutronVpnManager = neutronVpnManager;
183 this.elanItmUtils = elanItmUtils;
184 this.elanEtreeUtils = elanEtreeUtils;
185 this.elanL2GatewayUtils = elanL2GatewayUtils;
186 this.elanUtils = elanUtils;
187 this.jobCoordinator = jobCoordinator;
188 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
189 this.elanInstanceCache = elanInstanceCache;
190 this.elanInterfaceCache = elanInterfaceCache;
191 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
201 public void registerListener() {
202 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
206 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
207 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
211 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
212 String interfaceName = del.getName();
213 ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull();
215 * Handling in case the elan instance is deleted.If the Elan instance is
216 * deleted, there is no need to explicitly delete the elan interfaces
218 if (elanInfo == null) {
221 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
222 if (interfaceInfo == null && elanInfo.isExternal()) {
223 // In deleting external network, the underlying ietf Inteface might have been removed
224 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
225 // from Operational DS instead
226 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
228 String elanInstanceName = elanInfo.getElanInstanceName();
229 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
230 interfaceName, interfaceInfo, this);
231 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
234 @SuppressWarnings("checkstyle:ForbiddenMethod")
235 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
236 InterfaceInfo interfaceInfo) {
237 String elanName = elanInfo.getElanInstanceName();
238 boolean isLastElanInterface = false;
239 boolean isLastInterfaceOnDpn = false;
240 BigInteger dpId = null;
241 long elanTag = elanInfo.getElanTag();
242 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
243 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
244 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
245 if (elanState == null) {
246 interfaceTx.cancel();
247 return Collections.emptyList();
249 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
250 List<String> elanInterfaces = elanState.getElanInterfaces();
251 if (elanInterfaces.isEmpty()) {
252 isLastElanInterface = true;
254 if (interfaceInfo != null) {
255 dpId = interfaceInfo.getDpId();
256 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
257 interfaceName, elanTag, interfaceTx);
259 * If there are not elan ports, remove the unknown dmac, terminating
260 * service table flows, remote/local bc group
262 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
263 || dpnInterfaces.getInterfaces().isEmpty()) {
264 // No more Elan Interfaces in this DPN
265 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
266 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
267 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
269 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
270 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
271 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
272 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
273 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
274 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
275 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
276 elanUtils.removeTerminatingServiceAction(dpId,
277 elanUtils.getVxlanSegmentationId(elanInfo).intValue());
279 unsetExternalTunnelTable(dpId, elanInfo);
281 isLastInterfaceOnDpn = true;
283 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
287 List<ListenableFuture<Void>> futures = new ArrayList<>();
288 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
289 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
291 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
292 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
294 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
295 interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
296 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
297 ElanConstants.JOB_MAX_RETRIES);
302 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
303 WriteTransaction deleteFlowGroupTx) {
304 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
305 if (etreeLeafTag != null) {
306 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
307 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
311 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
312 WriteTransaction deleteFlowGroupTx) {
313 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
314 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
317 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
318 WriteTransaction deleteFlowGroupTx) {
319 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
320 if (etreeInstance != null) {
321 BigInteger dpnId = interfaceInfo.getDpId();
322 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
323 List<Bucket> listBuckets = new ArrayList<>();
325 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
326 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
327 MDSALUtil.buildBucketLists(listBuckets));
328 LOG.trace("deleted the localBroadCast Group:{}", group);
329 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
333 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
334 WriteTransaction deleteFlowGroupTx) {
335 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
336 if (etreeInstance != null) {
337 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
340 List<Bucket> listBuckets = new ArrayList<>();
341 List<Action> listAction = new ArrayList<>();
342 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
343 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
344 MDSALUtil.WATCH_GROUP));
346 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
347 BigInteger dpnId = interfaceInfo.getDpId();
348 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
349 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
350 MDSALUtil.buildBucketLists(listBuckets));
351 LOG.trace("deleting the remoteBroadCast group:{}", group);
352 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
356 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
357 String elanName = elanInfo.getElanInstanceName();
358 Elan elanState = ElanUtils.getElanByName(broker, elanName);
359 if (elanState == null) {
362 List<String> elanInterfaces = elanState.getElanInterfaces();
363 boolean isRemoved = elanInterfaces.remove(interfaceName);
368 if (elanInterfaces.isEmpty()) {
369 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
370 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
371 tx.delete(LogicalDatastoreType.OPERATIONAL,
372 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
374 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
375 .withKey(new ElanKey(elanName)).build();
376 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
382 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
383 // removing the ElanInterface from the config data_store if interface is
384 // not present in Interface config DS
385 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
386 && elanInterfaceCache.get(interfaceName).isPresent()) {
387 tx.delete(LogicalDatastoreType.CONFIGURATION,
388 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
392 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
393 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
394 String elanName = elanInfo.getElanInstanceName();
395 List<ListenableFuture<Void>> futures = new ArrayList<>();
396 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(flowTx -> {
397 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> {
398 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
399 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
400 Optional<ElanInterfaceMac> existingElanInterfaceMac =
401 interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet();
402 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
403 if (interfaceInfo != null) {
404 if (existingElanInterfaceMac.isPresent()) {
405 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
406 if (existingMacEntries != null) {
407 List<PhysAddress> macAddresses = new ArrayList<>();
408 for (MacEntry macEntry : existingMacEntries) {
409 PhysAddress macAddress = macEntry.getMacAddress();
410 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
411 macAddress.getValue(), interfaceName);
412 Optional<MacEntry> macEntryOptional =
413 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
414 if (!isLastElanInterface && macEntryOptional.isPresent()) {
415 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
416 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
418 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
419 macAddresses.add(macAddress);
422 // Removing all those MACs from External Devices belonging
424 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
425 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
429 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
430 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
431 } else if (existingElanInterfaceMac.isPresent()) {
432 // Interface does not exist in ConfigDS, so lets remove everything
433 // about that interface related to Elan
434 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
435 if (macEntries != null) {
436 for (MacEntry macEntry : macEntries) {
437 PhysAddress macAddress = macEntry.getMacAddress();
438 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
439 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
440 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
445 if (existingElanInterfaceMac.isPresent()) {
446 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
448 unbindService(interfaceName, interfaceTx);
449 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
455 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
456 String interfaceName, long elanTag,
457 WriteTransaction tx) {
458 synchronized (elanName.intern()) {
460 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
461 if (dpnInterfaces != null) {
462 List<String> interfaceLists = dpnInterfaces.getInterfaces();
463 if (interfaceLists != null) {
464 interfaceLists.remove(interfaceName);
467 if (interfaceLists == null || interfaceLists.isEmpty()) {
468 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
469 deleteElanDpnInterface(elanName, dpId, tx);
471 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
474 return dpnInterfaces;
478 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
479 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
480 for (DpnInterfaces dpnInterface : dpnInterfaces) {
481 BigInteger currentDpId = dpnInterface.getDpId();
482 if (!currentDpId.equals(dpId)) {
483 for (String elanInterface : dpnInterface.getInterfaces()) {
484 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
485 if (macs == null || macs.getMacEntry() == null) {
488 for (MacEntry mac : macs.getMacEntry()) {
489 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
490 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
497 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
498 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
499 if (etreeLeafTag != null) {
500 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
504 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
507 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
508 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
509 mac.getMacAddress().getValue(), elanTag)));
513 * Possible Scenarios for update
514 * a. if orig={1,2,3,4} and updated=null or updated={}
515 then all {1,2,3,4} should be removed
517 b. if orig=null or orig={} and updated ={1,2,3,4}
518 then all {1,2,3,4} should be added
520 c. if orig = {1,2,3,4} updated={2,3,4}
521 then 1 should be removed
523 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
524 then we should just add 5
526 e. if orig = {1,2,3,4} updated={2,3,4,5}
527 then 1 should be removed , 5 should be added
529 @SuppressWarnings("checkstyle:ForbiddenMethod")
531 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
532 // updating the static-Mac Entries for the existing elanInterface
533 String elanName = update.getElanInstanceName();
534 String interfaceName = update.getName();
536 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
537 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
538 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
539 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
541 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
542 deletedEntry.getMacAddress()));
544 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
545 * Hence add the macentries for the same.*/
546 for (StaticMacEntries staticMacEntry : updatedEntries) {
547 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
548 staticMacEntry.getMacAddress());
549 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
550 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
551 WriteTransaction tx = broker.newWriteOnlyTransaction();
552 if (existingMacEntry.isPresent()) {
553 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
554 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
557 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
558 elanName, interfaceName, staticMacEntry, tx);
560 ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(tx), LOG,
561 "Error in update: identifier={}, original={}, update={}", identifier, original, update);
566 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
567 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
568 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
569 String interfaceName = elanInterfaceAdded.getName();
570 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
571 if (interfaceInfo == null) {
572 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
575 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
577 if (elanInstance == null) {
578 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
579 .setDescription(elanInterfaceAdded.getDescription()).build();
580 // Add the ElanInstance in the Configuration data-store
581 List<String> elanInterfaces = new ArrayList<>();
582 elanInterfaces.add(interfaceName);
583 elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
586 Long elanTag = elanInstance.getElanTag();
587 // If elan tag is not updated, then put the elan interface into
588 // unprocessed entry map and entry. Let entries
589 // in this map get processed during ELAN update DCN.
590 if (elanTag == null) {
591 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
592 if (elanInterfaces == null) {
593 elanInterfaces = new ConcurrentLinkedQueue<>();
595 elanInterfaces.add(elanInterfaceAdded);
596 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
599 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
600 interfaceInfo, elanInstance, this);
601 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
602 }), LOG, "Error procedding added ELAN interface");
605 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
606 List<ListenableFuture<Void>> futures = new ArrayList<>();
607 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
608 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
611 for (ElanInterface elanInterface : elanInterfaces) {
612 String interfaceName = elanInterface.getName();
613 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
614 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
619 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
620 WriteTransaction writeFlowGroupTx) throws ElanException {
621 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
622 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
623 List<DpnInterfaces> dpnInterfaceLists = null;
624 if (elanDpnInterfacesList != null) {
625 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
627 if (dpnInterfaceLists == null) {
628 dpnInterfaceLists = new ArrayList<>();
630 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
631 BigInteger dstDpId = interfaceInfo.getDpId();
632 if (dpnInterfaces.getDpId().equals(dstDpId)) {
635 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
636 for (String remoteIf : remoteElanInterfaces) {
637 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
638 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
639 if (elanIfMac == null || remoteInterface == null) {
642 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
643 if (remoteMacEntries != null) {
644 for (MacEntry macEntry : remoteMacEntries) {
645 String macAddress = macEntry.getMacAddress().getValue();
646 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
647 dstDpId, elanInstance.getElanInstanceName());
648 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
649 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
650 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
657 @SuppressWarnings("checkstyle:ForbiddenMethod")
658 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
659 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
660 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
661 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
662 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
664 String interfaceName = elanInterface.getName();
665 String elanInstanceName = elanInterface.getElanInstanceName();
667 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
668 WriteTransaction tx = broker.newWriteOnlyTransaction();
669 if (elanInfo == null) {
670 List<String> elanInterfaces = new ArrayList<>();
671 elanInterfaces.add(interfaceName);
672 ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
674 createElanStateList(elanInstanceName, interfaceName, tx);
676 boolean isFirstInterfaceInDpn = false;
677 // Specific actions to the DPN where the ElanInterface has been added,
678 // for example, programming the
679 // External tunnel table if needed or adding the ElanInterface to the
680 // DpnInterfaces in the operational DS.
681 BigInteger dpId = interfaceInfo.getDpId();
682 DpnInterfaces dpnInterfaces = null;
683 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
684 synchronized (elanInstanceName.intern()) {
685 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
686 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
687 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
688 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
689 if (ElanUtils.isVlan(elanInstance)) {
690 isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
691 elanInstanceName, existingElanDpnInterfaces);
693 isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
695 if (isFirstInterfaceInDpn) {
696 // ELAN's 1st ElanInterface added to this DPN
697 if (!existingElanDpnInterfaces.isPresent()) {
698 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
700 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
701 elanInterfaces.add(interfaceName);
702 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
705 // The 1st ElanInterface in a DPN must program the Ext Tunnel
706 // table, but only if Elan has VNI
707 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
708 setExternalTunnelTable(dpId, elanInstance);
710 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
712 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
713 elanInterfaces.add(interfaceName);
714 if (elanInterfaces.size() == 1) { // 1st dpn interface
715 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
717 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
722 // add code to install Local/Remote BC group, unknow DMAC entry,
723 // terminating service table flow entry
724 // call bindservice of interfacemanager to create ingress table flow
726 // Add interface to the ElanInterfaceForwardingEntires Container
727 createElanInterfaceTablesList(interfaceName, tx);
728 List<ListenableFuture<Void>> futures = new ArrayList<>();
729 futures.add(ElanUtils.waitForTransactionToComplete(tx));
730 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
732 // add the vlan provider interface to remote BC group for the elan
733 // for internal vlan networks
734 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
735 if (interfaceManager.isExternalInterface(interfaceName)) {
736 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
737 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
741 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
742 //update the remote-DPNs remoteBC group entry with Tunnels
743 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
744 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
747 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
748 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
749 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
750 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
754 @SuppressWarnings("checkstyle:ForbiddenMethod")
755 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
756 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
757 throws ElanException {
758 String elanInstanceName = elanInstance.getElanInstanceName();
759 String interfaceName = elanInterface.getName();
760 WriteTransaction tx = broker.newWriteOnlyTransaction();
761 BigInteger dpId = interfaceInfo.getDpId();
762 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
763 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
764 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
766 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
767 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
769 boolean isInterfaceOperational = isOperational(interfaceInfo);
770 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
771 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
772 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
773 staticMacEntry.getMacAddress());
774 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
775 LogicalDatastoreType.OPERATIONAL, macId);
776 if (existingMacEntry.isPresent()) {
777 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
778 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
779 existingMacEntry.get(), tx);
781 elanForwardingEntriesHandler
782 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
785 if (isInterfaceOperational) {
786 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
788 String macAddress = staticMacEntry.getMacAddress().getValue();
789 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
790 macAddress, elanInstanceName, interfaceName);
791 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
792 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
796 if (isInterfaceOperational) {
797 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
799 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
800 staticMacAddresses.add(staticMacEntry.getMacAddress());
802 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
806 List<ListenableFuture<Void>> futures = new ArrayList<>();
807 futures.add(ElanUtils.waitForTransactionToComplete(tx));
808 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
809 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
810 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
812 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
813 if (neutronPort != null) {
814 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
816 } catch (IllegalArgumentException ex) {
817 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
823 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
824 PhysAddress physAddress) {
825 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
826 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
827 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
828 LogicalDatastoreType.OPERATIONAL, macId);
830 if (!existingMacEntry.isPresent()) {
834 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
835 .withKey(new MacEntryKey(physAddress)).build();
836 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
837 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
840 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
841 Optional<DpnInterfaces> existingElanDpnInterfaces) {
842 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
843 if (!existingElanDpnInterfaces.isPresent()) {
846 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
849 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
850 int dummyInterfaceCount = 0;
851 if (dpnInterfaces.getInterfaces().contains(routerPortUuid)) {
852 dummyInterfaceCount++;
854 if (dpnInterfaces.getInterfaces().contains(elanInstanceName)) {
855 dummyInterfaceCount++;
857 if (dpnInterfaces.getInterfaces().size() - dummyInterfaceCount == 0) {
863 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
864 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
865 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
868 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
869 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
870 WriteTransaction writeFlowGroupTx) throws ElanException {
871 if (!isOperational(interfaceInfo)) {
874 BigInteger dpId = interfaceInfo.getDpId();
875 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
876 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
878 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
879 if (isFirstInterfaceInDpn) {
880 // Terminating Service , UnknownDMAC Table.
881 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
882 // for ELAN Instance is VxLAN
883 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
884 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
886 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
888 * Install remote DMAC flow. This is required since this DPN is
889 * added later to the elan instance and remote DMACs of other
890 * interfaces in this elan instance are not present in the current
893 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
894 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
895 elanInstance.getElanInstanceName());
896 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
899 // bind the Elan service to the Interface
900 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
903 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
904 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
905 if (!isOperational(interfaceInfo)) {
908 // LocalBroadcast Group creation with elan-Interfaces
909 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
910 if (isFirstInterfaceInDpn) {
911 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
912 BigInteger dpId = interfaceInfo.getDpId();
913 // RemoteBroadcast Group creation
915 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
916 } catch (InterruptedException e1) {
917 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
919 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
921 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
922 } catch (InterruptedException e1) {
923 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
928 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
929 WriteTransaction writeFlowGroupTx) {
930 int ifTag = interfaceInfo.getInterfaceTag();
931 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
932 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
933 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
934 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
935 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
937 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
939 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
940 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
941 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
942 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
944 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
947 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
948 WriteTransaction deleteFlowGroupTx) {
949 int ifTag = interfaceInfo.getInterfaceTag();
950 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
951 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
953 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
955 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
956 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
957 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
958 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
960 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
963 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
964 InterfaceInfo interfaceInfo, long elanTag) {
965 return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
966 bucketKeyStart, elanTag);
969 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
970 int elanTag = elanInfo.getElanTag().intValue();
971 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
972 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
973 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
974 if (etreeInstance != null) {
975 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
976 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
977 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
981 @SuppressWarnings("checkstyle:IllegalCatch")
982 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
984 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
985 if (elanDpns != null) {
986 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
987 for (DpnInterfaces dpnInterface : dpnInterfaces) {
988 List<Bucket> remoteListBucketInfo = new ArrayList<>();
989 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
990 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
991 List<Action> listAction = new ArrayList<>();
993 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
994 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
995 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
997 for (DpnInterfaces otherFes : dpnInterfaces) {
998 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
999 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1000 && !otherFes.getInterfaces().isEmpty()) {
1002 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1003 dpnInterface.getDpId(), otherFes.getDpId(),
1004 elanUtils.isOpenstackVniSemanticsEnforced()
1005 ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1006 if (!remoteListActionInfo.isEmpty()) {
1007 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1008 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1011 } catch (Exception ex) {
1012 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1013 + "Logical Group Interface not found between source Dpn - {}, "
1014 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1019 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1020 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1021 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1023 if (remoteListBucketInfo.isEmpty()) {
1024 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1027 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1028 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1029 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1030 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
1034 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1035 } catch (InterruptedException e1) {
1036 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1042 * Returns the bucket info with the given interface as the only bucket.
1044 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
1045 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
1046 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
1049 private List<MatchInfo> buildMatchesForVni(Long vni) {
1050 List<MatchInfo> mkMatches = new ArrayList<>();
1051 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1052 mkMatches.add(match);
1056 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1057 List<InstructionInfo> mkInstructions = new ArrayList<>();
1058 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1059 return mkInstructions;
1062 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1063 List<MatchInfo> mkMatches = new ArrayList<>();
1064 // Matching metadata
1065 mkMatches.add(new MatchMetadata(
1066 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1071 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1072 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1075 * elanTag to be written in metadata when flow is selected
1076 * @return the instructions ready to be installed in a flow
1078 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1079 List<InstructionInfo> mkInstructions = new ArrayList<>();
1080 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1081 .getElanMetadataMask()));
1082 /* applicable for EXTERNAL_TUNNEL_TABLE only
1083 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1085 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1086 return mkInstructions;
1089 // Install DMAC entry on dst DPN
1090 @SuppressWarnings("checkstyle:ForbiddenMethod")
1091 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1092 BigInteger dstDpId) throws ElanException {
1093 String interfaceName = interfaceInfo.getInterfaceName();
1094 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1095 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1096 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1097 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1098 for (MacEntry macEntry : macEntries) {
1099 String macAddress = macEntry.getMacAddress().getValue();
1100 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1101 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1102 interfaceInfo.getDpId())) {
1103 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress);
1104 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1108 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1110 return Collections.emptyList();
1113 private void createDropBucket(List<Bucket> listBucket) {
1114 List<Action> actionsInfos = new ArrayList<>();
1115 actionsInfos.add(new ActionDrop().buildAction());
1116 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1117 MDSALUtil.WATCH_GROUP);
1118 listBucket.add(dropBucket);
1121 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1122 InterfaceInfo interfaceInfo) {
1123 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1124 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1127 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1128 InterfaceInfo interfaceInfo) {
1129 List<Bucket> listBucket = new ArrayList<>();
1131 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1133 List<String> interfaces = new ArrayList<>();
1134 if (newDpnInterface != null) {
1135 interfaces = newDpnInterface.getInterfaces();
1137 for (String ifName : interfaces) {
1138 // In case if there is a InterfacePort in the cache which is not in
1139 // operational state, skip processing it
1140 InterfaceInfo ifInfo = interfaceManager
1141 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1142 if (!isOperational(ifInfo)) {
1146 if (!interfaceManager.isExternalInterface(ifName)) {
1147 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1148 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1153 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1154 MDSALUtil.buildBucketLists(listBucket));
1155 LOG.trace("installing the localBroadCast Group:{}", group);
1156 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1159 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1160 InterfaceInfo interfaceInfo) {
1161 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1162 if (etreeInstance != null) {
1163 List<Bucket> listBucket = new ArrayList<>();
1166 List<String> interfaces = new ArrayList<>();
1167 if (newDpnInterface != null) {
1168 interfaces = newDpnInterface.getInterfaces();
1170 for (String ifName : interfaces) {
1171 // In case if there is a InterfacePort in the cache which is not
1173 // operational state, skip processing it
1174 InterfaceInfo ifInfo = interfaceManager
1175 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1176 if (!isOperational(ifInfo)) {
1180 if (!interfaceManager.isExternalInterface(ifName)) {
1181 // only add root interfaces
1182 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1186 if (listBucket.isEmpty()) { // No Buckets
1187 createDropBucket(listBucket);
1190 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1191 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1192 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1193 MDSALUtil.buildBucketLists(listBucket));
1194 LOG.trace("installing the localBroadCast Group:{}", group);
1195 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1199 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1200 InterfaceInfo ifInfo) {
1201 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1202 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1203 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1204 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1210 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1211 WriteTransaction deleteFlowGroupTx) {
1212 BigInteger dpnId = interfaceInfo.getDpId();
1213 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1214 List<Bucket> listBuckets = new ArrayList<>();
1216 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1217 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1219 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1220 MDSALUtil.buildBucketLists(listBuckets));
1221 LOG.trace("deleted the localBroadCast Group:{}", group);
1222 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1225 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1226 WriteTransaction deleteFlowGroupTx) {
1229 Long elanTag = elanInfo.getElanTag();
1230 List<Bucket> listBuckets = new ArrayList<>();
1231 List<Action> listAction = new ArrayList<>();
1232 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1233 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1234 MDSALUtil.WATCH_GROUP));
1236 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1237 BigInteger dpnId = interfaceInfo.getDpId();
1238 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1239 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1240 MDSALUtil.buildBucketLists(listBuckets));
1241 LOG.trace("deleting the remoteBroadCast group:{}", group);
1242 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1246 * Installs a flow in the External Tunnel table consisting in translating
1247 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1248 * elanTag that will be used later in the ELANs pipeline.
1255 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1256 long elanTag = elanInfo.getElanTag();
1257 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1258 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1259 elanInfo.getElanInstanceName(), // flowName
1262 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1263 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1264 getInstructionsIntOrExtTunnelTable(elanTag));
1266 mdsalManager.installFlow(flowEntity);
1270 * Removes, from External Tunnel table, the flow that translates from VNI to
1271 * elanTag. Important: ensure this method is only called whenever there is
1272 * no other ElanInterface in the specified DPN
1275 * DPN whose Ext Tunnel table is going to be modified
1277 * holds the elanTag needed for selecting the flow to be removed
1279 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1280 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1281 // last ElanInstance plus
1282 // adding a new one does (almost at the same time) are executed in that
1285 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1286 FlowEntity flowEntity = new FlowEntityBuilder()
1288 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1291 mdsalManager.removeFlow(flowEntity);
1294 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1295 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1296 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1299 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1300 WriteTransaction writeFlowGroupTx) {
1301 List<? extends MatchInfoBase> listMatchInfoBase;
1302 List<InstructionInfo> instructionInfos;
1304 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1305 serviceId = elanTag;
1306 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1307 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1309 serviceId = elanUtils.getVxlanSegmentationId(elanInfo);
1310 listMatchInfoBase = buildMatchesForVni(serviceId);
1311 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1313 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1314 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1315 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1317 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1320 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1321 WriteTransaction writeFlowGroupTx) {
1322 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1323 if (etreeInstance != null) {
1324 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1328 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1329 long elanTag = elanInfo.getElanTag();
1330 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1331 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1332 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1335 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1336 WriteTransaction writeFlowGroupTx) {
1337 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1338 if (etreeLeafTag != null) {
1339 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1340 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1341 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1345 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1346 WriteTransaction writeFlowGroupTx) {
1347 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1348 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1349 5, elanInfo.getElanInstanceName(), 0, 0,
1350 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1351 getMatchesForElanTag(elanTag, /* SH flag */false),
1352 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1354 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1357 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1358 WriteTransaction writeFlowGroupTx) {
1359 // only if ELAN can connect to external network, perform the following
1361 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1362 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1363 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1364 5, elanInfo.getElanInstanceName(), 0, 0,
1365 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1366 getMatchesForElanTag(elanTag, /* SH flag */true),
1367 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1368 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1373 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1375 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1376 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1377 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1379 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1380 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1381 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1383 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1387 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1388 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1391 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1392 if (isStandardElanService(elanInterface)) {
1393 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1394 elanInterface.getName(), lportTag, tx);
1395 } else { // Etree service
1396 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1400 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1401 WriteTransaction tx) {
1402 int instructionKey = 0;
1403 List<Instruction> instructions = new ArrayList<>();
1404 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1405 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1407 List<Action> actions = new ArrayList<>();
1408 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1409 lportTag).buildAction());
1410 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1411 elanTag).buildAction());
1412 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1414 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1417 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1418 BoundServices serviceInfo = ElanUtils.getBoundServices(
1419 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1420 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1421 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1422 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1424 if (!existingElanService.isPresent()) {
1425 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1426 WriteTransaction.CREATE_MISSING_PARENTS);
1430 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1431 WriteTransaction tx) {
1432 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1433 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1436 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1437 if (etreeInstance == null) {
1438 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1439 elanInterface.getName(), elanInfo.getElanInstanceName());
1441 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1442 elanInterface.getName(), lportTag, tx);
1447 private boolean isStandardElanService(ElanInterface elanInterface) {
1448 return elanInterface.augmentation(EtreeInterface.class) == null;
1451 protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
1452 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1453 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1454 if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
1455 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1459 private String getFlowRef(long tableId, long elanTag) {
1460 return String.valueOf(tableId) + elanTag;
1463 private String getFlowRef(long tableId, long elanTag, String flowName) {
1464 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1465 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1468 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1469 return String.valueOf(tableId) + elanTag + shFlag;
1472 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1473 List<Action> listAction = new ArrayList<>();
1476 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1478 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1482 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1483 List<String> interfaceNames, WriteTransaction tx) {
1484 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1485 .withKey(new DpnInterfacesKey(dpId)).build();
1486 tx.put(LogicalDatastoreType.OPERATIONAL,
1487 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1488 WriteTransaction.CREATE_MISSING_PARENTS);
1489 return dpnInterface;
1493 * Delete elan dpn interface from operational DS.
1495 * @param elanInstanceName
1496 * the elan instance name
1500 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1501 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1502 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1503 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1504 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1505 if (dpnInterfaces.isPresent()) {
1506 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1510 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1511 WriteTransaction tx) {
1512 List<String> interfaceNames = new ArrayList<>();
1513 interfaceNames.add(interfaceName);
1514 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1515 .withKey(new DpnInterfacesKey(dpId)).build();
1516 tx.put(LogicalDatastoreType.OPERATIONAL,
1517 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1518 WriteTransaction.CREATE_MISSING_PARENTS);
1519 return dpnInterface;
1522 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1523 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1524 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1525 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1526 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1527 // Adding new Elan Interface Port to the operational DataStore without
1528 // Static-Mac Entries..
1529 if (!interfaceMacTables.isPresent()) {
1530 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1531 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1532 tx.put(LogicalDatastoreType.OPERATIONAL,
1533 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1534 WriteTransaction.CREATE_MISSING_PARENTS);
1538 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1539 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1540 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1541 LogicalDatastoreType.OPERATIONAL, elanInstance);
1542 // Adding new Elan Interface Port to the operational DataStore without
1543 // Static-Mac Entries..
1544 if (elanInterfaceLists.isPresent()) {
1545 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1546 if (interfaceLists == null) {
1547 interfaceLists = new ArrayList<>();
1549 interfaceLists.add(interfaceName);
1550 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1551 .withKey(new ElanKey(elanInstanceName)).build();
1552 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1553 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1557 private boolean isOperational(InterfaceInfo interfaceInfo) {
1558 if (interfaceInfo == null) {
1561 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1564 @SuppressWarnings("checkstyle:IllegalCatch")
1565 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1566 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1567 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1568 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1569 if (dpnInterfaceLists == null) {
1572 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1573 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1575 String elanName = elanDpns.getElanInstanceName();
1576 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1577 if (elanInfo == null) {
1578 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1579 + "skipping this ELAN for tunnel handling", elanName);
1582 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1583 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1586 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1587 if (dpnInterfaces == null) {
1590 DpnInterfaces dstDpnIf = null;
1591 for (DpnInterfaces dpnIf : dpnInterfaces) {
1592 BigInteger dpnIfDpId = dpnIf.getDpId();
1593 if (dpnIfDpId.equals(srcDpId)) {
1595 } else if (dpnIfDpId.equals(dstDpId)) {
1601 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1602 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1603 jobCoordinator.enqueueJob(elanName, () -> {
1604 // update Remote BC Group
1605 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1607 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1608 } catch (RuntimeException e) {
1609 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1611 Set<String> interfaceLists = new HashSet<>();
1612 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1613 for (String ifName : interfaceLists) {
1614 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1615 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1616 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1617 if (isOperational(interfaceInfo)) {
1618 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1620 return Collections.emptyList();
1621 }, ElanConstants.JOB_MAX_RETRIES);
1623 return Collections.emptyList();
1624 }, ElanConstants.JOB_MAX_RETRIES);
1631 * Handle external tunnel state event.
1633 * @param externalTunnel
1634 * the external tunnel
1637 * @throws ElanException in case of issues creating the flow objects
1639 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1640 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1643 // dpId/externalNodeId will be available either in source or destination
1644 // based on the tunnel end point
1645 BigInteger dpId = null;
1646 NodeId externalNodeId = null;
1647 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1648 dpId = new BigInteger(externalTunnel.getSourceDevice());
1649 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1650 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1651 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1652 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1654 if (dpId == null || externalNodeId == null) {
1655 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1659 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1660 if (dpnInterfaceLists == null) {
1663 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1664 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1665 String elanName = elanDpns.getElanInstanceName();
1666 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1668 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1669 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1670 || dpnInterfaces.getInterfaces().isEmpty()) {
1673 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1675 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1676 // install L2gwDevices local macs in dpn.
1677 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1678 // Install dpn macs on external device
1679 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1682 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1686 * Installs dpn macs in external device. first it checks if the physical
1687 * locator towards this dpn tep is present or not if the physical locator is
1688 * present go ahead and add the ucast macs otherwise update the mcast mac
1689 * entry to include this dpn tep ip and schedule the job to put ucast macs
1690 * once the physical locator is programmed in device
1694 * @param lstElanInterfaceNames
1695 * the lst Elan interface names
1698 * @param externalNodeId
1699 * the external node id
1701 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1702 NodeId externalNodeId) {
1703 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1704 externalNodeId.getValue());
1705 if (elanL2GwDevice == null) {
1706 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1709 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1710 if (dpnTepIp == null) {
1711 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1716 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1717 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1718 LogicalDatastoreType.OPERATIONAL);
1719 boolean phyLocAlreadyExists =
1720 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1722 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1723 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1724 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1726 if (phyLocAlreadyExists) {
1727 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1730 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1731 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1735 * Validate external tunnel state event.
1737 * @param externalTunnel
1738 * the external tunnel
1741 * @return true, if successful
1743 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1744 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1745 String srcDevice = externalTunnel.getDestinationDevice();
1746 String destDevice = externalTunnel.getSourceDevice();
1747 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1748 LogicalDatastoreType.CONFIGURATION);
1749 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1750 otherEndPointExtTunnel);
1751 if (otherEndPointExtTunnel != null) {
1752 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1753 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1754 if (otherEndPointInterfaceOperational) {
1757 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1758 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1765 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1766 List<MatchInfo> mkMatches = new ArrayList<>();
1767 // Matching metadata
1769 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1770 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1775 protected ElanInterfaceManager getDataTreeChangeListener() {
1779 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1781 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1782 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1784 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1785 } catch (InterruptedException e) {
1786 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);