add bgpmanager service dependency
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnInterfaceManager.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.List;
11 import java.util.ArrayList;
12
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.FutureCallback;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.yangtools.concepts.ListenerRegistration;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacencyList;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
43     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
44     private ListenerRegistration<DataChangeListener> listenerRegistration;
45     private final DataBroker broker;
46
47     private static final FutureCallback<Void> DEFAULT_CALLBACK =
48             new FutureCallback<Void>() {
49                 public void onSuccess(Void result) {
50                     LOG.info("Success in Datastore operation");
51                 }
52
53                 public void onFailure(Throwable error) {
54                     LOG.error("Error in Datastore operation", error);
55                 };
56             };
57
58     /**
59      * Responsible for listening to data change related to VPN Interface
60      * Bind VPN Service on the interface and informs the BGP service
61      * 
62      * @param db - dataBroker service reference
63      */
64     public VpnInterfaceManager(final DataBroker db) {
65         super(VpnInterface.class);
66         broker = db;
67         registerListener(db);
68     }
69
70     @Override
71     public void close() throws Exception {
72         if (listenerRegistration != null) {
73             try {
74                 listenerRegistration.close();
75             } catch (final Exception e) {
76                 LOG.error("Error when cleaning up DataChangeListener.", e);
77             }
78             listenerRegistration = null;
79         }
80         LOG.info("VPN Interface Manager Closed");
81     }
82
83     private void registerListener(final DataBroker db) {
84         try {
85             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
86                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
87         } catch (final Exception e) {
88             LOG.error("VPN Service DataChange listener registration fail!", e);
89             throw new IllegalStateException("VPN Service registration Listener failed.", e);
90         }
91     }
92
93     @Override
94     protected void add(final InstanceIdentifier<VpnInterface> identifier,
95             final VpnInterface vpnInterface) {
96         LOG.info("key: " + identifier + ", value=" + vpnInterface );
97         addInterface(identifier, vpnInterface);
98     }
99
100     private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
101                               final VpnInterface vpnInterface) {
102         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
103         String interfaceName = key.getName();
104         InstanceIdentifierBuilder<Interface> idBuilder = 
105                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
106         InstanceIdentifier<Interface> id = idBuilder.build();
107         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
108         if (port.isPresent()) {
109             Interface interf = port.get();
110             bindServiceOnInterface(interf);
111             updateNextHops(identifier, vpnInterface);
112         }
113     }
114
115     private void updateNextHops(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
116         //Read NextHops
117         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
118         Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.CONFIGURATION, path);
119         String intfName = intf.getName();
120
121         if (adjacencies.isPresent()) {
122             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
123             List<Adjacency> value = new ArrayList<>();
124
125             if (!nextHops.isEmpty()) {
126                 LOG.info("NextHops are " + nextHops);
127                 for (Adjacency nextHop : nextHops) {
128                     //TODO: Generate label for the prefix and store it in the next hop model
129                     long label = 200;
130
131                     //TODO: Update BGP
132                     updatePrefixToBGP(nextHop);
133                     value.add(new AdjacencyBuilder(nextHop).setLabel(label).build());
134                 }
135             }
136             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
137             VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
138             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
139             asyncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK);
140         }
141     }
142
143     private void bindServiceOnInterface(Interface intf) {
144         //TODO: Create Ingress flow on the interface to bind the VPN service
145     }
146
147     private void updatePrefixToBGP(Adjacency nextHop) {
148         //TODO: Update the Prefix to BGP
149     }
150
151     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
152             InstanceIdentifier<T> path) {
153
154         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
155
156         Optional<T> result = Optional.absent();
157         try {
158             result = tx.read(datastoreType, path).get();
159         } catch (Exception e) {
160             throw new RuntimeException(e);
161         }
162
163         return result;
164     }
165
166     private InstanceIdentifier<VpnInterface> getWildCardPath() {
167         return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
168     }
169
170     @Override
171     protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
172         LOG.info("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
173         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
174         String interfaceName = key.getName();
175         InstanceIdentifierBuilder<Interface> idBuilder = 
176                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
177         InstanceIdentifier<Interface> id = idBuilder.build();
178         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
179         if (port.isPresent()) {
180             Interface interf = port.get();
181             unbindServiceOnInterface(interf);
182             removeNextHops(identifier, vpnInterface);
183         } else {
184             LOG.info("No nexthops were available to handle remove event {}", interfaceName);
185         }
186     }
187
188     private void removeNextHops(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
189         //Read NextHops
190         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
191         Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
192         String intfName = intf.getName();
193
194         if (adjacencies.isPresent()) {
195             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
196
197             if (!nextHops.isEmpty()) {
198                 LOG.trace("NextHops are " + nextHops);
199                 for (Adjacency nextHop : nextHops) {
200                     //TODO: Update BGP
201                     removePrefixFromBGP(nextHop);
202                 }
203             }
204
205             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
206             delete(LogicalDatastoreType.OPERATIONAL, interfaceId);
207         }
208     }
209
210     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
211         WriteTransaction tx = broker.newWriteOnlyTransaction();
212         tx.delete(datastoreType, path);
213         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
214     }
215
216     private void unbindServiceOnInterface(Interface intf) {
217         //TODO: Remove Ingress flow on the interface to unbind the VPN service
218     }
219
220     private void removePrefixFromBGP(Adjacency nextHop) {
221         //TODO: Update the Prefix to BGP
222     }
223
224     @Override
225     protected void update(InstanceIdentifier<VpnInterface> identifier, 
226                                    VpnInterface original, VpnInterface update) {
227         // TODO Auto-generated method stub
228
229     }
230
231     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
232                         InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
233         WriteTransaction tx = broker.newWriteOnlyTransaction();
234         tx.put(datastoreType, path, data, true);
235         Futures.addCallback(tx.submit(), callback);
236     }
237 }