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
10 package org.opendaylight.netvirt.elan.internal;
12 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
13 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Optional;
21 import java.util.concurrent.Callable;
22 import java.util.concurrent.ExecutionException;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
26 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
27 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
28 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
30 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
31 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
32 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
33 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
34 import org.opendaylight.infrautils.utils.concurrent.Executors;
35 import org.opendaylight.mdsal.binding.api.DataBroker;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
38 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
39 import org.opendaylight.netvirt.elan.utils.ElanConstants;
40 import org.opendaylight.netvirt.elan.utils.ElanUtils;
41 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 public class ElanLearntVpnVipToPortListener extends
56 AbstractAsyncDataTreeChangeListener<LearntVpnVipToPort> {
57 private static final Logger LOG = LoggerFactory.getLogger(ElanLearntVpnVipToPortListener.class);
58 private final DataBroker broker;
59 private final ManagedNewTransactionRunner txRunner;
60 private final IInterfaceManager interfaceManager;
61 private final ElanUtils elanUtils;
62 private final JobCoordinator jobCoordinator;
63 private final ElanInstanceCache elanInstanceCache;
64 private final ElanInterfaceCache elanInterfaceCache;
67 public ElanLearntVpnVipToPortListener(DataBroker broker, IInterfaceManager interfaceManager, ElanUtils elanUtils,
68 JobCoordinator jobCoordinator, ElanInstanceCache elanInstanceCache, ElanInterfaceCache elanInterfaceCache) {
69 super(broker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(LearntVpnVipToPortData.class)
70 .child(LearntVpnVipToPort.class),
71 Executors.newListeningSingleThreadExecutor("ElanLearntVpnVipToPortListener", LOG));
73 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
74 this.interfaceManager = interfaceManager;
75 this.elanUtils = elanUtils;
76 this.jobCoordinator = jobCoordinator;
77 this.elanInstanceCache = elanInstanceCache;
78 this.elanInterfaceCache = elanInterfaceCache;
82 LOG.info("{} registered", getClass().getSimpleName());
84 // ELAN will learn the MAC by itself using ElanPacketInHandler class.
85 //registerListener(LogicalDatastoreType.OPERATIONAL, broker);
90 public 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 public void update(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModificationBefore,
100 LearntVpnVipToPort dataObjectModificationAfter) {
104 public 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));
112 private class StaticMacAddWorker implements Callable<List<? extends ListenableFuture<?>>> {
114 String interfaceName;
116 StaticMacAddWorker(String macAddress, String interfaceName) {
117 this.macAddress = macAddress;
118 this.interfaceName = interfaceName;
122 public List<ListenableFuture<Void>> call() {
123 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
124 if (!elanInterface.isPresent()) {
125 LOG.debug("ElanInterface Not present for interfaceName {} for add event", interfaceName);
126 return Collections.emptyList();
128 List<ListenableFuture<Void>> futures = new ArrayList<>();
129 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, interfaceTx ->
130 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, flowTx ->
131 addMacEntryToDsAndSetupFlows(elanInterface.get().getElanInstanceName(), interfaceTx,
132 flowTx, ElanConstants.STATIC_MAC_TIMEOUT)))));
136 private void addMacEntryToDsAndSetupFlows(String elanName, TypedWriteTransaction<Operational> interfaceTx,
137 TypedWriteTransaction<Configuration> flowTx, int macTimeOut) {
138 LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
139 + "ElanForwardingTables DS", macAddress, interfaceName);
140 BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
141 PhysAddress physAddress = new PhysAddress(macAddress);
142 MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
143 .withKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
144 .setIsStaticAddress(false).build();
145 InstanceIdentifier<MacEntry> macEntryId = ElanUtils
146 .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
147 interfaceTx.put(macEntryId, macEntry);
148 InstanceIdentifier<MacEntry> elanMacEntryId =
149 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
150 interfaceTx.put(elanMacEntryId, macEntry);
151 ElanInstance elanInstance = elanInstanceCache.get(elanName).orElse(null);
152 elanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut,
153 macAddress, true, flowTx);
157 private class StaticMacRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
159 String interfaceName;
161 StaticMacRemoveWorker(String macAddress, String interfaceName) {
162 this.macAddress = macAddress;
163 this.interfaceName = interfaceName;
167 public List<ListenableFuture<Void>> call() {
168 Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
169 if (!elanInterface.isPresent()) {
170 LOG.debug("ElanInterface Not present for interfaceName {} for delete event", interfaceName);
171 return Collections.emptyList();
173 List<ListenableFuture<Void>> futures = new ArrayList<>();
174 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, interfaceTx ->
175 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx ->
176 deleteMacEntryFromDsAndRemoveFlows(elanInterface.get().getElanInstanceName(),
177 interfaceTx, flowTx)))));
181 private void deleteMacEntryFromDsAndRemoveFlows(String elanName,
182 TypedWriteTransaction<Operational> interfaceTx, TypedReadWriteTransaction<Configuration> flowTx)
183 throws ExecutionException, InterruptedException {
184 LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
185 + "and ElanForwardingTables DS", macAddress, interfaceName);
186 PhysAddress physAddress = new PhysAddress(macAddress);
187 MacEntry macEntry = elanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
188 InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
189 if (macEntry != null && interfaceInfo != null) {
190 elanUtils.deleteMacFlows(elanInstanceCache.get(elanName).orElse(null), interfaceInfo, macEntry, flowTx);
192 ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
194 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
199 private static String buildJobKey(String mac, String interfaceName) {
200 return "ENTERPRISEMACJOB" + mac + interfaceName;