5567d3e6206a47e3c47d2a65f283ff2ddc62ed3d
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnManager.java
1 /*
2  * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.vpnservice;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.List;
13
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;
47
48 import com.google.common.base.Optional;
49 import com.google.common.util.concurrent.FutureCallback;
50 import com.google.common.util.concurrent.Futures;
51
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;
60
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");
65                 }
66
67                 public void onFailure(Throwable error) {
68                     LOG.error("Error in Datastore operation", error);
69                 };
70             };
71
72     /**
73      * Listens for data change related to VPN Instance
74      * Informs the BGP about VRF information
75      *
76      * @param db - dataBroker reference
77      */
78     public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
79         super(VpnInstance.class);
80         broker = db;
81         this.bgpManager = bgpManager;
82         this.fibListener = new FibEntriesListener();
83         registerListener(db);
84     }
85
86     private void registerListener(final DataBroker db) {
87         try {
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);
95         }
96     }
97
98     public void setIdManager(IdManagerService idManager) {
99         this.idManager = idManager;
100     }
101
102     public void setVpnInterfaceManager(VpnInterfaceManager vpnInterfaceManager) {
103         this.vpnInterfaceManager = vpnInterfaceManager;
104     }
105
106     @Override
107     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
108         LOG.trace("Remove VPN event - Key: {}, value: {}", identifier, del);
109         String vpnName = del.getVpnInstanceName();
110
111         //Clean up vpn Interface
112         InstanceIdentifier<VpnInterfaces> vpnInterfacesId = InstanceIdentifier.builder(VpnInterfaces.class).build();
113         Optional<VpnInterfaces> optionalVpnInterfaces = read(LogicalDatastoreType.OPERATIONAL, vpnInterfacesId);
114
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);
122                 }
123             }
124         }
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);
128
129         VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
130         String rd = del.getIpv4Family().getRouteDistinguisher();
131
132         if (rd !=null) {
133
134             delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd));
135             try {
136                 bgpManager.deleteVrf(rd);
137             } catch(Exception e) {
138                 LOG.error("Exception when removing VRF from BGP", e);
139             }
140         } else {
141             delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
142         }
143     }
144
145     @Override
146     protected void update(InstanceIdentifier<VpnInstance> identifier,
147             VpnInstance original, VpnInstance update) {
148         LOG.trace("Update event - Key: {}, value: {}", identifier, update);
149     }
150
151     @Override
152     protected void add(InstanceIdentifier<VpnInstance> identifier,
153             VpnInstance value) {
154         LOG.trace("key: {}, value: {}", identifier, value);
155         VpnAfConfig config = value.getIpv4Family();
156         String rd = config.getRouteDistinguisher();
157
158         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, value.getVpnInstanceName());
159
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());
163
164         asyncWrite(LogicalDatastoreType.CONFIGURATION,
165                    VpnUtil.getVpnInstanceToVpnIdIdentifier(value.getVpnInstanceName()),
166                    vpnInstanceToVpnId, DEFAULT_CALLBACK);
167
168
169         if(rd == null) {
170             asyncWrite(LogicalDatastoreType.OPERATIONAL,
171                     VpnUtil.getVpnInstanceOpDataIdentifier(value.getVpnInstanceName()),
172                     VpnUtil.getVpnInstanceOpData(value.getVpnInstanceName(), vpnId), DEFAULT_CALLBACK);
173
174         } else {
175             asyncWrite(LogicalDatastoreType.OPERATIONAL,
176                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
177                        VpnUtil.getVpnInstanceOpData(rd, vpnId), DEFAULT_CALLBACK);
178
179             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
180
181             List<String> ertList = new ArrayList<String>();
182             List<String> irtList = new ArrayList<String>();
183
184             for (VpnTarget vpnTarget : vpnTargetList) {
185                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
186                     ertList.add(vpnTarget.getVrfRTValue());
187                 }
188                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
189                     irtList.add(vpnTarget.getVrfRTValue());
190                 }
191                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
192                     ertList.add(vpnTarget.getVrfRTValue());
193                     irtList.add(vpnTarget.getVrfRTValue());
194                 }
195             }
196
197             try {
198                 bgpManager.addVrf(rd, irtList, ertList);
199             } catch(Exception e) {
200                 LOG.error("Exception when adding VRF to BGP", e);
201             }
202         }
203     }
204
205     private InstanceIdentifier<?> getWildCardPath() {
206         return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
207     }
208
209     private InstanceIdentifier<?> getFibEntryListenerPath() {
210         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
211                 .child(VrfEntry.class);
212     }
213
214     @Override
215     public void close() throws Exception {
216         if (listenerRegistration != null) {
217             try {
218                 listenerRegistration.close();
219             } catch (final Exception e) {
220                 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
221             }
222             listenerRegistration = null;
223         }
224         if (fibListenerRegistration != null) {
225             try {
226                 fibListenerRegistration.close();
227             } catch (final Exception e) {
228                 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
229             }
230             fibListenerRegistration = null;
231         }
232         LOG.trace("VPN Manager Closed");
233     }
234
235     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
236             InstanceIdentifier<T> path) {
237
238         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
239
240         Optional<T> result = Optional.absent();
241         try {
242             result = tx.read(datastoreType, path).get();
243         } catch (Exception e) {
244             throw new RuntimeException(e);
245         }
246
247         return result;
248     }
249
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);
255     }
256
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();
262         }
263         return null;
264     }
265
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);
270     }
271
272     private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry>  {
273
274         public FibEntriesListener() {
275             super(VrfEntry.class);
276         }
277
278         @Override
279         protected void remove(InstanceIdentifier<VrfEntry> identifier,
280                 VrfEntry del) {
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.");
290                     return;
291                 }
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);
296             } else {
297                 LOG.warn("No VPN Instance found for RD: {}", rd);
298             }
299         }
300
301         @Override
302         protected void update(InstanceIdentifier<VrfEntry> identifier,
303                 VrfEntry original, VrfEntry update) {
304             // TODO Auto-generated method stub
305
306         }
307
308         @Override
309         protected void add(InstanceIdentifier<VrfEntry> identifier,
310                            VrfEntry add) {
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);
316             if(vpn != null) {
317                 List<Long> routeIds = vpn.getRouteEntryId();
318                 if(routeIds == null) {
319                     routeIds = new ArrayList<>();
320                 }
321                 LOG.debug("Adding label to vpn info - {}", label);
322                 routeIds.add(label);
323                 asyncWrite(LogicalDatastoreType.OPERATIONAL, VpnUtil.getVpnInstanceOpDataIdentifier(rd),
324                            new VpnInstanceOpDataEntryBuilder(vpn).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
325             } else {
326                 LOG.warn("No VPN Instance found for RD: {}", rd);
327             }
328         }
329     }
330 }