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