2 * Copyright (c) 2016 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 com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.List;
19 import java.util.Objects;
20 import java.util.Queue;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentLinkedQueue;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.stream.Collectors;
27 import org.apache.commons.lang3.StringUtils;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
32 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
33 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
34 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
35 import org.opendaylight.genius.itm.globals.ITMConstants;
36 import org.opendaylight.genius.mdsalutil.ActionInfo;
37 import org.opendaylight.genius.mdsalutil.ActionType;
38 import org.opendaylight.genius.mdsalutil.FlowEntity;
39 import org.opendaylight.genius.mdsalutil.InstructionInfo;
40 import org.opendaylight.genius.mdsalutil.InstructionType;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.genius.mdsalutil.MatchFieldType;
43 import org.opendaylight.genius.mdsalutil.MatchInfo;
44 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
45 import org.opendaylight.genius.mdsalutil.NwConstants;
46 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
47 import org.opendaylight.genius.utils.ServiceIndex;
48 import org.opendaylight.netvirt.elan.ElanException;
49 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
50 import org.opendaylight.netvirt.elan.utils.ElanConstants;
51 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
52 import org.opendaylight.netvirt.elan.utils.ElanUtils;
53 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
54 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
94 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
99 * Class in charge of handling creations, modifications and removals of
102 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
104 @SuppressWarnings("deprecation")
105 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
106 implements AutoCloseable {
108 private final DataBroker broker;
109 private final IMdsalApiManager mdsalManager;
110 private final IInterfaceManager interfaceManager;
111 private final IdManagerService idManager;
112 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
113 private ElanL2GatewayUtils elanL2GatewayUtils;
114 private ElanUtils elanUtils;
116 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
118 private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces = new ConcurrentHashMap<>();
120 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
122 public ElanInterfaceManager(final DataBroker dataBroker,
123 final IdManagerService managerService,
124 final IMdsalApiManager mdsalApiManager,
125 IInterfaceManager interfaceManager,
126 final ElanForwardingEntriesHandler elanForwardingEntriesHandler) {
127 super(ElanInterface.class, ElanInterfaceManager.class);
128 this.broker = dataBroker;
129 this.idManager = managerService;
130 this.mdsalManager = mdsalApiManager;
131 this.interfaceManager = interfaceManager;
132 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
135 public void setElanUtils(ElanUtils elanUtils) {
136 this.elanUtils = elanUtils;
137 this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
138 this.elanForwardingEntriesHandler.setElanUtils(elanUtils);
143 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
147 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
148 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
152 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
153 String interfaceName = del.getName();
154 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, del.getElanInstanceName());
156 * Handling in case the elan instance is deleted.If the Elan instance is
157 * deleted, there is no need to explicitly delete the elan interfaces
159 if (elanInfo == null) {
162 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
163 String elanInstanceName = elanInfo.getElanInstanceName();
164 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
165 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
166 interfaceName, interfaceInfo, false, this);
167 coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
170 public void removeElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, String interfaceName,
171 InterfaceInfo interfaceInfo, boolean isInterfaceStateRemoved) {
172 String elanName = elanInfo.getElanInstanceName();
173 boolean isLastElanInterface = false;
174 boolean isLastInterfaceOnDpn = false;
175 BigInteger dpId = null;
176 long elanTag = elanInfo.getElanTag();
177 WriteTransaction tx = broker.newWriteOnlyTransaction();
178 WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
179 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, tx);
180 if (elanState == null) {
183 List<String> elanInterfaces = elanState.getElanInterfaces();
184 if (elanInterfaces.size() == 0) {
185 isLastElanInterface = true;
187 if (interfaceInfo != null) {
188 dpId = interfaceInfo.getDpId();
189 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName,
192 * If there are not elan ports, remove the unknown dmac, terminating
193 * service table flows, remote/local bc group
195 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
196 || dpnInterfaces.getInterfaces().isEmpty()) {
197 // No more Elan Interfaces in this DPN
198 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
199 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
200 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, elanInfo.getElanTag());
201 removeEtreeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx);
202 removeElanBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
203 removeLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
204 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, deleteFlowGroupTx);
205 if (ElanUtils.isVxlan(elanInfo)) {
206 unsetExternalTunnelTable(dpId, elanInfo);
208 isLastInterfaceOnDpn = true;
210 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
213 futures.add(ElanUtils.waitForTransactionToComplete(tx));
214 futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
215 if (isLastInterfaceOnDpn && dpId != null && ElanUtils.isVxlan(elanInfo)) {
216 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
218 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
219 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
220 interfaceName, elanInfo, interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
221 coordinator.enqueueJob(interfaceName, removeInterfaceWorker, ElanConstants.JOB_MAX_RETRIES);
224 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
225 WriteTransaction deleteFlowGroupTx) {
226 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
227 if (etreeLeafTag != null) {
228 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
229 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
233 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
234 WriteTransaction deleteFlowGroupTx) {
235 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
236 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
239 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
240 WriteTransaction deleteFlowGroupTx) {
241 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
242 if (etreeInstance != null) {
243 BigInteger dpnId = interfaceInfo.getDpId();
244 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
245 List<Bucket> listBuckets = new ArrayList<>();
247 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
248 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
249 MDSALUtil.buildBucketLists(listBuckets));
250 LOG.trace("deleted the localBroadCast Group:{}", group);
251 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
255 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
256 WriteTransaction deleteFlowGroupTx) {
257 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
258 if (etreeInstance != null) {
259 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
262 List<Bucket> listBuckets = new ArrayList<>();
263 List<Action> listAction = new ArrayList<>();
264 listAction.add(new ActionInfo(ActionType.group,
265 new String[] { String.valueOf(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)) }, ++actionKey)
267 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
268 MDSALUtil.WATCH_GROUP));
270 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
271 BigInteger dpnId = interfaceInfo.getDpId();
272 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
273 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
274 MDSALUtil.buildBucketLists(listBuckets));
275 LOG.trace("deleting the remoteBroadCast group:{}", group);
276 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
280 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
281 String elanName = elanInfo.getElanInstanceName();
282 Elan elanState = ElanUtils.getElanByName(broker, elanName);
283 if (elanState == null) {
286 List<String> elanInterfaces = elanState.getElanInterfaces();
287 elanInterfaces.remove(interfaceName);
288 if (elanInterfaces.isEmpty()) {
289 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
290 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
291 tx.delete(LogicalDatastoreType.OPERATIONAL,
292 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
294 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
295 .setKey(new ElanKey(elanName)).build();
296 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
302 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
303 // removing the ElanInterface from the config data_store if interface is
304 // not present in Interface config DS
305 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
306 && ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName) != null) {
307 tx.delete(LogicalDatastoreType.CONFIGURATION,
308 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
312 void removeEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo,
313 InterfaceInfo interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved,
314 boolean isLastElanInterface) {
315 String elanName = elanInfo.getElanInstanceName();
316 WriteTransaction tx = broker.newWriteOnlyTransaction();
317 WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
318 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
319 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
320 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
321 if (interfaceInfo != null) {
322 Optional<ElanInterfaceMac> existingElanInterfaceMac = elanUtils.read(broker,
323 LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
324 if (existingElanInterfaceMac.isPresent()) {
325 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
326 List<MacEntry> macEntries = new ArrayList<>();
327 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
328 macEntries.addAll(existingMacEntries);
330 List<PhysAddress> macAddresses = macEntries.stream().map(macEntry -> {
331 PhysAddress macAddress = macEntry.getMacAddress();
332 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
333 macAddress.getValue(), interfaceName);
334 Optional<MacEntry> macEntryOptional = elanUtils.getMacEntryForElanInstance(elanName,
336 if (!isLastElanInterface && macEntryOptional.isPresent()) {
337 tx.delete(LogicalDatastoreType.OPERATIONAL,
338 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
340 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
342 } ).collect(Collectors.toList());
344 // Removing all those MACs from External Devices belonging
346 if (ElanUtils.isVxlan(elanInfo) && ! macAddresses.isEmpty()) {
347 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
350 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
351 removeFilterEqualsTable(elanInfo, interfaceInfo, deleteFlowGroupTx);
353 // Interface does not exist in ConfigDS, so lets remove everything
354 // about that interface related to Elan
355 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
356 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
357 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
358 macEntries.stream().forEach(macEntry -> {
359 PhysAddress macAddress = macEntry.getMacAddress();
360 Optional<MacEntry> macEntryOptional = elanUtils.getMacEntryForElanInstance(elanName,
362 if (macEntryOptional.isPresent()) {
363 tx.delete(LogicalDatastoreType.OPERATIONAL,
364 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
369 tx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
370 if (!isInterfaceStateRemoved) {
371 unbindService(elanInfo, interfaceName, tx);
373 deleteElanInterfaceFromConfigDS(interfaceName, tx);
374 futures.add(ElanUtils.waitForTransactionToComplete(tx));
375 futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
378 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
379 String interfaceName, long elanTag, WriteTransaction tx) {
380 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
381 if (dpnInterfaces != null) {
382 List<String> interfaceLists = dpnInterfaces.getInterfaces();
383 interfaceLists.remove(interfaceName);
385 if (interfaceLists == null || interfaceLists.isEmpty()) {
386 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
387 deleteElanDpnInterface(elanName, dpId, tx);
389 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
392 return dpnInterfaces;
395 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
396 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
397 for (DpnInterfaces dpnInterface : dpnInterfaces) {
398 BigInteger currentDpId = dpnInterface.getDpId();
399 if (!currentDpId.equals(dpId)) {
400 for (String elanInterface : dpnInterface.getInterfaces()) {
401 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
402 if (macs == null || macs.getMacEntry() == null) {
405 for (MacEntry mac : macs.getMacEntry()) {
406 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
407 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
414 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
415 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
416 if (etreeLeafTag != null) {
417 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
421 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
424 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
425 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
426 mac.getMacAddress().getValue(), elanTag)));
430 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
431 // updating the static-Mac Entries for the existing elanInterface
432 String elanName = update.getElanInstanceName();
433 String interfaceName = update.getName();
434 List<PhysAddress> existingPhysAddress = original.getStaticMacEntries();
435 List<PhysAddress> updatedPhysAddress = update.getStaticMacEntries();
436 if (updatedPhysAddress != null && !updatedPhysAddress.isEmpty()) {
437 List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
438 if (existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
439 existingClonedPhyAddress.addAll(0, existingPhysAddress);
440 existingPhysAddress.removeAll(updatedPhysAddress);
441 updatedPhysAddress.removeAll(existingClonedPhyAddress);
442 // removing the PhyAddress which are not presented in the
444 for (PhysAddress physAddress : existingPhysAddress) {
445 removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
448 // Adding the new PhysAddress which are presented in the updated
450 if (updatedPhysAddress.size() > 0) {
451 for (PhysAddress physAddress : updatedPhysAddress) {
452 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
453 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
454 LogicalDatastoreType.OPERATIONAL, macId);
455 WriteTransaction tx = broker.newWriteOnlyTransaction();
456 if (existingMacEntry.isPresent()) {
457 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
458 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
461 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
462 ElanUtils.getElanInstanceByName(broker, elanName), interfaceName, physAddress, tx);
464 ElanUtils.waitForTransactionToComplete(tx);
467 } else if (existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
468 for (PhysAddress physAddress : existingPhysAddress) {
469 removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
475 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
476 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
477 String interfaceName = elanInterfaceAdded.getName();
478 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
479 if (interfaceInfo == null) {
480 LOG.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
483 ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
485 if (elanInstance == null) {
486 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
487 .setDescription(elanInterfaceAdded.getDescription()).build();
488 // Add the ElanInstance in the Configuration data-store
489 WriteTransaction tx = broker.newWriteOnlyTransaction();
490 List<String> elanInterfaces = new ArrayList<>();
491 elanInterfaces.add(interfaceName);
492 ElanUtils.updateOperationalDataStore(broker, idManager,
493 elanInstance, elanInterfaces, tx);
494 ElanUtils.waitForTransactionToComplete(tx);
495 elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
498 Long elanTag = elanInstance.getElanTag();
499 // If elan tag is not updated, then put the elan interface into
500 // unprocessed entry map and entry. Let entries
501 // in this map get processed during ELAN update DCN.
502 if (elanTag == null) {
503 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
504 if (elanInterfaces == null) {
505 elanInterfaces = new ConcurrentLinkedQueue<>();
507 elanInterfaces.add(elanInterfaceAdded);
508 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
511 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
512 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
513 interfaceInfo, elanInstance, this);
514 coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
517 void handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
518 List<ListenableFuture<Void>> futures = new ArrayList<>();
519 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
520 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
523 for (ElanInterface elanInterface : elanInterfaces) {
524 String interfaceName = elanInterface.getName();
525 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
526 addElanInterface(futures, elanInterface, interfaceInfo, elanInstance);
530 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
531 WriteTransaction writeFlowGroupTx) throws ElanException {
532 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
533 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
534 List<DpnInterfaces> dpnInterfaceLists = null;
535 if (elanDpnInterfacesList != null) {
536 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
538 if (dpnInterfaceLists == null) {
539 dpnInterfaceLists = new ArrayList<>();
541 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
542 if (dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
545 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
546 for (String remoteIf : remoteElanInterfaces) {
547 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
548 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
549 if (elanIfMac == null) {
552 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
553 if (remoteMacEntries != null) {
554 for (MacEntry macEntry : remoteMacEntries) {
555 PhysAddress physAddress = macEntry.getMacAddress();
556 elanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
557 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), physAddress.getValue(),
558 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
565 void addElanInterface(List<ListenableFuture<Void>> futures, ElanInterface elanInterface,
566 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
567 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
568 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
569 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
571 String interfaceName = elanInterface.getName();
572 String elanInstanceName = elanInterface.getElanInstanceName();
574 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
575 WriteTransaction tx = broker.newWriteOnlyTransaction();
576 if (elanInfo == null) {
577 List<String> elanInterfaces = new ArrayList<>();
578 elanInterfaces.add(interfaceName);
579 ElanUtils.updateOperationalDataStore(broker, idManager,
580 elanInstance, elanInterfaces, tx);
582 createElanStateList(elanInstanceName, interfaceName, tx);
584 boolean isFirstInterfaceInDpn = false;
585 // Specific actions to the DPN where the ElanInterface has been added,
586 // for example, programming the
587 // External tunnel table if needed or adding the ElanInterface to the
588 // DpnInterfaces in the operational DS.
589 BigInteger dpId = interfaceInfo != null ? dpId = interfaceInfo.getDpId() : null;
590 DpnInterfaces dpnInterfaces = null;
591 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
592 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
593 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
594 Optional<DpnInterfaces> existingElanDpnInterfaces = elanUtils.read(broker,
595 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
596 if (!existingElanDpnInterfaces.isPresent()) {
597 isFirstInterfaceInDpn = true;
598 // ELAN's 1st ElanInterface added to this DPN
599 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
600 // The 1st ElanInterface in a DPN must program the Ext Tunnel
601 // table, but only if Elan has VNI
602 if (ElanUtils.isVxlan(elanInstance)) {
603 setExternalTunnelTable(dpId, elanInstance);
605 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
607 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
608 elanInterfaces.add(interfaceName);
609 if (elanInterfaces.size() == 1) { // 1st dpn interface
610 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
612 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
616 // add code to install Local/Remote BC group, unknow DMAC entry,
617 // terminating service table flow entry
618 // call bindservice of interfacemanager to create ingress table flow
620 // Add interface to the ElanInterfaceForwardingEntires Container
621 createElanInterfaceTablesList(interfaceName, tx);
622 if (interfaceInfo != null) {
623 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn, tx);
625 futures.add(ElanUtils.waitForTransactionToComplete(tx));
626 if (isFirstInterfaceInDpn && ElanUtils.isVxlan(elanInstance)) {
627 //update the remote-DPNs remoteBC group entry with Tunnels
628 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
631 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
632 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(interfaceName,
633 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
634 coordinator.enqueueJob(interfaceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
637 void setupEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInstance,
638 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
639 throws ElanException {
640 String elanInstanceName = elanInstance.getElanInstanceName();
641 String interfaceName = elanInterface.getName();
642 WriteTransaction tx = broker.newWriteOnlyTransaction();
643 BigInteger dpId = interfaceInfo.getDpId();
644 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
645 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
646 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
647 List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
648 if (staticMacAddresses != null) {
649 boolean isInterfaceOperational = isOperational(interfaceInfo);
650 for (PhysAddress physAddress : staticMacAddresses) {
651 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
652 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
653 LogicalDatastoreType.OPERATIONAL, macId);
654 if (existingMacEntry.isPresent()) {
655 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
656 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
657 existingMacEntry.get(), tx);
659 elanForwardingEntriesHandler
660 .addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress, tx);
663 if (isInterfaceOperational) {
664 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
666 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
667 physAddress.getValue(), true, writeFlowGroupTx);
671 if (isInterfaceOperational) {
672 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
674 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
678 futures.add(ElanUtils.waitForTransactionToComplete(tx));
679 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
682 protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName,
683 PhysAddress physAddress) {
684 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
685 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
686 Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
687 LogicalDatastoreType.OPERATIONAL, macId);
689 if (!existingMacEntry.isPresent()) {
693 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
694 .setKey(new MacEntryKey(physAddress)).build();
695 WriteTransaction tx = broker.newWriteOnlyTransaction();
696 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
697 ElanUtils.getElanInstanceByName(broker, elanInstanceName), interfaceInfo, macEntry, tx);
698 elanForwardingEntriesHandler.deleteElanInterfaceMacForwardingEntries(interfaceName,
700 ElanUtils.waitForTransactionToComplete(tx);
703 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
704 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
705 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
708 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
709 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
710 WriteTransaction writeFlowGroupTx) throws ElanException {
711 if (!isOperational(interfaceInfo)) {
714 BigInteger dpId = interfaceInfo.getDpId();
715 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
716 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
717 if (isFirstInterfaceInDpn) {
718 // Terminating Service , UnknownDMAC Table.
719 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
720 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
722 * Install remote DMAC flow. This is required since this DPN is
723 * added later to the elan instance and remote DMACs of other
724 * interfaces in this elan instance are not present in the current
727 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
729 // bind the Elan service to the Interface
730 bindService(elanInstance, elanInterface, tx);
733 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
734 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, WriteTransaction tx) {
735 if (!isOperational(interfaceInfo)) {
738 // LocalBroadcast Group creation with elan-Interfaces
739 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
740 if (isFirstInterfaceInDpn) {
741 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
742 BigInteger dpId = interfaceInfo.getDpId();
743 // RemoteBroadcast Group creation
745 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
746 } catch (InterruptedException e1) {
747 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
749 setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
751 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
752 } catch (InterruptedException e1) {
753 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
758 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
759 WriteTransaction writeFlowGroupTx) {
760 int ifTag = interfaceInfo.getInterfaceTag();
761 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
762 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
763 ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
764 getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
765 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
767 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
769 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
770 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
771 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
772 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
774 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
777 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
778 WriteTransaction deleteFlowGroupTx) {
779 int ifTag = interfaceInfo.getInterfaceTag();
780 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
781 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
782 ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
783 getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
784 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
786 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
788 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
789 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
790 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
791 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
793 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
796 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
797 InterfaceInfo interfaceInfo, long elanTag) {
798 return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart, elanTag);
801 private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
802 int bucketId, long elanTag) {
803 List<Bucket> listBucketInfo = new ArrayList<>();
804 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
805 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId, elanTag));
806 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
807 getNextAvailableBucketId(listBucketInfo.size())));
808 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
809 getNextAvailableBucketId(listBucketInfo.size())));
810 return listBucketInfo;
813 private int getNextAvailableBucketId(int bucketSize) {
814 return bucketSize + 1;
817 @SuppressWarnings("checkstyle:IllegalCatch")
818 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
820 List<Bucket> listBucketInfo = new ArrayList<>();
821 if (elanDpns != null) {
822 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
823 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId)
824 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
826 List<Action> listActionInfo = elanUtils.getInternalTunnelItmEgressAction(dpnId,
827 dpnInterface.getDpId(), elanTag);
828 if (listActionInfo.isEmpty()) {
831 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
832 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
834 } catch (Exception ex) {
835 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
836 dpnId, dpnInterface.getDpId(), ex);
841 return listBucketInfo;
844 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
845 DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
846 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
847 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
848 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
849 return Collections.emptyList();
852 List<Bucket> listBucketInfo = new ArrayList<>();
853 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
854 if (interfaceManager.isExternalInterface(interfaceName)) {
855 List<Action> listActionInfo = elanUtils.getExternalPortItmEgressAction(interfaceName);
856 if (!listActionInfo.isEmpty()) {
857 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
858 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
863 return listBucketInfo;
866 private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
867 if (elanDpns != null) {
868 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
869 if (dpnInterface.getDpId().equals(dpnId)) {
877 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
878 int elanTag = elanInfo.getElanTag().intValue();
879 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
880 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
881 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
882 if (etreeInstance != null) {
883 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
884 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
885 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
890 @SuppressWarnings("checkstyle:IllegalCatch")
891 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
893 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
894 if (elanDpns != null) {
895 List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
896 for (DpnInterfaces dpnInterface : dpnInterfaceses) {
897 List<Bucket> remoteListBucketInfo = new ArrayList<>();
898 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(),dpId)
899 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
900 List<Action> listAction = new ArrayList<>();
902 listAction.add(new ActionInfo(ActionType.group,
903 new String[] { String.valueOf(ElanUtils.getElanLocalBCGId(elanTag)) }, ++actionKey)
905 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
906 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
908 for (DpnInterfaces otherFes : dpnInterfaceses) {
909 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
910 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
911 && !otherFes.getInterfaces().isEmpty()) {
913 List<Action> remoteListActionInfo = elanUtils.getInternalTunnelItmEgressAction(
914 dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
915 if (!remoteListActionInfo.isEmpty()) {
917 .add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT,
918 bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
921 } catch (Exception ex) {
922 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
923 + "Logical Group Interface not found between source Dpn - {}, "
924 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
929 List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
931 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
933 if (remoteListBucketInfo.size() == 0) {
934 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
937 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
938 MDSALUtil.buildBucketLists(remoteListBucketInfo));
939 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group,
940 ElanConstants.DELAY_TIME_IN_MILLISECOND);
944 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
945 } catch (InterruptedException e1) {
946 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
952 * Returns the bucket info with the given interface as the only bucket.
954 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
955 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
956 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
959 private List<MatchInfo> buildMatchesForVni(Long vni) {
960 List<MatchInfo> mkMatches = new ArrayList<>();
961 MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(vni) });
962 mkMatches.add(match);
966 private List<Instruction> getInstructionsForOutGroup(long groupId) {
967 List<Instruction> mkInstructions = new ArrayList<>();
968 List<Action> actions = new ArrayList<>();
969 actions.add(new ActionInfo(ActionType.group, new String[] { Long.toString(groupId) }).buildAction());
970 mkInstructions.add(MDSALUtil.getWriteActionsInstruction(actions, 0));
971 return mkInstructions;
974 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
975 List<MatchInfo> mkMatches = new ArrayList<>();
977 mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
978 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG }));
983 * Builds the list of instructions to be installed in the External Tunnel
984 * table (38), which so far consists in writing the elanTag in metadata and
985 * send packet to the new DHCP table.
988 * elanTag to be written in metadata when flow is selected
989 * @return the instructions ready to be installed in a flow
991 private List<InstructionInfo> getInstructionsExtTunnelTable(Long elanTag) {
992 List<InstructionInfo> mkInstructions = new ArrayList<>();
993 mkInstructions.add(new InstructionInfo(InstructionType.write_metadata,
994 new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), ElanUtils.getElanMetadataMask() }));
995 // TODO: We should point to SMAC or DMAC depending on a configuration
996 // property to enable
998 mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.ELAN_DMAC_TABLE }));
1000 return mkInstructions;
1003 // Install DMAC entry on dst DPN
1004 public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId)
1005 throws ElanException {
1006 String interfaceName = interfaceInfo.getInterfaceName();
1007 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1008 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1009 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1010 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1011 for (MacEntry macEntry : macEntries) {
1012 PhysAddress physAddress = macEntry.getMacAddress();
1013 elanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue(),
1016 writeFlowTx.submit();
1020 public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
1021 setupElanBroadcastGroups(elanInfo, null, dpnId);
1024 public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1025 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1026 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1029 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1030 List<Bucket> listBucket = new ArrayList<>();
1033 Long elanTag = elanInfo.getElanTag();
1034 List<Action> listAction = new ArrayList<>();
1035 listAction.add(new ActionInfo(ActionType.group,
1036 new String[] { String.valueOf(ElanUtils.getElanLocalBCGId(elanTag)) }, ++actionKey).buildAction());
1037 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1038 MDSALUtil.WATCH_GROUP));
1040 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
1041 elanInfo.getElanTag());
1042 listBucket.addAll(listBucketInfoRemote);
1043 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1044 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1045 MDSALUtil.buildBucketLists(listBucket));
1046 LOG.trace("Installing the remote BroadCast Group:{}", group);
1047 mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
1050 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1051 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1052 if (etreeInstance != null) {
1053 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1054 List<Bucket> listBucket = new ArrayList<>();
1057 List<Action> listAction = new ArrayList<>();
1058 listAction.add(new ActionInfo(ActionType.group,
1059 new String[] { String.valueOf(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)) }, ++actionKey)
1061 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1062 MDSALUtil.WATCH_GROUP));
1064 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
1066 listBucket.addAll(listBucketInfoRemote);
1067 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1068 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1069 MDSALUtil.buildBucketLists(listBucket));
1070 LOG.trace("Installing the remote BroadCast Group:{}", group);
1071 mdsalManager.syncInstallGroup(dpnId, group,
1072 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1076 private void createDropBucket(List<Bucket> listBucket) {
1077 List<Action> actionsInfos = new ArrayList<>();
1078 actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}).buildAction());
1079 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1080 MDSALUtil.WATCH_GROUP);
1081 listBucket.add(dropBucket);
1084 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1085 InterfaceInfo interfaceInfo) {
1086 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1087 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1090 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1091 InterfaceInfo interfaceInfo) {
1092 List<Bucket> listBucket = new ArrayList<>();
1094 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1096 List<String> interfaces = new ArrayList<>();
1097 if (newDpnInterface != null) {
1098 interfaces = newDpnInterface.getInterfaces();
1100 for (String ifName : interfaces) {
1101 // In case if there is a InterfacePort in the cache which is not in
1102 // operational state, skip processing it
1103 InterfaceInfo ifInfo = interfaceManager
1104 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1105 if (!isOperational(ifInfo)) {
1109 if (!interfaceManager.isExternalInterface(ifName)) {
1110 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1111 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1116 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1117 MDSALUtil.buildBucketLists(listBucket));
1118 LOG.trace("installing the localBroadCast Group:{}", group);
1119 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
1120 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1123 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1124 InterfaceInfo interfaceInfo) {
1125 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1126 if (etreeInstance != null) {
1127 List<Bucket> listBucket = new ArrayList<>();
1130 List<String> interfaces = new ArrayList<>();
1131 if (newDpnInterface != null) {
1132 interfaces = newDpnInterface.getInterfaces();
1134 for (String ifName : interfaces) {
1135 // In case if there is a InterfacePort in the cache which is not
1137 // operational state, skip processing it
1138 InterfaceInfo ifInfo = interfaceManager
1139 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1140 if (!isOperational(ifInfo)) {
1144 if (!interfaceManager.isExternalInterface(ifName)) {
1145 // only add root interfaces
1146 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1150 if (listBucket.size() == 0) { // No Buckets
1151 createDropBucket(listBucket);
1154 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1155 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1156 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1157 MDSALUtil.buildBucketLists(listBucket));
1158 LOG.trace("installing the localBroadCast Group:{}", group);
1159 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
1160 ElanConstants.DELAY_TIME_IN_MILLISECOND);
1164 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1165 InterfaceInfo ifInfo) {
1166 EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(broker, ifName);
1167 if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1168 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1169 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1175 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1176 WriteTransaction deleteFlowGroupTx) {
1177 BigInteger dpnId = interfaceInfo.getDpId();
1178 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1179 List<Bucket> listBuckets = new ArrayList<>();
1181 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1182 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1184 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1185 MDSALUtil.buildBucketLists(listBuckets));
1186 LOG.trace("deleted the localBroadCast Group:{}", group);
1187 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1190 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1191 WriteTransaction deleteFlowGroupTx) {
1194 Long elanTag = elanInfo.getElanTag();
1195 List<Bucket> listBuckets = new ArrayList<>();
1196 List<Action> listAction = new ArrayList<>();
1197 listAction.add(new ActionInfo(ActionType.group,
1198 new String[] { String.valueOf(ElanUtils.getElanLocalBCGId(elanTag)) }, ++actionKey).buildAction());
1199 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1200 MDSALUtil.WATCH_GROUP));
1202 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanInfo.getElanTag()));
1203 BigInteger dpnId = interfaceInfo.getDpId();
1204 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1205 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1206 MDSALUtil.buildBucketLists(listBuckets));
1207 LOG.trace("deleting the remoteBroadCast group:{}", group);
1208 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1212 * Installs a flow in the External Tunnel table consisting in translating
1213 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1214 * elanTag that will be used later in the ELANs pipeline.
1221 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1222 long elanTag = elanInfo.getElanTag();
1223 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1224 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1225 elanInfo.getElanInstanceName(), // flowName
1228 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1229 buildMatchesForVni(elanInfo.getSegmentationId()), getInstructionsExtTunnelTable(elanTag));
1231 mdsalManager.installFlow(flowEntity);
1235 * Removes, from External Tunnel table, the flow that translates from VNI to
1236 * elanTag. Important: ensure this method is only called whenever there is
1237 * no other ElanInterface in the specified DPN
1240 * DPN whose Ext Tunnel table is going to be modified
1242 * holds the elanTag needed for selecting the flow to be removed
1244 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1245 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1246 // last ElanInstance plus
1247 // adding a new one does (almost at the same time) are executed in that
1250 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1251 FlowEntity flowEntity = new FlowEntity(dpnId);
1252 flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
1253 flowEntity.setFlowId(flowId);
1254 mdsalManager.removeFlow(flowEntity);
1257 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1258 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1259 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1262 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1263 WriteTransaction writeFlowGroupTx) {
1264 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1265 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, elanTag), 5,
1266 String.format("%s:%d", "ITM Flow Entry ", elanTag), 0, 0,
1267 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)),
1268 ElanUtils.getTunnelMatchesForServiceId((int) elanTag),
1269 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1271 mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
1274 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1275 WriteTransaction writeFlowGroupTx) {
1276 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1277 if (etreeInstance != null) {
1278 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1282 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1283 long elanTag = elanInfo.getElanTag();
1284 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1285 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1286 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1289 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1290 WriteTransaction writeFlowGroupTx) {
1291 EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
1292 if (etreeLeafTag != null) {
1293 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1294 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1295 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1299 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1300 WriteTransaction writeFlowGroupTx) {
1301 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1302 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,
1303 /* SH flag */false),
1304 5, elanInfo.getElanInstanceName(), 0, 0,
1305 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1306 getMatchesForElanTag(elanTag, /* SH flag */false),
1307 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1309 mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
1312 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1313 WriteTransaction writeFlowGroupTx) {
1314 // only if ELAN can connect to external network, perform the following
1315 if (ElanUtils.isVxlan(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1316 Flow flowEntity2 = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1317 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,
1319 5, elanInfo.getElanInstanceName(), 0, 0,
1320 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1321 getMatchesForElanTag(elanTag, /* SH flag */true),
1322 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1323 mdsalManager.addFlowToTx(dpId, flowEntity2, writeFlowGroupTx);
1328 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1330 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1331 elanTag, /* SH flag */ false))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1332 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1334 if (ElanUtils.isVxlan(elanInfo)) {
1335 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1336 elanTag, /* SH flag */ true))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1338 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1342 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1343 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1346 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, WriteTransaction tx) {
1347 if (isStandardElanService(elanInterface)) {
1348 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(), tx);
1349 } else { // Etree service
1350 bindEtreeService(elanInfo, elanInterface, tx);
1354 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, WriteTransaction tx) {
1355 int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
1356 int instructionKey = 0;
1357 List<Instruction> instructions = new ArrayList<>();
1358 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
1359 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1360 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_BASE_TABLE,
1362 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1363 BoundServices serviceInfo = ElanUtils.getBoundServices(
1364 String.format("%s.%s.%s", "vpn", elanInstanceName, interfaceName), elanServiceIndex,
1365 priority, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1366 tx.put(LogicalDatastoreType.CONFIGURATION,
1367 ElanUtils.buildServiceId(interfaceName, elanServiceIndex), serviceInfo, true);
1370 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, WriteTransaction tx) {
1371 if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1372 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(), tx);
1374 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1375 if (etreeInstance == null) {
1376 LOG.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
1377 + elanInfo.getElanInstanceName());
1379 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1380 elanInterface.getName(), tx);
1385 private boolean isStandardElanService(ElanInterface elanInterface) {
1386 return elanInterface.getAugmentation(EtreeInterface.class) == null;
1389 private boolean isStandardElanService(ElanInstance elanInstance) {
1390 return elanInstance.getAugmentation(EtreeInstance.class) == null;
1393 private void unbindService(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
1394 tx.delete(LogicalDatastoreType.CONFIGURATION, ElanUtils.buildServiceId(interfaceName,
1395 ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX)));
1398 private String getFlowRef(long tableId, long elanTag) {
1399 return new StringBuffer().append(tableId).append(elanTag).toString();
1402 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1403 return new StringBuffer().append(tableId).append(elanTag).append(shFlag).toString();
1406 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1407 List<Action> listAction = new ArrayList<>();
1409 listAction.add(new ActionInfo(ActionType.set_field_tunnel_id,
1410 new BigInteger[] { BigInteger.valueOf(interfaceInfo.getInterfaceTag()) }, actionKey).buildAction());
1412 listAction.add(new ActionInfo(ActionType.nx_resubmit,
1413 new String[] { String.valueOf(NwConstants.ELAN_FILTER_EQUALS_TABLE) }, actionKey).buildAction());
1417 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1418 List<String> interfaceNames, WriteTransaction tx) {
1419 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1420 .setKey(new DpnInterfacesKey(dpId)).build();
1421 tx.put(LogicalDatastoreType.OPERATIONAL,
1422 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, true);
1423 return dpnInterface;
1427 * Delete elan dpn interface from operational DS.
1429 * @param elanInstanceName
1430 * the elan instance name
1434 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1435 tx.delete(LogicalDatastoreType.OPERATIONAL,
1436 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
1439 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1440 WriteTransaction tx) {
1441 List<String> interfaceNames = new ArrayList<>();
1442 interfaceNames.add(interfaceName);
1443 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1444 .setKey(new DpnInterfacesKey(dpId)).build();
1445 tx.put(LogicalDatastoreType.OPERATIONAL,
1446 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, true);
1447 return dpnInterface;
1450 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1451 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1452 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1453 Optional<ElanInterfaceMac> interfaceMacTables = elanUtils.read(broker,
1454 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1455 // Adding new Elan Interface Port to the operational DataStore without
1456 // Static-Mac Entries..
1457 if (!interfaceMacTables.isPresent()) {
1458 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1459 .setKey(new ElanInterfaceMacKey(interfaceName)).build();
1460 tx.put(LogicalDatastoreType.OPERATIONAL,
1461 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1466 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1467 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1468 Optional<Elan> elanInterfaceLists = elanUtils.read(broker,
1469 LogicalDatastoreType.OPERATIONAL, elanInstance);
1470 // Adding new Elan Interface Port to the operational DataStore without
1471 // Static-Mac Entries..
1472 if (elanInterfaceLists.isPresent()) {
1473 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1474 if (interfaceLists == null) {
1475 interfaceLists = new ArrayList<>();
1477 interfaceLists.add(interfaceName);
1478 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1479 .setKey(new ElanKey(elanInstanceName)).build();
1480 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1485 private boolean isOperational(InterfaceInfo interfaceInfo) {
1486 if (interfaceInfo == null) {
1489 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1492 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) throws ElanException {
1493 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1494 if (dpnInterfaceLists == null) {
1497 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1498 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1500 String elanName = elanDpns.getElanInstanceName();
1501 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1502 if (dpnInterfaces == null) {
1505 for (DpnInterfaces dpnIf : dpnInterfaces) {
1506 if (dpnIf.getDpId().equals(srcDpId) || dpnIf.getDpId().equals(dstDpId)) {
1511 LOG.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1512 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1513 // update Remote BC Group
1514 setupElanBroadcastGroups(elanInfo, srcDpId);
1516 DpnInterfaces dpnInterface = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dstDpId);
1517 Set<String> interfaceLists = new HashSet<>();
1518 interfaceLists.addAll(dpnInterface.getInterfaces());
1519 for (String ifName : interfaceLists) {
1520 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1521 if (isOperational(interfaceInfo)) {
1522 installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1531 * Handle external tunnel state event.
1533 * @param externalTunnel
1534 * the external tunnel
1537 * @throws ElanException in case of issues creating the flow objects
1539 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1540 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1543 // dpId/externalNodeId will be available either in source or destination
1544 // based on the tunnel end point
1545 BigInteger dpId = null;
1546 NodeId externalNodeId = null;
1547 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1548 dpId = new BigInteger(externalTunnel.getSourceDevice());
1549 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1550 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1551 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1552 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1554 if (dpId == null || externalNodeId == null) {
1555 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1559 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1560 if (dpnInterfaceLists == null) {
1563 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1564 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1565 String elanName = elanDpns.getElanInstanceName();
1566 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1568 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1569 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1570 || dpnInterfaces.getInterfaces().isEmpty()) {
1573 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1575 setupElanBroadcastGroups(elanInfo, dpId);
1576 // install L2gwDevices local macs in dpn.
1577 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1578 // Install dpn macs on external device
1579 elanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1582 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1586 * Validate external tunnel state event.
1588 * @param externalTunnel
1589 * the external tunnel
1592 * @return true, if successful
1594 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1595 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1596 String srcDevice = externalTunnel.getDestinationDevice();
1597 String destDevice = externalTunnel.getSourceDevice();
1598 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1599 LogicalDatastoreType.CONFIGURATION);
1600 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1601 otherEndPointExtTunnel);
1602 if (otherEndPointExtTunnel != null) {
1603 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1604 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1605 if (otherEndPointInterfaceOperational) {
1608 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1609 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1616 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1617 List<MatchInfo> mkMatches = new ArrayList<>();
1618 // Matching metadata
1619 mkMatches.add(new MatchInfo(MatchFieldType.metadata,
1620 new BigInteger[] { MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG }));
1621 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(lportTag) }));
1625 private List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
1626 List<MatchInfo> mkMatches = new ArrayList<>();
1627 // Matching metadata
1628 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(lportTag) }));
1632 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
1633 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
1637 for (DpnInterfaces dpn : dpns) {
1638 setupElanBroadcastGroups(elanInfo, dpn.getDpId());
1642 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
1644 List<Bucket> listBucketInfo = new ArrayList<>();
1645 ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
1646 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
1647 for (L2GatewayDevice device : map.values()) {
1648 String interfaceName = elanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1649 device.getHwvtepNodeId());
1650 if (interfaceName == null) {
1653 List<Action> listActionInfo = elanUtils.buildTunnelItmEgressActions(interfaceName,
1654 elanInfo.getSegmentationId());
1655 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1656 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1659 return listBucketInfo;
1663 protected ElanInterfaceManager getDataTreeChangeListener() {