206175d680c64317a10476d2afcbd3cb8725fc6c
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / evpn / manager / NeutronEvpnManager.java
1 /*
2  * Copyright © 2017 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.netvirt.neutronvpn.evpn.manager;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import com.google.common.util.concurrent.SettableFuture;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.function.Consumer;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.netvirt.neutronvpn.NeutronvpnManager;
21 import org.opendaylight.netvirt.neutronvpn.NeutronvpnUtils;
22 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
23 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.createevpn.input.Evpn;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getevpn.output.EvpnInstances;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getevpn.output.EvpnInstancesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.common.RpcError;
43 import org.opendaylight.yangtools.yang.common.RpcResult;
44 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.slf4j.helpers.FormattingTuple;
48 import org.slf4j.helpers.MessageFormatter;
49
50
51 public class NeutronEvpnManager {
52     private static final Logger LOG = LoggerFactory.getLogger(NeutronEvpnManager.class);
53     private final DataBroker dataBroker;
54     private final NeutronvpnManager neutronvpnManager;
55     private final NeutronvpnUtils neutronvpnUtils;
56
57     public NeutronEvpnManager(DataBroker dataBroker, NeutronvpnManager neutronvpnManager,
58             NeutronvpnUtils neutronvpnUtils) {
59         this.dataBroker = dataBroker;
60         this.neutronvpnManager = neutronvpnManager;
61         this.neutronvpnUtils = neutronvpnUtils;
62     }
63
64     @SuppressWarnings("checkstyle:IllegalCatch")
65     public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
66         CreateEVPNOutputBuilder opBuilder = new CreateEVPNOutputBuilder();
67         SettableFuture<RpcResult<CreateEVPNOutput>> result = SettableFuture.create();
68         List<RpcError> errorList = new ArrayList<>();
69         int failurecount = 0;
70         List<String> existingRDs = neutronvpnUtils.getExistingRDs();
71
72         for (Evpn vpn : input.nonnullEvpn()) {
73             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
74                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
75                         formatAndLog(LOG::warn, "Creation of EVPN failed for VPN {} due to absence of RD/iRT/eRT input",
76                                 vpn.getId().getValue())));
77                 continue;
78             }
79             VpnInstance.Type vpnInstanceType = VpnInstance.Type.L2;
80             if (vpn.getRouteDistinguisher().size() > 1) {
81                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
82                         formatAndLog(LOG::warn, "Creation of EVPN failed for VPN {} due to multiple RD input {}",
83                                 vpn.getId().getValue(), vpn.getRouteDistinguisher())));
84                 continue;
85             }
86             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
87                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
88                         formatAndLog(LOG::warn,
89                                 "Creation of EVPN failed for VPN {} as another VPN with the same RD {} is already "
90                                         + "configured",
91                                 vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0))));
92                 continue;
93             }
94             try {
95                 List<String> rdList = vpn.getRouteDistinguisher() != null
96                         ? new ArrayList<>(vpn.getRouteDistinguisher()) : new ArrayList<>();
97                 List<String> importRdList = vpn.getImportRT() != null
98                         ? new ArrayList<>(vpn.getImportRT()) : new ArrayList<>();
99                 List<String> exportRdList = vpn.getExportRT() != null
100                         ? new ArrayList<>(vpn.getExportRT()) : new ArrayList<>();
101                 neutronvpnManager.createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), rdList,
102                         importRdList, exportRdList, null /*router-id*/, null /*network-id*/,
103                         vpnInstanceType, 0 /*l2vni*/);
104             } catch (Exception ex) {
105                 errorList.add(RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION,
106                         formatAndLog(LOG::error, "Creation of EVPN failed for VPN {}", vpn.getId().getValue(), ex),
107                         ex.getMessage()));
108                 failurecount++;
109             }
110         }
111         if (failurecount != 0) {
112             result.set(RpcResultBuilder.<CreateEVPNOutput>failed().withRpcErrors(errorList).build());
113         } else {
114             List<String> errorResponseList = new ArrayList<>();
115             if (!errorList.isEmpty()) {
116                 for (RpcError rpcError : errorList) {
117                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
118                             + ", ErrorMessage: " + rpcError.getMessage());
119                 }
120             } else {
121                 errorResponseList.add("EVPN creation successful with no errors");
122             }
123             opBuilder.setResponse(errorResponseList);
124             result.set(RpcResultBuilder.success(opBuilder.build()).build());
125         }
126         return result;
127     }
128
129     public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
130         GetEVPNOutputBuilder opBuilder = new GetEVPNOutputBuilder();
131         SettableFuture<RpcResult<GetEVPNOutput>> result = SettableFuture.create();
132         Uuid inputVpnId = input.getId();
133         List<VpnInstance> vpns = new ArrayList<>();
134         if (inputVpnId == null) {
135             vpns = VpnHelper.getAllVpnInstances(dataBroker);
136             if (!vpns.isEmpty()) {
137                 for (VpnInstance vpn : vpns) {
138                     if (vpn.getIpv4Family().getRouteDistinguisher() != null
139                             && vpn.getType() == VpnInstance.Type.L2) {
140                         vpns.add(vpn);
141                     }
142                 }
143             } else {
144                 // No VPN present
145                 result.set(RpcResultBuilder.success(opBuilder.build()).build());
146                 return result;
147             }
148         } else {
149             String name = inputVpnId.getValue();
150             VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, name);
151             if (vpnInstance != null && vpnInstance.getIpv4Family().getRouteDistinguisher() != null
152                     && vpnInstance.getType() == VpnInstance.Type.L2) {
153                 vpns.add(vpnInstance);
154             } else {
155                 result.set(RpcResultBuilder.<GetEVPNOutput>failed().withWarning(RpcError.ErrorType.PROTOCOL,
156                         "invalid-value",
157                         formatAndLog(LOG::error, "GetEVPN failed because VPN {} is not present", name)).build());
158             }
159         }
160         List<EvpnInstances> evpnList = new ArrayList<>();
161         for (VpnInstance vpnInstance : vpns) {
162             Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
163             InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
164                     .class, new VpnMapKey(vpnId)).build();
165             EvpnInstancesBuilder evpn = new EvpnInstancesBuilder();
166             List<String> rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
167             List<String> ertList = new ArrayList<>();
168             List<String> irtList = new ArrayList<>();
169             for (VpnTarget vpnTarget : vpnInstance.getIpv4Family().getVpnTargets().nonnullVpnTarget()) {
170                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
171                     ertList.add(vpnTarget.getVrfRTValue());
172                 }
173                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
174                     irtList.add(vpnTarget.getVrfRTValue());
175                 }
176                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
177                     ertList.add(vpnTarget.getVrfRTValue());
178                     irtList.add(vpnTarget.getVrfRTValue());
179                 }
180             }
181             evpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
182             try {
183                 Optional<VpnMap> optionalVpnMap =
184                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
185                                 vpnMapIdentifier);
186                 if (optionalVpnMap.isPresent()) {
187                     VpnMap vpnMap = optionalVpnMap.get();
188                     evpn.setTenantId(vpnMap.getTenantId()).setName(vpnMap.getName());
189                 }
190             } catch (ReadFailedException e) {
191                 LOG.error("Error reading the VPN map for {}", vpnMapIdentifier, e);
192                 result.set(RpcResultBuilder.<GetEVPNOutput>failed().withError(RpcError.ErrorType.APPLICATION,
193                         "Error reading the VPN map for " + vpnMapIdentifier, e).build());
194                 return result;
195             }
196             evpnList.add(evpn.build());
197         }
198
199         opBuilder.setEvpnInstances(evpnList);
200         result.set(RpcResultBuilder.success(opBuilder.build()).build());
201         return result;
202     }
203
204     public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
205         List<RpcError> errorList = new ArrayList<>();
206
207         if (input.getId() != null) {
208             for (Uuid vpn : input.getId()) {
209                 VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpn.getValue());
210                 if (vpnInstance != null) {
211                     neutronvpnManager.removeVpn(vpn);
212                 } else {
213                     errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-value",
214                         formatAndLog(LOG::warn, "EVPN with vpnid: {} does not exist", vpn.getValue())));
215                 }
216             }
217         }
218         List<String> errorResponseList = new ArrayList<>();
219         if (!errorList.isEmpty()) {
220             for (RpcError rpcError : errorList) {
221                 errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
222                         + ", ErrorMessage: " + rpcError.getMessage());
223             }
224         } else {
225             errorResponseList.add("Deletion of EVPN operation successful");
226         }
227         DeleteEVPNOutputBuilder opBuilder = new DeleteEVPNOutputBuilder();
228         opBuilder.setResponse(errorResponseList);
229         SettableFuture<RpcResult<DeleteEVPNOutput>> result = SettableFuture.create();
230         result.set(RpcResultBuilder.success(opBuilder.build()).build());
231         return result;
232     }
233
234     private String formatAndLog(Consumer<String> logger, String template, Object arg) {
235         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
236     }
237
238     private String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
239         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
240     }
241
242     private String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
243         String message = tuple.getMessage();
244         logger.accept(message);
245         return message;
246     }
247 }