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