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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.ExecutionException;
21 import javax.annotation.PostConstruct;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
26 import org.opendaylight.genius.infra.Datastore.Configuration;
27 import org.opendaylight.genius.infra.Datastore.Operational;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
31 import org.opendaylight.genius.infra.TypedWriteTransaction;
32 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
33 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
36 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
37 import org.opendaylight.netvirt.elan.utils.ElanConstants;
38 import org.opendaylight.netvirt.elan.utils.ElanUtils;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 public class ElanLearntVpnVipToPortListener extends
53 AsyncDataTreeChangeListenerBase<LearntVpnVipToPort, ElanLearntVpnVipToPortListener> {
54 private static final Logger LOG = LoggerFactory.getLogger(ElanLearntVpnVipToPortListener.class);
55 private final DataBroker broker;
56 private final ManagedNewTransactionRunner txRunner;
57 private final IInterfaceManager interfaceManager;
58 private final ElanUtils elanUtils;
59 private final JobCoordinator jobCoordinator;
60 private final ElanInstanceCache elanInstanceCache;
61 private final ElanInterfaceCache elanInterfaceCache;
64 public ElanLearntVpnVipToPortListener(DataBroker broker, IInterfaceManager interfaceManager, ElanUtils elanUtils,
65 JobCoordinator jobCoordinator, ElanInstanceCache elanInstanceCache, ElanInterfaceCache elanInterfaceCache) {
66 super(LearntVpnVipToPort.class, ElanLearntVpnVipToPortListener.class);
68 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
69 this.interfaceManager = interfaceManager;
70 this.elanUtils = elanUtils;
71 this.jobCoordinator = jobCoordinator;
72 this.elanInstanceCache = elanInstanceCache;
73 this.elanInterfaceCache = elanInterfaceCache;
79 /* ELAN will learn the MAC by itself using ElanPacketInHandler class.
80 registerListener(LogicalDatastoreType.OPERATIONAL, broker);
85 protected InstanceIdentifier<LearntVpnVipToPort> getWildCardPath() {
86 return InstanceIdentifier.create(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class);
90 protected void remove(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
91 String macAddress = dataObjectModification.getMacAddress();
92 String interfaceName = dataObjectModification.getPortName();
93 LOG.trace("Removing mac address {} from interface {} ", macAddress, interfaceName);
94 jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
95 new StaticMacRemoveWorker(macAddress, interfaceName));
99 protected void update(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModificationBefore,
100 LearntVpnVipToPort dataObjectModificationAfter) {
104 protected void add(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
105 String macAddress = dataObjectModification.getMacAddress();
106 String interfaceName = dataObjectModification.getPortName();
107 LOG.trace("Adding mac address {} to interface {} ", macAddress, interfaceName);
108 jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
109 new StaticMacAddWorker(macAddress, interfaceName));
113 protected ElanLearntVpnVipToPortListener getDataTreeChangeListener() {
117 private class StaticMacAddWorker implements Callable<List<ListenableFuture<Void>>> {
119 String interfaceName;
121 StaticMacAddWorker(String macAddress, String interfaceName) {
122 this.macAddress = macAddress;
123 this.interfaceName = interfaceName;
127 public List<ListenableFuture<Void>> call() {
128 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
129 if (!elanInterface.isPresent()) {
130 LOG.debug("ElanInterface Not present for interfaceName {} for add event", interfaceName);
131 return Collections.emptyList();
133 List<ListenableFuture<Void>> futures = new ArrayList<>();
134 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, interfaceTx ->
135 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, flowTx ->
136 addMacEntryToDsAndSetupFlows(elanInterface.get().getElanInstanceName(), interfaceTx,
137 flowTx, ElanConstants.STATIC_MAC_TIMEOUT)))));
141 private void addMacEntryToDsAndSetupFlows(String elanName, TypedWriteTransaction<Operational> interfaceTx,
142 TypedWriteTransaction<Configuration> flowTx, int macTimeOut) {
143 LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
144 + "ElanForwardingTables DS", macAddress, interfaceName);
145 BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
146 PhysAddress physAddress = new PhysAddress(macAddress);
147 MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
148 .withKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
149 .setIsStaticAddress(false).build();
150 InstanceIdentifier<MacEntry> macEntryId = ElanUtils
151 .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
152 interfaceTx.put(macEntryId, macEntry);
153 InstanceIdentifier<MacEntry> elanMacEntryId =
154 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
155 interfaceTx.put(elanMacEntryId, macEntry);
156 ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
157 elanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut,
158 macAddress, true, flowTx);
162 private class StaticMacRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
164 String interfaceName;
166 StaticMacRemoveWorker(String macAddress, String interfaceName) {
167 this.macAddress = macAddress;
168 this.interfaceName = interfaceName;
172 public List<ListenableFuture<Void>> call() {
173 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
174 if (!elanInterface.isPresent()) {
175 LOG.debug("ElanInterface Not present for interfaceName {} for delete event", interfaceName);
176 return Collections.emptyList();
178 List<ListenableFuture<Void>> futures = new ArrayList<>();
179 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, interfaceTx ->
180 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx ->
181 deleteMacEntryFromDsAndRemoveFlows(elanInterface.get().getElanInstanceName(),
182 interfaceTx, flowTx)))));
186 private void deleteMacEntryFromDsAndRemoveFlows(String elanName,
187 TypedWriteTransaction<Operational> interfaceTx, TypedReadWriteTransaction<Configuration> flowTx)
188 throws ExecutionException, InterruptedException {
189 LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
190 + "and ElanForwardingTables DS", macAddress, interfaceName);
191 PhysAddress physAddress = new PhysAddress(macAddress);
192 MacEntry macEntry = elanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
193 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
194 if (macEntry != null && interfaceInfo != null) {
195 elanUtils.deleteMacFlows(elanInstanceCache.get(elanName).orNull(), interfaceInfo, macEntry, flowTx);
197 ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
199 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
204 private static String buildJobKey(String mac, String interfaceName) {
205 return "ENTERPRISEMACJOB" + mac + interfaceName;