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;
14 import org.opendaylight.bgpmanager.api.IBgpManager;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
19 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceToVpnIdBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnRouteList;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
26 import org.opendaylight.yangtools.concepts.ListenerRegistration;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
32 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpDataBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 import com.google.common.base.Optional;
49 import com.google.common.util.concurrent.FutureCallback;
50 import com.google.common.util.concurrent.Futures;
52 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
53 private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
54 private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
55 private final DataBroker broker;
56 private final IBgpManager bgpManager;
57 private IdManagerService idManager;
58 private VpnInterfaceManager vpnInterfaceManager;
59 private final FibEntriesListener fibListener;
61 private static final FutureCallback<Void> DEFAULT_CALLBACK =
62 new FutureCallback<Void>() {
63 public void onSuccess(Void result) {
64 LOG.debug("Success in Datastore operation");
67 public void onFailure(Throwable error) {
68 LOG.error("Error in Datastore operation", error);
73 * Listens for data change related to VPN Instance
74 * Informs the BGP about VRF information
76 * @param db - dataBroker reference
78 public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
79 super(VpnInstance.class);
81 this.bgpManager = bgpManager;
82 this.fibListener = new FibEntriesListener();
86 private void registerListener(final DataBroker db) {
88 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
89 getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
90 fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
91 getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
92 } catch (final Exception e) {
93 LOG.error("VPN Service DataChange listener registration fail !", e);
94 throw new IllegalStateException("VPN Service registration Listener failed.", e);
98 public void setIdManager(IdManagerService idManager) {
99 this.idManager = idManager;
102 public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
103 this.vpnInterfaceManager = vpnInterfaceManager;
107 protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
108 LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
109 String vpnName = del.getVpnInstanceName();
111 //Clean up vpn Interface
112 InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
113 Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
115 if(optionalVpnInterfaces.isPresent()) {
116 List<VpnInterface> vpnInterfaces = optionalVpnInterfaces.get().getVpnInterface();
117 for(VpnInterface vpnInterface : vpnInterfaces) {
118 if(vpnInterface.getVpnInstanceName().equals(vpnName)) {
119 LOG.debug("VpnInterface {} will be removed from VPN {}", vpnInterface.getName(), vpnName);
120 vpnInterfaceManager.remove(
121 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
125 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
126 vpnIdentifier = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
127 delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
129 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
130 String rd = del.getIpv4Family().getRouteDistinguisher();
134 delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd));
136 bgpManager.deleteVrf(rd);
137 } catch(Exception e) {
138 LOG.error("Exception when removing VRF from BGP", e);
141 delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
146 protected void update(InstanceIdentifier<VpnInstance> identifier,
147 VpnInstance original, VpnInstance update) {
148 LOG.trace("Update event - Key: {}, value: {}", identifier, update);
152 protected void add(InstanceIdentifier<VpnInstance> identifier,
154 LOG.trace("key: {}, value: {}", identifier, value);
155 VpnAfConfig config = value.getIpv4Family();
156 String rd = config.getRouteDistinguisher();
158 long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, value.getVpnInstanceName());
160 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
161 vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(value.getVpnInstanceName(), vpnId,
162 (rd != null) ? rd : value.getVpnInstanceName());
164 asyncWrite(LogicalDatastoreType.CONFIGURATION,
165 VpnUtil.getVpnInstanceToVpnIdIdentifier(value.getVpnInstanceName()),
166 vpnInstanceToVpnId, DEFAULT_CALLBACK);
170 asyncWrite(LogicalDatastoreType.OPERATIONAL,
171 VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()),
172 VpnUtil.getVpnInstanceOpData(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK);
175 asyncWrite(LogicalDatastoreType.OPERATIONAL,
176 VpnUtil.getVpnInstanceOpDataIdentifier(rd),
177 VpnUtil.getVpnInstanceOpData(rd, vpnId), DEFAULT_CALLBACK);
179 List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
181 List<String> ertList = new ArrayList<String>();
182 List<String> irtList = new ArrayList<String>();
184 for (VpnTarget vpnTarget : vpnTargetList) {
185 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
186 ertList.add(vpnTarget.getVrfRTValue());
188 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
189 irtList.add(vpnTarget.getVrfRTValue());
191 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
192 ertList.add(vpnTarget.getVrfRTValue());
193 irtList.add(vpnTarget.getVrfRTValue());
198 bgpManager.addVrf(rd, irtList, ertList);
199 } catch(Exception e) {
200 LOG.error("Exception when adding VRF to BGP", e);
205 private InstanceIdentifier<?> getWildCardPath() {
206 return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
209 private InstanceIdentifier<?> getFibEntryListenerPath() {
210 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
211 .child(VrfEntry.class);
215 public void close() throws Exception {
216 if (listenerRegistration != null) {
218 listenerRegistration.close();
219 } catch (final Exception e) {
220 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
222 listenerRegistration = null;
224 if (fibListenerRegistration != null) {
226 fibListenerRegistration.close();
227 } catch (final Exception e) {
228 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
230 fibListenerRegistration = null;
232 LOG.trace("VPN Manager Closed");
235 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
236 InstanceIdentifier<T> path) {
238 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
240 Optional<T> result = Optional.absent();
242 result = tx.read(datastoreType, path).get();
243 } catch (Exception e) {
244 throw new RuntimeException(e);
250 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
251 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
252 WriteTransaction tx = broker.newWriteOnlyTransaction();
253 tx.put(datastoreType, path, data, true);
254 Futures.addCallback(tx.submit(), callback);
257 protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
258 InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
259 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id);
260 if(vpnInstanceOpData.isPresent()) {
261 return vpnInstanceOpData.get();
266 private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
267 WriteTransaction tx = broker.newWriteOnlyTransaction();
268 tx.delete(datastoreType, path);
269 Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
272 private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry> {
274 public FibEntriesListener() {
275 super(VrfEntry.class);
279 protected void remove(InstanceIdentifier<VrfEntry> identifier,
281 LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
282 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
283 String rd = key.getRouteDistinguisher();
284 Long label = del.getLabel();
285 VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(rd);
286 if(vpnInstanceOpData != null) {
287 List<Long> routeIds = vpnInstanceOpData.getRouteEntryId();
288 if(routeIds == null) {
289 LOG.debug("Fib Route entry is empty.");
292 LOG.debug("Removing label from vpn info - {}", label);
293 routeIds.remove(label);
294 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
295 new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
297 LOG.warn("No VPN Instance found for RD: {}", rd);
302 protected void update(InstanceIdentifier<VrfEntry> identifier,
303 VrfEntry original, VrfEntry update) {
304 // TODO Auto-generated method stub
309 protected void add(InstanceIdentifier<VrfEntry> identifier,
311 LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
312 final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
313 String rd = key.getRouteDistinguisher();
314 Long label = add.getLabel();
315 VpnInstanceOpDataEntry vpn = getVpnInstanceOpData(rd);
317 List<Long> routeIds = vpn.getRouteEntryId();
318 if(routeIds == null) {
319 routeIds = new ArrayList<>();
321 LOG.debug("Adding label to vpn info - {}", label);
323 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
324 new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
326 LOG.warn("No VPN Instance found for RD: {}", rd);