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