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 javax.annotation.PostConstruct;
29 import javax.inject.Inject;
30 import javax.inject.Singleton;
31 import org.apache.commons.lang3.StringUtils;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
34 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
37 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
41 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
42 import org.opendaylight.genius.itm.globals.ITMConstants;
43 import org.opendaylight.genius.mdsalutil.FlowEntity;
44 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
45 import org.opendaylight.genius.mdsalutil.InstructionInfo;
46 import org.opendaylight.genius.mdsalutil.MDSALUtil;
47 import org.opendaylight.genius.mdsalutil.MatchInfo;
48 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
49 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
50 import org.opendaylight.genius.mdsalutil.NwConstants;
51 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
52 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
53 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
54 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
55 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
58 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
59 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
60 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
61 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
62 import org.opendaylight.genius.utils.ServiceIndex;
63 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
64 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
65 import org.opendaylight.netvirt.elan.ElanException;
66 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
67 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
68 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
69 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
70 import org.opendaylight.netvirt.elan.utils.ElanConstants;
71 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
72 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
73 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
74 import org.opendaylight.netvirt.elan.utils.ElanUtils;
75 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
76 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
77 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
78 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
79 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
80 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
81 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
82 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
123 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
124 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
125 import org.slf4j.Logger;
126 import org.slf4j.LoggerFactory;
129 * Class in charge of handling creations, modifications and removals of
132 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
135 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager> {
136 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
137 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
138 private static final boolean SH_FLAG_SET = true;
139 private static final boolean SH_FLAG_UNSET = false;
141 private final DataBroker broker;
142 private final ManagedNewTransactionRunner txRunner;
143 private final IMdsalApiManager mdsalManager;
144 private final IInterfaceManager interfaceManager;
145 private final IdManagerService idManager;
146 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
147 private final INeutronVpnManager neutronVpnManager;
148 private final ElanItmUtils elanItmUtils;
149 private final ElanEtreeUtils elanEtreeUtils;
150 private final ElanL2GatewayUtils elanL2GatewayUtils;
151 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
152 private final ElanUtils elanUtils;
153 private final JobCoordinator jobCoordinator;
154 private final ElanInstanceCache elanInstanceCache;
155 private final ElanInterfaceCache elanInterfaceCache;
157 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
158 unProcessedElanInterfaces = new ConcurrentHashMap<>();
161 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
162 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
163 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
164 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
165 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
166 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
167 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
168 final ElanInstanceCache elanInstanceCache,
169 final ElanInterfaceCache elanInterfaceCache) {
170 super(ElanInterface.class, ElanInterfaceManager.class);
171 this.broker = dataBroker;
172 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
173 this.idManager = managerService;
174 this.mdsalManager = mdsalApiManager;
175 this.interfaceManager = interfaceManager;
176 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
177 this.neutronVpnManager = neutronVpnManager;
178 this.elanItmUtils = elanItmUtils;
179 this.elanEtreeUtils = elanEtreeUtils;
180 this.elanL2GatewayUtils = elanL2GatewayUtils;
181 this.elanUtils = elanUtils;
182 this.jobCoordinator = jobCoordinator;
183 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
184 this.elanInstanceCache = elanInstanceCache;
185 this.elanInterfaceCache = elanInterfaceCache;
191 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
195 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
196 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
200 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
201 String interfaceName = del.getName();
202 ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull();
204 * Handling in case the elan instance is deleted.If the Elan instance is
205 * deleted, there is no need to explicitly delete the elan interfaces
207 if (elanInfo == null) {
210 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
211 if (interfaceInfo == null && elanInfo.isExternal()) {
212 // In deleting external network, the underlying ietf Inteface might have been removed
213 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
214 // from Operational DS instead
215 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
217 String elanInstanceName = elanInfo.getElanInstanceName();
218 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
219 interfaceName, interfaceInfo, this);
220 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
223 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
224 InterfaceInfo interfaceInfo) {
225 String elanName = elanInfo.getElanInstanceName();
226 boolean isLastElanInterface = false;
227 boolean isLastInterfaceOnDpn = false;
228 BigInteger dpId = null;
229 long elanTag = elanInfo.getElanTag();
230 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
231 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
232 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
233 if (elanState == null) {
234 interfaceTx.cancel();
235 return Collections.emptyList();
237 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
238 List<String> elanInterfaces = elanState.getElanInterfaces();
239 if (elanInterfaces.isEmpty()) {
240 isLastElanInterface = true;
242 if (interfaceInfo != null) {
243 dpId = interfaceInfo.getDpId();
244 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
245 interfaceName, elanTag, interfaceTx);
247 * If there are not elan ports, remove the unknown dmac, terminating
248 * service table flows, remote/local bc group
250 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
251 || dpnInterfaces.getInterfaces().isEmpty()) {
252 // No more Elan Interfaces in this DPN
253 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
254 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
255 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
257 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
258 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
259 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
260 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
261 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
262 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
263 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
264 elanUtils.removeTerminatingServiceAction(dpId, elanInfo.getSegmentationId().intValue());
266 unsetExternalTunnelTable(dpId, elanInfo);
268 isLastInterfaceOnDpn = true;
270 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
274 List<ListenableFuture<Void>> futures = new ArrayList<>();
275 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
276 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
278 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
279 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
281 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
282 interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
283 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
284 ElanConstants.JOB_MAX_RETRIES);
289 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
290 WriteTransaction deleteFlowGroupTx) {
291 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
292 if (etreeLeafTag != null) {
293 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
294 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
298 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
299 WriteTransaction deleteFlowGroupTx) {
300 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
301 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
304 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
305 WriteTransaction deleteFlowGroupTx) {
306 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
307 if (etreeInstance != null) {
308 BigInteger dpnId = interfaceInfo.getDpId();
309 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
310 List<Bucket> listBuckets = new ArrayList<>();
312 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
313 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
314 MDSALUtil.buildBucketLists(listBuckets));
315 LOG.trace("deleted the localBroadCast Group:{}", group);
316 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
320 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
321 WriteTransaction deleteFlowGroupTx) {
322 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
323 if (etreeInstance != null) {
324 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
327 List<Bucket> listBuckets = new ArrayList<>();
328 List<Action> listAction = new ArrayList<>();
329 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
330 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
331 MDSALUtil.WATCH_GROUP));
333 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
334 BigInteger dpnId = interfaceInfo.getDpId();
335 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
336 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
337 MDSALUtil.buildBucketLists(listBuckets));
338 LOG.trace("deleting the remoteBroadCast group:{}", group);
339 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
343 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
344 String elanName = elanInfo.getElanInstanceName();
345 Elan elanState = ElanUtils.getElanByName(broker, elanName);
346 if (elanState == null) {
349 List<String> elanInterfaces = elanState.getElanInterfaces();
350 boolean isRemoved = elanInterfaces.remove(interfaceName);
355 if (elanInterfaces.isEmpty()) {
356 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
357 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
358 tx.delete(LogicalDatastoreType.OPERATIONAL,
359 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
361 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
362 .setKey(new ElanKey(elanName)).build();
363 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
369 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
370 // removing the ElanInterface from the config data_store if interface is
371 // not present in Interface config DS
372 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
373 && elanInterfaceCache.get(interfaceName).isPresent()) {
374 tx.delete(LogicalDatastoreType.CONFIGURATION,
375 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
379 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
380 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
381 String elanName = elanInfo.getElanInstanceName();
382 List<ListenableFuture<Void>> futures = new ArrayList<>();
383 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(flowTx -> {
384 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> {
385 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
386 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
387 Optional<ElanInterfaceMac> existingElanInterfaceMac =
388 interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet();
389 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
390 if (interfaceInfo != null) {
391 if (existingElanInterfaceMac.isPresent()) {
392 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
393 if (existingMacEntries != null) {
394 List<PhysAddress> macAddresses = new ArrayList<>();
395 for (MacEntry macEntry : existingMacEntries) {
396 PhysAddress macAddress = macEntry.getMacAddress();
397 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
398 macAddress.getValue(), interfaceName);
399 Optional<MacEntry> macEntryOptional =
400 elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
401 if (!isLastElanInterface && macEntryOptional.isPresent()) {
402 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
403 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
405 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
406 macAddresses.add(macAddress);
409 // Removing all those MACs from External Devices belonging
411 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
412 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
416 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
417 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
418 } else if (existingElanInterfaceMac.isPresent()) {
419 // Interface does not exist in ConfigDS, so lets remove everything
420 // about that interface related to Elan
421 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
422 if (macEntries != null) {
423 for (MacEntry macEntry : macEntries) {
424 PhysAddress macAddress = macEntry.getMacAddress();
425 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
426 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
427 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
432 if (existingElanInterfaceMac.isPresent()) {
433 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
435 unbindService(interfaceName, interfaceTx);
436 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
442 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
443 String interfaceName, long elanTag,
444 WriteTransaction tx) {
445 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
446 if (dpnInterfaces != null) {
447 List<String> interfaceLists = dpnInterfaces.getInterfaces();
448 if (interfaceLists != null) {
449 interfaceLists.remove(interfaceName);
452 if (interfaceLists == null || interfaceLists.isEmpty()) {
453 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
454 deleteElanDpnInterface(elanName, dpId, tx);
456 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
459 return dpnInterfaces;
462 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
463 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
464 for (DpnInterfaces dpnInterface : dpnInterfaces) {
465 BigInteger currentDpId = dpnInterface.getDpId();
466 if (!currentDpId.equals(dpId)) {
467 for (String elanInterface : dpnInterface.getInterfaces()) {
468 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
469 if (macs == null || macs.getMacEntry() == null) {
472 for (MacEntry mac : macs.getMacEntry()) {
473 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
474 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
481 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
482 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
483 if (etreeLeafTag != null) {
484 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
488 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
491 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
492 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
493 mac.getMacAddress().getValue(), elanTag)));
497 * Possible Scenarios for update
498 * a. if orig={1,2,3,4} and updated=null or updated={}
499 then all {1,2,3,4} should be removed
501 b. if orig=null or orig={} and updated ={1,2,3,4}
502 then all {1,2,3,4} should be added
504 c. if orig = {1,2,3,4} updated={2,3,4}
505 then 1 should be removed
507 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
508 then we should just add 5
510 e. if orig = {1,2,3,4} updated={2,3,4,5}
511 then 1 should be removed , 5 should be added
514 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
515 // updating the static-Mac Entries for the existing elanInterface
516 String elanName = update.getElanInstanceName();
517 String interfaceName = update.getName();
519 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
520 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
521 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
522 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
524 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
525 deletedEntry.getMacAddress()));
527 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
528 * Hence add the macentries for the same.*/
529 for (StaticMacEntries staticMacEntry : updatedEntries) {
530 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
531 staticMacEntry.getMacAddress());
532 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
533 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
534 WriteTransaction tx = broker.newWriteOnlyTransaction();
535 if (existingMacEntry.isPresent()) {
536 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
537 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
540 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
541 elanName, interfaceName, staticMacEntry, tx);
543 ElanUtils.waitForTransactionToComplete(tx);
548 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
549 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
550 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
551 String interfaceName = elanInterfaceAdded.getName();
552 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
553 if (interfaceInfo == null) {
554 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
557 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
559 if (elanInstance == null) {
560 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
561 .setDescription(elanInterfaceAdded.getDescription()).build();
562 // Add the ElanInstance in the Configuration data-store
563 List<String> elanInterfaces = new ArrayList<>();
564 elanInterfaces.add(interfaceName);
565 elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
568 Long elanTag = elanInstance.getElanTag();
569 // If elan tag is not updated, then put the elan interface into
570 // unprocessed entry map and entry. Let entries
571 // in this map get processed during ELAN update DCN.
572 if (elanTag == null) {
573 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
574 if (elanInterfaces == null) {
575 elanInterfaces = new ConcurrentLinkedQueue<>();
577 elanInterfaces.add(elanInterfaceAdded);
578 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
581 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
582 interfaceInfo, elanInstance, this);
583 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
584 }), LOG, "Error procedding added ELAN interface");
587 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
588 List<ListenableFuture<Void>> futures = new ArrayList<>();
589 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
590 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
593 for (ElanInterface elanInterface : elanInterfaces) {
594 String interfaceName = elanInterface.getName();
595 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
596 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
601 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
602 WriteTransaction writeFlowGroupTx) throws ElanException {
603 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
604 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
605 List<DpnInterfaces> dpnInterfaceLists = null;
606 if (elanDpnInterfacesList != null) {
607 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
609 if (dpnInterfaceLists == null) {
610 dpnInterfaceLists = new ArrayList<>();
612 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
613 BigInteger dstDpId = interfaceInfo.getDpId();
614 if (dpnInterfaces.getDpId().equals(dstDpId)) {
617 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
618 for (String remoteIf : remoteElanInterfaces) {
619 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
620 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
621 if (elanIfMac == null) {
624 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
625 if (remoteMacEntries != null) {
626 for (MacEntry macEntry : remoteMacEntries) {
627 String macAddress = macEntry.getMacAddress().getValue();
628 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
629 dstDpId, elanInstance.getElanInstanceName());
630 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
631 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
632 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
639 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
640 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
641 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
642 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
643 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
645 String interfaceName = elanInterface.getName();
646 String elanInstanceName = elanInterface.getElanInstanceName();
648 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
649 WriteTransaction tx = broker.newWriteOnlyTransaction();
650 if (elanInfo == null) {
651 List<String> elanInterfaces = new ArrayList<>();
652 elanInterfaces.add(interfaceName);
653 ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
655 createElanStateList(elanInstanceName, interfaceName, tx);
657 boolean isFirstInterfaceInDpn = false;
658 // Specific actions to the DPN where the ElanInterface has been added,
659 // for example, programming the
660 // External tunnel table if needed or adding the ElanInterface to the
661 // DpnInterfaces in the operational DS.
662 BigInteger dpId = interfaceInfo.getDpId();
663 DpnInterfaces dpnInterfaces = null;
664 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
665 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
666 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
667 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
668 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
669 if (!existingElanDpnInterfaces.isPresent()) {
670 isFirstInterfaceInDpn = true;
671 // ELAN's 1st ElanInterface added to this DPN
672 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
673 // The 1st ElanInterface in a DPN must program the Ext Tunnel
674 // table, but only if Elan has VNI
675 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
676 setExternalTunnelTable(dpId, elanInstance);
678 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
680 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
681 elanInterfaces.add(interfaceName);
682 if (elanInterfaces.size() == 1) { // 1st dpn interface
683 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
685 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
689 // add code to install Local/Remote BC group, unknow DMAC entry,
690 // terminating service table flow entry
691 // call bindservice of interfacemanager to create ingress table flow
693 // Add interface to the ElanInterfaceForwardingEntires Container
694 createElanInterfaceTablesList(interfaceName, tx);
695 List<ListenableFuture<Void>> futures = new ArrayList<>();
696 futures.add(ElanUtils.waitForTransactionToComplete(tx));
697 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
699 // add the vlan provider interface to remote BC group for the elan
700 // for internal vlan networks
701 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
702 if (interfaceManager.isExternalInterface(interfaceName)) {
703 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
704 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
708 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
709 //update the remote-DPNs remoteBC group entry with Tunnels
710 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
711 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
714 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
715 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
716 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
717 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
721 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
722 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
723 throws ElanException {
724 String elanInstanceName = elanInstance.getElanInstanceName();
725 String interfaceName = elanInterface.getName();
726 WriteTransaction tx = broker.newWriteOnlyTransaction();
727 BigInteger dpId = interfaceInfo.getDpId();
728 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
729 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
730 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
732 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
733 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
735 boolean isInterfaceOperational = isOperational(interfaceInfo);
736 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
737 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
738 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
739 staticMacEntry.getMacAddress());
740 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
741 LogicalDatastoreType.OPERATIONAL, macId);
742 if (existingMacEntry.isPresent()) {
743 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
744 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
745 existingMacEntry.get(), tx);
747 elanForwardingEntriesHandler
748 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
751 if (isInterfaceOperational) {
752 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
754 String macAddress = staticMacEntry.getMacAddress().getValue();
755 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
756 macAddress, elanInstanceName, interfaceName);
757 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
758 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
762 if (isInterfaceOperational) {
763 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
765 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
766 staticMacAddresses.add(staticMacEntry.getMacAddress());
768 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
772 List<ListenableFuture<Void>> futures = new ArrayList<>();
773 futures.add(ElanUtils.waitForTransactionToComplete(tx));
774 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
775 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
776 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
778 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
779 if (neutronPort != null) {
780 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
782 } catch (IllegalArgumentException ex) {
783 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
789 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
790 PhysAddress physAddress) {
791 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
792 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
793 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
794 LogicalDatastoreType.OPERATIONAL, macId);
796 if (!existingMacEntry.isPresent()) {
800 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
801 .setKey(new MacEntryKey(physAddress)).build();
802 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
803 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry);
806 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
807 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
808 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
811 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
812 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
813 WriteTransaction writeFlowGroupTx) throws ElanException {
814 if (!isOperational(interfaceInfo)) {
817 BigInteger dpId = interfaceInfo.getDpId();
818 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
819 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
821 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
822 if (isFirstInterfaceInDpn) {
823 // Terminating Service , UnknownDMAC Table.
824 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
825 // for ELAN Instance is VxLAN
826 if (isVxlan(elanInstance)) {
827 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
829 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
831 * Install remote DMAC flow. This is required since this DPN is
832 * added later to the elan instance and remote DMACs of other
833 * interfaces in this elan instance are not present in the current
836 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
837 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
838 elanInstance.getElanInstanceName());
839 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
842 // bind the Elan service to the Interface
843 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
846 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
847 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
848 if (!isOperational(interfaceInfo)) {
851 // LocalBroadcast Group creation with elan-Interfaces
852 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
853 if (isFirstInterfaceInDpn) {
854 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
855 BigInteger dpId = interfaceInfo.getDpId();
856 // RemoteBroadcast Group creation
858 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
859 } catch (InterruptedException e1) {
860 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
862 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
864 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
865 } catch (InterruptedException e1) {
866 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
871 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
872 WriteTransaction writeFlowGroupTx) {
873 int ifTag = interfaceInfo.getInterfaceTag();
874 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
875 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
876 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
877 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
878 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
880 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
882 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
883 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
884 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
885 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
887 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
890 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
891 WriteTransaction deleteFlowGroupTx) {
892 int ifTag = interfaceInfo.getInterfaceTag();
893 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
894 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
895 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
896 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
897 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
899 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
901 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
902 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
903 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
904 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
906 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
909 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
910 InterfaceInfo interfaceInfo, long elanTag) {
911 return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
912 bucketKeyStart, elanTag);
915 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
916 int elanTag = elanInfo.getElanTag().intValue();
917 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
918 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
919 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
920 if (etreeInstance != null) {
921 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
922 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
923 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
927 @SuppressWarnings("checkstyle:IllegalCatch")
928 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
930 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
931 if (elanDpns != null) {
932 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
933 for (DpnInterfaces dpnInterface : dpnInterfaces) {
934 List<Bucket> remoteListBucketInfo = new ArrayList<>();
935 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
936 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
937 List<Action> listAction = new ArrayList<>();
939 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
940 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
941 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
943 for (DpnInterfaces otherFes : dpnInterfaces) {
944 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
945 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
946 && !otherFes.getInterfaces().isEmpty()) {
948 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
949 dpnInterface.getDpId(), otherFes.getDpId(),
950 elanUtils.isOpenstackVniSemanticsEnforced() ? elanInfo.getSegmentationId()
952 if (!remoteListActionInfo.isEmpty()) {
953 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
954 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
957 } catch (Exception ex) {
958 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
959 + "Logical Group Interface not found between source Dpn - {}, "
960 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
965 List<Bucket> elanL2GwDevicesBuckets = elanL2GatewayMulticastUtils
966 .getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnInterface.getDpId(), bucketId);
967 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
969 if (remoteListBucketInfo.isEmpty()) {
970 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
973 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
974 MDSALUtil.buildBucketLists(remoteListBucketInfo));
975 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
976 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
980 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
981 } catch (InterruptedException e1) {
982 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
988 * Returns the bucket info with the given interface as the only bucket.
990 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
991 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
992 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
995 private List<MatchInfo> buildMatchesForVni(Long vni) {
996 List<MatchInfo> mkMatches = new ArrayList<>();
997 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
998 mkMatches.add(match);
1002 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1003 List<InstructionInfo> mkInstructions = new ArrayList<>();
1004 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1005 return mkInstructions;
1008 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1009 List<MatchInfo> mkMatches = new ArrayList<>();
1010 // Matching metadata
1011 mkMatches.add(new MatchMetadata(
1012 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1017 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1018 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1021 * elanTag to be written in metadata when flow is selected
1022 * @return the instructions ready to be installed in a flow
1024 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1025 List<InstructionInfo> mkInstructions = new ArrayList<>();
1026 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1027 .getElanMetadataMask()));
1028 /* applicable for EXTERNAL_TUNNEL_TABLE only
1029 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1031 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1032 return mkInstructions;
1035 // Install DMAC entry on dst DPN
1036 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1037 BigInteger dstDpId) throws ElanException {
1038 String interfaceName = interfaceInfo.getInterfaceName();
1039 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1040 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1041 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1042 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1043 for (MacEntry macEntry : macEntries) {
1044 String macAddress = macEntry.getMacAddress().getValue();
1045 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1046 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1047 interfaceInfo.getDpId())) {
1048 LOG.info("Acquired lock for mac : " + macAddress + ". Proceeding with remote dmac"
1049 + " install operation.");
1050 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1054 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1056 return Collections.emptyList();
1059 private void createDropBucket(List<Bucket> listBucket) {
1060 List<Action> actionsInfos = new ArrayList<>();
1061 actionsInfos.add(new ActionDrop().buildAction());
1062 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1063 MDSALUtil.WATCH_GROUP);
1064 listBucket.add(dropBucket);
1067 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1068 InterfaceInfo interfaceInfo) {
1069 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1070 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1073 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1074 InterfaceInfo interfaceInfo) {
1075 List<Bucket> listBucket = new ArrayList<>();
1077 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1079 List<String> interfaces = new ArrayList<>();
1080 if (newDpnInterface != null) {
1081 interfaces = newDpnInterface.getInterfaces();
1083 for (String ifName : interfaces) {
1084 // In case if there is a InterfacePort in the cache which is not in
1085 // operational state, skip processing it
1086 InterfaceInfo ifInfo = interfaceManager
1087 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1088 if (!isOperational(ifInfo)) {
1092 if (!interfaceManager.isExternalInterface(ifName)) {
1093 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1094 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1099 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1100 MDSALUtil.buildBucketLists(listBucket));
1101 LOG.trace("installing the localBroadCast Group:{}", group);
1102 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1105 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1106 InterfaceInfo interfaceInfo) {
1107 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1108 if (etreeInstance != null) {
1109 List<Bucket> listBucket = new ArrayList<>();
1112 List<String> interfaces = new ArrayList<>();
1113 if (newDpnInterface != null) {
1114 interfaces = newDpnInterface.getInterfaces();
1116 for (String ifName : interfaces) {
1117 // In case if there is a InterfacePort in the cache which is not
1119 // operational state, skip processing it
1120 InterfaceInfo ifInfo = interfaceManager
1121 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1122 if (!isOperational(ifInfo)) {
1126 if (!interfaceManager.isExternalInterface(ifName)) {
1127 // only add root interfaces
1128 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1132 if (listBucket.isEmpty()) { // No Buckets
1133 createDropBucket(listBucket);
1136 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1137 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1138 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1139 MDSALUtil.buildBucketLists(listBucket));
1140 LOG.trace("installing the localBroadCast Group:{}", group);
1141 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1145 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1146 InterfaceInfo ifInfo) {
1147 Optional<EtreeInterface> etreeInterface = elanInterfaceCache.getEtreeInterface(ifName);
1148 if (etreeInterface.isPresent() && etreeInterface.get().getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1149 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1150 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1156 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1157 WriteTransaction deleteFlowGroupTx) {
1158 BigInteger dpnId = interfaceInfo.getDpId();
1159 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1160 List<Bucket> listBuckets = new ArrayList<>();
1162 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1163 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1165 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1166 MDSALUtil.buildBucketLists(listBuckets));
1167 LOG.trace("deleted the localBroadCast Group:{}", group);
1168 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1171 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1172 WriteTransaction deleteFlowGroupTx) {
1175 Long elanTag = elanInfo.getElanTag();
1176 List<Bucket> listBuckets = new ArrayList<>();
1177 List<Action> listAction = new ArrayList<>();
1178 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1179 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1180 MDSALUtil.WATCH_GROUP));
1182 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1183 BigInteger dpnId = interfaceInfo.getDpId();
1184 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1185 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1186 MDSALUtil.buildBucketLists(listBuckets));
1187 LOG.trace("deleting the remoteBroadCast group:{}", group);
1188 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1192 * Installs a flow in the External Tunnel table consisting in translating
1193 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1194 * elanTag that will be used later in the ELANs pipeline.
1201 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1202 long elanTag = elanInfo.getElanTag();
1203 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1204 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1205 elanInfo.getElanInstanceName(), // flowName
1208 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1209 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1210 getInstructionsIntOrExtTunnelTable(elanTag));
1212 mdsalManager.installFlow(flowEntity);
1216 * Removes, from External Tunnel table, the flow that translates from VNI to
1217 * elanTag. Important: ensure this method is only called whenever there is
1218 * no other ElanInterface in the specified DPN
1221 * DPN whose Ext Tunnel table is going to be modified
1223 * holds the elanTag needed for selecting the flow to be removed
1225 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1226 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1227 // last ElanInstance plus
1228 // adding a new one does (almost at the same time) are executed in that
1231 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1232 FlowEntity flowEntity = new FlowEntityBuilder()
1234 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1237 mdsalManager.removeFlow(flowEntity);
1240 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1241 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1242 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1245 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1246 WriteTransaction writeFlowGroupTx) {
1247 List<? extends MatchInfoBase> listMatchInfoBase;
1248 List<InstructionInfo> instructionInfos;
1250 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1251 serviceId = elanTag;
1252 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1253 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1255 serviceId = elanInfo.getSegmentationId();
1256 listMatchInfoBase = buildMatchesForVni(serviceId);
1257 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1259 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1260 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1261 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1263 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1266 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1267 WriteTransaction writeFlowGroupTx) {
1268 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1269 if (etreeInstance != null) {
1270 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1274 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1275 long elanTag = elanInfo.getElanTag();
1276 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1277 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1278 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1281 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1282 WriteTransaction writeFlowGroupTx) {
1283 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1284 if (etreeLeafTag != null) {
1285 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1286 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1287 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1291 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1292 WriteTransaction writeFlowGroupTx) {
1293 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1294 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1295 5, elanInfo.getElanInstanceName(), 0, 0,
1296 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1297 getMatchesForElanTag(elanTag, /* SH flag */false),
1298 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1300 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1303 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1304 WriteTransaction writeFlowGroupTx) {
1305 // only if ELAN can connect to external network, perform the following
1307 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1308 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1309 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1310 5, elanInfo.getElanInstanceName(), 0, 0,
1311 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1312 getMatchesForElanTag(elanTag, /* SH flag */true),
1313 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1314 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1319 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1321 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1322 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1323 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1325 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1326 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1327 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1329 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1333 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1334 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1337 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1338 if (isStandardElanService(elanInterface)) {
1339 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1340 elanInterface.getName(), lportTag, tx);
1341 } else { // Etree service
1342 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1346 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1347 WriteTransaction tx) {
1348 int instructionKey = 0;
1349 List<Instruction> instructions = new ArrayList<>();
1350 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1351 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1353 List<Action> actions = new ArrayList<>();
1354 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1355 lportTag).buildAction());
1356 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1357 elanTag).buildAction());
1358 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1360 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1363 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1364 BoundServices serviceInfo = ElanUtils.getBoundServices(
1365 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1366 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1367 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1368 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1370 if (!existingElanService.isPresent()) {
1371 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1372 WriteTransaction.CREATE_MISSING_PARENTS);
1376 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1377 WriteTransaction tx) {
1378 if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1379 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1382 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1383 if (etreeInstance == null) {
1384 LOG.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
1385 + elanInfo.getElanInstanceName());
1387 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1388 elanInterface.getName(), lportTag, tx);
1393 private boolean isStandardElanService(ElanInterface elanInterface) {
1394 return elanInterface.getAugmentation(EtreeInterface.class) == null;
1397 protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
1398 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1399 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1400 if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
1401 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1405 private String getFlowRef(long tableId, long elanTag) {
1406 return String.valueOf(tableId) + elanTag;
1409 private String getFlowRef(long tableId, long elanTag, String flowName) {
1410 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1411 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1414 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1415 return String.valueOf(tableId) + elanTag + shFlag;
1418 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1419 List<Action> listAction = new ArrayList<>();
1422 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1424 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1428 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1429 List<String> interfaceNames, WriteTransaction tx) {
1430 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1431 .setKey(new DpnInterfacesKey(dpId)).build();
1432 tx.put(LogicalDatastoreType.OPERATIONAL,
1433 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1434 WriteTransaction.CREATE_MISSING_PARENTS);
1435 return dpnInterface;
1439 * Delete elan dpn interface from operational DS.
1441 * @param elanInstanceName
1442 * the elan instance name
1446 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1447 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1448 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1449 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1450 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1451 if (dpnInterfaces.isPresent()) {
1452 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1456 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1457 WriteTransaction tx) {
1458 List<String> interfaceNames = new ArrayList<>();
1459 interfaceNames.add(interfaceName);
1460 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1461 .setKey(new DpnInterfacesKey(dpId)).build();
1462 tx.put(LogicalDatastoreType.OPERATIONAL,
1463 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1464 WriteTransaction.CREATE_MISSING_PARENTS);
1465 return dpnInterface;
1468 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1469 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1470 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1471 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1472 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1473 // Adding new Elan Interface Port to the operational DataStore without
1474 // Static-Mac Entries..
1475 if (!interfaceMacTables.isPresent()) {
1476 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1477 .setKey(new ElanInterfaceMacKey(interfaceName)).build();
1478 tx.put(LogicalDatastoreType.OPERATIONAL,
1479 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1480 WriteTransaction.CREATE_MISSING_PARENTS);
1484 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1485 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1486 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1487 LogicalDatastoreType.OPERATIONAL, elanInstance);
1488 // Adding new Elan Interface Port to the operational DataStore without
1489 // Static-Mac Entries..
1490 if (elanInterfaceLists.isPresent()) {
1491 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1492 if (interfaceLists == null) {
1493 interfaceLists = new ArrayList<>();
1495 interfaceLists.add(interfaceName);
1496 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1497 .setKey(new ElanKey(elanInstanceName)).build();
1498 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1499 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1503 private boolean isOperational(InterfaceInfo interfaceInfo) {
1504 if (interfaceInfo == null) {
1507 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1510 @SuppressWarnings("checkstyle:IllegalCatch")
1511 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1512 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1513 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1514 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1515 if (dpnInterfaceLists == null) {
1518 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1519 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1521 String elanName = elanDpns.getElanInstanceName();
1522 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1523 if (elanInfo == null) {
1524 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1525 + "skipping this ELAN for tunnel handling", elanName);
1528 if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) {
1529 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1532 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1533 if (dpnInterfaces == null) {
1536 DpnInterfaces dstDpnIf = null;
1537 for (DpnInterfaces dpnIf : dpnInterfaces) {
1538 BigInteger dpnIfDpId = dpnIf.getDpId();
1539 if (dpnIfDpId.equals(srcDpId)) {
1541 } else if (dpnIfDpId.equals(dstDpId)) {
1547 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1548 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1549 jobCoordinator.enqueueJob(elanName, () -> {
1550 // update Remote BC Group
1551 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1553 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1554 } catch (RuntimeException e) {
1555 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1557 Set<String> interfaceLists = new HashSet<>();
1558 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1559 for (String ifName : interfaceLists) {
1560 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1561 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1562 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1563 if (isOperational(interfaceInfo)) {
1564 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1566 return Collections.emptyList();
1567 }, ElanConstants.JOB_MAX_RETRIES);
1569 return Collections.emptyList();
1570 }, ElanConstants.JOB_MAX_RETRIES);
1577 * Handle external tunnel state event.
1579 * @param externalTunnel
1580 * the external tunnel
1583 * @throws ElanException in case of issues creating the flow objects
1585 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1586 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1589 // dpId/externalNodeId will be available either in source or destination
1590 // based on the tunnel end point
1591 BigInteger dpId = null;
1592 NodeId externalNodeId = null;
1593 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1594 dpId = new BigInteger(externalTunnel.getSourceDevice());
1595 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1596 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1597 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1598 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1600 if (dpId == null || externalNodeId == null) {
1601 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1605 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1606 if (dpnInterfaceLists == null) {
1609 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1610 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1611 String elanName = elanDpns.getElanInstanceName();
1612 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1614 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1615 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1616 || dpnInterfaces.getInterfaces().isEmpty()) {
1619 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1621 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1622 // install L2gwDevices local macs in dpn.
1623 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1624 // Install dpn macs on external device
1625 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1628 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1632 * Installs dpn macs in external device. first it checks if the physical
1633 * locator towards this dpn tep is present or not if the physical locator is
1634 * present go ahead and add the ucast macs otherwise update the mcast mac
1635 * entry to include this dpn tep ip and schedule the job to put ucast macs
1636 * once the physical locator is programmed in device
1640 * @param lstElanInterfaceNames
1641 * the lst Elan interface names
1644 * @param externalNodeId
1645 * the external node id
1647 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1648 NodeId externalNodeId) {
1649 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1650 externalNodeId.getValue());
1651 if (elanL2GwDevice == null) {
1652 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1655 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1656 if (dpnTepIp == null) {
1657 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1662 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1663 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1664 LogicalDatastoreType.OPERATIONAL);
1665 boolean phyLocAlreadyExists =
1666 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1668 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1669 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1670 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1672 if (phyLocAlreadyExists) {
1673 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1676 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1677 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1681 * Validate external tunnel state event.
1683 * @param externalTunnel
1684 * the external tunnel
1687 * @return true, if successful
1689 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1690 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1691 String srcDevice = externalTunnel.getDestinationDevice();
1692 String destDevice = externalTunnel.getSourceDevice();
1693 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1694 LogicalDatastoreType.CONFIGURATION);
1695 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1696 otherEndPointExtTunnel);
1697 if (otherEndPointExtTunnel != null) {
1698 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1699 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1700 if (otherEndPointInterfaceOperational) {
1703 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1704 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1711 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1712 List<MatchInfo> mkMatches = new ArrayList<>();
1713 // Matching metadata
1715 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1716 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1721 protected ElanInterfaceManager getDataTreeChangeListener() {
1725 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1727 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1728 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1730 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1731 } catch (InterruptedException e) {
1732 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);