2 * Copyright (c) 2015 - 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.vpnservice;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.List;
13 import java.util.concurrent.*;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import org.opendaylight.bgpmanager.api.IBgpManager;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnIdBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnRouteList;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
29 import org.opendaylight.yangtools.concepts.ListenerRegistration;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
33 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
39 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
40 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpDataBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 import com.google.common.base.Optional;
52 import com.google.common.util.concurrent.FutureCallback;
53 import com.google.common.util.concurrent.Futures;
55 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
56 private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
57 private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration, opListenerRegistration;
58 private ConcurrentMap<String, Runnable> vpnOpMap = new ConcurrentHashMap<String, Runnable>();
59 private ExecutorService executorService = Executors.newSingleThreadExecutor();
60 private final DataBroker broker;
61 private final IBgpManager bgpManager;
62 private IdManagerService idManager;
63 private VpnInterfaceManager vpnInterfaceManager;
64 private final FibEntriesListener fibListener;
65 private final VpnInstanceOpListener vpnInstOpListener;
67 private static final FutureCallback<Void> DEFAULT_CALLBACK =
68 new FutureCallback<Void>() {
69 public void onSuccess(Void result) {
70 LOG.debug("Success in Datastore operation");
73 public void onFailure(Throwable error) {
74 LOG.error("Error in Datastore operation", error);
79 * Listens for data change related to VPN Instance
80 * Informs the BGP about VRF information
82 * @param db - dataBroker reference
84 public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
85 super(VpnInstance.class);
87 this.bgpManager = bgpManager;
88 this.fibListener = new FibEntriesListener();
89 this.vpnInstOpListener = new VpnInstanceOpListener();
93 private void registerListener(final DataBroker db) {
95 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
96 getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
97 fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
98 getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
99 opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
100 getVpnInstanceOpListenerPath(), vpnInstOpListener, DataChangeScope.SUBTREE);
102 } catch (final Exception e) {
103 LOG.error("VPN Service DataChange listener registration fail !", e);
104 throw new IllegalStateException("VPN Service registration Listener failed.", e);
108 public void setIdManager(IdManagerService idManager) {
109 this.idManager = idManager;
112 public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
113 this.vpnInterfaceManager = vpnInterfaceManager;
116 private void waitForOpDataRemoval(String id) {
117 //wait till DCN for removal of all DPNs in VPN arrivaes
118 Runnable notifyTask = new VpnNotifyTask();
119 synchronized (id.intern()) {
120 vpnOpMap.put(id, notifyTask);
121 synchronized (notifyTask) {
123 notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
124 } catch (InterruptedException e) {
132 protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
133 LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
134 String vpnName = del.getVpnInstanceName();
136 //Clean up vpn Interface
137 InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
138 Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
140 if(optionalVpnInterfaces.isPresent()) {
141 List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
142 for(VpnInterface vpnInterface : vpnInterfaces) {
143 if(vpnInterface.getVpnInstanceName().equals(vpnName)) {
144 LOG.debug("VpnInterface {} will be removed from VPN {}", vpnInterface.getName(), vpnName);
145 vpnInterfaceManager.remove(
146 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
150 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
151 vpnIdentifier = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
152 delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
154 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
155 String rd = del.getIpv4Family().getRouteDistinguisher();
160 bgpManager.deleteVrf(rd);
161 } catch (Exception e) {
162 LOG.error("Exception when removing VRF from BGP", e);
164 waitForOpDataRemoval(rd);
165 delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd));
167 waitForOpDataRemoval(vpnName);
168 delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
173 protected void update(InstanceIdentifier<VpnInstance> identifier,
174 VpnInstance original, VpnInstance update) {
175 LOG.trace("Update event - Key: {}, value: {}", identifier, update);
179 protected void add(InstanceIdentifier<VpnInstance> identifier,
181 LOG.trace("VPN Instance key: {}, value: {}", identifier, value);
182 VpnAfConfig config = value.getIpv4Family();
183 String rd = config.getRouteDistinguisher();
185 long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, value.getVpnInstanceName());
186 LOG.trace("VPN instance to ID generated.");
187 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
188 vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(value.getVpnInstanceName(), vpnId,
189 (rd != null) ? rd : value.getVpnInstanceName());
191 syncWrite(LogicalDatastoreType.CONFIGURATION,
192 VpnUtil.getVpnInstanceToVpnIdIdentifier(value.getVpnInstanceName()),
193 vpnInstanceToVpnId, DEFAULT_CALLBACK);
197 syncWrite(LogicalDatastoreType.OPERATIONAL,
198 VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()),
199 VpnUtil.getVpnInstanceOpDataBuilder(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK);
202 syncWrite(LogicalDatastoreType.OPERATIONAL,
203 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
204 VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId), DEFAULT_CALLBACK);
206 List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
208 List<String> ertList = new ArrayList<String>();
209 List<String> irtList = new ArrayList<String>();
211 for (VpnTarget vpnTarget : vpnTargetList) {
212 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
213 ertList.add(vpnTarget.getVrfRTValue());
215 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
216 irtList.add(vpnTarget.getVrfRTValue());
218 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
219 ertList.add(vpnTarget.getVrfRTValue());
220 irtList.add(vpnTarget.getVrfRTValue());
225 bgpManager.addVrf(rd, irtList, ertList);
226 } catch(Exception e) {
227 LOG.error("Exception when adding VRF to BGP", e);
230 //Try to add up vpn Interfaces if already in Operational Datastore
231 LOG.trace("Trying to add the vpn interfaces -1.");
232 InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
233 Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, vpnInterfacesId);
235 if(optionalVpnInterfaces.isPresent()) {
236 List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
237 for(VpnInterface vpnInterface : vpnInterfaces) {
238 if(vpnInterface.getVpnInstanceName().equals(value.getVpnInstanceName())) {
239 LOG.debug("VpnInterface {} will be added from VPN {}", vpnInterface.getName(), value.getVpnInstanceName());
240 vpnInterfaceManager.add(
241 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
248 private InstanceIdentifier<?> getWildCardPath() {
249 return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
252 private InstanceIdentifier<?> getFibEntryListenerPath() {
253 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
254 .child(VrfEntry.class);
257 private InstanceIdentifier<?> getVpnInstanceOpListenerPath() {
258 return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
263 public void close() throws Exception {
264 if (listenerRegistration != null) {
266 listenerRegistration.close();
267 } catch (final Exception e) {
268 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
270 listenerRegistration = null;
272 if (fibListenerRegistration != null) {
274 fibListenerRegistration.close();
275 } catch (final Exception e) {
276 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
278 fibListenerRegistration = null;
280 if (opListenerRegistration != null) {
282 opListenerRegistration.close();
283 } catch (final Exception e) {
284 LOG.error("Error when cleaning up VPN Instance Operational entries DataChangeListener.", e);
286 opListenerRegistration = null;
289 LOG.trace("VPN Manager Closed");
292 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
293 InstanceIdentifier<T> path) {
295 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
297 Optional<T> result = Optional.absent();
299 result = tx.read(datastoreType, path).get();
300 } catch (Exception e) {
301 throw new RuntimeException(e);
307 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
308 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
309 WriteTransaction tx = broker.newWriteOnlyTransaction();
310 tx.put(datastoreType, path, data, true);
311 Futures.addCallback(tx.submit(), callback);
314 private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
315 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
316 WriteTransaction tx = broker.newWriteOnlyTransaction();
317 tx.put(datastoreType, path, data, true);
318 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
321 } catch (InterruptedException | ExecutionException e) {
322 LOG.error("Error writing VPN instance to ID info to datastore (path, data) : ({}, {})", path, data);
323 throw new RuntimeException(e.getMessage());
327 protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
328 InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
329 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id);
330 if(vpnInstanceOpData.isPresent()) {
331 return vpnInstanceOpData.get();
336 private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
337 WriteTransaction tx = broker.newWriteOnlyTransaction();
338 tx.delete(datastoreType, path);
339 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
342 private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry> {
344 public FibEntriesListener() {
345 super(VrfEntry.class);
349 protected void remove(InstanceIdentifier<VrfEntry> identifier,
351 LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
352 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
353 String rd = key.getRouteDistinguisher();
354 Long label = del.getLabel();
355 VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
356 if(vpnInstanceOpData != null) {
357 List<Long> routeIds = vpnInstanceOpData.getRouteEntryId();
358 if(routeIds == null) {
359 LOG.debug("Fib Route entry is empty.");
362 LOG.debug("Removing label from vpn info - {}", label);
363 routeIds.remove(label);
364 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
365 new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
367 LOG.warn("No VPN Instance found for RD: {}", rd);
372 protected void update(InstanceIdentifier<VrfEntry> identifier,
373 VrfEntry original, VrfEntry update) {
374 // TODO Auto-generated method stub
379 protected void add(InstanceIdentifier<VrfEntry> identifier,
381 LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
382 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
383 String rd = key.getRouteDistinguisher();
384 Long label = add.getLabel();
385 VpnInstanceOpDataEntry vpn = getVpnInstanceOpData(rd);
387 List<Long> routeIds = vpn.getRouteEntryId();
388 if(routeIds == null) {
389 routeIds = new ArrayList<>();
391 LOG.debug("Adding label to vpn info - {}", label);
393 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
394 new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
396 LOG.warn("No VPN Instance found for RD: {}", rd);
401 class VpnInstanceOpListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<VpnInstanceOpDataEntry> {
403 public VpnInstanceOpListener() {
404 super(VpnInstanceOpDataEntry.class);
408 protected void remove(InstanceIdentifier<VpnInstanceOpDataEntry> identifier, VpnInstanceOpDataEntry del) {
413 protected void update(InstanceIdentifier<VpnInstanceOpDataEntry> identifier, VpnInstanceOpDataEntry original, VpnInstanceOpDataEntry update) {
414 final VpnInstanceOpDataEntryKey key = identifier.firstKeyOf(VpnInstanceOpDataEntry.class, VpnInstanceOpDataEntryKey.class);
415 String vpnName = key.getVrfId();
417 LOG.trace("VpnInstanceOpListener update: vpn name {} interface count in Old VpnOp Instance {} in New VpnOp Instance {}" ,
418 vpnName, original.getVpnInterfaceCount(), update.getVpnInterfaceCount() );
420 //if((original.getVpnToDpnList().size() != update.getVpnToDpnList().size()) && (update.getVpnToDpnList().size() == 0)) {
421 if((original.getVpnInterfaceCount() != update.getVpnInterfaceCount()) && (update.getVpnInterfaceCount() == 0)) {
422 notifyTaskIfRequired(vpnName);
426 private void notifyTaskIfRequired(String vpnName) {
427 Runnable notifyTask = vpnOpMap.remove(vpnName);
428 if (notifyTask == null) {
431 executorService.execute(notifyTask);
435 protected void add(InstanceIdentifier<VpnInstanceOpDataEntry> identifier, VpnInstanceOpDataEntry add) {