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