IPv6 loopback ip is not displaying in fib entry
[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<Adjacency>(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<Routes>(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<VpnInstanceNames>(keyVpnInstanceNamesMap.values()))) {
1014                 VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId,
1015                         new ArrayList<VpnInstanceNames>(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<VpnInstanceNames>(keyVpnInstanceNamesMap.values()))) {
1049                     VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId.getValue(),
1050                             new ArrayList<VpnInstanceNames>(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<AdjacencyKey, Adjacency>();
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.class, 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.EMPTY_LIST;
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.EMPTY_MAP;
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 ? null
1850                 : neutronvpnUtils.getInternetvpnUuidBoundToSubnetRouter(subnet);
1851         Subnetmap sn = updateSubnetNode(subnet, null, newVpnId, vpnExtUuid);
1852         if (sn == null) {
1853             LOG.error("Updating subnet {} with newVpn {} failed", subnet.getValue(), newVpnId.getValue());
1854             return sn;
1855         }
1856         /* vpnExtUuid will contain the value only on if the subnet is V6 and it is already been
1857          * associated with internet BGP-VPN.
1858          */
1859         if (vpnExtUuid != null) {
1860             /* Update V6 Internet default route match with new VPN metadata.
1861              * isBeingAssociated = true means oldVpnId is same as routerId
1862              * isBeingAssociated = false means newVpnId is same as routerId
1863             */
1864             if (isBeingAssociated) {
1865                 neutronvpnUtils.updateVpnInstanceWithFallback(oldVpnId, vpnExtUuid, true);
1866             } else {
1867                 neutronvpnUtils.updateVpnInstanceWithFallback(newVpnId, vpnExtUuid, true);
1868             }
1869         }
1870         //Update Router Interface first synchronously.
1871         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
1872         ListenableFuture<?> future =
1873                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1874                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1875                         neutronvpnUtils.getNeutronPort(sn.getRouterInterfacePortId()),
1876                         isBeingAssociated, true, tx, false));
1877         Futures.addCallback(future, new FutureCallback<Object>() {
1878             @Override
1879             public void onSuccess(Object result) {
1880                 // Check for ports on this subnet and update association of
1881                 // corresponding vpn-interfaces to external vpn
1882                 List<Uuid> portList = sn.getPortList();
1883                 if (portList != null) {
1884                     for (Uuid port : portList) {
1885                         LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1886                                 port.getValue(), isBeingAssociated);
1887                         jobCoordinator.enqueueJob("PORT-" + port.getValue(), () -> Collections.singletonList(
1888                                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1889                                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1890                                             neutronvpnUtils.getNeutronPort(port), isBeingAssociated, false,
1891                                             tx, false))));
1892                     }
1893                 }
1894             }
1895
1896             @Override
1897             public void onFailure(Throwable throwable) {
1898                 LOG.error(
1899                         "Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, "
1900                                 + "returning",
1901                         sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId, throwable);
1902             }
1903         }, MoreExecutors.directExecutor());
1904
1905         return sn;
1906     }
1907
1908     public InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
1909         return InstanceIdentifier.builder(RouterInterfacesMap.class)
1910                 .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
1911     }
1912
1913     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1914         final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1915         final ReentrantLock lock = lockForUuid(routerId);
1916         lock.lock();
1917         try {
1918             Optional<RouterInterfaces> optRouterInterfaces =
1919                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1920                         routerInterfacesId);
1921             Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1922                     .setInterfaceId(interfaceName).build();
1923             if (optRouterInterfaces.isPresent()) {
1924                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1925                     routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
1926             } else {
1927                 RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
1928                 List<Interfaces> interfaces = new ArrayList<>();
1929                 interfaces.add(routerInterface);
1930                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1931                     routerInterfacesId, builder.setInterfaces(interfaces).build());
1932             }
1933         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
1934             LOG.error("Error reading router interfaces for {}", routerInterfacesId, e);
1935         } finally {
1936             lock.unlock();
1937         }
1938     }
1939
1940     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1941         final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1942         final ReentrantLock lock = lockForUuid(routerId);
1943         lock.lock();
1944         try {
1945             Optional<RouterInterfaces> optRouterInterfaces =
1946                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1947                         routerInterfacesId);
1948             Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1949                     .setInterfaceId(interfaceName).build();
1950             if (optRouterInterfaces.isPresent()) {
1951                 RouterInterfaces routerInterfaces = optRouterInterfaces.get();
1952                 List<Interfaces> interfaces = new ArrayList<>(routerInterfaces.nonnullInterfaces().values());
1953                 if (interfaces != null && interfaces.remove(routerInterface)) {
1954                     if (interfaces.isEmpty()) {
1955                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1956                             routerInterfacesId);
1957                     } else {
1958                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1959                             routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
1960                     }
1961                 }
1962             }
1963         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
1964             LOG.error("Error reading the router interfaces for {}", routerInterfacesId, e);
1965         } finally {
1966             lock.unlock();
1967         }
1968     }
1969
1970     /**
1971      * Creates the corresponding static routes in the specified VPN. These static routes must be point to an
1972      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink. Otherwise the
1973      * route will be ignored.
1974      *
1975      * @param vpnName the VPN identifier
1976      * @param interVpnLinkRoutes The list of static routes
1977      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1978      */
1979     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1980                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1981         for (Routes route : interVpnLinkRoutes) {
1982             String nexthop = route.getNexthop().stringValue();
1983             String destination = route.getDestination().stringValue();
1984             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1985             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
1986                 AddStaticRouteInput rpcInput =
1987                         new AddStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1988                                 .setVpnInstanceName(vpnName.getValue())
1989                                 .build();
1990                 Future<RpcResult<AddStaticRouteOutput>> labelOuputFtr = vpnRpcService.addStaticRoute(rpcInput);
1991                 RpcResult<AddStaticRouteOutput> rpcResult;
1992                 try {
1993                     rpcResult = labelOuputFtr.get();
1994                     if (rpcResult.isSuccessful()) {
1995                         LOG.debug("Label generated for destination {} is: {}",
1996                                 destination, rpcResult.getResult().getLabel());
1997                     } else {
1998                         LOG.error("RPC call to add a static Route to {} with nexthop {} returned with errors {}",
1999                                 destination, nexthop, rpcResult.getErrors());
2000                     }
2001                 } catch (InterruptedException | ExecutionException e) {
2002                     LOG.error("Error happened while invoking addStaticRoute RPC for nexthop {} with destination {} "
2003                             + "for VPN {}", nexthop, destination, vpnName.getValue(), e);
2004                 }
2005             } else {
2006                 // Any other case is a fault.
2007                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
2008                         route.getDestination().stringValue(), nexthop);
2009                 continue;
2010             }
2011         }
2012     }
2013
2014     /**
2015      * Removes the corresponding static routes from the specified VPN. These static routes point to an
2016      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink.
2017      *
2018      * @param vpnName the VPN identifier
2019      * @param interVpnLinkRoutes The list of static routes
2020      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
2021      */
2022     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
2023                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
2024         for (Routes route : interVpnLinkRoutes) {
2025             String nexthop = route.getNexthop().stringValue();
2026             String destination = route.getDestination().stringValue();
2027             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
2028             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
2029                 RemoveStaticRouteInput rpcInput =
2030                         new RemoveStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
2031                                 .setVpnInstanceName(vpnName.getValue())
2032                                 .build();
2033
2034                 LoggingFutures.addErrorLogging(JdkFutureAdapters.listenInPoolThread(
2035                         vpnRpcService.removeStaticRoute(rpcInput)), LOG, "Remove VPN routes");
2036             } else {
2037                 // Any other case is a fault.
2038                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
2039                         route.getDestination().stringValue(), nexthop);
2040                 continue;
2041             }
2042         }
2043     }
2044
2045     /*
2046      * Returns true if the specified nexthop is the other endpoint in an
2047      * InterVpnLink, regarding one of the VPN's point of view.
2048      */
2049     private static boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid,
2050             InterVpnLink interVpnLink) {
2051         return
2052                 interVpnLink != null
2053                         && (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
2054                         && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop)
2055                         || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
2056                         && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop));
2057     }
2058
2059     @NonNull
2060     protected List<Adjacency> getAdjacencyforExtraRoute(List<Routes> routeList, String fixedIp) {
2061         List<Adjacency> adjList = new ArrayList<>();
2062         Map<String, List<String>> adjMap = new HashMap<>();
2063         for (Routes route : routeList) {
2064             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
2065                 LOG.error("Incorrect input received for extra route. {}", route);
2066             } else {
2067                 String nextHop = route.getNexthop().stringValue();
2068                 String destination = route.getDestination().stringValue();
2069                 if (!nextHop.equals(fixedIp)) {
2070                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
2071                     continue;
2072                 }
2073                 LOG.trace("Adding extra route for destination {} with nexthop {} ", destination,
2074                         nextHop);
2075                 List<String> hops = adjMap.computeIfAbsent(destination, k -> new ArrayList<>());
2076                 if (!hops.contains(nextHop)) {
2077                     hops.add(nextHop);
2078                 }
2079             }
2080         }
2081
2082         for (Entry<String, List<String>> entry : adjMap.entrySet()) {
2083             final String destination = entry.getKey();
2084             final List<String> ipList = entry.getValue();
2085             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
2086                     .setAdjacencyType(AdjacencyType.ExtraRoute).setNextHopIpList(ipList)
2087                     .withKey(new AdjacencyKey(destination)).build();
2088             adjList.add(erAdj);
2089         }
2090         return adjList;
2091     }
2092
2093     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
2094         checkAlarmExtraRoutes(vpnId, routeList);
2095
2096         for (Routes route : routeList) {
2097             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
2098                 LOG.error("Incorrect input received for extra route. {}", route);
2099             } else {
2100                 String nextHop = route.getNexthop().stringValue();
2101                 String destination = route.getDestination().stringValue();
2102                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2103                         nextHop);
2104                 if (infName != null) {
2105                     LOG.trace("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}",
2106                         destination, vpnId.getValue(), nextHop, infName);
2107                     boolean isLockAcquired = false;
2108                     try {
2109                         InstanceIdentifier<VpnInterface> identifier = InstanceIdentifier.builder(VpnInterfaces.class)
2110                                 .child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2111                         InstanceIdentifier<Adjacency> path = identifier.augmentation(Adjacencies.class)
2112                             .child(Adjacency.class, new AdjacencyKey(destination));
2113                         Optional<Adjacency> existingAdjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2114                                 LogicalDatastoreType.CONFIGURATION, path);
2115                         if (existingAdjacency.isPresent()
2116                                 && existingAdjacency.get().getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2117                             LOG.error("The route with destination {} nextHop {} is already present as"
2118                                             + " a primary adjacency for interface {}. Skipping adjacency addition.",
2119                                     destination, nextHop, infName);
2120                             continue;
2121                         }
2122                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
2123                             .setNextHopIpList(Collections.singletonList(nextHop)).withKey(new AdjacencyKey(destination))
2124                             .setAdjacencyType(AdjacencyType.ExtraRoute).build();
2125
2126                         try (AcquireResult lock = tryInterfaceLock(infName)) {
2127                             if (!lock.wasAcquired()) {
2128                                 // FIXME: why do we even bother with locking if we do not honor it?!
2129                                 logTryLockFailure(infName);
2130                             }
2131
2132                             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2133                                 path, erAdj);
2134                         }
2135                     } catch (TransactionCommitFailedException e) {
2136                         LOG.error("exception in adding extra route with destination: {}, next hop: {}",
2137                             destination, nextHop, e);
2138                     } catch (ExecutionException | InterruptedException e) {
2139                         LOG.error("Exception on reading data-store ", e);
2140                     }
2141                 } else {
2142                     LOG.error("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} "
2143                         + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2144                 }
2145             }
2146         }
2147     }
2148
2149     /**
2150      * This method setup or down an alarm about extra route fault.
2151      * When extra routes are configured, through a router, if the number of nexthops is greater than the number of
2152      * available RDs, then an alarm and an error is generated.<br>
2153      * <b>Be careful</b> the routeList could be changed.
2154      *
2155      * @param vpnId the vpnId of vpn to control.
2156      * @param routeList the list of router to check, it could be modified.
2157      */
2158     private void checkAlarmExtraRoutes(Uuid vpnId, List<Routes> routeList) {
2159         if (!neutronvpnAlarm.isAlarmEnabled()) {
2160             LOG.debug("checkAlarmExtraRoutes is not enable for vpnId {} routeList {}", vpnId, routeList);
2161             return;
2162         }
2163         VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(dataBroker, vpnId);
2164         if (vpnInstance == null || routeList == null || routeList.isEmpty() || !neutronvpnAlarm.isAlarmEnabled()) {
2165             LOG.debug("checkAlarmExtraRoutes have args null as following : vpnId {} routeList {}",
2166                     vpnId, routeList);
2167             return;
2168         }
2169         String primaryRd = neutronvpnUtils.getVpnRd(vpnId.getValue());
2170         if (primaryRd == null || primaryRd.equals(vpnId.getValue())) {
2171             LOG.debug("checkAlarmExtraRoutes. vpn {} is not a BGPVPN. cancel checkExtraRoute",
2172                     vpnId);
2173             return;
2174         }
2175         for (Routes route : routeList) {
2176             // count  the number of nexthops for each same route.getDestingation().getValue()
2177             String destination = route.getDestination().stringValue();
2178             String nextHop = route.getNexthop().stringValue();
2179             List<String> nextHopList = new ArrayList<>();
2180             nextHopList.add(nextHop);
2181             int nbNextHops = 1;
2182             for (Routes routeTmp : routeList) {
2183                 String routeDest = routeTmp.getDestination().stringValue();
2184                 if (!destination.equals(routeDest)) {
2185                     continue;
2186                 }
2187                 String routeNextH = routeTmp.getNexthop().stringValue();
2188                 if (nextHop.equals(routeNextH)) {
2189                     continue;
2190                 }
2191                 nbNextHops++;
2192                 nextHopList.add(routeTmp.getNexthop().stringValue());
2193             }
2194             final List<String> rdList = new ArrayList<>();
2195             if (vpnInstance != null
2196                     && vpnInstance.getRouteDistinguisher() != null) {
2197                 vpnInstance.getRouteDistinguisher().forEach(rd -> {
2198                     if (rd != null) {
2199                         rdList.add(rd);
2200                     }
2201                 });
2202             }
2203             // 1. VPN Instance Name
2204             String typeAlarm = "for vpnId: " + vpnId + " have exceeded next hops for prefixe";
2205
2206             // 2. Router ID
2207             List<Uuid> routerUuidList = neutronvpnUtils.getRouterIdListforVpn(vpnId);
2208             Uuid routerUuid = routerUuidList.get(0);
2209             StringBuilder detailsAlarm = new StringBuilder("routerUuid: ");
2210             detailsAlarm.append(routerUuid == null ? vpnId.toString() : routerUuid.getValue());
2211
2212             // 3. List of RDs associated with the VPN
2213             detailsAlarm.append(" List of RDs associated with the VPN: ");
2214             for (String s : rdList) {
2215                 detailsAlarm.append(s);
2216                 detailsAlarm.append(", ");
2217             }
2218
2219             // 4. Prefix in question
2220             detailsAlarm.append(" for prefix: ");
2221             detailsAlarm.append(route.getDestination().stringValue());
2222
2223             // 5. List of NHs for the prefix
2224             detailsAlarm.append(" for nextHops: ");
2225             for (String s : nextHopList) {
2226                 detailsAlarm.append(s);
2227                 detailsAlarm.append(", ");
2228             }
2229
2230             if (rdList.size() < nbNextHops) {
2231                 neutronvpnAlarm.raiseNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2232             } else {
2233                 neutronvpnAlarm.clearNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2234             }
2235         }
2236     }
2237
2238     // TODO Clean up the exception handling
2239     @SuppressWarnings("checkstyle:IllegalCatch")
2240     protected void removeAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList) {
2241         for (Routes route : routeList) {
2242             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
2243                 String nextHop = route.getNexthop().stringValue();
2244                 String destination = route.getDestination().stringValue();
2245                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2246                         nextHop);
2247                 if (infName == null) {
2248                     LOG.error("Unable to find VPN NextHop interface to remove extra-route destination {} on VPN {} "
2249                             + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2250                     // Proceed to remove the next extra-route
2251                     continue;
2252                 }
2253                 LOG.trace("Removing extra route for destination {} on vpn {} with nexthop {} and infName {}",
2254                         destination, vpnId.getValue(), nextHop, infName);
2255
2256                 InstanceIdentifier<Adjacency> adjacencyIdentifier =
2257                         InstanceIdentifier.builder(VpnInterfaces.class)
2258                                 .child(VpnInterface.class, new VpnInterfaceKey(infName))
2259                                 .augmentation(Adjacencies.class)
2260                                 .child(Adjacency.class, new AdjacencyKey(destination))
2261                                 .build();
2262
2263                 try {
2264                     // Looking for existing prefix in MDSAL database
2265                     Optional<Adjacency> adjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2266                             LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
2267                     boolean updateNextHops = false;
2268                     List<String> nextHopList = new ArrayList<>();
2269                     if (adjacency.isPresent()) {
2270                         List<String> nhListRead = adjacency.get().getNextHopIpList();
2271                         if (nhListRead.size() > 1) { // ECMP case
2272                             for (String nextHopRead : nhListRead) {
2273                                 if (nextHopRead.equals(nextHop)) {
2274                                     updateNextHops = true;
2275                                 } else {
2276                                     nextHopList.add(nextHopRead);
2277                                 }
2278                             }
2279                         }
2280                     }
2281
2282                     try (AcquireResult lock = tryInterfaceLock(infName)) {
2283                         if (!lock.wasAcquired()) {
2284                             // FIXME: why do we even bother with locking if we do not honor it?!
2285                             logTryLockFailure(infName);
2286                         }
2287
2288                         if (updateNextHops) {
2289                             // An update must be done, not including the current next hop
2290                             InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(
2291                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2292                             Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
2293                                     .setNextHopIpList(nextHopList)
2294                                     .withKey(new AdjacencyKey(destination))
2295                                     .build();
2296                             List<Adjacency> newAdjList = Collections.singletonList(newAdj);
2297                             Adjacencies erAdjs =
2298                                     new AdjacenciesBuilder().setAdjacency(getAdjacencyMap(newAdjList)).build();
2299                             VpnInterface vpnIf = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
2300                                     .addAugmentation(Adjacencies.class, erAdjs).build();
2301                             SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
2302                                 vpnIfIdentifier, vpnIf);
2303                         } else {
2304                             // Remove the whole route
2305                             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
2306                                 adjacencyIdentifier);
2307                             LOG.trace("extra route {} deleted successfully", route);
2308                         }
2309                     }
2310                 } catch (TransactionCommitFailedException | ExecutionException | InterruptedException e) {
2311                     LOG.error("exception in deleting extra route with destination {} for interface {}",
2312                             destination, infName, e);
2313                 }
2314             } else {
2315                 LOG.error("Incorrect input received for extra route: {}", route);
2316             }
2317         }
2318     }
2319
2320     public void removeVpn(Uuid vpnId) {
2321         // read VPNMaps
2322         VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2323         if (vpnMap != null) {
2324             Map<RouterIdsKey, RouterIds> keyRouterIdsMap = vpnMap.getRouterIds();
2325             List<Uuid> routerUuidList = new ArrayList<>();
2326             // dissociate router
2327             if (keyRouterIdsMap != null && !keyRouterIdsMap.isEmpty()) {
2328                 for (RouterIds router : keyRouterIdsMap.values()) {
2329                     Uuid routerId = router.getRouterId();
2330                     routerUuidList.add(routerId);
2331                     dissociateRouterFromVpn(vpnId, routerId);
2332                 }
2333             }
2334             if (!routerUuidList.contains(vpnId) && vpnMap.getNetworkIds() != null) {
2335                 dissociateNetworksFromVpn(vpnId, vpnMap.getNetworkIds());
2336             }
2337         } else {
2338             LOG.error("removeVpn: vpnMap is null for vpn {}", vpnId.getValue());
2339         }
2340         // remove entire vpnMaps node
2341         deleteVpnMapsNode(vpnId);
2342
2343         // remove vpn-instance
2344         deleteVpnInstance(vpnId);
2345         LOG.debug("Deleted L3VPN with ID {}", vpnId.getValue());
2346     }
2347
2348     private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
2349         return vpnInstance != null && vpnInstance.isL2vpn();
2350     }
2351
2352     // TODO Clean up the exception handling
2353     @SuppressWarnings("checkstyle:IllegalCatch")
2354     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
2355         updateVpnMaps(vpnId, null, routerId, null, null);
2356         LOG.debug("associateRouterToVpn: Updating association of subnets to external vpn {}", vpnId.getValue());
2357         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
2358         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2359         for (Subnetmap sn : subMapList) {
2360             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
2361             if (!ipVersion.isIpVersionChosen(ipVers)) {
2362                 ipVersion = ipVersion.addVersion(ipVers);
2363             }
2364         }
2365         if (ipVersion != IpVersionChoice.UNDEFINED) {
2366             LOG.debug("associateRouterToVpn: Updating vpnInstance ip address family {} for VPN {} ",
2367                     ipVersion, vpnId);
2368             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
2369         }
2370         for (Subnetmap sn : subMapList) {
2371             updateVpnForSubnet(routerId, vpnId, sn.getId(), true);
2372         }
2373     }
2374
2375     protected void associateRouterToInternalVpn(Uuid vpnId, Uuid routerId) {
2376         List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
2377         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
2378         LOG.debug("Adding subnets to internal vpn {}", vpnId.getValue());
2379         for (Uuid subnet : routerSubnets) {
2380             IpVersionChoice version = NeutronvpnUtils
2381                    .getIpVersionFromSubnet(neutronvpnUtils.getSubnetmap(subnet));
2382             if (version.isIpVersionChosen(IpVersionChoice.IPV4)) {
2383                 addSubnetToVpn(vpnId, subnet, null);
2384             } else {
2385                 addSubnetToVpn(vpnId, subnet, internetVpnId);
2386             }
2387         }
2388     }
2389
2390     // TODO Clean up the exception handling
2391     @SuppressWarnings("checkstyle:IllegalCatch")
2392     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
2393
2394         clearFromVpnMaps(vpnId, routerId, null);
2395         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
2396         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2397         for (Subnetmap sn : subMapList) {
2398             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
2399             if (ipVersion.isIpVersionChosen(ipVers)) {
2400                 ipVersion = ipVersion.addVersion(ipVers);
2401             }
2402             LOG.debug("dissociateRouterFromVpn: Updating association of subnets to internal vpn {}",
2403                     routerId.getValue());
2404             updateVpnForSubnet(vpnId, routerId, sn.getId(), false);
2405         }
2406         if (ipVersion != IpVersionChoice.UNDEFINED) {
2407             LOG.debug("dissociateRouterFromVpn; Updating vpnInstance with ip address family {} for VPN {} ",
2408                     ipVersion, vpnId);
2409             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
2410                     false);
2411         }
2412     }
2413
2414     /**
2415      * Parses and associates networks list with given VPN.
2416      *
2417      * @param vpnId Uuid of given VPN.
2418      * @param networkList List list of network Ids (Uuid), which will be associated.
2419      * @return list of formatted strings with detailed error messages.
2420      */
2421     @NonNull
2422     protected List<String> associateNetworksToVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
2423         List<String> failedNwList = new ArrayList<>();
2424         HashSet<Uuid> passedNwList = new HashSet<>();
2425         ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
2426         boolean isExternalNetwork = false;
2427         if (networkList.isEmpty()) {
2428             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
2429             failedNwList.add(String.format("Failed to associate networks with VPN %s as given networks list is empty",
2430                     vpnId.getValue()));
2431             return failedNwList;
2432         }
2433         VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
2434         if (vpnInstance == null) {
2435             LOG.error("associateNetworksToVpn: Can not find vpnInstance for VPN {} in ConfigDS", vpnId.getValue());
2436             failedNwList.add(String.format("Failed to associate network: can not found vpnInstance for VPN %s "
2437                                            + "in ConfigDS", vpnId.getValue()));
2438             return failedNwList;
2439         }
2440         try {
2441             if (isVpnOfTypeL2(vpnInstance) && neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance)) {
2442                 LOG.error("associateNetworksToVpn: EVPN {} supports only one network to be associated with",
2443                           vpnId.getValue());
2444                 failedNwList.add(String.format("Failed to associate network: EVPN %s supports only one network to be "
2445                                                + "associated with", vpnId.getValue()));
2446                 return failedNwList;
2447             }
2448             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2449             boolean isIpFamilyUpdated = false;
2450             IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2451             for (Uuid nw : networkList) {
2452                 Network network = neutronvpnUtils.getNeutronNetwork(nw);
2453                 if (network == null) {
2454                     LOG.error("associateNetworksToVpn: Network {} not found in ConfigDS", nw.getValue());
2455                     failedNwList.add(String.format("Failed to associate network: network %s not found in ConfigDS",
2456                                                    nw.getValue()));
2457                     continue;
2458                 }
2459                 NetworkProviderExtension providerExtension = network.augmentation(NetworkProviderExtension.class);
2460                 if (providerExtension.getSegments() != null && providerExtension.getSegments().size() > 1) {
2461                     LOG.error("associateNetworksToVpn: MultiSegmented network {} not supported in BGPVPN {}",
2462                               nw.getValue(), vpnId.getValue());
2463                     failedNwList.add(String.format("Failed to associate multisegmented network %s with BGPVPN %s",
2464                                                    nw.getValue(), vpnId.getValue()));
2465                     continue;
2466                 }
2467                 Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2468                 if (networkVpnId != null) {
2469                     LOG.error("associateNetworksToVpn: Network {} already associated with another VPN {}",
2470                               nw.getValue(), networkVpnId.getValue());
2471                     failedNwList.add(String.format("Failed to associate network %s as it is already associated to "
2472                                                    + "another VPN %s", nw.getValue(), networkVpnId.getValue()));
2473                     continue;
2474                 }
2475                 /* Handle association of external network(s) to Internet BGP-VPN use case outside of the
2476                  * networkList iteration
2477                  */
2478                 if (neutronvpnUtils.getIsExternal(network)) {
2479                     extNwMap.put(nw, network);
2480                     isExternalNetwork = true;
2481                     //Check whether router-gw is set with external network before external network to BGPVPN association
2482                     List<Uuid> routerList = neutronvpnUtils.getRouterIdsForExtNetwork(nw);
2483                     if (!routerList.isEmpty()) {
2484                         for (Uuid routerId : routerList) {
2485                             //If v6 subnet was already added to router means it requires IPv6 AddrFamily in VpnInstance
2486                             if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
2487                                 ipVersion = ipVersion.addVersion(IpVersionChoice.IPV6);
2488                                 LOG.debug("associateNetworksToVpn: External network {} is already associated with "
2489                                         + "router(router-gw) {} and V6 subnet is part of that router. Hence Set IPv6 "
2490                                         + "address family type in Internet VPN Instance {}", network, routerId, vpnId);
2491                                 break;
2492                             }
2493                         }
2494                     }
2495                 }
2496                 List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
2497                 if (subnetmapList == null || subnetmapList.isEmpty()) {
2498                     passedNwList.add(nw);
2499                     continue;
2500                 }
2501                 if (vpnManager.checkForOverlappingSubnets(nw, subnetmapList, vpnId, routeTargets, failedNwList)) {
2502                     continue;
2503                 }
2504                 for (Subnetmap subnetmap : subnetmapList) {
2505                     IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
2506                     if (!ipVersion.isIpVersionChosen(ipVers)) {
2507                         ipVersion = ipVersion.addVersion(ipVers);
2508                     }
2509                 }
2510                 //Update vpnInstance for IP address family
2511                 if (ipVersion != IpVersionChoice.UNDEFINED && !isIpFamilyUpdated) {
2512                     LOG.debug("associateNetworksToVpn: Updating vpnInstance with ip address family {}"
2513                             + " for VPN {} ", ipVersion, vpnId);
2514                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
2515                     isIpFamilyUpdated = true;
2516                 }
2517                 for (Subnetmap subnetmap : subnetmapList) {
2518                     Uuid subnetId = subnetmap.getId();
2519                     Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
2520                     if (subnetVpnId != null) {
2521                         LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {}"
2522                                 + " as it is already associated", subnetId.getValue(), subnetVpnId.getValue());
2523                         failedNwList.add(String.format("Failed to associate subnet %s with VPN %s"
2524                                 + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
2525                         continue;
2526                     }
2527                     if (!NeutronvpnUtils.getIsExternal(network)) {
2528                         LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
2529                                 vpnId.getValue());
2530                         addSubnetToVpn(vpnId, subnetId, null);
2531                         vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2532                                 vpnId.getValue());
2533                         passedNwList.add(nw);
2534                     }
2535                 }
2536                 passedNwList.add(nw);
2537                 //Handle association of external network(s) to Internet BGP-VPN Instance use case
2538                 if (!extNwMap.isEmpty() || extNwMap != null) {
2539                     for (Network extNw : extNwMap.values()) {
2540                         if (!associateExtNetworkToVpn(vpnId, extNw, vpnInstance.getBgpvpnType())) {
2541                             LOG.error("associateNetworksToVpn: Failed to associate Provider External Network {} with "
2542                                     + "VPN {}", extNw, vpnId.getValue());
2543                             failedNwList.add(String.format("Failed to associate Provider External Network %s with "
2544                                             + "VPN %s", extNw, vpnId.getValue()));
2545                             continue;
2546                         }
2547                     }
2548                 }
2549             }
2550         } catch (ExecutionException | InterruptedException e) {
2551             LOG.error("associateNetworksToVpn: Failed to associate VPN {} with networks {}: ", vpnId.getValue(),
2552                     networkList, e);
2553             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
2554                     networkList, e));
2555         }
2556         //VpnMap update for ext-nw is already done in associateExtNetworkToVpn() method.
2557         if (!isExternalNetwork) {
2558             updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
2559         }
2560         LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList, vpnId.getValue());
2561         return failedNwList;
2562     }
2563
2564     private boolean associateExtNetworkToVpn(@NonNull Uuid vpnId, @NonNull Network extNet,
2565                                              VpnInstance.BgpvpnType bgpVpnType) {
2566         if (!addExternalNetworkToVpn(extNet, vpnId)) {
2567             return false;
2568         }
2569         if (!bgpVpnType.equals(VpnInstance.BgpvpnType.InternetBGPVPN)) {
2570             LOG.info("associateExtNetworkToVpn: External network {} is associated to VPN {}."
2571                             + "Hence set vpnInstance type to {} from {} ", extNet.key().getUuid().getValue(),
2572                     vpnId.getValue(), VpnInstance.BgpvpnType.InternetBGPVPN.getName(),
2573                     VpnInstance.BgpvpnType.BGPVPN.getName());
2574             neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.InternetBGPVPN, vpnId);
2575         }
2576         //Update VpnMap with ext-nw is needed first before processing V6 internet default fallback flows
2577         List<Uuid> extNwList = Collections.singletonList(extNet.key().getUuid());
2578         updateVpnMaps(vpnId, null, null, null, extNwList);
2579         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2580         for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
2581             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2582             if (sm == null) {
2583                 LOG.error("associateExtNetworkToVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2584                 continue;
2585             }
2586             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
2587             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
2588                 continue;
2589             }
2590             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
2591                 updateVpnInternetForSubnet(sm, vpnId, true);
2592             }
2593             if (!ipVersion.isIpVersionChosen(ipVers)) {
2594                 ipVersion = ipVersion.addVersion(ipVers);
2595             }
2596         }
2597         if (ipVersion != IpVersionChoice.UNDEFINED) {
2598             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, true);
2599             LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
2600             neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, true);
2601         }
2602         return true;
2603     }
2604
2605     /**
2606      * Parses and disassociates networks list from given VPN.
2607      *
2608      * @param vpnId Uuid of given VPN.
2609      * @param networkList List list of network Ids (Uuid), which will be disassociated.
2610      * @return list of formatted strings with detailed error messages.
2611      */
2612     @NonNull
2613     protected List<String> dissociateNetworksFromVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
2614         List<String> failedNwList = new ArrayList<>();
2615         HashSet<Uuid> passedNwList = new HashSet<>();
2616         ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
2617         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2618         if (networkList.isEmpty()) {
2619             LOG.error("dissociateNetworksFromVpn: Failed as networks list is empty");
2620             failedNwList.add(String.format("Failed to disassociate networks from VPN %s as networks list is empty",
2621                              vpnId.getValue()));
2622             return failedNwList;
2623         }
2624         for (Uuid nw : networkList) {
2625             List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
2626             if (networkSubnets == null) {
2627                 passedNwList.add(nw);
2628                 continue;
2629             }
2630             Network network = neutronvpnUtils.getNeutronNetwork(nw);
2631             if (network == null) {
2632                 LOG.error("dissociateNetworksFromVpn: Network {} not found in ConfigDS", nw.getValue());
2633                 failedNwList.add(String.format("Failed to disassociate network %s as is not found in ConfigDS",
2634                         nw.getValue()));
2635                 continue;
2636             }
2637             Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2638             if (networkVpnId == null) {
2639                 LOG.error("dissociateNetworksFromVpn: Network {} is not associated to any VPN", nw.getValue());
2640                 failedNwList.add(String.format("Failed to disassociate network %s as is not associated to any VPN",
2641                                                nw.getValue()));
2642                 continue;
2643             }
2644             if (!vpnId.equals(networkVpnId)) {
2645                 LOG.error("dissociateNetworksFromVpn: Network {} is associated to another VPN {} instead of given {}",
2646                           nw.getValue(), networkVpnId.getValue(), vpnId.getValue());
2647                 failedNwList.add(String.format("Failed to disassociate network %s as it is associated to another "
2648                                 + "vpn %s instead of given %s", nw.getValue(), networkVpnId.getValue(),
2649                                 vpnId.getValue()));
2650                 continue;
2651             }
2652             /* Handle disassociation of external network(s) from Internet BGP-VPN use case outside of the
2653              * networkList iteration
2654              */
2655             if (neutronvpnUtils.getIsExternal(network)) {
2656                 extNwMap.put(nw, network);
2657                 //Handle external-Nw to BGPVPN Disassociation and still ext-router is being set with external-Nw
2658                 List<Uuid> routerList = neutronvpnUtils.getRouterIdsForExtNetwork(nw);
2659                 if (!routerList.isEmpty()) {
2660                     for (Uuid routerId : routerList) {
2661                         //If v6 subnet was already added to router means it requires IPv6 AddrFamily in VpnInstance
2662                         if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
2663                             ipVersion = ipVersion.addVersion(IpVersionChoice.IPV6);
2664                             LOG.debug("dissociateNetworksFromVpn: External network {} is still associated with "
2665                                     + "router(router-gw) {} and V6 subnet is part of that router. Hence Set IPv6 "
2666                                     + "address family type in Internet VPN Instance {}", network, routerId, vpnId);
2667                             break;
2668                         }
2669                     }
2670                 }
2671             }
2672             for (Uuid subnet : networkSubnets) {
2673                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
2674                 if (subnetmap == null) {
2675                     failedNwList.add(String.format("subnetmap %s not found for network %s",
2676                             subnet.getValue(), nw.getValue()));
2677                     LOG.error("dissociateNetworksFromVpn: Subnetmap for subnet {} not found when "
2678                             + "dissociating network {} from VPN {}", subnet.getValue(), nw.getValue(),
2679                             vpnId.getValue());
2680                     continue;
2681                 }
2682                 IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
2683                 if (!ipVersion.isIpVersionChosen(ipVers)) {
2684                     ipVersion = ipVersion.addVersion(ipVers);
2685                 }
2686                 if (!NeutronvpnUtils.getIsExternal(network)) {
2687                     LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
2688                             vpnId.getValue());
2689                     removeSubnetFromVpn(vpnId, subnetmap, null);
2690                     Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2691                     vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2692                             vpnId.getValue());
2693                     passedNwList.add(nw);
2694                 }
2695             }
2696             if (ipVersion != IpVersionChoice.UNDEFINED) {
2697                 LOG.debug("dissociateNetworksFromVpn: Updating vpnInstance with ip address family {}"
2698                         + " for VPN {}", ipVersion, vpnId);
2699                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
2700             }
2701         }
2702         //Handle disassociation of external network(s) from Internet BGP-VPN Instance use case
2703         if (!extNwMap.isEmpty() || extNwMap != null) {
2704             for (Network extNw : extNwMap.values()) {
2705                 if (disassociateExtNetworkFromVpn(vpnId, extNw)) {
2706                     passedNwList.add(extNw.getUuid());
2707                 } else {
2708                     LOG.error("dissociateNetworksFromVpn: Failed to withdraw External Provider Network {} from VPN {}",
2709                             extNw, vpnId.getValue());
2710                     failedNwList.add(String.format("Failed to withdraw External Provider Network %s from VPN %s",
2711                             extNw, vpnId.getValue()));
2712                     continue;
2713                 }
2714             }
2715         }
2716         clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
2717         LOG.info("dissociateNetworksFromVpn: Network(s) {} disassociated from L3VPN {} successfully",
2718                 passedNwList, vpnId.getValue());
2719         return failedNwList;
2720     }
2721
2722     private boolean disassociateExtNetworkFromVpn(@NonNull Uuid vpnId, @NonNull Network extNet) {
2723         if (!removeExternalNetworkFromVpn(extNet)) {
2724             return false;
2725         }
2726         // check, if there is another Provider Networks associated with given VPN
2727         List<Uuid> vpnNets = getNetworksForVpn(vpnId);
2728         if (vpnNets != null) {
2729             //Remove currently disassociated network from the list
2730             vpnNets.remove(extNet.getUuid());
2731             for (Uuid netId : vpnNets) {
2732                 if (NeutronvpnUtils.getIsExternal(getNeutronNetwork(netId))) {
2733                     LOG.error("dissociateExtNetworkFromVpn: Internet VPN {} is still associated with Provider Network "
2734                             + "{}", vpnId.getValue(), netId.getValue());
2735                     return true;
2736                 }
2737             }
2738         }
2739         ///Set VPN Type is BGPVPN from InternetBGPVPN
2740         LOG.info("disassociateExtNetworkFromVpn: Set BGP-VPN type with {} for VPN {} and update IPv6 address family. "
2741                         + "Since external network is disassociated from VPN {}",
2742                 VpnInstance.BgpvpnType.BGPVPN, extNet, vpnId.getValue());
2743         neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.BGPVPN, vpnId);
2744         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
2745         for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
2746             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2747             if (sm == null) {
2748                 LOG.error("disassociateExtNetworkFromVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2749                 continue;
2750             }
2751             IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
2752             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
2753                 continue;
2754             }
2755             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
2756                 updateVpnInternetForSubnet(sm, vpnId, false);
2757             }
2758             if (!ipVersion.isIpVersionChosen(ipVers)) {
2759                 ipVersion = ipVersion.addVersion(ipVers);
2760             }
2761         }
2762         if (ipVersion != IpVersionChoice.UNDEFINED) {
2763             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
2764             LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}",
2765                     vpnId.getValue());
2766             neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, false);
2767         }
2768         return true;
2769     }
2770
2771     /**
2772      * It handles the invocations to the neutronvpn:associateNetworks RPC method.
2773      */
2774     @Override
2775     // TODO Clean up the exception handling
2776     @SuppressWarnings("checkstyle:IllegalCatch")
2777     public ListenableFuture<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
2778
2779         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
2780         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
2781         StringBuilder returnMsg = new StringBuilder();
2782         Uuid vpnId = input.getVpnId();
2783
2784         try {
2785             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2786                 LOG.debug("associateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2787                         input.getNetworkId());
2788                 List<Uuid> netIds = input.getNetworkId();
2789                 if (netIds != null && !netIds.isEmpty()) {
2790                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
2791                     if (!failed.isEmpty()) {
2792                         returnMsg.append(failed);
2793                     }
2794                 }
2795             } else {
2796                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2797             }
2798             if (returnMsg.length() != 0) {
2799                 opBuilder.setResponse(
2800                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2801                                 "associate Networks to vpn {} failed due to {}", vpnId.getValue(), returnMsg));
2802                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().withResult(opBuilder.build()).build());
2803             } else {
2804                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().build());
2805             }
2806         } catch (Exception ex) {
2807             LOG.error("associate Networks to vpn failed {}", input.getVpnId().getValue(), ex);
2808             result.set(RpcResultBuilder.<AssociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2809                     formatAndLog(LOG::error, "associate Networks to vpn {} failed due to {}",
2810                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2811         }
2812         LOG.debug("associateNetworks returns..");
2813         return result;
2814     }
2815
2816     /**
2817      * It handles the invocations to the neutronvpn:associateRouter RPC method.
2818      */
2819     @Override
2820     public ListenableFuture<RpcResult<AssociateRouterOutput>> associateRouter(AssociateRouterInput input) {
2821
2822         SettableFuture<RpcResult<AssociateRouterOutput>> result = SettableFuture.create();
2823         LOG.debug("associateRouter {}", input);
2824         StringBuilder returnMsg = new StringBuilder();
2825         Uuid vpnId = input.getVpnId();
2826         Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter
2827                 .input.RouterIdsKey, org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602
2828                 .associaterouter.input.RouterIds> keyRouterIdsMap = input.nonnullRouterIds();
2829         Preconditions.checkArgument(!keyRouterIdsMap.isEmpty(), "associateRouter: RouterIds list is empty!");
2830         Preconditions.checkNotNull(vpnId, "associateRouter; VpnId not found!");
2831         Preconditions.checkNotNull(vpnId, "associateRouter; RouterIds not found!");
2832         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input
2833                 .RouterIds routerId : keyRouterIdsMap.values()) {
2834             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2835             Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2836             if (vpnMap != null) {
2837                 if (rtr != null) {
2838                     Uuid extVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2839                     if (vpnMap.getRouterIds() != null && vpnMap.getRouterIds().size() > 1) {
2840                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
2841                                 .append(routerId.getRouterId());
2842                     } else if (extVpnId != null) {
2843                         returnMsg.append("router ").append(routerId.getRouterId()).append(" already associated to "
2844                                 + "another VPN ").append(extVpnId.getValue());
2845                     } else {
2846                         LOG.debug("associateRouter RPC: VpnId {}, routerId {}", vpnId.getValue(),
2847                                 routerId.getRouterId());
2848                         associateRouterToVpn(vpnId, routerId.getRouterId());
2849                     }
2850                 } else {
2851                     returnMsg.append("router not found : ").append(routerId.getRouterId());
2852                 }
2853             } else {
2854                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2855             }
2856             if (returnMsg.length() != 0) {
2857                 result.set(RpcResultBuilder.<AssociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
2858                         "invalid-value", formatAndLog(LOG::error, "associate router to vpn {} failed "
2859                                 + "due to {}", routerId.getRouterId(), returnMsg)).build());
2860             } else {
2861                 result.set(RpcResultBuilder.success(new AssociateRouterOutputBuilder().build()).build());
2862             }
2863         }
2864         LOG.debug("associateRouter returns..");
2865         return result;
2866     }
2867
2868     /**
2869      * It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
2870      */
2871     @Override
2872     // TODO Clean up the exception handling
2873     @SuppressWarnings("checkstyle:IllegalCatch")
2874     public ListenableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
2875         GetFixedIPsForNeutronPortInput input) {
2876         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
2877         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
2878         Uuid portId = input.getPortId();
2879         StringBuilder returnMsg = new StringBuilder();
2880         try {
2881             List<String> fixedIPList = new ArrayList<>();
2882             Port port = neutronvpnUtils.getNeutronPort(portId);
2883             if (port != null) {
2884                 for (FixedIps ip : port.nonnullFixedIps().values()) {
2885                     fixedIPList.add(ip.getIpAddress().stringValue());
2886                 }
2887             } else {
2888                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
2889             }
2890             if (returnMsg.length() != 0) {
2891                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withWarning(ErrorType.PROTOCOL,
2892                         "invalid-value",
2893                         formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port failed due to {}",
2894                                 returnMsg)).build());
2895             } else {
2896                 opBuilder.setFixedIPs(fixedIPList);
2897                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().withResult(opBuilder.build())
2898                         .build());
2899                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().build());
2900             }
2901         } catch (Exception ex) {
2902             result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withError(ErrorType.APPLICATION,
2903                     formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port {} failed due to {}",
2904                             portId.getValue(), ex.getMessage(), ex)).build());
2905         }
2906         return result;
2907     }
2908
2909     /**
2910      * It handles the invocations to the neutronvpn:dissociateNetworks RPC method.
2911      */
2912     @Override
2913     // TODO Clean up the exception handling
2914     @SuppressWarnings("checkstyle:IllegalCatch")
2915     public ListenableFuture<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
2916
2917         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
2918         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
2919
2920         LOG.debug("dissociateNetworks {}", input);
2921         StringBuilder returnMsg = new StringBuilder();
2922         Uuid vpnId = input.getVpnId();
2923
2924         try {
2925             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2926                 LOG.debug("dissociateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2927                         input.getNetworkId());
2928                 List<Uuid> netIds = input.getNetworkId();
2929                 if (netIds != null && !netIds.isEmpty()) {
2930                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
2931                     if (!failed.isEmpty()) {
2932                         returnMsg.append(failed);
2933                     }
2934                 }
2935             } else {
2936                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2937             }
2938             if (returnMsg.length() != 0) {
2939                 opBuilder.setResponse(
2940                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2941                                 "dissociate Networks to vpn {} failed due to {}", vpnId.getValue(),
2942                                 returnMsg));
2943                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
2944             } else {
2945                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
2946             }
2947         } catch (Exception ex) {
2948             result.set(RpcResultBuilder.<DissociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2949                     formatAndLog(LOG::error, "dissociate Networks to vpn {} failed due to {}",
2950                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2951         }
2952         LOG.debug("dissociateNetworks returns..");
2953         return result;
2954     }
2955
2956     /**
2957      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
2958      */
2959     @Override
2960     // TODO Clean up the exception handling
2961     @SuppressWarnings("checkstyle:IllegalCatch")
2962     public ListenableFuture<RpcResult<DissociateRouterOutput>> dissociateRouter(DissociateRouterInput input) {
2963
2964         SettableFuture<RpcResult<DissociateRouterOutput>> result = SettableFuture.create();
2965
2966         LOG.debug("dissociateRouter {}", input);
2967         StringBuilder returnMsg = new StringBuilder();
2968         Uuid vpnId = input.getVpnId();
2969         Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2970                 .RouterIdsKey, org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602
2971                 .dissociaterouter.input.RouterIds> keyRouterIdsMap = input.nonnullRouterIds();
2972         String routerIdsString = "";
2973         Preconditions.checkArgument(!keyRouterIdsMap.isEmpty(), "dissociateRouter: RouterIds list is empty!");
2974         Preconditions.checkNotNull(vpnId, "dissociateRouter: vpnId not found!");
2975         Preconditions.checkNotNull(keyRouterIdsMap, "dissociateRouter: keyRouterIdsMap not found!");
2976         if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2977             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2978                     .RouterIds routerId : keyRouterIdsMap.values()) {
2979                 try {
2980                     if (routerId != null) {
2981                         routerIdsString += routerId.getRouterId() + ", ";
2982                         Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2983                         if (rtr != null) {
2984                             Uuid routerVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2985                             if (routerVpnId == null) {
2986                                 returnMsg.append("input router ").append(routerId.getRouterId())
2987                                         .append(" not associated to any vpn yet");
2988                             } else if (vpnId.equals(routerVpnId)) {
2989                                 dissociateRouterFromVpn(vpnId, routerId.getRouterId());
2990                             } else {
2991                                 returnMsg.append("input router ").append(routerId.getRouterId())
2992                                         .append(" associated to vpn ")
2993                                         .append(routerVpnId.getValue()).append("instead of the vpn given as input");
2994                             }
2995                         } else {
2996                             returnMsg.append("router not found : ").append(routerId.getRouterId());
2997                         }
2998                     }
2999                     if (returnMsg.length() != 0) {
3000                         result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
3001                                 "invalid-value", formatAndLog(LOG::error, "dissociate router {} to "
3002                                                 + "vpn {} failed due to {}", routerId.getRouterId(), vpnId.getValue(),
3003                                         returnMsg)).build());
3004                     } else {
3005                         result.set(RpcResultBuilder.success(new DissociateRouterOutputBuilder().build()).build());
3006                     }
3007                 } catch (Exception ex) {
3008                     result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withError(ErrorType.APPLICATION,
3009                             formatAndLog(LOG::error, "disssociate router {} to vpn {} failed due to {}",
3010                                     routerId.getRouterId(), vpnId.getValue(), ex.getMessage(), ex)).build());
3011                 }
3012             }
3013         } else {
3014             returnMsg.append("VPN not found : ").append(vpnId.getValue());
3015         }
3016
3017         LOG.debug("dissociateRouter returns..");
3018         return result;
3019     }
3020
3021     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
3022         // check if the router is associated to some VPN
3023         Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
3024         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
3025         if (vpnId != null) {
3026             // remove existing external vpn interfaces
3027             for (Uuid subnetId : routerSubnetIds) {
3028                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
3029                 if (subnetmap != null) {
3030                     removeSubnetFromVpn(vpnId, subnetmap, internetVpnId);
3031                 } else {
3032                     LOG.error("handleNeutronRouterDeleted: Subnetmap for subnet {} not found when deleting router {}",
3033                             subnetId, routerId.getValue());
3034                 }
3035             }
3036             clearFromVpnMaps(vpnId, routerId, null);
3037         } else {
3038             // remove existing internal vpn interfaces
3039             for (Uuid subnetId : routerSubnetIds) {
3040                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
3041                 if (subnetmap != null) {
3042                     removeSubnetFromVpn(routerId, subnetmap, internetVpnId);
3043                 } else {
3044                     LOG.error("handleNeutronRouterDeleted: Subnetmap for subnet {} not found when deleting router {}",
3045                             subnetId, routerId.getValue());
3046                 }
3047             }
3048         }
3049         // delete entire vpnMaps node for internal VPN
3050         deleteVpnMapsNode(routerId);
3051
3052         // delete vpn-instance for internal VPN
3053         deleteVpnInstance(routerId);
3054     }
3055
3056     protected Subnet getNeutronSubnet(Uuid subnetId) {
3057         return neutronvpnUtils.getNeutronSubnet(subnetId);
3058     }
3059
3060     @Nullable
3061     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
3062         Subnet sn = neutronvpnUtils.getNeutronSubnet(subnetId);
3063         if (null != sn) {
3064             return sn.getGatewayIp();
3065         }
3066         return null;
3067     }
3068
3069
3070     protected Network getNeutronNetwork(Uuid networkId) {
3071         return neutronvpnUtils.getNeutronNetwork(networkId);
3072     }
3073
3074     protected Port getNeutronPort(String name) {
3075         return neutronvpnUtils.getNeutronPort(new Uuid(name));
3076     }
3077
3078     protected Port getNeutronPort(Uuid portId) {
3079         return neutronvpnUtils.getNeutronPort(portId);
3080     }
3081
3082     protected Uuid getNetworkForSubnet(Uuid subnetId) {
3083         return neutronvpnUtils.getNetworkForSubnet(subnetId);
3084     }
3085
3086     protected List<Uuid> getNetworksForVpn(Uuid vpnId) {
3087         return neutronvpnUtils.getNetworksForVpn(vpnId);
3088     }
3089
3090     /**
3091      * Implementation of the "vpnservice:neutron-ports-show" Karaf CLI command.
3092      *
3093      * @return a List of String to be printed on screen
3094      * @throws ExecutionException or InterruptedException   if there was a problem reading from the data store
3095      */
3096     public List<String> showNeutronPortsCLI() throws ExecutionException, InterruptedException {
3097         List<String> result = new ArrayList<>();
3098         result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", "Port ID", "Mac Address", "Prefix Length",
3099             "IP Address"));
3100         result.add("-------------------------------------------------------------------------------------------");
3101         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
3102
3103         Optional<Ports> ports = syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
3104         if (ports.isPresent() && ports.get().getPort() != null) {
3105             for (Port port : ports.get().nonnullPort().values()) {
3106                 Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.getFixedIps();
3107                 if (keyFixedIpsMap != null && !keyFixedIpsMap.isEmpty()) {
3108                     List<String> ipList = new ArrayList<>();
3109                     for (FixedIps fixedIp : keyFixedIpsMap.values()) {
3110                         IpAddress ipAddress = fixedIp.getIpAddress();
3111                         if (ipAddress.getIpv4Address() != null) {
3112                             ipList.add(ipAddress.getIpv4Address().getValue());
3113                         } else {
3114                             ipList.add(ipAddress.getIpv6Address().getValue());
3115                         }
3116                     }
3117                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
3118                             .getMacAddress().getValue(), neutronvpnUtils.getIPPrefixFromPort(port),
3119                             ipList.toString()));
3120                 } else {
3121                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
3122                             .getMacAddress().getValue(), "Not Assigned", "Not Assigned"));
3123                 }
3124             }
3125         }
3126
3127         return result;
3128     }
3129
3130     /**
3131      * Implementation of the "vpnservice:l3vpn-config-show" karaf CLI command.
3132      *
3133      * @param vpnuuid Uuid of the VPN whose config must be shown
3134      * @return formatted output list
3135      * @throws InterruptedException if there was a thread related problem getting the data to display
3136      * @throws ExecutionException if there was any other problem getting the data to display
3137      */
3138     public List<String> showVpnConfigCLI(Uuid vpnuuid) throws InterruptedException, ExecutionException {
3139         List<String> result = new ArrayList<>();
3140         if (vpnuuid == null) {
3141             result.add("");
3142             result.add("Displaying VPN config for all VPNs");
3143             result.add("To display VPN config for a particular VPN, use the following syntax");
3144             result.add(getshowVpnConfigCLIHelp());
3145         }
3146         RpcResult<GetL3VPNOutput> rpcResult = getL3VPN(new GetL3VPNInputBuilder().setId(vpnuuid).build()).get();
3147         if (rpcResult.isSuccessful()) {
3148             result.add("");
3149             result.add(String.format(" %-37s %-37s %-7s ", "VPN ID", "Tenant ID", "RD"));
3150             result.add("");
3151             result.add(String.format(" %-80s ", "Import-RTs"));
3152             result.add("");
3153             result.add(String.format(" %-80s ", "Export-RTs"));
3154             result.add("");
3155             result.add(String.format(" %-76s ", "Subnet IDs"));
3156             result.add("");
3157             result.add("------------------------------------------------------------------------------------");
3158             result.add("");
3159             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnInstance vpn :
3160                     rpcResult.getResult().nonnullL3vpnInstances()) {
3161                 String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
3162                         : "\"                 " + "                  \"";
3163                 result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
3164                         vpn.getRouteDistinguisher()));
3165                 result.add("");
3166                 result.add(String.format(" %-80s ", vpn.getImportRT()));
3167                 result.add("");
3168                 result.add(String.format(" %-80s ", vpn.getExportRT()));
3169                 result.add("");
3170
3171                 Uuid vpnid = vpn.getId();
3172                 List<Uuid> subnetList = neutronvpnUtils.getSubnetsforVpn(vpnid);
3173                 if (!subnetList.isEmpty()) {
3174                     for (Uuid subnetuuid : subnetList) {
3175                         result.add(String.format(" %-76s ", subnetuuid.getValue()));
3176                     }
3177                 } else {
3178                     result.add(String.format(" %-76s ", "\"                                    \""));
3179                 }
3180                 result.add("");
3181                 result.add("----------------------------------------");
3182                 result.add("");
3183             }
3184         } else {
3185             String errortag = rpcResult.getErrors().iterator().next().getTag();
3186             if (Objects.equals(errortag, "")) {
3187                 result.add("");
3188                 result.add("No VPN has been configured yet");
3189             } else if (Objects.equals(errortag, "invalid-value")) {
3190                 result.add("");
3191                 result.add("VPN " + vpnuuid.getValue() + " is not present");
3192             } else {
3193                 result.add("error getting VPN info : " + rpcResult.getErrors());
3194                 result.add(getshowVpnConfigCLIHelp());
3195             }
3196         }
3197         return result;
3198     }
3199
3200     protected void createExternalVpnInterfaces(Uuid extNetId) {
3201         if (extNetId == null) {
3202             LOG.error("createExternalVpnInterfaces: external network is null");
3203             return;
3204         }
3205
3206         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
3207         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3208             LOG.error("No external ports attached to external network {}", extNetId.getValue());
3209             return;
3210         }
3211
3212         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3213             for (String elanInterface : extElanInterfaces) {
3214                 createExternalVpnInterface(extNetId, elanInterface, tx);
3215             }
3216         }), LOG, "Error creating external VPN interfaces for {}", extNetId);
3217     }
3218
3219     // TODO Clean up the exception handling
3220     @SuppressWarnings("checkstyle:IllegalCatch")
3221     protected void removeExternalVpnInterfaces(Uuid extNetId) {
3222         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
3223         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3224             LOG.error("No external ports attached for external network {}", extNetId.getValue());
3225             return;
3226         }
3227         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3228             for (String elanInterface : extElanInterfaces) {
3229                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
3230                         .buildVpnInterfaceIdentifier(elanInterface);
3231                 LOG.info("Removing vpn interface {}", elanInterface);
3232                 tx.delete(vpnIfIdentifier);
3233             }
3234         }), LOG, "Error removing external VPN interfaces for {}", extNetId);
3235     }
3236
3237     private void createExternalVpnInterface(Uuid vpnId, String infName,
3238                                             TypedWriteTransaction<Configuration> wrtConfigTxn) {
3239         writeVpnInterfaceToDs(Collections.singletonList(vpnId), infName, null, vpnId /* external network id */,
3240                 false /* not a router iface */, wrtConfigTxn);
3241     }
3242
3243     // TODO Clean up the exception handling
3244     @SuppressWarnings("checkstyle:IllegalCatch")
3245     private void writeVpnInterfaceToDs(@NonNull Collection<Uuid> vpnIdList, String infName,
3246             @Nullable Adjacencies adjacencies, Uuid networkUuid, Boolean isRouterInterface,
3247             TypedWriteTransaction<Configuration> wrtConfigTxn) {
3248         if (vpnIdList.isEmpty() || infName == null) {
3249             LOG.error("vpnid is empty or interface({}) is null", infName);
3250             return;
3251         }
3252         if (wrtConfigTxn == null) {
3253             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
3254                 tx -> writeVpnInterfaceToDs(vpnIdList, infName, adjacencies, networkUuid, isRouterInterface, tx)), LOG,
3255                 "Error writing VPN interface");
3256             return;
3257         }
3258         List<VpnInstanceNames> vpnIdListStruct = new ArrayList<>();
3259         for (Uuid vpnId: vpnIdList) {
3260             VpnInstanceNames vpnInstance = VpnHelper.getVpnInterfaceVpnInstanceNames(vpnId.getValue(),
3261                                    AssociatedSubnetType.V4AndV6Subnets);
3262             vpnIdListStruct.add(vpnInstance);
3263         }
3264
3265         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3266         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
3267                 .setName(infName)
3268                 .setVpnInstanceNames(vpnIdListStruct)
3269                 .setRouterInterface(isRouterInterface);
3270         LOG.info("Network Id is {}", networkUuid);
3271         if (networkUuid != null) {
3272             Network portNetwork = neutronvpnUtils.getNeutronNetwork(networkUuid);
3273             ProviderTypes providerType = NeutronvpnUtils.getProviderNetworkType(portNetwork);
3274             NetworkAttributes.NetworkType networkType = providerType != null
3275                     ? NetworkAttributes.NetworkType.valueOf(providerType.getName()) : null;
3276             String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(portNetwork);
3277             vpnb.setNetworkId(networkUuid).setNetworkType(networkType)
3278                 .setSegmentationId(segmentationId != null ? Long.parseLong(segmentationId) : 0L);
3279         }
3280
3281         if (adjacencies != null) {
3282             vpnb.addAugmentation(Adjacencies.class, adjacencies);
3283         }
3284         VpnInterface vpnIf = vpnb.build();
3285         try {
3286             LOG.info("Creating vpn interface {}", vpnIf);
3287             wrtConfigTxn.put(vpnIfIdentifier, vpnIf);
3288         } catch (Exception ex) {
3289             LOG.error("Creation of vpninterface {} failed", infName, ex);
3290         }
3291     }
3292
3293     private void updateVpnInterfaceWithAdjacencies(Uuid vpnId, String infName, Adjacencies adjacencies,
3294                                                    TypedWriteTransaction<Configuration> wrtConfigTxn) {
3295         if (vpnId == null || infName == null) {
3296             LOG.error("vpn id or interface is null");
3297             return;
3298         }
3299         if (wrtConfigTxn == null) {
3300             LOG.error("updateVpnInterfaceWithAdjancies called with wrtConfigTxn as null");
3301             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3302                 updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, tx);
3303             }), LOG, "Error updating VPN interface with adjacencies");
3304             return;
3305         }
3306
3307         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3308
3309         try (AcquireResult lock = tryInterfaceLock(infName)) {
3310             if (!lock.wasAcquired()) {
3311                 // FIXME: why do we even bother with locking if we do not honor it?!
3312                 logTryLockFailure(infName);
3313             }
3314
3315             try {
3316                 Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker
3317                         .syncReadOptional(dataBroker, LogicalDatastoreType
3318                             .CONFIGURATION, vpnIfIdentifier);
3319                 if (optionalVpnInterface.isPresent()) {
3320                     VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get());
3321                     LOG.debug("Updating vpn interface {} with new adjacencies", infName);
3322
3323                     if (adjacencies == null) {
3324                         return;
3325                     }
3326                     vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
3327                     if (optionalVpnInterface.get().getVpnInstanceNames() != null) {
3328                         List<VpnInstanceNames> listVpnInstances = new ArrayList<>(
3329                                 optionalVpnInterface.get().getVpnInstanceNames().values());
3330                         if (listVpnInstances.isEmpty()
3331                                 || !VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpnInstances)) {
3332                             VpnInstanceNames vpnInstance = VpnHelper.getVpnInterfaceVpnInstanceNames(vpnId.getValue(),
3333                                 AssociatedSubnetType.V4AndV6Subnets);
3334                             listVpnInstances.add(vpnInstance);
3335                             vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3336                         }
3337                     } else {
3338                         VpnInstanceNames vpnInstance = VpnHelper
3339                                 .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
3340                         List<VpnInstanceNames> listVpnInstances = new ArrayList<>();
3341                         listVpnInstances.add(vpnInstance);
3342                         vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3343                     }
3344                     LOG.info("Updating vpn interface {} with new adjacencies", infName);
3345                     wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
3346                 }
3347             } catch (IllegalStateException | ExecutionException | InterruptedException ex) {
3348                 // FIXME: why are we catching IllegalStateException here?
3349                 LOG.error("Update of vpninterface {} failed", infName, ex);
3350             }
3351         }
3352     }
3353
3354     private String getshowVpnConfigCLIHelp() {
3355         StringBuilder help = new StringBuilder("Usage:");
3356         help.append("display vpn-config [-vid/--vpnid <id>]");
3357         return help.toString();
3358     }
3359
3360     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
3361         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
3362     }
3363
3364     @Override
3365     public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
3366         return neutronEvpnManager.createEVPN(input);
3367     }
3368
3369     @Override
3370     public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
3371         return neutronEvpnManager.getEVPN(input);
3372     }
3373
3374     @Override
3375     public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
3376         return neutronEvpnManager.deleteEVPN(input);
3377     }
3378
3379     private boolean addExternalNetworkToVpn(Network extNet, Uuid vpnId) {
3380         Uuid extNetId = extNet.getUuid();
3381         InstanceIdentifier<Networks> extNetIdentifier = InstanceIdentifier.builder(ExternalNetworks.class)
3382                 .child(Networks.class, new NetworksKey(extNetId)).build();
3383
3384         try {
3385             Optional<Networks> optionalExtNets =
3386                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3387                                                                  extNetIdentifier);
3388             if (!optionalExtNets.isPresent()) {
3389                 LOG.error("addExternalNetworkToVpn: Provider Network {} is not present in ConfigDS",
3390                           extNetId.getValue());
3391                 return false;
3392             }
3393             NetworksBuilder builder = new NetworksBuilder(optionalExtNets.get());
3394             builder.setVpnid(vpnId);
3395             Networks networks = builder.build();
3396             // Add Networks object to the ExternalNetworks list
3397             LOG.trace("addExternalNetworkToVpn: Set VPN Id {} for Provider Network {}", vpnId.getValue(),
3398                       extNetId.getValue());
3399             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetIdentifier,
3400                                                   networks);
3401             return true;
3402         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException ex) {
3403             LOG.error("addExternalNetworkToVpn: Failed to set VPN Id {} to Provider Network {}: ", vpnId.getValue(),
3404                       extNetId.getValue(), ex);
3405         }
3406         return false;
3407     }
3408
3409     private boolean removeExternalNetworkFromVpn(Network extNet) {
3410         Uuid extNetId = extNet.getUuid();
3411         InstanceIdentifier<Networks> extNetsId = InstanceIdentifier.builder(ExternalNetworks.class)
3412             .child(Networks.class, new NetworksKey(extNetId)).build();
3413         try {
3414             Optional<Networks> optionalNets =
3415                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3416                             extNetsId);
3417             NetworksBuilder builder = null;
3418             if (optionalNets.isPresent()) {
3419                 builder = new NetworksBuilder(optionalNets.get());
3420             } else {
3421                 LOG.error("removeExternalNetworkFromVpn: Provider Network {} is not present in the ConfigDS",
3422                         extNetId.getValue());
3423                 return false;
3424             }
3425             builder.setVpnid(null);
3426             Networks networks = builder.build();
3427             LOG.info("removeExternalNetworkFromVpn: Withdraw VPN Id from Provider Network {} node",
3428                     extNetId.getValue());
3429             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetsId, networks);
3430             return true;
3431         } catch (TransactionCommitFailedException | ExecutionException | InterruptedException ex) {
3432             LOG.error("removeExternalNetworkFromVpn: Failed to withdraw VPN Id from Provider Network node {}: ",
3433                     extNetId.getValue(), ex);
3434         }
3435         return false;
3436     }
3437
3438     private Optional<String> getExistingOperationalVpn(String primaryRd) {
3439         Optional<String> existingVpnName = Optional.of(primaryRd);
3440         Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataOptional;
3441         try {
3442             vpnInstanceOpDataOptional = syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
3443                     neutronvpnUtils.getVpnOpDataIdentifier(primaryRd));
3444         } catch (ExecutionException | InterruptedException e) {
3445             LOG.error("getExistingOperationalVpn: Exception while checking operational status of vpn with rd {}",
3446                     primaryRd, e);
3447             /*Read failed. We don't know if a VPN exists or not.
3448             * Return primaryRd to halt caller execution, to be safe.*/
3449             return existingVpnName;
3450         }
3451         if (vpnInstanceOpDataOptional.isPresent()) {
3452             existingVpnName = Optional.of(vpnInstanceOpDataOptional.get().getVpnInstanceName());
3453         } else {
3454             existingVpnName = Optional.empty();
3455         }
3456         return existingVpnName;
3457     }
3458
3459     private static String formatAndLog(Consumer<String> logger, String template, Object arg) {
3460         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
3461     }
3462
3463     private static String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
3464         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
3465     }
3466
3467     private static String formatAndLog(Consumer<String> logger, String template, Object... args) {
3468         return logAndReturnMessage(logger, MessageFormatter.arrayFormat(template, args));
3469     }
3470
3471     private static String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
3472         String message = tuple.getMessage();
3473         logger.accept(message);
3474         return message;
3475     }
3476
3477     protected void addV6PrivateSubnetToExtNetwork(@NonNull Uuid routerId, @NonNull Uuid internetVpnId,
3478                                                   @NonNull Subnetmap subnetMap) {
3479         updateVpnInternetForSubnet(subnetMap, internetVpnId, true);
3480         neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
3481         if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(IpVersionChoice.IPV6, routerId, true)) {
3482             neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, true);
3483             LOG.info("addV6PrivateSubnetToExtNetwork: Advertise IPv6 Private Subnet {} to Internet VPN {}",
3484                     subnetMap.getId().getValue(), internetVpnId.getValue());
3485         }
3486     }
3487
3488     protected void removeV6PrivateSubnetToExtNetwork(@NonNull Uuid routerId, @NonNull Uuid internetVpnId,
3489                                                      @NonNull Subnetmap subnetMap) {
3490         updateVpnInternetForSubnet(subnetMap, internetVpnId, false);
3491         neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, false);
3492     }
3493
3494     protected void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove) {
3495         if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
3496             LOG.debug("processV6InternetFlowsForRtr: Successfully {} V6 internet vpn {} default fallback rule "
3497                             + "for the router {}", addOrRemove == NwConstants.ADD_FLOW ? "added" : "removed",
3498                     internetVpnId.getValue(), routerId.getValue());
3499             neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, addOrRemove == NwConstants.ADD_FLOW
3500                     ? true : false);
3501         }
3502     }
3503
3504     @CheckReturnValue
3505     private AcquireResult tryInterfaceLock(final String infName) {
3506         return interfaceLock.tryAcquire(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
3507     }
3508
3509     @CheckReturnValue
3510     private AcquireResult tryVpnLock(final Uuid vpnId) {
3511         return vpnLock.tryAcquire(vpnId, LOCK_WAIT_TIME, TimeUnit.SECONDS);
3512     }
3513
3514     private static ReentrantLock lockForUuid(Uuid uuid) {
3515         // FIXME: prove that this locks only on Uuids and not some other entity or create a separate lock domain
3516         return JvmGlobalLocks.getLockForString(uuid.getValue());
3517     }
3518
3519     private static void logTryLockFailure(Object objectId) {
3520         LOG.warn("Lock for {} was not acquired, continuing anyway", objectId, new Throwable());
3521     }
3522 }