2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.ListenableFuture;
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Objects;
26 import java.util.Queue;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentLinkedQueue;
31 import javax.annotation.PostConstruct;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
35 import org.apache.commons.lang3.StringUtils;
36 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
37 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
38 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
39 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
40 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
41 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
42 import org.opendaylight.genius.infra.Datastore.Configuration;
43 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
45 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
46 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
47 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
48 import org.opendaylight.genius.itm.globals.ITMConstants;
49 import org.opendaylight.genius.mdsalutil.FlowEntity;
50 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
51 import org.opendaylight.genius.mdsalutil.InstructionInfo;
52 import org.opendaylight.genius.mdsalutil.MDSALUtil;
53 import org.opendaylight.genius.mdsalutil.MatchInfo;
54 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
55 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
56 import org.opendaylight.genius.mdsalutil.NwConstants;
57 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
58 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
59 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
60 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
61 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
62 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
63 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
64 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
65 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
66 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
67 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
68 import org.opendaylight.genius.utils.ServiceIndex;
69 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
70 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
71 import org.opendaylight.netvirt.elan.ElanException;
72 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
73 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
74 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
75 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
76 import org.opendaylight.netvirt.elan.recovery.impl.ElanServiceRecoveryHandler;
77 import org.opendaylight.netvirt.elan.utils.ElanConstants;
78 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
79 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
80 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
81 import org.opendaylight.netvirt.elan.utils.ElanUtils;
82 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
83 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
84 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
85 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
86 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
87 import org.opendaylight.serviceutils.srm.RecoverableListener;
88 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
89 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
90 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
91 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
132 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
133 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
134 import org.slf4j.Logger;
135 import org.slf4j.LoggerFactory;
138 * Class in charge of handling creations, modifications and removals of
141 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
144 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
145 implements RecoverableListener {
146 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
147 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
148 private static final boolean SH_FLAG_SET = true;
149 private static final boolean SH_FLAG_UNSET = false;
151 private final DataBroker broker;
152 private final ManagedNewTransactionRunner txRunner;
153 private final IMdsalApiManager mdsalManager;
154 private final IInterfaceManager interfaceManager;
155 private final IdManagerService idManager;
156 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
157 private final INeutronVpnManager neutronVpnManager;
158 private final ElanItmUtils elanItmUtils;
159 private final ElanEtreeUtils elanEtreeUtils;
160 private final ElanL2GatewayUtils elanL2GatewayUtils;
161 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
162 private final ElanUtils elanUtils;
163 private final JobCoordinator jobCoordinator;
164 private final ElanInstanceCache elanInstanceCache;
165 private final ElanInterfaceCache elanInterfaceCache;
167 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
168 unProcessedElanInterfaces = new ConcurrentHashMap<>();
171 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
172 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
173 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
174 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
175 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
176 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
177 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
178 final ElanInstanceCache elanInstanceCache,
179 final ElanInterfaceCache elanInterfaceCache,
180 final ElanServiceRecoveryHandler elanServiceRecoveryHandler,
181 final ServiceRecoveryRegistry serviceRecoveryRegistry) {
182 super(ElanInterface.class, ElanInterfaceManager.class);
183 this.broker = dataBroker;
184 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
185 this.idManager = managerService;
186 this.mdsalManager = mdsalApiManager;
187 this.interfaceManager = interfaceManager;
188 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
189 this.neutronVpnManager = neutronVpnManager;
190 this.elanItmUtils = elanItmUtils;
191 this.elanEtreeUtils = elanEtreeUtils;
192 this.elanL2GatewayUtils = elanL2GatewayUtils;
193 this.elanUtils = elanUtils;
194 this.jobCoordinator = jobCoordinator;
195 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
196 this.elanInstanceCache = elanInstanceCache;
197 this.elanInterfaceCache = elanInterfaceCache;
198 serviceRecoveryRegistry.addRecoverableListener(elanServiceRecoveryHandler.buildServiceRegistryKey(), this);
208 public void registerListener() {
209 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
213 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
214 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
218 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
219 String interfaceName = del.getName();
220 ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull();
222 * Handling in case the elan instance is deleted.If the Elan instance is
223 * deleted, there is no need to explicitly delete the elan interfaces
225 if (elanInfo == null) {
228 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
229 if (interfaceInfo == null && elanInfo.isExternal()) {
230 // In deleting external network, the underlying ietf Inteface might have been removed
231 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
232 // from Operational DS instead
233 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
235 String elanInstanceName = elanInfo.getElanInstanceName();
236 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
237 interfaceName, interfaceInfo, this);
238 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
241 @SuppressWarnings("checkstyle:ForbidCertainMethod")
242 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
243 InterfaceInfo interfaceInfo) {
244 String elanName = elanInfo.getElanInstanceName();
245 boolean isLastElanInterface = false;
246 boolean isLastInterfaceOnDpn = false;
247 BigInteger dpId = null;
248 long elanTag = elanInfo.getElanTag();
249 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
250 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
251 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
252 if (elanState == null) {
253 interfaceTx.cancel();
254 return Collections.emptyList();
256 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
257 List<String> elanInterfaces = elanState.getElanInterfaces();
258 if (elanInterfaces.isEmpty()) {
259 isLastElanInterface = true;
261 if (interfaceInfo != null) {
262 dpId = interfaceInfo.getDpId();
263 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
264 interfaceName, elanTag, interfaceTx);
266 * If there are not elan ports, remove the unknown dmac, terminating
267 * service table flows, remote/local bc group
269 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
270 || dpnInterfaces.getInterfaces().isEmpty()) {
271 // No more Elan Interfaces in this DPN
272 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
273 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
274 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
276 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
277 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
278 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
279 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
280 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
281 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
282 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
283 elanUtils.removeTerminatingServiceAction(dpId,
284 elanUtils.getVxlanSegmentationId(elanInfo).intValue());
286 unsetExternalTunnelTable(dpId, elanInfo);
288 isLastInterfaceOnDpn = true;
290 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
294 List<ListenableFuture<Void>> futures = new ArrayList<>();
295 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
296 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
298 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
299 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
301 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
302 interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
303 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
304 ElanConstants.JOB_MAX_RETRIES);
309 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
310 WriteTransaction deleteFlowGroupTx) {
311 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
312 if (etreeLeafTag != null) {
313 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
314 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
318 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
319 WriteTransaction deleteFlowGroupTx) {
320 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
321 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
324 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
325 WriteTransaction deleteFlowGroupTx) {
326 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
327 if (etreeInstance != null) {
328 BigInteger dpnId = interfaceInfo.getDpId();
329 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
330 List<Bucket> listBuckets = new ArrayList<>();
332 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
333 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
334 MDSALUtil.buildBucketLists(listBuckets));
335 LOG.trace("deleted the localBroadCast Group:{}", group);
336 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
340 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
341 WriteTransaction deleteFlowGroupTx) {
342 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
343 if (etreeInstance != null) {
344 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
347 List<Bucket> listBuckets = new ArrayList<>();
348 List<Action> listAction = new ArrayList<>();
349 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
350 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
351 MDSALUtil.WATCH_GROUP));
353 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
354 BigInteger dpnId = interfaceInfo.getDpId();
355 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
356 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
357 MDSALUtil.buildBucketLists(listBuckets));
358 LOG.trace("deleting the remoteBroadCast group:{}", group);
359 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
363 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
364 String elanName = elanInfo.getElanInstanceName();
365 Elan elanState = ElanUtils.getElanByName(broker, elanName);
366 if (elanState == null) {
369 List<String> elanInterfaces = elanState.getElanInterfaces();
370 boolean isRemoved = elanInterfaces.remove(interfaceName);
375 if (elanInterfaces.isEmpty()) {
376 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
377 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
378 tx.delete(LogicalDatastoreType.OPERATIONAL,
379 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
381 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
382 .withKey(new ElanKey(elanName)).build();
383 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
389 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
390 // removing the ElanInterface from the config data_store if interface is
391 // not present in Interface config DS
392 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
393 && elanInterfaceCache.get(interfaceName).isPresent()) {
394 tx.delete(LogicalDatastoreType.CONFIGURATION,
395 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
399 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
400 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
401 String elanName = elanInfo.getElanInstanceName();
402 List<ListenableFuture<Void>> futures = new ArrayList<>();
403 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
404 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> {
405 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
406 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
407 Optional<ElanInterfaceMac> existingElanInterfaceMac =
408 interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet();
409 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
410 if (interfaceInfo != null) {
411 if (existingElanInterfaceMac.isPresent()) {
412 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
413 if (existingMacEntries != null) {
414 List<PhysAddress> macAddresses = new ArrayList<>();
415 for (MacEntry macEntry : existingMacEntries) {
416 PhysAddress macAddress = macEntry.getMacAddress();
417 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
418 macAddress.getValue(), interfaceName);
419 Optional<MacEntry> macEntryOptional =
420 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
421 if (!isLastElanInterface && macEntryOptional.isPresent()) {
422 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
423 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
425 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
426 macAddresses.add(macAddress);
429 // Removing all those MACs from External Devices belonging
431 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
432 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
436 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
437 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
438 } else if (existingElanInterfaceMac.isPresent()) {
439 // Interface does not exist in ConfigDS, so lets remove everything
440 // about that interface related to Elan
441 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
442 if (macEntries != null) {
443 for (MacEntry macEntry : macEntries) {
444 PhysAddress macAddress = macEntry.getMacAddress();
445 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
446 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
447 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
452 if (existingElanInterfaceMac.isPresent()) {
453 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
455 unbindService(interfaceName, interfaceTx);
456 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
462 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
463 String interfaceName, long elanTag,
464 WriteTransaction tx) {
465 synchronized (elanName.intern()) {
467 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
468 if (dpnInterfaces != null) {
469 List<String> interfaceLists = dpnInterfaces.getInterfaces();
470 if (interfaceLists != null) {
471 interfaceLists.remove(interfaceName);
474 if (interfaceLists == null || interfaceLists.isEmpty()) {
475 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
476 deleteElanDpnInterface(elanName, dpId, tx);
478 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
481 return dpnInterfaces;
485 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
486 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
487 for (DpnInterfaces dpnInterface : dpnInterfaces) {
488 BigInteger currentDpId = dpnInterface.getDpId();
489 if (!currentDpId.equals(dpId)) {
490 for (String elanInterface : dpnInterface.getInterfaces()) {
491 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
492 if (macs == null || macs.getMacEntry() == null) {
495 for (MacEntry mac : macs.getMacEntry()) {
496 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
497 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
504 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
505 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
506 if (etreeLeafTag != null) {
507 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
511 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
514 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
515 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
516 mac.getMacAddress().getValue(), elanTag)));
520 * Possible Scenarios for update
521 * a. if orig={1,2,3,4} and updated=null or updated={}
522 then all {1,2,3,4} should be removed
524 b. if orig=null or orig={} and updated ={1,2,3,4}
525 then all {1,2,3,4} should be added
527 c. if orig = {1,2,3,4} updated={2,3,4}
528 then 1 should be removed
530 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
531 then we should just add 5
533 e. if orig = {1,2,3,4} updated={2,3,4,5}
534 then 1 should be removed , 5 should be added
536 @SuppressWarnings("checkstyle:ForbidCertainMethod")
538 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
539 // updating the static-Mac Entries for the existing elanInterface
540 String elanName = update.getElanInstanceName();
541 String interfaceName = update.getName();
543 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
544 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
545 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
546 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
548 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
549 deletedEntry.getMacAddress()));
551 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
552 * Hence add the macentries for the same.*/
553 for (StaticMacEntries staticMacEntry : updatedEntries) {
554 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
555 staticMacEntry.getMacAddress());
556 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
557 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
558 WriteTransaction tx = broker.newWriteOnlyTransaction();
559 if (existingMacEntry.isPresent()) {
560 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
561 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
564 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
565 elanName, interfaceName, staticMacEntry, tx);
567 ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(tx), LOG,
568 "Error in update: identifier={}, original={}, update={}", identifier, original, update);
573 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
574 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
575 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
576 String interfaceName = elanInterfaceAdded.getName();
577 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
578 if (interfaceInfo == null) {
579 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
582 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
584 if (elanInstance == null) {
585 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
586 .setDescription(elanInterfaceAdded.getDescription()).build();
587 // Add the ElanInstance in the Configuration data-store
588 List<String> elanInterfaces = new ArrayList<>();
589 elanInterfaces.add(interfaceName);
590 elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
593 Long elanTag = elanInstance.getElanTag();
594 // If elan tag is not updated, then put the elan interface into
595 // unprocessed entry map and entry. Let entries
596 // in this map get processed during ELAN update DCN.
597 if (elanTag == null) {
598 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
599 if (elanInterfaces == null) {
600 elanInterfaces = new ConcurrentLinkedQueue<>();
602 elanInterfaces.add(elanInterfaceAdded);
603 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
606 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
607 interfaceInfo, elanInstance, this);
608 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
609 }), LOG, "Error procedding added ELAN interface");
612 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
613 List<ListenableFuture<Void>> futures = new ArrayList<>();
614 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
615 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
618 for (ElanInterface elanInterface : elanInterfaces) {
619 String interfaceName = elanInterface.getName();
620 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
621 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
626 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
627 WriteTransaction writeFlowGroupTx) throws ElanException {
628 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
629 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
630 List<DpnInterfaces> dpnInterfaceLists = null;
631 if (elanDpnInterfacesList != null) {
632 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
634 if (dpnInterfaceLists == null) {
635 dpnInterfaceLists = new ArrayList<>();
637 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
638 BigInteger dstDpId = interfaceInfo.getDpId();
639 if (dpnInterfaces.getDpId().equals(dstDpId)) {
642 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
643 for (String remoteIf : remoteElanInterfaces) {
644 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
645 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
646 if (elanIfMac == null || remoteInterface == null) {
649 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
650 if (remoteMacEntries != null) {
651 for (MacEntry macEntry : remoteMacEntries) {
652 String macAddress = macEntry.getMacAddress().getValue();
653 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
654 dstDpId, elanInstance.getElanInstanceName());
655 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
656 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
657 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
664 @SuppressWarnings("checkstyle:ForbidCertainMethod")
665 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
666 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
667 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
668 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
669 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
671 String interfaceName = elanInterface.getName();
672 String elanInstanceName = elanInterface.getElanInstanceName();
674 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
675 WriteTransaction tx = broker.newWriteOnlyTransaction();
676 if (elanInfo == null) {
677 List<String> elanInterfaces = new ArrayList<>();
678 elanInterfaces.add(interfaceName);
679 ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
681 createElanStateList(elanInstanceName, interfaceName, tx);
683 boolean isFirstInterfaceInDpn = false;
684 // Specific actions to the DPN where the ElanInterface has been added,
685 // for example, programming the
686 // External tunnel table if needed or adding the ElanInterface to the
687 // DpnInterfaces in the operational DS.
688 BigInteger dpId = interfaceInfo.getDpId();
689 DpnInterfaces dpnInterfaces = null;
690 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
691 synchronized (elanInstanceName.intern()) {
692 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
693 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
694 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
695 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
696 if (ElanUtils.isVlan(elanInstance)) {
697 isFirstInterfaceInDpn = checkIfFirstInterface(interfaceName,
698 elanInstanceName, existingElanDpnInterfaces);
700 isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
702 if (isFirstInterfaceInDpn) {
703 // ELAN's 1st ElanInterface added to this DPN
704 if (!existingElanDpnInterfaces.isPresent()) {
705 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
707 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
708 elanInterfaces.add(interfaceName);
709 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
712 // The 1st ElanInterface in a DPN must program the Ext Tunnel
713 // table, but only if Elan has VNI
714 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
715 setExternalTunnelTable(dpId, elanInstance);
717 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
719 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
720 elanInterfaces.add(interfaceName);
721 if (elanInterfaces.size() == 1) { // 1st dpn interface
722 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
724 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
729 // add code to install Local/Remote BC group, unknow DMAC entry,
730 // terminating service table flow entry
731 // call bindservice of interfacemanager to create ingress table flow
733 // Add interface to the ElanInterfaceForwardingEntires Container
734 createElanInterfaceTablesList(interfaceName, tx);
735 List<ListenableFuture<Void>> futures = new ArrayList<>();
736 futures.add(ElanUtils.waitForTransactionToComplete(tx));
737 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
739 // add the vlan provider interface to remote BC group for the elan
740 // for internal vlan networks
741 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
742 if (interfaceManager.isExternalInterface(interfaceName)) {
743 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
744 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
748 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
749 //update the remote-DPNs remoteBC group entry with Tunnels
750 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
751 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
754 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
755 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
756 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
757 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
761 @SuppressWarnings("checkstyle:ForbidCertainMethod")
762 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
763 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
764 throws ElanException {
765 String elanInstanceName = elanInstance.getElanInstanceName();
766 String interfaceName = elanInterface.getName();
767 WriteTransaction tx = broker.newWriteOnlyTransaction();
768 BigInteger dpId = interfaceInfo.getDpId();
769 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
770 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
771 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
773 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
774 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
776 boolean isInterfaceOperational = isOperational(interfaceInfo);
777 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
778 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
779 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
780 staticMacEntry.getMacAddress());
781 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
782 LogicalDatastoreType.OPERATIONAL, macId);
783 if (existingMacEntry.isPresent()) {
784 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
785 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
786 existingMacEntry.get(), tx);
788 elanForwardingEntriesHandler
789 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
792 if (isInterfaceOperational) {
793 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
795 String macAddress = staticMacEntry.getMacAddress().getValue();
796 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
797 macAddress, elanInstanceName, interfaceName);
798 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
799 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
803 if (isInterfaceOperational) {
804 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
806 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
807 staticMacAddresses.add(staticMacEntry.getMacAddress());
809 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
813 List<ListenableFuture<Void>> futures = new ArrayList<>();
814 futures.add(ElanUtils.waitForTransactionToComplete(tx));
815 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
816 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
817 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
819 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
820 if (neutronPort != null) {
821 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
823 } catch (IllegalArgumentException ex) {
824 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
830 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
831 PhysAddress physAddress) {
832 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
833 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
834 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
835 LogicalDatastoreType.OPERATIONAL, macId);
837 if (!existingMacEntry.isPresent()) {
841 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
842 .withKey(new MacEntryKey(physAddress)).build();
843 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
844 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
847 private boolean checkIfFirstInterface(String elanInterface, String elanInstanceName,
848 Optional<DpnInterfaces> existingElanDpnInterfaces) {
849 String routerPortUuid = ElanUtils.getRouterPordIdFromElanInstance(broker, elanInstanceName);
850 if (!existingElanDpnInterfaces.isPresent()) {
853 if (elanInterface.equals(elanInstanceName) || elanInterface.equals(routerPortUuid)) {
856 DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
857 int dummyInterfaceCount = 0;
858 if (dpnInterfaces.getInterfaces().contains(routerPortUuid)) {
859 dummyInterfaceCount++;
861 if (dpnInterfaces.getInterfaces().contains(elanInstanceName)) {
862 dummyInterfaceCount++;
864 if (dpnInterfaces.getInterfaces().size() - dummyInterfaceCount == 0) {
870 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
871 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
872 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
875 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
876 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
877 WriteTransaction writeFlowGroupTx) throws ElanException {
878 if (!isOperational(interfaceInfo)) {
881 BigInteger dpId = interfaceInfo.getDpId();
882 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
883 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
885 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
886 if (isFirstInterfaceInDpn) {
887 // Terminating Service , UnknownDMAC Table.
888 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
889 // for ELAN Instance is VxLAN
890 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
891 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
893 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
895 * Install remote DMAC flow. This is required since this DPN is
896 * added later to the elan instance and remote DMACs of other
897 * interfaces in this elan instance are not present in the current
900 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
901 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
902 elanInstance.getElanInstanceName());
903 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
906 // bind the Elan service to the Interface
907 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
910 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
911 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
912 if (!isOperational(interfaceInfo)) {
915 // LocalBroadcast Group creation with elan-Interfaces
916 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
917 if (isFirstInterfaceInDpn) {
918 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
919 BigInteger dpId = interfaceInfo.getDpId();
920 // RemoteBroadcast Group creation
922 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
923 } catch (InterruptedException e1) {
924 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
926 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
928 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
929 } catch (InterruptedException e1) {
930 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
935 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
936 WriteTransaction writeFlowGroupTx) {
937 int ifTag = interfaceInfo.getInterfaceTag();
938 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
939 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
940 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
941 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
942 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
944 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
946 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
947 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
948 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
949 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
951 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
954 // TODO skitt Fix the exception handling here
955 @SuppressWarnings("checkstyle:IllegalCatch")
956 @SuppressFBWarnings("REC_CATCH_EXCEPTION")
957 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
958 TypedReadWriteTransaction<Configuration> flowTx) {
960 int ifTag = interfaceInfo.getInterfaceTag();
961 Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
962 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
964 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
966 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
967 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
968 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
969 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
971 mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
972 } catch (Exception e) {
973 LOG.error("Error removing flow", e);
974 throw new RuntimeException("Error removing flow", e);
978 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
979 InterfaceInfo interfaceInfo, long elanTag) {
980 return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
981 bucketKeyStart, elanTag);
984 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
985 int elanTag = elanInfo.getElanTag().intValue();
986 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
987 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
988 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
989 if (etreeInstance != null) {
990 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
991 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
992 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
996 @SuppressWarnings("checkstyle:IllegalCatch")
997 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
999 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1000 if (elanDpns != null) {
1001 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1002 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1003 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1004 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1005 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1006 List<Action> listAction = new ArrayList<>();
1008 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1009 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1010 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1012 for (DpnInterfaces otherFes : dpnInterfaces) {
1013 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1014 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1015 && !otherFes.getInterfaces().isEmpty()) {
1017 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1018 dpnInterface.getDpId(), otherFes.getDpId(),
1019 elanUtils.isOpenstackVniSemanticsEnforced()
1020 ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
1021 if (!remoteListActionInfo.isEmpty()) {
1022 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1023 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1026 } catch (Exception ex) {
1027 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1028 + "Logical Group Interface not found between source Dpn - {}, "
1029 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1034 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
1035 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
1036 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1038 if (remoteListBucketInfo.isEmpty()) {
1039 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1042 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1043 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1044 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1045 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
1049 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1050 } catch (InterruptedException e1) {
1051 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1057 * Returns the bucket info with the given interface as the only bucket.
1059 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
1060 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
1061 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
1064 private List<MatchInfo> buildMatchesForVni(Long vni) {
1065 List<MatchInfo> mkMatches = new ArrayList<>();
1066 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1067 mkMatches.add(match);
1071 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1072 List<InstructionInfo> mkInstructions = new ArrayList<>();
1073 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1074 return mkInstructions;
1077 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1078 List<MatchInfo> mkMatches = new ArrayList<>();
1079 // Matching metadata
1080 mkMatches.add(new MatchMetadata(
1081 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1086 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1087 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1090 * elanTag to be written in metadata when flow is selected
1091 * @return the instructions ready to be installed in a flow
1093 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1094 List<InstructionInfo> mkInstructions = new ArrayList<>();
1095 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1096 .getElanMetadataMask()));
1097 /* applicable for EXTERNAL_TUNNEL_TABLE only
1098 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1100 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1101 return mkInstructions;
1104 // Install DMAC entry on dst DPN
1105 @SuppressWarnings("checkstyle:ForbidCertainMethod")
1106 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1107 BigInteger dstDpId) throws ElanException {
1108 String interfaceName = interfaceInfo.getInterfaceName();
1109 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1110 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1111 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1112 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1113 for (MacEntry macEntry : macEntries) {
1114 String macAddress = macEntry.getMacAddress().getValue();
1115 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1116 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1117 interfaceInfo.getDpId())) {
1118 LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress);
1119 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1123 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1125 return Collections.emptyList();
1128 private void createDropBucket(List<Bucket> listBucket) {
1129 List<Action> actionsInfos = new ArrayList<>();
1130 actionsInfos.add(new ActionDrop().buildAction());
1131 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1132 MDSALUtil.WATCH_GROUP);
1133 listBucket.add(dropBucket);
1136 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1137 InterfaceInfo interfaceInfo) {
1138 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1139 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1142 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1143 InterfaceInfo interfaceInfo) {
1144 List<Bucket> listBucket = new ArrayList<>();
1146 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1148 List<String> interfaces = new ArrayList<>();
1149 if (newDpnInterface != null) {
1150 interfaces = newDpnInterface.getInterfaces();
1152 for (String ifName : interfaces) {
1153 // In case if there is a InterfacePort in the cache which is not in
1154 // operational state, skip processing it
1155 InterfaceInfo ifInfo = interfaceManager
1156 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1157 if (!isOperational(ifInfo)) {
1161 if (!interfaceManager.isExternalInterface(ifName)) {
1162 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1163 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1168 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1169 MDSALUtil.buildBucketLists(listBucket));
1170 LOG.trace("installing the localBroadCast Group:{}", group);
1171 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1174 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1175 InterfaceInfo interfaceInfo) {
1176 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1177 if (etreeInstance != null) {
1178 List<Bucket> listBucket = new ArrayList<>();
1181 List<String> interfaces = new ArrayList<>();
1182 if (newDpnInterface != null) {
1183 interfaces = newDpnInterface.getInterfaces();
1185 for (String ifName : interfaces) {
1186 // In case if there is a InterfacePort in the cache which is not
1188 // operational state, skip processing it
1189 InterfaceInfo ifInfo = interfaceManager
1190 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1191 if (!isOperational(ifInfo)) {
1195 if (!interfaceManager.isExternalInterface(ifName)) {
1196 // only add root interfaces
1197 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1201 if (listBucket.isEmpty()) { // No Buckets
1202 createDropBucket(listBucket);
1205 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1206 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1207 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1208 MDSALUtil.buildBucketLists(listBucket));
1209 LOG.trace("installing the localBroadCast Group:{}", group);
1210 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1214 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1215 InterfaceInfo ifInfo) {
1216 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1217 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1218 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1219 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1225 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1226 WriteTransaction deleteFlowGroupTx) {
1227 BigInteger dpnId = interfaceInfo.getDpId();
1228 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1229 List<Bucket> listBuckets = new ArrayList<>();
1231 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1232 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1234 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1235 MDSALUtil.buildBucketLists(listBuckets));
1236 LOG.trace("deleted the localBroadCast Group:{}", group);
1237 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1240 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1241 WriteTransaction deleteFlowGroupTx) {
1244 Long elanTag = elanInfo.getElanTag();
1245 List<Bucket> listBuckets = new ArrayList<>();
1246 List<Action> listAction = new ArrayList<>();
1247 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1248 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1249 MDSALUtil.WATCH_GROUP));
1251 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1252 BigInteger dpnId = interfaceInfo.getDpId();
1253 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1254 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1255 MDSALUtil.buildBucketLists(listBuckets));
1256 LOG.trace("deleting the remoteBroadCast group:{}", group);
1257 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1261 * Installs a flow in the External Tunnel table consisting in translating
1262 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1263 * elanTag that will be used later in the ELANs pipeline.
1270 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1271 long elanTag = elanInfo.getElanTag();
1272 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1273 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1274 elanInfo.getElanInstanceName(), // flowName
1277 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1278 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1279 getInstructionsIntOrExtTunnelTable(elanTag));
1281 mdsalManager.installFlow(flowEntity);
1285 * Removes, from External Tunnel table, the flow that translates from VNI to
1286 * elanTag. Important: ensure this method is only called whenever there is
1287 * no other ElanInterface in the specified DPN
1290 * DPN whose Ext Tunnel table is going to be modified
1292 * holds the elanTag needed for selecting the flow to be removed
1294 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1295 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1296 // last ElanInstance plus
1297 // adding a new one does (almost at the same time) are executed in that
1300 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1301 FlowEntity flowEntity = new FlowEntityBuilder()
1303 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1306 mdsalManager.removeFlow(flowEntity);
1309 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1310 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1311 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1314 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1315 WriteTransaction writeFlowGroupTx) {
1316 List<? extends MatchInfoBase> listMatchInfoBase;
1317 List<InstructionInfo> instructionInfos;
1319 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1320 serviceId = elanTag;
1321 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1322 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1324 serviceId = elanUtils.getVxlanSegmentationId(elanInfo);
1325 listMatchInfoBase = buildMatchesForVni(serviceId);
1326 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1328 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1329 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1330 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1332 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1335 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1336 WriteTransaction writeFlowGroupTx) {
1337 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1338 if (etreeInstance != null) {
1339 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1343 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1344 long elanTag = elanInfo.getElanTag();
1345 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1346 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1347 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1350 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1351 WriteTransaction writeFlowGroupTx) {
1352 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1353 if (etreeLeafTag != null) {
1354 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1355 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1356 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1360 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1361 WriteTransaction writeFlowGroupTx) {
1362 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1363 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1364 5, elanInfo.getElanInstanceName(), 0, 0,
1365 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1366 getMatchesForElanTag(elanTag, /* SH flag */false),
1367 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1369 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1372 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1373 WriteTransaction writeFlowGroupTx) {
1374 // only if ELAN can connect to external network, perform the following
1376 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1377 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1378 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1379 5, elanInfo.getElanInstanceName(), 0, 0,
1380 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1381 getMatchesForElanTag(elanTag, /* SH flag */true),
1382 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1383 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1388 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1390 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1391 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1392 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1394 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1395 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1396 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1398 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1402 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1403 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1406 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1407 if (isStandardElanService(elanInterface)) {
1408 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1409 elanInterface.getName(), lportTag, tx);
1410 } else { // Etree service
1411 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1415 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1416 WriteTransaction tx) {
1417 int instructionKey = 0;
1418 List<Instruction> instructions = new ArrayList<>();
1419 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1420 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1422 List<Action> actions = new ArrayList<>();
1423 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1424 lportTag).buildAction());
1425 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1426 elanTag).buildAction());
1427 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1429 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1432 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1433 BoundServices serviceInfo = ElanUtils.getBoundServices(
1434 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1435 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1436 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1437 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1439 if (!existingElanService.isPresent()) {
1440 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1441 WriteTransaction.CREATE_MISSING_PARENTS);
1445 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1446 WriteTransaction tx) {
1447 if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1448 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1451 EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
1452 if (etreeInstance == null) {
1453 LOG.error("EtreeInterface {} is associated with a non EtreeInstance: {}",
1454 elanInterface.getName(), elanInfo.getElanInstanceName());
1456 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1457 elanInterface.getName(), lportTag, tx);
1462 private boolean isStandardElanService(ElanInterface elanInterface) {
1463 return elanInterface.augmentation(EtreeInterface.class) == null;
1466 protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
1467 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1468 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1469 if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
1470 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1474 private String getFlowRef(long tableId, long elanTag) {
1475 return String.valueOf(tableId) + elanTag;
1478 private String getFlowRef(long tableId, long elanTag, String flowName) {
1479 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1480 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1483 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1484 return String.valueOf(tableId) + elanTag + shFlag;
1487 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1488 List<Action> listAction = new ArrayList<>();
1491 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1493 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1497 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1498 List<String> interfaceNames, WriteTransaction tx) {
1499 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1500 .withKey(new DpnInterfacesKey(dpId)).build();
1501 tx.put(LogicalDatastoreType.OPERATIONAL,
1502 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1503 WriteTransaction.CREATE_MISSING_PARENTS);
1504 return dpnInterface;
1508 * Delete elan dpn interface from operational DS.
1510 * @param elanInstanceName
1511 * the elan instance name
1515 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1516 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1517 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1518 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1519 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1520 if (dpnInterfaces.isPresent()) {
1521 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1525 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1526 WriteTransaction tx) {
1527 List<String> interfaceNames = new ArrayList<>();
1528 interfaceNames.add(interfaceName);
1529 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1530 .withKey(new DpnInterfacesKey(dpId)).build();
1531 tx.put(LogicalDatastoreType.OPERATIONAL,
1532 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1533 WriteTransaction.CREATE_MISSING_PARENTS);
1534 return dpnInterface;
1537 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1538 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1539 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1540 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1541 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1542 // Adding new Elan Interface Port to the operational DataStore without
1543 // Static-Mac Entries..
1544 if (!interfaceMacTables.isPresent()) {
1545 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1546 .withKey(new ElanInterfaceMacKey(interfaceName)).build();
1547 tx.put(LogicalDatastoreType.OPERATIONAL,
1548 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1549 WriteTransaction.CREATE_MISSING_PARENTS);
1553 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1554 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1555 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1556 LogicalDatastoreType.OPERATIONAL, elanInstance);
1557 // Adding new Elan Interface Port to the operational DataStore without
1558 // Static-Mac Entries..
1559 if (elanInterfaceLists.isPresent()) {
1560 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1561 if (interfaceLists == null) {
1562 interfaceLists = new ArrayList<>();
1564 interfaceLists.add(interfaceName);
1565 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1566 .withKey(new ElanKey(elanInstanceName)).build();
1567 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1568 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1572 private boolean isOperational(InterfaceInfo interfaceInfo) {
1573 if (interfaceInfo == null) {
1576 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1579 @SuppressWarnings("checkstyle:IllegalCatch")
1580 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1581 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1582 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1583 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1584 if (dpnInterfaceLists == null) {
1587 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1588 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1590 String elanName = elanDpns.getElanInstanceName();
1591 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1592 if (elanInfo == null) {
1593 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1594 + "skipping this ELAN for tunnel handling", elanName);
1597 if (!isVxlanNetworkOrVxlanSegment(elanInfo)) {
1598 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1601 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1602 if (dpnInterfaces == null) {
1605 DpnInterfaces dstDpnIf = null;
1606 for (DpnInterfaces dpnIf : dpnInterfaces) {
1607 BigInteger dpnIfDpId = dpnIf.getDpId();
1608 if (dpnIfDpId.equals(srcDpId)) {
1610 } else if (dpnIfDpId.equals(dstDpId)) {
1616 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1617 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1618 jobCoordinator.enqueueJob(elanName, () -> {
1619 // update Remote BC Group
1620 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1622 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1623 } catch (RuntimeException e) {
1624 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1626 Set<String> interfaceLists = new HashSet<>();
1627 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1628 for (String ifName : interfaceLists) {
1629 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1630 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1631 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1632 if (isOperational(interfaceInfo)) {
1633 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1635 return Collections.emptyList();
1636 }, ElanConstants.JOB_MAX_RETRIES);
1638 return Collections.emptyList();
1639 }, ElanConstants.JOB_MAX_RETRIES);
1646 * Handle external tunnel state event.
1648 * @param externalTunnel
1649 * the external tunnel
1652 * @throws ElanException in case of issues creating the flow objects
1654 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1655 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1658 // dpId/externalNodeId will be available either in source or destination
1659 // based on the tunnel end point
1660 BigInteger dpId = null;
1661 NodeId externalNodeId = null;
1662 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1663 dpId = new BigInteger(externalTunnel.getSourceDevice());
1664 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1665 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1666 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1667 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1669 if (dpId == null || externalNodeId == null) {
1670 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1674 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1675 if (dpnInterfaceLists == null) {
1678 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1679 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1680 String elanName = elanDpns.getElanInstanceName();
1681 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1683 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1684 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1685 || dpnInterfaces.getInterfaces().isEmpty()) {
1688 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1690 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1691 // install L2gwDevices local macs in dpn.
1692 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1693 // Install dpn macs on external device
1694 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1697 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1701 * Installs dpn macs in external device. first it checks if the physical
1702 * locator towards this dpn tep is present or not if the physical locator is
1703 * present go ahead and add the ucast macs otherwise update the mcast mac
1704 * entry to include this dpn tep ip and schedule the job to put ucast macs
1705 * once the physical locator is programmed in device
1709 * @param lstElanInterfaceNames
1710 * the lst Elan interface names
1713 * @param externalNodeId
1714 * the external node id
1716 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1717 NodeId externalNodeId) {
1718 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1719 externalNodeId.getValue());
1720 if (elanL2GwDevice == null) {
1721 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1724 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1725 if (dpnTepIp == null) {
1726 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1731 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1732 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1733 LogicalDatastoreType.OPERATIONAL);
1734 boolean phyLocAlreadyExists =
1735 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1737 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1738 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1739 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1741 if (phyLocAlreadyExists) {
1742 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1745 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1746 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1750 * Validate external tunnel state event.
1752 * @param externalTunnel
1753 * the external tunnel
1756 * @return true, if successful
1758 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1759 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1760 String srcDevice = externalTunnel.getDestinationDevice();
1761 String destDevice = externalTunnel.getSourceDevice();
1762 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1763 LogicalDatastoreType.CONFIGURATION);
1764 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1765 otherEndPointExtTunnel);
1766 if (otherEndPointExtTunnel != null) {
1767 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1768 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1769 if (otherEndPointInterfaceOperational) {
1772 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1773 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1780 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1781 List<MatchInfo> mkMatches = new ArrayList<>();
1782 // Matching metadata
1784 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1785 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1790 protected ElanInterfaceManager getDataTreeChangeListener() {
1794 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1796 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1797 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1799 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1800 } catch (InterruptedException e) {
1801 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);