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