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