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