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