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