Bug 7700: create-l3vpn (REST/CLI) should not allow another VPN to use the same VPNID
[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.L3vpnInstance;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpnBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpnBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.createl3vpn.input.L3vpn;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstances;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstancesBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInput;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInputBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
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
183                 builder.setRouterId(routerId);
184                 builder.setRouterInterfaceName(routerInterfaceName);
185                 builder.setRouterIntfMacAddress(routerIntfMacAddress);
186
187                 if (fixedIp != null) {
188                     List<String> fixedIps = builder.getRouterInterfaceFixedIps();
189                     if (fixedIps == null) {
190                         fixedIps = new ArrayList<>();
191                     }
192                     fixedIps.add(fixedIp);
193                     builder.setRouterInterfaceFixedIps(fixedIps);
194                 } else {
195                     builder.setRouterInterfaceFixedIps(null);
196                 }
197                 subnetmap = builder.build();
198                 LOG.debug("WithRouterFixedIPs Creating/Updating subnetMap node for Router FixedIps: {} ",
199                     subnetId.getValue());
200                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
201             }
202         } catch (Exception e) {
203             LOG.error("WithRouterFixedIPs: Updation of subnetMap for Router FixedIps failed for node: {}",
204                 subnetId.getValue());
205         }
206     }
207
208     // TODO Clean up the exception handling
209     @SuppressWarnings("checkstyle:IllegalCatch")
210     protected Subnetmap updateSubnetNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId, Uuid routerId,
211                                          Uuid vpnId) {
212         Subnetmap subnetmap = null;
213         SubnetmapBuilder builder = null;
214         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
215                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
216                 .build();
217         try {
218             synchronized (subnetId.getValue().intern()) {
219                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
220                 if (sn.isPresent()) {
221                     builder = new SubnetmapBuilder(sn.get());
222                     LOG.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
223                 } else {
224                     builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
225                     LOG.debug("creating new subnetmap node for subnet ID {}", subnetId.getValue());
226                 }
227
228                 if (subnetIp != null) {
229                     builder.setSubnetIp(subnetIp);
230                 }
231                 if (routerId != null) {
232                     builder.setRouterId(routerId);
233                 }
234                 if (networkId != null) {
235                     builder.setNetworkId(networkId);
236                 }
237                 if (vpnId != null) {
238                     builder.setVpnId(vpnId);
239                 }
240                 if (tenantId != null) {
241                     builder.setTenantId(tenantId);
242                 }
243
244                 subnetmap = builder.build();
245                 LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
246                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
247             }
248         } catch (Exception e) {
249             LOG.error("Updation of subnetMap failed for node: {}", subnetId.getValue());
250         }
251         return subnetmap;
252     }
253
254     // TODO Clean up the exception handling
255     @SuppressWarnings("checkstyle:IllegalCatch")
256     protected Subnetmap removeFromSubnetNode(Uuid subnetId, Uuid networkId, Uuid routerId, Uuid vpnId, Uuid portId) {
257         Subnetmap subnetmap = null;
258         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
259                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
260                 .build();
261         try {
262             synchronized (subnetId.getValue().intern()) {
263                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
264                 if (sn.isPresent()) {
265                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
266                     if (routerId != null) {
267                         builder.setRouterId(null);
268                     }
269                     if (networkId != null) {
270                         builder.setNetworkId(null);
271                     }
272                     if (vpnId != null) {
273                         builder.setVpnId(null);
274                     }
275                     if (portId != null && builder.getPortList() != null) {
276                         List<Uuid> portList = builder.getPortList();
277                         portList.remove(portId);
278                         builder.setPortList(portList);
279                     }
280
281                     subnetmap = builder.build();
282                     LOG.debug("Removing from existing subnetmap node: {} ", subnetId.getValue());
283                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
284                 } else {
285                     LOG.warn("removing from non-existing subnetmap node: {} ", subnetId.getValue());
286                 }
287             }
288         } catch (Exception e) {
289             LOG.error("Removal from subnetmap failed for node: {}", subnetId.getValue());
290         }
291         return subnetmap;
292     }
293
294     // TODO Clean up the exception handling
295     @SuppressWarnings("checkstyle:IllegalCatch")
296     protected Subnetmap updateSubnetmapNodeWithPorts(Uuid subnetId, Uuid portId, Uuid directPortId) {
297         Subnetmap subnetmap = null;
298         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
299                 new SubnetmapKey(subnetId)).build();
300         try {
301             synchronized (subnetId.getValue().intern()) {
302                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
303                 if (sn.isPresent()) {
304                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
305                     if (null != portId) {
306                         List<Uuid> portList = builder.getPortList();
307                         if (null == portList) {
308                             portList = new ArrayList<>();
309                         }
310                         portList.add(portId);
311                         builder.setPortList(portList);
312                         LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
313                                 portId.getValue());
314                     }
315                     if (null != directPortId) {
316                         List<Uuid> directPortList = builder.getDirectPortList();
317                         if (null == directPortList) {
318                             directPortList = new ArrayList<>();
319                         }
320                         directPortList.add(directPortId);
321                         builder.setDirectPortList(directPortList);
322                         LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
323                                 directPortId.getValue());
324                     }
325                     subnetmap = builder.build();
326                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
327                 } else {
328                     LOG.error("Trying to update non-existing subnetmap node {} ", subnetId.getValue());
329                 }
330             }
331         } catch (Exception e) {
332             LOG.error("Updating port list of a given subnetMap failed for node: {} with exception{}",
333                     subnetId.getValue(), e);
334         }
335         return subnetmap;
336     }
337
338     // TODO Clean up the exception handling
339     @SuppressWarnings("checkstyle:IllegalCatch")
340     protected Subnetmap removePortsFromSubnetmapNode(Uuid subnetId, Uuid portId, Uuid directPortId) {
341         Subnetmap subnetmap = null;
342         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
343                 new SubnetmapKey(subnetId)).build();
344         try {
345             synchronized (subnetId.getValue().intern()) {
346                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
347                 if (sn.isPresent()) {
348                     SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
349                     if (null != portId && null != builder.getPortList()) {
350                         List<Uuid> portList = builder.getPortList();
351                         portList.remove(portId);
352                         builder.setPortList(portList);
353                         LOG.debug("Removing port {} from existing subnetmap node: {} ", portId.getValue(),
354                                 subnetId.getValue());
355                     }
356                     if (null != directPortId && null != builder.getDirectPortList()) {
357                         List<Uuid> directPortList = builder.getDirectPortList();
358                         directPortList.remove(directPortId);
359                         builder.setDirectPortList(directPortList);
360                         LOG.debug("Removing direct port {} from existing subnetmap node: {} ", directPortId
361                                 .getValue(), subnetId.getValue());
362                     }
363                     subnetmap = builder.build();
364                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
365                 } else {
366                     LOG.error("Trying to remove port from non-existing subnetmap node {}", subnetId.getValue());
367                 }
368             }
369         } catch (Exception e) {
370             LOG.error("Removing a port from port list of a subnetmap failed for node: {} with expection {}",
371                     subnetId.getValue(), e);
372         }
373         return subnetmap;
374     }
375
376     // TODO Clean up the exception handling
377     @SuppressWarnings("checkstyle:IllegalCatch")
378     protected void deleteSubnetMapNode(Uuid subnetId) {
379         InstanceIdentifier<Subnetmap> subnetMapIdentifier =
380                 InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,new SubnetmapKey(subnetId)).build();
381         LOG.debug("removing subnetMap node: {} ", subnetId.getValue());
382         try {
383             synchronized (subnetId.getValue().intern()) {
384                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
385             }
386         } catch (Exception e) {
387             LOG.error("Delete subnetMap node failed for subnet : {} ", subnetId.getValue());
388         }
389     }
390
391     // TODO Clean up the exception handling
392     @SuppressWarnings("checkstyle:IllegalCatch")
393     private void updateVpnInstanceNode(String vpnName, List<String> rd, List<String> irt, List<String> ert) {
394
395         VpnInstanceBuilder builder = null;
396         List<VpnTarget> vpnTargetList = new ArrayList<>();
397         boolean isLockAcquired = false;
398         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
399             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
400         try {
401             Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
402                     vpnIdentifier);
403             LOG.debug("Creating/Updating a new vpn-instance node: {} ", vpnName);
404             if (optionalVpn.isPresent()) {
405                 builder = new VpnInstanceBuilder(optionalVpn.get());
406                 LOG.debug("updating existing vpninstance node");
407             } else {
408                 builder = new VpnInstanceBuilder().setKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName);
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);
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      * @throws Exception if association of L3VPN failed
793      */
794     public void createL3Vpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt, List<String> ert,
795                             Uuid router, List<Uuid> networks) throws Exception {
796
797         // Update VPN Instance node
798         updateVpnInstanceNode(vpn.getValue(), rd, irt, ert);
799
800         // Please note that router and networks will be filled into VPNMaps
801         // by subsequent calls here to associateRouterToVpn and
802         // associateNetworksToVpn
803         updateVpnMaps(vpn, name, null, tenant, null);
804
805         if (router != null) {
806             associateRouterToVpn(vpn, router);
807         }
808         if (networks != null) {
809             List<String> failStrings = associateNetworksToVpn(vpn, networks);
810             if (failStrings != null &&  !failStrings.isEmpty()) {
811                 LOG.error("L3VPN {} association to networks failed with error message {}. ",
812                         vpn.getValue(), failStrings.get(0));
813                 throw new Exception(failStrings.get(0));
814             }
815         }
816     }
817
818     /**
819      * It handles the invocations to the createL3VPN RPC method.
820      */
821     @Override
822     // TODO Clean up the exception handling
823     @SuppressWarnings("checkstyle:IllegalCatch")
824     public Future<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
825
826         CreateL3VPNOutputBuilder opBuilder = new CreateL3VPNOutputBuilder();
827         SettableFuture<RpcResult<CreateL3VPNOutput>> result = SettableFuture.create();
828         List<RpcError> errorList = new ArrayList<>();
829         int failurecount = 0;
830         int warningcount = 0;
831
832         List<L3vpn> vpns = input.getL3vpn();
833         for (L3vpn vpn : vpns) {
834             RpcError error = null;
835             String msg;
836             if (NeutronvpnUtils.doesVpnExist(dataBroker, vpn.getId())) {
837                 msg = String.format("Creation of L3VPN failed for VPN %s due to VPN with the same ID already present",
838                                 vpn.getId().getValue());
839                 LOG.warn(msg);
840                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
841                 errorList.add(error);
842                 warningcount++;
843                 continue;
844             }
845             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
846                 msg = String.format("Creation of L3VPN failed for VPN %s due to absence of RD/iRT/eRT input",
847                         vpn.getId().getValue());
848                 LOG.warn(msg);
849                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
850                 errorList.add(error);
851                 warningcount++;
852                 continue;
853             }
854             if (vpn.getRouteDistinguisher().size() > 1) {
855                 msg = String.format("Creation of L3VPN failed for VPN %s due to multiple RD input %s",
856                         vpn.getId().getValue(), vpn.getRouteDistinguisher());
857                 LOG.warn(msg);
858                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
859                 errorList.add(error);
860                 warningcount++;
861                 continue;
862             }
863             List<String> existingRDs = NeutronvpnUtils.getExistingRDs(dataBroker);
864             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
865                 msg = String.format("Creation of L3VPN failed for VPN %s as another VPN with the same RD %s "
866                     + "is already configured",
867                     vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0));
868                 LOG.warn(msg);
869                 error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
870                 errorList.add(error);
871                 warningcount++;
872                 continue;
873             }
874             if (vpn.getRouterId() != null) {
875                 if (NeutronvpnUtils.getNeutronRouter(dataBroker, vpn.getRouterId()) == null) {
876                     msg = String.format("Creation of L3VPN failed for VPN %s due to router not found %s",
877                             vpn.getId().getValue(), vpn.getRouterId().getValue());
878                     LOG.warn(msg);
879                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
880                     errorList.add(error);
881                     warningcount++;
882                     continue;
883                 }
884                 Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, vpn.getRouterId(), true);
885                 if (vpnId != null) {
886                     msg = String.format("Creation of L3VPN failed for VPN %s due to router %s already associated to "
887                                     + "another VPN %s", vpn.getId().getValue(), vpn.getRouterId().getValue(),
888                             vpnId.getValue());
889                     LOG.warn(msg);
890                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
891                     errorList.add(error);
892                     warningcount++;
893                     continue;
894                 }
895             }
896             if (vpn.getNetworkIds() != null) {
897                 for (Uuid nw : vpn.getNetworkIds()) {
898                     Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
899                     Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
900                     if (network == null) {
901                         msg = String.format("Creation of L3VPN failed for VPN %s due to network not found %s",
902                                 vpn.getId().getValue(), nw.getValue());
903                         LOG.warn(msg);
904                         error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
905                         errorList.add(error);
906                         warningcount++;
907                     } else if (vpnId != null) {
908                         msg = String.format("Creation of L3VPN failed for VPN %s due to network %s already associated"
909                                         + " to another VPN %s", vpn.getId().getValue(), nw.getValue(),
910                                 vpnId.getValue());
911                         LOG.warn(msg);
912                         error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
913                         errorList.add(error);
914                         warningcount++;
915                     }
916                 }
917                 if (error != null) {
918                     continue;
919                 }
920             }
921             try {
922                 createL3Vpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), vpn.getRouteDistinguisher(),
923                         vpn.getImportRT(), vpn.getExportRT(), vpn.getRouterId(), vpn.getNetworkIds());
924             } catch (Exception ex) {
925                 msg = String.format("Creation of L3VPN failed for VPN %s", vpn.getId().getValue());
926                 LOG.error(msg, ex);
927                 error = RpcResultBuilder.newError(ErrorType.APPLICATION, msg, ex.getMessage());
928                 errorList.add(error);
929                 failurecount++;
930             }
931         }
932         // if at least one succeeds; result is success
933         // if none succeeds; result is failure
934         if (failurecount + warningcount == vpns.size()) {
935             result.set(RpcResultBuilder.<CreateL3VPNOutput>failed().withRpcErrors(errorList).build());
936         } else {
937             List<String> errorResponseList = new ArrayList<>();
938             if (!errorList.isEmpty()) {
939                 for (RpcError rpcError : errorList) {
940                     String errorResponse = String.format("ErrorType: %s, ErrorTag: %s, ErrorMessage: %s", rpcError
941                             .getErrorType(), rpcError.getTag(), rpcError.getMessage());
942                     errorResponseList.add(errorResponse);
943                 }
944             } else {
945                 errorResponseList.add("Operation successful with no errors");
946             }
947             opBuilder.setResponse(errorResponseList);
948             result.set(RpcResultBuilder.<CreateL3VPNOutput>success().withResult(opBuilder.build()).build());
949         }
950         return result;
951     }
952
953     /**
954      * It handles the invocations to the neutronvpn:getL3VPN RPC method.
955      */
956     @Override
957     // TODO Clean up the exception handling
958     @SuppressWarnings("checkstyle:IllegalCatch")
959     public Future<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
960
961         GetL3VPNOutputBuilder opBuilder = new GetL3VPNOutputBuilder();
962         SettableFuture<RpcResult<GetL3VPNOutput>> result = SettableFuture.create();
963         Uuid inputVpnId = input.getId();
964         List<VpnInstance> vpns = new ArrayList<>();
965
966         try {
967             if (inputVpnId == null) {
968                 // get all vpns
969                 InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class)
970                         .build();
971                 Optional<VpnInstances> optionalVpns = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
972                         .CONFIGURATION, vpnsIdentifier);
973                 if (optionalVpns.isPresent() && !optionalVpns.get().getVpnInstance().isEmpty()) {
974                     for (VpnInstance vpn : optionalVpns.get().getVpnInstance()) {
975                         // eliminating implicitly created (router and VLAN provider external network specific) VPNs
976                         // from getL3VPN output
977                         if (vpn.getIpv4Family().getRouteDistinguisher() != null) {
978                             vpns.add(vpn);
979                         }
980                     }
981                 } else {
982                     // No VPN present
983                     result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
984                     return result;
985                 }
986             } else {
987                 String name = inputVpnId.getValue();
988                 InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
989                         .child(VpnInstance.class, new VpnInstanceKey(name)).build();
990                 // read VpnInstance Info
991                 Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
992                         vpnIdentifier);
993                 // eliminating implicitly created (router or VLAN provider external network specific) VPN from
994                 // getL3VPN output
995                 if (optionalVpn.isPresent() && optionalVpn.get().getIpv4Family().getRouteDistinguisher() != null) {
996                     vpns.add(optionalVpn.get());
997                 } else {
998                     String message = String.format("GetL3VPN failed because VPN %s is not present", name);
999                     LOG.error(message);
1000                     result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withWarning(ErrorType.PROTOCOL,
1001                             "invalid-value", message).build());
1002                 }
1003             }
1004             List<L3vpnInstances> l3vpnList = new ArrayList<>();
1005             for (VpnInstance vpnInstance : vpns) {
1006                 Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
1007                 // create VpnMaps id
1008                 InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
1009                         .class, new VpnMapKey(vpnId)).build();
1010                 L3vpnInstancesBuilder l3vpn = new L3vpnInstancesBuilder();
1011
1012                 List<String> rd = Arrays.asList(vpnInstance.getIpv4Family().getRouteDistinguisher().split(","));
1013                 List<VpnTarget> vpnTargetList = vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget();
1014
1015                 List<String> ertList = new ArrayList<>();
1016                 List<String> irtList = new ArrayList<>();
1017
1018                 for (VpnTarget vpnTarget : vpnTargetList) {
1019                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
1020                         ertList.add(vpnTarget.getVrfRTValue());
1021                     }
1022                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
1023                         irtList.add(vpnTarget.getVrfRTValue());
1024                     }
1025                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
1026                         ertList.add(vpnTarget.getVrfRTValue());
1027                         irtList.add(vpnTarget.getVrfRTValue());
1028                     }
1029                 }
1030
1031                 l3vpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
1032                 Optional<VpnMap> optionalVpnMap = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1033                         vpnMapIdentifier);
1034                 if (optionalVpnMap.isPresent()) {
1035                     VpnMap vpnMap = optionalVpnMap.get();
1036                     l3vpn.setRouterId(vpnMap.getRouterId()).setNetworkIds(vpnMap.getNetworkIds())
1037                             .setTenantId(vpnMap.getTenantId()).setName(vpnMap.getName());
1038                 }
1039                 l3vpnList.add(l3vpn.build());
1040             }
1041
1042             opBuilder.setL3vpnInstances(l3vpnList);
1043             result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1044
1045         } catch (Exception ex) {
1046             String message = String.format("GetL3VPN failed due to %s", ex.getMessage());
1047             LOG.error(message, ex);
1048             result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withError(ErrorType.APPLICATION, message).build());
1049         }
1050         return result;
1051     }
1052
1053     /**
1054      * It handles the invocations to the neutronvpn:deleteL3VPN RPC method.
1055      */
1056     @Override
1057     // TODO Clean up the exception handling
1058     @SuppressWarnings("checkstyle:IllegalCatch")
1059     public Future<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
1060
1061         DeleteL3VPNOutputBuilder opBuilder = new DeleteL3VPNOutputBuilder();
1062         SettableFuture<RpcResult<DeleteL3VPNOutput>> result = SettableFuture.create();
1063         List<RpcError> errorList = new ArrayList<>();
1064
1065         int failurecount = 0;
1066         int warningcount = 0;
1067         List<Uuid> vpns = input.getId();
1068         for (Uuid vpn : vpns) {
1069             RpcError error;
1070             String msg;
1071             try {
1072                 InstanceIdentifier<VpnInstance> vpnIdentifier =
1073                         InstanceIdentifier.builder(VpnInstances.class)
1074                             .child(VpnInstance.class, new VpnInstanceKey(vpn.getValue())).build();
1075                 Optional<VpnInstance> optionalVpn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1076                         .CONFIGURATION, vpnIdentifier);
1077                 if (optionalVpn.isPresent()) {
1078                     removeL3Vpn(vpn);
1079                 } else {
1080                     msg = String.format("VPN with vpnid: %s does not exist", vpn.getValue());
1081                     LOG.warn(msg);
1082                     error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-value", msg);
1083                     errorList.add(error);
1084                     warningcount++;
1085                 }
1086             } catch (Exception ex) {
1087                 msg = String.format("Deletion of L3VPN failed when deleting for uuid %s", vpn.getValue());
1088                 LOG.error(msg, ex);
1089                 error = RpcResultBuilder.newError(ErrorType.APPLICATION, msg, ex.getMessage());
1090                 errorList.add(error);
1091                 failurecount++;
1092             }
1093         }
1094         // if at least one succeeds; result is success
1095         // if none succeeds; result is failure
1096         if (failurecount + warningcount == vpns.size()) {
1097             result.set(RpcResultBuilder.<DeleteL3VPNOutput>failed().withRpcErrors(errorList).build());
1098         } else {
1099             List<String> errorResponseList = new ArrayList<>();
1100             if (!errorList.isEmpty()) {
1101                 for (RpcError rpcError : errorList) {
1102                     String errorResponse = String.format("ErrorType: %s, ErrorTag: %s, ErrorMessage: %s", rpcError
1103                             .getErrorType(), rpcError.getTag(), rpcError.getMessage());
1104                     errorResponseList.add(errorResponse);
1105                 }
1106             } else {
1107                 errorResponseList.add("Operation successful with no errors");
1108             }
1109             opBuilder.setResponse(errorResponseList);
1110             result.set(RpcResultBuilder.<DeleteL3VPNOutput>success().withResult(opBuilder.build()).build());
1111         }
1112         return result;
1113     }
1114
1115     protected void addSubnetToVpn(final Uuid vpnId, Uuid subnet) {
1116         LOG.debug("Adding subnet {} to vpn {}", subnet.getValue(), vpnId.getValue());
1117         Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId);
1118         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
1119         // Check if there are ports on this subnet and add corresponding
1120         // vpn-interfaces
1121         List<Uuid> portList = sn.getPortList();
1122         if (portList != null) {
1123             for (final Uuid portId : sn.getPortList()) {
1124                 LOG.debug("adding vpn-interface for port {}", portId.getValue());
1125                 final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1126                 portDataStoreCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1127                     WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
1128                     List<ListenableFuture<Void>> futures = new ArrayList<>();
1129                     createVpnInterface(vpnId, routerId, NeutronvpnUtils.getNeutronPort(dataBroker, portId),
1130                             wrtConfigTxn);
1131                     futures.add(wrtConfigTxn.submit());
1132                     return futures;
1133                 });
1134             }
1135         }
1136     }
1137
1138     protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet, boolean isBeingAssociated) {
1139         LOG.debug("Updating VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
1140         // Read the subnet first to see if its already associated to a VPN
1141         Uuid oldVpnId = null;
1142         InstanceIdentifier<Subnetmap> snId = InstanceIdentifier.builder(Subnetmaps.class)
1143             .child(Subnetmap.class, new SubnetmapKey(subnet)).build();
1144         Subnetmap sn = null;
1145         Optional<Subnetmap> optSn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, snId);
1146         if (optSn.isPresent()) {
1147             sn = optSn.get();
1148             oldVpnId = sn.getVpnId();
1149             List<String> ips = sn.getRouterInterfaceFixedIps();
1150             for (String ipValue : ips) {
1151                 // Update the association of router-interface to external vpn
1152                 String portName =
1153                     NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, oldVpnId.getValue(), ipValue);
1154                 if (portName != null) {
1155                     updateVpnInterface(vpnId, oldVpnId,
1156                         NeutronvpnUtils.getNeutronPort(dataBroker, new Uuid(portName)),
1157                         isBeingAssociated, true);
1158                 }
1159             }
1160         }
1161         sn = updateSubnetNode(subnet, null, null, null, null, vpnId);
1162         // Check for ports on this subnet and update association of
1163         // corresponding vpn-interfaces to external vpn
1164         List<Uuid> portList = sn.getPortList();
1165         if (portList != null) {
1166             for (Uuid port : sn.getPortList()) {
1167                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1168                     port.getValue(), isBeingAssociated);
1169                 updateVpnInterface(vpnId, oldVpnId, NeutronvpnUtils.getNeutronPort(dataBroker, port),
1170                         isBeingAssociated, false);
1171             }
1172         }
1173     }
1174
1175     public InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
1176         return InstanceIdentifier.builder(RouterInterfacesMap.class)
1177                 .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
1178     }
1179
1180     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1181         synchronized (routerId.getValue().intern()) {
1182             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1183             Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1184                     .CONFIGURATION, routerInterfacesId);
1185             Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
1186                 .setInterfaceId(interfaceName).build();
1187             if (optRouterInterfaces.isPresent()) {
1188                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces
1189                         .class, new InterfacesKey(interfaceName)), routerInterface);
1190             } else {
1191                 RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
1192                 List<Interfaces> interfaces = new ArrayList<>();
1193                 interfaces.add(routerInterface);
1194                 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId.child(Interfaces
1195                         .class, new InterfacesKey(interfaceName)), routerInterface);
1196             }
1197         }
1198     }
1199
1200     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1201         synchronized (routerId.getValue().intern()) {
1202             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1203             Optional<RouterInterfaces> optRouterInterfaces = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
1204                     .CONFIGURATION, routerInterfacesId);
1205             Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
1206                 .setInterfaceId(interfaceName).build();
1207             if (optRouterInterfaces.isPresent()) {
1208                 RouterInterfaces routerInterfaces = optRouterInterfaces.get();
1209                 List<Interfaces> interfaces = routerInterfaces.getInterfaces();
1210                 if (interfaces != null && interfaces.remove(routerInterface)) {
1211                     if (interfaces.isEmpty()) {
1212                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInterfacesId);
1213                     } else {
1214                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1215                                 routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
1216                     }
1217                 }
1218             }
1219         }
1220     }
1221
1222     /**
1223      * Creates the corresponding static routes in the specified VPN. These static routes must be point to an
1224      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink. Otherwise the
1225      * route will be ignored.
1226      *
1227      * @param vpnName the VPN identifier
1228      * @param interVpnLinkRoutes The list of static routes
1229      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1230      */
1231     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1232                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1233         for ( Routes route : interVpnLinkRoutes ) {
1234             String nexthop = String.valueOf(route.getNexthop().getValue());
1235             String destination = String.valueOf(route.getDestination().getValue());
1236             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1237             if ( isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink) ) {
1238                 AddStaticRouteInput rpcInput =
1239                         new AddStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1240                                 .setVpnInstanceName(vpnName.getValue())
1241                                 .build();
1242                 Future<RpcResult<AddStaticRouteOutput>> labelOuputFtr = vpnRpcService.addStaticRoute(rpcInput);
1243                 RpcResult<AddStaticRouteOutput> rpcResult;
1244                 try {
1245                     rpcResult = labelOuputFtr.get();
1246                     if ( rpcResult.isSuccessful() ) {
1247                         LOG.debug("Label generated for destination {} is: {}",
1248                                 destination, rpcResult.getResult().getLabel());
1249                     } else {
1250                         LOG.warn("RPC call to add a static Route to {} with nexthop {} returned with errors {}",
1251                                 destination, nexthop, rpcResult.getErrors());
1252                     }
1253                 } catch (InterruptedException | ExecutionException e) {
1254                     LOG.warn("Error happened while invoking addStaticRoute RPC: ", e);
1255                 }
1256             } else {
1257                 // Any other case is a fault.
1258                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1259                         String.valueOf(route.getDestination().getValue()), nexthop );
1260                 continue;
1261             }
1262         }
1263     }
1264
1265     /**
1266      * Removes the corresponding static routes from the specified VPN. These static routes point to an
1267      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink.
1268      *
1269      * @param vpnName the VPN identifier
1270      * @param interVpnLinkRoutes The list of static routes
1271      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1272      */
1273     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1274                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1275         for ( Routes route : interVpnLinkRoutes ) {
1276             String nexthop = String.valueOf(route.getNexthop().getValue());
1277             String destination = String.valueOf(route.getDestination().getValue());
1278             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1279             if ( isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink) ) {
1280                 RemoveStaticRouteInput rpcInput =
1281                         new RemoveStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1282                                 .setVpnInstanceName(vpnName.getValue())
1283                                 .build();
1284                 vpnRpcService.removeStaticRoute(rpcInput);
1285             } else {
1286                 // Any other case is a fault.
1287                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1288                         String.valueOf(route.getDestination().getValue()), nexthop );
1289                 continue;
1290             }
1291         }
1292     }
1293
1294     /*
1295      * Returns true if the specified nexthop is the other endpoint in an
1296      * InterVpnLink, regarding one of the VPN's point of view.
1297      */
1298     private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
1299         return
1300                 interVpnLink != null
1301                         && (   (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
1302                         && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
1303                         || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
1304                         && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
1305     }
1306
1307     protected List<Adjacency> getAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList, String fixedIp) {
1308         List<Adjacency> adjList = new ArrayList<>();
1309         Map<String, List<String>> adjMap = new HashMap<>();
1310         for (Routes route : routeList) {
1311             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
1312                 LOG.error("Incorrect input received for extra route. {}", route);
1313             } else {
1314                 String nextHop = String.valueOf(route.getNexthop().getValue());
1315                 String destination = String.valueOf(route.getDestination().getValue());
1316                 if (!nextHop.equals(fixedIp)) {
1317                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
1318                     continue;
1319                 }
1320                 LOG.trace("Adding extra route for destination {} onto vpn {} with nexthop {} ", destination,
1321                         vpnId.getValue(), nextHop);
1322                 List<String> hops = adjMap.computeIfAbsent(destination, k -> new ArrayList<>());
1323                 if (!hops.contains(nextHop)) {
1324                     hops.add(nextHop);
1325                 }
1326             }
1327         }
1328
1329         for (String destination : adjMap.keySet()) {
1330             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
1331                 .setNextHopIpList(adjMap.get(destination)).setKey(new AdjacencyKey(destination)).build();
1332             adjList.add(erAdj);
1333         }
1334         return  adjList;
1335     }
1336
1337     // TODO Clean up the exception handling
1338     @SuppressWarnings("checkstyle:IllegalCatch")
1339     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
1340         for (Routes route : routeList) {
1341             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
1342                 LOG.error("Incorrect input received for extra route. {}", route);
1343             } else {
1344                 String nextHop = String.valueOf(route.getNexthop().getValue());
1345                 String destination = String.valueOf(route.getDestination().getValue());
1346                 String infName = NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, vpnId.getValue(),
1347                         nextHop);
1348                 if (infName != null) {
1349                     LOG.trace("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}",
1350                         destination, vpnId.getValue(), nextHop, infName);
1351                     boolean isLockAcquired = false;
1352                     try {
1353                         InstanceIdentifier<VpnInterface> identifier = InstanceIdentifier.builder(VpnInterfaces.class)
1354                                 .child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
1355                         InstanceIdentifier<Adjacency> path = identifier.augmentation(Adjacencies.class)
1356                             .child(Adjacency.class, new AdjacencyKey(destination));
1357                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
1358                             .setNextHopIpList(Collections.singletonList(nextHop)).setKey(new AdjacencyKey(destination))
1359                             .build();
1360                         isLockAcquired = NeutronvpnUtils.lock(infName);
1361                         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, erAdj);
1362                     } catch (Exception e) {
1363                         LOG.error("exception in adding extra route with destination: {}, next hop: {}",
1364                             destination, nextHop, e);
1365                     } finally {
1366                         if (isLockAcquired) {
1367                             NeutronvpnUtils.unlock(infName);
1368                         }
1369                     }
1370                 } else {
1371                     LOG.debug("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} "
1372                         + "with nexthop {}", destination, vpnId.getValue(), nextHop);
1373                 }
1374             }
1375         }
1376     }
1377
1378     // TODO Clean up the exception handling
1379     @SuppressWarnings("checkstyle:IllegalCatch")
1380     protected void removeAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList) {
1381         for (Routes route : routeList) {
1382             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
1383                 boolean isLockAcquired = false;
1384                 String nextHop = String.valueOf(route.getNexthop().getValue());
1385                 String destination = String.valueOf(route.getDestination().getValue());
1386                 String infName = NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, vpnId.getValue(),
1387                         nextHop);
1388                 if (infName == null) {
1389                     LOG.error("Unable to find VPN NextHop interface to remove extra-route destination {} on VPN {} "
1390                             + "with nexthop {}", destination, vpnId.getValue(), nextHop);
1391                     // Proceed to remove the next extra-route
1392                     continue;
1393                 }
1394                 LOG.trace("Removing extra route for destination {} on vpn {} with nexthop {} and infName {}",
1395                         destination, vpnId.getValue(), nextHop, infName);
1396
1397                 InstanceIdentifier<Adjacency> adjacencyIdentifier =
1398                         InstanceIdentifier.builder(VpnInterfaces.class)
1399                                 .child(VpnInterface.class, new VpnInterfaceKey(infName))
1400                                 .augmentation(Adjacencies.class)
1401                                 .child(Adjacency.class, new AdjacencyKey(destination))
1402                                 .build();
1403
1404                 // Looking for existing prefix in MDSAL database
1405                 Optional<Adjacency> adjacency = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1406                         adjacencyIdentifier);
1407                 boolean updateNextHops = false;
1408                 List<String> nextHopList = new ArrayList<>();
1409                 if (adjacency.isPresent()) {
1410                     List<String> nhListRead = adjacency.get().getNextHopIpList();
1411                     if (nhListRead.size() > 1) { // ECMP case
1412                         for (String nextHopRead : nhListRead) {
1413                             if (nextHopRead.equals(nextHop)) {
1414                                 updateNextHops = true;
1415                             } else {
1416                                 nextHopList.add(nextHopRead);
1417                             }
1418                         }
1419                     }
1420                 }
1421
1422                 try {
1423                     isLockAcquired = NeutronvpnUtils.lock(infName);
1424                     if (updateNextHops) {
1425                         // An update must be done, not including the current next hop
1426                         InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(
1427                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
1428                         Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
1429                                 .setNextHopIpList(nextHopList)
1430                                 .setKey(new AdjacencyKey(destination))
1431                                 .build();
1432                         Adjacencies erAdjs =
1433                                 new AdjacenciesBuilder().setAdjacency(Collections.singletonList(newAdj)).build();
1434                         VpnInterface vpnIf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
1435                                 .addAugmentation(Adjacencies.class, erAdjs).build();
1436                         MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
1437                     } else {
1438                         // Remove the whole route
1439                         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
1440                         LOG.trace("extra route {} deleted successfully", route);
1441                     }
1442                 } catch (Exception e) {
1443                     LOG.error("exception in deleting extra route: {}" + e);
1444                 } finally {
1445                     if (isLockAcquired) {
1446                         NeutronvpnUtils.unlock(infName);
1447                     }
1448                 }
1449             } else {
1450                 LOG.error("Incorrect input received for extra route. {}", route);
1451             }
1452         }
1453     }
1454
1455     protected void removeL3Vpn(Uuid id) {
1456         // read VPNMaps
1457         VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, id);
1458         Uuid router = (vpnMap != null) ? vpnMap.getRouterId() : null;
1459         // dissociate router
1460         if (router != null) {
1461             dissociateRouterFromVpn(id, router);
1462         }
1463         // dissociate networks
1464         if (!id.equals(router)) {
1465             dissociateNetworksFromVpn(id, vpnMap.getNetworkIds());
1466         }
1467         // remove entire vpnMaps node
1468         deleteVpnMapsNode(id);
1469
1470         // remove vpn-instance
1471         deleteVpnInstance(id);
1472     }
1473
1474     protected void removeSubnetFromVpn(final Uuid vpnId, Uuid subnet) {
1475         LOG.debug("Removing subnet {} from vpn {}", subnet.getValue(), vpnId.getValue());
1476         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
1477         Subnetmap sn = NeutronvpnUtils.getSubnetmap(dataBroker, subnet);
1478         if (sn != null) {
1479             // Check if there are ports on this subnet; remove corresponding vpn-interfaces
1480             List<Uuid> portList = sn.getPortList();
1481             if (portList != null) {
1482                 for (final Uuid portId : sn.getPortList()) {
1483                     LOG.debug("removing vpn-interface for port {}", portId.getValue());
1484                     final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1485                     portDataStoreCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1486                         WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
1487                         List<ListenableFuture<Void>> futures = new ArrayList<>();
1488                         Port port = NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1489                         if (port != null) {
1490                             deleteVpnInterface(vpnId, routerId, port, wrtConfigTxn);
1491                         } else {
1492                             LOG.error("Cannot proceed with deleteVpnInterface for port {} in subnet {} since port is "
1493                                 + "absent in Neutron config DS", portId.getValue(), subnet.getValue());
1494                         }
1495                         futures.add(wrtConfigTxn.submit());
1496                         return futures;
1497                     });
1498                 }
1499             }
1500             // update subnet-vpn association
1501             removeFromSubnetNode(subnet, null, null, vpnId, null);
1502         } else {
1503             LOG.warn("Subnetmap for subnet {} not found", subnet.getValue());
1504         }
1505     }
1506
1507     // TODO Clean up the exception handling
1508     @SuppressWarnings("checkstyle:IllegalCatch")
1509     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
1510         updateVpnMaps(vpnId, null, routerId, null, null);
1511         LOG.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
1512         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1513         if (routerSubnets != null) {
1514             for (Uuid subnetId : routerSubnets) {
1515                 updateVpnForSubnet(vpnId, subnetId, true);
1516             }
1517         }
1518         try {
1519             checkAndPublishRouterAssociatedtoVpnNotification(routerId, vpnId);
1520             LOG.debug("notification upon association of router {} to VPN {} published", routerId.getValue(),
1521                     vpnId.getValue());
1522         } catch (Exception e) {
1523             LOG.error("publishing of notification upon association of router {} to VPN {} failed : ", routerId
1524                     .getValue(), vpnId.getValue(), e);
1525         }
1526     }
1527
1528     protected void associateRouterToInternalVpn(Uuid vpnId, Uuid routerId) {
1529         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1530         LOG.debug("Adding subnets to internal vpn {}", vpnId.getValue());
1531         for (Uuid subnet : routerSubnets) {
1532             addSubnetToVpn(vpnId, subnet);
1533         }
1534     }
1535
1536     // TODO Clean up the exception handling
1537     @SuppressWarnings("checkstyle:IllegalCatch")
1538     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
1539
1540         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
1541         if (routerSubnets != null) {
1542             for (Uuid subnetId : routerSubnets) {
1543                 LOG.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
1544                 updateVpnForSubnet(routerId, subnetId, false);
1545             }
1546         }
1547         clearFromVpnMaps(vpnId, routerId, null);
1548         try {
1549             checkAndPublishRouterDisassociatedFromVpnNotification(routerId, vpnId);
1550             LOG.debug("notification upon disassociation of router {} from VPN {} published", routerId.getValue(),
1551                     vpnId.getValue());
1552         } catch (Exception e) {
1553             LOG.error("publishing of notification upon disassociation of router {} from VPN {} failed : ", routerId
1554                     .getValue(), vpnId.getValue(), e);
1555         }
1556     }
1557
1558     protected List<String> associateNetworksToVpn(Uuid vpn, List<Uuid> networks) {
1559         List<String> failedNwList = new ArrayList<>();
1560         List<Uuid> passedNwList = new ArrayList<>();
1561         if (!networks.isEmpty()) {
1562             // process corresponding subnets for VPN
1563             for (Uuid nw : networks) {
1564                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
1565                 Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
1566                 if (network == null) {
1567                     failedNwList.add(String.format("network %s not found", nw.getValue()));
1568                 } else if (vpnId != null) {
1569                     failedNwList.add(String.format("network %s already associated to another VPN %s", nw.getValue(),
1570                             vpnId.getValue()));
1571                 } else {
1572                     List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
1573                     LOG.debug("Adding network subnets...{}", networkSubnets);
1574                     if (networkSubnets != null) {
1575                         for (Uuid subnet : networkSubnets) {
1576                             // check if subnet added as router interface to some router
1577                             Uuid subnetVpnId = NeutronvpnUtils.getVpnForSubnet(dataBroker, subnet);
1578                             if (subnetVpnId == null) {
1579                                 addSubnetToVpn(vpn, subnet);
1580                                 passedNwList.add(nw);
1581                             } else {
1582                                 failedNwList.add(String.format("subnet %s already added as router interface bound to "
1583                                     + "internal/external VPN %s", subnet.getValue(), subnetVpnId.getValue()));
1584                             }
1585                         }
1586                     }
1587                     if (NeutronvpnUtils.getIsExternal(network)) {
1588                         nvpnNatManager.addExternalNetworkToVpn(network, vpn);
1589                     }
1590                 }
1591             }
1592             updateVpnMaps(vpn, null, null, null, passedNwList);
1593         }
1594         return failedNwList;
1595     }
1596
1597     protected List<String> dissociateNetworksFromVpn(Uuid vpn, List<Uuid> networks) {
1598         List<String> failedNwList = new ArrayList<>();
1599         List<Uuid> passedNwList = new ArrayList<>();
1600         if (networks != null && !networks.isEmpty()) {
1601             // process corresponding subnets for VPN
1602             for (Uuid nw : networks) {
1603                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
1604                 if (network == null) {
1605                     failedNwList.add(String.format("network %s not found", nw.getValue()));
1606                 } else {
1607                     Uuid vpnId = NeutronvpnUtils.getVpnForNetwork(dataBroker, nw);
1608                     if (vpn.equals(vpnId)) {
1609                         List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
1610                         LOG.debug("Removing network subnets...");
1611                         if (networkSubnets != null) {
1612                             for (Uuid subnet : networkSubnets) {
1613                                 removeSubnetFromVpn(vpn, subnet);
1614                                 passedNwList.add(nw);
1615                             }
1616                         }
1617                     } else {
1618                         if (vpnId == null) {
1619                             failedNwList.add(String.format("input network %s not associated to any vpn yet", nw
1620                                     .getValue()));
1621                         } else {
1622                             failedNwList.add(String.format("input network %s associated to a another vpn %s instead "
1623                                 + "of the one given as input", nw.getValue(), vpnId.getValue()));
1624                         }
1625                     }
1626                     if (NeutronvpnUtils.getIsExternal(network)) {
1627                         nvpnNatManager.removeExternalNetworkFromVpn(network);
1628                     }
1629                 }
1630             }
1631             clearFromVpnMaps(vpn, null, passedNwList);
1632         }
1633         return failedNwList;
1634     }
1635
1636     /**
1637      * It handles the invocations to the neutronvpn:associateNetworks RPC method.
1638      */
1639     @Override
1640     // TODO Clean up the exception handling
1641     @SuppressWarnings("checkstyle:IllegalCatch")
1642     public Future<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
1643
1644         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
1645         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
1646         LOG.debug("associateNetworks {}", input);
1647         StringBuilder returnMsg = new StringBuilder();
1648         Uuid vpnId = input.getVpnId();
1649
1650         try {
1651             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1652                 List<Uuid> netIds = input.getNetworkId();
1653                 if (netIds != null && !netIds.isEmpty()) {
1654                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
1655                     if (!failed.isEmpty()) {
1656                         returnMsg.append(failed);
1657                     }
1658                 }
1659             } else {
1660                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1661             }
1662             if (returnMsg.length() != 0) {
1663                 String message = String.format("associate Networks to vpn %s failed due to %s",
1664                         vpnId.getValue(), returnMsg);
1665                 LOG.error(message);
1666                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: %s",
1667                         message);
1668                 opBuilder.setResponse(errorResponse);
1669                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().withResult(opBuilder.build()).build());
1670             } else {
1671                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().build());
1672             }
1673         } catch (Exception ex) {
1674             String message = String.format("associate Networks to vpn %s failed due to %s",
1675                     input.getVpnId().getValue(), ex.getMessage());
1676             LOG.error(message, ex);
1677             result.set(RpcResultBuilder.<AssociateNetworksOutput>failed().withError(ErrorType.APPLICATION, message)
1678                     .build());
1679         }
1680         LOG.debug("associateNetworks returns..");
1681         return result;
1682     }
1683
1684     /**
1685      * It handles the invocations to the neutronvpn:associateRouter RPC method.
1686      */
1687     @Override
1688     // TODO Clean up the exception handling
1689     @SuppressWarnings("checkstyle:IllegalCatch")
1690     public Future<RpcResult<Void>> associateRouter(AssociateRouterInput input) {
1691
1692         SettableFuture<RpcResult<Void>> result = SettableFuture.create();
1693         LOG.debug("associateRouter {}", input);
1694         StringBuilder returnMsg = new StringBuilder();
1695         Uuid vpnId = input.getVpnId();
1696         Uuid routerId = input.getRouterId();
1697         try {
1698             VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, vpnId);
1699             Router rtr = NeutronvpnUtils.getNeutronRouter(dataBroker, routerId);
1700             if (vpnMap != null) {
1701                 if (rtr != null) {
1702                     Uuid extVpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1703                     if (vpnMap.getRouterId() != null) {
1704                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
1705                                 .append(vpnMap.getRouterId().getValue());
1706                     } else if (extVpnId != null) {
1707                         returnMsg.append("router ").append(routerId.getValue()).append(" already associated to "
1708                             + "another VPN ").append(extVpnId.getValue());
1709                     } else {
1710                         associateRouterToVpn(vpnId, routerId);
1711                     }
1712                 } else {
1713                     returnMsg.append("router not found : ").append(routerId.getValue());
1714                 }
1715             } else {
1716                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1717             }
1718             if (returnMsg.length() != 0) {
1719                 String message = String.format("associate router to vpn %s failed due to %s", routerId.getValue(),
1720                         returnMsg);
1721                 LOG.error(message);
1722                 result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value", message)
1723                         .build());
1724             } else {
1725                 result.set(RpcResultBuilder.<Void>success().build());
1726             }
1727         } catch (Exception ex) {
1728             String message = String.format("associate router %s to vpn %s failed due to %s", routerId.getValue(),
1729                     vpnId.getValue(), ex.getMessage());
1730             LOG.error(message, ex);
1731             result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION, message).build());
1732         }
1733         LOG.debug("associateRouter returns..");
1734         return result;
1735     }
1736
1737     /** It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
1738      */
1739     @Override
1740     // TODO Clean up the exception handling
1741     @SuppressWarnings("checkstyle:IllegalCatch")
1742     public Future<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
1743         GetFixedIPsForNeutronPortInput input) {
1744         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
1745         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
1746         Uuid portId = input.getPortId();
1747         StringBuilder returnMsg = new StringBuilder();
1748         try {
1749             List<String> fixedIPList = new ArrayList<>();
1750             Port port = NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1751             if (port != null) {
1752                 List<FixedIps> fixedIPs = port.getFixedIps();
1753                 for (FixedIps ip : fixedIPs) {
1754                     fixedIPList.add(String.valueOf(ip.getIpAddress().getValue()));
1755                 }
1756             } else {
1757                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
1758             }
1759             if (returnMsg.length() != 0) {
1760                 String message = String.format("Retrieval of FixedIPList for neutron port failed due to %s", returnMsg);
1761                 LOG.error(message);
1762                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed()
1763                         .withWarning(ErrorType.PROTOCOL, "invalid-value", message).build());
1764             } else {
1765                 opBuilder.setFixedIPs(fixedIPList);
1766                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().withResult(opBuilder.build())
1767                         .build());
1768                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().build());
1769             }
1770         } catch (Exception ex) {
1771             String message = String.format("Retrieval of FixedIPList for neutron port %s failed due to %s",
1772                     portId.getValue(), ex.getMessage());
1773             LOG.error(message, ex);
1774             result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed()
1775                     .withError(ErrorType.APPLICATION, message).build());
1776         }
1777         return result;
1778     }
1779
1780     /**
1781      * It handles the invocations to the neutronvpn:dissociateNetworks RPC method.
1782      */
1783     @Override
1784     // TODO Clean up the exception handling
1785     @SuppressWarnings("checkstyle:IllegalCatch")
1786     public Future<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
1787
1788         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
1789         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
1790
1791         LOG.debug("dissociateNetworks {}", input);
1792         StringBuilder returnMsg = new StringBuilder();
1793         Uuid vpnId = input.getVpnId();
1794
1795         try {
1796             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1797                 List<Uuid> netIds = input.getNetworkId();
1798                 if (netIds != null && !netIds.isEmpty()) {
1799                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
1800                     if (!failed.isEmpty()) {
1801                         returnMsg.append(failed);
1802                     }
1803                 }
1804             } else {
1805                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1806             }
1807             if (returnMsg.length() != 0) {
1808                 String message = String.format("dissociate Networks to vpn %s failed due to %s", vpnId.getValue(),
1809                         returnMsg);
1810                 LOG.error(message);
1811                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: "
1812                         + message);
1813                 opBuilder.setResponse(errorResponse);
1814                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
1815             } else {
1816                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
1817             }
1818         } catch (Exception ex) {
1819             String message = String.format("dissociate Networks to vpn %s failed due to %s",
1820                     input.getVpnId().getValue(), ex.getMessage());
1821             LOG.error(message, ex);
1822             result.set(RpcResultBuilder.<DissociateNetworksOutput>failed().withError(ErrorType.APPLICATION, message)
1823                     .build());
1824         }
1825         LOG.debug("dissociateNetworks returns..");
1826         return result;
1827     }
1828
1829     /**
1830      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
1831      */
1832     @Override
1833     // TODO Clean up the exception handling
1834     @SuppressWarnings("checkstyle:IllegalCatch")
1835     public Future<RpcResult<Void>> dissociateRouter(DissociateRouterInput input) {
1836
1837         SettableFuture<RpcResult<Void>> result = SettableFuture.create();
1838
1839         LOG.debug("dissociateRouter {}", input);
1840         StringBuilder returnMsg = new StringBuilder();
1841         Uuid vpnId = input.getVpnId();
1842         Uuid routerId = input.getRouterId();
1843         try {
1844             if (NeutronvpnUtils.getVpnMap(dataBroker, vpnId) != null) {
1845                 if (routerId != null) {
1846                     Router rtr = NeutronvpnUtils.getNeutronRouter(dataBroker, routerId);
1847                     if (rtr != null) {
1848                         Uuid routerVpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1849                         if (vpnId.equals(routerVpnId)) {
1850                             dissociateRouterFromVpn(vpnId, routerId);
1851                         } else {
1852                             if (routerVpnId == null) {
1853                                 returnMsg.append("input router ").append(routerId.getValue())
1854                                     .append(" not associated to any vpn yet");
1855                             } else {
1856                                 returnMsg.append("input router ").append(routerId.getValue())
1857                                     .append(" associated to vpn ")
1858                                     .append(routerVpnId.getValue()).append("instead of the vpn given as input");
1859                             }
1860                         }
1861                     } else {
1862                         returnMsg.append("router not found : ").append(routerId.getValue());
1863                     }
1864                 }
1865             } else {
1866                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
1867             }
1868             if (returnMsg.length() != 0) {
1869                 String message = String.format("dissociate router %s to vpn %s failed due to %s", routerId.getValue(),
1870                         vpnId.getValue(), returnMsg);
1871                 LOG.error(message);
1872                 String errorResponse = String.format("ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: "
1873                         + message);
1874                 result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value", message)
1875                         .build());
1876             } else {
1877                 result.set(RpcResultBuilder.<Void>success().build());
1878             }
1879         } catch (Exception ex) {
1880             String message = String.format("disssociate router %s to vpn %s failed due to %s", routerId.getValue(),
1881                     vpnId.getValue(), ex.getMessage());
1882             LOG.error(message, ex);
1883             result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION, message).build());
1884         }
1885         LOG.debug("dissociateRouter returns..");
1886
1887         return result;
1888     }
1889
1890     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
1891         // check if the router is associated to some VPN
1892         Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
1893         if (vpnId != null) {
1894             // remove existing external vpn interfaces
1895             for (Uuid subnetId : routerSubnetIds) {
1896                 removeSubnetFromVpn(vpnId, subnetId);
1897             }
1898             clearFromVpnMaps(vpnId, routerId, null);
1899         } else {
1900             // remove existing internal vpn interfaces
1901             for (Uuid subnetId : routerSubnetIds) {
1902                 removeSubnetFromVpn(routerId, subnetId);
1903             }
1904         }
1905         // delete entire vpnMaps node for internal VPN
1906         deleteVpnMapsNode(routerId);
1907
1908         // delete vpn-instance for internal VPN
1909         deleteVpnInstance(routerId);
1910     }
1911
1912     protected Subnet getNeutronSubnet(Uuid subnetId) {
1913         return NeutronvpnUtils.getNeutronSubnet(dataBroker, subnetId);
1914     }
1915
1916     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
1917         Subnet sn = NeutronvpnUtils.getNeutronSubnet(dataBroker, subnetId);
1918         if (null != sn) {
1919             return sn.getGatewayIp();
1920         }
1921         return null;
1922     }
1923
1924
1925     protected Network getNeutronNetwork(Uuid networkId) {
1926         return NeutronvpnUtils.getNeutronNetwork(dataBroker, networkId);
1927     }
1928
1929     protected Port getNeutronPort(String name) {
1930         return NeutronvpnUtils.getNeutronPort(dataBroker, new Uuid(name));
1931     }
1932
1933     protected Port getNeutronPort(Uuid portId) {
1934         return NeutronvpnUtils.getNeutronPort(dataBroker, portId);
1935     }
1936
1937     protected List<Uuid> getSubnetsforVpn(Uuid vpnid) {
1938         List<Uuid> subnets = new ArrayList<>();
1939         // read subnetmaps
1940         InstanceIdentifier<Subnetmaps> subnetmapsid = InstanceIdentifier.builder(Subnetmaps.class).build();
1941         Optional<Subnetmaps> subnetmaps = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
1942                 subnetmapsid);
1943         if (subnetmaps.isPresent() && subnetmaps.get().getSubnetmap() != null) {
1944             List<Subnetmap> subnetMapList = subnetmaps.get().getSubnetmap();
1945             for (Subnetmap subnetMap : subnetMapList) {
1946                 if (subnetMap.getVpnId() != null && subnetMap.getVpnId().equals(vpnid)) {
1947                     subnets.add(subnetMap.getId());
1948                 }
1949             }
1950         }
1951         return subnets;
1952     }
1953
1954     /**
1955      * Implementation of the "vpnservice:neutron-ports-show" Karaf CLI command.
1956      *
1957      * @return a List of String to be printed on screen
1958      */
1959     // TODO Clean up the exception handling and the console output
1960     @SuppressWarnings({"checkstyle:IllegalCatch", "checkstyle:RegexpSinglelineJava"})
1961     public List<String> showNeutronPortsCLI() {
1962         List<String> result = new ArrayList<>();
1963         result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", "Port ID", "Mac Address", "Prefix Length",
1964             "IP Address"));
1965         result.add("-------------------------------------------------------------------------------------------");
1966         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
1967         try {
1968             Optional<Ports> ports =
1969                 NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
1970             if (ports.isPresent() && ports.get().getPort() != null) {
1971                 for (Port port : ports.get().getPort()) {
1972                     List<FixedIps> fixedIPs = port.getFixedIps();
1973                     try {
1974                         if (fixedIPs != null && !fixedIPs.isEmpty()) {
1975                             List<String> ipList = new ArrayList<>();
1976                             for (FixedIps fixedIp : fixedIPs) {
1977                                 IpAddress ipAddress = fixedIp.getIpAddress();
1978                                 if (ipAddress.getIpv4Address() != null) {
1979                                     ipList.add(ipAddress.getIpv4Address().getValue());
1980                                 } else {
1981                                     ipList.add((ipAddress.getIpv6Address().getValue()));
1982                                 }
1983                             }
1984                             result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
1985                                     .getMacAddress().getValue(), NeutronvpnUtils.getIPPrefixFromPort(dataBroker, port),
1986                                     ipList.toString()));
1987                         } else {
1988                             result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
1989                                     .getMacAddress().getValue(), "Not Assigned", "Not " + "Assigned"));
1990                         }
1991                     } catch (Exception e) {
1992                         LOG.error("Failed to retrieve neutronPorts info for port {}: ", port.getUuid().getValue(),
1993                                 e);
1994                         System.out.println("Failed to retrieve neutronPorts info for port: " + port.getUuid()
1995                                 .getValue() + ": " + e.getMessage());
1996                     }
1997                 }
1998             }
1999         } catch (Exception e) {
2000             LOG.error("Failed to retrieve neutronPorts info : ", e);
2001             System.out.println("Failed to retrieve neutronPorts info : " + e.getMessage());
2002         }
2003         return result;
2004     }
2005
2006     /**
2007      * Implementation of the "vpnservice:l3vpn-config-show" karaf CLI command.
2008      *
2009      * @param vpnuuid Uuid of the VPN whose config must be shown
2010      * @return formatted output list
2011      */
2012     @SuppressWarnings("checkstyle:RegexpSinglelineJava")
2013     public List<String> showVpnConfigCLI(Uuid vpnuuid) {
2014         List<String> result = new ArrayList<>();
2015         if (vpnuuid == null) {
2016             System.out.println("");
2017             System.out.println("Displaying VPN config for all VPNs");
2018             System.out.println("To display VPN config for a particular VPN, use the following syntax");
2019             System.out.println(getshowVpnConfigCLIHelp());
2020         }
2021         try {
2022             RpcResult<GetL3VPNOutput> rpcResult = getL3VPN(new GetL3VPNInputBuilder().setId(vpnuuid).build()).get();
2023             if (rpcResult.isSuccessful()) {
2024                 result.add("");
2025                 result.add(String.format(" %-37s %-37s %-7s ", "VPN ID", "Tenant ID", "RD"));
2026                 result.add("");
2027                 result.add(String.format(" %-80s ", "Import-RTs"));
2028                 result.add("");
2029                 result.add(String.format(" %-80s ", "Export-RTs"));
2030                 result.add("");
2031                 result.add(String.format(" %-76s ", "Subnet IDs"));
2032                 result.add("");
2033                 result.add("------------------------------------------------------------------------------------");
2034                 result.add("");
2035                 List<L3vpnInstances> vpnList = rpcResult.getResult().getL3vpnInstances();
2036                 for (L3vpnInstance vpn : vpnList) {
2037                     String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
2038                             : "\"                 " + "                  \"";
2039                     result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
2040                             vpn.getRouteDistinguisher()));
2041                     result.add("");
2042                     result.add(String.format(" %-80s ", vpn.getImportRT()));
2043                     result.add("");
2044                     result.add(String.format(" %-80s ", vpn.getExportRT()));
2045                     result.add("");
2046
2047                     Uuid vpnid = vpn.getId();
2048                     List<Uuid> subnetList = getSubnetsforVpn(vpnid);
2049                     if (!subnetList.isEmpty()) {
2050                         for (Uuid subnetuuid : subnetList) {
2051                             result.add(String.format(" %-76s ", subnetuuid.getValue()));
2052                         }
2053                     } else {
2054                         result.add(String.format(" %-76s ", "\"                                    \""));
2055                     }
2056                     result.add("");
2057                     result.add("----------------------------------------");
2058                     result.add("");
2059                 }
2060             } else {
2061                 String errortag = rpcResult.getErrors().iterator().next().getTag();
2062                 if (errortag == "") {
2063                     System.out.println("");
2064                     System.out.println("No VPN has been configured yet");
2065                 } else if (errortag == "invalid-value") {
2066                     System.out.println("");
2067                     System.out.println("VPN " + vpnuuid.getValue() + " is not present");
2068                 } else {
2069                     System.out.println("error getting VPN info : " + rpcResult.getErrors());
2070                     System.out.println(getshowVpnConfigCLIHelp());
2071                 }
2072             }
2073         } catch (InterruptedException | ExecutionException e) {
2074             LOG.error("error getting VPN info : ", e);
2075             System.out.println("error getting VPN info : " + e.getMessage());
2076         }
2077         return result;
2078     }
2079
2080     protected void createExternalVpnInterfaces(Uuid extNetId) {
2081         if (extNetId == null) {
2082             LOG.trace("external network is null");
2083             return;
2084         }
2085
2086         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
2087         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
2088             LOG.trace("No external ports attached to external network {}", extNetId.getValue());
2089             return;
2090         }
2091
2092         WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2093         for (String elanInterface : extElanInterfaces) {
2094             createExternalVpnInterface(extNetId, elanInterface, wrtConfigTxn);
2095         }
2096         wrtConfigTxn.submit();
2097     }
2098
2099     // TODO Clean up the exception handling
2100     @SuppressWarnings("checkstyle:IllegalCatch")
2101     protected void removeExternalVpnInterfaces(Uuid extNetId) {
2102         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
2103         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
2104             LOG.trace("No external ports attached for external network {}", extNetId);
2105             return;
2106         }
2107         try {
2108
2109             WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2110             for (String elanInterface : extElanInterfaces) {
2111                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
2112                         .buildVpnInterfaceIdentifier(elanInterface);
2113                 LOG.info("Removing vpn interface {}", elanInterface);
2114                 wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
2115             }
2116             wrtConfigTxn.submit();
2117
2118         } catch (Exception ex) {
2119             LOG.error("Removal of vpninterfaces {} failed due to {}", extElanInterfaces, ex);
2120         }
2121     }
2122
2123     private void createExternalVpnInterface(Uuid vpnId, String infName, WriteTransaction wrtConfigTxn) {
2124         writeVpnInterfaceToDs(vpnId, infName, null, false /* not a router iface */, wrtConfigTxn);
2125     }
2126
2127     // TODO Clean up the exception handling
2128     @SuppressWarnings("checkstyle:IllegalCatch")
2129     private void writeVpnInterfaceToDs(Uuid vpnId, String infName, Adjacencies adjacencies,
2130             Boolean isRouterInterface, WriteTransaction wrtConfigTxn) {
2131         if (vpnId == null || infName == null) {
2132             LOG.debug("vpn id or interface is null");
2133             return;
2134         }
2135
2136         Boolean wrtConfigTxnPresent = true;
2137         if (wrtConfigTxn == null) {
2138             wrtConfigTxnPresent = false;
2139             wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
2140         }
2141
2142         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
2143         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
2144                 .setName(infName)
2145                 .setVpnInstanceName(vpnId.getValue())
2146                 .setIsRouterInterface(isRouterInterface);
2147         if (adjacencies != null) {
2148             vpnb.addAugmentation(Adjacencies.class, adjacencies);
2149         }
2150         VpnInterface vpnIf = vpnb.build();
2151         try {
2152             LOG.info("Creating vpn interface {}", vpnIf);
2153             wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
2154         } catch (Exception ex) {
2155             LOG.error("Creation of vpninterface {} failed due to {}", infName, ex);
2156         }
2157
2158         if (!wrtConfigTxnPresent) {
2159             wrtConfigTxn.submit();
2160         }
2161     }
2162
2163     private String getshowVpnConfigCLIHelp() {
2164         StringBuilder help = new StringBuilder("Usage:");
2165         help.append("display vpn-config [-vid/--vpnid <id>]");
2166         return help.toString();
2167     }
2168
2169     private void checkAndPublishRouterAssociatedtoVpnNotification(Uuid routerId, Uuid vpnId) throws
2170             InterruptedException {
2171         RouterAssociatedToVpn routerAssociatedToVpn = new RouterAssociatedToVpnBuilder().setRouterId(routerId)
2172                 .setVpnId(vpnId).build();
2173         LOG.info("publishing notification upon association of router to VPN");
2174         notificationPublishService.putNotification(routerAssociatedToVpn);
2175     }
2176
2177     private void checkAndPublishRouterDisassociatedFromVpnNotification(Uuid routerId, Uuid vpnId) throws
2178             InterruptedException {
2179         RouterDisassociatedFromVpn routerDisassociatedFromVpn =
2180             new RouterDisassociatedFromVpnBuilder().setRouterId(routerId).setVpnId(vpnId).build();
2181         LOG.info("publishing notification upon disassociation of router from VPN");
2182         notificationPublishService.putNotification(routerDisassociatedFromVpn);
2183     }
2184
2185     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
2186         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
2187     }
2188 }