2 * Copyright (c) 2015 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.Collection;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.Future;
17 import org.opendaylight.bgpmanager.api.IBgpManager;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
22 import org.opendaylight.yangtools.concepts.ListenerRegistration;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
29 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
30 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
32 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1Builder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 import com.google.common.base.Optional;
48 import com.google.common.util.concurrent.FutureCallback;
49 import com.google.common.util.concurrent.Futures;
51 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
52 private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
53 private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
54 private final DataBroker broker;
55 private final IBgpManager bgpManager;
56 private IdManagerService idManager;
57 private VpnInterfaceManager vpnInterfaceManager;
58 private final FibEntriesListener fibListener;
60 private static final FutureCallback<Void> DEFAULT_CALLBACK =
61 new FutureCallback<Void>() {
62 public void onSuccess(Void result) {
63 LOG.debug("Success in Datastore operation");
66 public void onFailure(Throwable error) {
67 LOG.error("Error in Datastore operation", error);
72 * Listens for data change related to VPN Instance
73 * Informs the BGP about VRF information
75 * @param db - dataBroker reference
77 public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
78 super(VpnInstance.class);
80 this.bgpManager = bgpManager;
81 this.fibListener = new FibEntriesListener();
85 private void registerListener(final DataBroker db) {
87 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
88 getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
89 fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
90 getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
91 } catch (final Exception e) {
92 LOG.error("VPN Service DataChange listener registration fail !", e);
93 throw new IllegalStateException("VPN Service registration Listener failed.", e);
97 public void setIdManager(IdManagerService idManager) {
98 this.idManager = idManager;
101 public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
102 this.vpnInterfaceManager = vpnInterfaceManager;
106 protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
107 LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
108 String vpnName = del.getVpnInstanceName();
109 InstanceIdentifier<VpnInstance> vpnIdentifier = VpnUtil.getVpnInstanceIdentifier(vpnName);
110 //Clean up vpn Interface
111 InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
112 Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
114 if(optionalVpnInterfaces.isPresent()) {
115 List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
116 for(VpnInterface vpnInterface : vpnInterfaces) {
117 if(vpnInterface.getVpnInstanceName().equals(vpnName)) {
118 LOG.debug("VpnInterface {} will be removed from VPN {}", vpnInterface.getName(), vpnName);
119 vpnInterfaceManager.remove(
120 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
125 delete(LogicalDatastoreType.OPERATIONAL, vpnIdentifier);
127 String rd = del.getIpv4Family().getRouteDistinguisher();
129 bgpManager.deleteVrf(rd);
130 } catch(Exception e) {
131 LOG.error("Exception when removing VRF from BGP", e);
136 protected void update(InstanceIdentifier<VpnInstance> identifier,
137 VpnInstance original, VpnInstance update) {
138 LOG.trace("Update event - Key: {}, value: {}", identifier, update);
142 protected void add(InstanceIdentifier<VpnInstance> identifier,
144 LOG.trace("key: {}, value: {}", identifier, value);
146 long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, value.getVpnInstanceName());
148 VpnInstance opValue = new VpnInstanceBuilder(value).
149 addAugmentation(VpnInstance1.class, new VpnInstance1Builder().setVpnId(vpnId).build()).build();
151 asyncWrite(LogicalDatastoreType.OPERATIONAL, identifier, opValue, DEFAULT_CALLBACK);
153 //public void addVrf(String rd, Collection<String> importRts, Collection<String> exportRts)
154 VpnAfConfig config = value.getIpv4Family();
155 String rd = config.getRouteDistinguisher();
156 List<String> importRts = Arrays.asList(config.getImportRoutePolicy().split(","));
157 List<String> exportRts = Arrays.asList(config.getExportRoutePolicy().split(","));
159 bgpManager.addVrf(rd, importRts, exportRts);
160 } catch(Exception e) {
161 LOG.error("Exception when adding VRF to BGP", e);
165 private InstanceIdentifier<?> getWildCardPath() {
166 return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
169 private InstanceIdentifier<?> getFibEntryListenerPath() {
170 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
171 .child(VrfEntry.class);
175 public void close() throws Exception {
176 if (listenerRegistration != null) {
178 listenerRegistration.close();
179 } catch (final Exception e) {
180 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
182 listenerRegistration = null;
184 if (fibListenerRegistration != null) {
186 fibListenerRegistration.close();
187 } catch (final Exception e) {
188 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
190 fibListenerRegistration = null;
192 LOG.trace("VPN Manager Closed");
195 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
196 InstanceIdentifier<T> path) {
198 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
200 Optional<T> result = Optional.absent();
202 result = tx.read(datastoreType, path).get();
203 } catch (Exception e) {
204 throw new RuntimeException(e);
210 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
211 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
212 WriteTransaction tx = broker.newWriteOnlyTransaction();
213 tx.put(datastoreType, path, data, true);
214 Futures.addCallback(tx.submit(), callback);
217 private VpnInstance getVpnForRD(String rd) {
218 InstanceIdentifier<VpnInstances> id = InstanceIdentifier.create(VpnInstances.class);
219 Optional<VpnInstances> vpnInstances = read(LogicalDatastoreType.OPERATIONAL, id);
220 if(vpnInstances.isPresent()) {
221 List<VpnInstance> vpns = vpnInstances.get().getVpnInstance();
222 for(VpnInstance vpn : vpns) {
223 if(vpn.getIpv4Family().getRouteDistinguisher().equals(rd)) {
231 // private Integer getUniqueId(IdManagerService idManager, String poolName,String idKey) {
232 // AllocateIdInput getIdInput = new AllocateIdInputBuilder()
233 // .setPoolName(poolName)
234 // .setIdKey(idKey).build();
237 // Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
238 // RpcResult<AllocateIdOutput> rpcResult = result.get();
239 // if(rpcResult.isSuccessful()) {
240 // return rpcResult.getResult().getIdValue().intValue();
242 // LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
244 // } catch (InterruptedException | ExecutionException e) {
245 // LOG.warn("Exception when getting Unique Id",e);
250 private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
251 WriteTransaction tx = broker.newWriteOnlyTransaction();
252 tx.delete(datastoreType, path);
253 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
256 private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry> {
258 public FibEntriesListener() {
259 super(VrfEntry.class);
263 protected void remove(InstanceIdentifier<VrfEntry> identifier,
265 LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
266 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
267 String rd = key.getRouteDistinguisher();
268 Long label = del.getLabel();
269 VpnInstance vpn = getVpnForRD(rd);
271 InstanceIdentifier<VpnInstance> id = VpnUtil.getVpnInstanceIdentifier(vpn.getVpnInstanceName());
272 InstanceIdentifier<VpnInstance1> augId = id.augmentation(VpnInstance1.class);
273 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.OPERATIONAL, augId);
274 if(vpnAugmenation.isPresent()) {
275 VpnInstance1 vpnAug = vpnAugmenation.get();
276 List<Long> routeIds = vpnAug.getRouteEntryId();
277 if(routeIds == null) {
278 LOG.debug("Fib Route entry is empty.");
281 LOG.debug("Removing label from vpn info - {}", label);
282 routeIds.remove(label);
283 asyncWrite(LogicalDatastoreType.OPERATIONAL, augId,
284 new VpnInstance1Builder(vpnAug).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
286 LOG.warn("VPN Augmentation not found for vpn instance {}", vpn.getVpnInstanceName());
289 LOG.warn("No VPN Instance found for RD: {}", rd);
294 protected void update(InstanceIdentifier<VrfEntry> identifier,
295 VrfEntry original, VrfEntry update) {
296 // TODO Auto-generated method stub
301 protected void add(InstanceIdentifier<VrfEntry> identifier,
303 LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
304 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
305 String rd = key.getRouteDistinguisher();
306 Long label = add.getLabel();
307 VpnInstance vpn = getVpnForRD(rd);
309 InstanceIdentifier<VpnInstance> id = VpnUtil.getVpnInstanceIdentifier(vpn.getVpnInstanceName());
310 InstanceIdentifier<VpnInstance1> augId = id.augmentation(VpnInstance1.class);
311 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.OPERATIONAL, augId);
312 if(vpnAugmenation.isPresent()) {
313 VpnInstance1 vpnAug = vpnAugmenation.get();
314 List<Long> routeIds = vpnAug.getRouteEntryId();
315 if(routeIds == null) {
316 routeIds = new ArrayList<>();
318 LOG.debug("Adding label to vpn info - {}", label);
320 asyncWrite(LogicalDatastoreType.OPERATIONAL, augId,
321 new VpnInstance1Builder(vpnAug).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
323 LOG.warn("VPN Augmentation not found for vpn instance {}", vpn.getVpnInstanceName());
326 LOG.warn("No VPN Instance found for RD: {}", rd);