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