Create l3vpn & asso with ext-nw failed
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
1 /*
2  * Copyright © 2015, 2018 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 java.util.Collections.singletonList;
11 import static org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker.syncReadOptional;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13
14 import com.google.common.base.Preconditions;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.JdkFutureAdapters;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import com.google.common.util.concurrent.SettableFuture;
21 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.EventListener;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.util.Set;
35 import java.util.concurrent.ConcurrentHashMap;
36 import java.util.concurrent.ConcurrentMap;
37 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.Future;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.locks.ReentrantLock;
41 import java.util.function.Consumer;
42 import java.util.stream.Collectors;
43 import javax.annotation.PreDestroy;
44 import javax.inject.Inject;
45 import javax.inject.Singleton;
46 import org.eclipse.jdt.annotation.NonNull;
47 import org.eclipse.jdt.annotation.Nullable;
48 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
49 import org.opendaylight.genius.infra.Datastore.Configuration;
50 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
51 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
52 import org.opendaylight.genius.infra.TypedWriteTransaction;
53 import org.opendaylight.genius.mdsalutil.NwConstants;
54 import org.opendaylight.genius.utils.JvmGlobalLocks;
55 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
56 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
57 import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
58 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
59 import org.opendaylight.mdsal.binding.api.DataBroker;
60 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
61 import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
62 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
63 import org.opendaylight.netvirt.alarm.NeutronvpnAlarms;
64 import org.opendaylight.netvirt.elanmanager.api.IElanService;
65 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
66 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
67 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
68 import org.opendaylight.netvirt.neutronvpn.evpn.manager.NeutronEvpnManager;
69 import org.opendaylight.netvirt.neutronvpn.evpn.utils.NeutronEvpnUtils;
70 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
71 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.AdjacenciesBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInstances;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInterfaces;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency.AdjacencyType;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstance;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstanceBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstanceKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.VpnTargets;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.VpnTargetsBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTarget;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTargetBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTargetKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceKey;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNamesKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksInput;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutput;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutputBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterInput;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterOutput;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterOutputBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNInput;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutput;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNInput;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutput;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutputBuilder;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNInput;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNInput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutput;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutputBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksInput;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutput;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutputBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterInput;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterOutput;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterOutputBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNInput;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutput;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInput;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutputBuilder;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNInput;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNInputBuilder;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutput;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutputBuilder;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.createl3vpn.input.L3vpn;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstances;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getl3vpn.output.L3vpnInstancesBuilder;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesBuilder;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesBuilder;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.InterfacesKey;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
151 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapBuilder;
152 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
153 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
154 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
155 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
156 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.vpnmap.RouterIds;
157 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.vpnmap.RouterIdsBuilder;
158 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.vpnmap.RouterIdsKey;
159 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInput;
160 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInputBuilder;
161 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutput;
162 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
163 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
164 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
165 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.BgpvpnVni;
166 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.OperationalPortStatus;
167 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.Features;
168 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.Feature;
169 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureBuilder;
170 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureKey;
171 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
172 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
173 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
174 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
175 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsKey;
176 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
177 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
178 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.provider.ext.rev150712.NetworkProviderExtension;
179 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
180 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
181 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
182 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
183 import org.opendaylight.yangtools.yang.common.RpcError;
184 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
185 import org.opendaylight.yangtools.yang.common.RpcResult;
186 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
187 import org.slf4j.Logger;
188 import org.slf4j.LoggerFactory;
189 import org.slf4j.helpers.FormattingTuple;
190 import org.slf4j.helpers.MessageFormatter;
191
192 @Singleton
193 public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, EventListener {
194
195     private static final Logger LOG = LoggerFactory.getLogger(NeutronvpnManager.class);
196     private static final long LOCK_WAIT_TIME = 10L;
197
198     private final DataBroker dataBroker;
199     private final ManagedNewTransactionRunner txRunner;
200     private final VpnRpcService vpnRpcService;
201     private final NeutronFloatingToFixedIpMappingChangeListener floatingIpMapListener;
202     private final IElanService elanService;
203     private final NeutronvpnConfig neutronvpnConfig;
204     private final NeutronEvpnManager neutronEvpnManager;
205     private final NeutronEvpnUtils neutronEvpnUtils;
206     private final JobCoordinator jobCoordinator;
207     private final NeutronvpnUtils neutronvpnUtils;
208     private final IVpnManager vpnManager;
209     private final ConcurrentHashMap<Uuid, Uuid> unprocessedPortsMap = new ConcurrentHashMap<>();
210     private final NeutronvpnAlarms neutronvpnAlarm = new NeutronvpnAlarms();
211     private final NamedLocks<Uuid> vpnLock = new NamedLocks<>();
212     private final NamedLocks<String> interfaceLock = new NamedLocks<>();
213
214     @Inject
215     public NeutronvpnManager(
216             final DataBroker dataBroker,
217             final VpnRpcService vpnRpcSrv, final IElanService elanService,
218             final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
219             final NeutronvpnConfig neutronvpnConfig, final IVpnManager vpnManager,
220             final JobCoordinator jobCoordinator,
221             final NeutronvpnUtils neutronvpnUtils) throws TransactionCommitFailedException {
222         this.dataBroker = dataBroker;
223         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
224         vpnRpcService = vpnRpcSrv;
225         this.elanService = elanService;
226         floatingIpMapListener = neutronFloatingToFixedIpMappingChangeListener;
227         this.neutronvpnConfig = neutronvpnConfig;
228         neutronEvpnManager = new NeutronEvpnManager(dataBroker, this, neutronvpnUtils);
229         neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager, jobCoordinator);
230         this.jobCoordinator = jobCoordinator;
231         this.neutronvpnUtils = neutronvpnUtils;
232         this.vpnManager = vpnManager;
233
234         configureFeatures();
235     }
236
237     @Override
238     @PreDestroy
239     public void close() {
240         LOG.info("{} close", getClass().getSimpleName());
241     }
242
243     private void configureFeatures() throws TransactionCommitFailedException {
244         InstanceIdentifier<Feature> iid = InstanceIdentifier.builder(
245                         Neutron.class).child(Features.class).child(
246                         Feature.class, new FeatureKey(OperationalPortStatus.class)).build();
247         Feature feature = new FeatureBuilder().withKey(new FeatureKey(OperationalPortStatus.class)).build();
248         try {
249             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, iid, feature);
250         } catch (OptimisticLockFailedException e) {
251             LOG.debug("Optimistic lock failed exception while configuring feature {}", feature, e);
252         }
253         InstanceIdentifier<Feature> bgpvpnVniIid = InstanceIdentifier.builder(
254                 Neutron.class).child(Features.class).child(
255                 Feature.class, new FeatureKey(BgpvpnVni.class)).build();
256         Feature bgpvpnVniFeature = new FeatureBuilder().withKey(new FeatureKey(BgpvpnVni.class)).build();
257         try {
258             SingleTransactionDataBroker.syncWrite(
259                     dataBroker, LogicalDatastoreType.OPERATIONAL, bgpvpnVniIid, bgpvpnVniFeature);
260         } catch (OptimisticLockFailedException e) {
261             LOG.debug("Optimistic lock failed exception while configuring feature {}", bgpvpnVniFeature, e);
262         }
263     }
264
265     public String getOpenDaylightVniRangesConfig() {
266         return neutronvpnConfig.getOpendaylightVniRanges();
267     }
268
269     // TODO Clean up the exception handling
270     @SuppressWarnings("checkstyle:IllegalCatch")
271     protected void createSubnetmapNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId,
272                                        NetworkAttributes.@Nullable NetworkType networkType, long segmentationId,
273                                         boolean isExternalNw) {
274         try {
275             InstanceIdentifier<Subnetmap> subnetMapIdentifier = NeutronvpnUtils.buildSubnetMapIdentifier(subnetId);
276             final ReentrantLock lock = lockForUuid(subnetId);
277             lock.lock();
278             try {
279                 LOG.info("createSubnetmapNode: subnet ID {}", subnetId.getValue());
280                 Optional<Subnetmap> sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
281                         LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
282                 if (sn.isPresent()) {
283                     LOG.error("createSubnetmapNode: Subnetmap node for subnet ID {} already exists, returning",
284                         subnetId.getValue());
285                     return;
286                 }
287                 SubnetmapBuilder subnetmapBuilder = new SubnetmapBuilder().withKey(new SubnetmapKey(subnetId))
288                         .setId(subnetId).setSubnetIp(subnetIp).setTenantId(tenantId).setNetworkId(networkId)
289                         .setNetworkType(networkType).setSegmentationId(segmentationId).setExternal(isExternalNw);
290                 LOG.debug("createSubnetmapNode: Adding a new subnet node in Subnetmaps DS for subnet {}",
291                     subnetId.getValue());
292                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
293                         subnetMapIdentifier, subnetmapBuilder.build());
294             } finally {
295                 lock.unlock();
296             }
297         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
298             LOG.error("createSubnetmapNode: Creating subnetmap node failed for subnet {}", subnetId.getValue());
299         }
300         // check if there are ports to update for already created Subnetmap node
301         LOG.debug("createSubnetmapNode: Update created Subnetmap for subnet {} with ports", subnetId.getValue());
302         for (Map.Entry<Uuid, Uuid> entry : unprocessedPortsMap.entrySet()) {
303             if (entry.getValue().getValue().equals(subnetId.getValue())) {
304                 updateSubnetmapNodeWithPorts(subnetId, entry.getKey(), null);
305                 unprocessedPortsMap.remove(entry.getKey());
306             }
307         }
308     }
309
310     @Nullable
311     protected Subnetmap updateSubnetNode(Uuid subnetId, @Nullable Uuid routerId, Uuid vpnId,
312             @Nullable Uuid internetvpnId) {
313         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
314                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
315                 .build();
316         final ReentrantLock lock = lockForUuid(subnetId);
317         lock.lock();
318         try {
319             Optional<Subnetmap> sn =
320                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
321             if (!sn.isPresent()) {
322                 LOG.error("subnetmap node for subnet {} does not exist, returning", subnetId.getValue());
323                 return null;
324             }
325             LOG.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
326             SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
327             if (routerId != null) {
328                 builder.setRouterId(routerId);
329             }
330             if (vpnId != null) {
331                 builder.setVpnId(vpnId);
332             }
333             if (NeutronvpnUtils.getIpVersionFromString(sn.get().getSubnetIp()) == IpVersionChoice.IPV6) {
334                 builder.setInternetVpnId(internetvpnId);
335             }
336             Subnetmap subnetmap = builder.build();
337             LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
338             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
339             return subnetmap;
340         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
341             LOG.error("Subnet map update failed for node {}", subnetId.getValue(), e);
342             return null;
343         } finally {
344             lock.unlock();
345         }
346     }
347
348     protected void updateSubnetNodeWithFixedIp(Uuid subnetId, @Nullable Uuid routerId,
349                                                @Nullable Uuid routerInterfacePortId, @Nullable String fixedIp,
350                                                @Nullable String routerIntfMacAddress, @Nullable Uuid vpnId) {
351         InstanceIdentifier<Subnetmap> id =
352                 InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
353         final ReentrantLock lock = lockForUuid(subnetId);
354         lock.lock();
355         try {
356             Optional<Subnetmap> sn =
357                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
358             if (!sn.isPresent()) {
359                 LOG.error("updateSubnetNodeWithFixedIp: subnetmap node for subnet {} does not exist, returning ",
360                     subnetId.getValue());
361                 return;
362             }
363             LOG.debug("updateSubnetNodeWithFixedIp: Updating existing subnetmap node for subnet ID {}",
364                 subnetId.getValue());
365             SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
366             builder.setRouterId(routerId);
367             builder.setRouterInterfacePortId(routerInterfacePortId);
368             builder.setRouterIntfMacAddress(routerIntfMacAddress);
369             builder.setRouterInterfaceFixedIp(fixedIp);
370             if (vpnId != null) {
371                 builder.setVpnId(vpnId);
372             }
373             Subnetmap subnetmap = builder.build();
374             LOG.debug("WithRouterFixedIP Creating/Updating subnetMap node for Router FixedIp: {} ",
375                 subnetId.getValue());
376             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
377         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
378             LOG.error("updateSubnetNodeWithFixedIp: subnet map for Router FixedIp failed for node {}",
379                 subnetId.getValue(), e);
380         } finally {
381             lock.unlock();
382         }
383     }
384
385     protected Subnetmap updateSubnetmapNodeWithPorts(Uuid subnetId, @Nullable Uuid portId,
386             @Nullable Uuid directPortId) {
387         Subnetmap subnetmap = null;
388         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
389                 new SubnetmapKey(subnetId)).build();
390         LOG.info("updateSubnetmapNodeWithPorts: Updating subnetMap with portList for subnetId {}", subnetId.getValue());
391         final ReentrantLock lock = lockForUuid(subnetId);
392         lock.lock();
393         try {
394             Optional<Subnetmap> sn =
395                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
396                         id);
397             if (sn.isPresent()) {
398                 SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
399                 if (null != portId) {
400                     List<Uuid> existingPortList = builder.getPortList();
401                     List<Uuid> portList = new ArrayList<>();
402                     if (null != existingPortList) {
403                         portList.addAll(existingPortList);
404                     }
405                     portList.add(portId);
406                     builder.setPortList(portList);
407                     LOG.debug("updateSubnetmapNodeWithPorts: Updating existing subnetmap node {} with port {}",
408                         subnetId.getValue(), portId.getValue());
409                 }
410                 if (null != directPortId) {
411                     List<Uuid> existingDirectPortList = builder.getDirectPortList();
412                     List<Uuid> directPortList = new ArrayList<>();
413                     if (null != existingDirectPortList) {
414                         directPortList.addAll(existingDirectPortList);
415                     }
416                     directPortList.add(directPortId);
417                     builder.setDirectPortList(directPortList);
418                     LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
419                         directPortId.getValue());
420                 }
421                 subnetmap = builder.build();
422                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
423                     subnetmap);
424             } else {
425                 LOG.info("updateSubnetmapNodeWithPorts: Subnetmap node is not ready {}, put port {} in unprocessed "
426                         + "cache ", subnetId.getValue(), portId.getValue());
427                 unprocessedPortsMap.put(portId, subnetId);
428             }
429         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
430             LOG.error("Updating port list of a given subnetMap failed for node: {}", subnetId.getValue(), e);
431         } finally {
432             lock.unlock();
433         }
434         return subnetmap;
435     }
436
437     protected Subnetmap removeFromSubnetNode(Uuid subnetId, @Nullable Uuid networkId, @Nullable Uuid routerId,
438                                             Uuid vpnId, @Nullable Uuid portId) {
439         Subnetmap subnetmap = null;
440         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
441                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
442                 .build();
443         final ReentrantLock lock = lockForUuid(subnetId);
444         lock.lock();
445         try {
446             Optional<Subnetmap> sn =
447                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
448                         id);
449             if (sn.isPresent()) {
450                 SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
451                 if (routerId != null) {
452                     builder.setRouterId(null);
453                 }
454                 if (networkId != null) {
455                     builder.setNetworkId(null);
456                 }
457                 if (vpnId != null) {
458                     builder.setVpnId(null);
459                 }
460                 builder.setInternetVpnId(null);
461                 if (portId != null && builder.getPortList() != null) {
462                     List<Uuid> portList = new ArrayList<>(builder.getPortList());
463                     portList.remove(portId);
464                     builder.setPortList(portList);
465                 }
466
467                 subnetmap = builder.build();
468                 LOG.debug("Removing from existing subnetmap node: {} ", subnetId.getValue());
469                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
470                     subnetmap);
471             } else {
472                 LOG.warn("removing from non-existing subnetmap node: {} ", subnetId.getValue());
473             }
474         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
475             LOG.error("Removal from subnetmap failed for node: {}", subnetId.getValue());
476         } finally {
477             lock.unlock();
478         }
479         return subnetmap;
480     }
481
482     @Nullable
483     protected Subnetmap removePortsFromSubnetmapNode(Uuid subnetId, @Nullable Uuid portId,
484             @Nullable Uuid directPortId) {
485         Subnetmap subnetmap = null;
486         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
487                 new SubnetmapKey(subnetId)).build();
488         final ReentrantLock lock = lockForUuid(subnetId);
489         lock.lock();
490         try {
491             Optional<Subnetmap> sn =
492                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
493                         id);
494             if (sn.isPresent()) {
495                 SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
496                 if (null != portId && null != builder.getPortList() && !builder.getPortList().isEmpty()) {
497                     List<Uuid> portList = new ArrayList<>(builder.getPortList());
498                     portList.remove(portId);
499                     builder.setPortList(portList);
500                     LOG.debug("Removing port {} from existing subnetmap node: {} ", portId.getValue(),
501                         subnetId.getValue());
502                 }
503                 if (null != directPortId && null != builder.getDirectPortList()
504                         && !builder.getDirectPortList().isEmpty()) {
505                     List<Uuid> directPortList = new ArrayList<>(builder.getDirectPortList());
506                     directPortList.remove(directPortId);
507                     builder.setDirectPortList(directPortList);
508                     LOG.debug("Removing direct port {} from existing subnetmap node: {} ", directPortId
509                         .getValue(), subnetId.getValue());
510                 }
511                 subnetmap = builder.build();
512                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
513                     subnetmap);
514             } else {
515                 LOG.info("Trying to remove port from non-existing subnetmap node {}", subnetId.getValue());
516             }
517         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
518             LOG.error("Removing a port from port list of a subnetmap failed for node: {}",
519                     subnetId.getValue(), e);
520         } finally {
521             lock.unlock();
522         }
523         return subnetmap;
524     }
525
526     // TODO Clean up the exception handling
527     @SuppressWarnings("checkstyle:IllegalCatch")
528     protected void deleteSubnetMapNode(Uuid subnetId) {
529         InstanceIdentifier<Subnetmap> subnetMapIdentifier =
530                 InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
531         LOG.debug("removing subnetMap node: {} ", subnetId.getValue());
532         final ReentrantLock lock = lockForUuid(subnetId);
533         lock.lock();
534         try {
535             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
536         } catch (TransactionCommitFailedException e) {
537             LOG.error("Delete subnetMap node failed for subnet : {} ", subnetId.getValue());
538         } finally {
539             lock.unlock();
540         }
541     }
542
543     public void updateVpnInstanceWithRDs(String vpnInstanceId, final List<String> rds) {
544         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
545             .child(VpnInstance.class, new VpnInstanceKey(vpnInstanceId)).build();
546         try {
547             Optional<VpnInstance> vpnInstanceConfig =
548                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
549                             vpnIdentifier);
550             if (!vpnInstanceConfig.isPresent()) {
551                 LOG.debug("updateVpnInstanceWithRDs: "
552                         + "No VpnInstance present under config vpnInstance:{}", vpnInstanceId);
553                 return;
554             }
555             VpnInstance vpnInstance = vpnInstanceConfig.get();
556             VpnInstanceBuilder updateVpnInstanceBuilder = new VpnInstanceBuilder(vpnInstance);
557             updateVpnInstanceBuilder.setRouteDistinguisher(rds);
558             LOG.debug("updateVpnInstanceWithRDs: "
559                     + "Updating Config vpn-instance: {} with the list of RDs: {}", vpnInstanceId, rds);
560             SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier,
561                     updateVpnInstanceBuilder.build());
562         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException ex) {
563             LOG.warn("updateVpnInstanceWithRDs: Error configuring vpn-instance: {} with "
564                     + "the list of RDs: {}", vpnInstanceId, rds, ex);
565         }
566     }
567
568     private void updateVpnInstanceNode(Uuid vpnId, List<String> rd, List<String> irt, List<String> ert,
569                                        boolean isL2Vpn, long l3vni, IpVersionChoice ipVersion) {
570         String vpnName = vpnId.getValue();
571         VpnInstanceBuilder builder = null;
572         List<VpnTarget> vpnTargetList = new ArrayList<>();
573         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
574             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
575         Optional<VpnInstance> optionalVpn;
576         try {
577             optionalVpn = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
578                 vpnIdentifier);
579         } catch (ExecutionException | InterruptedException e) {
580             LOG.error("Update VPN Instance node failed for node: {} {} {} {}", vpnName, rd, irt, ert);
581             return;
582         }
583
584         LOG.debug("Creating/Updating a new vpn-instance node: {} ", vpnName);
585         if (optionalVpn.isPresent()) {
586             builder = new VpnInstanceBuilder(optionalVpn.get());
587             LOG.debug("updating existing vpninstance node");
588         } else {
589             builder = new VpnInstanceBuilder().withKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName)
590                     .setL2vpn(isL2Vpn).setL3vni(l3vni).setBgpvpnType(VpnInstance.BgpvpnType.InternalVPN);
591         }
592         if (irt != null && !irt.isEmpty()) {
593             if (ert != null && !ert.isEmpty()) {
594                 List<String> commonRT = new ArrayList<>(irt);
595                 commonRT.retainAll(ert);
596
597                 for (String common : commonRT) {
598                     irt.remove(common);
599                     ert.remove(common);
600                     VpnTarget vpnTarget =
601                             new VpnTargetBuilder().withKey(new VpnTargetKey(common)).setVrfRTValue(common)
602                             .setVrfRTType(VpnTarget.VrfRTType.Both).build();
603                     vpnTargetList.add(vpnTarget);
604                 }
605             }
606             for (String importRT : irt) {
607                 VpnTarget vpnTarget =
608                         new VpnTargetBuilder().withKey(new VpnTargetKey(importRT)).setVrfRTValue(importRT)
609                         .setVrfRTType(VpnTarget.VrfRTType.ImportExtcommunity).build();
610                 vpnTargetList.add(vpnTarget);
611             }
612         }
613
614         if (ert != null && !ert.isEmpty()) {
615             for (String exportRT : ert) {
616                 VpnTarget vpnTarget =
617                         new VpnTargetBuilder().withKey(new VpnTargetKey(exportRT)).setVrfRTValue(exportRT)
618                         .setVrfRTType(VpnTarget.VrfRTType.ExportExtcommunity).build();
619                 vpnTargetList.add(vpnTarget);
620             }
621         }
622
623         VpnTargets vpnTargets = new VpnTargetsBuilder().setVpnTarget(vpnTargetList).build();
624         if (rd != null && !rd.isEmpty()) {
625             builder.setRouteDistinguisher(rd).setVpnTargets(vpnTargets).setBgpvpnType(VpnInstance.BgpvpnType.BGPVPN);
626         }
627
628         builder.setIpAddressFamilyConfigured(VpnInstance.IpAddressFamilyConfigured.forValue(ipVersion.choice));
629         VpnInstance newVpn = builder.build();
630         try (AcquireResult lock = tryVpnLock(vpnId)) {
631             if (!lock.wasAcquired()) {
632                 // FIXME: why do we even bother with locking if we do not honor it?!
633                 logTryLockFailure(vpnId);
634             }
635
636             LOG.debug("Creating/Updating vpn-instance for {} ", vpnName);
637             try {
638                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier,
639                     newVpn);
640             } catch (TransactionCommitFailedException e) {
641                 LOG.error("Update VPN Instance node failed for node: {} {} {} {}", vpnName, rd, irt, ert);
642             }
643         }
644     }
645
646     private void deleteVpnMapsNode(Uuid vpnId) {
647         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
648                 .child(VpnMap.class, new VpnMapKey(vpnId))
649                 .build();
650         LOG.debug("removing vpnMaps node: {} ", vpnId.getValue());
651         try (AcquireResult lock = tryVpnLock(vpnId)) {
652             if (!lock.wasAcquired()) {
653                 // FIXME: why do we even bother with locking if we do not honor it?!
654                 logTryLockFailure(vpnId);
655             }
656
657             try {
658                 SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
659                     vpnMapIdentifier);
660             } catch (TransactionCommitFailedException e) {
661                 LOG.error("Delete vpnMaps node failed for vpn : {} ", vpnId.getValue());
662             }
663         }
664     }
665
666     protected void updateVpnMaps(Uuid vpnId, @Nullable String name, @Nullable Uuid router, @Nullable Uuid tenantId,
667             @Nullable List<Uuid> networks) {
668         VpnMapBuilder builder;
669         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
670                 .child(VpnMap.class, new VpnMapKey(vpnId))
671                 .build();
672         try {
673             Optional<VpnMap> optionalVpnMap =
674                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
675                             vpnMapIdentifier);
676             if (optionalVpnMap.isPresent()) {
677                 builder = new VpnMapBuilder(optionalVpnMap.get());
678             } else {
679                 builder = new VpnMapBuilder().withKey(new VpnMapKey(vpnId)).setVpnId(vpnId);
680             }
681
682             if (name != null) {
683                 builder.setName(name);
684             }
685             if (tenantId != null) {
686                 builder.setTenantId(tenantId);
687             }
688             if (router != null) {
689                 RouterIds vpnRouterId = new RouterIdsBuilder().setRouterId(router).build();
690                 List<RouterIds> rtrIds = builder.getRouterIds() != null
691                         ? new ArrayList<>(builder.getRouterIds().values()) : null;
692                 if (rtrIds == null) {
693                     rtrIds = Collections.singletonList(vpnRouterId);
694                 } else {
695                     rtrIds.add(vpnRouterId);
696                 }
697                 builder.setRouterIds(rtrIds);
698             }
699             if (networks != null) {
700                 List<Uuid> nwList = builder.getNetworkIds() != null
701                     ? new ArrayList<>(builder.getNetworkIds()) : new ArrayList<>();
702                 nwList.addAll(networks);
703                 builder.setNetworkIds(nwList);
704             }
705
706             try (AcquireResult lock = tryVpnLock(vpnId)) {
707                 if (!lock.wasAcquired()) {
708                     // FIXME: why do we even bother with locking if we do not honor it?!
709                     logTryLockFailure(vpnId);
710                 }
711
712                 LOG.debug("Creating/Updating vpnMaps node: {} ", vpnId.getValue());
713                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier,
714                         builder.build());
715                 LOG.debug("VPNMaps DS updated for VPN {} ", vpnId.getValue());
716             }
717         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
718             LOG.error("UpdateVpnMaps failed for node: {} ", vpnId.getValue());
719         }
720     }
721
722     private void clearFromVpnMaps(Uuid vpnId, @Nullable Uuid routerId, @Nullable List<Uuid> networkIds) {
723         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
724                 .child(VpnMap.class, new VpnMapKey(vpnId))
725                 .build();
726         Optional<VpnMap> optionalVpnMap;
727         try {
728             optionalVpnMap =
729                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
730                             vpnMapIdentifier);
731         } catch (ExecutionException | InterruptedException e) {
732             LOG.error("Error reading the VPN map for {}", vpnMapIdentifier, e);
733             return;
734         }
735         if (optionalVpnMap.isPresent()) {
736             VpnMap vpnMap = optionalVpnMap.get();
737             VpnMapBuilder vpnMapBuilder = new VpnMapBuilder(vpnMap);
738             List<RouterIds> rtrIds = new ArrayList<>(vpnMap.nonnullRouterIds().values());
739             if (rtrIds == null) {
740                 rtrIds = new ArrayList<>();
741             }
742             if (routerId != null) {
743                 if (vpnMap.getNetworkIds() == null && routerId.equals(vpnMap.getVpnId())) {
744                     rtrIds.add(new RouterIdsBuilder().setRouterId(routerId).build());
745                     vpnMapBuilder.setRouterIds(rtrIds);
746
747                     try (AcquireResult lock = tryVpnLock(vpnId)) {
748                         if (!lock.wasAcquired()) {
749                             // FIXME: why do we even bother with locking if we do not honor it?!
750                             logTryLockFailure(vpnId);
751                         }
752
753                         LOG.debug("removing vpnMaps node: {} ", vpnId);
754                         try {
755                             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
756                                     vpnMapIdentifier);
757                         } catch (TransactionCommitFailedException e) {
758                             LOG.error("Deletion of vpnMaps node failed for vpn {}", vpnId.getValue());
759                         }
760                     }
761                     return;
762                 } else if (vpnMap.getNetworkIds() == null && !routerId.equals(vpnMap.getVpnId())) {
763                     rtrIds.remove(new RouterIdsBuilder().setRouterId(routerId).build());
764                     vpnMapBuilder.setRouterIds(rtrIds);
765                     LOG.debug("Removing routerId {} in vpnMaps for the vpn {}", routerId, vpnId.getValue());
766                 }
767             }
768             if (networkIds != null) {
769                 List<Uuid> vpnNw = vpnMap.getNetworkIds() != null
770                         ? new ArrayList<>(vpnMap.getNetworkIds()) : new ArrayList<>();
771                 vpnNw.removeAll(networkIds);
772                 if (vpnNw.isEmpty()) {
773                     LOG.debug("setting networks null in vpnMaps node: {} ", vpnId.getValue());
774                     vpnMapBuilder.setNetworkIds(null);
775                 } else {
776                     vpnMapBuilder.setNetworkIds(vpnNw);
777                 }
778             }
779
780             try (AcquireResult lock = tryVpnLock(vpnId)) {
781                 if (!lock.wasAcquired()) {
782                     // FIXME: why do we even bother with locking if we do not honor it?!
783                     logTryLockFailure(vpnId);
784                 }
785
786                 LOG.debug("clearing from vpnMaps node: {} ", vpnId.getValue());
787                 try {
788                     SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
789                         vpnMapIdentifier, vpnMapBuilder.build());
790                 } catch (TransactionCommitFailedException e) {
791                     LOG.error("Clearing from vpnMaps node failed for vpn {}", vpnId.getValue());
792                 }
793             }
794         } else {
795             LOG.error("VPN : {} not found", vpnId.getValue());
796         }
797         LOG.debug("Clear from VPNMaps DS successful for VPN {} ", vpnId.getValue());
798     }
799
800     private void deleteVpnInstance(Uuid vpnId) {
801         InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
802                 .child(VpnInstance.class,
803                         new VpnInstanceKey(vpnId.getValue()))
804                 .build();
805
806         try (AcquireResult lock = tryVpnLock(vpnId)) {
807             if (!lock.wasAcquired()) {
808                 // FIXME: why do we even bother with locking if we do not honor it?!
809                 logTryLockFailure(vpnId);
810             }
811
812             LOG.debug("Deleting vpnInstance {}", vpnId.getValue());
813             try {
814                 SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
815             } catch (TransactionCommitFailedException e) {
816                 LOG.error("Deletion of VPNInstance node failed for VPN {}", vpnId.getValue());
817             }
818         }
819     }
820
821     protected Adjacencies createPortIpAdjacencies(Port port, Boolean isRouterInterface,
822                                                   TypedWriteTransaction<Configuration> wrtConfigTxn,
823                                                   @Nullable VpnInterface vpnIface) {
824         List<Adjacency> adjList = new ArrayList<>();
825         if (vpnIface != null) {
826             adjList = new ArrayList<Adjacency>(vpnIface.augmentation(Adjacencies.class).getAdjacency().values());
827         }
828         String infName = port.getUuid().getValue();
829         LOG.trace("neutronVpnManager: create config adjacencies for Port: {}", infName);
830         for (FixedIps ip : port.nonnullFixedIps().values()) {
831             String ipValue = ip.getIpAddress().stringValue();
832             String ipPrefix = ip.getIpAddress().getIpv4Address() != null ? ipValue + "/32" : ipValue + "/128";
833             Subnetmap snTemp = neutronvpnUtils.getSubnetmap(ip.getSubnetId());
834             if (snTemp != null && !FibHelper.doesPrefixBelongToSubnet(ipPrefix,
835                     snTemp.getSubnetIp(), false)) {
836                 continue;
837             }
838             Uuid vpnId = snTemp != null ? snTemp.getVpnId() : null;
839             if (vpnId != null) {
840                 neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue,
841                         infName, port.getMacAddress().getValue(), isRouterInterface, wrtConfigTxn);
842                 //Create Neutron port adjacency if VPN presence is existing for subnet
843                 Adjacency vmAdj = new AdjacencyBuilder().withKey(new AdjacencyKey(ipPrefix)).setIpAddress(ipPrefix)
844                         .setMacAddress(port.getMacAddress().getValue()).setAdjacencyType(AdjacencyType.PrimaryAdjacency)
845                         .setSubnetId(ip.getSubnetId()).build();
846                 if (!adjList.contains(vmAdj)) {
847                     adjList.add(vmAdj);
848                 }
849             }
850             Uuid routerId = snTemp != null ? snTemp.getRouterId() : null;
851             if (snTemp != null && snTemp.getInternetVpnId() != null) {
852                 neutronvpnUtils.createVpnPortFixedIpToPort(snTemp.getInternetVpnId().getValue(),
853                     ipValue, infName, port.getMacAddress().getValue(), isRouterInterface, wrtConfigTxn);
854             }
855             if (routerId != null) {
856                 Router rtr = neutronvpnUtils.getNeutronRouter(routerId);
857                 if (rtr != null && rtr.getRoutes() != null) {
858                     List<Routes> routeList = new ArrayList<Routes>(rtr.getRoutes().values());
859                     // create extraroute Adjacence for each ipValue,
860                     // because router can have IPv4 and IPv6 subnet ports, or can have
861                     // more that one IPv4 subnet port or more than one IPv6 subnet port
862                     List<Adjacency> erAdjList = getAdjacencyforExtraRoute(routeList, ipValue);
863                     if (!erAdjList.isEmpty()) {
864                         adjList.addAll(erAdjList);
865                     }
866                 }
867             }
868         }
869         return new AdjacenciesBuilder().setAdjacency(getAdjacencyMap(adjList)).build();
870     }
871
872     private Map<AdjacencyKey, Adjacency> getAdjacencyMap(List<Adjacency> adjList) {
873         //convert to set to remove duplicates.
874         Set<Adjacency> adjset = adjList.stream().collect(Collectors.toSet());
875         Map<AdjacencyKey, Adjacency> adjacencyMap = new HashMap<>();
876         for (Adjacency adj : adjset) {
877             adjacencyMap.put(new AdjacencyKey(adj.getIpAddress()), adj);
878         }
879         return adjacencyMap;
880     }
881
882     protected void createVpnInterface(Collection<Uuid> vpnIds, Port port,
883                                       @Nullable TypedWriteTransaction<Configuration> wrtConfigTxn) {
884         boolean isRouterInterface = false;
885         if (port.getDeviceOwner() != null) {
886             isRouterInterface = NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(port.getDeviceOwner());
887         }
888         String infName = port.getUuid().getValue();
889         // Handling cluster reboot scenario where VpnInterface already exists in datastore.
890         VpnInterface vpnIface = VpnHelper.getVpnInterface(dataBroker, infName);
891         Adjacencies adjs = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, vpnIface);
892         LOG.trace("createVpnInterface for Port: {}, isRouterInterface: {}", infName, isRouterInterface);
893         writeVpnInterfaceToDs(vpnIds, infName, adjs, port.getNetworkId(), isRouterInterface, wrtConfigTxn);
894     }
895
896     protected void withdrawPortIpFromVpnIface(Uuid vpnId, Uuid internetVpnId,
897                        Port port, Subnetmap sn, TypedWriteTransaction<Configuration> wrtConfigTxn) {
898         String infName = port.getUuid().getValue();
899         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
900         Optional<VpnInterface> optionalVpnInterface = null;
901         LOG.debug("withdrawPortIpFromVpnIface vpn {} internetVpn {} Port {}",
902                   vpnId, internetVpnId, infName);
903         try {
904             optionalVpnInterface = SingleTransactionDataBroker
905                     .syncReadOptional(dataBroker, LogicalDatastoreType
906                     .CONFIGURATION, vpnIfIdentifier);
907         } catch (ExecutionException | InterruptedException e) {
908             LOG.error("withdrawPortIpFromVpnIface: Error reading the VPN interface for {}", vpnIfIdentifier, e);
909             return;
910         }
911         if (!optionalVpnInterface.isPresent()) {
912             return;
913         }
914         LOG.trace("withdraw adjacencies for Port: {} subnet {}", port.getUuid().getValue(),
915                 sn != null ? sn.getSubnetIp() : "null");
916         Map<AdjacencyKey, Adjacency> keyAdjacencyMap
917                 = optionalVpnInterface.get().augmentation(Adjacencies.class).nonnullAdjacency();
918         List<Adjacency> updatedAdjsList = new ArrayList<>();
919         boolean isIpFromAnotherSubnet = false;
920         for (Adjacency adj : keyAdjacencyMap.values()) {
921             String adjString = FibHelper.getIpFromPrefix(adj.getIpAddress());
922             if (sn == null || !Objects.equals(adj.getSubnetId(), sn.getId())) {
923                 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
924                     isIpFromAnotherSubnet = true;
925                 }
926                 updatedAdjsList.add(adj);
927                 continue;
928             }
929             if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
930                 LOG.error("withdrawPortIpFromVpnIface: suppressing primaryAdjacency {} FixedIp for vpnId {}",
931                       adjString, vpnId);
932                 if (vpnId != null) {
933                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(),
934                             String.valueOf(adjString), wrtConfigTxn);
935                 }
936                 if (internetVpnId != null) {
937                     neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
938                           String.valueOf(adjString), wrtConfigTxn);
939                 }
940             } else {
941                 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(port.getDeviceOwner())
942                         && sn.getRouterId() != null) {
943                     Router rtr = neutronvpnUtils.getNeutronRouter(sn.getRouterId());
944                     if (rtr != null && rtr.getRoutes() != null) {
945                         List<Routes> extraRoutesToRemove = new ArrayList<>();
946                         for (Routes rt: rtr.getRoutes().values()) {
947                             if (rt.getNexthop().toString().equals(adjString)) {
948                                 extraRoutesToRemove.add(rt);
949                             }
950                         }
951                         if (vpnId != null) {
952                             LOG.error("withdrawPortIpFromVpnIface: suppressing extraRoute {} for vpnId {}",
953                                   extraRoutesToRemove, vpnId);
954                             removeAdjacencyforExtraRoute(vpnId, extraRoutesToRemove);
955                         }
956                         /* removeAdjacencyforExtraRoute done also for internet-vpn-id, in previous call */
957                     }
958                 }
959             }
960         }
961         Adjacencies adjacencies = new AdjacenciesBuilder().setAdjacency(getAdjacencyMap(updatedAdjsList)).build();
962         if (vpnId != null) {
963             updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, wrtConfigTxn);
964         }
965         if (!isIpFromAnotherSubnet) {
966             // no more subnetworks for neutron port
967             if (sn != null && sn.getRouterId() != null) {
968                 removeFromNeutronRouterInterfacesMap(sn.getRouterId(), port.getUuid().getValue());
969             }
970             deleteVpnInterface(infName, null /* vpn-id */, wrtConfigTxn);
971             return;
972         }
973         return;
974     }
975
976     // TODO Clean up the exception handling
977     @SuppressWarnings("checkstyle:IllegalCatch")
978     protected void deleteVpnInterface(String infName, @Nullable String vpnId,
979                                       @Nullable TypedWriteTransaction<Configuration> wrtConfigTxn) {
980         if (wrtConfigTxn == null) {
981             LoggingFutures.addErrorLogging(
982                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
983                         tx -> deleteVpnInterface(infName, vpnId, tx)),
984                     LOG, "Error deleting VPN interface {} {}", infName, vpnId);
985             return;
986         }
987
988         InstanceIdentifier<VpnInterface> vpnIfIdentifier =
989             NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
990         Optional<VpnInterface> optionalVpnInterface;
991         try {
992             optionalVpnInterface =
993                 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
994                             vpnIfIdentifier);
995         } catch (ExecutionException | InterruptedException ex) {
996             LOG.error("Error during deletion of vpninterface {}", infName, ex);
997             return;
998         }
999         if (!optionalVpnInterface.isPresent()) {
1000             LOG.warn("Deletion of vpninterface {}, optionalVpnInterface is not present()", infName);
1001             return;
1002         }
1003         if (vpnId != null) {
1004             VpnInterface vpnInterface = optionalVpnInterface.get();
1005             Map<VpnInstanceNamesKey, VpnInstanceNames> keyVpnInstanceNamesMap = vpnInterface.getVpnInstanceNames();
1006             if (keyVpnInstanceNamesMap != null
1007                 && VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId,
1008                     new ArrayList<VpnInstanceNames>(keyVpnInstanceNamesMap.values()))) {
1009                 VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId,
1010                         new ArrayList<VpnInstanceNames>(keyVpnInstanceNamesMap.values()));
1011                 if (!keyVpnInstanceNamesMap.isEmpty()) {
1012                     LOG.debug("Deleting vpn interface {} not immediately since vpnInstanceName "
1013                             + "List not empty", infName);
1014                     return;
1015                 }
1016                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
1017                         .setVpnInstanceNames(keyVpnInstanceNamesMap);
1018                 wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder
1019                         .build());
1020             }
1021         }
1022         LOG.debug("Deleting vpn interface {}", infName);
1023         wrtConfigTxn.delete(vpnIfIdentifier);
1024     }
1025
1026     protected void removeInternetVpnFromVpnInterface(Uuid vpnId, Port port,
1027                                              TypedWriteTransaction<Configuration> writeConfigTxn,
1028                                              Subnetmap sm) {
1029         if (vpnId == null || port == null) {
1030             return;
1031         }
1032         String infName = port.getUuid().getValue();
1033         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
1034         try {
1035             Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker
1036                     .syncReadOptional(dataBroker, LogicalDatastoreType
1037                     .CONFIGURATION, vpnIfIdentifier);
1038             if (optionalVpnInterface.isPresent()) {
1039                 Map<VpnInstanceNamesKey, VpnInstanceNames> keyVpnInstanceNamesMap
1040                         = optionalVpnInterface.get().getVpnInstanceNames();
1041                 if (keyVpnInstanceNamesMap != null
1042                     && VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(),
1043                         new ArrayList<VpnInstanceNames>(keyVpnInstanceNamesMap.values()))) {
1044                     VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId.getValue(),
1045                             new ArrayList<VpnInstanceNames>(keyVpnInstanceNamesMap.values()));
1046                 }
1047                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
1048                          .setVpnInstanceNames(keyVpnInstanceNamesMap);
1049                 Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
1050                 LOG.debug("Updating vpn interface {}", infName);
1051                 Map<AdjacencyKey, Adjacency> keyAdjacencyMap = adjs != null ? adjs.getAdjacency() : new HashMap<>();
1052                 Iterator<Adjacency> adjacencyIter = keyAdjacencyMap.values().iterator();
1053                 while (adjacencyIter.hasNext()) {
1054                     Adjacency adjacency = adjacencyIter.next();
1055                     if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
1056                         continue;
1057                     }
1058                     String mipToQuery = adjacency.getIpAddress().split("/")[0];
1059                     InstanceIdentifier<LearntVpnVipToPort> id =
1060                         NeutronvpnUtils.buildLearntVpnVipToPortIdentifier(vpnId.getValue(), mipToQuery);
1061                     Optional<LearntVpnVipToPort> optionalVpnVipToPort =
1062                             SingleTransactionDataBroker.syncReadOptional(dataBroker,
1063                                     LogicalDatastoreType.OPERATIONAL, id);
1064                     if (optionalVpnVipToPort.isPresent()) {
1065                         LOG.trace("Removing adjacencies from vpninterface {} upon dissociation of router {}",
1066                              infName, vpnId);
1067                         if (keyVpnInstanceNamesMap == null || keyVpnInstanceNamesMap.isEmpty()) {
1068                             adjacencyIter.remove();
1069                         }
1070                         neutronvpnUtils.removeLearntVpnVipToPort(vpnId.getValue(), mipToQuery);
1071                         LOG.trace("Entry for fixedIP {} for port {} on VPN {} removed from VpnPortFixedIPToPortData",
1072                                 mipToQuery, infName, vpnId.getValue());
1073                     }
1074                 }
1075                 for (FixedIps ip : port.nonnullFixedIps().values()) {
1076                     String ipValue = ip.getIpAddress().stringValue();
1077                     //skip IPv4 address
1078                     if (!NeutronvpnUtils.getIpVersionFromString(ipValue).isIpVersionChosen(IpVersionChoice.IPV6)) {
1079                         continue;
1080                     }
1081                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(),
1082                             ipValue, writeConfigTxn);
1083                 }
1084                 if (keyVpnInstanceNamesMap == null || keyVpnInstanceNamesMap.isEmpty()) {
1085                     if (sm != null && sm.getRouterId() != null) {
1086                         removeFromNeutronRouterInterfacesMap(sm.getRouterId(), port.getUuid().getValue());
1087                     }
1088                     deleteVpnInterface(port.getUuid().getValue(), null /* vpn-id */, writeConfigTxn);
1089                 } else {
1090                     writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
1091                 }
1092             } else {
1093                 LOG.info("removeVpnFromVpnInterface: VPN Interface {} not found", infName);
1094             }
1095         } catch (ExecutionException | InterruptedException ex) {
1096             LOG.error("Update of vpninterface {} failed", infName, ex);
1097         }
1098     }
1099
1100     protected void updateVpnInterface(Uuid vpnId, @Nullable Uuid oldVpnId, Port port, boolean isBeingAssociated,
1101                                       boolean isSubnetIp,
1102                                       TypedWriteTransaction<Configuration> writeConfigTxn,
1103                                       boolean isInternetVpn) {
1104         if (vpnId == null || port == null) {
1105             return;
1106         }
1107         String infName = port.getUuid().getValue();
1108         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
1109
1110         try (AcquireResult lock = tryInterfaceLock(infName)) {
1111             if (!lock.wasAcquired()) {
1112                 // FIXME: why do we even bother with locking if we do not honor it?!
1113                 logTryLockFailure(infName);
1114             }
1115
1116             try {
1117                 Optional<VpnInterface> optionalVpnInterface =
1118                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1119                             vpnIfIdentifier);
1120                 if (optionalVpnInterface.isPresent()) {
1121                     VpnInstanceNames vpnInstance = VpnHelper
1122                             .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
1123                     List<VpnInstanceNames> listVpn = new ArrayList<>(optionalVpnInterface.get()
1124                             .getVpnInstanceNames().values());
1125                     if (oldVpnId != null
1126                             && VpnHelper.doesVpnInterfaceBelongToVpnInstance(oldVpnId.getValue(), listVpn)) {
1127                         VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(oldVpnId.getValue(), listVpn);
1128                     }
1129                     if (vpnId.getValue() != null
1130                             && !VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpn)) {
1131                         listVpn.add(vpnInstance);
1132                     }
1133                     VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
1134                             .setVpnInstanceNames(listVpn);
1135                     LOG.debug("Updating vpn interface {}", infName);
1136                     if (!isBeingAssociated) {
1137                         Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
1138                         Map<AdjacencyKey, Adjacency> keyAdjacencyMap = adjs != null ? adjs.getAdjacency()
1139                                 : new HashMap<AdjacencyKey, Adjacency>();
1140                         Iterator<Adjacency> adjacencyIter = keyAdjacencyMap.values().iterator();
1141                         while (adjacencyIter.hasNext()) {
1142                             Adjacency adjacency = adjacencyIter.next();
1143                             String mipToQuery = adjacency.getIpAddress().split("/")[0];
1144                             InstanceIdentifier<LearntVpnVipToPort> id =
1145                                     NeutronvpnUtils.buildLearntVpnVipToPortIdentifier(oldVpnId.getValue(), mipToQuery);
1146                             Optional<LearntVpnVipToPort> optionalVpnVipToPort =
1147                                     SingleTransactionDataBroker.syncReadOptional(dataBroker,
1148                                         LogicalDatastoreType.OPERATIONAL, id);
1149                             if (optionalVpnVipToPort.isPresent()
1150                                     && optionalVpnVipToPort.get().getPortName().equals(infName)) {
1151                                 LOG.trace("Removing adjacencies from vpninterface {} upon dissociation of router {} "
1152                                         + "from VPN {}", infName, vpnId, oldVpnId);
1153                                 adjacencyIter.remove();
1154                                 neutronvpnUtils.removeLearntVpnVipToPort(oldVpnId.getValue(), mipToQuery);
1155                                 LOG.trace(
1156                                     "Entry for fixedIP {} for port {} on VPN {} removed from LearntVpnVipToPort",
1157                                     mipToQuery, infName, vpnId.getValue());
1158                             }
1159                             InstanceIdentifier<VpnPortipToPort> build =
1160                                     NeutronvpnUtils.buildVpnPortipToPortIdentifier(oldVpnId.getValue(), mipToQuery);
1161                             Optional<VpnPortipToPort> persistedIp = SingleTransactionDataBroker.syncReadOptional(
1162                                 dataBroker, LogicalDatastoreType.OPERATIONAL, build);
1163                             if (persistedIp.isPresent() && persistedIp.get().getPortName().equals(infName)) {
1164                                 neutronvpnUtils.removeVpnPortFixedIpToPort(oldVpnId.getValue(), mipToQuery, null);
1165                                 LOG.trace("Entry for fixedIP {} for port {} on VPN {} removed from VpnPortipToPort",
1166                                     mipToQuery, infName, vpnId.getValue());
1167                             }
1168                         }
1169                         Adjacencies adjacencies = new AdjacenciesBuilder().setAdjacency(keyAdjacencyMap).build();
1170                         vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
1171                     }
1172                     for (FixedIps ip : port.nonnullFixedIps().values()) {
1173                         String ipValue = ip.getIpAddress().stringValue();
1174                         if (oldVpnId != null) {
1175                             neutronvpnUtils.removeVpnPortFixedIpToPort(oldVpnId.getValue(),
1176                                 ipValue, writeConfigTxn);
1177                         }
1178                         if (NeutronvpnUtils.getIpVersionFromString(ipValue) != IpVersionChoice.IPV6
1179                                 && isInternetVpn == true) {
1180                             continue;
1181                         }
1182
1183                         neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue, infName, port
1184                             .getMacAddress().getValue(), isSubnetIp, writeConfigTxn);
1185                     }
1186                     writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
1187                 } else {
1188                     LOG.error("VPN Interface {} not found", infName);
1189                 }
1190             } catch (ExecutionException | InterruptedException ex) {
1191                 LOG.error("Updation of vpninterface {} failed", infName, ex);
1192             }
1193         }
1194     }
1195
1196     public void createL3InternalVpn(Uuid vpnId, String name, Uuid tenantId, List<String> rdList, List<String> irtList,
1197                                     List<String> ertList, Uuid routerId, List<Uuid> networksList) {
1198
1199         IpVersionChoice ipVersChoices = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(routerId);
1200
1201         // Update VPN Instance node
1202         updateVpnInstanceNode(vpnId, rdList, irtList, ertList, false /*isL2Vpn*/, 0 /*l3vni*/, ipVersChoices);
1203
1204         // Update local vpn-subnet DS
1205         updateVpnMaps(vpnId, name, routerId, tenantId, networksList);
1206
1207         if (routerId != null) {
1208             Uuid existingVpn = neutronvpnUtils.getVpnForRouter(routerId, true);
1209             if (existingVpn != null) {
1210                 // use case when a cluster is rebooted and router add DCN is received, triggering #createL3InternalVpn
1211                 // if before reboot, router was already associated to VPN, should not proceed associating router to
1212                 // internal VPN. Adding to RouterInterfacesMap is also not needed since it's a config DS and will be
1213                 // preserved upon reboot.
1214                 // For a non-reboot case #associateRouterToInternalVPN already takes care of adding to
1215                 // RouterInterfacesMap via #createVPNInterface call.
1216                 LOG.info("Associating router to Internal VPN skipped for VPN {} due to router {} already associated "
1217                         + "to external VPN {}", vpnId.getValue(), routerId.getValue(), existingVpn.getValue());
1218                 return;
1219             }
1220             associateRouterToInternalVpn(vpnId, routerId);
1221         }
1222     }
1223
1224     /**
1225      * Performs the creation of a Neutron L3VPN, associating the new VPN to the
1226      * specified Neutron Networks and Routers.
1227      *
1228      * @param vpnId Uuid of the VPN tp be created
1229      * @param name Representative name of the new VPN
1230      * @param tenantId Uuid of the Tenant under which the VPN is going to be created
1231      * @param rdList Route-distinguisher for the VPN
1232      * @param irtList A list of Import Route Targets
1233      * @param ertList A list of Export Route Targets
1234      * @param routerIdsList ist of neutron router Id to associate with created VPN
1235      * @param networkList UUID of the neutron network the VPN may be associated to
1236      * @param isL2Vpn True if VPN Instance is of type L2, false if L3
1237      * @param l3vni L3VNI for the VPN Instance using VxLAN as the underlay
1238      * @throws Exception if association of L3VPN failed
1239      */
1240     public void createVpn(Uuid vpnId, String name, Uuid tenantId, List<String> rdList, List<String> irtList,
1241                     List<String> ertList,  @Nullable List<Uuid> routerIdsList, @Nullable List<Uuid> networkList,
1242                           boolean isL2Vpn, long l3vni) throws Exception {
1243
1244         IpVersionChoice ipVersChoices = IpVersionChoice.UNDEFINED;
1245
1246         if (routerIdsList != null && !routerIdsList.isEmpty()) {
1247             for (Uuid routerId : routerIdsList) {
1248                 IpVersionChoice vers = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(routerId);
1249                 ipVersChoices = ipVersChoices.addVersion(vers);
1250             }
1251         }
1252         updateVpnInstanceNode(vpnId, rdList, irtList, ertList, isL2Vpn, l3vni, ipVersChoices);
1253
1254         // Please note that router and networks will be filled into VPNMaps
1255         // by subsequent calls here to associateRouterToVpn and
1256         // associateNetworksToVpn
1257         updateVpnMaps(vpnId, name, null, tenantId, null);
1258         LOG.debug("Created L3VPN with ID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, routerIdsList {}, "
1259                         + "networkList {}", vpnId.getValue(), name, tenantId, rdList, irtList, ertList, routerIdsList,
1260                 networkList);
1261
1262         if (routerIdsList != null && !routerIdsList.isEmpty()) {
1263             for (Uuid routerId : routerIdsList) {
1264                 associateRouterToVpn(vpnId, routerId);
1265             }
1266         }
1267         if (networkList != null) {
1268             List<String> failStrings = associateNetworksToVpn(vpnId, networkList);
1269             if (!failStrings.isEmpty()) {
1270                 LOG.error("VPN {} association to networks failed for networks: {}. ",
1271                         vpnId.getValue(), failStrings);
1272                 throw new Exception(failStrings.toString());
1273             }
1274         }
1275     }
1276
1277     /**
1278      * It handles the invocations to the createVPN RPC method.
1279      */
1280     @Override
1281     // TODO Clean up the exception handling
1282     @SuppressWarnings("checkstyle:IllegalCatch")
1283     public ListenableFuture<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
1284
1285         CreateL3VPNOutputBuilder opBuilder = new CreateL3VPNOutputBuilder();
1286         SettableFuture<RpcResult<CreateL3VPNOutput>> result = SettableFuture.create();
1287         List<RpcError> errorList = new ArrayList<>();
1288         int failurecount = 0;
1289         int warningcount = 0;
1290
1291         List<L3vpn> vpns = input.getL3vpn();
1292         if (vpns == null) {
1293             vpns = Collections.emptyList();
1294         }
1295         for (L3vpn vpn : vpns) {
1296             if (neutronvpnUtils.doesVpnExist(vpn.getId())) {
1297                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1298                         formatAndLog(LOG::warn,
1299                                 "Creation of L3VPN failed for VPN {} due to VPN with the same ID already present",
1300                                 vpn.getId().getValue())));
1301                 warningcount++;
1302                 continue;
1303             }
1304             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
1305                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1306                         formatAndLog(LOG::warn,
1307                                 "Creation of L3VPN failed for VPN {} due to absence of RD/iRT/eRT input",
1308                                 vpn.getId().getValue())));
1309                 warningcount++;
1310                 continue;
1311             }
1312             long l3vni = 0;
1313             if (vpn.getL3vni() != null) {
1314                 l3vni = vpn.getL3vni().toJava();
1315             }
1316
1317             List<String> existingRDs = neutronvpnUtils.getExistingRDs();
1318             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
1319                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1320                         formatAndLog(LOG::warn,
1321                                 "Creation of L3VPN failed for VPN {} as another VPN with the same RD {} "
1322                                         + "is already configured",
1323                                 vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0))));
1324                 warningcount++;
1325                 continue;
1326             }
1327             Optional<String> operationalVpn = getExistingOperationalVpn(vpn.getRouteDistinguisher().get(0));
1328             if (operationalVpn.isPresent()) {
1329                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION, "application-error",
1330                         formatAndLog(LOG::error,
1331                                 "Creation of L3VPN failed for VPN {} as another VPN {} with the same RD {} "
1332                                         + "is still available. Please retry creation of a new vpn with the same RD"
1333                                         + " after a couple of minutes.", vpn.getId().getValue(), operationalVpn.get(),
1334                                 vpn.getRouteDistinguisher().get(0))));
1335                 warningcount++;
1336                 continue;
1337             }
1338             if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
1339                 Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt
1340                         .neutronvpn.rev150602.vpn.instance.RouterIdsKey, org.opendaylight.yang.gen.v1.urn.opendaylight
1341                         .netvirt.neutronvpn.rev150602.vpn.instance.RouterIds> keyRouterIdsMap = vpn.getRouterIds();
1342                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
1343                         routerId : keyRouterIdsMap.values()) {
1344                     if (neutronvpnUtils.getNeutronRouter(routerId.getRouterId()) == null) {
1345                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1346                                 formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to absense of routers"
1347                                         + "{}", vpn.getId(), routerId.getRouterId())));
1348                         warningcount++;
1349                         continue;
1350                     }
1351                     Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
1352                     if (vpnId != null) {
1353                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1354                                 formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to router {} already "
1355                                                 + "associated to another VPN {}", vpn.getId(), routerId.getRouterId(),
1356                                         vpnId.getValue())));
1357                         warningcount++;
1358                         continue;
1359                     }
1360                 }
1361             }
1362             if (vpn.getNetworkIds() != null) {
1363                 int initialWarningCount = warningcount;
1364                 for (Uuid nw : vpn.getNetworkIds()) {
1365                     Network network = neutronvpnUtils.getNeutronNetwork(nw);
1366                     Uuid vpnId = neutronvpnUtils.getVpnForNetwork(nw);
1367                     if (network == null) {
1368                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1369                                 formatAndLog(LOG::warn,
1370                                         "Creation of L3VPN failed for VPN {} due to network not found {}",
1371                                         vpn.getId().getValue(), nw.getValue())));
1372                         warningcount++;
1373                     } else if (vpnId != null) {
1374                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1375                                 formatAndLog(LOG::warn,
1376                                         "Creation of L3VPN failed for VPN {} due to network {} already associated"
1377                                                 + " to another VPN {}", vpn.getId().getValue(), nw.getValue(),
1378                                         vpnId.getValue())));
1379                         warningcount++;
1380                     }
1381                 }
1382                 if (warningcount != initialWarningCount) {
1383                     continue;
1384                 }
1385             }
1386             List<Uuid> rtrIdsList = new ArrayList<>();
1387             if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
1388                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
1389                         rtrId : vpn.getRouterIds().values()) {
1390                     rtrIdsList.add(rtrId.getRouterId());
1391                 }
1392             }
1393             try {
1394                 LOG.debug("L3VPN add RPC: VpnID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, "
1395                                 + "routerIdList {}, networksList {}", vpn.getId().getValue(), vpn.getName(),
1396                         vpn.getTenantId(), vpn.getRouteDistinguisher(), vpn.getImportRT(),
1397                         vpn.getExportRT(), rtrIdsList, vpn.getNetworkIds());
1398
1399                 List<String> rdList = vpn.getRouteDistinguisher() != null
1400                         ? new ArrayList<>(vpn.getRouteDistinguisher()) : new ArrayList<>();
1401                 List<String> importRdList = vpn.getImportRT() != null
1402                         ? new ArrayList<>(vpn.getImportRT()) : new ArrayList<>();
1403                 List<String> exportRdList = vpn.getExportRT() != null
1404                         ? new ArrayList<>(vpn.getExportRT()) : new ArrayList<>();
1405
1406                 createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), rdList,
1407                         importRdList, exportRdList, rtrIdsList, vpn.getNetworkIds(), false /*isL2Vpn*/, l3vni);
1408             } catch (Exception ex) {
1409                 LOG.error("VPN Creation exception :", ex);
1410                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION,
1411                         formatAndLog(LOG::error, "Creation of VPN failed for VPN {}", vpn.getId().getValue(), ex),
1412                         ex.getMessage()));
1413                 failurecount++;
1414             }
1415         }
1416         // if at least one succeeds; result is success
1417         // if none succeeds; result is failure
1418         if (failurecount + warningcount == vpns.size()) {
1419             result.set(RpcResultBuilder.<CreateL3VPNOutput>failed().withRpcErrors(errorList).build());
1420         } else {
1421             List<String> errorResponseList = new ArrayList<>();
1422             if (!errorList.isEmpty()) {
1423                 for (RpcError rpcError : errorList) {
1424                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
1425                             + ", ErrorMessage: " + rpcError.getMessage());
1426                 }
1427             } else {
1428                 errorResponseList.add("Operation successful with no errors");
1429             }
1430             opBuilder.setResponse(errorResponseList);
1431             result.set(RpcResultBuilder.<CreateL3VPNOutput>success().withResult(opBuilder.build()).build());
1432         }
1433         return result;
1434     }
1435
1436     /**
1437      * It handles the invocations to the neutronvpn:getL3VPN RPC method.
1438      */
1439     @Override
1440     public ListenableFuture<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
1441
1442         GetL3VPNOutputBuilder opBuilder = new GetL3VPNOutputBuilder();
1443         SettableFuture<RpcResult<GetL3VPNOutput>> result = SettableFuture.create();
1444         Uuid inputVpnId = input.getId();
1445         List<VpnInstance> vpns = new ArrayList<>();
1446         List<L3vpnInstances> l3vpnList = new ArrayList<>();
1447
1448         try {
1449             if (inputVpnId == null) {
1450                 // get all vpns
1451                 InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class)
1452                         .build();
1453                 Optional<VpnInstances> optionalVpns =
1454                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1455                                 vpnsIdentifier);
1456                 if (optionalVpns.isPresent() && !optionalVpns.get().getVpnInstance().isEmpty()) {
1457                     for (VpnInstance vpn : optionalVpns.get().nonnullVpnInstance().values()) {
1458                         // eliminating implicitly created (router and VLAN provider external network specific) VPNs
1459                         // from getL3VPN output
1460                         if (vpn.getRouteDistinguisher() != null) {
1461                             vpns.add(vpn);
1462                         }
1463                     }
1464                 } else {
1465                     // No VPN present
1466                     opBuilder.setL3vpnInstances(l3vpnList);
1467                     result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1468                     return result;
1469                 }
1470             } else {
1471                 String name = inputVpnId.getValue();
1472                 InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
1473                         .child(VpnInstance.class, new VpnInstanceKey(name)).build();
1474                 // read VpnInstance Info
1475                 Optional<VpnInstance> optionalVpn =
1476                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1477                                 vpnIdentifier);
1478                 // eliminating implicitly created (router or VLAN provider external network specific) VPN from
1479                 // getL3VPN output
1480                 if (optionalVpn.isPresent() && optionalVpn.get().getRouteDistinguisher() != null) {
1481                     vpns.add(optionalVpn.get());
1482                 } else {
1483                     result.set(
1484                             RpcResultBuilder.<GetL3VPNOutput>failed().withWarning(ErrorType.PROTOCOL, "invalid-value",
1485                                     formatAndLog(LOG::error, "GetL3VPN failed because VPN {} is not present",
1486                                             name)).build());
1487                 }
1488             }
1489             for (VpnInstance vpnInstance : vpns) {
1490                 Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
1491                 // create VpnMaps id
1492                 L3vpnInstancesBuilder l3vpn = new L3vpnInstancesBuilder();
1493                 List<String> rd = Collections.EMPTY_LIST;
1494                 if (vpnInstance.getRouteDistinguisher() != null) {
1495                     rd = vpnInstance.getRouteDistinguisher();
1496                 }
1497                 List<String> ertList = new ArrayList<>();
1498                 List<String> irtList = new ArrayList<>();
1499
1500                 if (vpnInstance.getVpnTargets() != null) {
1501                     Map<VpnTargetKey, VpnTarget> keyVpnTargetMap = Collections.EMPTY_MAP;
1502                     if (!vpnInstance.getVpnTargets().getVpnTarget().isEmpty()) {
1503                         keyVpnTargetMap = vpnInstance.getVpnTargets().getVpnTarget();
1504                     }
1505                     if (!keyVpnTargetMap.isEmpty()) {
1506                         for (VpnTarget vpnTarget : keyVpnTargetMap.values()) {
1507                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
1508                                 ertList.add(vpnTarget.getVrfRTValue());
1509                             }
1510                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
1511                                 irtList.add(vpnTarget.getVrfRTValue());
1512                             }
1513                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
1514                                 ertList.add(vpnTarget.getVrfRTValue());
1515                                 irtList.add(vpnTarget.getVrfRTValue());
1516                             }
1517                         }
1518                     }
1519                 }
1520
1521                 l3vpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
1522
1523                 if (vpnInstance.getL3vni() != null) {
1524                     l3vpn.setL3vni(vpnInstance.getL3vni());
1525                 }
1526                 InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
1527                         .class, new VpnMapKey(vpnId)).build();
1528                 Optional<VpnMap> optionalVpnMap =
1529                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1530                                 vpnMapIdentifier);
1531                 if (optionalVpnMap.isPresent()) {
1532                     VpnMap vpnMap = optionalVpnMap.get();
1533                     List<Uuid> rtrIds = new ArrayList<>();
1534                     if (vpnMap.getRouterIds() != null && !vpnMap.getRouterIds().isEmpty()) {
1535                         for (RouterIds rtrId : vpnMap.getRouterIds().values()) {
1536                             rtrIds.add(rtrId.getRouterId());
1537                         }
1538                     }
1539                     l3vpn.setRouterIds(NeutronvpnUtils.getVpnInstanceRouterIdsList(rtrIds))
1540                             .setNetworkIds(vpnMap.getNetworkIds()).setTenantId(vpnMap.getTenantId())
1541                             .setName(vpnMap.getName());
1542
1543                 }
1544                 l3vpnList.add(l3vpn.build());
1545             }
1546
1547             opBuilder.setL3vpnInstances(l3vpnList);
1548             result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1549
1550         } catch (ExecutionException | InterruptedException ex) {
1551             result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withError(ErrorType.APPLICATION,
1552                     formatAndLog(LOG::error, "GetVPN failed due to {}", ex.getMessage())).build());
1553         }
1554         return result;
1555     }
1556
1557     /**
1558      * It handles the invocations to the neutronvpn:deleteL3VPN RPC method.
1559      */
1560     @Override
1561     public ListenableFuture<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
1562
1563         DeleteL3VPNOutputBuilder opBuilder = new DeleteL3VPNOutputBuilder();
1564         SettableFuture<RpcResult<DeleteL3VPNOutput>> result = SettableFuture.create();
1565         List<RpcError> errorList = new ArrayList<>();
1566
1567         int failurecount = 0;
1568         int warningcount = 0;
1569         List<Uuid> vpns = input.getId() != null ? input.getId() : Collections.emptyList();
1570         for (Uuid vpn : vpns) {
1571             try {
1572                 LOG.debug("L3VPN delete RPC: VpnID {}", vpn.getValue());
1573                 InstanceIdentifier<VpnInstance> vpnIdentifier =
1574                         InstanceIdentifier.builder(VpnInstances.class)
1575                             .child(VpnInstance.class, new VpnInstanceKey(vpn.getValue())).build();
1576                 Optional<VpnInstance> optionalVpn =
1577                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1578                                 vpnIdentifier);
1579                 if (optionalVpn.isPresent()) {
1580                     removeVpn(vpn);
1581                 } else {
1582                     errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-value",
1583                             formatAndLog(LOG::warn, "VPN with vpnid: {} does not exist", vpn.getValue())));
1584                     warningcount++;
1585                 }
1586             } catch (ExecutionException | InterruptedException ex) {
1587                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION,
1588                         formatAndLog(LOG::error, "Deletion of L3VPN failed when deleting for uuid {}", vpn.getValue()),
1589                         ex.getMessage()));
1590                 failurecount++;
1591             }
1592         }
1593         // if at least one succeeds; result is success
1594         // if none succeeds; result is failure
1595         if (failurecount + warningcount == vpns.size()) {
1596             result.set(RpcResultBuilder.<DeleteL3VPNOutput>failed().withRpcErrors(errorList).build());
1597         } else {
1598             List<String> errorResponseList = new ArrayList<>();
1599             if (!errorList.isEmpty()) {
1600                 for (RpcError rpcError : errorList) {
1601                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
1602                             + ", ErrorMessage: " + rpcError.getMessage());
1603                 }
1604             } else {
1605                 errorResponseList.add("Operation successful with no errors");
1606             }
1607             opBuilder.setResponse(errorResponseList);
1608             result.set(RpcResultBuilder.<DeleteL3VPNOutput>success().withResult(opBuilder.build()).build());
1609         }
1610         return result;
1611     }
1612
1613     public void createVpnInstanceForSubnet(Uuid subnetId) {
1614         LOG.debug("Creating/Updating L3 internalVPN for subnetID {} ", subnetId);
1615         createL3InternalVpn(subnetId, subnetId.getValue(), null, null, null, null, null, null);
1616     }
1617
1618     public void removeVpnInstanceForSubnet(Uuid subnetId) {
1619         LOG.debug("Removing vpn-instance for subnetID {} ", subnetId);
1620         removeVpn(subnetId);
1621     }
1622
1623     protected void addSubnetToVpn(@Nullable final Uuid vpnId, Uuid subnet, @Nullable final Uuid internetVpnId) {
1624         LOG.debug("addSubnetToVpn: Adding subnet {} to vpn {}", subnet.getValue(),
1625                   vpnId != null ? vpnId.getValue() : internetVpnId.getValue());
1626         Subnetmap sn = updateSubnetNode(subnet, null, vpnId, internetVpnId);
1627         if (sn == null) {
1628             LOG.error("addSubnetToVpn: subnetmap is null, cannot add subnet {} to VPN {}", subnet.getValue(),
1629                 vpnId != null ? vpnId.getValue() : internetVpnId.getValue());
1630             return;
1631         }
1632         if (vpnId != null) {
1633             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
1634             if (vpnMap == null) {
1635                 LOG.error("addSubnetToVpn: No vpnMap for vpnId {},"
1636                      + " cannot add subnet {} to VPN", vpnId.getValue(),
1637                     subnet.getValue());
1638                 return;
1639             }
1640             final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
1641             LOG.debug("addSubnetToVpn: VpnInstance {}", vpnInstance);
1642             if (isVpnOfTypeL2(vpnInstance)) {
1643                 neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
1644                         NeutronEvpnUtils.Operation.ADD);
1645             }
1646         }
1647         if (internetVpnId != null) {
1648             VpnMap vpnMap = neutronvpnUtils.getVpnMap(internetVpnId);
1649             if (vpnMap == null) {
1650                 LOG.error("addSubnetToVpn: No vpnMap for InternetVpnId {}, cannot add "
1651                     + "subnet {} to VPN", internetVpnId.getValue(),
1652                     subnet.getValue());
1653                 return;
1654             }
1655         }
1656         final Uuid internetId = internetVpnId;
1657         // Check if there are ports on this subnet and add corresponding vpn-interfaces
1658         List<Uuid> portList = sn.getPortList();
1659         if (portList != null) {
1660             for (final Uuid portId : portList) {
1661                 String vpnInfName = portId.getValue();
1662                 VpnInterface vpnIface = VpnHelper.getVpnInterface(dataBroker, vpnInfName);
1663                 Port port = neutronvpnUtils.getNeutronPort(portId);
1664                 if (port == null) {
1665                     LOG.error("addSubnetToVpn: Cannot proceed with addSubnetToVpn for port {} in subnet {} "
1666                         + "since port is absent in Neutron config DS", portId.getValue(), subnet.getValue());
1667                     continue;
1668                 }
1669                 final Boolean isRouterInterface = port.getDeviceOwner()
1670                         .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) ? true : false;
1671                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1672                     ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1673                         wrtConfigTxn -> {
1674                             Adjacencies portAdj = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn,
1675                                     vpnIface);
1676                             if (vpnIface == null) {
1677                                 LOG.trace("addSubnetToVpn: create new VpnInterface for Port {}", vpnInfName);
1678                                 Set<Uuid> listVpn = new HashSet<>();
1679                                 if (vpnId != null) {
1680                                     listVpn.add(vpnId);
1681                                 }
1682                                 if (internetId != null) {
1683                                     listVpn.add(internetId);
1684                                 }
1685                                 writeVpnInterfaceToDs(listVpn, vpnInfName, portAdj, port.getNetworkId(),
1686                                         isRouterInterface, wrtConfigTxn);
1687                                 if (sn.getRouterId() != null) {
1688                                     addToNeutronRouterInterfacesMap(sn.getRouterId(), portId.getValue());
1689                                 }
1690                             } else {
1691                                 LOG.trace("update VpnInterface for Port {} with adj {}", vpnInfName, portAdj);
1692                                 if (vpnId != null) {
1693                                     updateVpnInterfaceWithAdjacencies(vpnId, vpnInfName, portAdj, wrtConfigTxn);
1694                                 }
1695                                 if (internetId != null) {
1696                                     updateVpnInterfaceWithAdjacencies(internetId, vpnInfName, portAdj, wrtConfigTxn);
1697                                 }
1698                             }
1699                         });
1700                     LoggingFutures.addErrorLogging(future, LOG,
1701                             "addSubnetToVpn: Failed while creating VPN interface for vpnId {}, portId {}"
1702                                     + "{}, subnetId {}", vpnId.getValue(), portId, subnet.getValue());
1703                     return Collections.singletonList(future);
1704                 });
1705             }
1706         }
1707     }
1708
1709     protected void removeSubnetFromVpn(final Uuid vpnId, Subnetmap subnetmap, @Nullable Uuid internetVpnId) {
1710         Preconditions.checkArgument(vpnId != null || internetVpnId != null,
1711                 "removeSubnetFromVpn: at least one VPN must be not null");
1712         Uuid subnetId = subnetmap.getId();
1713         LOG.debug("Removing subnet {} from vpn {}/{}", subnetId.getValue(),
1714                   vpnId, internetVpnId);
1715         LOG.error("removeSubnetFromVpn: Subnetmap for subnet {} not found", subnetId.getValue());
1716         VpnMap vpnMap = null;
1717         VpnInstance vpnInstance = null;
1718         if (vpnId != null) {
1719             vpnMap = neutronvpnUtils.getVpnMap(vpnId);
1720             if (vpnMap == null) {
1721                 LOG.error("No vpnMap for vpnId {}, cannot remove subnet {} from VPN",
1722                         vpnId.getValue(), subnetId.getValue());
1723                 return;
1724             }
1725             vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
1726         }
1727         if (internetVpnId == null) {
1728             internetVpnId = subnetmap.getInternetVpnId();
1729         }
1730         if (internetVpnId != null) {
1731             vpnMap = neutronvpnUtils.getVpnMap(internetVpnId);
1732             if (vpnMap == null) {
1733                 LOG.error("No vpnMap for vpnId {}, cannot remove subnet {}"
1734                         + " from Internet VPN",
1735                         internetVpnId.getValue(), subnetId.getValue());
1736                 return;
1737             }
1738         }
1739         if (vpnInstance != null && isVpnOfTypeL2(vpnInstance)) {
1740             neutronEvpnUtils.updateElanAndVpn(vpnInstance, subnetmap.getNetworkId().getValue(),
1741                     NeutronEvpnUtils.Operation.DELETE);
1742         }
1743         boolean subnetVpnAssociation = false;
1744         if (vpnId != null && subnetmap.getVpnId() != null
1745             && subnetmap.getVpnId().getValue().equals(vpnId.getValue())) {
1746             subnetVpnAssociation = true;
1747         } else if (internetVpnId != null && subnetmap.getInternetVpnId() != null
1748             && subnetmap.getInternetVpnId().getValue().matches(internetVpnId.getValue())) {
1749             subnetVpnAssociation = true;
1750         }
1751         if (subnetVpnAssociation == false) {
1752             LOG.error("Removing subnet : Subnetmap is not in VPN {}/{}, owns {} and {}",
1753                       vpnId, internetVpnId, subnetmap.getVpnId(), subnetmap.getInternetVpnId());
1754             return;
1755         }
1756         // Check if there are ports on this subnet; remove corresponding vpn-interfaces
1757         List<Uuid> portList = subnetmap.getPortList();
1758         final Uuid internetId = internetVpnId;
1759         if (portList != null) {
1760             for (final Uuid portId : portList) {
1761                 LOG.debug("withdrawing subnet IP {} from vpn-interface {}", subnetmap.getSubnetIp(), portId.getValue());
1762                 final Port port = neutronvpnUtils.getNeutronPort(portId);
1763                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> {
1764                     List<ListenableFuture<Void>> futures = new ArrayList<>();
1765                     ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(
1766                         CONFIGURATION, tx -> {
1767                             if (port != null) {
1768                                 withdrawPortIpFromVpnIface(vpnId, internetId, port, subnetmap, tx);
1769                             } else {
1770                                 LOG.warn("Cannot proceed with withdrawPortIpFromVpnIface for port {} in subnet {} since"
1771                                                 + " port is absent in Neutron config DS", portId.getValue(),
1772                                         subnetId.getValue());
1773                             }
1774                         });
1775                     LoggingFutures.addErrorLogging(future, LOG,
1776                             "removeSubnetFromVpn: Exception while processing deletion of VPN interfaces for port {}"
1777                                     + " belonging to subnet {} and vpnId {}",
1778                             portId.getValue(), subnetId.getValue(), vpnId.getValue());
1779                     futures.add(future);
1780                     return futures;
1781                 });
1782             }
1783         }
1784         //update subnet-vpn association
1785         removeFromSubnetNode(subnetId, null, null, vpnId, null);
1786     }
1787
1788     protected void updateVpnInternetForSubnet(Subnetmap sm, Uuid vpn, boolean isBeingAssociated) {
1789         LOG.debug("updateVpnInternetForSubnet: {} subnet {} with BGPVPN Internet {} ",
1790              isBeingAssociated ? "associating" : "dissociating", sm.getSubnetIp(),
1791              vpn.getValue());
1792         Uuid internalVpnId = sm.getVpnId();
1793         if (internalVpnId == null) {
1794             LOG.error("updateVpnInternetForSubnet: can not find Internal or BGPVPN Id for subnet {}, bailing out",
1795                       sm.getId().getValue());
1796             return;
1797         }
1798         if (isBeingAssociated) {
1799             updateSubnetNode(sm.getId(), null, sm.getVpnId(), vpn);
1800         } else {
1801             updateSubnetNode(sm.getId(), null, sm.getVpnId(), null);
1802         }
1803
1804         jobCoordinator.enqueueJob("VPN-" + vpn.getValue(), () -> singletonList(
1805             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
1806                 if (isBeingAssociated) {
1807                     updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(
1808                             sm.getRouterInterfacePortId()), true, true, wrtConfigTxn, true);
1809                 } else {
1810                     removeInternetVpnFromVpnInterface(vpn,
1811                             neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()), wrtConfigTxn, sm);
1812                 }
1813                 }
1814             )));
1815
1816         // Check for ports on this subnet and update association of
1817         // corresponding vpn-interfaces to internet vpn
1818         List<Uuid> portList = sm.getPortList();
1819         if (portList != null) {
1820             for (Uuid port : portList) {
1821                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1822                         port.getValue(), isBeingAssociated);
1823                 jobCoordinator.enqueueJob("PORT-" + port.getValue(),
1824                     () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1825                         tx -> {
1826                             if (isBeingAssociated) {
1827                                 updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(port),
1828                                         true, false, tx, true);
1829                             } else {
1830                                 removeInternetVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(port), tx, sm);
1831                             }
1832                         })));
1833             }
1834         }
1835     }
1836
1837     @Nullable
1838     private Subnetmap updateVpnForSubnet(Uuid oldVpnId, Uuid newVpnId, Uuid subnet, boolean isBeingAssociated) {
1839         LOG.debug("Moving subnet {} from oldVpn {} to newVpn {} ", subnet.getValue(),
1840                 oldVpnId.getValue(), newVpnId.getValue());
1841         Uuid networkUuid = neutronvpnUtils.getSubnetmap(subnet).getNetworkId();
1842         Network network = neutronvpnUtils.getNeutronNetwork(networkUuid);
1843         boolean netIsExternal = NeutronvpnUtils.getIsExternal(network);
1844         Uuid vpnExtUuid = netIsExternal ? null
1845                 : neutronvpnUtils.getInternetvpnUuidBoundToSubnetRouter(subnet);
1846         Subnetmap sn = updateSubnetNode(subnet, null, newVpnId, vpnExtUuid);
1847         if (sn == null) {
1848             LOG.error("Updating subnet {} with newVpn {} failed", subnet.getValue(), newVpnId.getValue());
1849             return sn;
1850         }
1851         /* vpnExtUuid will contain the value only on if the subnet is V6 and it is already been
1852          * associated with internet BGP-VPN.
1853          */
1854         if (vpnExtUuid != null) {
1855             /* Update V6 Internet default route match with new VPN metadata.
1856              * isBeingAssociated = true means oldVpnId is same as routerId
1857              * isBeingAssociated = false means newVpnId is same as routerId
1858             */
1859             if (isBeingAssociated) {
1860                 neutronvpnUtils.updateVpnInstanceWithFallback(oldVpnId, vpnExtUuid, true);
1861             } else {
1862                 neutronvpnUtils.updateVpnInstanceWithFallback(newVpnId, vpnExtUuid, true);
1863             }
1864         }
1865         //Update Router Interface first synchronously.
1866         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
1867         ListenableFuture<Void> future =
1868                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1869                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1870                         neutronvpnUtils.getNeutronPort(sn.getRouterInterfacePortId()),
1871                         isBeingAssociated, true, tx, false));
1872         Futures.addCallback(future, new FutureCallback<Void>() {
1873             @Override
1874             public void onSuccess(Void result) {
1875                 // Check for ports on this subnet and update association of
1876                 // corresponding vpn-interfaces to external vpn
1877                 List<Uuid> portList = sn.getPortList();
1878                 if (portList != null) {
1879                     for (Uuid port : portList) {
1880                         LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1881                                 port.getValue(), isBeingAssociated);
1882                         jobCoordinator.enqueueJob("PORT-" + port.getValue(), () -> Collections.singletonList(
1883                                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1884                                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1885                                             neutronvpnUtils.getNeutronPort(port), isBeingAssociated, false,
1886                                             tx, false))));
1887                     }
1888                 }
1889             }
1890
1891             @Override
1892             public void onFailure(Throwable throwable) {
1893                 LOG.error(
1894                         "Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, "
1895                                 + "returning",
1896                         sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId, throwable);
1897             }
1898         }, MoreExecutors.directExecutor());
1899
1900         return sn;
1901     }
1902
1903     public InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
1904         return InstanceIdentifier.builder(RouterInterfacesMap.class)
1905                 .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
1906     }
1907
1908     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1909         final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1910         final ReentrantLock lock = lockForUuid(routerId);
1911         lock.lock();
1912         try {
1913             Optional<RouterInterfaces> optRouterInterfaces =
1914                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1915                         routerInterfacesId);
1916             Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1917                     .setInterfaceId(interfaceName).build();
1918             if (optRouterInterfaces.isPresent()) {
1919                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1920                     routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
1921             } else {
1922                 RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
1923                 List<Interfaces> interfaces = new ArrayList<>();
1924                 interfaces.add(routerInterface);
1925                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1926                     routerInterfacesId, builder.setInterfaces(interfaces).build());
1927             }
1928         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
1929             LOG.error("Error reading router interfaces for {}", routerInterfacesId, e);
1930         } finally {
1931             lock.unlock();
1932         }
1933     }
1934
1935     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1936         final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1937         final ReentrantLock lock = lockForUuid(routerId);
1938         lock.lock();
1939         try {
1940             Optional<RouterInterfaces> optRouterInterfaces =
1941                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1942                         routerInterfacesId);
1943             Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1944                     .setInterfaceId(interfaceName).build();
1945             if (optRouterInterfaces.isPresent()) {
1946                 RouterInterfaces routerInterfaces = optRouterInterfaces.get();
1947                 List<Interfaces> interfaces = new ArrayList<>(routerInterfaces.nonnullInterfaces().values());
1948                 if (interfaces != null && interfaces.remove(routerInterface)) {
1949                     if (interfaces.isEmpty()) {
1950                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1951                             routerInterfacesId);
1952                     } else {
1953                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1954                             routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
1955                     }
1956                 }
1957             }
1958         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
1959             LOG.error("Error reading the router interfaces for {}", routerInterfacesId, e);
1960         } finally {
1961             lock.unlock();
1962         }
1963     }
1964
1965     /**
1966      * Creates the corresponding static routes in the specified VPN. These static routes must be point to an
1967      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink. Otherwise the
1968      * route will be ignored.
1969      *
1970      * @param vpnName the VPN identifier
1971      * @param interVpnLinkRoutes The list of static routes
1972      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1973      */
1974     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1975                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1976         for (Routes route : interVpnLinkRoutes) {
1977             String nexthop = route.getNexthop().stringValue();
1978             String destination = route.getDestination().stringValue();
1979             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1980             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
1981                 AddStaticRouteInput rpcInput =
1982                         new AddStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1983                                 .setVpnInstanceName(vpnName.getValue())
1984                                 .build();
1985                 Future<RpcResult<AddStaticRouteOutput>> labelOuputFtr = vpnRpcService.addStaticRoute(rpcInput);
1986                 RpcResult<AddStaticRouteOutput> rpcResult;
1987                 try {
1988                     rpcResult = labelOuputFtr.get();
1989                     if (rpcResult.isSuccessful()) {
1990                         LOG.debug("Label generated for destination {} is: {}",
1991                                 destination, rpcResult.getResult().getLabel());
1992                     } else {
1993                         LOG.error("RPC call to add a static Route to {} with nexthop {} returned with errors {}",
1994                                 destination, nexthop, rpcResult.getErrors());
1995                     }
1996                 } catch (InterruptedException | ExecutionException e) {
1997                     LOG.error("Error happened while invoking addStaticRoute RPC for nexthop {} with destination {} "
1998                             + "for VPN {}", nexthop, destination, vpnName.getValue(), e);
1999                 }
2000             } else {
2001                 // Any other case is a fault.
2002                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
2003                         route.getDestination().stringValue(), nexthop);
2004                 continue;
2005             }
2006         }
2007     }
2008
2009     /**
2010      * Removes the corresponding static routes from the specified VPN. These static routes point to an
2011      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink.
2012      *
2013      * @param vpnName the VPN identifier
2014      * @param interVpnLinkRoutes The list of static routes
2015      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
2016      */
2017     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
2018                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
2019         for (Routes route : interVpnLinkRoutes) {
2020             String nexthop = route.getNexthop().stringValue();
2021             String destination = route.getDestination().stringValue();
2022             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
2023             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
2024                 RemoveStaticRouteInput rpcInput =
2025                         new RemoveStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
2026                                 .setVpnInstanceName(vpnName.getValue())
2027                                 .build();
2028
2029                 LoggingFutures.addErrorLogging(JdkFutureAdapters.listenInPoolThread(
2030                         vpnRpcService.removeStaticRoute(rpcInput)), LOG, "Remove VPN routes");
2031             } else {
2032                 // Any other case is a fault.
2033                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
2034                         route.getDestination().stringValue(), nexthop);
2035                 continue;
2036             }
2037         }
2038     }
2039
2040     /*
2041      * Returns true if the specified nexthop is the other endpoint in an
2042      * InterVpnLink, regarding one of the VPN's point of view.
2043      */
2044     private static boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid,
2045             InterVpnLink interVpnLink) {
2046         return
2047                 interVpnLink != null
2048                         && (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
2049                         && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop)
2050                         || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
2051                         && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop));
2052     }
2053
2054     @NonNull
2055     protected List<Adjacency> getAdjacencyforExtraRoute(List<Routes> routeList, String fixedIp) {
2056         List<Adjacency> adjList = new ArrayList<>();
2057         Map<String, List<String>> adjMap = new HashMap<>();
2058         for (Routes route : routeList) {
2059             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
2060                 LOG.error("Incorrect input received for extra route. {}", route);
2061             } else {
2062                 String nextHop = route.getNexthop().stringValue();
2063                 String destination = route.getDestination().stringValue();
2064                 if (!nextHop.equals(fixedIp)) {
2065                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
2066                     continue;
2067                 }
2068                 LOG.trace("Adding extra route for destination {} with nexthop {} ", destination,
2069                         nextHop);
2070                 List<String> hops = adjMap.computeIfAbsent(destination, k -> new ArrayList<>());
2071                 if (!hops.contains(nextHop)) {
2072                     hops.add(nextHop);
2073                 }
2074             }
2075         }
2076
2077         for (Entry<String, List<String>> entry : adjMap.entrySet()) {
2078             final String destination = entry.getKey();
2079             final List<String> ipList = entry.getValue();
2080             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
2081                     .setAdjacencyType(AdjacencyType.ExtraRoute).setNextHopIpList(ipList)
2082                     .withKey(new AdjacencyKey(destination)).build();
2083             adjList.add(erAdj);
2084         }
2085         return adjList;
2086     }
2087
2088     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
2089         checkAlarmExtraRoutes(vpnId, routeList);
2090
2091         for (Routes route : routeList) {
2092             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
2093                 LOG.error("Incorrect input received for extra route. {}", route);
2094             } else {
2095                 String nextHop = route.getNexthop().stringValue();
2096                 String destination = route.getDestination().stringValue();
2097                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2098                         nextHop);
2099                 if (infName != null) {
2100                     LOG.trace("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}",
2101                         destination, vpnId.getValue(), nextHop, infName);
2102                     boolean isLockAcquired = false;
2103                     try {
2104                         InstanceIdentifier<VpnInterface> identifier = InstanceIdentifier.builder(VpnInterfaces.class)
2105                                 .child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2106                         InstanceIdentifier<Adjacency> path = identifier.augmentation(Adjacencies.class)
2107                             .child(Adjacency.class, new AdjacencyKey(destination));
2108                         Optional<Adjacency> existingAdjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2109                                 LogicalDatastoreType.CONFIGURATION, path);
2110                         if (existingAdjacency.isPresent()
2111                                 && existingAdjacency.get().getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2112                             LOG.error("The route with destination {} nextHop {} is already present as"
2113                                             + " a primary adjacency for interface {}. Skipping adjacency addition.",
2114                                     destination, nextHop, infName);
2115                             continue;
2116                         }
2117                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
2118                             .setNextHopIpList(Collections.singletonList(nextHop)).withKey(new AdjacencyKey(destination))
2119                             .setAdjacencyType(AdjacencyType.ExtraRoute).build();
2120
2121                         try (AcquireResult lock = tryInterfaceLock(infName)) {
2122                             if (!lock.wasAcquired()) {
2123                                 // FIXME: why do we even bother with locking if we do not honor it?!
2124                                 logTryLockFailure(infName);
2125                             }
2126
2127                             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2128                                 path, erAdj);
2129                         }
2130                     } catch (TransactionCommitFailedException e) {
2131                         LOG.error("exception in adding extra route with destination: {}, next hop: {}",
2132                             destination, nextHop, e);
2133                     } catch (ExecutionException | InterruptedException e) {
2134                         LOG.error("Exception on reading data-store ", e);
2135                     }
2136                 } else {
2137                     LOG.error("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} "
2138                         + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2139                 }
2140             }
2141         }
2142     }
2143
2144     /**
2145      * This method setup or down an alarm about extra route fault.
2146      * When extra routes are configured, through a router, if the number of nexthops is greater than the number of
2147      * available RDs, then an alarm and an error is generated.<br>
2148      * <b>Be careful</b> the routeList could be changed.
2149      *
2150      * @param vpnId the vpnId of vpn to control.
2151      * @param routeList the list of router to check, it could be modified.
2152      */
2153     private void checkAlarmExtraRoutes(Uuid vpnId, List<Routes> routeList) {
2154         if (!neutronvpnAlarm.isAlarmEnabled()) {
2155             LOG.debug("checkAlarmExtraRoutes is not enable for vpnId {} routeList {}", vpnId, routeList);
2156             return;
2157         }
2158         VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(dataBroker, vpnId);
2159         if (vpnInstance == null || routeList == null || routeList.isEmpty() || !neutronvpnAlarm.isAlarmEnabled()) {
2160             LOG.debug("checkAlarmExtraRoutes have args null as following : vpnId {} routeList {}",
2161                     vpnId, routeList);
2162             return;
2163         }
2164         String primaryRd = neutronvpnUtils.getVpnRd(vpnId.getValue());
2165         if (primaryRd == null || primaryRd.equals(vpnId.getValue())) {
2166             LOG.debug("checkAlarmExtraRoutes. vpn {} is not a BGPVPN. cancel checkExtraRoute",
2167                     vpnId);
2168             return;
2169         }
2170         for (Routes route : routeList) {
2171             // count  the number of nexthops for each same route.getDestingation().getValue()
2172             String destination = route.getDestination().stringValue();
2173             String nextHop = route.getNexthop().stringValue();
2174             List<String> nextHopList = new ArrayList<>();
2175             nextHopList.add(nextHop);
2176             int nbNextHops = 1;
2177             for (Routes routeTmp : routeList) {
2178                 String routeDest = routeTmp.getDestination().stringValue();
2179                 if (!destination.equals(routeDest)) {
2180                     continue;
2181                 }
2182                 String routeNextH = routeTmp.getNexthop().stringValue();
2183                 if (nextHop.equals(routeNextH)) {
2184                     continue;
2185                 }
2186                 nbNextHops++;
2187                 nextHopList.add(routeTmp.getNexthop().stringValue());
2188             }
2189             final List<String> rdList = new ArrayList<>();
2190             if (vpnInstance != null
2191                     && vpnInstance.getRouteDistinguisher() != null) {
2192                 vpnInstance.getRouteDistinguisher().forEach(rd -> {
2193                     if (rd != null) {
2194                         rdList.add(rd);
2195                     }
2196                 });
2197             }
2198             // 1. VPN Instance Name
2199             String typeAlarm = "for vpnId: " + vpnId + " have exceeded next hops for prefixe";
2200
2201             // 2. Router ID
2202             List<Uuid> routerUuidList = neutronvpnUtils.getRouterIdListforVpn(vpnId);
2203             Uuid routerUuid = routerUuidList.get(0);
2204             StringBuilder detailsAlarm = new StringBuilder("routerUuid: ");
2205             detailsAlarm.append(routerUuid == null ? vpnId.toString() : routerUuid.getValue());
2206
2207             // 3. List of RDs associated with the VPN
2208             detailsAlarm.append(" List of RDs associated with the VPN: ");
2209             for (String s : rdList) {
2210                 detailsAlarm.append(s);
2211                 detailsAlarm.append(", ");
2212             }
2213
2214             // 4. Prefix in question
2215             detailsAlarm.append(" for prefix: ");
2216             detailsAlarm.append(route.getDestination().stringValue());
2217
2218             // 5. List of NHs for the prefix
2219             detailsAlarm.append(" for nextHops: ");
2220             for (String s : nextHopList) {
2221                 detailsAlarm.append(s);
2222                 detailsAlarm.append(", ");
2223             }
2224
2225             if (rdList.size() < nbNextHops) {
2226                 neutronvpnAlarm.raiseNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2227             } else {
2228                 neutronvpnAlarm.clearNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2229             }
2230         }
2231     }
2232
2233     // TODO Clean up the exception handling
2234     @SuppressWarnings("checkstyle:IllegalCatch")
2235     protected void removeAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList) {
2236         for (Routes route : routeList) {
2237             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
2238                 String nextHop = route.getNexthop().stringValue();
2239                 String destination = route.getDestination().stringValue();
2240                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2241                         nextHop);
2242                 if (infName == null) {
2243                     LOG.error("Unable to find VPN NextHop interface to remove extra-route destination {} on VPN {} "
2244                             + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2245                     // Proceed to remove the next extra-route
2246                     continue;
2247                 }
2248                 LOG.trace("Removing extra route for destination {} on vpn {} with nexthop {} and infName {}",
2249                         destination, vpnId.getValue(), nextHop, infName);
2250
2251                 InstanceIdentifier<Adjacency> adjacencyIdentifier =
2252                         InstanceIdentifier.builder(VpnInterfaces.class)
2253                                 .child(VpnInterface.class, new VpnInterfaceKey(infName))
2254                                 .augmentation(Adjacencies.class)
2255                                 .child(Adjacency.class, new AdjacencyKey(destination))
2256                                 .build();
2257
2258                 try {
2259                     // Looking for existing prefix in MDSAL database
2260                     Optional<Adjacency> adjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2261                             LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
2262                     boolean updateNextHops = false;
2263                     List<String> nextHopList = new ArrayList<>();
2264                     if (adjacency.isPresent()) {
2265                         List<String> nhListRead = adjacency.get().getNextHopIpList();
2266                         if (nhListRead.size() > 1) { // ECMP case
2267                             for (String nextHopRead : nhListRead) {
2268                                 if (nextHopRead.equals(nextHop)) {
2269                                     updateNextHops = true;
2270                                 } else {
2271                                     nextHopList.add(nextHopRead);
2272                                 }
2273                             }
2274                         }
2275                     }
2276
2277                     try (AcquireResult lock = tryInterfaceLock(infName)) {
2278                         if (!lock.wasAcquired()) {
2279                             // FIXME: why do we even bother with locking if we do not honor it?!
2280                             logTryLockFailure(infName);
2281                         }
2282
2283                         if (updateNextHops) {
2284                             // An update must be done, not including the current next hop
2285                             InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(
2286                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2287                             Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
2288                                     .setNextHopIpList(nextHopList)
2289                                     .withKey(new AdjacencyKey(destination))
2290                                     .build();
2291                             List<Adjacency> newAdjList = Collections.singletonList(newAdj);
2292                             Adjacencies erAdjs =
2293                                     new AdjacenciesBuilder().setAdjacency(getAdjacencyMap(newAdjList)).build();
2294                             VpnInterface vpnIf = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
2295                                     .addAugmentation(Adjacencies.class, erAdjs).build();
2296                             SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
2297                                 vpnIfIdentifier, vpnIf);
2298                         } else {
2299                             // Remove the whole route
2300                             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
2301                                 adjacencyIdentifier);
2302                             LOG.trace("extra route {} deleted successfully", route);
2303                         }
2304                     }
2305                 } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
2306                     LOG.error("exception in deleting extra route with destination {} for interface {}",
2307                             destination, infName, e);
2308                 }
2309             } else {
2310                 LOG.error("Incorrect input received for extra route: {}", route);
2311             }
2312         }
2313     }
2314
2315     public void removeVpn(Uuid vpnId) {
2316         // read VPNMaps
2317         VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2318         if (vpnMap != null) {
2319             Map<RouterIdsKey, RouterIds> keyRouterIdsMap = vpnMap.getRouterIds();
2320             List<Uuid> routerUuidList = new ArrayList<>();
2321             // dissociate router
2322             if (keyRouterIdsMap != null && !keyRouterIdsMap.isEmpty()) {
2323                 for (RouterIds router : keyRouterIdsMap.values()) {
2324                     Uuid routerId = router.getRouterId();
2325                     routerUuidList.add(routerId);
2326                     dissociateRouterFromVpn(vpnId, routerId);
2327                 }
2328             }
2329             if (!routerUuidList.contains(vpnId) && vpnMap.getNetworkIds() != null) {
2330                 dissociateNetworksFromVpn(vpnId, vpnMap.getNetworkIds());
2331             }
2332         } else {
2333             LOG.error("removeVpn: vpnMap is null for vpn {}", vpnId.getValue());
2334         }
2335         // remove entire vpnMaps node
2336         deleteVpnMapsNode(vpnId);
2337
2338         // remove vpn-instance
2339         deleteVpnInstance(vpnId);
2340         LOG.debug("Deleted L3VPN with ID {}", vpnId.getValue());
2341     }
2342
2343     private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
2344         return vpnInstance != null && vpnInstance.isL2vpn();
2345     }
2346
2347     // TODO Clean up the exception handling
2348     @SuppressWarnings("checkstyle:IllegalCatch")
2349     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
2350         updateVpnMaps(vpnId, null, routerId, null, null);
2351         LOG.debug("associateRouterToVpn: Updating association of subnets to external vpn {}", vpnId.getValue());
2352         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
2353         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2354         for (Subnetmap sn : subMapList) {
2355             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
2356             if (!ipVersion.isIpVersionChosen(ipVers)) {
2357                 ipVersion = ipVersion.addVersion(ipVers);
2358             }
2359         }
2360         if (ipVersion != IpVersionChoice.UNDEFINED) {
2361             LOG.debug("associateRouterToVpn: Updating vpnInstance ip address family {} for VPN {} ",
2362                     ipVersion, vpnId);
2363             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
2364         }
2365         for (Subnetmap sn : subMapList) {
2366             updateVpnForSubnet(routerId, vpnId, sn.getId(), true);
2367         }
2368     }
2369
2370     protected void associateRouterToInternalVpn(Uuid vpnId, Uuid routerId) {
2371         List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
2372         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
2373         LOG.debug("Adding subnets to internal vpn {}", vpnId.getValue());
2374         for (Uuid subnet : routerSubnets) {
2375             IpVersionChoice version = NeutronvpnUtils
2376                    .getIpVersionFromSubnet(neutronvpnUtils.getSubnetmap(subnet));
2377             if (version.isIpVersionChosen(IpVersionChoice.IPV4)) {
2378                 addSubnetToVpn(vpnId, subnet, null);
2379             } else {
2380                 addSubnetToVpn(vpnId, subnet, internetVpnId);
2381             }
2382         }
2383     }
2384
2385     // TODO Clean up the exception handling
2386     @SuppressWarnings("checkstyle:IllegalCatch")
2387     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
2388
2389         clearFromVpnMaps(vpnId, routerId, null);
2390         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
2391         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2392         for (Subnetmap sn : subMapList) {
2393             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
2394             if (ipVersion.isIpVersionChosen(ipVers)) {
2395                 ipVersion = ipVersion.addVersion(ipVers);
2396             }
2397             LOG.debug("dissociateRouterFromVpn: Updating association of subnets to internal vpn {}",
2398                     routerId.getValue());
2399             updateVpnForSubnet(vpnId, routerId, sn.getId(), false);
2400         }
2401         if (ipVersion != IpVersionChoice.UNDEFINED) {
2402             LOG.debug("dissociateRouterFromVpn; Updating vpnInstance with ip address family {} for VPN {} ",
2403                     ipVersion, vpnId);
2404             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
2405                     false);
2406         }
2407     }
2408
2409     /**
2410      * Parses and associates networks list with given VPN.
2411      *
2412      * @param vpnId Uuid of given VPN.
2413      * @param networkList List list of network Ids (Uuid), which will be associated.
2414      * @return list of formatted strings with detailed error messages.
2415      */
2416     @NonNull
2417     protected List<String> associateNetworksToVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
2418         List<String> failedNwList = new ArrayList<>();
2419         HashSet<Uuid> passedNwList = new HashSet<>();
2420         ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
2421         boolean isExternalNetwork = false;
2422         if (networkList.isEmpty()) {
2423             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
2424             failedNwList.add(String.format("Failed to associate networks with VPN %s as given networks list is empty",
2425                     vpnId.getValue()));
2426             return failedNwList;
2427         }
2428         VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
2429         if (vpnInstance == null) {
2430             LOG.error("associateNetworksToVpn: Can not find vpnInstance for VPN {} in ConfigDS", vpnId.getValue());
2431             failedNwList.add(String.format("Failed to associate network: can not found vpnInstance for VPN %s "
2432                                            + "in ConfigDS", vpnId.getValue()));
2433             return failedNwList;
2434         }
2435         try {
2436             if (isVpnOfTypeL2(vpnInstance) && neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance)) {
2437                 LOG.error("associateNetworksToVpn: EVPN {} supports only one network to be associated with",
2438                           vpnId.getValue());
2439                 failedNwList.add(String.format("Failed to associate network: EVPN %s supports only one network to be "
2440                                                + "associated with", vpnId.getValue()));
2441                 return failedNwList;
2442             }
2443             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2444             boolean isIpFamilyUpdated = false;
2445             for (Uuid nw : networkList) {
2446                 Network network = neutronvpnUtils.getNeutronNetwork(nw);
2447                 if (network == null) {
2448                     LOG.error("associateNetworksToVpn: Network {} not found in ConfigDS", nw.getValue());
2449                     failedNwList.add(String.format("Failed to associate network: network %s not found in ConfigDS",
2450                                                    nw.getValue()));
2451                     continue;
2452                 }
2453                 NetworkProviderExtension providerExtension = network.augmentation(NetworkProviderExtension.class);
2454                 if (providerExtension.getSegments() != null && providerExtension.getSegments().size() > 1) {
2455                     LOG.error("associateNetworksToVpn: MultiSegmented network {} not supported in BGPVPN {}",
2456                               nw.getValue(), vpnId.getValue());
2457                     failedNwList.add(String.format("Failed to associate multisegmented network %s with BGPVPN %s",
2458                                                    nw.getValue(), vpnId.getValue()));
2459                     continue;
2460                 }
2461                 Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2462                 if (networkVpnId != null) {
2463                     LOG.error("associateNetworksToVpn: Network {} already associated with another VPN {}",
2464                               nw.getValue(), networkVpnId.getValue());
2465                     failedNwList.add(String.format("Failed to associate network %s as it is already associated to "
2466                                                    + "another VPN %s", nw.getValue(), networkVpnId.getValue()));
2467                     continue;
2468                 }
2469                 /* Handle association of external network(s) to Internet BGP-VPN use case outside of the
2470                  * networkList iteration
2471                  */
2472                 if (neutronvpnUtils.getIsExternal(network)) {
2473                     extNwMap.put(nw, network);
2474                 }
2475                 if (NeutronvpnUtils.getIsExternal(network)) {
2476                     isExternalNetwork = true;
2477                 }
2478                 List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
2479                 if (subnetmapList == null || subnetmapList.isEmpty()) {
2480                     passedNwList.add(nw);
2481                     continue;
2482                 }
2483                 if (vpnManager.checkForOverlappingSubnets(nw, subnetmapList, vpnId, routeTargets, failedNwList)) {
2484                     continue;
2485                 }
2486                 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2487                 for (Subnetmap subnetmap : subnetmapList) {
2488                     IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
2489                     if (!ipVersion.isIpVersionChosen(ipVers)) {
2490                         ipVersion = ipVersion.addVersion(ipVers);
2491                     }
2492                 }
2493                 //Update vpnInstance for IP address family
2494                 if (ipVersion != IpVersionChoice.UNDEFINED && !isIpFamilyUpdated) {
2495                     LOG.debug("associateNetworksToVpn: Updating vpnInstance with ip address family {}"
2496                             + " for VPN {} ", ipVersion, vpnId);
2497                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
2498                     isIpFamilyUpdated = true;
2499                 }
2500                 for (Subnetmap subnetmap : subnetmapList) {
2501                     Uuid subnetId = subnetmap.getId();
2502                     Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
2503                     if (subnetVpnId != null) {
2504                         LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {}"
2505                                 + " as it is already associated", subnetId.getValue(), subnetVpnId.getValue());
2506                         failedNwList.add(String.format("Failed to associate subnet %s with VPN %s"
2507                                 + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
2508                         continue;
2509                     }
2510                     if (!NeutronvpnUtils.getIsExternal(network)) {
2511                         LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
2512                                 vpnId.getValue());
2513                         addSubnetToVpn(vpnId, subnetId, null);
2514                         vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2515                                 vpnId.getValue());
2516                         passedNwList.add(nw);
2517                     }
2518                 }
2519                 passedNwList.add(nw);
2520                 //Handle association of external network(s) to Internet BGP-VPN Instance use case
2521                 if (!extNwMap.isEmpty() || extNwMap != null) {
2522                     for (Network extNw : extNwMap.values()) {
2523                         if (!associateExtNetworkToVpn(vpnId, extNw, vpnInstance.getBgpvpnType())) {
2524                             LOG.error("associateNetworksToVpn: Failed to associate Provider External Network {} with "
2525                                     + "VPN {}", extNw, vpnId.getValue());
2526                             failedNwList.add(String.format("Failed to associate Provider External Network %s with "
2527                                             + "VPN %s", extNw, vpnId.getValue()));
2528                             continue;
2529                         }
2530                     }
2531                 }
2532             }
2533         } catch (ExecutionException | InterruptedException e) {
2534             LOG.error("associateNetworksToVpn: Failed to associate VPN {} with networks {}: ", vpnId.getValue(),
2535                     networkList, e);
2536             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
2537                     networkList, e));
2538         }
2539         //VpnMap update for ext-nw is already done in associateExtNetworkToVpn() method.
2540         if (!isExternalNetwork) {
2541             updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
2542         }
2543         LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList, vpnId.getValue());
2544         return failedNwList;
2545     }
2546
2547     private boolean associateExtNetworkToVpn(@NonNull Uuid vpnId, @NonNull Network extNet,
2548                                              VpnInstance.BgpvpnType bgpVpnType) {
2549         if (!addExternalNetworkToVpn(extNet, vpnId)) {
2550             return false;
2551         }
2552         if (!bgpVpnType.equals(VpnInstance.BgpvpnType.InternetBGPVPN)) {
2553             LOG.info("associateExtNetworkToVpn: External network {} is associated to VPN {}."
2554                             + "Hence set vpnInstance type to {} from {} ", extNet.key().getUuid().getValue(),
2555                     vpnId.getValue(), VpnInstance.BgpvpnType.InternetBGPVPN.getName(),
2556                     VpnInstance.BgpvpnType.BGPVPN.getName());
2557             neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.InternetBGPVPN, vpnId);
2558         }
2559         //Update VpnMap with ext-nw is needed first before processing V6 internet default fallback flows
2560         List<Uuid> extNwList = Collections.singletonList(extNet.key().getUuid());
2561         updateVpnMaps(vpnId, null, null, null, extNwList);
2562         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2563         for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
2564             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2565             if (sm == null) {
2566                 LOG.error("associateExtNetworkToVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2567                 continue;
2568             }
2569             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
2570             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
2571                 continue;
2572             }
2573             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
2574                 updateVpnInternetForSubnet(sm, vpnId, true);
2575             }
2576             if (!ipVersion.isIpVersionChosen(ipVers)) {
2577                 ipVersion = ipVersion.addVersion(ipVers);
2578             }
2579         }
2580         if (ipVersion != IpVersionChoice.UNDEFINED) {
2581             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, true);
2582             LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
2583             neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, true);
2584         }
2585         return true;
2586     }
2587
2588     /**
2589      * Parses and disassociates networks list from given VPN.
2590      *
2591      * @param vpnId Uuid of given VPN.
2592      * @param networkList List list of network Ids (Uuid), which will be disassociated.
2593      * @return list of formatted strings with detailed error messages.
2594      */
2595     @NonNull
2596     protected List<String> dissociateNetworksFromVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
2597         List<String> failedNwList = new ArrayList<>();
2598         HashSet<Uuid> passedNwList = new HashSet<>();
2599         ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
2600         if (networkList.isEmpty()) {
2601             LOG.error("dissociateNetworksFromVpn: Failed as networks list is empty");
2602             failedNwList.add(String.format("Failed to disassociate networks from VPN %s as networks list is empty",
2603                              vpnId.getValue()));
2604             return failedNwList;
2605         }
2606         for (Uuid nw : networkList) {
2607             List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
2608             if (networkSubnets == null) {
2609                 passedNwList.add(nw);
2610                 continue;
2611             }
2612             Network network = neutronvpnUtils.getNeutronNetwork(nw);
2613             if (network == null) {
2614                 LOG.error("dissociateNetworksFromVpn: Network {} not found in ConfigDS", nw.getValue());
2615                 failedNwList.add(String.format("Failed to disassociate network %s as is not found in ConfigDS",
2616                         nw.getValue()));
2617                 continue;
2618             }
2619             Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2620             if (networkVpnId == null) {
2621                 LOG.error("dissociateNetworksFromVpn: Network {} is not associated to any VPN", nw.getValue());
2622                 failedNwList.add(String.format("Failed to disassociate network %s as is not associated to any VPN",
2623                                                nw.getValue()));
2624                 continue;
2625             }
2626             if (!vpnId.equals(networkVpnId)) {
2627                 LOG.error("dissociateNetworksFromVpn: Network {} is associated to another VPN {} instead of given {}",
2628                           nw.getValue(), networkVpnId.getValue(), vpnId.getValue());
2629                 failedNwList.add(String.format("Failed to disassociate network %s as it is associated to another "
2630                                 + "vpn %s instead of given %s", nw.getValue(), networkVpnId.getValue(),
2631                                 vpnId.getValue()));
2632                 continue;
2633             }
2634             /* Handle disassociation of external network(s) from Internet BGP-VPN use case outside of the
2635              * networkList iteration
2636              */
2637             if (neutronvpnUtils.getIsExternal(network)) {
2638                 extNwMap.put(nw, network);
2639             }
2640             IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2641             for (Uuid subnet : networkSubnets) {
2642                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
2643                 if (subnetmap == null) {
2644                     failedNwList.add(String.format("subnetmap %s not found for network %s",
2645                             subnet.getValue(), nw.getValue()));
2646                     LOG.error("dissociateNetworksFromVpn: Subnetmap for subnet {} not found when "
2647                             + "dissociating network {} from VPN {}", subnet.getValue(), nw.getValue(),
2648                             vpnId.getValue());
2649                     continue;
2650                 }
2651                 IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
2652                 if (!ipVersion.isIpVersionChosen(ipVers)) {
2653                     ipVersion = ipVersion.addVersion(ipVers);
2654                 }
2655                 if (!NeutronvpnUtils.getIsExternal(network)) {
2656                     LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
2657                             vpnId.getValue());
2658                     removeSubnetFromVpn(vpnId, subnetmap, null);
2659                     Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2660                     vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2661                             vpnId.getValue());
2662                     passedNwList.add(nw);
2663                 }
2664             }
2665             if (ipVersion != IpVersionChoice.UNDEFINED) {
2666                 LOG.debug("dissociateNetworksFromVpn: Updating vpnInstance with ip address family {}"
2667                         + " for VPN {}", ipVersion, vpnId);
2668                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
2669             }
2670         }
2671         //Handle disassociation of external network(s) from Internet BGP-VPN Instance use case
2672         if (!extNwMap.isEmpty() || extNwMap != null) {
2673             for (Network extNw : extNwMap.values()) {
2674                 if (disassociateExtNetworkFromVpn(vpnId, extNw)) {
2675                     passedNwList.add(extNw.getUuid());
2676                 } else {
2677                     LOG.error("dissociateNetworksFromVpn: Failed to withdraw External Provider Network {} from VPN {}",
2678                             extNw, vpnId.getValue());
2679                     failedNwList.add(String.format("Failed to withdraw External Provider Network %s from VPN %s",
2680                             extNw, vpnId.getValue()));
2681                     continue;
2682                 }
2683             }
2684         }
2685         clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
2686         LOG.info("dissociateNetworksFromVpn: Network(s) {} disassociated from L3VPN {} successfully",
2687                 passedNwList, vpnId.getValue());
2688         return failedNwList;
2689     }
2690
2691     private boolean disassociateExtNetworkFromVpn(@NonNull Uuid vpnId, @NonNull Network extNet) {
2692         if (!removeExternalNetworkFromVpn(extNet)) {
2693             return false;
2694         }
2695         // check, if there is another Provider Networks associated with given VPN
2696         List<Uuid> vpnNets = getNetworksForVpn(vpnId);
2697         if (vpnNets != null) {
2698             //Remove currently disassociated network from the list
2699             vpnNets.remove(extNet.getUuid());
2700             for (Uuid netId : vpnNets) {
2701                 if (NeutronvpnUtils.getIsExternal(getNeutronNetwork(netId))) {
2702                     LOG.error("dissociateExtNetworkFromVpn: Internet VPN {} is still associated with Provider Network "
2703                             + "{}", vpnId.getValue(), netId.getValue());
2704                     return true;
2705                 }
2706             }
2707         }
2708         ///Set VPN Type is BGPVPN from InternetBGPVPN
2709         LOG.info("disassociateExtNetworkFromVpn: Set BGP-VPN type with {} for VPN {} and update IPv6 address family. "
2710                         + "Since external network is disassociated from VPN {}",
2711                 VpnInstance.BgpvpnType.BGPVPN, extNet, vpnId.getValue());
2712         neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.BGPVPN, vpnId);
2713         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2714         for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
2715             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2716             if (sm == null) {
2717                 LOG.error("disassociateExtNetworkFromVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2718                 continue;
2719             }
2720             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
2721             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
2722                 continue;
2723             }
2724             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
2725                 updateVpnInternetForSubnet(sm, vpnId, false);
2726             }
2727             if (!ipVersion.isIpVersionChosen(ipVers)) {
2728                 ipVersion = ipVersion.addVersion(ipVers);
2729             }
2730         }
2731         if (ipVersion != IpVersionChoice.UNDEFINED) {
2732             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
2733             LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}",
2734                     vpnId.getValue());
2735             neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, false);
2736         }
2737         return true;
2738     }
2739
2740     /**
2741      * It handles the invocations to the neutronvpn:associateNetworks RPC method.
2742      */
2743     @Override
2744     // TODO Clean up the exception handling
2745     @SuppressWarnings("checkstyle:IllegalCatch")
2746     public ListenableFuture<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
2747
2748         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
2749         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
2750         StringBuilder returnMsg = new StringBuilder();
2751         Uuid vpnId = input.getVpnId();
2752
2753         try {
2754             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2755                 LOG.debug("associateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2756                         input.getNetworkId());
2757                 List<Uuid> netIds = input.getNetworkId();
2758                 if (netIds != null && !netIds.isEmpty()) {
2759                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
2760                     if (!failed.isEmpty()) {
2761                         returnMsg.append(failed);
2762                     }
2763                 }
2764             } else {
2765                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2766             }
2767             if (returnMsg.length() != 0) {
2768                 opBuilder.setResponse(
2769                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2770                                 "associate Networks to vpn {} failed due to {}", vpnId.getValue(), returnMsg));
2771                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().withResult(opBuilder.build()).build());
2772             } else {
2773                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().build());
2774             }
2775         } catch (Exception ex) {
2776             LOG.error("associate Networks to vpn failed {}", input.getVpnId().getValue(), ex);
2777             result.set(RpcResultBuilder.<AssociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2778                     formatAndLog(LOG::error, "associate Networks to vpn {} failed due to {}",
2779                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2780         }
2781         LOG.debug("associateNetworks returns..");
2782         return result;
2783     }
2784
2785     /**
2786      * It handles the invocations to the neutronvpn:associateRouter RPC method.
2787      */
2788     @Override
2789     public ListenableFuture<RpcResult<AssociateRouterOutput>> associateRouter(AssociateRouterInput input) {
2790
2791         SettableFuture<RpcResult<AssociateRouterOutput>> result = SettableFuture.create();
2792         LOG.debug("associateRouter {}", input);
2793         StringBuilder returnMsg = new StringBuilder();
2794         Uuid vpnId = input.getVpnId();
2795         Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter
2796                 .input.RouterIdsKey, org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602
2797                 .associaterouter.input.RouterIds> keyRouterIdsMap = input.nonnullRouterIds();
2798         Preconditions.checkArgument(!keyRouterIdsMap.isEmpty(), "associateRouter: RouterIds list is empty!");
2799         Preconditions.checkNotNull(vpnId, "associateRouter; VpnId not found!");
2800         Preconditions.checkNotNull(vpnId, "associateRouter; RouterIds not found!");
2801         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input
2802                 .RouterIds routerId : keyRouterIdsMap.values()) {
2803             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2804             Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2805             if (vpnMap != null) {
2806                 if (rtr != null) {
2807                     Uuid extVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2808                     if (vpnMap.getRouterIds() != null && vpnMap.getRouterIds().size() > 1) {
2809                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
2810                                 .append(routerId.getRouterId());
2811                     } else if (extVpnId != null) {
2812                         returnMsg.append("router ").append(routerId.getRouterId()).append(" already associated to "
2813                                 + "another VPN ").append(extVpnId.getValue());
2814                     } else {
2815                         LOG.debug("associateRouter RPC: VpnId {}, routerId {}", vpnId.getValue(),
2816                                 routerId.getRouterId());
2817                         associateRouterToVpn(vpnId, routerId.getRouterId());
2818                     }
2819                 } else {
2820                     returnMsg.append("router not found : ").append(routerId.getRouterId());
2821                 }
2822             } else {
2823                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2824             }
2825             if (returnMsg.length() != 0) {
2826                 result.set(RpcResultBuilder.<AssociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
2827                         "invalid-value", formatAndLog(LOG::error, "associate router to vpn {} failed "
2828                                 + "due to {}", routerId.getRouterId(), returnMsg)).build());
2829             } else {
2830                 result.set(RpcResultBuilder.success(new AssociateRouterOutputBuilder().build()).build());
2831             }
2832         }
2833         LOG.debug("associateRouter returns..");
2834         return result;
2835     }
2836
2837     /**
2838      * It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
2839      */
2840     @Override
2841     // TODO Clean up the exception handling
2842     @SuppressWarnings("checkstyle:IllegalCatch")
2843     public ListenableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
2844         GetFixedIPsForNeutronPortInput input) {
2845         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
2846         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
2847         Uuid portId = input.getPortId();
2848         StringBuilder returnMsg = new StringBuilder();
2849         try {
2850             List<String> fixedIPList = new ArrayList<>();
2851             Port port = neutronvpnUtils.getNeutronPort(portId);
2852             if (port != null) {
2853                 for (FixedIps ip : port.nonnullFixedIps().values()) {
2854                     fixedIPList.add(ip.getIpAddress().stringValue());
2855                 }
2856             } else {
2857                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
2858             }
2859             if (returnMsg.length() != 0) {
2860                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withWarning(ErrorType.PROTOCOL,
2861                         "invalid-value",
2862                         formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port failed due to {}",
2863                                 returnMsg)).build());
2864             } else {
2865                 opBuilder.setFixedIPs(fixedIPList);
2866                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().withResult(opBuilder.build())
2867                         .build());
2868                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().build());
2869             }
2870         } catch (Exception ex) {
2871             result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withError(ErrorType.APPLICATION,
2872                     formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port {} failed due to {}",
2873                             portId.getValue(), ex.getMessage(), ex)).build());
2874         }
2875         return result;
2876     }
2877
2878     /**
2879      * It handles the invocations to the neutronvpn:dissociateNetworks RPC method.
2880      */
2881     @Override
2882     // TODO Clean up the exception handling
2883     @SuppressWarnings("checkstyle:IllegalCatch")
2884     public ListenableFuture<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
2885
2886         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
2887         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
2888
2889         LOG.debug("dissociateNetworks {}", input);
2890         StringBuilder returnMsg = new StringBuilder();
2891         Uuid vpnId = input.getVpnId();
2892
2893         try {
2894             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2895                 LOG.debug("dissociateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2896                         input.getNetworkId());
2897                 List<Uuid> netIds = input.getNetworkId();
2898                 if (netIds != null && !netIds.isEmpty()) {
2899                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
2900                     if (!failed.isEmpty()) {
2901                         returnMsg.append(failed);
2902                     }
2903                 }
2904             } else {
2905                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2906             }
2907             if (returnMsg.length() != 0) {
2908                 opBuilder.setResponse(
2909                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2910                                 "dissociate Networks to vpn {} failed due to {}", vpnId.getValue(),
2911                                 returnMsg));
2912                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
2913             } else {
2914                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
2915             }
2916         } catch (Exception ex) {
2917             result.set(RpcResultBuilder.<DissociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2918                     formatAndLog(LOG::error, "dissociate Networks to vpn {} failed due to {}",
2919                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2920         }
2921         LOG.debug("dissociateNetworks returns..");
2922         return result;
2923     }
2924
2925     /**
2926      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
2927      */
2928     @Override
2929     // TODO Clean up the exception handling
2930     @SuppressWarnings("checkstyle:IllegalCatch")
2931     public ListenableFuture<RpcResult<DissociateRouterOutput>> dissociateRouter(DissociateRouterInput input) {
2932
2933         SettableFuture<RpcResult<DissociateRouterOutput>> result = SettableFuture.create();
2934
2935         LOG.debug("dissociateRouter {}", input);
2936         StringBuilder returnMsg = new StringBuilder();
2937         Uuid vpnId = input.getVpnId();
2938         Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2939                 .RouterIdsKey, org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602
2940                 .dissociaterouter.input.RouterIds> keyRouterIdsMap = input.nonnullRouterIds();
2941         String routerIdsString = "";
2942         Preconditions.checkArgument(!keyRouterIdsMap.isEmpty(), "dissociateRouter: RouterIds list is empty!");
2943         Preconditions.checkNotNull(vpnId, "dissociateRouter: vpnId not found!");
2944         Preconditions.checkNotNull(keyRouterIdsMap, "dissociateRouter: keyRouterIdsMap not found!");
2945         if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2946             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2947                     .RouterIds routerId : keyRouterIdsMap.values()) {
2948                 try {
2949                     if (routerId != null) {
2950                         routerIdsString += routerId.getRouterId() + ", ";
2951                         Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2952                         if (rtr != null) {
2953                             Uuid routerVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2954                             if (routerVpnId == null) {
2955                                 returnMsg.append("input router ").append(routerId.getRouterId())
2956                                         .append(" not associated to any vpn yet");
2957                             } else if (vpnId.equals(routerVpnId)) {
2958                                 dissociateRouterFromVpn(vpnId, routerId.getRouterId());
2959                             } else {
2960                                 returnMsg.append("input router ").append(routerId.getRouterId())
2961                                         .append(" associated to vpn ")
2962                                         .append(routerVpnId.getValue()).append("instead of the vpn given as input");
2963                             }
2964                         } else {
2965                             returnMsg.append("router not found : ").append(routerId.getRouterId());
2966                         }
2967                     }
2968                     if (returnMsg.length() != 0) {
2969                         result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
2970                                 "invalid-value", formatAndLog(LOG::error, "dissociate router {} to "
2971                                                 + "vpn {} failed due to {}", routerId.getRouterId(), vpnId.getValue(),
2972                                         returnMsg)).build());
2973                     } else {
2974                         result.set(RpcResultBuilder.success(new DissociateRouterOutputBuilder().build()).build());
2975                     }
2976                 } catch (Exception ex) {
2977                     result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withError(ErrorType.APPLICATION,
2978                             formatAndLog(LOG::error, "disssociate router {} to vpn {} failed due to {}",
2979                                     routerId.getRouterId(), vpnId.getValue(), ex.getMessage(), ex)).build());
2980                 }
2981             }
2982         } else {
2983             returnMsg.append("VPN not found : ").append(vpnId.getValue());
2984         }
2985
2986         LOG.debug("dissociateRouter returns..");
2987         return result;
2988     }
2989
2990     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
2991         // check if the router is associated to some VPN
2992         Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
2993         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
2994         if (vpnId != null) {
2995             // remove existing external vpn interfaces
2996             for (Uuid subnetId : routerSubnetIds) {
2997                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
2998                 if (subnetmap != null) {
2999                     removeSubnetFromVpn(vpnId, subnetmap, internetVpnId);
3000                 } else {
3001                     LOG.error("handleNeutronRouterDeleted: Subnetmap for subnet {} not found when deleting router {}",
3002                             subnetId, routerId.getValue());
3003                 }
3004             }
3005             clearFromVpnMaps(vpnId, routerId, null);
3006         } else {
3007             // remove existing internal vpn interfaces
3008             for (Uuid subnetId : routerSubnetIds) {
3009                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
3010                 if (subnetmap != null) {
3011                     removeSubnetFromVpn(routerId, subnetmap, internetVpnId);
3012                 } else {
3013                     LOG.error("handleNeutronRouterDeleted: Subnetmap for subnet {} not found when deleting router {}",
3014                             subnetId, routerId.getValue());
3015                 }
3016             }
3017         }
3018         // delete entire vpnMaps node for internal VPN
3019         deleteVpnMapsNode(routerId);
3020
3021         // delete vpn-instance for internal VPN
3022         deleteVpnInstance(routerId);
3023     }
3024
3025     protected Subnet getNeutronSubnet(Uuid subnetId) {
3026         return neutronvpnUtils.getNeutronSubnet(subnetId);
3027     }
3028
3029     @Nullable
3030     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
3031         Subnet sn = neutronvpnUtils.getNeutronSubnet(subnetId);
3032         if (null != sn) {
3033             return sn.getGatewayIp();
3034         }
3035         return null;
3036     }
3037
3038
3039     protected Network getNeutronNetwork(Uuid networkId) {
3040         return neutronvpnUtils.getNeutronNetwork(networkId);
3041     }
3042
3043     protected Port getNeutronPort(String name) {
3044         return neutronvpnUtils.getNeutronPort(new Uuid(name));
3045     }
3046
3047     protected Port getNeutronPort(Uuid portId) {
3048         return neutronvpnUtils.getNeutronPort(portId);
3049     }
3050
3051     protected Uuid getNetworkForSubnet(Uuid subnetId) {
3052         return neutronvpnUtils.getNetworkForSubnet(subnetId);
3053     }
3054
3055     protected List<Uuid> getNetworksForVpn(Uuid vpnId) {
3056         return neutronvpnUtils.getNetworksForVpn(vpnId);
3057     }
3058
3059     /**
3060      * Implementation of the "vpnservice:neutron-ports-show" Karaf CLI command.
3061      *
3062      * @return a List of String to be printed on screen
3063      * @throws ExecutionException or InterruptedException   if there was a problem reading from the data store
3064      */
3065     public List<String> showNeutronPortsCLI() throws ExecutionException, InterruptedException {
3066         List<String> result = new ArrayList<>();
3067         result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", "Port ID", "Mac Address", "Prefix Length",
3068             "IP Address"));
3069         result.add("-------------------------------------------------------------------------------------------");
3070         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
3071
3072         Optional<Ports> ports = syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
3073         if (ports.isPresent() && ports.get().getPort() != null) {
3074             for (Port port : ports.get().nonnullPort().values()) {
3075                 Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.getFixedIps();
3076                 if (keyFixedIpsMap != null && !keyFixedIpsMap.isEmpty()) {
3077                     List<String> ipList = new ArrayList<>();
3078                     for (FixedIps fixedIp : keyFixedIpsMap.values()) {
3079                         IpAddress ipAddress = fixedIp.getIpAddress();
3080                         if (ipAddress.getIpv4Address() != null) {
3081                             ipList.add(ipAddress.getIpv4Address().getValue());
3082                         } else {
3083                             ipList.add(ipAddress.getIpv6Address().getValue());
3084                         }
3085                     }
3086                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
3087                             .getMacAddress().getValue(), neutronvpnUtils.getIPPrefixFromPort(port),
3088                             ipList.toString()));
3089                 } else {
3090                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
3091                             .getMacAddress().getValue(), "Not Assigned", "Not Assigned"));
3092                 }
3093             }
3094         }
3095
3096         return result;
3097     }
3098
3099     /**
3100      * Implementation of the "vpnservice:l3vpn-config-show" karaf CLI command.
3101      *
3102      * @param vpnuuid Uuid of the VPN whose config must be shown
3103      * @return formatted output list
3104      * @throws InterruptedException if there was a thread related problem getting the data to display
3105      * @throws ExecutionException if there was any other problem getting the data to display
3106      */
3107     public List<String> showVpnConfigCLI(Uuid vpnuuid) throws InterruptedException, ExecutionException {
3108         List<String> result = new ArrayList<>();
3109         if (vpnuuid == null) {
3110             result.add("");
3111             result.add("Displaying VPN config for all VPNs");
3112             result.add("To display VPN config for a particular VPN, use the following syntax");
3113             result.add(getshowVpnConfigCLIHelp());
3114         }
3115         RpcResult<GetL3VPNOutput> rpcResult = getL3VPN(new GetL3VPNInputBuilder().setId(vpnuuid).build()).get();
3116         if (rpcResult.isSuccessful()) {
3117             result.add("");
3118             result.add(String.format(" %-37s %-37s %-7s ", "VPN ID", "Tenant ID", "RD"));
3119             result.add("");
3120             result.add(String.format(" %-80s ", "Import-RTs"));
3121             result.add("");
3122             result.add(String.format(" %-80s ", "Export-RTs"));
3123             result.add("");
3124             result.add(String.format(" %-76s ", "Subnet IDs"));
3125             result.add("");
3126             result.add("------------------------------------------------------------------------------------");
3127             result.add("");
3128             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnInstance vpn :
3129                     rpcResult.getResult().nonnullL3vpnInstances()) {
3130                 String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
3131                         : "\"                 " + "                  \"";
3132                 result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
3133                         vpn.getRouteDistinguisher()));
3134                 result.add("");
3135                 result.add(String.format(" %-80s ", vpn.getImportRT()));
3136                 result.add("");
3137                 result.add(String.format(" %-80s ", vpn.getExportRT()));
3138                 result.add("");
3139
3140                 Uuid vpnid = vpn.getId();
3141                 List<Uuid> subnetList = neutronvpnUtils.getSubnetsforVpn(vpnid);
3142                 if (!subnetList.isEmpty()) {
3143                     for (Uuid subnetuuid : subnetList) {
3144                         result.add(String.format(" %-76s ", subnetuuid.getValue()));
3145                     }
3146                 } else {
3147                     result.add(String.format(" %-76s ", "\"                                    \""));
3148                 }
3149                 result.add("");
3150                 result.add("----------------------------------------");
3151                 result.add("");
3152             }
3153         } else {
3154             String errortag = rpcResult.getErrors().iterator().next().getTag();
3155             if (Objects.equals(errortag, "")) {
3156                 result.add("");
3157                 result.add("No VPN has been configured yet");
3158             } else if (Objects.equals(errortag, "invalid-value")) {
3159                 result.add("");
3160                 result.add("VPN " + vpnuuid.getValue() + " is not present");
3161             } else {
3162                 result.add("error getting VPN info : " + rpcResult.getErrors());
3163                 result.add(getshowVpnConfigCLIHelp());
3164             }
3165         }
3166         return result;
3167     }
3168
3169     protected void createExternalVpnInterfaces(Uuid extNetId) {
3170         if (extNetId == null) {
3171             LOG.error("createExternalVpnInterfaces: external network is null");
3172             return;
3173         }
3174
3175         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
3176         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3177             LOG.error("No external ports attached to external network {}", extNetId.getValue());
3178             return;
3179         }
3180
3181         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3182             for (String elanInterface : extElanInterfaces) {
3183                 createExternalVpnInterface(extNetId, elanInterface, tx);
3184             }
3185         }), LOG, "Error creating external VPN interfaces for {}", extNetId);
3186     }
3187
3188     // TODO Clean up the exception handling
3189     @SuppressWarnings("checkstyle:IllegalCatch")
3190     protected void removeExternalVpnInterfaces(Uuid extNetId) {
3191         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
3192         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3193             LOG.error("No external ports attached for external network {}", extNetId.getValue());
3194             return;
3195         }
3196         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3197             for (String elanInterface : extElanInterfaces) {
3198                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
3199                         .buildVpnInterfaceIdentifier(elanInterface);
3200                 LOG.info("Removing vpn interface {}", elanInterface);
3201                 tx.delete(vpnIfIdentifier);
3202             }
3203         }), LOG, "Error removing external VPN interfaces for {}", extNetId);
3204     }
3205
3206     private void createExternalVpnInterface(Uuid vpnId, String infName,
3207                                             TypedWriteTransaction<Configuration> wrtConfigTxn) {
3208         writeVpnInterfaceToDs(Collections.singletonList(vpnId), infName, null, vpnId /* external network id */,
3209                 false /* not a router iface */, wrtConfigTxn);
3210     }
3211
3212     // TODO Clean up the exception handling
3213     @SuppressWarnings("checkstyle:IllegalCatch")
3214     private void writeVpnInterfaceToDs(@NonNull Collection<Uuid> vpnIdList, String infName,
3215             @Nullable Adjacencies adjacencies, Uuid networkUuid, Boolean isRouterInterface,
3216             TypedWriteTransaction<Configuration> wrtConfigTxn) {
3217         if (vpnIdList.isEmpty() || infName == null) {
3218             LOG.error("vpnid is empty or interface({}) is null", infName);
3219             return;
3220         }
3221         if (wrtConfigTxn == null) {
3222             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
3223                 tx -> writeVpnInterfaceToDs(vpnIdList, infName, adjacencies, networkUuid, isRouterInterface, tx)), LOG,
3224                 "Error writing VPN interface");
3225             return;
3226         }
3227         List<VpnInstanceNames> vpnIdListStruct = new ArrayList<>();
3228         for (Uuid vpnId: vpnIdList) {
3229             VpnInstanceNames vpnInstance = VpnHelper.getVpnInterfaceVpnInstanceNames(vpnId.getValue(),
3230                                    AssociatedSubnetType.V4AndV6Subnets);
3231             vpnIdListStruct.add(vpnInstance);
3232         }
3233
3234         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3235         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
3236                 .setName(infName)
3237                 .setVpnInstanceNames(vpnIdListStruct)
3238                 .setRouterInterface(isRouterInterface);
3239         LOG.info("Network Id is {}", networkUuid);
3240         if (networkUuid != null) {
3241             Network portNetwork = neutronvpnUtils.getNeutronNetwork(networkUuid);
3242             ProviderTypes providerType = NeutronvpnUtils.getProviderNetworkType(portNetwork);
3243             NetworkAttributes.NetworkType networkType = providerType != null
3244                     ? NetworkAttributes.NetworkType.valueOf(providerType.getName()) : null;
3245             String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(portNetwork);
3246             vpnb.setNetworkId(networkUuid).setNetworkType(networkType)
3247                 .setSegmentationId(segmentationId != null ? Long.parseLong(segmentationId) : 0L);
3248         }
3249
3250         if (adjacencies != null) {
3251             vpnb.addAugmentation(Adjacencies.class, adjacencies);
3252         }
3253         VpnInterface vpnIf = vpnb.build();
3254         try {
3255             LOG.info("Creating vpn interface {}", vpnIf);
3256             wrtConfigTxn.put(vpnIfIdentifier, vpnIf);
3257         } catch (Exception ex) {
3258             LOG.error("Creation of vpninterface {} failed", infName, ex);
3259         }
3260     }
3261
3262     private void updateVpnInterfaceWithAdjacencies(Uuid vpnId, String infName, Adjacencies adjacencies,
3263                                                    TypedWriteTransaction<Configuration> wrtConfigTxn) {
3264         if (vpnId == null || infName == null) {
3265             LOG.error("vpn id or interface is null");
3266             return;
3267         }
3268         if (wrtConfigTxn == null) {
3269             LOG.error("updateVpnInterfaceWithAdjancies called with wrtConfigTxn as null");
3270             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3271                 updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, tx);
3272             }), LOG, "Error updating VPN interface with adjacencies");
3273             return;
3274         }
3275
3276         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3277
3278         try (AcquireResult lock = tryInterfaceLock(infName)) {
3279             if (!lock.wasAcquired()) {
3280                 // FIXME: why do we even bother with locking if we do not honor it?!
3281                 logTryLockFailure(infName);
3282             }
3283
3284             try {
3285                 Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker
3286                         .syncReadOptional(dataBroker, LogicalDatastoreType
3287                             .CONFIGURATION, vpnIfIdentifier);
3288                 if (optionalVpnInterface.isPresent()) {
3289                     VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get());
3290                     LOG.debug("Updating vpn interface {} with new adjacencies", infName);
3291
3292                     if (adjacencies == null) {
3293                         return;
3294                     }
3295                     vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
3296                     if (optionalVpnInterface.get().getVpnInstanceNames() != null) {
3297                         List<VpnInstanceNames> listVpnInstances = new ArrayList<>(
3298                                 optionalVpnInterface.get().getVpnInstanceNames().values());
3299                         if (listVpnInstances.isEmpty()
3300                                 || !VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpnInstances)) {
3301                             VpnInstanceNames vpnInstance = VpnHelper.getVpnInterfaceVpnInstanceNames(vpnId.getValue(),
3302                                 AssociatedSubnetType.V4AndV6Subnets);
3303                             listVpnInstances.add(vpnInstance);
3304                             vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3305                         }
3306                     } else {
3307                         VpnInstanceNames vpnInstance = VpnHelper
3308                                 .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
3309                         List<VpnInstanceNames> listVpnInstances = new ArrayList<>();
3310                         listVpnInstances.add(vpnInstance);
3311                         vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3312                     }
3313                     LOG.info("Updating vpn interface {} with new adjacencies", infName);
3314                     wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
3315                 }
3316             } catch (IllegalStateException | ExecutionException | InterruptedException ex) {
3317                 // FIXME: why are we catching IllegalStateException here?
3318                 LOG.error("Update of vpninterface {} failed", infName, ex);
3319             }
3320         }
3321     }
3322
3323     private String getshowVpnConfigCLIHelp() {
3324         StringBuilder help = new StringBuilder("Usage:");
3325         help.append("display vpn-config [-vid/--vpnid <id>]");
3326         return help.toString();
3327     }
3328
3329     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
3330         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
3331     }
3332
3333     @Override
3334     public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
3335         return neutronEvpnManager.createEVPN(input);
3336     }
3337
3338     @Override
3339     public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
3340         return neutronEvpnManager.getEVPN(input);
3341     }
3342
3343     @Override
3344     public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
3345         return neutronEvpnManager.deleteEVPN(input);
3346     }
3347
3348     private boolean addExternalNetworkToVpn(Network extNet, Uuid vpnId) {
3349         Uuid extNetId = extNet.getUuid();
3350         InstanceIdentifier<Networks> extNetIdentifier = InstanceIdentifier.builder(ExternalNetworks.class)
3351                 .child(Networks.class, new NetworksKey(extNetId)).build();
3352
3353         try {
3354             Optional<Networks> optionalExtNets =
3355                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3356                                                                  extNetIdentifier);
3357             if (!optionalExtNets.isPresent()) {
3358                 LOG.error("addExternalNetworkToVpn: Provider Network {} is not present in ConfigDS",
3359                           extNetId.getValue());
3360                 return false;
3361             }
3362             NetworksBuilder builder = new NetworksBuilder(optionalExtNets.get());
3363             builder.setVpnid(vpnId);
3364             Networks networks = builder.build();
3365             // Add Networks object to the ExternalNetworks list
3366             LOG.trace("addExternalNetworkToVpn: Set VPN Id {} for Provider Network {}", vpnId.getValue(),
3367                       extNetId.getValue());
3368             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetIdentifier,
3369                                                   networks);
3370             return true;
3371         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException ex) {
3372             LOG.error("addExternalNetworkToVpn: Failed to set VPN Id {} to Provider Network {}: ", vpnId.getValue(),
3373                       extNetId.getValue(), ex);
3374         }
3375         return false;
3376     }
3377
3378     private boolean removeExternalNetworkFromVpn(Network extNet) {
3379         Uuid extNetId = extNet.getUuid();
3380         InstanceIdentifier<Networks> extNetsId = InstanceIdentifier.builder(ExternalNetworks.class)
3381             .child(Networks.class, new NetworksKey(extNetId)).build();
3382         try {
3383             Optional<Networks> optionalNets =
3384                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3385                             extNetsId);
3386             NetworksBuilder builder = null;
3387             if (optionalNets.isPresent()) {
3388                 builder = new NetworksBuilder(optionalNets.get());
3389             } else {
3390                 LOG.error("removeExternalNetworkFromVpn: Provider Network {} is not present in the ConfigDS",
3391                         extNetId.getValue());
3392                 return false;
3393             }
3394             builder.setVpnid(null);
3395             Networks networks = builder.build();
3396             LOG.info("removeExternalNetworkFromVpn: Withdraw VPN Id from Provider Network {} node",
3397                     extNetId.getValue());
3398             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetsId, networks);
3399             return true;
3400         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException ex) {
3401             LOG.error("removeExternalNetworkFromVpn: Failed to withdraw VPN Id from Provider Network node {}: ",
3402                     extNetId.getValue(), ex);
3403         }
3404         return false;
3405     }
3406
3407     private Optional<String> getExistingOperationalVpn(String primaryRd) {
3408         Optional<String> existingVpnName = Optional.of(primaryRd);
3409         Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataOptional;
3410         try {
3411             vpnInstanceOpDataOptional = syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
3412                     neutronvpnUtils.getVpnOpDataIdentifier(primaryRd));
3413         } catch (ExecutionException | InterruptedException e) {
3414             LOG.error("getExistingOperationalVpn: Exception while checking operational status of vpn with rd {}",
3415                     primaryRd, e);
3416             /*Read failed. We don't know if a VPN exists or not.
3417             * Return primaryRd to halt caller execution, to be safe.*/
3418             return existingVpnName;
3419         }
3420         if (vpnInstanceOpDataOptional.isPresent()) {
3421             existingVpnName = Optional.of(vpnInstanceOpDataOptional.get().getVpnInstanceName());
3422         } else {
3423             existingVpnName = Optional.empty();
3424         }
3425         return existingVpnName;
3426     }
3427
3428     private static String formatAndLog(Consumer<String> logger, String template, Object arg) {
3429         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
3430     }
3431
3432     private static String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
3433         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
3434     }
3435
3436     private static String formatAndLog(Consumer<String> logger, String template, Object... args) {
3437         return logAndReturnMessage(logger, MessageFormatter.arrayFormat(template, args));
3438     }
3439
3440     private static String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
3441         String message = tuple.getMessage();
3442         logger.accept(message);
3443         return message;
3444     }
3445
3446     protected void addV6PrivateSubnetToExtNetwork(@NonNull Uuid routerId, @NonNull Uuid internetVpnId,
3447                                                   @NonNull Subnetmap subnetMap) {
3448         updateVpnInternetForSubnet(subnetMap, internetVpnId, true);
3449         neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
3450         if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(IpVersionChoice.IPV6, routerId, true)) {
3451             neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, true);
3452             LOG.info("addV6PrivateSubnetToExtNetwork: Advertise IPv6 Private Subnet {} to Internet VPN {}",
3453                     subnetMap.getId().getValue(), internetVpnId.getValue());
3454         }
3455     }
3456
3457     protected void removeV6PrivateSubnetToExtNetwork(@NonNull Uuid routerId, @NonNull Uuid internetVpnId,
3458                                                      @NonNull Subnetmap subnetMap) {
3459         updateVpnInternetForSubnet(subnetMap, internetVpnId, false);
3460         neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, false);
3461     }
3462
3463     protected void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove) {
3464         if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
3465             LOG.debug("processV6InternetFlowsForRtr: Successfully {} V6 internet vpn {} default fallback rule "
3466                             + "for the router {}", addOrRemove == NwConstants.ADD_FLOW ? "added" : "removed",
3467                     internetVpnId.getValue(), routerId.getValue());
3468             neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, addOrRemove == NwConstants.ADD_FLOW
3469                     ? true : false);
3470         }
3471     }
3472
3473     @CheckReturnValue
3474     private AcquireResult tryInterfaceLock(final String infName) {
3475         return interfaceLock.tryAcquire(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
3476     }
3477
3478     @CheckReturnValue
3479     private AcquireResult tryVpnLock(final Uuid vpnId) {
3480         return vpnLock.tryAcquire(vpnId, LOCK_WAIT_TIME, TimeUnit.SECONDS);
3481     }
3482
3483     private static ReentrantLock lockForUuid(Uuid uuid) {
3484         // FIXME: prove that this locks only on Uuids and not some other entity or create a separate lock domain
3485         return JvmGlobalLocks.getLockForString(uuid.getValue());
3486     }
3487
3488     private static void logTryLockFailure(Object objectId) {
3489         LOG.warn("Lock for {} was not acquired, continuing anyway", objectId, new Throwable());
3490     }
3491 }