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.isVxlan;
11 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Objects;
24 import java.util.Queue;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentLinkedQueue;
28 import java.util.concurrent.ConcurrentMap;
29 import java.util.stream.Collectors;
30 import javax.annotation.PostConstruct;
31 import javax.inject.Inject;
32 import javax.inject.Singleton;
33 import org.apache.commons.lang3.StringUtils;
34 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
38 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
39 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.itm.globals.ITMConstants;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
44 import org.opendaylight.genius.mdsalutil.InstructionInfo;
45 import org.opendaylight.genius.mdsalutil.MDSALUtil;
46 import org.opendaylight.genius.mdsalutil.MatchInfo;
47 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
48 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
49 import org.opendaylight.genius.mdsalutil.NwConstants;
50 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
51 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
52 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
53 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
54 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
58 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
59 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
60 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
61 import org.opendaylight.genius.utils.ServiceIndex;
62 import org.opendaylight.netvirt.elan.ElanException;
63 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
64 import org.opendaylight.netvirt.elan.utils.ElanConstants;
65 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
66 import org.opendaylight.netvirt.elan.utils.ElanUtils;
67 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
68 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
69 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
70 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
71 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
114 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
115 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
116 import org.slf4j.Logger;
117 import org.slf4j.LoggerFactory;
120 * Class in charge of handling creations, modifications and removals of
123 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
126 @SuppressWarnings("deprecation")
127 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
128 implements AutoCloseable {
130 private final DataBroker broker;
131 private final IMdsalApiManager mdsalManager;
132 private final IInterfaceManager interfaceManager;
133 private final IdManagerService idManager;
134 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
135 private final INeutronVpnManager neutronVpnManager;
136 private ElanL2GatewayUtils elanL2GatewayUtils;
137 private ElanUtils elanUtils;
139 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
140 private static final boolean SH_FLAG_SET = true;
141 private static final boolean SH_FLAG_UNSET = false;
143 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
144 unProcessedElanInterfaces = new ConcurrentHashMap<>();
146 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
149 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
150 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
151 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
152 final INeutronVpnManager neutronVpnManager) {
153 super(ElanInterface.class, ElanInterfaceManager.class);
154 this.broker = dataBroker;
155 this.idManager = managerService;
156 this.mdsalManager = mdsalApiManager;
157 this.interfaceManager = interfaceManager;
158 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
159 this.neutronVpnManager = neutronVpnManager;
163 * This method is used instead of "regular" standard constructor dependency injection in, only,
164 * ElanServiceProvider's constructor to wire things together. It was done like this because of the unholy
165 * triumvirate of unhealthy love triangle between (at least) ElanUtils, ElanInterfaceManager and
166 * ElanL2GatewayMulticastUtils. The proper solution to be able to get rid of this would be to split up some of these
167 * relatively big classes into smaller classes, and then inject more fine grained among them.
169 public void setElanUtils(ElanUtils elanUtils) {
170 this.elanUtils = elanUtils;
171 this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
172 this.elanForwardingEntriesHandler.setElanUtils(elanUtils);
178 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
182 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
183 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
187 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
188 String interfaceName = del.getName();
189 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, del.getElanInstanceName());
191 * Handling in case the elan instance is deleted.If the Elan instance is
192 * deleted, there is no need to explicitly delete the elan interfaces
194 if (elanInfo == null) {
197 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
198 if (interfaceInfo == null && elanInfo.isExternal()) {
199 // In deleting external network, the underlying ietf Inteface might have been removed
200 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
201 // from Operational DS instead
202 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
204 String elanInstanceName = elanInfo.getElanInstanceName();
205 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
206 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
207 interfaceName, interfaceInfo, false, this);
208 coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
211 public void removeElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, String interfaceName,
212 InterfaceInfo interfaceInfo, boolean isInterfaceStateRemoved) {
213 String elanName = elanInfo.getElanInstanceName();
214 boolean isLastElanInterface = false;
215 boolean isLastInterfaceOnDpn = false;
216 BigInteger dpId = null;
217 long elanTag = elanInfo.getElanTag();
218 WriteTransaction tx = broker.newWriteOnlyTransaction();
219 WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
220 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, tx);
221 if (elanState == null) {
224 List<String> elanInterfaces = elanState.getElanInterfaces();
225 if (elanInterfaces.isEmpty()) {
226 isLastElanInterface = true;
228 if (interfaceInfo != null) {
229 dpId = interfaceInfo.getDpId();
230 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
231 interfaceName, elanTag, tx);
233 * If there are not elan ports, remove the unknown dmac, terminating
234 * service table flows, remote/local bc group
236 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
237 || dpnInterfaces.getInterfaces().isEmpty()) {
238 // No more Elan Interfaces in this DPN
239 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
240 if (!elanUtils.isOpenStackVniSemanticsEnforced()) {
241 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
243 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, elanInfo.getElanTag());
244 removeEtreeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx);
245 removeElanBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
246 removeLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
247 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, deleteFlowGroupTx);
248 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
249 if (elanUtils.isOpenStackVniSemanticsEnforced()) {
250 elanUtils.removeTerminatingServiceAction(dpId, elanInfo.getSegmentationId().intValue());
252 unsetExternalTunnelTable(dpId, elanInfo);
254 isLastInterfaceOnDpn = true;
256 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
259 futures.add(ElanUtils.waitForTransactionToComplete(tx));
260 futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
262 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
263 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
265 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
266 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
267 interfaceName, elanInfo, interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
268 coordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
269 ElanConstants.JOB_MAX_RETRIES);
272 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
273 WriteTransaction deleteFlowGroupTx) {
274 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
275 if (etreeLeafTag != null) {
276 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
277 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
281 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
282 WriteTransaction deleteFlowGroupTx) {
283 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
284 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
287 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
288 WriteTransaction deleteFlowGroupTx) {
289 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
290 if (etreeInstance != null) {
291 BigInteger dpnId = interfaceInfo.getDpId();
292 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
293 List<Bucket> listBuckets = new ArrayList<>();
295 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
296 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
297 MDSALUtil.buildBucketLists(listBuckets));
298 LOG.trace("deleted the localBroadCast Group:{}", group);
299 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
303 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
304 WriteTransaction deleteFlowGroupTx) {
305 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
306 if (etreeInstance != null) {
307 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
310 List<Bucket> listBuckets = new ArrayList<>();
311 List<Action> listAction = new ArrayList<>();
312 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
313 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
314 MDSALUtil.WATCH_GROUP));
316 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
317 BigInteger dpnId = interfaceInfo.getDpId();
318 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
319 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
320 MDSALUtil.buildBucketLists(listBuckets));
321 LOG.trace("deleting the remoteBroadCast group:{}", group);
322 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
326 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
327 String elanName = elanInfo.getElanInstanceName();
328 Elan elanState = ElanUtils.getElanByName(broker, elanName);
329 if (elanState == null) {
332 List<String> elanInterfaces = elanState.getElanInterfaces();
333 boolean isRemoved = elanInterfaces.remove(interfaceName);
338 if (elanInterfaces.isEmpty()) {
339 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
340 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
341 tx.delete(LogicalDatastoreType.OPERATIONAL,
342 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
344 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
345 .setKey(new ElanKey(elanName)).build();
346 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
352 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
353 // removing the ElanInterface from the config data_store if interface is
354 // not present in Interface config DS
355 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
356 && ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName) != null) {
357 tx.delete(LogicalDatastoreType.CONFIGURATION,
358 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
362 void removeEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, InterfaceInfo
363 interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved, boolean isLastElanInterface) {
364 String elanName = elanInfo.getElanInstanceName();
365 WriteTransaction tx = broker.newWriteOnlyTransaction();
366 WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
367 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
368 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
369 Optional<ElanInterfaceMac> existingElanInterfaceMac = elanUtils.read(broker,
370 LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
371 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
372 if (interfaceInfo != null) {
373 if (existingElanInterfaceMac.isPresent()) {
374 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
375 List<MacEntry> macEntries = new ArrayList<>();
376 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
377 macEntries.addAll(existingMacEntries);
379 List<PhysAddress> macAddresses = macEntries.stream().map(macEntry -> {
380 PhysAddress macAddress = macEntry.getMacAddress();
381 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
382 macAddress.getValue(), interfaceName);
383 Optional<MacEntry> macEntryOptional = elanUtils.getMacEntryForElanInstance(elanName,
385 if (!isLastElanInterface && macEntryOptional.isPresent()) {
386 tx.delete(LogicalDatastoreType.OPERATIONAL,
387 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
389 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
391 }).collect(Collectors.toList());
393 // Removing all those MACs from External Devices belonging
395 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
396 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
399 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
400 removeFilterEqualsTable(elanInfo, interfaceInfo, deleteFlowGroupTx);
401 } else if (existingElanInterfaceMac.isPresent()) {
402 // Interface does not exist in ConfigDS, so lets remove everything
403 // about that interface related to Elan
404 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
405 if (macEntries != null) {
406 for (MacEntry macEntry : macEntries) {
407 PhysAddress macAddress = macEntry.getMacAddress();
408 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
409 tx.delete(LogicalDatastoreType.OPERATIONAL,
410 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
415 if (existingElanInterfaceMac.isPresent()) {
416 tx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
418 if (!isInterfaceStateRemoved) {
419 unbindService(interfaceName, tx);
421 deleteElanInterfaceFromConfigDS(interfaceName, tx);
422 futures.add(ElanUtils.waitForTransactionToComplete(tx));
423 futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
426 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
427 String interfaceName, long elanTag,
428 WriteTransaction tx) {
429 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
430 if (dpnInterfaces != null) {
431 List<String> interfaceLists = dpnInterfaces.getInterfaces();
432 interfaceLists.remove(interfaceName);
434 if (interfaceLists == null || interfaceLists.isEmpty()) {
435 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
436 deleteElanDpnInterface(elanName, dpId, tx);
438 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
441 return dpnInterfaces;
444 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
445 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
446 for (DpnInterfaces dpnInterface : dpnInterfaces) {
447 BigInteger currentDpId = dpnInterface.getDpId();
448 if (!currentDpId.equals(dpId)) {
449 for (String elanInterface : dpnInterface.getInterfaces()) {
450 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
451 if (macs == null || macs.getMacEntry() == null) {
454 for (MacEntry mac : macs.getMacEntry()) {
455 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
456 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
463 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
464 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
465 if (etreeLeafTag != null) {
466 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
470 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
473 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
474 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
475 mac.getMacAddress().getValue(), elanTag)));
479 * Possible Scenarios for update
480 * a. if orig={1,2,3,4} and updated=null or updated={}
481 then all {1,2,3,4} should be removed
483 b. if orig=null or orig={} and updated ={1,2,3,4}
484 then all {1,2,3,4} should be added
486 c. if orig = {1,2,3,4} updated={2,3,4}
487 then 1 should be removed
489 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
490 then we should just add 5
492 e. if orig = {1,2,3,4} updated={2,3,4,5}
493 then 1 should be removed , 5 should be added
496 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
497 // updating the static-Mac Entries for the existing elanInterface
498 String elanName = update.getElanInstanceName();
499 String interfaceName = update.getName();
501 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
502 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
503 List<StaticMacEntries> deletedEntries = elanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
504 List<StaticMacEntries> updatedEntries = elanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
506 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
507 deletedEntry.getMacAddress()));
509 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
510 * Hence add the macentries for the same.*/
511 for (StaticMacEntries staticMacEntry : updatedEntries) {
512 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
513 staticMacEntry.getMacAddress());
514 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
515 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
516 WriteTransaction tx = broker.newWriteOnlyTransaction();
517 if (existingMacEntry.isPresent()) {
518 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
519 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
522 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
523 ElanUtils.getElanInstanceByName(broker, elanName), interfaceName, staticMacEntry, tx);
525 ElanUtils.waitForTransactionToComplete(tx);
530 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
531 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
532 String interfaceName = elanInterfaceAdded.getName();
533 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
534 if (interfaceInfo == null) {
535 LOG.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
538 ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
540 if (elanInstance == null) {
541 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
542 .setDescription(elanInterfaceAdded.getDescription()).build();
543 // Add the ElanInstance in the Configuration data-store
544 WriteTransaction tx = broker.newWriteOnlyTransaction();
545 List<String> elanInterfaces = new ArrayList<>();
546 elanInterfaces.add(interfaceName);
547 ElanUtils.updateOperationalDataStore(broker, idManager,
548 elanInstance, elanInterfaces, tx);
549 ElanUtils.waitForTransactionToComplete(tx);
550 elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
553 Long elanTag = elanInstance.getElanTag();
554 // If elan tag is not updated, then put the elan interface into
555 // unprocessed entry map and entry. Let entries
556 // in this map get processed during ELAN update DCN.
557 if (elanTag == null) {
558 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
559 if (elanInterfaces == null) {
560 elanInterfaces = new ConcurrentLinkedQueue<>();
562 elanInterfaces.add(elanInterfaceAdded);
563 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
566 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
567 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
568 interfaceInfo, elanInstance, this);
569 coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
572 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
573 List<ListenableFuture<Void>> futures = new ArrayList<>();
574 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
575 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
578 for (ElanInterface elanInterface : elanInterfaces) {
579 String interfaceName = elanInterface.getName();
580 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
581 addElanInterface(futures, elanInterface, interfaceInfo, elanInstance);
586 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
587 WriteTransaction writeFlowGroupTx) throws ElanException {
588 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
589 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
590 List<DpnInterfaces> dpnInterfaceLists = null;
591 if (elanDpnInterfacesList != null) {
592 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
594 if (dpnInterfaceLists == null) {
595 dpnInterfaceLists = new ArrayList<>();
597 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
598 BigInteger dstDpId = interfaceInfo.getDpId();
599 if (dpnInterfaces.getDpId().equals(dstDpId)) {
602 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
603 for (String remoteIf : remoteElanInterfaces) {
604 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
605 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
606 if (elanIfMac == null) {
609 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
610 if (remoteMacEntries != null) {
611 for (MacEntry macEntry : remoteMacEntries) {
612 String macAddress = macEntry.getMacAddress().getValue();
613 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
614 dstDpId, elanInstance.getElanInstanceName());
615 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
616 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
617 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
624 void addElanInterface(List<ListenableFuture<Void>> futures, ElanInterface elanInterface,
625 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
626 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
627 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
628 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
630 String interfaceName = elanInterface.getName();
631 String elanInstanceName = elanInterface.getElanInstanceName();
633 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
634 WriteTransaction tx = broker.newWriteOnlyTransaction();
635 if (elanInfo == null) {
636 List<String> elanInterfaces = new ArrayList<>();
637 elanInterfaces.add(interfaceName);
638 ElanUtils.updateOperationalDataStore(broker, idManager,
639 elanInstance, elanInterfaces, tx);
641 createElanStateList(elanInstanceName, interfaceName, tx);
643 boolean isFirstInterfaceInDpn = false;
644 // Specific actions to the DPN where the ElanInterface has been added,
645 // for example, programming the
646 // External tunnel table if needed or adding the ElanInterface to the
647 // DpnInterfaces in the operational DS.
648 BigInteger dpId = interfaceInfo != null ? dpId = interfaceInfo.getDpId() : null;
649 DpnInterfaces dpnInterfaces = null;
650 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
651 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
652 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
653 Optional<DpnInterfaces> existingElanDpnInterfaces = elanUtils.read(broker,
654 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
655 if (!existingElanDpnInterfaces.isPresent()) {
656 isFirstInterfaceInDpn = true;
657 // ELAN's 1st ElanInterface added to this DPN
658 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
659 // The 1st ElanInterface in a DPN must program the Ext Tunnel
660 // table, but only if Elan has VNI
661 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
662 setExternalTunnelTable(dpId, elanInstance);
664 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
666 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
667 elanInterfaces.add(interfaceName);
668 if (elanInterfaces.size() == 1) { // 1st dpn interface
669 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
671 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
675 // add code to install Local/Remote BC group, unknow DMAC entry,
676 // terminating service table flow entry
677 // call bindservice of interfacemanager to create ingress table flow
679 // Add interface to the ElanInterfaceForwardingEntires Container
680 createElanInterfaceTablesList(interfaceName, tx);
681 futures.add(ElanUtils.waitForTransactionToComplete(tx));
682 if (interfaceInfo != null) {
683 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces,
684 isFirstInterfaceInDpn, null);
686 // add the vlan provider interface to remote BC group for the elan
687 // for internal vlan networks
688 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
689 if (interfaceManager.isExternalInterface(interfaceName)) {
690 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
691 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
696 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
697 //update the remote-DPNs remoteBC group entry with Tunnels
698 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
699 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
702 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
703 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
704 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
705 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
706 coordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
709 void setupEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInstance,
710 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
711 throws ElanException {
712 String elanInstanceName = elanInstance.getElanInstanceName();
713 String interfaceName = elanInterface.getName();
714 WriteTransaction tx = broker.newWriteOnlyTransaction();
715 BigInteger dpId = interfaceInfo.getDpId();
716 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
717 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
718 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
720 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
721 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
723 boolean isInterfaceOperational = isOperational(interfaceInfo);
724 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
725 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
726 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
727 staticMacEntry.getMacAddress());
728 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
729 LogicalDatastoreType.OPERATIONAL, macId);
730 if (existingMacEntry.isPresent()) {
731 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
732 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
733 existingMacEntry.get(), tx);
735 elanForwardingEntriesHandler
736 .addElanInterfaceForwardingTableList(elanInstance, interfaceName, staticMacEntry, tx);
739 if (isInterfaceOperational) {
740 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
742 String macAddress = staticMacEntry.getMacAddress().getValue();
743 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
744 macAddress, elanInstanceName, interfaceName);
745 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
746 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
750 if (isInterfaceOperational) {
751 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
753 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
754 staticMacAddresses.add(staticMacEntry.getMacAddress());
756 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
760 futures.add(ElanUtils.waitForTransactionToComplete(tx));
761 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
762 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
763 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
765 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
766 if (neutronPort != null) {
767 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
769 } catch (IllegalArgumentException ex) {
770 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
775 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
776 PhysAddress physAddress) {
777 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
778 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
779 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
780 LogicalDatastoreType.OPERATIONAL, macId);
782 if (!existingMacEntry.isPresent()) {
786 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
787 .setKey(new MacEntryKey(physAddress)).build();
788 WriteTransaction tx = broker.newWriteOnlyTransaction();
789 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
790 ElanUtils.getElanInstanceByName(broker, elanInstanceName), interfaceInfo, macEntry, tx);
791 ElanUtils.waitForTransactionToComplete(tx);
794 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
795 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
796 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
799 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
800 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
801 WriteTransaction writeFlowGroupTx) throws ElanException {
802 if (!isOperational(interfaceInfo)) {
805 BigInteger dpId = interfaceInfo.getDpId();
806 if (!elanUtils.isOpenStackVniSemanticsEnforced()) {
807 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
809 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
810 if (isFirstInterfaceInDpn) {
811 // Terminating Service , UnknownDMAC Table.
812 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
813 // for ELAN Instance is VxLAN
814 if (isVxlan(elanInstance)) {
815 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
817 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
819 * Install remote DMAC flow. This is required since this DPN is
820 * added later to the elan instance and remote DMACs of other
821 * interfaces in this elan instance are not present in the current
824 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
825 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
826 elanInstance.getElanInstanceName());
827 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
830 // bind the Elan service to the Interface
831 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
834 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
835 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, WriteTransaction tx) {
836 if (!isOperational(interfaceInfo)) {
839 // LocalBroadcast Group creation with elan-Interfaces
840 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
841 if (isFirstInterfaceInDpn) {
842 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
843 BigInteger dpId = interfaceInfo.getDpId();
844 // RemoteBroadcast Group creation
846 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
847 } catch (InterruptedException e1) {
848 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
850 setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
852 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
853 } catch (InterruptedException e1) {
854 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
859 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
860 WriteTransaction writeFlowGroupTx) {
861 int ifTag = interfaceInfo.getInterfaceTag();
862 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
863 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
864 ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
865 elanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
866 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
868 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
870 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
871 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
872 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
873 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
875 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
878 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
879 WriteTransaction deleteFlowGroupTx) {
880 int ifTag = interfaceInfo.getInterfaceTag();
881 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
882 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
883 ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
884 elanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
885 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
887 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
889 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
890 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
891 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
892 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
894 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
897 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
898 InterfaceInfo interfaceInfo, long elanTag) {
899 return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart, elanTag);
902 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
903 int bucketId, long elanTag) {
904 List<Bucket> listBucketInfo = new ArrayList<>();
905 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
907 if (isVxlan(elanInfo)) {
908 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
909 elanUtils.isOpenStackVniSemanticsEnforced() ? elanInfo.getSegmentationId() : elanTag));
911 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
912 getNextAvailableBucketId(listBucketInfo.size())));
913 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
914 getNextAvailableBucketId(listBucketInfo.size())));
915 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
916 getNextAvailableBucketId(listBucketInfo.size())));
917 return listBucketInfo;
920 private int getNextAvailableBucketId(int bucketSize) {
921 return bucketSize + 1;
924 @SuppressWarnings("checkstyle:IllegalCatch")
925 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
927 List<Bucket> listBucketInfo = new ArrayList<>();
928 if (elanDpns != null) {
929 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
930 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId)
931 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
933 List<Action> listActionInfo = elanUtils.getInternalTunnelItmEgressAction(dpnId,
934 dpnInterface.getDpId(), elanTagOrVni);
935 if (listActionInfo.isEmpty()) {
938 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
939 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
941 } catch (Exception ex) {
942 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
943 dpnId, dpnInterface.getDpId(), ex);
948 return listBucketInfo;
951 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
952 DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
953 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
954 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
955 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
956 return Collections.emptyList();
958 List<Bucket> listBucketInfo = new ArrayList<>();
959 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
960 if (interfaceManager.isExternalInterface(interfaceName)) {
961 List<Action> listActionInfo = elanUtils.getExternalPortItmEgressAction(interfaceName);
962 if (!listActionInfo.isEmpty()) {
963 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
964 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
969 return listBucketInfo;
972 private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
973 if (elanDpns != null) {
974 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
975 if (dpnInterface.getDpId().equals(dpnId)) {
983 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
984 int elanTag = elanInfo.getElanTag().intValue();
985 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
986 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
987 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
988 if (etreeInstance != null) {
989 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
990 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
991 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
995 @SuppressWarnings("checkstyle:IllegalCatch")
996 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
998 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
999 if (elanDpns != null) {
1000 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1001 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1002 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1003 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1004 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1005 List<Action> listAction = new ArrayList<>();
1007 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1008 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1009 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1011 for (DpnInterfaces otherFes : dpnInterfaces) {
1012 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1013 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1014 && !otherFes.getInterfaces().isEmpty()) {
1016 List<Action> remoteListActionInfo = elanUtils.getInternalTunnelItmEgressAction(
1017 dpnInterface.getDpId(), otherFes.getDpId(),
1018 elanUtils.isOpenStackVniSemanticsEnforced() ? elanInfo.getSegmentationId()
1020 if (!remoteListActionInfo.isEmpty()) {
1021 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1022 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1025 } catch (Exception ex) {
1026 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1027 + "Logical Group Interface not found between source Dpn - {}, "
1028 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1033 List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
1035 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1037 if (remoteListBucketInfo.isEmpty()) {
1038 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1041 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1042 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1043 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1044 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group,
1045 ElanConstants.DELAY_TIME_IN_MILLISECOND);
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 public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
1106 List<ListenableFuture<Void>> futures) throws ElanException {
1107 String interfaceName = interfaceInfo.getInterfaceName();
1108 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1109 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1110 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1111 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1112 for (MacEntry macEntry : macEntries) {
1113 String macAddress = macEntry.getMacAddress().getValue();
1114 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1115 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1116 interfaceInfo.getDpId())) {
1117 LOG.info("Acquired lock for mac : " + macAddress + ". Proceeding with remote dmac"
1118 + " install operation.");
1119 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1123 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1127 public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
1128 setupElanBroadcastGroups(elanInfo, null, dpnId);
1131 public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1132 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1133 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1136 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1137 List<Bucket> listBucket = new ArrayList<>();
1140 Long elanTag = elanInfo.getElanTag();
1141 List<Action> listAction = new ArrayList<>();
1142 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1143 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1144 MDSALUtil.WATCH_GROUP));
1146 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
1147 listBucket.addAll(listBucketInfoRemote);
1148 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1149 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1150 MDSALUtil.buildBucketLists(listBucket));
1151 LOG.trace("Installing the remote BroadCast Group:{}", group);
1152 mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
1155 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1156 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1157 if (etreeInstance != null) {
1158 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1159 List<Bucket> listBucket = new ArrayList<>();
1162 List<Action> listAction = new ArrayList<>();
1163 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
1164 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1165 MDSALUtil.WATCH_GROUP));
1167 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
1169 listBucket.addAll(listBucketInfoRemote);
1170 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1171 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1172 MDSALUtil.buildBucketLists(listBucket));
1173 LOG.trace("Installing the remote BroadCast Group:{}", group);
1174 mdsalManager.syncInstallGroup(dpnId, group,
1175 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1179 private void createDropBucket(List<Bucket> listBucket) {
1180 List<Action> actionsInfos = new ArrayList<>();
1181 actionsInfos.add(new ActionDrop().buildAction());
1182 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1183 MDSALUtil.WATCH_GROUP);
1184 listBucket.add(dropBucket);
1187 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1188 InterfaceInfo interfaceInfo) {
1189 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1190 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1193 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1194 InterfaceInfo interfaceInfo) {
1195 List<Bucket> listBucket = new ArrayList<>();
1197 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1199 List<String> interfaces = new ArrayList<>();
1200 if (newDpnInterface != null) {
1201 interfaces = newDpnInterface.getInterfaces();
1203 for (String ifName : interfaces) {
1204 // In case if there is a InterfacePort in the cache which is not in
1205 // operational state, skip processing it
1206 InterfaceInfo ifInfo = interfaceManager
1207 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1208 if (!isOperational(ifInfo)) {
1212 if (!interfaceManager.isExternalInterface(ifName)) {
1213 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1214 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1219 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1220 MDSALUtil.buildBucketLists(listBucket));
1221 LOG.trace("installing the localBroadCast Group:{}", group);
1222 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
1223 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1226 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1227 InterfaceInfo interfaceInfo) {
1228 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1229 if (etreeInstance != null) {
1230 List<Bucket> listBucket = new ArrayList<>();
1233 List<String> interfaces = new ArrayList<>();
1234 if (newDpnInterface != null) {
1235 interfaces = newDpnInterface.getInterfaces();
1237 for (String ifName : interfaces) {
1238 // In case if there is a InterfacePort in the cache which is not
1240 // operational state, skip processing it
1241 InterfaceInfo ifInfo = interfaceManager
1242 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1243 if (!isOperational(ifInfo)) {
1247 if (!interfaceManager.isExternalInterface(ifName)) {
1248 // only add root interfaces
1249 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1253 if (listBucket.isEmpty()) { // No Buckets
1254 createDropBucket(listBucket);
1257 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1258 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1259 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1260 MDSALUtil.buildBucketLists(listBucket));
1261 LOG.trace("installing the localBroadCast Group:{}", group);
1262 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
1263 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1267 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1268 InterfaceInfo ifInfo) {
1269 EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(broker, ifName);
1270 if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1271 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1272 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1278 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1279 WriteTransaction deleteFlowGroupTx) {
1280 BigInteger dpnId = interfaceInfo.getDpId();
1281 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1282 List<Bucket> listBuckets = new ArrayList<>();
1284 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1285 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1287 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1288 MDSALUtil.buildBucketLists(listBuckets));
1289 LOG.trace("deleted the localBroadCast Group:{}", group);
1290 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1293 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1294 WriteTransaction deleteFlowGroupTx) {
1297 Long elanTag = elanInfo.getElanTag();
1298 List<Bucket> listBuckets = new ArrayList<>();
1299 List<Action> listAction = new ArrayList<>();
1300 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1301 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1302 MDSALUtil.WATCH_GROUP));
1304 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1305 BigInteger dpnId = interfaceInfo.getDpId();
1306 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1307 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1308 MDSALUtil.buildBucketLists(listBuckets));
1309 LOG.trace("deleting the remoteBroadCast group:{}", group);
1310 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1314 * Installs a flow in the External Tunnel table consisting in translating
1315 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1316 * elanTag that will be used later in the ELANs pipeline.
1323 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1324 long elanTag = elanInfo.getElanTag();
1325 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1326 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1327 elanInfo.getElanInstanceName(), // flowName
1330 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1331 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1332 getInstructionsIntOrExtTunnelTable(elanTag));
1334 mdsalManager.installFlow(flowEntity);
1338 * Removes, from External Tunnel table, the flow that translates from VNI to
1339 * elanTag. Important: ensure this method is only called whenever there is
1340 * no other ElanInterface in the specified DPN
1343 * DPN whose Ext Tunnel table is going to be modified
1345 * holds the elanTag needed for selecting the flow to be removed
1347 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1348 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1349 // last ElanInstance plus
1350 // adding a new one does (almost at the same time) are executed in that
1353 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1354 FlowEntity flowEntity = new FlowEntityBuilder()
1356 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1359 mdsalManager.removeFlow(flowEntity);
1362 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1363 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1364 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1367 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1368 WriteTransaction writeFlowGroupTx) {
1369 List<? extends MatchInfoBase> listMatchInfoBase;
1370 List<InstructionInfo> instructionInfos;
1372 if (!elanUtils.isOpenStackVniSemanticsEnforced()) {
1373 serviceId = elanTag;
1374 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1375 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1377 serviceId = elanInfo.getSegmentationId();
1378 listMatchInfoBase = buildMatchesForVni(serviceId);
1379 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1381 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1382 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1383 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1385 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1388 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1389 WriteTransaction writeFlowGroupTx) {
1390 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1391 if (etreeInstance != null) {
1392 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1396 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1397 long elanTag = elanInfo.getElanTag();
1398 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1399 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1400 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1403 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1404 WriteTransaction writeFlowGroupTx) {
1405 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
1406 if (etreeLeafTag != null) {
1407 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1408 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1409 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1413 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1414 WriteTransaction writeFlowGroupTx) {
1415 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1416 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1417 5, elanInfo.getElanInstanceName(), 0, 0,
1418 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1419 getMatchesForElanTag(elanTag, /* SH flag */false),
1420 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1422 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1425 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1426 WriteTransaction writeFlowGroupTx) {
1427 // only if ELAN can connect to external network, perform the following
1429 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1430 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1431 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1432 5, elanInfo.getElanInstanceName(), 0, 0,
1433 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1434 getMatchesForElanTag(elanTag, /* SH flag */true),
1435 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1436 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1441 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1443 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1444 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1445 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1447 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1448 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1449 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1451 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1455 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1456 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1459 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1460 if (isStandardElanService(elanInterface)) {
1461 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1462 elanInterface.getName(), lportTag, tx);
1463 } else { // Etree service
1464 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1468 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1469 WriteTransaction tx) {
1470 int instructionKey = 0;
1471 List<Instruction> instructions = new ArrayList<>();
1472 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1473 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1475 List<Action> actions = new ArrayList<>();
1476 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1477 lportTag).buildAction());
1478 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1479 elanTag).buildAction());
1480 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1482 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1485 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1486 BoundServices serviceInfo = ElanUtils.getBoundServices(
1487 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1488 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1489 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1490 Optional<BoundServices> existingElanService = elanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1492 if (!existingElanService.isPresent()) {
1493 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1494 WriteTransaction.CREATE_MISSING_PARENTS);
1498 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1499 WriteTransaction tx) {
1500 if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1501 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1504 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1505 if (etreeInstance == null) {
1506 LOG.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
1507 + elanInfo.getElanInstanceName());
1509 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1510 elanInterface.getName(), lportTag, tx);
1515 private boolean isStandardElanService(ElanInterface elanInterface) {
1516 return elanInterface.getAugmentation(EtreeInterface.class) == null;
1519 private boolean isStandardElanService(ElanInstance elanInstance) {
1520 return elanInstance.getAugmentation(EtreeInstance.class) == null;
1523 protected void unbindService(String interfaceName, WriteTransaction tx) {
1524 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1525 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1526 Optional<BoundServices> existingElanService = elanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1528 if (existingElanService.isPresent()) {
1529 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1533 private String getFlowRef(long tableId, long elanTag) {
1534 return String.valueOf(tableId) + elanTag;
1537 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1538 return String.valueOf(tableId) + elanTag + shFlag;
1541 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1542 List<Action> listAction = new ArrayList<>();
1545 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1547 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1551 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1552 List<String> interfaceNames, WriteTransaction tx) {
1553 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1554 .setKey(new DpnInterfacesKey(dpId)).build();
1555 tx.put(LogicalDatastoreType.OPERATIONAL,
1556 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1557 WriteTransaction.CREATE_MISSING_PARENTS);
1558 return dpnInterface;
1562 * Delete elan dpn interface from operational DS.
1564 * @param elanInstanceName
1565 * the elan instance name
1569 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1570 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1571 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1572 Optional<DpnInterfaces> dpnInterfaces = elanUtils.read(broker,
1573 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1574 if (dpnInterfaces.isPresent()) {
1575 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1579 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1580 WriteTransaction tx) {
1581 List<String> interfaceNames = new ArrayList<>();
1582 interfaceNames.add(interfaceName);
1583 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1584 .setKey(new DpnInterfacesKey(dpId)).build();
1585 tx.put(LogicalDatastoreType.OPERATIONAL,
1586 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1587 WriteTransaction.CREATE_MISSING_PARENTS);
1588 return dpnInterface;
1591 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1592 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1593 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1594 Optional<ElanInterfaceMac> interfaceMacTables = elanUtils.read(broker,
1595 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1596 // Adding new Elan Interface Port to the operational DataStore without
1597 // Static-Mac Entries..
1598 if (!interfaceMacTables.isPresent()) {
1599 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1600 .setKey(new ElanInterfaceMacKey(interfaceName)).build();
1601 tx.put(LogicalDatastoreType.OPERATIONAL,
1602 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1603 WriteTransaction.CREATE_MISSING_PARENTS);
1607 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1608 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1609 Optional<Elan> elanInterfaceLists = elanUtils.read(broker,
1610 LogicalDatastoreType.OPERATIONAL, elanInstance);
1611 // Adding new Elan Interface Port to the operational DataStore without
1612 // Static-Mac Entries..
1613 if (elanInterfaceLists.isPresent()) {
1614 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1615 if (interfaceLists == null) {
1616 interfaceLists = new ArrayList<>();
1618 interfaceLists.add(interfaceName);
1619 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1620 .setKey(new ElanKey(elanInstanceName)).build();
1621 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1622 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1626 private boolean isOperational(InterfaceInfo interfaceInfo) {
1627 if (interfaceInfo == null) {
1630 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1633 @SuppressWarnings("checkstyle:IllegalCatch")
1634 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) throws ElanException {
1635 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1636 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1637 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1638 if (dpnInterfaceLists == null) {
1641 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1642 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1644 String elanName = elanDpns.getElanInstanceName();
1645 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1646 if (elanInfo == null) {
1647 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1648 + "skipping this ELAN for tunnel handling", elanName);
1651 if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) {
1652 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1655 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1656 if (dpnInterfaces == null) {
1659 DpnInterfaces dstDpnIf = null;
1660 for (DpnInterfaces dpnIf : dpnInterfaces) {
1661 BigInteger dpnIfDpId = dpnIf.getDpId();
1662 if (dpnIfDpId.equals(srcDpId)) {
1664 } else if (dpnIfDpId.equals(dstDpId)) {
1670 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1671 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1672 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1673 dataStoreCoordinator.enqueueJob(elanName, () -> {
1674 // update Remote BC Group
1675 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1676 List<ListenableFuture<Void>> elanFutures = new ArrayList<>();
1678 setupElanBroadcastGroups(elanInfo, srcDpId);
1679 } catch (RuntimeException e) {
1680 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1681 ElanUtils.addToListenableFutureIfTxException(e, elanFutures);
1683 Set<String> interfaceLists = new HashSet<>();
1684 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1685 for (String ifName : interfaceLists) {
1686 dataStoreCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1687 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1688 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1689 List<ListenableFuture<Void>> elanInterfacefutures = new ArrayList<>();
1690 if (isOperational(interfaceInfo)) {
1691 installDMacAddressTables(elanInfo, interfaceInfo, srcDpId, elanInterfacefutures);
1693 return elanInterfacefutures;
1694 }, ElanConstants.JOB_MAX_RETRIES);
1697 }, ElanConstants.JOB_MAX_RETRIES);
1704 * Handle external tunnel state event.
1706 * @param externalTunnel
1707 * the external tunnel
1710 * @throws ElanException in case of issues creating the flow objects
1712 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1713 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1716 // dpId/externalNodeId will be available either in source or destination
1717 // based on the tunnel end point
1718 BigInteger dpId = null;
1719 NodeId externalNodeId = null;
1720 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1721 dpId = new BigInteger(externalTunnel.getSourceDevice());
1722 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1723 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1724 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1725 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1727 if (dpId == null || externalNodeId == null) {
1728 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1732 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1733 if (dpnInterfaceLists == null) {
1736 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1737 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1738 String elanName = elanDpns.getElanInstanceName();
1739 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1741 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1742 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1743 || dpnInterfaces.getInterfaces().isEmpty()) {
1746 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1748 setupElanBroadcastGroups(elanInfo, dpId);
1749 // install L2gwDevices local macs in dpn.
1750 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1751 // Install dpn macs on external device
1752 elanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1755 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1759 * Validate external tunnel state event.
1761 * @param externalTunnel
1762 * the external tunnel
1765 * @return true, if successful
1767 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1768 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1769 String srcDevice = externalTunnel.getDestinationDevice();
1770 String destDevice = externalTunnel.getSourceDevice();
1771 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1772 LogicalDatastoreType.CONFIGURATION);
1773 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1774 otherEndPointExtTunnel);
1775 if (otherEndPointExtTunnel != null) {
1776 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1777 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1778 if (otherEndPointInterfaceOperational) {
1781 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1782 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1789 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1790 List<MatchInfo> mkMatches = new ArrayList<>();
1791 // Matching metadata
1793 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1794 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1798 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
1799 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
1803 for (DpnInterfaces dpn : dpns) {
1804 setupElanBroadcastGroups(elanInfo, dpn.getDpId());
1808 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
1810 List<Bucket> listBucketInfo = new ArrayList<>();
1811 ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
1812 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
1813 for (L2GatewayDevice device : map.values()) {
1814 String interfaceName = elanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1815 device.getHwvtepNodeId());
1816 if (interfaceName == null) {
1819 List<Action> listActionInfo = elanUtils.buildTunnelItmEgressActions(interfaceName,
1820 ElanUtils.getVxlanSegmentationId(elanInfo));
1821 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1822 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1825 return listBucketInfo;
1828 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
1830 List<Bucket> listBucketInfo = new ArrayList<>();
1831 List<ExternalTeps> teps = elanInfo.getExternalTeps();
1832 if (teps == null || teps.isEmpty()) {
1833 return listBucketInfo;
1835 for (ExternalTeps tep : teps) {
1836 String interfaceName = elanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1837 tep.getTepIp().toString());
1838 if (interfaceName == null) {
1839 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
1842 List<Action> listActionInfo = elanUtils.buildTunnelItmEgressActions(interfaceName,
1843 elanInfo.getSegmentationId());
1844 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1845 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1848 return listBucketInfo;
1852 protected ElanInterfaceManager getDataTreeChangeListener() {
1856 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1858 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1859 setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1861 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1862 } catch (InterruptedException e) {
1863 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);