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