2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlan;
11 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Objects;
24 import java.util.Queue;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentLinkedQueue;
28 import java.util.concurrent.ConcurrentMap;
29 import java.util.stream.Collectors;
30 import javax.annotation.Nonnull;
31 import javax.annotation.PostConstruct;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
34 import org.apache.commons.lang3.StringUtils;
35 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
36 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
37 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
38 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
39 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
40 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
41 import org.opendaylight.genius.itm.globals.ITMConstants;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
44 import org.opendaylight.genius.mdsalutil.InstructionInfo;
45 import org.opendaylight.genius.mdsalutil.MDSALUtil;
46 import org.opendaylight.genius.mdsalutil.MatchInfo;
47 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
48 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
49 import org.opendaylight.genius.mdsalutil.NwConstants;
50 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
51 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
52 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
53 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
54 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteActions;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
58 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
59 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
60 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
61 import org.opendaylight.genius.utils.ServiceIndex;
62 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
63 import org.opendaylight.netvirt.elan.ElanException;
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.instances.elan.instance.ExternalTeps;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
120 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
121 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
122 import org.slf4j.Logger;
123 import org.slf4j.LoggerFactory;
126 * Class in charge of handling creations, modifications and removals of
129 * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
132 @SuppressWarnings("deprecation")
133 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager> {
135 private final DataBroker broker;
136 private final IMdsalApiManager mdsalManager;
137 private final IInterfaceManager interfaceManager;
138 private final IdManagerService idManager;
139 private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
140 private final INeutronVpnManager neutronVpnManager;
141 private final ElanItmUtils elanItmUtils;
142 private final ElanEtreeUtils elanEtreeUtils;
143 private final ElanL2GatewayUtils elanL2GatewayUtils;
144 private ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
145 private ElanUtils elanUtils;
146 private final JobCoordinator jobCoordinator;
148 private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
149 private static final boolean SH_FLAG_SET = true;
150 private static final boolean SH_FLAG_UNSET = false;
152 private final Map<String, ConcurrentLinkedQueue<ElanInterface>>
153 unProcessedElanInterfaces = new ConcurrentHashMap<>();
155 private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
158 public ElanInterfaceManager(final DataBroker dataBroker, final IdManagerService managerService,
159 final IMdsalApiManager mdsalApiManager, IInterfaceManager interfaceManager,
160 final ElanForwardingEntriesHandler elanForwardingEntriesHandler,
161 final INeutronVpnManager neutronVpnManager, final ElanItmUtils elanItmUtils,
162 final ElanEtreeUtils elanEtreeUtils, final ElanL2GatewayUtils elanL2GatewayUtils,
163 final JobCoordinator jobCoordinator) {
164 super(ElanInterface.class, ElanInterfaceManager.class);
165 this.broker = dataBroker;
166 this.idManager = managerService;
167 this.mdsalManager = mdsalApiManager;
168 this.interfaceManager = interfaceManager;
169 this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
170 this.neutronVpnManager = neutronVpnManager;
171 this.elanItmUtils = elanItmUtils;
172 this.elanEtreeUtils = elanEtreeUtils;
173 this.elanL2GatewayUtils = elanL2GatewayUtils;
174 this.jobCoordinator = jobCoordinator;
178 * This method is used instead of "regular" standard constructor dependency injection in, only,
179 * ElanServiceProvider's constructor to wire things together. It was done like this because of the unholy
180 * triumvirate of unhealthy love triangle between (at least) ElanUtils, ElanInterfaceManager and
181 * ElanL2GatewayMulticastUtils. The proper solution to be able to get rid of this would be to split up some of these
182 * relatively big classes into smaller classes, and then inject more fine grained among them.
184 public void setElanUtils(ElanUtils elanUtils) {
185 this.elanUtils = elanUtils;
186 this.elanL2GatewayMulticastUtils = elanUtils.getElanL2GatewayMulticastUtils();
187 this.elanForwardingEntriesHandler.setElanUtils(elanUtils);
193 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
197 protected InstanceIdentifier<ElanInterface> getWildCardPath() {
198 return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
202 protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
203 String interfaceName = del.getName();
204 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, del.getElanInstanceName());
206 * Handling in case the elan instance is deleted.If the Elan instance is
207 * deleted, there is no need to explicitly delete the elan interfaces
209 if (elanInfo == null) {
212 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
213 if (interfaceInfo == null && elanInfo.isExternal()) {
214 // In deleting external network, the underlying ietf Inteface might have been removed
215 // from the config DS prior to deleting the ELAN interface. We try to get the InterfaceInfo
216 // from Operational DS instead
217 interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
219 String elanInstanceName = elanInfo.getElanInstanceName();
220 InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
221 interfaceName, interfaceInfo, false, this);
222 jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
225 public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
226 InterfaceInfo interfaceInfo, boolean isInterfaceStateRemoved) {
227 String elanName = elanInfo.getElanInstanceName();
228 boolean isLastElanInterface = false;
229 boolean isLastInterfaceOnDpn = false;
230 BigInteger dpId = null;
231 long elanTag = elanInfo.getElanTag();
232 // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
233 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
234 Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
235 if (elanState == null) {
236 interfaceTx.cancel();
237 return Collections.emptyList();
239 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
240 List<String> elanInterfaces = elanState.getElanInterfaces();
241 if (elanInterfaces.isEmpty()) {
242 isLastElanInterface = true;
244 if (interfaceInfo != null) {
245 dpId = interfaceInfo.getDpId();
246 DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
247 interfaceName, elanTag, interfaceTx);
249 * If there are not elan ports, remove the unknown dmac, terminating
250 * service table flows, remote/local bc group
252 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
253 || dpnInterfaces.getInterfaces().isEmpty()) {
254 // No more Elan Interfaces in this DPN
255 LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
256 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
257 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
259 removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
260 removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
261 removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
262 removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
263 removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
264 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
265 if (elanUtils.isOpenstackVniSemanticsEnforced()) {
266 elanUtils.removeTerminatingServiceAction(dpId, elanInfo.getSegmentationId().intValue());
268 unsetExternalTunnelTable(dpId, elanInfo);
270 isLastInterfaceOnDpn = true;
272 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
276 List<ListenableFuture<Void>> futures = new ArrayList<>();
277 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
278 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
280 if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
281 setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
283 InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
284 interfaceName, elanInfo, interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
285 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
286 ElanConstants.JOB_MAX_RETRIES);
291 private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
292 WriteTransaction deleteFlowGroupTx) {
293 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
294 if (etreeLeafTag != null) {
295 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
296 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
300 private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
301 WriteTransaction deleteFlowGroupTx) {
302 removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
303 removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
306 private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
307 WriteTransaction deleteFlowGroupTx) {
308 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
309 if (etreeInstance != null) {
310 BigInteger dpnId = interfaceInfo.getDpId();
311 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
312 List<Bucket> listBuckets = new ArrayList<>();
314 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
315 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
316 MDSALUtil.buildBucketLists(listBuckets));
317 LOG.trace("deleted the localBroadCast Group:{}", group);
318 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
322 private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
323 WriteTransaction deleteFlowGroupTx) {
324 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
325 if (etreeInstance != null) {
326 long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
329 List<Bucket> listBuckets = new ArrayList<>();
330 List<Action> listAction = new ArrayList<>();
331 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
332 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
333 MDSALUtil.WATCH_GROUP));
335 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
336 BigInteger dpnId = interfaceInfo.getDpId();
337 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
338 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
339 MDSALUtil.buildBucketLists(listBuckets));
340 LOG.trace("deleting the remoteBroadCast group:{}", group);
341 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
345 private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
346 String elanName = elanInfo.getElanInstanceName();
347 Elan elanState = ElanUtils.getElanByName(broker, elanName);
348 if (elanState == null) {
351 List<String> elanInterfaces = elanState.getElanInterfaces();
352 boolean isRemoved = elanInterfaces.remove(interfaceName);
357 if (elanInterfaces.isEmpty()) {
358 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
359 tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
360 tx.delete(LogicalDatastoreType.OPERATIONAL,
361 ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
363 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
364 .setKey(new ElanKey(elanName)).build();
365 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
371 private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
372 // removing the ElanInterface from the config data_store if interface is
373 // not present in Interface config DS
374 if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
375 && ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName) != null) {
376 tx.delete(LogicalDatastoreType.CONFIGURATION,
377 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
381 List<ListenableFuture<Void>> removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo
382 interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved, boolean isLastElanInterface) {
383 String elanName = elanInfo.getElanInstanceName();
384 WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
385 WriteTransaction flowTx = broker.newWriteOnlyTransaction();
386 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
387 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
388 Optional<ElanInterfaceMac> existingElanInterfaceMac = ElanUtils.read(broker,
389 LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
390 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
391 if (interfaceInfo != null) {
392 if (existingElanInterfaceMac.isPresent()) {
393 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
394 List<MacEntry> macEntries = new ArrayList<>();
395 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
396 macEntries.addAll(existingMacEntries);
398 List<PhysAddress> macAddresses = macEntries.stream().map(macEntry -> {
399 PhysAddress macAddress = macEntry.getMacAddress();
400 LOG.debug("removing the mac-entry:{} present on elanInterface:{}",
401 macAddress.getValue(), interfaceName);
402 Optional<MacEntry> macEntryOptional = elanUtils.getMacEntryForElanInstance(elanName,
404 if (!isLastElanInterface && macEntryOptional.isPresent()) {
405 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
406 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
408 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
410 }).collect(Collectors.toList());
412 // Removing all those MACs from External Devices belonging
414 if (isVxlanNetworkOrVxlanSegment(elanInfo) && ! macAddresses.isEmpty()) {
415 elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
418 removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
419 removeFilterEqualsTable(elanInfo, interfaceInfo, flowTx);
420 } else if (existingElanInterfaceMac.isPresent()) {
421 // Interface does not exist in ConfigDS, so lets remove everything
422 // about that interface related to Elan
423 List<MacEntry> macEntries = existingElanInterfaceMac.get().getMacEntry();
424 if (macEntries != null) {
425 for (MacEntry macEntry : macEntries) {
426 PhysAddress macAddress = macEntry.getMacAddress();
427 if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
428 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
429 ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
434 if (existingElanInterfaceMac.isPresent()) {
435 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
437 if (!isInterfaceStateRemoved) {
438 unbindService(interfaceName, interfaceTx);
440 deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
441 List<ListenableFuture<Void>> futures = new ArrayList<>();
442 futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
443 futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
447 private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
448 String interfaceName, long elanTag,
449 WriteTransaction tx) {
450 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
451 if (dpnInterfaces != null) {
452 List<String> interfaceLists = dpnInterfaces.getInterfaces();
453 if (interfaceLists != null) {
454 interfaceLists.remove(interfaceName);
457 if (interfaceLists == null || interfaceLists.isEmpty()) {
458 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
459 deleteElanDpnInterface(elanName, dpId, tx);
461 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
464 return dpnInterfaces;
467 private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
468 List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
469 for (DpnInterfaces dpnInterface : dpnInterfaces) {
470 BigInteger currentDpId = dpnInterface.getDpId();
471 if (!currentDpId.equals(dpId)) {
472 for (String elanInterface : dpnInterface.getInterfaces()) {
473 ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
474 if (macs == null || macs.getMacEntry() == null) {
477 for (MacEntry mac : macs.getMacEntry()) {
478 removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
479 removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
486 private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
487 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
488 if (etreeLeafTag != null) {
489 removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
493 private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
496 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
497 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
498 mac.getMacAddress().getValue(), elanTag)));
502 * Possible Scenarios for update
503 * a. if orig={1,2,3,4} and updated=null or updated={}
504 then all {1,2,3,4} should be removed
506 b. if orig=null or orig={} and updated ={1,2,3,4}
507 then all {1,2,3,4} should be added
509 c. if orig = {1,2,3,4} updated={2,3,4}
510 then 1 should be removed
512 d. basically if orig = { 1,2,3,4} and updated is {1,2,3,4,5}
513 then we should just add 5
515 e. if orig = {1,2,3,4} updated={2,3,4,5}
516 then 1 should be removed , 5 should be added
519 protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
520 // updating the static-Mac Entries for the existing elanInterface
521 String elanName = update.getElanInstanceName();
522 String interfaceName = update.getName();
524 List<StaticMacEntries> originalStaticMacEntries = original.getStaticMacEntries();
525 List<StaticMacEntries> updatedStaticMacEntries = update.getStaticMacEntries();
526 List<StaticMacEntries> deletedEntries = ElanUtils.diffOf(originalStaticMacEntries, updatedStaticMacEntries);
527 List<StaticMacEntries> updatedEntries = ElanUtils.diffOf(updatedStaticMacEntries, originalStaticMacEntries);
529 deletedEntries.forEach((deletedEntry) -> removeInterfaceStaticMacEntries(elanName, interfaceName,
530 deletedEntry.getMacAddress()));
532 /*if updatedStaticMacEntries is NOT NULL, which means as part of update call these entries were added.
533 * Hence add the macentries for the same.*/
534 for (StaticMacEntries staticMacEntry : updatedEntries) {
535 InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
536 staticMacEntry.getMacAddress());
537 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
538 LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
539 WriteTransaction tx = broker.newWriteOnlyTransaction();
540 if (existingMacEntry.isPresent()) {
541 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
542 elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
545 elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
546 ElanUtils.getElanInstanceByName(broker, elanName), interfaceName, staticMacEntry, tx);
548 ElanUtils.waitForTransactionToComplete(tx);
553 protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
554 String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
555 String interfaceName = elanInterfaceAdded.getName();
556 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
557 if (interfaceInfo == null) {
558 LOG.info("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
561 ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
563 if (elanInstance == null) {
564 elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
565 .setDescription(elanInterfaceAdded.getDescription()).build();
566 // Add the ElanInstance in the Configuration data-store
567 WriteTransaction tx = broker.newWriteOnlyTransaction();
568 List<String> elanInterfaces = new ArrayList<>();
569 elanInterfaces.add(interfaceName);
570 ElanUtils.updateOperationalDataStore(broker, idManager,
571 elanInstance, elanInterfaces, tx);
572 ElanUtils.waitForTransactionToComplete(tx);
573 elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
576 Long elanTag = elanInstance.getElanTag();
577 // If elan tag is not updated, then put the elan interface into
578 // unprocessed entry map and entry. Let entries
579 // in this map get processed during ELAN update DCN.
580 if (elanTag == null) {
581 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
582 if (elanInterfaces == null) {
583 elanInterfaces = new ConcurrentLinkedQueue<>();
585 elanInterfaces.add(elanInterfaceAdded);
586 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
589 InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
590 interfaceInfo, elanInstance, this);
591 jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
594 List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
595 List<ListenableFuture<Void>> futures = new ArrayList<>();
596 Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
597 if (elanInterfaces == null || elanInterfaces.isEmpty()) {
600 for (ElanInterface elanInterface : elanInterfaces) {
601 String interfaceName = elanInterface.getName();
602 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
603 futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
608 void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
609 WriteTransaction writeFlowGroupTx) throws ElanException {
610 ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
611 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
612 List<DpnInterfaces> dpnInterfaceLists = null;
613 if (elanDpnInterfacesList != null) {
614 dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
616 if (dpnInterfaceLists == null) {
617 dpnInterfaceLists = new ArrayList<>();
619 for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
620 BigInteger dstDpId = interfaceInfo.getDpId();
621 if (dpnInterfaces.getDpId().equals(dstDpId)) {
624 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
625 for (String remoteIf : remoteElanInterfaces) {
626 ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
627 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
628 if (elanIfMac == null) {
631 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
632 if (remoteMacEntries != null) {
633 for (MacEntry macEntry : remoteMacEntries) {
634 String macAddress = macEntry.getMacAddress().getValue();
635 LOG.info("Programming remote dmac {} on the newly added DPN {} for elan {}", macAddress,
636 dstDpId, elanInstance.getElanInstanceName());
637 elanUtils.setupRemoteDmacFlow(dstDpId, remoteInterface.getDpId(),
638 remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), macAddress,
639 elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
646 List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
647 InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
648 Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
649 Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
650 Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
652 String interfaceName = elanInterface.getName();
653 String elanInstanceName = elanInterface.getElanInstanceName();
655 Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
656 WriteTransaction tx = broker.newWriteOnlyTransaction();
657 if (elanInfo == null) {
658 List<String> elanInterfaces = new ArrayList<>();
659 elanInterfaces.add(interfaceName);
660 ElanUtils.updateOperationalDataStore(broker, idManager,
661 elanInstance, elanInterfaces, tx);
663 createElanStateList(elanInstanceName, interfaceName, tx);
665 boolean isFirstInterfaceInDpn = false;
666 // Specific actions to the DPN where the ElanInterface has been added,
667 // for example, programming the
668 // External tunnel table if needed or adding the ElanInterface to the
669 // DpnInterfaces in the operational DS.
670 BigInteger dpId = interfaceInfo.getDpId();
671 DpnInterfaces dpnInterfaces = null;
672 if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
673 InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
674 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
675 Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
676 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
677 if (!existingElanDpnInterfaces.isPresent()) {
678 isFirstInterfaceInDpn = true;
679 // ELAN's 1st ElanInterface added to this DPN
680 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
681 // The 1st ElanInterface in a DPN must program the Ext Tunnel
682 // table, but only if Elan has VNI
683 if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
684 setExternalTunnelTable(dpId, elanInstance);
686 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
688 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
689 elanInterfaces.add(interfaceName);
690 if (elanInterfaces.size() == 1) { // 1st dpn interface
691 elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
693 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
697 // add code to install Local/Remote BC group, unknow DMAC entry,
698 // terminating service table flow entry
699 // call bindservice of interfacemanager to create ingress table flow
701 // Add interface to the ElanInterfaceForwardingEntires Container
702 createElanInterfaceTablesList(interfaceName, tx);
703 List<ListenableFuture<Void>> futures = new ArrayList<>();
704 futures.add(ElanUtils.waitForTransactionToComplete(tx));
705 installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces,
706 isFirstInterfaceInDpn, null);
708 // add the vlan provider interface to remote BC group for the elan
709 // for internal vlan networks
710 if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
711 if (interfaceManager.isExternalInterface(interfaceName)) {
712 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
713 handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
717 if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
718 //update the remote-DPNs remoteBC group entry with Tunnels
719 LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
720 setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
723 String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
724 InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
725 elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
726 jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
730 List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
731 ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
732 throws ElanException {
733 String elanInstanceName = elanInstance.getElanInstanceName();
734 String interfaceName = elanInterface.getName();
735 WriteTransaction tx = broker.newWriteOnlyTransaction();
736 BigInteger dpId = interfaceInfo.getDpId();
737 WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
738 installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
739 isFirstInterfaceInDpn, tx, writeFlowGroupTx);
741 List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
742 List<PhysAddress> staticMacAddresses = Lists.newArrayList();
744 boolean isInterfaceOperational = isOperational(interfaceInfo);
745 if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
746 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
747 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
748 staticMacEntry.getMacAddress());
749 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
750 LogicalDatastoreType.OPERATIONAL, macId);
751 if (existingMacEntry.isPresent()) {
752 elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
753 elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
754 existingMacEntry.get(), tx);
756 elanForwardingEntriesHandler
757 .addElanInterfaceForwardingTableList(elanInstance, interfaceName, staticMacEntry, tx);
760 if (isInterfaceOperational) {
761 // Setting SMAC, DMAC, UDMAC in this DPN and also in other
763 String macAddress = staticMacEntry.getMacAddress().getValue();
764 LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
765 macAddress, elanInstanceName, interfaceName);
766 elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
767 staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
771 if (isInterfaceOperational) {
772 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
774 for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
775 staticMacAddresses.add(staticMacEntry.getMacAddress());
777 elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
781 List<ListenableFuture<Void>> futures = new ArrayList<>();
782 futures.add(ElanUtils.waitForTransactionToComplete(tx));
783 futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
784 if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
785 //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
787 Port neutronPort = neutronVpnManager.getNeutronPort(interfaceName);
788 if (neutronPort != null) {
789 NeutronUtils.updatePortStatus(interfaceName, NeutronUtils.PORT_STATUS_ACTIVE, broker);
791 } catch (IllegalArgumentException ex) {
792 LOG.trace("Interface: {} is not part of Neutron Network", interfaceName);
798 protected void removeInterfaceStaticMacEntries(String elanInstanceName, String interfaceName,
799 PhysAddress physAddress) {
800 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
801 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
802 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
803 LogicalDatastoreType.OPERATIONAL, macId);
805 if (!existingMacEntry.isPresent()) {
809 MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
810 .setKey(new MacEntryKey(physAddress)).build();
811 WriteTransaction tx = broker.newWriteOnlyTransaction();
812 elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
813 ElanUtils.getElanInstanceByName(broker, elanInstanceName), interfaceInfo, macEntry, tx);
814 ElanUtils.waitForTransactionToComplete(tx);
817 private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
818 return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
819 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
822 private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
823 InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
824 WriteTransaction writeFlowGroupTx) throws ElanException {
825 if (!isOperational(interfaceInfo)) {
828 BigInteger dpId = interfaceInfo.getDpId();
829 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
830 elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
832 setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
833 if (isFirstInterfaceInDpn) {
834 // Terminating Service , UnknownDMAC Table.
835 // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
836 // for ELAN Instance is VxLAN
837 if (isVxlan(elanInstance)) {
838 setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
840 setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
842 * Install remote DMAC flow. This is required since this DPN is
843 * added later to the elan instance and remote DMACs of other
844 * interfaces in this elan instance are not present in the current
847 if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
848 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
849 elanInstance.getElanInstanceName());
850 programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
853 // bind the Elan service to the Interface
854 bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
857 public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
858 DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, WriteTransaction tx) {
859 if (!isOperational(interfaceInfo)) {
862 // LocalBroadcast Group creation with elan-Interfaces
863 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
864 if (isFirstInterfaceInDpn) {
865 LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
866 BigInteger dpId = interfaceInfo.getDpId();
867 // RemoteBroadcast Group creation
869 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
870 } catch (InterruptedException e1) {
871 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
873 setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
875 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
876 } catch (InterruptedException e1) {
877 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
882 public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
883 WriteTransaction writeFlowGroupTx) {
884 int ifTag = interfaceInfo.getInterfaceTag();
885 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
886 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
887 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
888 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
889 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
891 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
893 Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
894 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
895 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
896 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
898 mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
901 public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
902 WriteTransaction deleteFlowGroupTx) {
903 int ifTag = interfaceInfo.getInterfaceTag();
904 Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
905 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
906 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
907 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
908 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
910 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
912 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
913 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
914 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
915 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
917 mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
920 private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
921 InterfaceInfo interfaceInfo, long elanTag) {
922 return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart, elanTag);
926 public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
927 int bucketId, long elanTag) {
928 List<Bucket> listBucketInfo = new ArrayList<>();
929 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
931 if (isVxlan(elanInfo)) {
932 listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
933 elanUtils.isOpenstackVniSemanticsEnforced() ? elanInfo.getSegmentationId() : elanTag));
935 listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
936 getNextAvailableBucketId(listBucketInfo.size())));
937 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
938 getNextAvailableBucketId(listBucketInfo.size())));
939 listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
940 getNextAvailableBucketId(listBucketInfo.size())));
941 return listBucketInfo;
944 private int getNextAvailableBucketId(int bucketSize) {
945 return bucketSize + 1;
948 @SuppressWarnings("checkstyle:IllegalCatch")
949 private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
951 List<Bucket> listBucketInfo = new ArrayList<>();
952 if (elanDpns != null) {
953 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
954 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId)
955 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
957 List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
958 dpnInterface.getDpId(), elanTagOrVni);
959 if (listActionInfo.isEmpty()) {
962 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
963 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
965 } catch (Exception ex) {
966 LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
967 dpnId, dpnInterface.getDpId(), ex);
972 return listBucketInfo;
975 private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
976 DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
977 DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
978 if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
979 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
980 return Collections.emptyList();
982 List<Bucket> listBucketInfo = new ArrayList<>();
983 for (String interfaceName : currDpnInterfaces.getInterfaces()) {
984 if (interfaceManager.isExternalInterface(interfaceName)) {
985 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
986 if (!listActionInfo.isEmpty()) {
987 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
988 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
993 return listBucketInfo;
996 private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
997 if (elanDpns != null) {
998 for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
999 if (dpnInterface.getDpId().equals(dpnId)) {
1000 return dpnInterface;
1007 private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
1008 int elanTag = elanInfo.getElanTag().intValue();
1009 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1010 setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
1011 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1012 if (etreeInstance != null) {
1013 int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
1014 long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1015 setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
1019 @SuppressWarnings("checkstyle:IllegalCatch")
1020 private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
1022 ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
1023 if (elanDpns != null) {
1024 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1025 for (DpnInterfaces dpnInterface : dpnInterfaces) {
1026 List<Bucket> remoteListBucketInfo = new ArrayList<>();
1027 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
1028 && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
1029 List<Action> listAction = new ArrayList<>();
1031 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1032 remoteListBucketInfo.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
1033 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1035 for (DpnInterfaces otherFes : dpnInterfaces) {
1036 if (elanUtils.isDpnPresent(otherFes.getDpId()) && !Objects.equals(otherFes.getDpId(),
1037 dpnInterface.getDpId()) && otherFes.getInterfaces() != null
1038 && !otherFes.getInterfaces().isEmpty()) {
1040 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
1041 dpnInterface.getDpId(), otherFes.getDpId(),
1042 elanUtils.isOpenstackVniSemanticsEnforced() ? elanInfo.getSegmentationId()
1044 if (!remoteListActionInfo.isEmpty()) {
1045 remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
1046 .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1049 } catch (Exception ex) {
1050 LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
1051 + "Logical Group Interface not found between source Dpn - {}, "
1052 + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
1057 List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
1059 remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
1061 if (remoteListBucketInfo.isEmpty()) {
1062 LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
1065 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1066 MDSALUtil.buildBucketLists(remoteListBucketInfo));
1067 LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
1068 mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
1072 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1073 } catch (InterruptedException e1) {
1074 LOG.warn("Error while waiting for remote BC group on other DPNs for ELAN {} to install", elanInfo);
1080 * Returns the bucket info with the given interface as the only bucket.
1082 private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
1083 return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
1084 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
1087 private List<MatchInfo> buildMatchesForVni(Long vni) {
1088 List<MatchInfo> mkMatches = new ArrayList<>();
1089 MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
1090 mkMatches.add(match);
1094 private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
1095 List<InstructionInfo> mkInstructions = new ArrayList<>();
1096 mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
1097 return mkInstructions;
1100 private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
1101 List<MatchInfo> mkMatches = new ArrayList<>();
1102 // Matching metadata
1103 mkMatches.add(new MatchMetadata(
1104 ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1109 * Builds the list of instructions to be installed in the INTERNAL_TUNNEL_TABLE (36) / EXTERNAL_TUNNEL_TABLE (38)
1110 * which so far consists of writing the elanTag in metadata and send the packet to ELAN_DMAC_TABLE.
1113 * elanTag to be written in metadata when flow is selected
1114 * @return the instructions ready to be installed in a flow
1116 private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
1117 List<InstructionInfo> mkInstructions = new ArrayList<>();
1118 mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
1119 .getElanMetadataMask()));
1120 /* applicable for EXTERNAL_TUNNEL_TABLE only
1121 * TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
1123 mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
1124 return mkInstructions;
1127 // Install DMAC entry on dst DPN
1128 public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1129 BigInteger dstDpId) throws ElanException {
1130 String interfaceName = interfaceInfo.getInterfaceName();
1131 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
1132 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
1133 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
1134 WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
1135 for (MacEntry macEntry : macEntries) {
1136 String macAddress = macEntry.getMacAddress().getValue();
1137 LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
1138 synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
1139 interfaceInfo.getDpId())) {
1140 LOG.info("Acquired lock for mac : " + macAddress + ". Proceeding with remote dmac"
1141 + " install operation.");
1142 elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
1146 return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
1148 return Collections.emptyList();
1151 public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
1152 setupElanBroadcastGroups(elanInfo, null, dpnId);
1155 public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1156 setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1157 setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
1160 public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1161 List<Bucket> listBucket = new ArrayList<>();
1164 Long elanTag = elanInfo.getElanTag();
1165 List<Action> listAction = new ArrayList<>();
1166 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
1167 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1168 MDSALUtil.WATCH_GROUP));
1170 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
1171 listBucket.addAll(listBucketInfoRemote);
1172 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
1173 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1174 MDSALUtil.buildBucketLists(listBucket));
1175 LOG.trace("Installing the remote BroadCast Group:{}", group);
1176 mdsalManager.syncInstallGroup(dpnId, group);
1179 public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
1180 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1181 if (etreeInstance != null) {
1182 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1183 List<Bucket> listBucket = new ArrayList<>();
1186 List<Action> listAction = new ArrayList<>();
1187 listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
1188 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1189 MDSALUtil.WATCH_GROUP));
1191 List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
1193 listBucket.addAll(listBucketInfoRemote);
1194 long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
1195 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1196 MDSALUtil.buildBucketLists(listBucket));
1197 LOG.trace("Installing the remote BroadCast Group:{}", group);
1198 mdsalManager.syncInstallGroup(dpnId, group);
1202 private void createDropBucket(List<Bucket> listBucket) {
1203 List<Action> actionsInfos = new ArrayList<>();
1204 actionsInfos.add(new ActionDrop().buildAction());
1205 Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
1206 MDSALUtil.WATCH_GROUP);
1207 listBucket.add(dropBucket);
1210 public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1211 InterfaceInfo interfaceInfo) {
1212 setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1213 setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
1216 public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1217 InterfaceInfo interfaceInfo) {
1218 List<Bucket> listBucket = new ArrayList<>();
1220 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1222 List<String> interfaces = new ArrayList<>();
1223 if (newDpnInterface != null) {
1224 interfaces = newDpnInterface.getInterfaces();
1226 for (String ifName : interfaces) {
1227 // In case if there is a InterfacePort in the cache which is not in
1228 // operational state, skip processing it
1229 InterfaceInfo ifInfo = interfaceManager
1230 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1231 if (!isOperational(ifInfo)) {
1235 if (!interfaceManager.isExternalInterface(ifName)) {
1236 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1237 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1242 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1243 MDSALUtil.buildBucketLists(listBucket));
1244 LOG.trace("installing the localBroadCast Group:{}", group);
1245 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1248 private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
1249 InterfaceInfo interfaceInfo) {
1250 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1251 if (etreeInstance != null) {
1252 List<Bucket> listBucket = new ArrayList<>();
1255 List<String> interfaces = new ArrayList<>();
1256 if (newDpnInterface != null) {
1257 interfaces = newDpnInterface.getInterfaces();
1259 for (String ifName : interfaces) {
1260 // In case if there is a InterfacePort in the cache which is not
1262 // operational state, skip processing it
1263 InterfaceInfo ifInfo = interfaceManager
1264 .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
1265 if (!isOperational(ifInfo)) {
1269 if (!interfaceManager.isExternalInterface(ifName)) {
1270 // only add root interfaces
1271 bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
1275 if (listBucket.isEmpty()) { // No Buckets
1276 createDropBucket(listBucket);
1279 long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
1280 long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
1281 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1282 MDSALUtil.buildBucketLists(listBucket));
1283 LOG.trace("installing the localBroadCast Group:{}", group);
1284 mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
1288 private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
1289 InterfaceInfo ifInfo) {
1290 EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(broker, ifName);
1291 if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1292 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
1293 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1299 public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1300 WriteTransaction deleteFlowGroupTx) {
1301 BigInteger dpnId = interfaceInfo.getDpId();
1302 long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
1303 List<Bucket> listBuckets = new ArrayList<>();
1305 listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
1306 // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
1308 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1309 MDSALUtil.buildBucketLists(listBuckets));
1310 LOG.trace("deleted the localBroadCast Group:{}", group);
1311 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1314 public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
1315 WriteTransaction deleteFlowGroupTx) {
1318 Long elanTag = elanInfo.getElanTag();
1319 List<Bucket> listBuckets = new ArrayList<>();
1320 List<Action> listAction = new ArrayList<>();
1321 listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
1322 listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
1323 MDSALUtil.WATCH_GROUP));
1325 listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
1326 BigInteger dpnId = interfaceInfo.getDpId();
1327 long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
1328 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
1329 MDSALUtil.buildBucketLists(listBuckets));
1330 LOG.trace("deleting the remoteBroadCast group:{}", group);
1331 mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
1335 * Installs a flow in the External Tunnel table consisting in translating
1336 * the VNI retrieved from the packet that came over a tunnel with a TOR into
1337 * elanTag that will be used later in the ELANs pipeline.
1344 public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1345 long elanTag = elanInfo.getElanTag();
1346 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
1347 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
1348 elanInfo.getElanInstanceName(), // flowName
1351 ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
1352 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
1353 getInstructionsIntOrExtTunnelTable(elanTag));
1355 mdsalManager.installFlow(flowEntity);
1359 * Removes, from External Tunnel table, the flow that translates from VNI to
1360 * elanTag. Important: ensure this method is only called whenever there is
1361 * no other ElanInterface in the specified DPN
1364 * DPN whose Ext Tunnel table is going to be modified
1366 * holds the elanTag needed for selecting the flow to be removed
1368 public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
1369 // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
1370 // last ElanInstance plus
1371 // adding a new one does (almost at the same time) are executed in that
1374 String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
1375 FlowEntity flowEntity = new FlowEntityBuilder()
1377 .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
1380 mdsalManager.removeFlow(flowEntity);
1383 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1384 setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
1385 setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
1388 public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1389 WriteTransaction writeFlowGroupTx) {
1390 List<? extends MatchInfoBase> listMatchInfoBase;
1391 List<InstructionInfo> instructionInfos;
1393 if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
1394 serviceId = elanTag;
1395 listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
1396 instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
1398 serviceId = elanInfo.getSegmentationId();
1399 listMatchInfoBase = buildMatchesForVni(serviceId);
1400 instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
1402 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1403 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
1404 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
1406 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1409 private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
1410 WriteTransaction writeFlowGroupTx) {
1411 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1412 if (etreeInstance != null) {
1413 setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
1417 public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
1418 long elanTag = elanInfo.getElanTag();
1419 installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1420 installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
1421 setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
1424 private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1425 WriteTransaction writeFlowGroupTx) {
1426 EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1427 if (etreeLeafTag != null) {
1428 long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
1429 installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1430 installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
1434 private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1435 WriteTransaction writeFlowGroupTx) {
1436 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1437 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
1438 5, elanInfo.getElanInstanceName(), 0, 0,
1439 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1440 getMatchesForElanTag(elanTag, /* SH flag */false),
1441 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
1443 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1446 private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
1447 WriteTransaction writeFlowGroupTx) {
1448 // only if ELAN can connect to external network, perform the following
1450 if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
1451 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1452 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */true),
1453 5, elanInfo.getElanInstanceName(), 0, 0,
1454 ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1455 getMatchesForElanTag(elanTag, /* SH flag */true),
1456 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
1457 mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
1462 private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
1464 Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1465 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
1466 mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
1468 if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
1469 Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
1470 elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
1472 mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
1476 private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1477 elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1480 private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
1481 if (isStandardElanService(elanInterface)) {
1482 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
1483 elanInterface.getName(), lportTag, tx);
1484 } else { // Etree service
1485 bindEtreeService(elanInfo, elanInterface, lportTag, tx);
1489 private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
1490 WriteTransaction tx) {
1491 int instructionKey = 0;
1492 List<Instruction> instructions = new ArrayList<>();
1493 instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
1494 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1496 List<Action> actions = new ArrayList<>();
1497 actions.add(new ActionRegLoad(0, NxmNxReg1.class, 0, ElanConstants.INTERFACE_TAG_LENGTH - 1,
1498 lportTag).buildAction());
1499 actions.add(new ActionRegLoad(1, ElanConstants.ELAN_REG_ID, 0, ElanConstants.ELAN_TAG_LENGTH - 1,
1500 elanTag).buildAction());
1501 instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
1503 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
1506 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1507 BoundServices serviceInfo = ElanUtils.getBoundServices(
1508 String.format("%s.%s.%s", "elan", elanInstanceName, interfaceName), elanServiceIndex,
1509 NwConstants.ELAN_SERVICE_INDEX, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1510 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1511 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1513 if (!existingElanService.isPresent()) {
1514 tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
1515 WriteTransaction.CREATE_MISSING_PARENTS);
1519 private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
1520 WriteTransaction tx) {
1521 if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1522 bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
1525 EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
1526 if (etreeInstance == null) {
1527 LOG.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
1528 + elanInfo.getElanInstanceName());
1530 bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
1531 elanInterface.getName(), lportTag, tx);
1536 private boolean isStandardElanService(ElanInterface elanInterface) {
1537 return elanInterface.getAugmentation(EtreeInterface.class) == null;
1540 protected void unbindService(String interfaceName, WriteTransaction tx) {
1541 short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1542 InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
1543 Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
1545 if (existingElanService.isPresent()) {
1546 tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
1550 private String getFlowRef(long tableId, long elanTag) {
1551 return String.valueOf(tableId) + elanTag;
1554 private String getFlowRef(long tableId, long elanTag, String flowName) {
1555 return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
1556 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
1559 private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1560 return String.valueOf(tableId) + elanTag + shFlag;
1563 private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1564 List<Action> listAction = new ArrayList<>();
1567 new ActionSetFieldTunnelId(BigInteger.valueOf(interfaceInfo.getInterfaceTag())).buildAction(actionKey));
1569 listAction.add(new ActionNxResubmit(NwConstants.ELAN_FILTER_EQUALS_TABLE).buildAction(actionKey));
1573 private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
1574 List<String> interfaceNames, WriteTransaction tx) {
1575 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1576 .setKey(new DpnInterfacesKey(dpId)).build();
1577 tx.put(LogicalDatastoreType.OPERATIONAL,
1578 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1579 WriteTransaction.CREATE_MISSING_PARENTS);
1580 return dpnInterface;
1584 * Delete elan dpn interface from operational DS.
1586 * @param elanInstanceName
1587 * the elan instance name
1591 private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1592 InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
1593 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
1594 Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
1595 LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1596 if (dpnInterfaces.isPresent()) {
1597 tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
1601 private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
1602 WriteTransaction tx) {
1603 List<String> interfaceNames = new ArrayList<>();
1604 interfaceNames.add(interfaceName);
1605 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
1606 .setKey(new DpnInterfacesKey(dpId)).build();
1607 tx.put(LogicalDatastoreType.OPERATIONAL,
1608 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
1609 WriteTransaction.CREATE_MISSING_PARENTS);
1610 return dpnInterface;
1613 private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1614 InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
1615 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1616 Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
1617 LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1618 // Adding new Elan Interface Port to the operational DataStore without
1619 // Static-Mac Entries..
1620 if (!interfaceMacTables.isPresent()) {
1621 ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
1622 .setKey(new ElanInterfaceMacKey(interfaceName)).build();
1623 tx.put(LogicalDatastoreType.OPERATIONAL,
1624 ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
1625 WriteTransaction.CREATE_MISSING_PARENTS);
1629 private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1630 InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1631 Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
1632 LogicalDatastoreType.OPERATIONAL, elanInstance);
1633 // Adding new Elan Interface Port to the operational DataStore without
1634 // Static-Mac Entries..
1635 if (elanInterfaceLists.isPresent()) {
1636 List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1637 if (interfaceLists == null) {
1638 interfaceLists = new ArrayList<>();
1640 interfaceLists.add(interfaceName);
1641 Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
1642 .setKey(new ElanKey(elanInstanceName)).build();
1643 tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1644 elanState, WriteTransaction.CREATE_MISSING_PARENTS);
1648 private boolean isOperational(InterfaceInfo interfaceInfo) {
1649 if (interfaceInfo == null) {
1652 return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1655 @SuppressWarnings("checkstyle:IllegalCatch")
1656 public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) throws ElanException {
1657 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1658 LOG.trace("processing tunnel state event for srcDpId {} dstDpId {}"
1659 + " and dpnInterfaceList {}", srcDpId, dstDpId, dpnInterfaceLists);
1660 if (dpnInterfaceLists == null) {
1663 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1664 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1666 String elanName = elanDpns.getElanInstanceName();
1667 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1668 if (elanInfo == null) {
1669 LOG.warn("ELAN Info is null for elanName {} that does exist in elanDpnInterfaceList, "
1670 + "skipping this ELAN for tunnel handling", elanName);
1673 if (ElanUtils.isFlat(elanInfo) || ElanUtils.isVlan(elanInfo)) {
1674 LOG.debug("Ignoring internal tunnel state event for Flat/Vlan elan {}", elanName);
1677 List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1678 if (dpnInterfaces == null) {
1681 DpnInterfaces dstDpnIf = null;
1682 for (DpnInterfaces dpnIf : dpnInterfaces) {
1683 BigInteger dpnIfDpId = dpnIf.getDpId();
1684 if (dpnIfDpId.equals(srcDpId)) {
1686 } else if (dpnIfDpId.equals(dstDpId)) {
1692 LOG.info("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1693 final DpnInterfaces finalDstDpnIf = dstDpnIf; // var needs to be final so it can be accessed in lambda
1694 jobCoordinator.enqueueJob(elanName, () -> {
1695 // update Remote BC Group
1696 LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
1698 setupElanBroadcastGroups(elanInfo, srcDpId);
1699 } catch (RuntimeException e) {
1700 LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
1702 Set<String> interfaceLists = new HashSet<>();
1703 interfaceLists.addAll(finalDstDpnIf.getInterfaces());
1704 for (String ifName : interfaceLists) {
1705 jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(ifName), () -> {
1706 LOG.info("Processing tunnel up event for elan {} and interface {}", elanName, ifName);
1707 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
1708 if (isOperational(interfaceInfo)) {
1709 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1711 return Collections.emptyList();
1712 }, ElanConstants.JOB_MAX_RETRIES);
1714 return Collections.emptyList();
1715 }, ElanConstants.JOB_MAX_RETRIES);
1722 * Handle external tunnel state event.
1724 * @param externalTunnel
1725 * the external tunnel
1728 * @throws ElanException in case of issues creating the flow objects
1730 public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
1731 if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1734 // dpId/externalNodeId will be available either in source or destination
1735 // based on the tunnel end point
1736 BigInteger dpId = null;
1737 NodeId externalNodeId = null;
1738 if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1739 dpId = new BigInteger(externalTunnel.getSourceDevice());
1740 externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1741 } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1742 dpId = new BigInteger(externalTunnel.getDestinationDevice());
1743 externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1745 if (dpId == null || externalNodeId == null) {
1746 LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1750 ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
1751 if (dpnInterfaceLists == null) {
1754 List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1755 for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1756 String elanName = elanDpns.getElanInstanceName();
1757 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
1759 DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1760 if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1761 || dpnInterfaces.getInterfaces().isEmpty()) {
1764 LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1766 setupElanBroadcastGroups(elanInfo, dpId);
1767 // install L2gwDevices local macs in dpn.
1768 elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
1769 // Install dpn macs on external device
1770 installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1773 LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1777 * Installs dpn macs in external device. first it checks if the physical
1778 * locator towards this dpn tep is present or not if the physical locator is
1779 * present go ahead and add the ucast macs otherwise update the mcast mac
1780 * entry to include this dpn tep ip and schedule the job to put ucast macs
1781 * once the physical locator is programmed in device
1785 * @param lstElanInterfaceNames
1786 * the lst Elan interface names
1789 * @param externalNodeId
1790 * the external node id
1792 private void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames, BigInteger dpnId,
1793 NodeId externalNodeId) {
1794 L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
1795 externalNodeId.getValue());
1796 if (elanL2GwDevice == null) {
1797 LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
1800 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, externalNodeId);
1801 if (dpnTepIp == null) {
1802 LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}", dpnId,
1807 String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
1808 RemoteMcastMacs remoteMcastMac = elanL2GatewayUtils.readRemoteMcastMac(externalNodeId, logicalSwitchName,
1809 LogicalDatastoreType.OPERATIONAL);
1810 boolean phyLocAlreadyExists =
1811 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
1813 LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
1814 phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
1815 List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
1817 if (phyLocAlreadyExists) {
1818 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1821 elanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
1822 elanL2GatewayUtils.scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
1826 * Validate external tunnel state event.
1828 * @param externalTunnel
1829 * the external tunnel
1832 * @return true, if successful
1834 private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1835 if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1836 String srcDevice = externalTunnel.getDestinationDevice();
1837 String destDevice = externalTunnel.getSourceDevice();
1838 ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
1839 LogicalDatastoreType.CONFIGURATION);
1840 LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1841 otherEndPointExtTunnel);
1842 if (otherEndPointExtTunnel != null) {
1843 boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
1844 otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
1845 if (otherEndPointInterfaceOperational) {
1848 LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1849 otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1856 private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
1857 List<MatchInfo> mkMatches = new ArrayList<>();
1858 // Matching metadata
1860 new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG));
1861 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
1865 public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
1866 List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
1867 for (DpnInterfaces dpn : dpns) {
1868 setupElanBroadcastGroups(elanInfo, dpn.getDpId());
1872 public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
1874 List<Bucket> listBucketInfo = new ArrayList<>();
1875 ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
1876 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
1877 for (L2GatewayDevice device : map.values()) {
1878 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1879 device.getHwvtepNodeId());
1880 if (interfaceName == null) {
1883 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
1884 ElanUtils.getVxlanSegmentationId(elanInfo));
1885 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1886 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1889 return listBucketInfo;
1892 public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
1894 List<Bucket> listBucketInfo = new ArrayList<>();
1895 List<ExternalTeps> teps = elanInfo.getExternalTeps();
1896 if (teps == null || teps.isEmpty()) {
1897 return listBucketInfo;
1899 for (ExternalTeps tep : teps) {
1900 String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1901 tep.getTepIp().toString());
1902 if (interfaceName == null) {
1903 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
1906 List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
1907 elanInfo.getSegmentationId());
1908 listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1909 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1912 return listBucketInfo;
1916 protected ElanInterfaceManager getDataTreeChangeListener() {
1920 public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
1922 LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
1923 setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
1925 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
1926 } catch (InterruptedException e) {
1927 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInstance);