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