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.vpn.instances.VpnInstance;
30 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1Builder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 import com.google.common.base.Optional;
46 import com.google.common.util.concurrent.FutureCallback;
47 import com.google.common.util.concurrent.Futures;
49 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
50 private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
51 private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
52 private final DataBroker broker;
53 private final IBgpManager bgpManager;
54 private IdManagerService idManager;
55 private final FibEntriesListener fibListener;
57 private static final FutureCallback<Void> DEFAULT_CALLBACK =
58 new FutureCallback<Void>() {
59 public void onSuccess(Void result) {
60 LOG.debug("Success in Datastore operation");
63 public void onFailure(Throwable error) {
64 LOG.error("Error in Datastore operation", error);
69 * Listens for data change related to VPN Instance
70 * Informs the BGP about VRF information
72 * @param db - dataBroker reference
74 public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
75 super(VpnInstance.class);
77 this.bgpManager = bgpManager;
78 this.fibListener = new FibEntriesListener();
82 private void registerListener(final DataBroker db) {
84 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
85 getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
86 fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
87 getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
88 } catch (final Exception e) {
89 LOG.error("VPN Service DataChange listener registration fail!", e);
90 throw new IllegalStateException("VPN Service registration Listener failed.", e);
94 public void setIdManager(IdManagerService idManager) {
95 this.idManager = idManager;
99 protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
100 LOG.info("Remove event - Key: {}, value: {}", identifier, del);
101 String vpnName = del.getVpnInstanceName();
102 InstanceIdentifier<VpnInstance> vpnIdentifier = VpnUtil.getVpnInstanceIdentifier(vpnName);
103 delete(LogicalDatastoreType.OPERATIONAL, vpnIdentifier);
105 String rd = del.getIpv4Family().getRouteDistinguisher();
107 bgpManager.deleteVrf(rd);
108 } catch(Exception e) {
109 LOG.error("Exception when removing VRF from BGP", e);
114 protected void update(InstanceIdentifier<VpnInstance> identifier,
115 VpnInstance original, VpnInstance update) {
116 LOG.info("Update event - Key: {}, value: {}", identifier, update);
120 protected void add(InstanceIdentifier<VpnInstance> identifier,
122 LOG.info("key: {}, value: {}" +identifier, value);
124 long vpnId = getUniqueId(value.getVpnInstanceName());
125 InstanceIdentifier<VpnInstance1> augId = identifier.augmentation(VpnInstance1.class);
126 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.CONFIGURATION, augId);
127 if(vpnAugmenation.isPresent()) {
128 VpnInstance1 vpn = vpnAugmenation.get();
129 vpnId = vpn.getVpnId();
130 LOG.info("VPN ID is {}", vpnId);
133 VpnInstance opValue = new VpnInstanceBuilder(value).
134 addAugmentation(VpnInstance1.class, new VpnInstance1Builder().setVpnId(vpnId).build()).build();
136 asyncWrite(LogicalDatastoreType.OPERATIONAL, identifier, opValue, DEFAULT_CALLBACK);
138 //public void addVrf(String rd, Collection<String> importRts, Collection<String> exportRts)
139 VpnAfConfig config = value.getIpv4Family();
140 String rd = config.getRouteDistinguisher();
141 List<String> importRts = Arrays.asList(config.getImportRoutePolicy().split(","));
142 List<String> exportRts = Arrays.asList(config.getExportRoutePolicy().split(","));
144 bgpManager.addVrf(rd, importRts, exportRts);
145 } catch(Exception e) {
146 LOG.error("Exception when adding VRF to BGP", e);
150 private InstanceIdentifier<?> getWildCardPath() {
151 return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
154 private InstanceIdentifier<?> getFibEntryListenerPath() {
155 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
156 .child(VrfEntry.class);
160 public void close() throws Exception {
161 if (listenerRegistration != null) {
163 listenerRegistration.close();
164 } catch (final Exception e) {
165 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
167 listenerRegistration = null;
169 if (fibListenerRegistration != null) {
171 fibListenerRegistration.close();
172 } catch (final Exception e) {
173 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
175 fibListenerRegistration = null;
177 LOG.trace("VPN Manager Closed");
180 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
181 InstanceIdentifier<T> path) {
183 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
185 Optional<T> result = Optional.absent();
187 result = tx.read(datastoreType, path).get();
188 } catch (Exception e) {
189 throw new RuntimeException(e);
195 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
196 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
197 WriteTransaction tx = broker.newWriteOnlyTransaction();
198 tx.put(datastoreType, path, data, true);
199 Futures.addCallback(tx.submit(), callback);
202 private VpnInstance getVpnForRD(String rd) {
203 InstanceIdentifier<VpnInstances> id = InstanceIdentifier.create(VpnInstances.class);
204 Optional<VpnInstances> vpnInstances = read(LogicalDatastoreType.OPERATIONAL, id);
205 if(vpnInstances.isPresent()) {
206 List<VpnInstance> vpns = vpnInstances.get().getVpnInstance();
207 for(VpnInstance vpn : vpns) {
208 if(vpn.getIpv4Family().getRouteDistinguisher().equals(rd)) {
216 private Integer getUniqueId(String idKey) {
217 GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder()
218 .setPoolName(VpnConstants.VPN_IDPOOL_NAME)
219 .setIdKey(idKey).build();
222 Future<RpcResult<GetUniqueIdOutput>> result = idManager.getUniqueId(getIdInput);
223 RpcResult<GetUniqueIdOutput> rpcResult = result.get();
224 if(rpcResult.isSuccessful()) {
225 return rpcResult.getResult().getIdValue().intValue();
227 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
229 } catch (NullPointerException | InterruptedException | ExecutionException e) {
230 LOG.warn("Exception when getting Unique Id",e);
235 private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
236 WriteTransaction tx = broker.newWriteOnlyTransaction();
237 tx.delete(datastoreType, path);
238 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
241 private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry> {
243 public FibEntriesListener() {
244 super(VrfEntry.class);
248 protected void remove(InstanceIdentifier<VrfEntry> identifier,
250 LOG.info("Remove Fib event - Key : {}, value : {} ",identifier, del);
251 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
252 String rd = key.getRouteDistinguisher();
253 Long label = del.getLabel();
254 VpnInstance vpn = getVpnForRD(rd);
256 InstanceIdentifier<VpnInstance> id = VpnUtil.getVpnInstanceIdentifier(vpn.getVpnInstanceName());
257 InstanceIdentifier<VpnInstance1> augId = id.augmentation(VpnInstance1.class);
258 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.OPERATIONAL, augId);
259 if(vpnAugmenation.isPresent()) {
260 VpnInstance1 vpnAug = vpnAugmenation.get();
261 List<Long> routeIds = vpnAug.getRouteEntryId();
262 if(routeIds == null) {
263 LOG.debug("Fib Route entry is empty.");
266 LOG.info("Removing label from vpn info - {}", label);
267 routeIds.remove(label);
268 asyncWrite(LogicalDatastoreType.OPERATIONAL, augId,
269 new VpnInstance1Builder(vpnAug).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
271 LOG.info("VPN Augmentation not found");
274 LOG.warn("No VPN Instance found for RD: {}", rd);
279 protected void update(InstanceIdentifier<VrfEntry> identifier,
280 VrfEntry original, VrfEntry update) {
281 // TODO Auto-generated method stub
286 protected void add(InstanceIdentifier<VrfEntry> identifier,
288 LOG.info("Add Vrf Entry event - Key : {}, value : {}",identifier, add);
289 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
290 String rd = key.getRouteDistinguisher();
291 Long label = add.getLabel();
292 VpnInstance vpn = getVpnForRD(rd);
294 InstanceIdentifier<VpnInstance> id = VpnUtil.getVpnInstanceIdentifier(vpn.getVpnInstanceName());
295 InstanceIdentifier<VpnInstance1> augId = id.augmentation(VpnInstance1.class);
296 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.OPERATIONAL, augId);
297 if(vpnAugmenation.isPresent()) {
298 VpnInstance1 vpnAug = vpnAugmenation.get();
299 List<Long> routeIds = vpnAug.getRouteEntryId();
300 if(routeIds == null) {
301 routeIds = new ArrayList<>();
303 LOG.info("Adding label to vpn info - {}", label);
305 asyncWrite(LogicalDatastoreType.OPERATIONAL, augId,
306 new VpnInstance1Builder(vpnAug).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
308 LOG.info("VPN Augmentation not found");
311 LOG.warn("No VPN Instance found for RD: {}", rd);