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