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