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 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
459 if (dpnInterfaces != null) {
460 List<String> interfaceLists = dpnInterfaces.getInterfaces();
461 if (interfaceLists != null) {
462 interfaceLists.remove(interfaceName);
465 if (interfaceLists == null || interfaceLists.isEmpty()) {
466 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
467 deleteElanDpnInterface(elanName, dpId, tx);
469 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
472 return dpnInterfaces;
475 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
476 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
477 for (DpnInterfaces dpnInterface : dpnInterfaces) {
478 BigInteger currentDpId = dpnInterface.getDpId();
479 if (!currentDpId.equals(dpId)) {
480 for (String elanInterface : dpnInterface.getInterfaces()) {
481 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
482 if (macs == null || macs.getMacEntry() == null) {
485 for (MacEntry mac : macs.getMacEntry()) {
486 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
487 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
494 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
495 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
496 if (etreeLeafTag != null) {
497 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
501 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
504 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
505 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
506 mac.getMacAddress().getValue(), elanTag)));
510 * Possible Scenarios for update
511 * a. if orig={1,2,3,4} and updated=null or updated={}
512 then all {1,2,3,4} should be removed
514 b. if orig=null or orig={} and updated ={1,2,3,4}
515 then all {1,2,3,4} should be added
517 c. if orig = {1,2,3,4} updated={2,3,4}
518 then 1 should be removed
520 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
521 then we should just add 5
523 e. if orig = {1,2,3,4} updated={2,3,4,5}
524 then 1 should be removed , 5 should be added
526 @SuppressWarnings("checkstyle:ForbiddenMethod")
528 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
529 // updating the static-Mac Entries for the existing elanInterface
530 String elanName = update.getElanInstanceName();
531 String interfaceName = update.getName();
533 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
534 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
535 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
536 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
538 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
539 deletedEntry.getMacAddress()));
541 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
542 * Hence add the macentries for the same.*/
543 for (StaticMacEntries staticMacEntry : updatedEntries) {
544 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
545 staticMacEntry.getMacAddress());
546 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
547 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
548 WriteTransaction tx = broker.newWriteOnlyTransaction();
549 if (existingMacEntry.isPresent()) {
550 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
551 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
554 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
555 elanName, interfaceName, staticMacEntry, tx);
557 ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(tx), LOG,
558 "Error in update: identifier={}, original={}, update={}", identifier, original, update);
563 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
564 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
565 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
566 String interfaceName = elanInterfaceAdded.getName();
567 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
568 if (interfaceInfo == null) {
569 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
572 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
574 if (elanInstance == null) {
575 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
576 .setDescription(elanInterfaceAdded.getDescription()).build();
577 // Add the ElanInstance in the Configuration data-store
578 List<String> elanInterfaces = new ArrayList<>();
579 elanInterfaces.add(interfaceName);
580 elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
583 Long elanTag = elanInstance.getElanTag();
584 // If elan tag is not updated, then put the elan interface into
585 // unprocessed entry map and entry. Let entries
586 // in this map get processed during ELAN update DCN.
587 if (elanTag == null) {
588 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
589 if (elanInterfaces == null) {
590 elanInterfaces = new ConcurrentLinkedQueue<>();
592 elanInterfaces.add(elanInterfaceAdded);
593 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
596 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
597 interfaceInfo, elanInstance, this);
598 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
599 }), LOG, "Error procedding added ELAN interface");
602 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
603 List<ListenableFuture<Void>> futures = new ArrayList<>();
604 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
605 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
608 for (ElanInterface elanInterface : elanInterfaces) {
609 String interfaceName = elanInterface.getName();
610 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
611 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
616 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
617 WriteTransaction writeFlowGroupTx) throws ElanException {
618 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
619 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
620 List<DpnInterfaces> dpnInterfaceLists = null;
621 if (elanDpnInterfacesList != null) {
622 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
624 if (dpnInterfaceLists == null) {
625 dpnInterfaceLists = new ArrayList<>();
627 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
628 BigInteger dstDpId = interfaceInfo.getDpId();
629 if (dpnInterfaces.getDpId().equals(dstDpId)) {
632 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
633 for (String remoteIf : remoteElanInterfaces) {
634 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
635 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
636 if (elanIfMac == null || remoteInterface == null) {
639 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
640 if (remoteMacEntries != null) {
641 for (MacEntry macEntry : remoteMacEntries) {
642 String macAddress = macEntry.getMacAddress().getValue();
643 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
644 dstDpId, elanInstance.getElanInstanceName());
645 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
646 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
647 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
654 @SuppressWarnings("checkstyle:ForbiddenMethod")
655 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
656 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
657 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
658 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
659 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
661 String interfaceName = elanInterface.getName();
662 String elanInstanceName = elanInterface.getElanInstanceName();
664 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
665 WriteTransaction tx = broker.newWriteOnlyTransaction();
666 if (elanInfo == null) {
667 List<String> elanInterfaces = new ArrayList<>();
668 elanInterfaces.add(interfaceName);
669 ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
671 createElanStateList(elanInstanceName, interfaceName, tx);
673 boolean isFirstInterfaceInDpn = false;
674 // Specific actions to the DPN where the ElanInterface has been added,
675 // for example, programming the
676 // External tunnel table if needed or adding the ElanInterface to the
677 // DpnInterfaces in the operational DS.
678 BigInteger dpId = interfaceInfo.getDpId();
679 DpnInterfaces dpnInterfaces = null;
680 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
681 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
682 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
683 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
684 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
685 if (ElanUtils.isVlan(elanInstance)) {
686 isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
687 elanInstanceName, existingElanDpnInterfaces);
689 isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
691 if (isFirstInterfaceInDpn) {
692 // ELAN's 1st ElanInterface added to this DPN
693 if (!existingElanDpnInterfaces.isPresent()) {
694 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
696 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
697 elanInterfaces.add(interfaceName);
698 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
701 // The 1st ElanInterface in a DPN must program the Ext Tunnel
702 // table, but only if Elan has VNI
703 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
704 setExternalTunnelTable(dpId, elanInstance);
706 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
708 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
709 elanInterfaces.add(interfaceName);
710 if (elanInterfaces.size() == 1) { // 1st dpn interface
711 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
713 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
717 // add code to install Local/Remote BC group, unknow DMAC entry,
718 // terminating service table flow entry
719 // call bindservice of interfacemanager to create ingress table flow
721 // Add interface to the ElanInterfaceForwardingEntires Container
722 createElanInterfaceTablesList(interfaceName, tx);
723 List<ListenableFuture<Void>> futures = new ArrayList<>();
724 futures.add(ElanUtils.waitForTransactionToComplete(tx));
725 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
727 // add the vlan provider interface to remote BC group for the elan
728 // for internal vlan networks
729 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
730 if (interfaceManager.isExternalInterface(interfaceName)) {
731 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
732 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
736 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
737 //update the remote-DPNs remoteBC group entry with Tunnels
738 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
739 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
742 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
743 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
744 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
745 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
749 @SuppressWarnings("checkstyle:ForbiddenMethod")
750 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
751 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
752 throws ElanException {
753 String elanInstanceName = elanInstance.getElanInstanceName();
754 String interfaceName = elanInterface.getName();
755 WriteTransaction tx = broker.newWriteOnlyTransaction();
756 BigInteger dpId = interfaceInfo.getDpId();
757 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
758 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
759 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
761 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
762 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
764 boolean isInterfaceOperational = isOperational(interfaceInfo);
765 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
766 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
767 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
768 staticMacEntry.getMacAddress());
769 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
770 LogicalDatastoreType.OPERATIONAL, macId);
771 if (existingMacEntry.isPresent()) {
772 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
773 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
774 existingMacEntry.get(), tx);
776 elanForwardingEntriesHandler
777 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
780 if (isInterfaceOperational) {
781 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
783 String macAddress = staticMacEntry.getMacAddress().getValue();
784 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
785 macAddress, elanInstanceName, interfaceName);
786 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
787 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
791 if (isInterfaceOperational) {
792 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
794 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
795 staticMacAddresses.add(staticMacEntry.getMacAddress());
797 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
801 List<ListenableFuture<Void>> futures = new ArrayList<>();
802 futures.add(ElanUtils.waitForTransactionToComplete(tx));
803 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
804 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
805 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
807 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
808 if (neutronPort != null) {
809 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
811 } catch (IllegalArgumentException ex) {
812 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
818 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
819 PhysAddress physAddress) {
820 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
821 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
822 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
823 LogicalDatastoreType.OPERATIONAL, macId);
825 if (!existingMacEntry.isPresent()) {
829 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
830 .withKey(new MacEntryKey(physAddress)).build();
831 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
832 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
835 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
836 Optional<DpnInterfaces> existingElanDpnInterfaces) {
837 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
838 if (!existingElanDpnInterfaces.isPresent()) {
841 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
843 if (dpnInterfaces.getInterfaces().size() == 0 || (dpnInterfaces.getInterfaces().size() == 1
844 && dpnInterfaces.getInterfaces().contains(routerPortUuid))) {
850 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
851 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
852 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
855 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
856 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
857 WriteTransaction writeFlowGroupTx) throws ElanException {
858 if (!isOperational(interfaceInfo)) {
861 BigInteger dpId = interfaceInfo.getDpId();
862 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
863 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
865 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
866 if (isFirstInterfaceInDpn) {
867 // Terminating Service , UnknownDMAC Table.
868 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
869 // for ELAN Instance is VxLAN
870 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
871 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
873 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
875 * Install remote DMAC flow. This is required since this DPN is
876 * added later to the elan instance and remote DMACs of other
877 * interfaces in this elan instance are not present in the current
880 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
881 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
882 elanInstance.getElanInstanceName());
883 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
886 // bind the Elan service to the Interface
887 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
890 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
891 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
892 if (!isOperational(interfaceInfo)) {
895 // LocalBroadcast Group creation with elan-Interfaces
896 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
897 if (isFirstInterfaceInDpn) {
898 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
899 BigInteger dpId = interfaceInfo.getDpId();
900 // RemoteBroadcast Group creation
902 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
903 } catch (InterruptedException e1) {
904 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
906 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
908 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
909 } catch (InterruptedException e1) {
910 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
915 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
916 WriteTransaction writeFlowGroupTx) {
917 int ifTag = interfaceInfo.getInterfaceTag();
918 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
919 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
920 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
921 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
922 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
924 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
926 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
927 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
928 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
929 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
931 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
934 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
935 WriteTransaction deleteFlowGroupTx) {
936 int ifTag = interfaceInfo.getInterfaceTag();
937 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
938 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
939 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
940 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
941 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
943 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
945 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
946 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
947 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
948 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
950 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
953 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
954 InterfaceInfo interfaceInfo, long elanTag) {
955 return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
956 bucketKeyStart, elanTag);
959 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
960 int elanTag = elanInfo.getElanTag().intValue();
961 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
962 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
963 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
964 if (etreeInstance != null) {
965 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
966 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
967 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
971 @SuppressWarnings("checkstyle:IllegalCatch")
972 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
974 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
975 if (elanDpns != null) {
976 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
977 for (DpnInterfaces dpnInterface : dpnInterfaces) {
978 List<Bucket> remoteListBucketInfo = new ArrayList<>();
979 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
980 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
981 List<Action> listAction = new ArrayList<>();
983 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
984 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
985 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
987 for (DpnInterfaces otherFes : dpnInterfaces) {
988 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
989 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
990 && !otherFes.getInterfaces().isEmpty()) {
992 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
993 dpnInterface.getDpId(), otherFes.getDpId(),
994 elanUtils.isOpenstackVniSemanticsEnforced()
995 ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
996 if (!remoteListActionInfo.isEmpty()) {
997 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
998 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1001 } catch (Exception ex) {
1002 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1003 + "Logical Group Interface not found between source Dpn - {}, "
1004 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1009 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1010 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1011 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1013 if (remoteListBucketInfo.isEmpty()) {
1014 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1017 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1018 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1019 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1020 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
1024 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1025 } catch (InterruptedException e1) {
1026 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1032 * Returns the bucket info with the given interface as the only bucket.
1034 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
1035 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
1036 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
1039 private List<MatchInfo> buildMatchesForVni(Long vni) {
1040 List<MatchInfo> mkMatches = new ArrayList<>();
1041 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1042 mkMatches.add(match);
1046 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1047 List<InstructionInfo> mkInstructions = new ArrayList<>();
1048 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1049 return mkInstructions;
1052 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1053 List<MatchInfo> mkMatches = new ArrayList<>();
1054 // Matching metadata
1055 mkMatches.add(new MatchMetadata(
1056 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1061 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1062 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1065 * elanTag to be written in metadata when flow is selected
1066 * @return the instructions ready to be installed in a flow
1068 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1069 List<InstructionInfo> mkInstructions = new ArrayList<>();
1070 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1071 .getElanMetadataMask()));
1072 /* applicable for EXTERNAL_TUNNEL_TABLE only
1073 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1075 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1076 return mkInstructions;
1079 // Install DMAC entry on dst DPN
1080 @SuppressWarnings("checkstyle:ForbiddenMethod")
1081 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1082 BigInteger dstDpId) throws ElanException {
1083 String interfaceName = interfaceInfo.getInterfaceName();
1084 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1085 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1086 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1087 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1088 for (MacEntry macEntry : macEntries) {
1089 String macAddress = macEntry.getMacAddress().getValue();
1090 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1091 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1092 interfaceInfo.getDpId())) {
1093 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress);
1094 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1098 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1100 return Collections.emptyList();
1103 private void createDropBucket(List<Bucket> listBucket) {
1104 List<Action> actionsInfos = new ArrayList<>();
1105 actionsInfos.add(new ActionDrop().buildAction());
1106 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1107 MDSALUtil.WATCH_GROUP);
1108 listBucket.add(dropBucket);
1111 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1112 InterfaceInfo interfaceInfo) {
1113 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1114 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1117 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1118 InterfaceInfo interfaceInfo) {
1119 List<Bucket> listBucket = new ArrayList<>();
1121 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1123 List<String> interfaces = new ArrayList<>();
1124 if (newDpnInterface != null) {
1125 interfaces = newDpnInterface.getInterfaces();
1127 for (String ifName : interfaces) {
1128 // In case if there is a InterfacePort in the cache which is not in
1129 // operational state, skip processing it
1130 InterfaceInfo ifInfo = interfaceManager
1131 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1132 if (!isOperational(ifInfo)) {
1136 if (!interfaceManager.isExternalInterface(ifName)) {
1137 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1138 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1143 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1144 MDSALUtil.buildBucketLists(listBucket));
1145 LOG.trace("installing the localBroadCast Group:{}", group);
1146 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1149 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1150 InterfaceInfo interfaceInfo) {
1151 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1152 if (etreeInstance != null) {
1153 List<Bucket> listBucket = new ArrayList<>();
1156 List<String> interfaces = new ArrayList<>();
1157 if (newDpnInterface != null) {
1158 interfaces = newDpnInterface.getInterfaces();
1160 for (String ifName : interfaces) {
1161 // In case if there is a InterfacePort in the cache which is not
1163 // operational state, skip processing it
1164 InterfaceInfo ifInfo = interfaceManager
1165 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1166 if (!isOperational(ifInfo)) {
1170 if (!interfaceManager.isExternalInterface(ifName)) {
1171 // only add root interfaces
1172 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1176 if (listBucket.isEmpty()) { // No Buckets
1177 createDropBucket(listBucket);
1180 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1181 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1182 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1183 MDSALUtil.buildBucketLists(listBucket));
1184 LOG.trace("installing the localBroadCast Group:{}", group);
1185 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1189 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1190 InterfaceInfo ifInfo) {
1191 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1192 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1193 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1194 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1200 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1201 WriteTransaction deleteFlowGroupTx) {
1202 BigInteger dpnId = interfaceInfo.getDpId();
1203 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1204 List<Bucket> listBuckets = new ArrayList<>();
1206 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1207 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1209 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1210 MDSALUtil.buildBucketLists(listBuckets));
1211 LOG.trace("deleted the localBroadCast Group:{}", group);
1212 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1215 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1216 WriteTransaction deleteFlowGroupTx) {
1219 Long elanTag = elanInfo.getElanTag();
1220 List<Bucket> listBuckets = new ArrayList<>();
1221 List<Action> listAction = new ArrayList<>();
1222 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1223 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1224 MDSALUtil.WATCH_GROUP));
1226 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1227 BigInteger dpnId = interfaceInfo.getDpId();
1228 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1229 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1230 MDSALUtil.buildBucketLists(listBuckets));
1231 LOG.trace("deleting the remoteBroadCast group:{}", group);
1232 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1236 * Installs a flow in the External Tunnel table consisting in translating
1237 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1238 * elanTag that will be used later in the ELANs pipeline.
1245 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1246 long elanTag = elanInfo.getElanTag();
1247 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1248 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1249 elanInfo.getElanInstanceName(), // flowName
1252 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1253 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1254 getInstructionsIntOrExtTunnelTable(elanTag));
1256 mdsalManager.installFlow(flowEntity);
1260 * Removes, from External Tunnel table, the flow that translates from VNI to
1261 * elanTag. Important: ensure this method is only called whenever there is
1262 * no other ElanInterface in the specified DPN
1265 * DPN whose Ext Tunnel table is going to be modified
1267 * holds the elanTag needed for selecting the flow to be removed
1269 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1270 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1271 // last ElanInstance plus
1272 // adding a new one does (almost at the same time) are executed in that
1275 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1276 FlowEntity flowEntity = new FlowEntityBuilder()
1278 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1281 mdsalManager.removeFlow(flowEntity);
1284 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1285 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1286 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1289 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1290 WriteTransaction writeFlowGroupTx) {
1291 List<? extends MatchInfoBase> listMatchInfoBase;
1292 List<InstructionInfo> instructionInfos;
1294 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1295 serviceId = elanTag;
1296 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1297 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1299 serviceId = elanUtils.getVxlanSegmentationId(elanInfo);
1300 listMatchInfoBase = buildMatchesForVni(serviceId);
1301 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1303 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1304 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1305 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1307 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1310 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1311 WriteTransaction writeFlowGroupTx) {
1312 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1313 if (etreeInstance != null) {
1314 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1318 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1319 long elanTag = elanInfo.getElanTag();
1320 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1321 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1322 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1325 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1326 WriteTransaction writeFlowGroupTx) {
1327 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1328 if (etreeLeafTag != null) {
1329 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1330 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1331 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1335 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1336 WriteTransaction writeFlowGroupTx) {
1337 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1338 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1339 5, elanInfo.getElanInstanceName(), 0, 0,
1340 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1341 getMatchesForElanTag(elanTag, /* SH flag */false),
1342 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1344 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1347 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1348 WriteTransaction writeFlowGroupTx) {
1349 // only if ELAN can connect to external network, perform the following
1351 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1352 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1353 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1354 5, elanInfo.getElanInstanceName(), 0, 0,
1355 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1356 getMatchesForElanTag(elanTag, /* SH flag */true),
1357 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1358 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1363 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1365 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1366 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1367 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1369 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1370 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1371 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1373 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1377 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1378 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1381 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1382 if (isStandardElanService(elanInterface)) {
1383 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1384 elanInterface.getName(), lportTag, tx);
1385 } else { // Etree service
1386 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1390 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1391 WriteTransaction tx) {
1392 int instructionKey = 0;
1393 List<Instruction> instructions = new ArrayList<>();
1394 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1395 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1397 List<Action> actions = new ArrayList<>();
1398 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1399 lportTag).buildAction());
1400 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1401 elanTag).buildAction());
1402 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1404 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1407 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1408 BoundServices serviceInfo = ElanUtils.getBoundServices(
1409 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1410 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1411 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1412 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1414 if (!existingElanService.isPresent()) {
1415 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1416 WriteTransaction.CREATE_MISSING_PARENTS);
1420 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1421 WriteTransaction tx) {
1422 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1423 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1426 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1427 if (etreeInstance == null) {
1428 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1429 elanInterface.getName(), elanInfo.getElanInstanceName());
1431 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1432 elanInterface.getName(), lportTag, tx);
1437 private boolean isStandardElanService(ElanInterface elanInterface) {
1438 return elanInterface.augmentation(EtreeInterface.class) == null;
1441 protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
1442 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1443 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1444 if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
1445 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1449 private String getFlowRef(long tableId, long elanTag) {
1450 return String.valueOf(tableId) + elanTag;
1453 private String getFlowRef(long tableId, long elanTag, String flowName) {
1454 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1455 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1458 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1459 return String.valueOf(tableId) + elanTag + shFlag;
1462 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1463 List<Action> listAction = new ArrayList<>();
1466 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1468 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1472 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1473 List<String> interfaceNames, WriteTransaction tx) {
1474 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1475 .withKey(new DpnInterfacesKey(dpId)).build();
1476 tx.put(LogicalDatastoreType.OPERATIONAL,
1477 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1478 WriteTransaction.CREATE_MISSING_PARENTS);
1479 return dpnInterface;
1483 * Delete elan dpn interface from operational DS.
1485 * @param elanInstanceName
1486 * the elan instance name
1490 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1491 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1492 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1493 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1494 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1495 if (dpnInterfaces.isPresent()) {
1496 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1500 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1501 WriteTransaction tx) {
1502 List<String> interfaceNames = new ArrayList<>();
1503 interfaceNames.add(interfaceName);
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;
1512 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1513 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1514 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1515 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1516 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1517 // Adding new Elan Interface Port to the operational DataStore without
1518 // Static-Mac Entries..
1519 if (!interfaceMacTables.isPresent()) {
1520 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1521 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1522 tx.put(LogicalDatastoreType.OPERATIONAL,
1523 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1524 WriteTransaction.CREATE_MISSING_PARENTS);
1528 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1529 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1530 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1531 LogicalDatastoreType.OPERATIONAL, elanInstance);
1532 // Adding new Elan Interface Port to the operational DataStore without
1533 // Static-Mac Entries..
1534 if (elanInterfaceLists.isPresent()) {
1535 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1536 if (interfaceLists == null) {
1537 interfaceLists = new ArrayList<>();
1539 interfaceLists.add(interfaceName);
1540 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1541 .withKey(new ElanKey(elanInstanceName)).build();
1542 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1543 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1547 private boolean isOperational(InterfaceInfo interfaceInfo) {
1548 if (interfaceInfo == null) {
1551 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1554 @SuppressWarnings("checkstyle:IllegalCatch")
1555 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1556 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1557 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1558 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1559 if (dpnInterfaceLists == null) {
1562 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1563 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1565 String elanName = elanDpns.getElanInstanceName();
1566 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1567 if (elanInfo == null) {
1568 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1569 + "skipping this ELAN for tunnel handling", elanName);
1572 if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) {
1573 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1576 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1577 if (dpnInterfaces == null) {
1580 DpnInterfaces dstDpnIf = null;
1581 for (DpnInterfaces dpnIf : dpnInterfaces) {
1582 BigInteger dpnIfDpId = dpnIf.getDpId();
1583 if (dpnIfDpId.equals(srcDpId)) {
1585 } else if (dpnIfDpId.equals(dstDpId)) {
1591 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1592 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1593 jobCoordinator.enqueueJob(elanName, () -> {
1594 // update Remote BC Group
1595 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1597 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1598 } catch (RuntimeException e) {
1599 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1601 Set<String> interfaceLists = new HashSet<>();
1602 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1603 for (String ifName : interfaceLists) {
1604 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1605 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1606 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1607 if (isOperational(interfaceInfo)) {
1608 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1610 return Collections.emptyList();
1611 }, ElanConstants.JOB_MAX_RETRIES);
1613 return Collections.emptyList();
1614 }, ElanConstants.JOB_MAX_RETRIES);
1621 * Handle external tunnel state event.
1623 * @param externalTunnel
1624 * the external tunnel
1627 * @throws ElanException in case of issues creating the flow objects
1629 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1630 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1633 // dpId/externalNodeId will be available either in source or destination
1634 // based on the tunnel end point
1635 BigInteger dpId = null;
1636 NodeId externalNodeId = null;
1637 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1638 dpId = new BigInteger(externalTunnel.getSourceDevice());
1639 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1640 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1641 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1642 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1644 if (dpId == null || externalNodeId == null) {
1645 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1649 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1650 if (dpnInterfaceLists == null) {
1653 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1654 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1655 String elanName = elanDpns.getElanInstanceName();
1656 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1658 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1659 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1660 || dpnInterfaces.getInterfaces().isEmpty()) {
1663 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1665 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1666 // install L2gwDevices local macs in dpn.
1667 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1668 // Install dpn macs on external device
1669 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1672 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1676 * Installs dpn macs in external device. first it checks if the physical
1677 * locator towards this dpn tep is present or not if the physical locator is
1678 * present go ahead and add the ucast macs otherwise update the mcast mac
1679 * entry to include this dpn tep ip and schedule the job to put ucast macs
1680 * once the physical locator is programmed in device
1684 * @param lstElanInterfaceNames
1685 * the lst Elan interface names
1688 * @param externalNodeId
1689 * the external node id
1691 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1692 NodeId externalNodeId) {
1693 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1694 externalNodeId.getValue());
1695 if (elanL2GwDevice == null) {
1696 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1699 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1700 if (dpnTepIp == null) {
1701 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1706 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1707 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1708 LogicalDatastoreType.OPERATIONAL);
1709 boolean phyLocAlreadyExists =
1710 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1712 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1713 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1714 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1716 if (phyLocAlreadyExists) {
1717 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1720 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1721 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1725 * Validate external tunnel state event.
1727 * @param externalTunnel
1728 * the external tunnel
1731 * @return true, if successful
1733 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1734 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1735 String srcDevice = externalTunnel.getDestinationDevice();
1736 String destDevice = externalTunnel.getSourceDevice();
1737 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1738 LogicalDatastoreType.CONFIGURATION);
1739 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1740 otherEndPointExtTunnel);
1741 if (otherEndPointExtTunnel != null) {
1742 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1743 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1744 if (otherEndPointInterfaceOperational) {
1747 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1748 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1755 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1756 List<MatchInfo> mkMatches = new ArrayList<>();
1757 // Matching metadata
1759 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1760 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1765 protected ElanInterfaceManager getDataTreeChangeListener() {
1769 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1771 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1772 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1774 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1775 } catch (InterruptedException e) {
1776 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);