2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.elan.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
27 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
28 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
29 import org.opendaylight.netvirt.elan.ElanException;
30 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
31 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
32 import org.opendaylight.netvirt.elan.utils.ElanConstants;
33 import org.opendaylight.netvirt.elan.utils.ElanUtils;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 public class ElanLearntVpnVipToPortListener extends
48 AsyncDataTreeChangeListenerBase<LearntVpnVipToPort, ElanLearntVpnVipToPortListener> {
49 private static final Logger LOG = LoggerFactory.getLogger(ElanLearntVpnVipToPortListener.class);
50 private final DataBroker broker;
51 private final ManagedNewTransactionRunner txRunner;
52 private final IInterfaceManager interfaceManager;
53 private final ElanUtils elanUtils;
54 private final JobCoordinator jobCoordinator;
55 private final ElanInstanceCache elanInstanceCache;
56 private final ElanInterfaceCache elanInterfaceCache;
59 public ElanLearntVpnVipToPortListener(DataBroker broker, IInterfaceManager interfaceManager, ElanUtils elanUtils,
60 JobCoordinator jobCoordinator, ElanInstanceCache elanInstanceCache, ElanInterfaceCache elanInterfaceCache) {
61 super(LearntVpnVipToPort.class, ElanLearntVpnVipToPortListener.class);
63 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
64 this.interfaceManager = interfaceManager;
65 this.elanUtils = elanUtils;
66 this.jobCoordinator = jobCoordinator;
67 this.elanInstanceCache = elanInstanceCache;
68 this.elanInterfaceCache = elanInterfaceCache;
74 registerListener(LogicalDatastoreType.OPERATIONAL, broker);
78 protected InstanceIdentifier<LearntVpnVipToPort> getWildCardPath() {
79 return InstanceIdentifier.create(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class);
83 protected void remove(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
84 String macAddress = dataObjectModification.getMacAddress();
85 String interfaceName = dataObjectModification.getPortName();
86 LOG.trace("Removing mac address {} from interface {} ", macAddress, interfaceName);
87 jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
88 new StaticMacRemoveWorker(macAddress, interfaceName));
92 protected void update(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModificationBefore,
93 LearntVpnVipToPort dataObjectModificationAfter) {
97 protected void add(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
98 String macAddress = dataObjectModification.getMacAddress();
99 String interfaceName = dataObjectModification.getPortName();
100 LOG.trace("Adding mac address {} to interface {} ", macAddress, interfaceName);
101 jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
102 new StaticMacAddWorker(macAddress, interfaceName));
106 protected ElanLearntVpnVipToPortListener getDataTreeChangeListener() {
110 private class StaticMacAddWorker implements Callable<List<ListenableFuture<Void>>> {
112 String interfaceName;
114 StaticMacAddWorker(String macAddress, String interfaceName) {
115 this.macAddress = macAddress;
116 this.interfaceName = interfaceName;
120 public List<ListenableFuture<Void>> call() throws Exception {
121 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
122 if (!elanInterface.isPresent()) {
123 LOG.debug("ElanInterface Not present for interfaceName {} for add event", interfaceName);
124 return Collections.emptyList();
126 List<ListenableFuture<Void>> futures = new ArrayList<>();
127 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(interfaceTx -> futures.add(
128 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
129 flowTx -> addMacEntryToDsAndSetupFlows(elanInterface.get().getElanInstanceName(),
130 interfaceTx, flowTx, ElanConstants.STATIC_MAC_TIMEOUT)))));
134 private void addMacEntryToDsAndSetupFlows(String elanName, WriteTransaction interfaceTx,
135 WriteTransaction flowTx, int macTimeOut) throws ElanException {
136 LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
137 + "ElanForwardingTables DS", macAddress, interfaceName);
138 BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
139 PhysAddress physAddress = new PhysAddress(macAddress);
140 MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
141 .setKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
142 .setIsStaticAddress(false).build();
143 InstanceIdentifier<MacEntry> macEntryId = ElanUtils
144 .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
145 interfaceTx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry);
146 InstanceIdentifier<MacEntry> elanMacEntryId =
147 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
148 interfaceTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
149 ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
150 elanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut,
151 macAddress, true, flowTx);
155 private class StaticMacRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
157 String interfaceName;
159 StaticMacRemoveWorker(String macAddress, String interfaceName) {
160 this.macAddress = macAddress;
161 this.interfaceName = interfaceName;
165 public List<ListenableFuture<Void>> call() {
166 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
167 if (!elanInterface.isPresent()) {
168 LOG.debug("ElanInterface Not present for interfaceName {} for delete event", interfaceName);
169 return Collections.emptyList();
171 List<ListenableFuture<Void>> futures = new ArrayList<>();
172 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(interfaceTx -> futures.add(
173 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
174 flowTx -> deleteMacEntryFromDsAndRemoveFlows(elanInterface.get().getElanInstanceName(),
175 interfaceTx, flowTx)))));
179 private void deleteMacEntryFromDsAndRemoveFlows(String elanName, WriteTransaction interfaceTx,
180 WriteTransaction flowTx) {
181 LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
182 + "and ElanForwardingTables DS", macAddress, interfaceName);
183 PhysAddress physAddress = new PhysAddress(macAddress);
184 MacEntry macEntry = elanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
185 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
186 if (macEntry != null && interfaceInfo != null) {
187 elanUtils.deleteMacFlows(elanInstanceCache.get(elanName).orNull(), interfaceInfo, macEntry, flowTx);
188 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
189 ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
190 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
191 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
196 private String buildJobKey(String mac, String interfaceName) {
197 return "ENTERPRISEMACJOB" + mac + interfaceName;