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