Merge "RpcRegistration and RpcResult for IdManager."
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnManager.java
1 /*
2  * Copyright (c) 2015 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.Collection;
13 import java.util.List;
14
15 import org.opendaylight.bgpmanager.api.IBgpManager;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
20 import org.opendaylight.yangtools.concepts.ListenerRegistration;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1Builder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.google.common.base.Optional;
39 import com.google.common.util.concurrent.FutureCallback;
40 import com.google.common.util.concurrent.Futures;
41
42 public class VpnManager extends AbstractDataChangeListener<VpnInstance> implements AutoCloseable {
43     private static final Logger LOG = LoggerFactory.getLogger(VpnManager.class);
44     private ListenerRegistration<DataChangeListener> listenerRegistration, fibListenerRegistration;
45     private final DataBroker broker;
46     private final IBgpManager bgpManager;
47     private final FibEntriesListener fibListener;
48
49     private static final FutureCallback<Void> DEFAULT_CALLBACK =
50             new FutureCallback<Void>() {
51                 public void onSuccess(Void result) {
52                     LOG.debug("Success in Datastore operation");
53                 }
54
55                 public void onFailure(Throwable error) {
56                     LOG.error("Error in Datastore operation", error);
57                 };
58             };
59
60     /**
61      * Listens for data change related to VPN Instance
62      * Informs the BGP about VRF information
63      * 
64      * @param db - dataBroker reference
65      */
66     public VpnManager(final DataBroker db, final IBgpManager bgpManager) {
67         super(VpnInstance.class);
68         broker = db;
69         this.bgpManager = bgpManager;
70         this.fibListener = new FibEntriesListener();
71         registerListener(db);
72     }
73
74     private void registerListener(final DataBroker db) {
75         try {
76             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
77                     getWildCardPath(), VpnManager.this, DataChangeScope.SUBTREE);
78             fibListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
79                     getFibEntryListenerPath(), fibListener, DataChangeScope.BASE);
80         } catch (final Exception e) {
81             LOG.error("VPN Service DataChange listener registration fail!", e);
82             throw new IllegalStateException("VPN Service registration Listener failed.", e);
83         }
84     }
85
86     @Override
87     protected void remove(InstanceIdentifier<VpnInstance> identifier,
88             VpnInstance del) {
89         // TODO Auto-generated method stub
90     }
91
92     @Override
93     protected void update(InstanceIdentifier<VpnInstance> identifier,
94             VpnInstance original, VpnInstance update) {
95         // TODO Auto-generated method stub
96     }
97
98     @Override
99     protected void add(InstanceIdentifier<VpnInstance> identifier,
100             VpnInstance value) {
101         LOG.info("key: {}, value: {}" +identifier, value);
102         //TODO: Generate VPN ID for this instance, where to store in model ... ?
103         long vpnId = 1000;
104         InstanceIdentifier<VpnInstance1> augId = identifier.augmentation(VpnInstance1.class);
105         Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.CONFIGURATION, augId);
106         if(vpnAugmenation.isPresent()) {
107             VpnInstance1 vpn = vpnAugmenation.get();
108             vpnId = vpn.getVpnId();
109             LOG.info("VPN ID is {}", vpnId);
110         }
111
112         VpnInstance opValue = new VpnInstanceBuilder(value).
113                  addAugmentation(VpnInstance1.class, new VpnInstance1Builder().setVpnId(vpnId).build()).build();
114
115         asyncWrite(LogicalDatastoreType.OPERATIONAL, identifier, opValue, DEFAULT_CALLBACK);
116
117         //TODO: Add VRF to BGP
118         //public void addVrf(String rd, Collection<String> importRts, Collection<String> exportRts)
119         VpnAfConfig config = value.getIpv4Family();
120         String rd = config.getRouteDistinguisher();
121         List<String> importRts = Arrays.asList(config.getImportRoutePolicy().split(","));
122         List<String> exportRts = Arrays.asList(config.getExportRoutePolicy().split(","));
123         try {
124             bgpManager.addVrf(rd, importRts, exportRts);
125         } catch(Exception e) {
126             LOG.error("Exception when adding VRF to BGP", e);
127         }
128     }
129
130     private InstanceIdentifier<?> getWildCardPath() {
131         return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
132     }
133
134     private InstanceIdentifier<?> getFibEntryListenerPath() {
135         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class)
136                 .child(VrfEntry.class);
137     }
138
139     @Override
140     public void close() throws Exception {
141         if (listenerRegistration != null) {
142             try {
143                 listenerRegistration.close();
144             } catch (final Exception e) {
145                 LOG.error("Error when cleaning up Vpn DataChangeListener.", e);
146             }
147             listenerRegistration = null;
148         }
149         if (fibListenerRegistration != null) {
150             try {
151                 fibListenerRegistration.close();
152             } catch (final Exception e) {
153                 LOG.error("Error when cleaning up Fib entries DataChangeListener.", e);
154             }
155             fibListenerRegistration = null;
156         }
157         LOG.trace("VPN Manager Closed");
158     }
159
160     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
161             InstanceIdentifier<T> path) {
162
163         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
164
165         Optional<T> result = Optional.absent();
166         try {
167             result = tx.read(datastoreType, path).get();
168         } catch (Exception e) {
169             throw new RuntimeException(e);
170         }
171
172         return result;
173     }
174
175     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
176             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
177         WriteTransaction tx = broker.newWriteOnlyTransaction();
178         tx.put(datastoreType, path, data, true);
179         Futures.addCallback(tx.submit(), callback);
180     }
181
182     private VpnInstance getVpnForRD(String rd) {
183         InstanceIdentifier<VpnInstances> id = InstanceIdentifier.create(VpnInstances.class);
184         Optional<VpnInstances> vpnInstances = read(LogicalDatastoreType.OPERATIONAL, id);
185         if(vpnInstances.isPresent()) {
186             List<VpnInstance> vpns = vpnInstances.get().getVpnInstance();
187             for(VpnInstance vpn : vpns) {
188                 if(vpn.getIpv4Family().getRouteDistinguisher().equals(rd)) {
189                     return vpn;
190                 }
191             }
192         }
193         return null;
194     }
195
196     private class FibEntriesListener extends AbstractDataChangeListener<VrfEntry>  {
197
198         public FibEntriesListener() {
199             super(VrfEntry.class);
200         }
201
202         @Override
203         protected void remove(InstanceIdentifier<VrfEntry> identifier,
204                 VrfEntry del) {
205             // TODO Auto-generated method stub
206
207         }
208
209         @Override
210         protected void update(InstanceIdentifier<VrfEntry> identifier,
211                 VrfEntry original, VrfEntry update) {
212             // TODO Auto-generated method stub
213
214         }
215
216         @Override
217         protected void add(InstanceIdentifier<VrfEntry> identifier,
218                 VrfEntry add) {
219             LOG.info("Key : " + identifier + " value : " + add);
220             final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
221             String rd = key.getRouteDistinguisher();
222             Long label = add.getLabel();
223             VpnInstance vpn = getVpnForRD(rd);
224             if(vpn != null) {
225                 InstanceIdentifier<VpnInstance> id = VpnUtil.getVpnInstanceIdentifier(vpn.getVpnInstanceName());
226                 InstanceIdentifier<VpnInstance1> augId = id.augmentation(VpnInstance1.class);
227                 Optional<VpnInstance1> vpnAugmenation = read(LogicalDatastoreType.OPERATIONAL, augId);
228                 if(vpnAugmenation.isPresent()) {
229                     VpnInstance1 vpnAug = vpnAugmenation.get();
230                     List<Long> routeIds = vpnAug.getRouteEntryId();
231                     if(routeIds == null) {
232                         routeIds = new ArrayList<>();
233                     }
234                     LOG.info("Adding label to vpn info " + label);
235                     routeIds.add(label);
236                     asyncWrite(LogicalDatastoreType.OPERATIONAL, augId,
237                             new VpnInstance1Builder(vpnAug).setRouteEntryId(routeIds).build(), DEFAULT_CALLBACK);
238                 } else {
239                     LOG.info("VPN Augmentation not found");
240                 }
241             } else {
242                 LOG.warn("No VPN Instance found for RD: {}", rd);
243             }
244         }
245     }
246 }