2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlan;
11 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Objects;
24 import java.util.Queue;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentLinkedQueue;
28 import java.util.stream.Collectors;
29 import javax.annotation.PostConstruct;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.apache.commons.lang3.StringUtils;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
38 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
39 import org.opendaylight.genius.itm.globals.ITMConstants;
40 import org.opendaylight.genius.mdsalutil.FlowEntity;
41 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
42 import org.opendaylight.genius.mdsalutil.InstructionInfo;
43 import org.opendaylight.genius.mdsalutil.MDSALUtil;
44 import org.opendaylight.genius.mdsalutil.MatchInfo;
45 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
46 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
47 import org.opendaylight.genius.mdsalutil.NwConstants;
48 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
49 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
50 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
51 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
52 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
53 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
54 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
56 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
57 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
58 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
59 import org.opendaylight.genius.utils.ServiceIndex;
60 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
61 import org.opendaylight.netvirt.elan.ElanException;
62 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
63 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
64 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
65 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
66 import org.opendaylight.netvirt.elan.utils.ElanConstants;
67 import org.opendaylight.netvirt.elan.utils.ElanEtreeUtils;
68 import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
69 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
70 import org.opendaylight.netvirt.elan.utils.ElanUtils;
71 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
72 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
73 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
74 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
75 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
78 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
119 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
120 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
121 import org.slf4j.Logger;
122 import org.slf4j.LoggerFactory;
125 * Class in charge of handling creations, modifications and removals of
128 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
131 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager> {
132 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
133 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
134 private static final boolean SH_FLAG_SET = true;
135 private static final boolean SH_FLAG_UNSET = false;
137 private final DataBroker broker;
138 private final IMdsalApiManager mdsalManager;
139 private final IInterfaceManager interfaceManager;
140 private final IdManagerService idManager;
141 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
142 private final INeutronVpnManager neutronVpnManager;
143 private final ElanItmUtils elanItmUtils;
144 private final ElanEtreeUtils elanEtreeUtils;
145 private final ElanL2GatewayUtils elanL2GatewayUtils;
146 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
147 private final ElanUtils elanUtils;
148 private final JobCoordinator jobCoordinator;
149 private final ElanInstanceCache elanInstanceCache;
150 private final ElanInterfaceCache elanInterfaceCache;
152 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
153 unProcessedElanInterfaces = new ConcurrentHashMap<>();
156 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
157 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
158 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
159 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
160 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
161 final ElanUtils elanUtils, final JobCoordinator jobCoordinator,
162 final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
163 final ElanInstanceCache elanInstanceCache,
164 final ElanInterfaceCache elanInterfaceCache) {
165 super(ElanInterface.class, ElanInterfaceManager.class);
166 this.broker = dataBroker;
167 this.idManager = managerService;
168 this.mdsalManager = mdsalApiManager;
169 this.interfaceManager = interfaceManager;
170 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
171 this.neutronVpnManager = neutronVpnManager;
172 this.elanItmUtils = elanItmUtils;
173 this.elanEtreeUtils = elanEtreeUtils;
174 this.elanL2GatewayUtils = elanL2GatewayUtils;
175 this.elanUtils = elanUtils;
176 this.jobCoordinator = jobCoordinator;
177 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
178 this.elanInstanceCache = elanInstanceCache;
179 this.elanInterfaceCache = elanInterfaceCache;
185 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
189 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
190 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
194 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
195 String interfaceName = del.getName();
196 ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull();
198 * Handling in case the elan instance is deleted.If the Elan instance is
199 * deleted, there is no need to explicitly delete the elan interfaces
201 if (elanInfo == null) {
204 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
205 if (interfaceInfo == null && elanInfo.isExternal()) {
206 // In deleting external network, the underlying ietf Inteface might have been removed
207 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
208 // from Operational DS instead
209 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
211 String elanInstanceName = elanInfo.getElanInstanceName();
212 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
213 interfaceName, interfaceInfo, this);
214 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
217 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
218 InterfaceInfo interfaceInfo) {
219 String elanName = elanInfo.getElanInstanceName();
220 boolean isLastElanInterface = false;
221 boolean isLastInterfaceOnDpn = false;
222 BigInteger dpId = null;
223 long elanTag = elanInfo.getElanTag();
224 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
225 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
226 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
227 if (elanState == null) {
228 interfaceTx.cancel();
229 return Collections.emptyList();
231 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
232 List<String> elanInterfaces = elanState.getElanInterfaces();
233 if (elanInterfaces.isEmpty()) {
234 isLastElanInterface = true;
236 if (interfaceInfo != null) {
237 dpId = interfaceInfo.getDpId();
238 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
239 interfaceName, elanTag, interfaceTx);
241 * If there are not elan ports, remove the unknown dmac, terminating
242 * service table flows, remote/local bc group
244 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
245 || dpnInterfaces.getInterfaces().isEmpty()) {
246 // No more Elan Interfaces in this DPN
247 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
248 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
249 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
251 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
252 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
253 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
254 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
255 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
256 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
257 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
258 elanUtils.removeTerminatingServiceAction(dpId, elanInfo.getSegmentationId().intValue());
260 unsetExternalTunnelTable(dpId, elanInfo);
262 isLastInterfaceOnDpn = true;
264 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
268 List<ListenableFuture<Void>> futures = new ArrayList<>();
269 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
270 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
272 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
273 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
275 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
276 interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
277 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
278 ElanConstants.JOB_MAX_RETRIES);
283 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
284 WriteTransaction deleteFlowGroupTx) {
285 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
286 if (etreeLeafTag != null) {
287 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
288 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
292 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
293 WriteTransaction deleteFlowGroupTx) {
294 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
295 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
298 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
299 WriteTransaction deleteFlowGroupTx) {
300 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
301 if (etreeInstance != null) {
302 BigInteger dpnId = interfaceInfo.getDpId();
303 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
304 List<Bucket> listBuckets = new ArrayList<>();
306 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
307 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
308 MDSALUtil.buildBucketLists(listBuckets));
309 LOG.trace("deleted the localBroadCast Group:{}", group);
310 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
314 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
315 WriteTransaction deleteFlowGroupTx) {
316 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
317 if (etreeInstance != null) {
318 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
321 List<Bucket> listBuckets = new ArrayList<>();
322 List<Action> listAction = new ArrayList<>();
323 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
324 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
325 MDSALUtil.WATCH_GROUP));
327 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
328 BigInteger dpnId = interfaceInfo.getDpId();
329 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
330 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
331 MDSALUtil.buildBucketLists(listBuckets));
332 LOG.trace("deleting the remoteBroadCast group:{}", group);
333 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
337 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
338 String elanName = elanInfo.getElanInstanceName();
339 Elan elanState = ElanUtils.getElanByName(broker, elanName);
340 if (elanState == null) {
343 List<String> elanInterfaces = elanState.getElanInterfaces();
344 boolean isRemoved = elanInterfaces.remove(interfaceName);
349 if (elanInterfaces.isEmpty()) {
350 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
351 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
352 tx.delete(LogicalDatastoreType.OPERATIONAL,
353 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
355 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
356 .setKey(new ElanKey(elanName)).build();
357 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
363 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
364 // removing the ElanInterface from the config data_store if interface is
365 // not present in Interface config DS
366 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
367 && elanInterfaceCache.get(interfaceName).isPresent()) {
368 tx.delete(LogicalDatastoreType.CONFIGURATION,
369 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
373 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
374 interfaceInfo, String interfaceName, boolean isLastElanInterface) {
375 String elanName = elanInfo.getElanInstanceName();
376 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
377 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
378 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
379 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
380 Optional<ElanInterfaceMac> existingElanInterfaceMac = ElanUtils.read(broker,
381 LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
382 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
383 if (interfaceInfo != null) {
384 if (existingElanInterfaceMac.isPresent()) {
385 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
386 List<MacEntry> macEntries = new ArrayList<>();
387 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
388 macEntries.addAll(existingMacEntries);
390 List<PhysAddress> macAddresses = macEntries.stream().map(macEntry -> {
391 PhysAddress macAddress = macEntry.getMacAddress();
392 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
393 macAddress.getValue(), interfaceName);
394 Optional<MacEntry> macEntryOptional = elanUtils.getMacEntryForElanInstance(elanName,
396 if (!isLastElanInterface && macEntryOptional.isPresent()) {
397 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
398 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
400 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
402 }).collect(Collectors.toList());
404 // Removing all those MACs from External Devices belonging
406 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
407 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
410 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
411 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
412 } else if (existingElanInterfaceMac.isPresent()) {
413 // Interface does not exist in ConfigDS, so lets remove everything
414 // about that interface related to Elan
415 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
416 if (macEntries != null) {
417 for (MacEntry macEntry : macEntries) {
418 PhysAddress macAddress = macEntry.getMacAddress();
419 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
420 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
421 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
426 if (existingElanInterfaceMac.isPresent()) {
427 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
429 unbindService(interfaceName, interfaceTx);
430 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
431 List<ListenableFuture<Void>> futures = new ArrayList<>();
432 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
433 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
437 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
438 String interfaceName, long elanTag,
439 WriteTransaction tx) {
440 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
441 if (dpnInterfaces != null) {
442 List<String> interfaceLists = dpnInterfaces.getInterfaces();
443 if (interfaceLists != null) {
444 interfaceLists.remove(interfaceName);
447 if (interfaceLists == null || interfaceLists.isEmpty()) {
448 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
449 deleteElanDpnInterface(elanName, dpId, tx);
451 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
454 return dpnInterfaces;
457 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
458 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
459 for (DpnInterfaces dpnInterface : dpnInterfaces) {
460 BigInteger currentDpId = dpnInterface.getDpId();
461 if (!currentDpId.equals(dpId)) {
462 for (String elanInterface : dpnInterface.getInterfaces()) {
463 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
464 if (macs == null || macs.getMacEntry() == null) {
467 for (MacEntry mac : macs.getMacEntry()) {
468 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
469 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
476 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
477 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
478 if (etreeLeafTag != null) {
479 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
483 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
486 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
487 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
488 mac.getMacAddress().getValue(), elanTag)));
492 * Possible Scenarios for update
493 * a. if orig={1,2,3,4} and updated=null or updated={}
494 then all {1,2,3,4} should be removed
496 b. if orig=null or orig={} and updated ={1,2,3,4}
497 then all {1,2,3,4} should be added
499 c. if orig = {1,2,3,4} updated={2,3,4}
500 then 1 should be removed
502 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
503 then we should just add 5
505 e. if orig = {1,2,3,4} updated={2,3,4,5}
506 then 1 should be removed , 5 should be added
509 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
510 // updating the static-Mac Entries for the existing elanInterface
511 String elanName = update.getElanInstanceName();
512 String interfaceName = update.getName();
514 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
515 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
516 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
517 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
519 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
520 deletedEntry.getMacAddress()));
522 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
523 * Hence add the macentries for the same.*/
524 for (StaticMacEntries staticMacEntry : updatedEntries) {
525 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
526 staticMacEntry.getMacAddress());
527 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
528 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
529 WriteTransaction tx = broker.newWriteOnlyTransaction();
530 if (existingMacEntry.isPresent()) {
531 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
532 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
535 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
536 elanName, interfaceName, staticMacEntry, tx);
538 ElanUtils.waitForTransactionToComplete(tx);
543 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
544 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
545 String interfaceName = elanInterfaceAdded.getName();
546 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
547 if (interfaceInfo == null) {
548 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
551 ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
553 if (elanInstance == null) {
554 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
555 .setDescription(elanInterfaceAdded.getDescription()).build();
556 // Add the ElanInstance in the Configuration data-store
557 WriteTransaction tx = broker.newWriteOnlyTransaction();
558 List<String> elanInterfaces = new ArrayList<>();
559 elanInterfaces.add(interfaceName);
560 elanInstance = ElanUtils.updateOperationalDataStore(broker, idManager,
561 elanInstance, elanInterfaces, tx);
565 Long elanTag = elanInstance.getElanTag();
566 // If elan tag is not updated, then put the elan interface into
567 // unprocessed entry map and entry. Let entries
568 // in this map get processed during ELAN update DCN.
569 if (elanTag == null) {
570 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
571 if (elanInterfaces == null) {
572 elanInterfaces = new ConcurrentLinkedQueue<>();
574 elanInterfaces.add(elanInterfaceAdded);
575 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
578 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
579 interfaceInfo, elanInstance, this);
580 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
583 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
584 List<ListenableFuture<Void>> futures = new ArrayList<>();
585 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
586 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
589 for (ElanInterface elanInterface : elanInterfaces) {
590 String interfaceName = elanInterface.getName();
591 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
592 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
597 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
598 WriteTransaction writeFlowGroupTx) throws ElanException {
599 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
600 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
601 List<DpnInterfaces> dpnInterfaceLists = null;
602 if (elanDpnInterfacesList != null) {
603 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
605 if (dpnInterfaceLists == null) {
606 dpnInterfaceLists = new ArrayList<>();
608 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
609 BigInteger dstDpId = interfaceInfo.getDpId();
610 if (dpnInterfaces.getDpId().equals(dstDpId)) {
613 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
614 for (String remoteIf : remoteElanInterfaces) {
615 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
616 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
617 if (elanIfMac == null) {
620 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
621 if (remoteMacEntries != null) {
622 for (MacEntry macEntry : remoteMacEntries) {
623 String macAddress = macEntry.getMacAddress().getValue();
624 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
625 dstDpId, elanInstance.getElanInstanceName());
626 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
627 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
628 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
635 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
636 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
637 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
638 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
639 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
641 String interfaceName = elanInterface.getName();
642 String elanInstanceName = elanInterface.getElanInstanceName();
644 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
645 WriteTransaction tx = broker.newWriteOnlyTransaction();
646 if (elanInfo == null) {
647 List<String> elanInterfaces = new ArrayList<>();
648 elanInterfaces.add(interfaceName);
649 ElanUtils.updateOperationalDataStore(broker, idManager,
650 elanInstance, elanInterfaces, tx);
652 createElanStateList(elanInstanceName, interfaceName, tx);
654 boolean isFirstInterfaceInDpn = false;
655 // Specific actions to the DPN where the ElanInterface has been added,
656 // for example, programming the
657 // External tunnel table if needed or adding the ElanInterface to the
658 // DpnInterfaces in the operational DS.
659 BigInteger dpId = interfaceInfo.getDpId();
660 DpnInterfaces dpnInterfaces = null;
661 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
662 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
663 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
664 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
665 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
666 if (!existingElanDpnInterfaces.isPresent()) {
667 isFirstInterfaceInDpn = true;
668 // ELAN's 1st ElanInterface added to this DPN
669 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
670 // The 1st ElanInterface in a DPN must program the Ext Tunnel
671 // table, but only if Elan has VNI
672 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
673 setExternalTunnelTable(dpId, elanInstance);
675 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
677 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
678 elanInterfaces.add(interfaceName);
679 if (elanInterfaces.size() == 1) { // 1st dpn interface
680 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
682 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
686 // add code to install Local/Remote BC group, unknow DMAC entry,
687 // terminating service table flow entry
688 // call bindservice of interfacemanager to create ingress table flow
690 // Add interface to the ElanInterfaceForwardingEntires Container
691 createElanInterfaceTablesList(interfaceName, tx);
692 List<ListenableFuture<Void>> futures = new ArrayList<>();
693 futures.add(ElanUtils.waitForTransactionToComplete(tx));
694 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces,
695 isFirstInterfaceInDpn, null);
697 // add the vlan provider interface to remote BC group for the elan
698 // for internal vlan networks
699 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
700 if (interfaceManager.isExternalInterface(interfaceName)) {
701 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
702 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
706 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
707 //update the remote-DPNs remoteBC group entry with Tunnels
708 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
709 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
712 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
713 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
714 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
715 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
719 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
720 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
721 throws ElanException {
722 String elanInstanceName = elanInstance.getElanInstanceName();
723 String interfaceName = elanInterface.getName();
724 WriteTransaction tx = broker.newWriteOnlyTransaction();
725 BigInteger dpId = interfaceInfo.getDpId();
726 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
727 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
728 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
730 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
731 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
733 boolean isInterfaceOperational = isOperational(interfaceInfo);
734 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
735 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
736 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
737 staticMacEntry.getMacAddress());
738 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
739 LogicalDatastoreType.OPERATIONAL, macId);
740 if (existingMacEntry.isPresent()) {
741 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
742 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
743 existingMacEntry.get(), tx);
745 elanForwardingEntriesHandler
746 .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
749 if (isInterfaceOperational) {
750 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
752 String macAddress = staticMacEntry.getMacAddress().getValue();
753 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
754 macAddress, elanInstanceName, interfaceName);
755 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
756 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
760 if (isInterfaceOperational) {
761 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
763 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
764 staticMacAddresses.add(staticMacEntry.getMacAddress());
766 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
770 List<ListenableFuture<Void>> futures = new ArrayList<>();
771 futures.add(ElanUtils.waitForTransactionToComplete(tx));
772 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
773 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
774 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
776 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
777 if (neutronPort != null) {
778 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
780 } catch (IllegalArgumentException ex) {
781 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
787 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
788 PhysAddress physAddress) {
789 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
790 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
791 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
792 LogicalDatastoreType.OPERATIONAL, macId);
794 if (!existingMacEntry.isPresent()) {
798 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
799 .setKey(new MacEntryKey(physAddress)).build();
800 WriteTransaction tx = broker.newWriteOnlyTransaction();
801 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
802 elanInstanceCache.get(elanInstanceName).orNull(), interfaceInfo, macEntry, tx);
803 ElanUtils.waitForTransactionToComplete(tx);
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, WriteTransaction tx) {
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, WriteTransaction tx) {
1398 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1399 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1400 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1402 if (existingElanService.isPresent()) {
1403 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1407 private String getFlowRef(long tableId, long elanTag) {
1408 return String.valueOf(tableId) + elanTag;
1411 private String getFlowRef(long tableId, long elanTag, String flowName) {
1412 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1413 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1416 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1417 return String.valueOf(tableId) + elanTag + shFlag;
1420 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1421 List<Action> listAction = new ArrayList<>();
1424 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1426 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1430 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1431 List<String> interfaceNames, WriteTransaction tx) {
1432 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1433 .setKey(new DpnInterfacesKey(dpId)).build();
1434 tx.put(LogicalDatastoreType.OPERATIONAL,
1435 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1436 WriteTransaction.CREATE_MISSING_PARENTS);
1437 return dpnInterface;
1441 * Delete elan dpn interface from operational DS.
1443 * @param elanInstanceName
1444 * the elan instance name
1448 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1449 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1450 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1451 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1452 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1453 if (dpnInterfaces.isPresent()) {
1454 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1458 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1459 WriteTransaction tx) {
1460 List<String> interfaceNames = new ArrayList<>();
1461 interfaceNames.add(interfaceName);
1462 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1463 .setKey(new DpnInterfacesKey(dpId)).build();
1464 tx.put(LogicalDatastoreType.OPERATIONAL,
1465 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1466 WriteTransaction.CREATE_MISSING_PARENTS);
1467 return dpnInterface;
1470 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1471 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1472 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1473 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1474 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1475 // Adding new Elan Interface Port to the operational DataStore without
1476 // Static-Mac Entries..
1477 if (!interfaceMacTables.isPresent()) {
1478 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1479 .setKey(new ElanInterfaceMacKey(interfaceName)).build();
1480 tx.put(LogicalDatastoreType.OPERATIONAL,
1481 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1482 WriteTransaction.CREATE_MISSING_PARENTS);
1486 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1487 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1488 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1489 LogicalDatastoreType.OPERATIONAL, elanInstance);
1490 // Adding new Elan Interface Port to the operational DataStore without
1491 // Static-Mac Entries..
1492 if (elanInterfaceLists.isPresent()) {
1493 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1494 if (interfaceLists == null) {
1495 interfaceLists = new ArrayList<>();
1497 interfaceLists.add(interfaceName);
1498 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1499 .setKey(new ElanKey(elanInstanceName)).build();
1500 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1501 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1505 private boolean isOperational(InterfaceInfo interfaceInfo) {
1506 if (interfaceInfo == null) {
1509 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1512 @SuppressWarnings("checkstyle:IllegalCatch")
1513 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) throws ElanException {
1514 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1515 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1516 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1517 if (dpnInterfaceLists == null) {
1520 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1521 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1523 String elanName = elanDpns.getElanInstanceName();
1524 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1525 if (elanInfo == null) {
1526 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1527 + "skipping this ELAN for tunnel handling", elanName);
1530 if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) {
1531 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1534 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1535 if (dpnInterfaces == null) {
1538 DpnInterfaces dstDpnIf = null;
1539 for (DpnInterfaces dpnIf : dpnInterfaces) {
1540 BigInteger dpnIfDpId = dpnIf.getDpId();
1541 if (dpnIfDpId.equals(srcDpId)) {
1543 } else if (dpnIfDpId.equals(dstDpId)) {
1549 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1550 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1551 jobCoordinator.enqueueJob(elanName, () -> {
1552 // update Remote BC Group
1553 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1555 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
1556 } catch (RuntimeException e) {
1557 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1559 Set<String> interfaceLists = new HashSet<>();
1560 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1561 for (String ifName : interfaceLists) {
1562 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1563 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1564 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1565 if (isOperational(interfaceInfo)) {
1566 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1568 return Collections.emptyList();
1569 }, ElanConstants.JOB_MAX_RETRIES);
1571 return Collections.emptyList();
1572 }, ElanConstants.JOB_MAX_RETRIES);
1579 * Handle external tunnel state event.
1581 * @param externalTunnel
1582 * the external tunnel
1585 * @throws ElanException in case of issues creating the flow objects
1587 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1588 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1591 // dpId/externalNodeId will be available either in source or destination
1592 // based on the tunnel end point
1593 BigInteger dpId = null;
1594 NodeId externalNodeId = null;
1595 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1596 dpId = new BigInteger(externalTunnel.getSourceDevice());
1597 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1598 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1599 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1600 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1602 if (dpId == null || externalNodeId == null) {
1603 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1607 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1608 if (dpnInterfaceLists == null) {
1611 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1612 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1613 String elanName = elanDpns.getElanInstanceName();
1614 ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
1616 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1617 if (elanInfo == null || dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1618 || dpnInterfaces.getInterfaces().isEmpty()) {
1621 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1623 elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
1624 // install L2gwDevices local macs in dpn.
1625 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1626 // Install dpn macs on external device
1627 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1630 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1634 * Installs dpn macs in external device. first it checks if the physical
1635 * locator towards this dpn tep is present or not if the physical locator is
1636 * present go ahead and add the ucast macs otherwise update the mcast mac
1637 * entry to include this dpn tep ip and schedule the job to put ucast macs
1638 * once the physical locator is programmed in device
1642 * @param lstElanInterfaceNames
1643 * the lst Elan interface names
1646 * @param externalNodeId
1647 * the external node id
1649 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1650 NodeId externalNodeId) {
1651 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1652 externalNodeId.getValue());
1653 if (elanL2GwDevice == null) {
1654 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1657 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1658 if (dpnTepIp == null) {
1659 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1664 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1665 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1666 LogicalDatastoreType.OPERATIONAL);
1667 boolean phyLocAlreadyExists =
1668 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1670 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1671 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1672 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1674 if (phyLocAlreadyExists) {
1675 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1678 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1679 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1683 * Validate external tunnel state event.
1685 * @param externalTunnel
1686 * the external tunnel
1689 * @return true, if successful
1691 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1692 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1693 String srcDevice = externalTunnel.getDestinationDevice();
1694 String destDevice = externalTunnel.getSourceDevice();
1695 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1696 LogicalDatastoreType.CONFIGURATION);
1697 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1698 otherEndPointExtTunnel);
1699 if (otherEndPointExtTunnel != null) {
1700 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1701 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1702 if (otherEndPointInterfaceOperational) {
1705 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1706 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1713 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1714 List<MatchInfo> mkMatches = new ArrayList<>();
1715 // Matching metadata
1717 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1718 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1723 protected ElanInterfaceManager getDataTreeChangeListener() {
1727 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1729 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1730 elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1732 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1733 } catch (InterruptedException e) {
1734 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);