Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / vpnintent / impl / src / main / java / org / opendaylight / vpnservice / impl / VpnintentProvider.java
1 /*
2  * Copyright (c) 2016 Inocybe Technologies 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.impl;
9
10 import java.util.concurrent.Future;
11
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
16 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
17 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
18 import org.opendaylight.nic.mapping.api.IntentMappingService;
19 import org.opendaylight.nic.utils.MdsalUtils;
20 import org.opendaylight.vpnservice.utils.IidFactory;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.AddVpnEndpointInput;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.FailoverType;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabelsBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.RemoveVpnEndpointInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.RemoveVpnInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.VpnintentService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.Vpns;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.VpnsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.Endpoint;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.EndpointBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.EndpointKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpns.VpnIntents;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpns.VpnIntentsKey;
36 import org.opendaylight.yangtools.yang.binding.DataObject;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.RpcResult;
39 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
40 import org.osgi.framework.BundleContext;
41 import org.osgi.framework.FrameworkUtil;
42 import org.osgi.framework.ServiceReference;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.common.base.Preconditions;
47 import com.google.common.util.concurrent.FutureCallback;
48 import com.google.common.util.concurrent.Futures;
49
50 public class VpnintentProvider implements VpnintentService, BindingAwareProvider, AutoCloseable {
51
52     private static final Logger LOG = LoggerFactory.getLogger(VpnintentProvider.class);
53     public static final InstanceIdentifier<MplsLabels> LABELS_IID = IidFactory.getMplsLabelsIid();
54     public static final InstanceIdentifier<Vpns> VPN_IID = IidFactory.getVpnsIid();
55     public static final InstanceIdentifier<VpnIntents> VPN_INTENT_IID = IidFactory.getVpnIntentIid();
56     public static final InstanceIdentifier<Endpoint> ENDPOINT_IID = IidFactory.getEndpointIid();
57
58     private DataBroker dataBroker;
59     private IntentMappingService intentMappingService;
60     private BindingAwareBroker.RpcRegistration<VpnintentService> rpcRegistration = null;
61     private MdsalUtils mdsal;
62
63     @Override
64     public void onSessionInitiated(ProviderContext session) {
65         LOG.info("VpnintentProvider Session Initiated");
66         dataBroker = session.getSALService(DataBroker.class);
67         rpcRegistration = session.addRpcImplementation(VpnintentService.class, this);
68         this.mdsal = new MdsalUtils(this.dataBroker);
69
70         // Load IntentMappingService Reference
71         loadIntentMappingServiceReference();
72
73         Vpns vpns = new VpnsBuilder().build();
74         MplsLabels labels = new MplsLabelsBuilder().build();
75
76         // Initialize MD-SAL data store for vpn-intents and mpls-labels
77         initDatastore(LogicalDatastoreType.CONFIGURATION, VPN_IID, vpns);
78         initDatastore(LogicalDatastoreType.OPERATIONAL, LABELS_IID, labels);
79     }
80
81     @Override
82     public void close() throws Exception {
83         LOG.info("VpnintentProvider Closed");
84     }
85
86     private <T extends DataObject> void initDatastore(LogicalDatastoreType store, InstanceIdentifier<T> iid, T object) {
87         // Put data to MD-SAL data store
88         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
89         transaction.put(store, iid, object);
90
91         // Perform the tx.submit asynchronously
92         Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
93             @Override
94             public void onSuccess(final Void result) {
95                 LOG.info("initDatastore for VPN-Intents: transaction succeeded");
96             }
97
98             @Override
99             public void onFailure(final Throwable throwable) {
100                 LOG.error("initDatastore for VPN-Intents: transaction failed");
101             }
102         });
103         LOG.info("initDatastore: data populated: {}, {}, {}", store, iid, object);
104     }
105
106     @Override
107     public Future<RpcResult<Void>> removeVpn(RemoveVpnInput input) {
108         InstanceIdentifier<VpnIntents> vpnIdentifier = InstanceIdentifier.builder(Vpns.class)
109                 .child(VpnIntents.class, new VpnIntentsKey(input.getVpnName())).build();
110         MappingServiceManager msManager = new MappingServiceManager(intentMappingService);
111         MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
112
113         VpnIntents vpn = getVpn(input.getVpnName());
114
115         if (vpn.getEndpoint() != null && vpn.getEndpoint().size() > 0) {
116             for (Endpoint endpoint : vpn.getEndpoint()) {
117                 // Release MPLS label
118                 mplsManager.deleteLabel(endpoint);
119
120                 // Remove all intents related to this endpoint
121                 IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
122                 intentManager.removeIntentsByEndpoint(endpoint.getSiteName());
123
124                 // Remove info from Mapping Service
125                 msManager.delete(endpoint.getSiteName());
126             }
127         }
128
129         mdsal.delete(LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
130         LOG.info("Deleted VPN {}", input.getVpnName());
131         return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
132     }
133
134     @Override
135     public Future<RpcResult<Void>> addVpnEndpoint(AddVpnEndpointInput input) {
136         Endpoint currentEndpoint = new EndpointBuilder().setIpPrefix(input.getIpPrefix())
137                 .setSiteName(input.getSiteName()).setSwitchPortId(input.getSwitchPortId())
138                 .setKey(new EndpointKey(input.getSiteName())).build();
139         VpnIntents vpn = getVpn(input.getVpnName());
140         String failOverType = null;
141         if (vpn.isPathProtection() && vpn.getFailoverType()!= null) {
142             if (vpn.getFailoverType().equals(FailoverType.FastReroute)) {
143                 failOverType = IntentServiceManager.FAST_REROUTE;
144             } else if(vpn.getFailoverType().equals(FailoverType.SlowReroute)) {
145                 failOverType = IntentServiceManager.SLOW_REROUTE;
146             }
147         }
148
149         MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
150
151         // Get unique MPLS label
152         Long mplsLabel = mplsManager.getUniqueLabel(currentEndpoint);
153
154         // Add info into Mapping Service
155         MappingServiceManager msManager = new MappingServiceManager(intentMappingService);
156         msManager.add(currentEndpoint.getSiteName(), extractIP(currentEndpoint.getIpPrefix()),
157                 currentEndpoint.getSwitchPortId(), mplsLabel, null);
158
159         if (vpn.getEndpoint() != null && vpn.getEndpoint().size() > 0) {
160             IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
161
162             for (Endpoint member : vpn.getEndpoint()) {
163                 // Create mesh of Intents
164                 intentManager.addIntent(member.getSiteName(), currentEndpoint.getSiteName(),
165                         IntentServiceManager.ACTION_ALLOW, failOverType);
166                 intentManager.addIntent(currentEndpoint.getSiteName(), member.getSiteName(),
167                         IntentServiceManager.ACTION_ALLOW, failOverType);
168             }
169         }
170         // Associate endpoint with VPN
171         addEndpointToVpn(vpn, currentEndpoint);
172
173         return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
174     }
175
176     /**
177      * @param IpPrefix
178      *            object
179      * @return String representation of IP prefix
180      */
181     private String extractIP(IpPrefix ipPrefix) {
182         String ip = null;
183         if (ipPrefix.getIpv4Prefix() != null) {
184             ip = ipPrefix.getIpv4Prefix().getValue();
185         } else if (ipPrefix.getIpv6Prefix() != null) {
186             ip = ipPrefix.getIpv6Prefix().getValue();
187         }
188         return ip;
189     }
190
191     /**
192      * @param vpnName
193      *            VPN name
194      * @return VPN instance
195      */
196     private VpnIntents getVpn(String vpnName) {
197         InstanceIdentifier<VpnIntents> identifier = InstanceIdentifier.builder(Vpns.class)
198                 .child(VpnIntents.class, new VpnIntentsKey(vpnName)).build();
199
200         VpnIntents vpnIntents = mdsal.read(LogicalDatastoreType.CONFIGURATION, identifier);
201         Preconditions.checkNotNull(vpnIntents);
202         return vpnIntents;
203     }
204
205     @Override
206     public Future<RpcResult<Void>> removeVpnEndpoint(RemoveVpnEndpointInput input) {
207         Endpoint endpoint = getEndpoint(input.getVpnName(), input.getSiteName());
208
209         // Release MPLS label
210         MplsLabelManagerService mplsManager = new MplsLabelManagerService(dataBroker);
211         mplsManager.deleteLabel(endpoint);
212
213         // Remove all intents related to this endpoint
214         IntentServiceManager intentManager = new IntentServiceManager(dataBroker);
215         intentManager.removeIntentsByEndpoint(input.getSiteName());
216
217         // Remove endpoint from VPN
218         removeEndpointFromVpn(input.getVpnName(), input.getSiteName());
219
220         return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
221     }
222
223     /**
224      * @param siteName
225      *            Site name of the VPN member
226      * @return VPN member (Endpoint)
227      */
228     private Endpoint getEndpoint(String vpnName, String siteName) {
229         InstanceIdentifier<Endpoint> endpointID = InstanceIdentifier.builder(Vpns.class)
230                 .child(VpnIntents.class, new VpnIntentsKey(vpnName)).child(Endpoint.class, new EndpointKey(siteName))
231                 .build();
232
233         return mdsal.read(LogicalDatastoreType.CONFIGURATION, endpointID);
234     }
235
236     /**
237      * @param vpnName
238      *            VPN name
239      * @param siteName
240      *            Site name
241      */
242     private void removeEndpointFromVpn(String vpnName, String siteName) {
243         InstanceIdentifier<Endpoint> identifier = InstanceIdentifier.builder(Vpns.class)
244                 .child(VpnIntents.class, new VpnIntentsKey(vpnName)).child(Endpoint.class, new EndpointKey(siteName))
245                 .build();
246
247         mdsal.delete(LogicalDatastoreType.CONFIGURATION, identifier);
248         LOG.info("Deleted VPN member : {} from VPN: {}", siteName, vpnName);
249     }
250
251     /**
252      * @param vpn
253      *            VPN
254      * @param vpnMember
255      *            VPN member (endpoint)
256      */
257     private void addEndpointToVpn(VpnIntents vpn, Endpoint vpnMember) {
258         InstanceIdentifier<Endpoint> identifier = InstanceIdentifier.builder(Vpns.class)
259                 .child(VpnIntents.class, vpn.getKey())
260                 .child(Endpoint.class, vpnMember.getKey()).build();
261
262         mdsal.put(LogicalDatastoreType.CONFIGURATION, identifier, vpnMember);
263         LOG.info("Added VPN member : {} to VPN: {}", vpnMember.getSiteName(), vpn.getVpnName());
264     }
265
266     /**
267      * Load IntentMappingService reference
268      */
269     private void loadIntentMappingServiceReference() {
270         ServiceReference<?> serviceReference = getBundleCtx().getServiceReference(IntentMappingService.class);
271         intentMappingService = (IntentMappingService) getBundleCtx().getService(serviceReference);
272     }
273
274     private BundleContext getBundleCtx() {
275         return FrameworkUtil.getBundle(this.getClass()).getBundleContext();
276     }
277 }