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