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