Bug 7720: create/delete VPN CLI handling addition/removal of subnets
[netvirt.git] / vpnservice / neutronvpn / neutronvpn-impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
1 /*
2  * Copyright © 2015, 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;
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.Arrays;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.EventListener;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.Future;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
29 import org.opendaylight.genius.mdsalutil.MDSALUtil;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.netvirt.elanmanager.api.IElanService;
32 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
33 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
34 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
35 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
36 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargetsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTargetBuilder;
39 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTargetKey;
40 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
41 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
42 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
43 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4FamilyBuilder;
44 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
45 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
46 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksInput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterInput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNInput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutputBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpnBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpnBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.createl3vpn.input.L3vpn;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstances;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstancesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesKey;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInput;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInputBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutput;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
116 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
117 import org.opendaylight.yangtools.yang.common.RpcError;
118 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
119 import org.opendaylight.yangtools.yang.common.RpcResult;
120 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
121 import org.slf4j.Logger;
122 import org.slf4j.LoggerFactory;
123
124 public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, EventListener {
125     private static final Logger LOG = LoggerFactory.getLogger(NeutronvpnManager.class);
126     private final DataBroker dataBroker;
127     private final NeutronvpnNatManager nvpnNatManager;
128     private final NotificationPublishService notificationPublishService;
129     private final VpnRpcService vpnRpcService;
130     private final NeutronFloatingToFixedIpMappingChangeListener floatingIpMapListener;
131     private final NeutronvpnConfig neutronvpnConfig;
132     private final IMdsalApiManager mdsalUtil;
133     private final IElanService elanService;
134
135     public NeutronvpnManager(
136             final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
137             final NotificationPublishService notiPublishService, final NeutronvpnNatManager vpnNatMgr,
138             final VpnRpcService vpnRpcSrv, final IElanService elanService,
139             final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
140             final NeutronvpnConfig neutronvpnConfig) {
141         this.dataBroker = dataBroker;
142         mdsalUtil = mdsalManager;
143         nvpnNatManager = vpnNatMgr;
144         notificationPublishService = notiPublishService;
145         vpnRpcService = vpnRpcSrv;
146         this.elanService = elanService;
147         floatingIpMapListener = neutronFloatingToFixedIpMappingChangeListener;
148         LOG.info("neutronvpnConfig: {}", neutronvpnConfig);
149         this.neutronvpnConfig = neutronvpnConfig;
150     }
151
152     @Override
153     public void close() throws Exception {
154         LOG.info("{} close", getClass().getSimpleName());
155     }
156
157     public NeutronvpnConfig getNeutronvpnConfig() {
158         return neutronvpnConfig;
159     }
160
161     // TODO Clean up the exception handling
162     @SuppressWarnings("checkstyle:IllegalCatch")
163     protected void updateSubnetNodeWithFixedIps(Uuid subnetId, Uuid routerId,
164                                                 Uuid routerInterfaceName, String fixedIp,
165                                                 String routerIntfMacAddress) {
166         Subnetmap subnetmap = null;
167         SubnetmapBuilder builder = null;
168         InstanceIdentifier<Subnetmap> id =
169             InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
170         try {
171             synchronized (subnetId.getValue().intern()) {
172                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
173                 if (sn.isPresent()) {
174                     builder = new SubnetmapBuilder(sn.get());
175                     LOG.debug("WithRouterFixedIPs: Updating existing subnetmap node for subnet ID {}",
176                         subnetId.getValue());
177                 } else {
178                     builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
179                     LOG.debug("WithRouterFixedIPs: creating new subnetmap node for subnet ID {}",
180                         subnetId.getValue());
181                 }
182                 builder.setRouterId(routerId);
183                 builder.setRouterInterfaceName(routerInterfaceName);
184                 builder.setRouterIntfMacAddress(routerIntfMacAddress);
185                 if (fixedIp != null) {
186                     List<String> fixedIps = builder.getRouterInterfaceFixedIps();
187                     if (fixedIps == null) {
188                         fixedIps = new ArrayList<>();
189                     }
190                     fixedIps.add(fixedIp);
191                     builder.setRouterInterfaceFixedIps(fixedIps);
192                 } else {
193                     builder.setRouterInterfaceFixedIps(null);
194                 }
195                 subnetmap = builder.build();
196                 LOG.debug("WithRouterFixedIPs Creating/Updating subnetMap node for Router FixedIps: {} ",
197                     subnetId.getValue());
198                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
199             }
200         } catch (Exception e) {
201             LOG.error("WithRouterFixedIPs: Updation of subnetMap for Router FixedIps failed for node: {}",
202                 subnetId.getValue());
203         }
204     }
205
206     // TODO Clean up the exception handling
207     @SuppressWarnings("checkstyle:IllegalCatch")
208     protected Subnetmap updateSubnetNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId, Uuid routerId,
209                                          Uuid vpnId) {
210         Subnetmap subnetmap = null;
211         SubnetmapBuilder builder = null;
212         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
213                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
214                 .build();
215         try {
216             synchronized (subnetId.getValue().intern()) {
217                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
218                 if (sn.isPresent()) {
219                     builder = new SubnetmapBuilder(sn.get());
220                     LOG.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
221                 } else {
222                     builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
223                     LOG.debug("creating new subnetmap node for subnet ID {}", subnetId.getValue());
224                 }
225
226                 if (subnetIp != null) {
227                     builder.setSubnetIp(subnetIp);
228                 }
229                 if (routerId != null) {
230                     builder.setRouterId(routerId);
231                 }
232                 if (networkId != null) {
233                     builder.setNetworkId(networkId);
234                 }
235                 if (vpnId != null) {
236                     builder.setVpnId(vpnId);
237                 }
238                 if (tenantId != null) {
239                     builder.setTenantId(tenantId);
240                 }
241
242                 subnetmap = builder.build();
243                 LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
244                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
245             }
246         } catch (Exception e) {
247             LOG.error("Updation of subnetMap failed for node: {}", subnetId.getValue());
248         }
249         return subnetmap;
250     }
251
252     // TODO Clean up the exception handling
253     @SuppressWarnings("checkstyle:IllegalCatch")
254     protected Subnetmap removeFromSubnetNode(Uuid subnetId, Uuid networkId, Uuid routerId, Uuid vpnId, Uuid portId) {
255         Subnetmap subnetmap = null;
256         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
257                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
258                 .build();
259         try {
260             synchronized (subnetId.getValue().intern()) {
261                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
262                 if (sn.isPresent()) {
263                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
264                     if (routerId != null) {
265                         builder.setRouterId(null);
266                     }
267                     if (networkId != null) {
268                         builder.setNetworkId(null);
269                     }
270                     if (vpnId != null) {
271                         builder.setVpnId(null);
272                     }
273                     if (portId != null && builder.getPortList() != null) {
274                         List<Uuid> portList = builder.getPortList();
275                         portList.remove(portId);
276                         builder.setPortList(portList);
277                     }
278
279                     subnetmap = builder.build();
280                     LOG.debug("Removing from existing subnetmap node: {} ", subnetId.getValue());
281                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
282                 } else {
283                     LOG.warn("removing from non-existing subnetmap node: {} ", subnetId.getValue());
284                 }
285             }
286         } catch (Exception e) {
287             LOG.error("Removal from subnetmap failed for node: {}", subnetId.getValue());
288         }
289         return subnetmap;
290     }
291
292     // TODO Clean up the exception handling
293     @SuppressWarnings("checkstyle:IllegalCatch")
294     protected Subnetmap updateSubnetmapNodeWithPorts(Uuid subnetId, Uuid portId, Uuid directPortId) {
295         Subnetmap subnetmap = null;
296         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
297                 new SubnetmapKey(subnetId)).build();
298         try {
299             synchronized (subnetId.getValue().intern()) {
300                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
301                 if (sn.isPresent()) {
302                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
303                     if (null != portId) {
304                         List<Uuid> portList = builder.getPortList();
305                         if (null == portList) {
306                             portList = new ArrayList<>();
307                         }
308                         portList.add(portId);
309                         builder.setPortList(portList);
310                         LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
311                                 portId.getValue());
312                     }
313                     if (null != directPortId) {
314                         List<Uuid> directPortList = builder.getDirectPortList();
315                         if (null == directPortList) {
316                             directPortList = new ArrayList<>();
317                         }
318                         directPortList.add(directPortId);
319                         builder.setDirectPortList(directPortList);
320                         LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
321                                 directPortId.getValue());
322                     }
323                     subnetmap = builder.build();
324                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
325                 } else {
326                     LOG.error("Trying to update non-existing subnetmap node {} ", subnetId.getValue());
327                 }
328             }
329         } catch (Exception e) {
330             LOG.error("Updating port list of a given subnetMap failed for node: {} with exception{}",
331                     subnetId.getValue(), e);
332         }
333         return subnetmap;
334     }
335
336     // TODO Clean up the exception handling
337     @SuppressWarnings("checkstyle:IllegalCatch")
338     protected Subnetmap removePortsFromSubnetmapNode(Uuid subnetId, Uuid portId, Uuid directPortId) {
339         Subnetmap subnetmap = null;
340         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
341                 new SubnetmapKey(subnetId)).build();
342         try {
343             synchronized (subnetId.getValue().intern()) {
344                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
345                 if (sn.isPresent()) {
346                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
347                     if (null != portId && null != builder.getPortList()) {
348                         List<Uuid> portList = builder.getPortList();
349                         portList.remove(portId);
350                         builder.setPortList(portList);
351                         LOG.debug("Removing port {} from existing subnetmap node: {} ", portId.getValue(),
352                                 subnetId.getValue());
353                     }
354                     if (null != directPortId && null != builder.getDirectPortList()) {
355                         List<Uuid> directPortList = builder.getDirectPortList();
356                         directPortList.remove(directPortId);
357                         builder.setDirectPortList(directPortList);
358                         LOG.debug("Removing direct port {} from existing subnetmap node: {} ", directPortId
359                                 .getValue(), subnetId.getValue());
360                     }
361                     subnetmap = builder.build();
362                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
363                 } else {
364                     LOG.error("Trying to remove port from non-existing subnetmap node {}", subnetId.getValue());
365                 }
366             }
367         } catch (Exception e) {
368             LOG.error("Removing a port from port list of a subnetmap failed for node: {} with expection {}",
369                     subnetId.getValue(), e);
370         }
371         return subnetmap;
372     }
373
374     // TODO Clean up the exception handling
375     @SuppressWarnings("checkstyle:IllegalCatch")
376     protected void deleteSubnetMapNode(Uuid subnetId) {
377         InstanceIdentifier<Subnetmap> subnetMapIdentifier =
378                 InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,new SubnetmapKey(subnetId)).build();
379         LOG.debug("removing subnetMap node: {} ", subnetId.getValue());
380         try {
381             synchronized (subnetId.getValue().intern()) {
382                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
383             }
384         } catch (Exception e) {
385             LOG.error("Delete subnetMap node failed for subnet : {} ", subnetId.getValue());
386         }
387     }
388
389     // TODO Clean up the exception handling
390     @SuppressWarnings("checkstyle:IllegalCatch")
391     private void updateVpnInstanceNode(String vpnName, List<String> rd, List<String> irt, List<String> ert,
392                                        VpnInstance.Type type, long l3vni) {
393
394         VpnInstanceBuilder builder = null;
395         List<VpnTarget> vpnTargetList = new ArrayList<>();
396         boolean isLockAcquired = false;
397         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
398             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
399         try {
400             Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
401                     vpnIdentifier);
402             LOG.debug("Creating/Updating a new vpn-instance node: {} ", vpnName);
403             if (optionalVpn.isPresent()) {
404                 builder = new VpnInstanceBuilder(optionalVpn.get());
405                 LOG.debug("updating existing vpninstance node");
406             } else {
407                 builder = new VpnInstanceBuilder().setKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName)
408                         .setType(type).setL3vni(l3vni);
409             }
410             if (irt != null && !irt.isEmpty()) {
411                 if (ert != null && !ert.isEmpty()) {
412                     List<String> commonRT = new ArrayList<>(irt);
413                     commonRT.retainAll(ert);
414
415                     for (String common : commonRT) {
416                         irt.remove(common);
417                         ert.remove(common);
418                         VpnTarget vpnTarget =
419                                 new VpnTargetBuilder().setKey(new VpnTargetKey(common)).setVrfRTValue(common)
420                                         .setVrfRTType(VpnTarget.VrfRTType.Both).build();
421                         vpnTargetList.add(vpnTarget);
422                     }
423                 }
424                 for (String importRT : irt) {
425                     VpnTarget vpnTarget =
426                             new VpnTargetBuilder().setKey(new VpnTargetKey(importRT)).setVrfRTValue(importRT)
427                                     .setVrfRTType(VpnTarget.VrfRTType.ImportExtcommunity).build();
428                     vpnTargetList.add(vpnTarget);
429                 }
430             }
431
432             if (ert != null && !ert.isEmpty()) {
433                 for (String exportRT : ert) {
434                     VpnTarget vpnTarget =
435                             new VpnTargetBuilder().setKey(new VpnTargetKey(exportRT)).setVrfRTValue(exportRT)
436                                     .setVrfRTType(VpnTarget.VrfRTType.ExportExtcommunity).build();
437                     vpnTargetList.add(vpnTarget);
438                 }
439             }
440
441             VpnTargets vpnTargets = new VpnTargetsBuilder().setVpnTarget(vpnTargetList).build();
442
443             Ipv4FamilyBuilder ipv4vpnBuilder = new Ipv4FamilyBuilder().setVpnTargets(vpnTargets);
444
445             if (rd != null && !rd.isEmpty()) {
446                 ipv4vpnBuilder.setRouteDistinguisher(rd.get(0));
447             }
448
449             VpnInstance newVpn = builder.setIpv4Family(ipv4vpnBuilder.build()).build();
450             isLockAcquired = NeutronvpnUtils.lock(vpnName);
451             LOG.debug("Creating/Updating vpn-instance for {} ", vpnName);
452             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier, newVpn);
453         } catch (Exception e) {
454             LOG.error("Update VPN Instance node failed for node: {} {} {} {}", vpnName, rd, irt, ert);
455         } finally {
456             if (isLockAcquired) {
457                 NeutronvpnUtils.unlock(vpnName);
458             }
459         }
460     }
461
462     // TODO Clean up the exception handling
463     @SuppressWarnings("checkstyle:IllegalCatch")
464     private void deleteVpnMapsNode(Uuid vpnid) {
465         boolean isLockAcquired = false;
466         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
467                 .child(VpnMap.class, new VpnMapKey(vpnid))
468                 .build();
469         LOG.debug("removing vpnMaps node: {} ", vpnid.getValue());
470         try {
471             isLockAcquired = NeutronvpnUtils.lock(vpnid.getValue());
472             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier);
473         } catch (Exception e) {
474             LOG.error("Delete vpnMaps node failed for vpn : {} ", vpnid.getValue());
475         } finally {
476             if (isLockAcquired) {
477                 NeutronvpnUtils.unlock(vpnid.getValue());
478             }
479         }
480     }
481
482     // TODO Clean up the exception handling
483     @SuppressWarnings("checkstyle:IllegalCatch")
484     private void updateVpnMaps(Uuid vpnId, String name, Uuid router, Uuid tenantId, List<Uuid> networks) {
485         VpnMapBuilder builder;
486         boolean isLockAcquired = false;
487         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
488                 .child(VpnMap.class, new VpnMapKey(vpnId))
489                 .build();
490         try {
491             Optional<VpnMap> optionalVpnMap = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
492                     vpnMapIdentifier);
493             if (optionalVpnMap.isPresent()) {
494                 builder = new VpnMapBuilder(optionalVpnMap.get());
495             } else {
496                 builder = new VpnMapBuilder().setKey(new VpnMapKey(vpnId)).setVpnId(vpnId);
497             }
498
499             if (name != null) {
500                 builder.setName(name);
501             }
502             if (tenantId != null) {
503                 builder.setTenantId(tenantId);
504             }
505             if (router != null) {
506                 builder.setRouterId(router);
507             }
508             if (networks != null) {
509                 List<Uuid> nwList = builder.getNetworkIds();
510                 if (nwList == null) {
511                     nwList = new ArrayList<>();
512                 }
513                 nwList.addAll(networks);
514                 builder.setNetworkIds(nwList);
515             }
516
517             isLockAcquired = NeutronvpnUtils.lock(vpnId.getValue());
518             LOG.debug("Creating/Updating vpnMaps node: {} ", vpnId.getValue());
519             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier, builder.build());
520             LOG.debug("VPNMaps DS updated for VPN {} ", vpnId.getValue());
521         } catch (Exception e) {
522             LOG.error("UpdateVpnMaps failed for node: {} ", vpnId.getValue());
523         } finally {
524             if (isLockAcquired) {
525                 NeutronvpnUtils.unlock(vpnId.getValue());
526             }
527         }
528     }
529
530     // TODO Clean up the exception handling
531     @SuppressWarnings("checkstyle:IllegalCatch")
532     private void clearFromVpnMaps(Uuid vpnId, Uuid routerId, List<Uuid> networkIds) {
533         boolean isLockAcquired = false;
534         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
535                 .child(VpnMap.class, new VpnMapKey(vpnId))
536                 .build();
537         Optional<VpnMap> optionalVpnMap = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
538                 vpnMapIdentifier);
539         if (optionalVpnMap.isPresent()) {
540             VpnMap vpnMap = optionalVpnMap.get();
541             VpnMapBuilder vpnMapBuilder = new VpnMapBuilder(vpnMap);
542             if (routerId != null) {
543                 if (vpnMap.getNetworkIds() == null && routerId.equals(vpnMap.getVpnId())) {
544                     try {
545                         // remove entire node in case of internal VPN
546                         isLockAcquired = NeutronvpnUtils.lock(vpnId.getValue());
547                         LOG.debug("removing vpnMaps node: {} ", vpnId);
548                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier);
549                     } catch (Exception e) {
550                         LOG.error("Deletion of vpnMaps node failed for vpn {}", vpnId.getValue());
551                     } finally {
552                         if (isLockAcquired) {
553                             NeutronvpnUtils.unlock(vpnId.getValue());
554                         }
555                     }
556                     return;
557                 }
558                 vpnMapBuilder.setRouterId(null);
559             }
560             if (networkIds != null) {
561                 List<Uuid> vpnNw = vpnMap.getNetworkIds();
562                 for (Uuid nw : networkIds) {
563                     vpnNw.remove(nw);
564                 }
565                 if (vpnNw.isEmpty()) {
566                     LOG.debug("setting networks null in vpnMaps node: {} ", vpnId.getValue());
567                     vpnMapBuilder.setNetworkIds(null);
568                 } else {
569                     vpnMapBuilder.setNetworkIds(vpnNw);
570                 }
571             }
572
573             try {
574                 isLockAcquired = NeutronvpnUtils.lock(vpnId.getValue());
575                 LOG.debug("clearing from vpnMaps node: {} ", vpnId.getValue());
576                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier,
577                         vpnMapBuilder.build());
578             } catch (Exception e) {
579                 LOG.error("Clearing from vpnMaps node failed for vpn {}", vpnId.getValue());
580             } finally {
581                 if (isLockAcquired) {
582                     NeutronvpnUtils.unlock(vpnId.getValue());
583                 }
584             }
585         } else {
586             LOG.error("VPN : {} not found", vpnId.getValue());
587         }
588         LOG.debug("Clear from VPNMaps DS successful for VPN {} ", vpnId.getValue());
589     }
590
591     // TODO Clean up the exception handling
592     @SuppressWarnings("checkstyle:IllegalCatch")
593     private void deleteVpnInstance(Uuid vpnId) {
594         boolean isLockAcquired = false;
595         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
596                 .child(VpnInstance.class,
597                         new VpnInstanceKey(vpnId.getValue()))
598                 .build();
599         try {
600             isLockAcquired = NeutronvpnUtils.lock(vpnId.getValue());
601             LOG.debug("Deleting vpnInstance {}", vpnId.getValue());
602             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
603         } catch (Exception e) {
604             LOG.error("Deletion of VPNInstance node failed for VPN {}", vpnId.getValue());
605         } finally {
606             if (isLockAcquired) {
607                 NeutronvpnUtils.unlock(vpnId.getValue());
608             }
609         }
610     }
611
612     protected void createVpnInterface(Uuid vpnId, Uuid routerId, Port port,
613                                       WriteTransaction wrtConfigTxn) {
614         String infName = port.getUuid().getValue();
615         List<Adjacency> adjList = new ArrayList<>();
616         Boolean isRouterInterface = false;
617         if (port.getDeviceOwner() != null) {
618             isRouterInterface = port.getDeviceOwner().equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF);
619         }
620         LOG.trace("createVpnInterface - isRouterInterface:{}", isRouterInterface);
621         Router rtr = null;
622         if (routerId != null) {
623             rtr = NeutronvpnUtils.getNeutronRouter(dataBroker, routerId);
624         }
625         List<FixedIps> ips = port.getFixedIps();
626         // create adjacency list
627         for (FixedIps ip : ips) {
628             // create vm adjacency
629             String ipValue = String.valueOf(ip.getIpAddress().getValue());
630             String ipPrefix = (ip.getIpAddress().getIpv4Address() != null) ? ipValue + "/32" : ipValue + "/128";
631             Adjacency vmAdj = new AdjacencyBuilder().setKey(new AdjacencyKey(ipPrefix)).setIpAddress(ipPrefix)
632                     .setMacAddress(port.getMacAddress().getValue()).setPrimaryAdjacency(true)
633                     .setSubnetId(ip.getSubnetId()).build();
634             adjList.add(vmAdj);
635             // create extra route adjacency
636             if (rtr != null && rtr.getRoutes() != null) {
637                 List<Routes> routeList = rtr.getRoutes();
638                 List<Adjacency> erAdjList = getAdjacencyforExtraRoute(vpnId, routeList, ipValue);
639                 if (erAdjList != null && !erAdjList.isEmpty()) {
640                     adjList.addAll(erAdjList);
641                 }
642             }
643             NeutronvpnUtils.createVpnPortFixedIpToPort(dataBroker, vpnId.getValue(), ipValue, infName, port
644                             .getMacAddress().getValue(), isRouterInterface, wrtConfigTxn);
645         }
646         // create vpn-interface on this neutron port
647         Adjacencies adjs = new AdjacenciesBuilder().setAdjacency(adjList).build();
648         writeVpnInterfaceToDs(vpnId, infName, adjs, isRouterInterface, wrtConfigTxn);
649         if (routerId != null) {
650             addToNeutronRouterInterfacesMap(routerId, infName);
651         }
652     }
653
654     // TODO Clean up the exception handling
655     @SuppressWarnings("checkstyle:IllegalCatch")
656     protected void deleteVpnInterface(Uuid vpnId, Uuid routerId, Port port, WriteTransaction wrtConfigTxn) {
657         Boolean wrtConfigTxnPresent = true;
658         if (wrtConfigTxn == null) {
659             wrtConfigTxnPresent = false;
660             wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
661         }
662         String infName = port.getUuid().getValue();
663         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
664         try {
665             LOG.debug("Deleting vpn interface {}", infName);
666             wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
667
668             List<FixedIps> ips = port.getFixedIps();
669             for (FixedIps ip : ips) {
670                 String ipValue = String.valueOf(ip.getIpAddress().getValue());
671                 NeutronvpnUtils.removeVpnPortFixedIpToPort(dataBroker, vpnId.getValue(),
672                         ipValue, wrtConfigTxn);
673             }
674         } catch (Exception ex) {
675             LOG.error("Deletion of vpninterface {} failed due to {}", infName, ex);
676         }
677         if (routerId != null) {
678             removeFromNeutronRouterInterfacesMap(routerId, infName);
679         }
680         if (!wrtConfigTxnPresent) {
681             wrtConfigTxn.submit();
682         }
683     }
684
685     // TODO Clean up the exception handling
686     @SuppressWarnings("checkstyle:IllegalCatch")
687     protected void updateVpnInterface(Uuid vpnId, Uuid oldVpnId, Port port, boolean isBeingAssociated,
688                                       boolean isSubnetIp) {
689         if (vpnId == null || port == null) {
690             return;
691         }
692         boolean isLockAcquired = false;
693         String infName = port.getUuid().getValue();
694         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
695
696         try {
697             WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
698             isLockAcquired = NeutronvpnUtils.lock(infName);
699             Optional<VpnInterface> optionalVpnInterface = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
700                     .CONFIGURATION, vpnIfIdentifier);
701             if (optionalVpnInterface.isPresent()) {
702                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
703                         .setVpnInstanceName(vpnId.getValue());
704                 LOG.debug("Updating vpn interface {}", infName);
705                 if (!isBeingAssociated) {
706                     Adjacencies adjs = vpnIfBuilder.getAugmentation(Adjacencies.class);
707                     List<Adjacency> adjacencyList = (adjs != null) ? adjs.getAdjacency() : new ArrayList<>();
708                     Iterator<Adjacency> adjacencyIter = adjacencyList.iterator();
709                     while (adjacencyIter.hasNext()) {
710                         Adjacency adjacency = adjacencyIter.next();
711                         String mipToQuery = adjacency.getIpAddress().split("/")[0];
712                         InstanceIdentifier<LearntVpnVipToPort> id =
713                             NeutronvpnUtils.buildLearntVpnVipToPortIdentifier(oldVpnId.getValue(), mipToQuery);
714                         Optional<LearntVpnVipToPort> optionalVpnVipToPort =
715                             NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
716                         if (optionalVpnVipToPort.isPresent()) {
717                             LOG.trace("Removing adjacencies from vpninterface {} upon dissociation of router {} "
718                                 + "from VPN " + "{}", infName, vpnId, oldVpnId);
719                             adjacencyIter.remove();
720                             NeutronvpnUtils.removeLearntVpnVipToPort(dataBroker, oldVpnId.getValue(), mipToQuery);
721                             LOG.trace("Entry for fixedIP {} for port {} on VPN removed from "
722                                 + "VpnPortFixedIPToPortData", mipToQuery, infName, vpnId.getValue());
723                         }
724                     }
725                     Adjacencies adjacencies = new AdjacenciesBuilder().setAdjacency(adjacencyList).build();
726                     vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
727                 }
728                 List<FixedIps> ips = port.getFixedIps();
729                 for (FixedIps ip : ips) {
730                     String ipValue = String.valueOf(ip.getIpAddress().getValue());
731                     if (oldVpnId != null) {
732                         NeutronvpnUtils.removeVpnPortFixedIpToPort(dataBroker, oldVpnId.getValue(),
733                                 ipValue, writeConfigTxn);
734                     }
735                     NeutronvpnUtils.createVpnPortFixedIpToPort(dataBroker, vpnId.getValue(), ipValue, infName, port
736                             .getMacAddress().getValue(), isSubnetIp, writeConfigTxn);
737                 }
738                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder
739                         .build());
740                 writeConfigTxn.submit();
741             } else {
742                 LOG.error("VPN Interface {} not found", infName);
743             }
744         } catch (Exception ex) {
745             LOG.error("Updation of vpninterface {} failed due to {}", infName, ex);
746         } finally {
747             if (isLockAcquired) {
748                 NeutronvpnUtils.unlock(infName);
749             }
750         }
751     }
752
753     public void createL3InternalVpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt,
754                                     List<String> ert, Uuid router, List<Uuid> networks) {
755
756         // Update VPN Instance node
757         updateVpnInstanceNode(vpn.getValue(), rd, irt, ert, VpnInstance.Type.L3, 0 /*l3vni*/);
758
759         // Update local vpn-subnet DS
760         updateVpnMaps(vpn, name, router, tenant, networks);
761
762         if (router != null) {
763             Uuid existingVpn = NeutronvpnUtils.getVpnForRouter(dataBroker, router, true);
764             if (existingVpn != null) {
765                 // use case when a cluster is rebooted and router add DCN is received, triggering #createL3InternalVpn
766
767                 // if before reboot, router was already associated to VPN, should not proceed associating router to
768                 // internal VPN. Adding to RouterInterfacesMap is also not needed since it's a config DS and will be
769                 // preserved upon reboot.
770                 // For a non-reboot case #associateRouterToInternalVPN already takes care of adding to
771                 // RouterInterfacesMap via #createVPNInterface call.
772                 LOG.info("Associating router to Internal VPN skipped for VPN {} due to router {} already associated "
773                     + "to external VPN {}", vpn.getValue(), router.getValue(), existingVpn.getValue());
774                 return;
775             }
776             associateRouterToInternalVpn(vpn, router);
777         }
778     }
779
780     /**
781      * Performs the creation of a Neutron L3VPN, associating the new VPN to the
782      * specified Neutron Networks and Routers.
783      *
784      * @param vpn Uuid of the VPN tp be created
785      * @param name Representative name of the new VPN
786      * @param tenant Uuid of the Tenant under which the VPN is going to be created
787      * @param rd Route-distinguisher for the VPN
788      * @param irt A list of Import Route Targets
789      * @param ert A list of Export Route Targets
790      * @param router UUID of the neutron router the VPN may be associated to
791      * @param networks UUID of the neutron network the VPN may be associated to
792      * @param type Type of the VPN Instance
793      * @param l3vni L3VNI for the VPN Instance using VxLAN as the underlay
794      * @throws Exception if association of L3VPN failed
795      */
796     public void createVpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt, List<String> ert,
797                             Uuid router, List<Uuid> networks, VpnInstance.Type type, long l3vni) throws Exception {
798
799         // Update VPN Instance node
800         updateVpnInstanceNode(vpn.getValue(), rd, irt, ert, type, l3vni);
801
802         // Please note that router and networks will be filled into VPNMaps
803         // by subsequent calls here to associateRouterToVpn and
804         // associateNetworksToVpn
805         updateVpnMaps(vpn, name, null, tenant, null);
806
807         if (router != null) {
808             associateRouterToVpn(vpn, router);
809         }
810         if (networks != null) {
811             List<String> failStrings = associateNetworksToVpn(vpn, networks);
812             if (failStrings != null &&  !failStrings.isEmpty()) {
813                 LOG.error("VPN {} association to networks failed with error message {}. ",
814                         vpn.getValue(), failStrings.get(0));
815                 throw new Exception(failStrings.get(0));
816             }
817         }
818     }
819
820     /**
821      * It handles the invocations to the createVPN RPC method.
822      */
823     @Override
824     // TODO Clean up the exception handling
825     @SuppressWarnings("checkstyle:IllegalCatch")
826     public Future<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
827
828         CreateL3VPNOutputBuilder opBuilder = new CreateL3VPNOutputBuilder();
829         SettableFuture<RpcResult<CreateL3VPNOutput>> result = SettableFuture.create();
830         List<RpcError> errorList = new ArrayList<>();
831         int failurecount = 0;
832         int warningcount = 0;
833
834         List<L3vpn> vpns = input.getL3vpn();
835         for (L3vpn vpn : vpns) {
836             RpcError error = null;
837             String msg;
838             if (NeutronvpnUtils.doesVpnExist(dataBroker, vpn.getId())) {
839                 msg = String.format("Creation of L3VPN failed for VPN %s due to VPN with the same ID already present",
840                                 vpn.getId().getValue());
841                 LOG.warn(msg);
842                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
843                 errorList.add(error);
844                 warningcount++;
845                 continue;
846             }
847             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
848                 msg = String.format("Creation of L3VPN failed for VPN %s due to absence of RD/iRT/eRT input",
849                         vpn.getId().getValue());
850                 LOG.warn(msg);
851                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
852                 errorList.add(error);
853                 warningcount++;
854                 continue;
855             }
856             VpnInstance.Type vpnInstanceType = VpnInstance.Type.L3;
857             long l3vni = 0;
858             if (vpn.getL3vni() != null) {
859                 l3vni = vpn.getL3vni();
860             }
861
862             if (vpn.getRouteDistinguisher().size() > 1) {
863                 msg = String.format("Creation of VPN failed for VPN %s due to multiple RD input %s",
864                         vpn.getId().getValue(), vpn.getRouteDistinguisher());
865                 LOG.warn(msg);
866                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
867                 errorList.add(error);
868                 warningcount++;
869                 continue;
870             }
871             List<String> existingRDs = NeutronvpnUtils.getExistingRDs(dataBroker);
872             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
873                 msg = String.format("Creation of L3VPN failed for VPN %s as another VPN with the same RD %s "
874                     + "is already configured",
875                     vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0));
876                 LOG.warn(msg);
877                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
878                 errorList.add(error);
879                 warningcount++;
880                 continue;
881             }
882             if (vpn.getRouterId() != null) {
883                 if (NeutronvpnUtils.getNeutronRouter(dataBroker, vpn.getRouterId()) == null) {
884                     msg = String.format("Creation of L3VPN failed for VPN %s due to router not found %s",
885                             vpn.getId().getValue(), vpn.getRouterId().getValue());
886                     LOG.warn(msg);
887                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
888                     errorList.add(error);
889                     warningcount++;
890                     continue;
891                 }
892                 Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, vpn.getRouterId(), true);
893                 if (vpnId != null) {
894                     msg = String.format("Creation of L3VPN failed for VPN %s due to router %s already associated to "
895                                     + "another VPN %s", vpn.getId().getValue(), vpn.getRouterId().getValue(),
896                             vpnId.getValue());
897                     LOG.warn(msg);
898                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
899                     errorList.add(error);
900                     warningcount++;
901                     continue;
902                 }
903             }
904             if (vpn.getNetworkIds() != null) {
905                 for (Uuid nw : vpn.getNetworkIds()) {
906                     Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
907                     Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
908                     if (network == null) {
909                         msg = String.format("Creation of L3VPN failed for VPN %s due to network not found %s",
910                                 vpn.getId().getValue(), nw.getValue());
911                         LOG.warn(msg);
912                         error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
913                         errorList.add(error);
914                         warningcount++;
915                     } else if (vpnId != null) {
916                         msg = String.format("Creation of L3VPN failed for VPN %s due to network %s already associated"
917                                         + " to another VPN %s", vpn.getId().getValue(), nw.getValue(),
918                                 vpnId.getValue());
919                         LOG.warn(msg);
920                         error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
921                         errorList.add(error);
922                         warningcount++;
923                     }
924                 }
925                 if (error != null) {
926                     continue;
927                 }
928             }
929             try {
930                 createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), vpn.getRouteDistinguisher(),
931                         vpn.getImportRT(), vpn.getExportRT(), vpn.getRouterId(), vpn.getNetworkIds(),
932                         vpnInstanceType, l3vni);
933             } catch (Exception ex) {
934                 msg = String.format("Creation of VPN failed for VPN %s", vpn.getId().getValue());
935                 LOG.error(msg, ex);
936                 error = RpcResultBuilder.newError(ErrorType.APPLICATION, msg, ex.getMessage());
937                 errorList.add(error);
938                 failurecount++;
939             }
940         }
941         // if at least one succeeds; result is success
942         // if none succeeds; result is failure
943         if (failurecount + warningcount == vpns.size()) {
944             result.set(RpcResultBuilder.<CreateL3VPNOutput>failed().withRpcErrors(errorList).build());
945         } else {
946             List<String> errorResponseList = new ArrayList<>();
947             if (!errorList.isEmpty()) {
948                 for (RpcError rpcError : errorList) {
949                     String errorResponse = String.format("ErrorType: %s, ErrorTag: %s, ErrorMessage: %s", rpcError
950                             .getErrorType(), rpcError.getTag(), rpcError.getMessage());
951                     errorResponseList.add(errorResponse);
952                 }
953             } else {
954                 errorResponseList.add("Operation successful with no errors");
955             }
956             opBuilder.setResponse(errorResponseList);
957             result.set(RpcResultBuilder.<CreateL3VPNOutput>success().withResult(opBuilder.build()).build());
958         }
959         return result;
960     }
961
962     /**
963      * It handles the invocations to the neutronvpn:getL3VPN RPC method.
964      */
965     @Override
966     // TODO Clean up the exception handling
967     @SuppressWarnings("checkstyle:IllegalCatch")
968     public Future<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
969
970         GetL3VPNOutputBuilder opBuilder = new GetL3VPNOutputBuilder();
971         SettableFuture<RpcResult<GetL3VPNOutput>> result = SettableFuture.create();
972         Uuid inputVpnId = input.getId();
973         List<VpnInstance> vpns = new ArrayList<>();
974
975         try {
976             if (inputVpnId == null) {
977                 // get all vpns
978                 InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class)
979                         .build();
980                 Optional<VpnInstances> optionalVpns = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
981                         .CONFIGURATION, vpnsIdentifier);
982                 if (optionalVpns.isPresent() && !optionalVpns.get().getVpnInstance().isEmpty()) {
983                     for (VpnInstance vpn : optionalVpns.get().getVpnInstance()) {
984                         // eliminating implicitly created (router and VLAN provider external network specific) VPNs
985                         // from getL3VPN output
986                         if (vpn.getIpv4Family().getRouteDistinguisher() != null) {
987                             vpns.add(vpn);
988                         }
989                     }
990                 } else {
991                     // No VPN present
992                     result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
993                     return result;
994                 }
995             } else {
996                 String name = inputVpnId.getValue();
997                 InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
998                         .child(VpnInstance.class, new VpnInstanceKey(name)).build();
999                 // read VpnInstance Info
1000                 Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1001                         vpnIdentifier);
1002                 // eliminating implicitly created (router or VLAN provider external network specific) VPN from
1003                 // getL3VPN output
1004                 if (optionalVpn.isPresent() && optionalVpn.get().getIpv4Family().getRouteDistinguisher() != null) {
1005                     vpns.add(optionalVpn.get());
1006                 } else {
1007                     String message = String.format("GetL3VPN failed because VPN %s is not present", name);
1008                     LOG.error(message);
1009                     result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withWarning(ErrorType.PROTOCOL,
1010                             "invalid-value", message).build());
1011                 }
1012             }
1013             List<L3vpnInstances> l3vpnList = new ArrayList<>();
1014             for (VpnInstance vpnInstance : vpns) {
1015                 Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
1016                 // create VpnMaps id
1017                 L3vpnInstancesBuilder l3vpn = new L3vpnInstancesBuilder();
1018
1019                 List<String> rd = Arrays.asList(vpnInstance.getIpv4Family().getRouteDistinguisher().split(","));
1020                 List<VpnTarget> vpnTargetList = vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget();
1021
1022                 List<String> ertList = new ArrayList<>();
1023                 List<String> irtList = new ArrayList<>();
1024
1025                 for (VpnTarget vpnTarget : vpnTargetList) {
1026                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
1027                         ertList.add(vpnTarget.getVrfRTValue());
1028                     }
1029                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
1030                         irtList.add(vpnTarget.getVrfRTValue());
1031                     }
1032                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
1033                         ertList.add(vpnTarget.getVrfRTValue());
1034                         irtList.add(vpnTarget.getVrfRTValue());
1035                     }
1036                 }
1037
1038                 l3vpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
1039                 if (vpnInstance.getL3vni() != null) {
1040                     l3vpn.setL3vni(vpnInstance.getL3vni());
1041                 }
1042                 InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
1043                         .class, new VpnMapKey(vpnId)).build();
1044                 Optional<VpnMap> optionalVpnMap = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1045                         vpnMapIdentifier);
1046                 if (optionalVpnMap.isPresent()) {
1047                     VpnMap vpnMap = optionalVpnMap.get();
1048                     l3vpn.setRouterId(vpnMap.getRouterId()).setNetworkIds(vpnMap.getNetworkIds())
1049                             .setTenantId(vpnMap.getTenantId()).setName(vpnMap.getName());
1050                 }
1051                 l3vpnList.add(l3vpn.build());
1052             }
1053
1054             opBuilder.setL3vpnInstances(l3vpnList);
1055             result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1056
1057         } catch (Exception ex) {
1058             String message = String.format("GetVPN failed due to %s", ex.getMessage());
1059             LOG.error(message, ex);
1060             result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withError(ErrorType.APPLICATION, message).build());
1061         }
1062         return result;
1063     }
1064
1065     /**
1066      * It handles the invocations to the neutronvpn:deleteL3VPN RPC method.
1067      */
1068     @Override
1069     // TODO Clean up the exception handling
1070     @SuppressWarnings("checkstyle:IllegalCatch")
1071     public Future<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
1072
1073         DeleteL3VPNOutputBuilder opBuilder = new DeleteL3VPNOutputBuilder();
1074         SettableFuture<RpcResult<DeleteL3VPNOutput>> result = SettableFuture.create();
1075         List<RpcError> errorList = new ArrayList<>();
1076
1077         int failurecount = 0;
1078         int warningcount = 0;
1079         List<Uuid> vpns = input.getId();
1080         for (Uuid vpn : vpns) {
1081             RpcError error;
1082             String msg;
1083             try {
1084                 InstanceIdentifier<VpnInstance> vpnIdentifier =
1085                         InstanceIdentifier.builder(VpnInstances.class)
1086                             .child(VpnInstance.class, new VpnInstanceKey(vpn.getValue())).build();
1087                 Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1088                         .CONFIGURATION, vpnIdentifier);
1089                 if (optionalVpn.isPresent()) {
1090                     removeVpn(vpn);
1091                 } else {
1092                     msg = String.format("VPN with vpnid: %s does not exist", vpn.getValue());
1093                     LOG.warn(msg);
1094                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-value", msg);
1095                     errorList.add(error);
1096                     warningcount++;
1097                 }
1098             } catch (Exception ex) {
1099                 msg = String.format("Deletion of L3VPN failed when deleting for uuid %s", vpn.getValue());
1100                 LOG.error(msg, ex);
1101                 error = RpcResultBuilder.newError(ErrorType.APPLICATION, msg, ex.getMessage());
1102                 errorList.add(error);
1103                 failurecount++;
1104             }
1105         }
1106         // if at least one succeeds; result is success
1107         // if none succeeds; result is failure
1108         if (failurecount + warningcount == vpns.size()) {
1109             result.set(RpcResultBuilder.<DeleteL3VPNOutput>failed().withRpcErrors(errorList).build());
1110         } else {
1111             List<String> errorResponseList = new ArrayList<>();
1112             if (!errorList.isEmpty()) {
1113                 for (RpcError rpcError : errorList) {
1114                     String errorResponse = String.format("ErrorType: %s, ErrorTag: %s, ErrorMessage: %s", rpcError
1115                             .getErrorType(), rpcError.getTag(), rpcError.getMessage());
1116                     errorResponseList.add(errorResponse);
1117                 }
1118             } else {
1119                 errorResponseList.add("Operation successful with no errors");
1120             }
1121             opBuilder.setResponse(errorResponseList);
1122             result.set(RpcResultBuilder.<DeleteL3VPNOutput>success().withResult(opBuilder.build()).build());
1123         }
1124         return result;
1125     }
1126
1127     protected void addSubnetToVpn(final Uuid vpnId, Uuid subnet) {
1128         LOG.debug("Adding subnet {} to vpn {}", subnet.getValue(), vpnId.getValue());
1129         Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId);
1130         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
1131         // Check if there are ports on this subnet and add corresponding
1132         // vpn-interfaces
1133         List<Uuid> portList = sn.getPortList();
1134         if (portList != null) {
1135             for (final Uuid portId : sn.getPortList()) {
1136                 LOG.debug("adding vpn-interface for port {}", portId.getValue());
1137                 final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1138                 portDataStoreCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1139                     WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
1140                     List<ListenableFuture<Void>> futures = new ArrayList<>();
1141                     createVpnInterface(vpnId, routerId, NeutronvpnUtils.getNeutronPort(dataBroker, portId),
1142                             wrtConfigTxn);
1143                     futures.add(wrtConfigTxn.submit());
1144                     return futures;
1145                 });
1146             }
1147         }
1148     }
1149
1150     protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet, boolean isBeingAssociated) {
1151         LOG.debug("Updating VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
1152         // Read the subnet first to see if its already associated to a VPN
1153         Uuid oldVpnId = null;
1154         InstanceIdentifier<Subnetmap> snId = InstanceIdentifier.builder(Subnetmaps.class)
1155             .child(Subnetmap.class, new SubnetmapKey(subnet)).build();
1156         Subnetmap sn = null;
1157         Optional<Subnetmap> optSn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, snId);
1158         if (optSn.isPresent()) {
1159             sn = optSn.get();
1160             oldVpnId = sn.getVpnId();
1161             List<String> ips = sn.getRouterInterfaceFixedIps();
1162             for (String ipValue : ips) {
1163                 // Update the association of router-interface to external vpn
1164                 String portName =
1165                     NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, oldVpnId.getValue(), ipValue);
1166                 if (portName != null) {
1167                     updateVpnInterface(vpnId, oldVpnId,
1168                         NeutronvpnUtils.getNeutronPort(dataBroker, new Uuid(portName)),
1169                         isBeingAssociated, true);
1170                 }
1171             }
1172         }
1173         sn = updateSubnetNode(subnet, null, null, null, null, vpnId);
1174         // Check for ports on this subnet and update association of
1175         // corresponding vpn-interfaces to external vpn
1176         List<Uuid> portList = sn.getPortList();
1177         if (portList != null) {
1178             for (Uuid port : sn.getPortList()) {
1179                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1180                     port.getValue(), isBeingAssociated);
1181                 updateVpnInterface(vpnId, oldVpnId, NeutronvpnUtils.getNeutronPort(dataBroker, port),
1182                         isBeingAssociated, false);
1183             }
1184         }
1185     }
1186
1187     public InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
1188         return InstanceIdentifier.builder(RouterInterfacesMap.class)
1189                 .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
1190     }
1191
1192     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1193         synchronized (routerId.getValue().intern()) {
1194             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1195             Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1196                     .CONFIGURATION, routerInterfacesId);
1197             Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
1198                 .setInterfaceId(interfaceName).build();
1199             if (optRouterInterfaces.isPresent()) {
1200                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces
1201                         .class, new InterfacesKey(interfaceName)), routerInterface);
1202             } else {
1203                 RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
1204                 List<Interfaces> interfaces = new ArrayList<>();
1205                 interfaces.add(routerInterface);
1206                 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces
1207                         .class, new InterfacesKey(interfaceName)), routerInterface);
1208             }
1209         }
1210     }
1211
1212     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1213         synchronized (routerId.getValue().intern()) {
1214             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1215             Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1216                     .CONFIGURATION, routerInterfacesId);
1217             Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
1218                 .setInterfaceId(interfaceName).build();
1219             if (optRouterInterfaces.isPresent()) {
1220                 RouterInterfaces routerInterfaces = optRouterInterfaces.get();
1221                 List<Interfaces> interfaces = routerInterfaces.getInterfaces();
1222                 if (interfaces != null && interfaces.remove(routerInterface)) {
1223                     if (interfaces.isEmpty()) {
1224                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
1225                     } else {
1226                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1227                                 routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
1228                     }
1229                 }
1230             }
1231         }
1232     }
1233
1234     /**
1235      * Creates the corresponding static routes in the specified VPN. These static routes must be point to an
1236      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink. Otherwise the
1237      * route will be ignored.
1238      *
1239      * @param vpnName the VPN identifier
1240      * @param interVpnLinkRoutes The list of static routes
1241      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1242      */
1243     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1244                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1245         for ( Routes route : interVpnLinkRoutes ) {
1246             String nexthop = String.valueOf(route.getNexthop().getValue());
1247             String destination = String.valueOf(route.getDestination().getValue());
1248             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1249             if ( isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink) ) {
1250                 AddStaticRouteInput rpcInput =
1251                         new AddStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1252                                 .setVpnInstanceName(vpnName.getValue())
1253                                 .build();
1254                 Future<RpcResult<AddStaticRouteOutput>> labelOuputFtr = vpnRpcService.addStaticRoute(rpcInput);
1255                 RpcResult<AddStaticRouteOutput> rpcResult;
1256                 try {
1257                     rpcResult = labelOuputFtr.get();
1258                     if ( rpcResult.isSuccessful() ) {
1259                         LOG.debug("Label generated for destination {} is: {}",
1260                                 destination, rpcResult.getResult().getLabel());
1261                     } else {
1262                         LOG.warn("RPC call to add a static Route to {} with nexthop {} returned with errors {}",
1263                                 destination, nexthop, rpcResult.getErrors());
1264                     }
1265                 } catch (InterruptedException | ExecutionException e) {
1266                     LOG.warn("Error happened while invoking addStaticRoute RPC: ", e);
1267                 }
1268             } else {
1269                 // Any other case is a fault.
1270                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1271                         String.valueOf(route.getDestination().getValue()), nexthop );
1272                 continue;
1273             }
1274         }
1275     }
1276
1277     /**
1278      * Removes the corresponding static routes from the specified VPN. These static routes point to an
1279      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink.
1280      *
1281      * @param vpnName the VPN identifier
1282      * @param interVpnLinkRoutes The list of static routes
1283      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1284      */
1285     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1286                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1287         for ( Routes route : interVpnLinkRoutes ) {
1288             String nexthop = String.valueOf(route.getNexthop().getValue());
1289             String destination = String.valueOf(route.getDestination().getValue());
1290             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1291             if ( isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink) ) {
1292                 RemoveStaticRouteInput rpcInput =
1293                         new RemoveStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1294                                 .setVpnInstanceName(vpnName.getValue())
1295                                 .build();
1296                 vpnRpcService.removeStaticRoute(rpcInput);
1297             } else {
1298                 // Any other case is a fault.
1299                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1300                         String.valueOf(route.getDestination().getValue()), nexthop );
1301                 continue;
1302             }
1303         }
1304     }
1305
1306     /*
1307      * Returns true if the specified nexthop is the other endpoint in an
1308      * InterVpnLink, regarding one of the VPN's point of view.
1309      */
1310     private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
1311         return
1312                 interVpnLink != null
1313                         && (   (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
1314                         && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
1315                         || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
1316                         && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
1317     }
1318
1319     protected List<Adjacency> getAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList, String fixedIp) {
1320         List<Adjacency> adjList = new ArrayList<>();
1321         Map<String, List<String>> adjMap = new HashMap<>();
1322         for (Routes route : routeList) {
1323             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
1324                 LOG.error("Incorrect input received for extra route. {}", route);
1325             } else {
1326                 String nextHop = String.valueOf(route.getNexthop().getValue());
1327                 String destination = String.valueOf(route.getDestination().getValue());
1328                 if (!nextHop.equals(fixedIp)) {
1329                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
1330                     continue;
1331                 }
1332                 LOG.trace("Adding extra route for destination {} onto vpn {} with nexthop {} ", destination,
1333                         vpnId.getValue(), nextHop);
1334                 List<String> hops = adjMap.computeIfAbsent(destination, k -> new ArrayList<>());
1335                 if (!hops.contains(nextHop)) {
1336                     hops.add(nextHop);
1337                 }
1338             }
1339         }
1340
1341         for (String destination : adjMap.keySet()) {
1342             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
1343                 .setNextHopIpList(adjMap.get(destination)).setKey(new AdjacencyKey(destination)).build();
1344             adjList.add(erAdj);
1345         }
1346         return  adjList;
1347     }
1348
1349     // TODO Clean up the exception handling
1350     @SuppressWarnings("checkstyle:IllegalCatch")
1351     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
1352         for (Routes route : routeList) {
1353             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
1354                 LOG.error("Incorrect input received for extra route. {}", route);
1355             } else {
1356                 String nextHop = String.valueOf(route.getNexthop().getValue());
1357                 String destination = String.valueOf(route.getDestination().getValue());
1358                 String infName = NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, vpnId.getValue(),
1359                         nextHop);
1360                 if (infName != null) {
1361                     LOG.trace("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}",
1362                         destination, vpnId.getValue(), nextHop, infName);
1363                     boolean isLockAcquired = false;
1364                     try {
1365                         InstanceIdentifier<VpnInterface> identifier = InstanceIdentifier.builder(VpnInterfaces.class)
1366                                 .child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
1367                         InstanceIdentifier<Adjacency> path = identifier.augmentation(Adjacencies.class)
1368                             .child(Adjacency.class, new AdjacencyKey(destination));
1369                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
1370                             .setNextHopIpList(Collections.singletonList(nextHop)).setKey(new AdjacencyKey(destination))
1371                             .build();
1372                         isLockAcquired = NeutronvpnUtils.lock(infName);
1373                         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, erAdj);
1374                     } catch (Exception e) {
1375                         LOG.error("exception in adding extra route with destination: {}, next hop: {}",
1376                             destination, nextHop, e);
1377                     } finally {
1378                         if (isLockAcquired) {
1379                             NeutronvpnUtils.unlock(infName);
1380                         }
1381                     }
1382                 } else {
1383                     LOG.debug("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} "
1384                         + "with nexthop {}", destination, vpnId.getValue(), nextHop);
1385                 }
1386             }
1387         }
1388     }
1389
1390     // TODO Clean up the exception handling
1391     @SuppressWarnings("checkstyle:IllegalCatch")
1392     protected void removeAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList) {
1393         for (Routes route : routeList) {
1394             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
1395                 boolean isLockAcquired = false;
1396                 String nextHop = String.valueOf(route.getNexthop().getValue());
1397                 String destination = String.valueOf(route.getDestination().getValue());
1398                 String infName = NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, vpnId.getValue(),
1399                         nextHop);
1400                 if (infName == null) {
1401                     LOG.error("Unable to find VPN NextHop interface to remove extra-route destination {} on VPN {} "
1402                             + "with nexthop {}", destination, vpnId.getValue(), nextHop);
1403                     // Proceed to remove the next extra-route
1404                     continue;
1405                 }
1406                 LOG.trace("Removing extra route for destination {} on vpn {} with nexthop {} and infName {}",
1407                         destination, vpnId.getValue(), nextHop, infName);
1408
1409                 InstanceIdentifier<Adjacency> adjacencyIdentifier =
1410                         InstanceIdentifier.builder(VpnInterfaces.class)
1411                                 .child(VpnInterface.class, new VpnInterfaceKey(infName))
1412                                 .augmentation(Adjacencies.class)
1413                                 .child(Adjacency.class, new AdjacencyKey(destination))
1414                                 .build();
1415
1416                 // Looking for existing prefix in MDSAL database
1417                 Optional<Adjacency> adjacency = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1418                         adjacencyIdentifier);
1419                 boolean updateNextHops = false;
1420                 List<String> nextHopList = new ArrayList<>();
1421                 if (adjacency.isPresent()) {
1422                     List<String> nhListRead = adjacency.get().getNextHopIpList();
1423                     if (nhListRead.size() > 1) { // ECMP case
1424                         for (String nextHopRead : nhListRead) {
1425                             if (nextHopRead.equals(nextHop)) {
1426                                 updateNextHops = true;
1427                             } else {
1428                                 nextHopList.add(nextHopRead);
1429                             }
1430                         }
1431                     }
1432                 }
1433
1434                 try {
1435                     isLockAcquired = NeutronvpnUtils.lock(infName);
1436                     if (updateNextHops) {
1437                         // An update must be done, not including the current next hop
1438                         InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(
1439                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
1440                         Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
1441                                 .setNextHopIpList(nextHopList)
1442                                 .setKey(new AdjacencyKey(destination))
1443                                 .build();
1444                         Adjacencies erAdjs =
1445                                 new AdjacenciesBuilder().setAdjacency(Collections.singletonList(newAdj)).build();
1446                         VpnInterface vpnIf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
1447                                 .addAugmentation(Adjacencies.class, erAdjs).build();
1448                         MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
1449                     } else {
1450                         // Remove the whole route
1451                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
1452                         LOG.trace("extra route {} deleted successfully", route);
1453                     }
1454                 } catch (Exception e) {
1455                     LOG.error("exception in deleting extra route: {}" + e);
1456                 } finally {
1457                     if (isLockAcquired) {
1458                         NeutronvpnUtils.unlock(infName);
1459                     }
1460                 }
1461             } else {
1462                 LOG.error("Incorrect input received for extra route. {}", route);
1463             }
1464         }
1465     }
1466
1467     protected void removeVpn(Uuid id) {
1468         // read VPNMaps
1469         VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, id);
1470         Uuid router = (vpnMap != null) ? vpnMap.getRouterId() : null;
1471         // dissociate router
1472         if (router != null) {
1473             dissociateRouterFromVpn(id, router);
1474         }
1475         // dissociate networks
1476         if (!id.equals(router)) {
1477             dissociateNetworksFromVpn(id, vpnMap.getNetworkIds());
1478         }
1479         // remove entire vpnMaps node
1480         deleteVpnMapsNode(id);
1481
1482         // remove vpn-instance
1483         deleteVpnInstance(id);
1484     }
1485
1486     protected void removeSubnetFromVpn(final Uuid vpnId, Uuid subnet) {
1487         LOG.debug("Removing subnet {} from vpn {}", subnet.getValue(), vpnId.getValue());
1488         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
1489         Subnetmap sn = NeutronvpnUtils.getSubnetmap(dataBroker, subnet);
1490         if (sn != null) {
1491             // Check if there are ports on this subnet; remove corresponding vpn-interfaces
1492             List<Uuid> portList = sn.getPortList();
1493             if (portList != null) {
1494                 for (final Uuid portId : sn.getPortList()) {
1495                     LOG.debug("removing vpn-interface for port {}", portId.getValue());
1496                     final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1497                     portDataStoreCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1498                         WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
1499                         List<ListenableFuture<Void>> futures = new ArrayList<>();
1500                         Port port = NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1501                         if (port != null) {
1502                             deleteVpnInterface(vpnId, routerId, port, wrtConfigTxn);
1503                         } else {
1504                             LOG.error("Cannot proceed with deleteVpnInterface for port {} in subnet {} since port is "
1505                                 + "absent in Neutron config DS", portId.getValue(), subnet.getValue());
1506                         }
1507                         futures.add(wrtConfigTxn.submit());
1508                         return futures;
1509                     });
1510                 }
1511             }
1512             // update subnet-vpn association
1513             removeFromSubnetNode(subnet, null, null, vpnId, null);
1514         } else {
1515             LOG.warn("Subnetmap for subnet {} not found", subnet.getValue());
1516         }
1517     }
1518
1519     // TODO Clean up the exception handling
1520     @SuppressWarnings("checkstyle:IllegalCatch")
1521     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
1522         updateVpnMaps(vpnId, null, routerId, null, null);
1523         LOG.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
1524         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1525         if (routerSubnets != null) {
1526             for (Uuid subnetId : routerSubnets) {
1527                 updateVpnForSubnet(vpnId, subnetId, true);
1528             }
1529         }
1530         try {
1531             checkAndPublishRouterAssociatedtoVpnNotification(routerId, vpnId);
1532             LOG.debug("notification upon association of router {} to VPN {} published", routerId.getValue(),
1533                     vpnId.getValue());
1534         } catch (Exception e) {
1535             LOG.error("publishing of notification upon association of router {} to VPN {} failed : ", routerId
1536                     .getValue(), vpnId.getValue(), e);
1537         }
1538     }
1539
1540     protected void associateRouterToInternalVpn(Uuid vpnId, Uuid routerId) {
1541         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1542         LOG.debug("Adding subnets to internal vpn {}", vpnId.getValue());
1543         for (Uuid subnet : routerSubnets) {
1544             addSubnetToVpn(vpnId, subnet);
1545         }
1546     }
1547
1548     // TODO Clean up the exception handling
1549     @SuppressWarnings("checkstyle:IllegalCatch")
1550     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
1551
1552         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1553         if (routerSubnets != null) {
1554             for (Uuid subnetId : routerSubnets) {
1555                 LOG.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
1556                 updateVpnForSubnet(routerId, subnetId, false);
1557             }
1558         }
1559         clearFromVpnMaps(vpnId, routerId, null);
1560         try {
1561             checkAndPublishRouterDisassociatedFromVpnNotification(routerId, vpnId);
1562             LOG.debug("notification upon disassociation of router {} from VPN {} published", routerId.getValue(),
1563                     vpnId.getValue());
1564         } catch (Exception e) {
1565             LOG.error("publishing of notification upon disassociation of router {} from VPN {} failed : ", routerId
1566                     .getValue(), vpnId.getValue(), e);
1567         }
1568     }
1569
1570     protected List<String> associateNetworksToVpn(Uuid vpn, List<Uuid> networks) {
1571         List<String> failedNwList = new ArrayList<>();
1572         List<Uuid> passedNwList = new ArrayList<>();
1573         if (!networks.isEmpty()) {
1574             // process corresponding subnets for VPN
1575             for (Uuid nw : networks) {
1576                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
1577                 NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
1578                 if (providerExtension.getSegments() != null && providerExtension.getSegments().size() > 1) {
1579                     LOG.error("MultiSegmented networks not supported in VPN. Failed to associate network {} on vpn {}",
1580                             nw.getValue(), vpn.getValue());
1581                     failedNwList.add(String.format("Failed to associate network %s on vpn %s as it is multisegmented.",
1582                             nw.getValue(), vpn.getValue()));
1583                     continue;
1584                 }
1585                 Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
1586                 if (network == null) {
1587                     failedNwList.add(String.format("network %s not found", nw.getValue()));
1588                 } else if (vpnId != null) {
1589                     failedNwList.add(String.format("network %s already associated to another VPN %s", nw.getValue(),
1590                             vpnId.getValue()));
1591                 } else {
1592                     List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
1593                     LOG.debug("Adding network subnets...{}", networkSubnets);
1594                     if (networkSubnets != null) {
1595                         for (Uuid subnet : networkSubnets) {
1596                             // check if subnet added as router interface to some router
1597                             Uuid subnetVpnId = NeutronvpnUtils.getVpnForSubnet(dataBroker, subnet);
1598                             if (subnetVpnId == null) {
1599                                 addSubnetToVpn(vpn, subnet);
1600                                 passedNwList.add(nw);
1601                             } else {
1602                                 failedNwList.add(String.format("subnet %s already added as router interface bound to "
1603                                     + "internal/external VPN %s", subnet.getValue(), subnetVpnId.getValue()));
1604                             }
1605                         }
1606                     }
1607                     if (NeutronvpnUtils.getIsExternal(network)) {
1608                         nvpnNatManager.addExternalNetworkToVpn(network, vpn);
1609                     }
1610                 }
1611             }
1612             updateVpnMaps(vpn, null, null, null, passedNwList);
1613         }
1614         return failedNwList;
1615     }
1616
1617     protected List<String> dissociateNetworksFromVpn(Uuid vpn, List<Uuid> networks) {
1618         List<String> failedNwList = new ArrayList<>();
1619         List<Uuid> passedNwList = new ArrayList<>();
1620         if (networks != null && !networks.isEmpty()) {
1621             // process corresponding subnets for VPN
1622             for (Uuid nw : networks) {
1623                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
1624                 if (network == null) {
1625                     failedNwList.add(String.format("network %s not found", nw.getValue()));
1626                 } else {
1627                     Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
1628                     if (vpn.equals(vpnId)) {
1629                         List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
1630                         LOG.debug("Removing network subnets...");
1631                         if (networkSubnets != null) {
1632                             for (Uuid subnet : networkSubnets) {
1633                                 removeSubnetFromVpn(vpn, subnet);
1634                                 passedNwList.add(nw);
1635                             }
1636                         }
1637                     } else {
1638                         if (vpnId == null) {
1639                             failedNwList.add(String.format("input network %s not associated to any vpn yet", nw
1640                                     .getValue()));
1641                         } else {
1642                             failedNwList.add(String.format("input network %s associated to a another vpn %s instead "
1643                                 + "of the one given as input", nw.getValue(), vpnId.getValue()));
1644                         }
1645                     }
1646                     if (NeutronvpnUtils.getIsExternal(network)) {
1647                         nvpnNatManager.removeExternalNetworkFromVpn(network);
1648                     }
1649                 }
1650             }
1651             clearFromVpnMaps(vpn, null, passedNwList);
1652         }
1653         return failedNwList;
1654     }
1655
1656     /**
1657      * It handles the invocations to the neutronvpn:associateNetworks RPC method.
1658      */
1659     @Override
1660     // TODO Clean up the exception handling
1661     @SuppressWarnings("checkstyle:IllegalCatch")
1662     public Future<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
1663
1664         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
1665         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
1666         LOG.debug("associateNetworks {}", input);
1667         StringBuilder returnMsg = new StringBuilder();
1668         Uuid vpnId = input.getVpnId();
1669
1670         try {
1671             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1672                 List<Uuid> netIds = input.getNetworkId();
1673                 if (netIds != null && !netIds.isEmpty()) {
1674                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
1675                     if (!failed.isEmpty()) {
1676                         returnMsg.append(failed);
1677                     }
1678                 }
1679             } else {
1680                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1681             }
1682             if (returnMsg.length() != 0) {
1683                 String message = String.format("associate Networks to vpn %s failed due to %s",
1684                         vpnId.getValue(), returnMsg);
1685                 LOG.error(message);
1686                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: %s",
1687                         message);
1688                 opBuilder.setResponse(errorResponse);
1689                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().withResult(opBuilder.build()).build());
1690             } else {
1691                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().build());
1692             }
1693         } catch (Exception ex) {
1694             String message = String.format("associate Networks to vpn %s failed due to %s",
1695                     input.getVpnId().getValue(), ex.getMessage());
1696             LOG.error(message, ex);
1697             result.set(RpcResultBuilder.<AssociateNetworksOutput>failed().withError(ErrorType.APPLICATION, message)
1698                     .build());
1699         }
1700         LOG.debug("associateNetworks returns..");
1701         return result;
1702     }
1703
1704     /**
1705      * It handles the invocations to the neutronvpn:associateRouter RPC method.
1706      */
1707     @Override
1708     // TODO Clean up the exception handling
1709     @SuppressWarnings("checkstyle:IllegalCatch")
1710     public Future<RpcResult<Void>> associateRouter(AssociateRouterInput input) {
1711
1712         SettableFuture<RpcResult<Void>> result = SettableFuture.create();
1713         LOG.debug("associateRouter {}", input);
1714         StringBuilder returnMsg = new StringBuilder();
1715         Uuid vpnId = input.getVpnId();
1716         Uuid routerId = input.getRouterId();
1717         try {
1718             VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, vpnId);
1719             Router rtr = NeutronvpnUtils.getNeutronRouter(dataBroker, routerId);
1720             if (vpnMap != null) {
1721                 if (rtr != null) {
1722                     Uuid extVpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1723                     if (vpnMap.getRouterId() != null) {
1724                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
1725                                 .append(vpnMap.getRouterId().getValue());
1726                     } else if (extVpnId != null) {
1727                         returnMsg.append("router ").append(routerId.getValue()).append(" already associated to "
1728                             + "another VPN ").append(extVpnId.getValue());
1729                     } else {
1730                         associateRouterToVpn(vpnId, routerId);
1731                     }
1732                 } else {
1733                     returnMsg.append("router not found : ").append(routerId.getValue());
1734                 }
1735             } else {
1736                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1737             }
1738             if (returnMsg.length() != 0) {
1739                 String message = String.format("associate router to vpn %s failed due to %s", routerId.getValue(),
1740                         returnMsg);
1741                 LOG.error(message);
1742                 result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value", message)
1743                         .build());
1744             } else {
1745                 result.set(RpcResultBuilder.<Void>success().build());
1746             }
1747         } catch (Exception ex) {
1748             String message = String.format("associate router %s to vpn %s failed due to %s", routerId.getValue(),
1749                     vpnId.getValue(), ex.getMessage());
1750             LOG.error(message, ex);
1751             result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION, message).build());
1752         }
1753         LOG.debug("associateRouter returns..");
1754         return result;
1755     }
1756
1757     /** It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
1758      */
1759     @Override
1760     // TODO Clean up the exception handling
1761     @SuppressWarnings("checkstyle:IllegalCatch")
1762     public Future<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
1763         GetFixedIPsForNeutronPortInput input) {
1764         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
1765         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
1766         Uuid portId = input.getPortId();
1767         StringBuilder returnMsg = new StringBuilder();
1768         try {
1769             List<String> fixedIPList = new ArrayList<>();
1770             Port port = NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1771             if (port != null) {
1772                 List<FixedIps> fixedIPs = port.getFixedIps();
1773                 for (FixedIps ip : fixedIPs) {
1774                     fixedIPList.add(String.valueOf(ip.getIpAddress().getValue()));
1775                 }
1776             } else {
1777                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
1778             }
1779             if (returnMsg.length() != 0) {
1780                 String message = String.format("Retrieval of FixedIPList for neutron port failed due to %s", returnMsg);
1781                 LOG.error(message);
1782                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed()
1783                         .withWarning(ErrorType.PROTOCOL, "invalid-value", message).build());
1784             } else {
1785                 opBuilder.setFixedIPs(fixedIPList);
1786                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().withResult(opBuilder.build())
1787                         .build());
1788                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().build());
1789             }
1790         } catch (Exception ex) {
1791             String message = String.format("Retrieval of FixedIPList for neutron port %s failed due to %s",
1792                     portId.getValue(), ex.getMessage());
1793             LOG.error(message, ex);
1794             result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed()
1795                     .withError(ErrorType.APPLICATION, message).build());
1796         }
1797         return result;
1798     }
1799
1800     /**
1801      * It handles the invocations to the neutronvpn:dissociateNetworks RPC method.
1802      */
1803     @Override
1804     // TODO Clean up the exception handling
1805     @SuppressWarnings("checkstyle:IllegalCatch")
1806     public Future<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
1807
1808         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
1809         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
1810
1811         LOG.debug("dissociateNetworks {}", input);
1812         StringBuilder returnMsg = new StringBuilder();
1813         Uuid vpnId = input.getVpnId();
1814
1815         try {
1816             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1817                 List<Uuid> netIds = input.getNetworkId();
1818                 if (netIds != null && !netIds.isEmpty()) {
1819                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
1820                     if (!failed.isEmpty()) {
1821                         returnMsg.append(failed);
1822                     }
1823                 }
1824             } else {
1825                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1826             }
1827             if (returnMsg.length() != 0) {
1828                 String message = String.format("dissociate Networks to vpn %s failed due to %s", vpnId.getValue(),
1829                         returnMsg);
1830                 LOG.error(message);
1831                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: "
1832                         + message);
1833                 opBuilder.setResponse(errorResponse);
1834                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
1835             } else {
1836                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
1837             }
1838         } catch (Exception ex) {
1839             String message = String.format("dissociate Networks to vpn %s failed due to %s",
1840                     input.getVpnId().getValue(), ex.getMessage());
1841             LOG.error(message, ex);
1842             result.set(RpcResultBuilder.<DissociateNetworksOutput>failed().withError(ErrorType.APPLICATION, message)
1843                     .build());
1844         }
1845         LOG.debug("dissociateNetworks returns..");
1846         return result;
1847     }
1848
1849     /**
1850      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
1851      */
1852     @Override
1853     // TODO Clean up the exception handling
1854     @SuppressWarnings("checkstyle:IllegalCatch")
1855     public Future<RpcResult<Void>> dissociateRouter(DissociateRouterInput input) {
1856
1857         SettableFuture<RpcResult<Void>> result = SettableFuture.create();
1858
1859         LOG.debug("dissociateRouter {}", input);
1860         StringBuilder returnMsg = new StringBuilder();
1861         Uuid vpnId = input.getVpnId();
1862         Uuid routerId = input.getRouterId();
1863         try {
1864             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1865                 if (routerId != null) {
1866                     Router rtr = NeutronvpnUtils.getNeutronRouter(dataBroker, routerId);
1867                     if (rtr != null) {
1868                         Uuid routerVpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1869                         if (vpnId.equals(routerVpnId)) {
1870                             dissociateRouterFromVpn(vpnId, routerId);
1871                         } else {
1872                             if (routerVpnId == null) {
1873                                 returnMsg.append("input router ").append(routerId.getValue())
1874                                     .append(" not associated to any vpn yet");
1875                             } else {
1876                                 returnMsg.append("input router ").append(routerId.getValue())
1877                                     .append(" associated to vpn ")
1878                                     .append(routerVpnId.getValue()).append("instead of the vpn given as input");
1879                             }
1880                         }
1881                     } else {
1882                         returnMsg.append("router not found : ").append(routerId.getValue());
1883                     }
1884                 }
1885             } else {
1886                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1887             }
1888             if (returnMsg.length() != 0) {
1889                 String message = String.format("dissociate router %s to vpn %s failed due to %s", routerId.getValue(),
1890                         vpnId.getValue(), returnMsg);
1891                 LOG.error(message);
1892                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: "
1893                         + message);
1894                 result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value", message)
1895                         .build());
1896             } else {
1897                 result.set(RpcResultBuilder.<Void>success().build());
1898             }
1899         } catch (Exception ex) {
1900             String message = String.format("disssociate router %s to vpn %s failed due to %s", routerId.getValue(),
1901                     vpnId.getValue(), ex.getMessage());
1902             LOG.error(message, ex);
1903             result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION, message).build());
1904         }
1905         LOG.debug("dissociateRouter returns..");
1906
1907         return result;
1908     }
1909
1910     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
1911         // check if the router is associated to some VPN
1912         Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1913         if (vpnId != null) {
1914             // remove existing external vpn interfaces
1915             for (Uuid subnetId : routerSubnetIds) {
1916                 removeSubnetFromVpn(vpnId, subnetId);
1917             }
1918             clearFromVpnMaps(vpnId, routerId, null);
1919         } else {
1920             // remove existing internal vpn interfaces
1921             for (Uuid subnetId : routerSubnetIds) {
1922                 removeSubnetFromVpn(routerId, subnetId);
1923             }
1924         }
1925         // delete entire vpnMaps node for internal VPN
1926         deleteVpnMapsNode(routerId);
1927
1928         // delete vpn-instance for internal VPN
1929         deleteVpnInstance(routerId);
1930     }
1931
1932     protected Subnet getNeutronSubnet(Uuid subnetId) {
1933         return NeutronvpnUtils.getNeutronSubnet(dataBroker, subnetId);
1934     }
1935
1936     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
1937         Subnet sn = NeutronvpnUtils.getNeutronSubnet(dataBroker, subnetId);
1938         if (null != sn) {
1939             return sn.getGatewayIp();
1940         }
1941         return null;
1942     }
1943
1944
1945     protected Network getNeutronNetwork(Uuid networkId) {
1946         return NeutronvpnUtils.getNeutronNetwork(dataBroker, networkId);
1947     }
1948
1949     protected Port getNeutronPort(String name) {
1950         return NeutronvpnUtils.getNeutronPort(dataBroker, new Uuid(name));
1951     }
1952
1953     protected Port getNeutronPort(Uuid portId) {
1954         return NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1955     }
1956
1957     protected Uuid getNetworkForSubnet(Uuid subnetId) {
1958         return NeutronvpnUtils.getNetworkForSubnet(dataBroker, subnetId);
1959     }
1960
1961     protected List<Uuid> getNetworksForVpn(Uuid vpnId) {
1962         return NeutronvpnUtils.getNetworksforVpn(dataBroker, vpnId);
1963     }
1964
1965     /**
1966      * Implementation of the "vpnservice:neutron-ports-show" Karaf CLI command.
1967      *
1968      * @return a List of String to be printed on screen
1969      */
1970     // TODO Clean up the exception handling and the console output
1971     @SuppressWarnings({"checkstyle:IllegalCatch", "checkstyle:RegexpSinglelineJava"})
1972     public List<String> showNeutronPortsCLI() {
1973         List<String> result = new ArrayList<>();
1974         result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", "Port ID", "Mac Address", "Prefix Length",
1975             "IP Address"));
1976         result.add("-------------------------------------------------------------------------------------------");
1977         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
1978         try {
1979             Optional<Ports> ports =
1980                 NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
1981             if (ports.isPresent() && ports.get().getPort() != null) {
1982                 for (Port port : ports.get().getPort()) {
1983                     List<FixedIps> fixedIPs = port.getFixedIps();
1984                     try {
1985                         if (fixedIPs != null && !fixedIPs.isEmpty()) {
1986                             List<String> ipList = new ArrayList<>();
1987                             for (FixedIps fixedIp : fixedIPs) {
1988                                 IpAddress ipAddress = fixedIp.getIpAddress();
1989                                 if (ipAddress.getIpv4Address() != null) {
1990                                     ipList.add(ipAddress.getIpv4Address().getValue());
1991                                 } else {
1992                                     ipList.add((ipAddress.getIpv6Address().getValue()));
1993                                 }
1994                             }
1995                             result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
1996                                     .getMacAddress().getValue(), NeutronvpnUtils.getIPPrefixFromPort(dataBroker, port),
1997                                     ipList.toString()));
1998                         } else {
1999                             result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
2000                                     .getMacAddress().getValue(), "Not Assigned", "Not " + "Assigned"));
2001                         }
2002                     } catch (Exception e) {
2003                         LOG.error("Failed to retrieve neutronPorts info for port {}: ", port.getUuid().getValue(),
2004                                 e);
2005                         System.out.println("Failed to retrieve neutronPorts info for port: " + port.getUuid()
2006                                 .getValue() + ": " + e.getMessage());
2007                     }
2008                 }
2009             }
2010         } catch (Exception e) {
2011             LOG.error("Failed to retrieve neutronPorts info : ", e);
2012             System.out.println("Failed to retrieve neutronPorts info : " + e.getMessage());
2013         }
2014         return result;
2015     }
2016
2017     /**
2018      * Implementation of the "vpnservice:l3vpn-config-show" karaf CLI command.
2019      *
2020      * @param vpnuuid Uuid of the VPN whose config must be shown
2021      * @return formatted output list
2022      */
2023     @SuppressWarnings("checkstyle:RegexpSinglelineJava")
2024     public List<String> showVpnConfigCLI(Uuid vpnuuid) {
2025         List<String> result = new ArrayList<>();
2026         if (vpnuuid == null) {
2027             System.out.println("");
2028             System.out.println("Displaying VPN config for all VPNs");
2029             System.out.println("To display VPN config for a particular VPN, use the following syntax");
2030             System.out.println(getshowVpnConfigCLIHelp());
2031         }
2032         try {
2033             RpcResult<GetL3VPNOutput> rpcResult = getL3VPN(new GetL3VPNInputBuilder().setId(vpnuuid).build()).get();
2034             if (rpcResult.isSuccessful()) {
2035                 result.add("");
2036                 result.add(String.format(" %-37s %-37s %-7s ", "VPN ID", "Tenant ID", "RD"));
2037                 result.add("");
2038                 result.add(String.format(" %-80s ", "Import-RTs"));
2039                 result.add("");
2040                 result.add(String.format(" %-80s ", "Export-RTs"));
2041                 result.add("");
2042                 result.add(String.format(" %-76s ", "Subnet IDs"));
2043                 result.add("");
2044                 result.add("------------------------------------------------------------------------------------");
2045                 result.add("");
2046                 List<L3vpnInstances> vpnList = rpcResult.getResult().getL3vpnInstances();
2047                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
2048                             .rev150602.VpnInstance vpn : vpnList) {
2049                     String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
2050                             : "\"                 " + "                  \"";
2051                     result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
2052                             vpn.getRouteDistinguisher()));
2053                     result.add("");
2054                     result.add(String.format(" %-80s ", vpn.getImportRT()));
2055                     result.add("");
2056                     result.add(String.format(" %-80s ", vpn.getExportRT()));
2057                     result.add("");
2058
2059                     Uuid vpnid = vpn.getId();
2060                     List<Uuid> subnetList = NeutronvpnUtils.getSubnetsforVpn(dataBroker, vpnid);
2061                     if (!subnetList.isEmpty()) {
2062                         for (Uuid subnetuuid : subnetList) {
2063                             result.add(String.format(" %-76s ", subnetuuid.getValue()));
2064                         }
2065                     } else {
2066                         result.add(String.format(" %-76s ", "\"                                    \""));
2067                     }
2068                     result.add("");
2069                     result.add("----------------------------------------");
2070                     result.add("");
2071                 }
2072             } else {
2073                 String errortag = rpcResult.getErrors().iterator().next().getTag();
2074                 if (errortag == "") {
2075                     System.out.println("");
2076                     System.out.println("No VPN has been configured yet");
2077                 } else if (errortag == "invalid-value") {
2078                     System.out.println("");
2079                     System.out.println("VPN " + vpnuuid.getValue() + " is not present");
2080                 } else {
2081                     System.out.println("error getting VPN info : " + rpcResult.getErrors());
2082                     System.out.println(getshowVpnConfigCLIHelp());
2083                 }
2084             }
2085         } catch (InterruptedException | ExecutionException e) {
2086             LOG.error("error getting VPN info : ", e);
2087             System.out.println("error getting VPN info : " + e.getMessage());
2088         }
2089         return result;
2090     }
2091
2092     protected void createExternalVpnInterfaces(Uuid extNetId) {
2093         if (extNetId == null) {
2094             LOG.trace("external network is null");
2095             return;
2096         }
2097
2098         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
2099         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
2100             LOG.trace("No external ports attached to external network {}", extNetId.getValue());
2101             return;
2102         }
2103
2104         WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2105         for (String elanInterface : extElanInterfaces) {
2106             createExternalVpnInterface(extNetId, elanInterface, wrtConfigTxn);
2107         }
2108         wrtConfigTxn.submit();
2109     }
2110
2111     // TODO Clean up the exception handling
2112     @SuppressWarnings("checkstyle:IllegalCatch")
2113     protected void removeExternalVpnInterfaces(Uuid extNetId) {
2114         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
2115         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
2116             LOG.trace("No external ports attached for external network {}", extNetId);
2117             return;
2118         }
2119         try {
2120
2121             WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2122             for (String elanInterface : extElanInterfaces) {
2123                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
2124                         .buildVpnInterfaceIdentifier(elanInterface);
2125                 LOG.info("Removing vpn interface {}", elanInterface);
2126                 wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
2127             }
2128             wrtConfigTxn.submit();
2129
2130         } catch (Exception ex) {
2131             LOG.error("Removal of vpninterfaces {} failed due to {}", extElanInterfaces, ex);
2132         }
2133     }
2134
2135     private void createExternalVpnInterface(Uuid vpnId, String infName, WriteTransaction wrtConfigTxn) {
2136         writeVpnInterfaceToDs(vpnId, infName, null, false /* not a router iface */, wrtConfigTxn);
2137     }
2138
2139     // TODO Clean up the exception handling
2140     @SuppressWarnings("checkstyle:IllegalCatch")
2141     private void writeVpnInterfaceToDs(Uuid vpnId, String infName, Adjacencies adjacencies,
2142             Boolean isRouterInterface, WriteTransaction wrtConfigTxn) {
2143         if (vpnId == null || infName == null) {
2144             LOG.debug("vpn id or interface is null");
2145             return;
2146         }
2147
2148         Boolean wrtConfigTxnPresent = true;
2149         if (wrtConfigTxn == null) {
2150             wrtConfigTxnPresent = false;
2151             wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2152         }
2153
2154         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
2155         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
2156                 .setName(infName)
2157                 .setVpnInstanceName(vpnId.getValue())
2158                 .setIsRouterInterface(isRouterInterface);
2159         if (adjacencies != null) {
2160             vpnb.addAugmentation(Adjacencies.class, adjacencies);
2161         }
2162         VpnInterface vpnIf = vpnb.build();
2163         try {
2164             LOG.info("Creating vpn interface {}", vpnIf);
2165             wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
2166         } catch (Exception ex) {
2167             LOG.error("Creation of vpninterface {} failed due to {}", infName, ex);
2168         }
2169
2170         if (!wrtConfigTxnPresent) {
2171             wrtConfigTxn.submit();
2172         }
2173     }
2174
2175     private String getshowVpnConfigCLIHelp() {
2176         StringBuilder help = new StringBuilder("Usage:");
2177         help.append("display vpn-config [-vid/--vpnid <id>]");
2178         return help.toString();
2179     }
2180
2181     private void checkAndPublishRouterAssociatedtoVpnNotification(Uuid routerId, Uuid vpnId) throws
2182             InterruptedException {
2183         RouterAssociatedToVpn routerAssociatedToVpn = new RouterAssociatedToVpnBuilder().setRouterId(routerId)
2184                 .setVpnId(vpnId).build();
2185         LOG.info("publishing notification upon association of router to VPN");
2186         notificationPublishService.putNotification(routerAssociatedToVpn);
2187     }
2188
2189     private void checkAndPublishRouterDisassociatedFromVpnNotification(Uuid routerId, Uuid vpnId) throws
2190             InterruptedException {
2191         RouterDisassociatedFromVpn routerDisassociatedFromVpn =
2192             new RouterDisassociatedFromVpnBuilder().setRouterId(routerId).setVpnId(vpnId).build();
2193         LOG.info("publishing notification upon disassociation of router from VPN");
2194         notificationPublishService.putNotification(routerDisassociatedFromVpn);
2195     }
2196
2197     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
2198         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
2199     }
2200 }