d2f37a6559d23d850fefecf17b358af571a62700
[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 java.util.stream.Collectors;
40 import javax.annotation.Nonnull;
41 import javax.annotation.Nullable;
42 import javax.annotation.PreDestroy;
43 import javax.inject.Inject;
44 import javax.inject.Singleton;
45 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
46 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
47 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
48 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
49 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
50 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
51 import org.opendaylight.genius.infra.Datastore;
52 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
53 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
54 import org.opendaylight.genius.infra.TypedWriteTransaction;
55 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
56 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
57 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
58 import org.opendaylight.netvirt.alarm.NeutronvpnAlarms;
59 import org.opendaylight.netvirt.elanmanager.api.IElanService;
60 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
61 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
62 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
63 import org.opendaylight.netvirt.neutronvpn.evpn.manager.NeutronEvpnManager;
64 import org.opendaylight.netvirt.neutronvpn.evpn.utils.NeutronEvpnUtils;
65 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
66 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
67 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
68 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
69 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
70 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargetsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
72 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTargetBuilder;
73 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTargetKey;
74 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
75 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceBuilder;
76 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
77 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv4FamilyBuilder;
78 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.vpn.instance.Ipv6FamilyBuilder;
79 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
80 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
81 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
82 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
83 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
84 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
85 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry.BgpvpnType;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
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     private 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 = String.valueOf(ip.getIpAddress().getValue());
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, 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 (internetVpnId != null) {
921             updateVpnInterfaceWithAdjacencies(internetVpnId, infName, adjacencies, wrtConfigTxn);
922         }
923         if (!isIpFromAnotherSubnet) {
924             // no more subnetworks for neutron port
925             if (sn != null && sn.getRouterId() != null) {
926                 removeFromNeutronRouterInterfacesMap(sn.getRouterId(), port.getUuid().getValue());
927             }
928             deleteVpnInterface(infName, null /* vpn-id */, wrtConfigTxn);
929             return;
930         }
931         return;
932     }
933
934     // TODO Clean up the exception handling
935     @SuppressWarnings("checkstyle:IllegalCatch")
936     protected void deleteVpnInterface(String infName, @Nullable String vpnId,
937                                       TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
938         if (wrtConfigTxn == null) {
939             ListenableFutures.addErrorLogging(
940                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
941                         tx -> deleteVpnInterface(infName, vpnId, tx)),
942                     LOG, "Error deleting VPN interface {} {}", infName, vpnId);
943             return;
944         }
945
946         InstanceIdentifier<VpnInterface> vpnIfIdentifier =
947             NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
948         Optional<VpnInterface> optionalVpnInterface;
949         try {
950             optionalVpnInterface =
951                 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
952                             vpnIfIdentifier);
953         } catch (ReadFailedException ex) {
954             LOG.error("Error during deletion of vpninterface {}", infName, ex);
955             return;
956         }
957         if (!optionalVpnInterface.isPresent()) {
958             LOG.warn("Deletion of vpninterface {}, optionalVpnInterface is not present()", infName);
959             return;
960         }
961         if (vpnId != null) {
962             VpnInterface vpnInterface = optionalVpnInterface.get();
963             List<VpnInstanceNames> vpnList = vpnInterface.getVpnInstanceNames();
964             if (vpnList != null
965                 && VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId, vpnList)) {
966                 VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId, vpnList);
967                 if (!vpnList.isEmpty()) {
968                     LOG.debug("Deleting vpn interface {} not immediately since vpnInstanceName "
969                             + "List not empty", infName);
970                     return;
971                 }
972                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
973                         .setVpnInstanceNames(vpnList);
974                 wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder
975                         .build());
976             }
977         }
978         LOG.debug("Deleting vpn interface {}", infName);
979         wrtConfigTxn.delete(vpnIfIdentifier);
980     }
981
982     protected void removeVpnFromVpnInterface(Uuid vpnId, Port port,
983                                              TypedWriteTransaction<Datastore.Configuration> writeConfigTxn,
984                                              Subnetmap sm) {
985         if (vpnId == null || port == null) {
986             return;
987         }
988         String infName = port.getUuid().getValue();
989         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
990         try {
991             Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker
992                     .syncReadOptional(dataBroker, LogicalDatastoreType
993                     .CONFIGURATION, vpnIfIdentifier);
994             if (optionalVpnInterface.isPresent()) {
995                 List<VpnInstanceNames> listVpn = optionalVpnInterface.get().getVpnInstanceNames();
996                 if (listVpn != null
997                     && VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpn)) {
998                     VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(vpnId.getValue(), listVpn);
999                 }
1000                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
1001                          .setVpnInstanceNames(listVpn);
1002                 Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
1003                 LOG.debug("Updating vpn interface {}", infName);
1004                 List<Adjacency> adjacencyList = adjs != null ? adjs.getAdjacency() : new ArrayList<>();
1005                 Iterator<Adjacency> adjacencyIter = adjacencyList.iterator();
1006                 while (adjacencyIter.hasNext()) {
1007                     Adjacency adjacency = adjacencyIter.next();
1008                     if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
1009                         continue;
1010                     }
1011                     String mipToQuery = adjacency.getIpAddress().split("/")[0];
1012                     InstanceIdentifier<LearntVpnVipToPort> id =
1013                         NeutronvpnUtils.buildLearntVpnVipToPortIdentifier(vpnId.getValue(), mipToQuery);
1014                     Optional<LearntVpnVipToPort> optionalVpnVipToPort =
1015                             SingleTransactionDataBroker.syncReadOptional(dataBroker,
1016                                     LogicalDatastoreType.OPERATIONAL, id);
1017                     if (optionalVpnVipToPort.isPresent()) {
1018                         LOG.trace("Removing adjacencies from vpninterface {} upon dissociation of router {}",
1019                              infName, vpnId);
1020                         if (listVpn == null || listVpn.isEmpty()) {
1021                             adjacencyIter.remove();
1022                         }
1023                         neutronvpnUtils.removeLearntVpnVipToPort(vpnId.getValue(), mipToQuery);
1024                         LOG.trace("Entry for fixedIP {} for port {} on VPN {} removed from VpnPortFixedIPToPortData",
1025                                 mipToQuery, infName, vpnId.getValue());
1026                     }
1027                 }
1028                 List<FixedIps> ips = port.getFixedIps();
1029                 for (FixedIps ip : ips) {
1030                     String ipValue = String.valueOf(ip.getIpAddress().getValue());
1031                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(),
1032                             ipValue, writeConfigTxn);
1033                 }
1034                 if (listVpn == null || listVpn.isEmpty()) {
1035                     if (sm != null && sm.getRouterId() != null) {
1036                         removeFromNeutronRouterInterfacesMap(sm.getRouterId(), port.getUuid().getValue());
1037                     }
1038                     deleteVpnInterface(port.getUuid().getValue(), null /* vpn-id */, writeConfigTxn);
1039                 } else {
1040                     writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
1041                 }
1042             } else {
1043                 LOG.info("removeVpnFromVpnInterface: VPN Interface {} not found", infName);
1044             }
1045         } catch (ReadFailedException ex) {
1046             LOG.error("Update of vpninterface {} failed", infName, ex);
1047         }
1048     }
1049
1050     protected void updateVpnInterface(Uuid vpnId, Uuid oldVpnId, Port port, boolean isBeingAssociated,
1051                                       boolean isSubnetIp,
1052                                       TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
1053         if (vpnId == null || port == null) {
1054             return;
1055         }
1056         boolean isLockAcquired = false;
1057         String infName = port.getUuid().getValue();
1058         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
1059
1060         try {
1061             isLockAcquired = interfaceLock.tryLock(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
1062             Optional<VpnInterface> optionalVpnInterface =
1063                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1064                             vpnIfIdentifier);
1065             if (optionalVpnInterface.isPresent()) {
1066                 VpnInstanceNames vpnInstance = VpnHelper
1067                     .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
1068                 List<VpnInstanceNames> listVpn = new ArrayList<>(optionalVpnInterface
1069                            .get().getVpnInstanceNames());
1070                 if (oldVpnId != null
1071                     && VpnHelper.doesVpnInterfaceBelongToVpnInstance(oldVpnId.getValue(), listVpn)) {
1072                     VpnHelper.removeVpnInterfaceVpnInstanceNamesFromList(oldVpnId.getValue(), listVpn);
1073                 }
1074                 if (vpnId.getValue() != null
1075                     && !VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpn)) {
1076                     listVpn.add(vpnInstance);
1077                 }
1078                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
1079                         .setVpnInstanceNames(listVpn);
1080                 LOG.debug("Updating vpn interface {}", infName);
1081                 if (!isBeingAssociated) {
1082                     Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
1083                     List<Adjacency> adjacencyList = adjs != null ? adjs.getAdjacency() : new ArrayList<>();
1084                     Iterator<Adjacency> adjacencyIter = adjacencyList.iterator();
1085                     while (adjacencyIter.hasNext()) {
1086                         Adjacency adjacency = adjacencyIter.next();
1087                         String mipToQuery = adjacency.getIpAddress().split("/")[0];
1088                         InstanceIdentifier<LearntVpnVipToPort> id =
1089                             NeutronvpnUtils.buildLearntVpnVipToPortIdentifier(oldVpnId.getValue(), mipToQuery);
1090                         Optional<LearntVpnVipToPort> optionalVpnVipToPort =
1091                                 SingleTransactionDataBroker.syncReadOptional(dataBroker,
1092                                         LogicalDatastoreType.OPERATIONAL, id);
1093                         if (optionalVpnVipToPort.isPresent()) {
1094                             LOG.trace("Removing adjacencies from vpninterface {} upon dissociation of router {} "
1095                                 + "from VPN {}", infName, vpnId, oldVpnId);
1096                             adjacencyIter.remove();
1097                             neutronvpnUtils.removeLearntVpnVipToPort(oldVpnId.getValue(), mipToQuery);
1098                             LOG.trace(
1099                                     "Entry for fixedIP {} for port {} on VPN {} removed from VpnPortFixedIPToPortData",
1100                                     mipToQuery, infName, vpnId.getValue());
1101                         }
1102                     }
1103                     Adjacencies adjacencies = new AdjacenciesBuilder().setAdjacency(adjacencyList).build();
1104                     vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
1105                 }
1106                 List<FixedIps> ips = port.getFixedIps();
1107                 for (FixedIps ip : ips) {
1108                     String ipValue = String.valueOf(ip.getIpAddress().getValue());
1109                     if (oldVpnId != null) {
1110                         neutronvpnUtils.removeVpnPortFixedIpToPort(oldVpnId.getValue(),
1111                                 ipValue, writeConfigTxn);
1112                     }
1113                     neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue, infName, port
1114                             .getMacAddress().getValue(), isSubnetIp, writeConfigTxn);
1115                 }
1116                 writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
1117             } else {
1118                 LOG.error("VPN Interface {} not found", infName);
1119             }
1120         } catch (ReadFailedException ex) {
1121             LOG.error("Updation of vpninterface {} failed", infName, ex);
1122         } finally {
1123             if (isLockAcquired) {
1124                 interfaceLock.unlock(infName);
1125             }
1126         }
1127     }
1128
1129     public void createL3InternalVpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt,
1130                                     List<String> ert, Uuid router, List<Uuid> networks) {
1131
1132         IpVersionChoice ipVersChoices = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(router);
1133
1134         // Update VPN Instance node
1135         updateVpnInstanceNode(vpn, rd, irt, ert, VpnInstance.Type.L3, 0 /*l3vni*/, ipVersChoices);
1136
1137         // Update local vpn-subnet DS
1138         updateVpnMaps(vpn, name, router, tenant, networks);
1139
1140         if (router != null) {
1141             Uuid existingVpn = neutronvpnUtils.getVpnForRouter(router, true);
1142             if (existingVpn != null) {
1143                 // use case when a cluster is rebooted and router add DCN is received, triggering #createL3InternalVpn
1144                 // if before reboot, router was already associated to VPN, should not proceed associating router to
1145                 // internal VPN. Adding to RouterInterfacesMap is also not needed since it's a config DS and will be
1146                 // preserved upon reboot.
1147                 // For a non-reboot case #associateRouterToInternalVPN already takes care of adding to
1148                 // RouterInterfacesMap via #createVPNInterface call.
1149                 LOG.info("Associating router to Internal VPN skipped for VPN {} due to router {} already associated "
1150                     + "to external VPN {}", vpn.getValue(), router.getValue(), existingVpn.getValue());
1151                 return;
1152             }
1153             associateRouterToInternalVpn(vpn, router);
1154         }
1155     }
1156
1157     /**
1158      * Performs the creation of a Neutron L3VPN, associating the new VPN to the
1159      * specified Neutron Networks and Routers.
1160      *
1161      * @param vpnId Uuid of the VPN tp be created
1162      * @param name Representative name of the new VPN
1163      * @param tenantId Uuid of the Tenant under which the VPN is going to be created
1164      * @param rdList Route-distinguisher for the VPN
1165      * @param irtList A list of Import Route Targets
1166      * @param ertList A list of Export Route Targets
1167      * @param routerIdsList ist of neutron router Id to associate with created VPN
1168      * @param networkList UUID of the neutron network the VPN may be associated to
1169      * @param type Type of the VPN Instance
1170      * @param l3vni L3VNI for the VPN Instance using VxLAN as the underlay
1171      * @throws Exception if association of L3VPN failed
1172      */
1173     public void createVpn(Uuid vpnId, String name, Uuid tenantId, List<String> rdList, List<String> irtList,
1174                     List<String> ertList,  @Nullable List<Uuid> routerIdsList, List<Uuid> networkList,
1175                     VpnInstance.Type type, long l3vni) throws Exception {
1176
1177         IpVersionChoice ipVersChoices = IpVersionChoice.UNDEFINED;
1178
1179         if (routerIdsList != null && !routerIdsList.isEmpty()) {
1180             for (Uuid routerId : routerIdsList) {
1181                 IpVersionChoice vers = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(routerId);
1182                 ipVersChoices = ipVersChoices.addVersion(vers);
1183             }
1184         }
1185         updateVpnInstanceNode(vpnId, rdList, irtList, ertList, type, l3vni, ipVersChoices);
1186
1187         // Please note that router and networks will be filled into VPNMaps
1188         // by subsequent calls here to associateRouterToVpn and
1189         // associateNetworksToVpn
1190         updateVpnMaps(vpnId, name, null, tenantId, null);
1191         LOG.debug("Created L3VPN with ID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, routerIdsList {}, "
1192                         + "networkList {}", vpnId.getValue(), name, tenantId, rdList, irtList, ertList, routerIdsList,
1193                 networkList);
1194
1195         if (routerIdsList != null && !routerIdsList.isEmpty()) {
1196             for (Uuid routerId : routerIdsList) {
1197                 associateRouterToVpn(vpnId, routerId);
1198             }
1199         }
1200         if (networkList != null) {
1201             List<String> failStrings = associateNetworksToVpn(vpnId, networkList);
1202             if (!failStrings.isEmpty()) {
1203                 LOG.error("VPN {} association to networks failed for networks: {}. ",
1204                         vpnId.getValue(), failStrings.toString());
1205                 throw new Exception(failStrings.toString());
1206             }
1207         }
1208     }
1209
1210     /**
1211      * It handles the invocations to the createVPN RPC method.
1212      */
1213     @Override
1214     // TODO Clean up the exception handling
1215     @SuppressWarnings("checkstyle:IllegalCatch")
1216     public ListenableFuture<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
1217
1218         CreateL3VPNOutputBuilder opBuilder = new CreateL3VPNOutputBuilder();
1219         SettableFuture<RpcResult<CreateL3VPNOutput>> result = SettableFuture.create();
1220         List<RpcError> errorList = new ArrayList<>();
1221         int failurecount = 0;
1222         int warningcount = 0;
1223
1224         List<L3vpn> vpns = input.getL3vpn();
1225         if (vpns == null) {
1226             vpns = Collections.emptyList();
1227         }
1228         for (L3vpn vpn : vpns) {
1229             if (neutronvpnUtils.doesVpnExist(vpn.getId())) {
1230                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1231                         formatAndLog(LOG::warn,
1232                                 "Creation of L3VPN failed for VPN {} due to VPN with the same ID already present",
1233                                 vpn.getId().getValue())));
1234                 warningcount++;
1235                 continue;
1236             }
1237             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
1238                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1239                         formatAndLog(LOG::warn,
1240                                 "Creation of L3VPN failed for VPN {} due to absence of RD/iRT/eRT input",
1241                                 vpn.getId().getValue())));
1242                 warningcount++;
1243                 continue;
1244             }
1245             VpnInstance.Type vpnInstanceType = VpnInstance.Type.L3;
1246             long l3vni = 0;
1247             if (vpn.getL3vni() != null) {
1248                 l3vni = vpn.getL3vni();
1249             }
1250
1251             List<String> existingRDs = neutronvpnUtils.getExistingRDs();
1252             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
1253                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1254                         formatAndLog(LOG::warn,
1255                                 "Creation of L3VPN failed for VPN {} as another VPN with the same RD {} "
1256                                         + "is already configured",
1257                                 vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0))));
1258                 warningcount++;
1259                 continue;
1260             }
1261             Optional<String> operationalVpn = getExistingOperationalVpn(vpn.getRouteDistinguisher().get(0));
1262             if (operationalVpn.isPresent()) {
1263                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION, "application-error",
1264                         formatAndLog(LOG::error,
1265                                 "Creation of L3VPN failed for VPN {} as another VPN {} with the same RD {} "
1266                                         + "is still available. Please retry creation of a new vpn with the same RD"
1267                                         + " after a couple of minutes.", vpn.getId().getValue(), operationalVpn.get(),
1268                                 vpn.getRouteDistinguisher().get(0))));
1269                 warningcount++;
1270                 continue;
1271             }
1272             if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
1273                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds>
1274                         routerIdsList = vpn.getRouterIds();
1275                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
1276                         routerId : routerIdsList) {
1277                     if (neutronvpnUtils.getNeutronRouter(routerId.getRouterId()) == null) {
1278                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1279                                 formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to absense of routers"
1280                                         + "{}", vpn.getId(), routerId.getRouterId())));
1281                         warningcount++;
1282                         continue;
1283                     }
1284                     Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
1285                     if (vpnId != null) {
1286                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1287                                 formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to router {} already "
1288                                                 + "associated to another VPN {}", vpn.getId(), routerId.getRouterId(),
1289                                         vpnId.getValue())));
1290                         warningcount++;
1291                         continue;
1292                     }
1293                 }
1294             }
1295             if (vpn.getNetworkIds() != null) {
1296                 int initialWarningCount = warningcount;
1297                 for (Uuid nw : vpn.getNetworkIds()) {
1298                     Network network = neutronvpnUtils.getNeutronNetwork(nw);
1299                     Uuid vpnId = neutronvpnUtils.getVpnForNetwork(nw);
1300                     if (network == null) {
1301                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1302                                 formatAndLog(LOG::warn,
1303                                         "Creation of L3VPN failed for VPN {} due to network not found {}",
1304                                         vpn.getId().getValue(), nw.getValue())));
1305                         warningcount++;
1306                     } else if (vpnId != null) {
1307                         errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
1308                                 formatAndLog(LOG::warn,
1309                                         "Creation of L3VPN failed for VPN {} due to network {} already associated"
1310                                                 + " to another VPN {}", vpn.getId().getValue(), nw.getValue(),
1311                                         vpnId.getValue())));
1312                         warningcount++;
1313                     }
1314                 }
1315                 if (warningcount != initialWarningCount) {
1316                     continue;
1317                 }
1318             }
1319             List<Uuid> rtrIdsList = new ArrayList<>();
1320             if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
1321                 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
1322                         rtrId : vpn.getRouterIds()) {
1323                     rtrIdsList.add(rtrId.getRouterId());
1324                 }
1325             }
1326             try {
1327                 LOG.debug("L3VPN add RPC: VpnID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, "
1328                                 + "routerIdList {}, networksList {}", vpn.getId().getValue(), vpn.getName(),
1329                         vpn.getTenantId(), vpn.getRouteDistinguisher().toString(), vpn.getImportRT().toString(),
1330                         vpn.getExportRT().toString(), rtrIdsList, vpn.getNetworkIds());
1331                 createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), vpn.getRouteDistinguisher(),
1332                         vpn.getImportRT(), vpn.getExportRT(), rtrIdsList, vpn.getNetworkIds(),
1333                         vpnInstanceType, l3vni);
1334             } catch (Exception ex) {
1335                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION,
1336                         formatAndLog(LOG::error, "Creation of VPN failed for VPN {}", vpn.getId().getValue(), ex),
1337                         ex.getMessage()));
1338                 failurecount++;
1339             }
1340         }
1341         // if at least one succeeds; result is success
1342         // if none succeeds; result is failure
1343         if (failurecount + warningcount == vpns.size()) {
1344             result.set(RpcResultBuilder.<CreateL3VPNOutput>failed().withRpcErrors(errorList).build());
1345         } else {
1346             List<String> errorResponseList = new ArrayList<>();
1347             if (!errorList.isEmpty()) {
1348                 for (RpcError rpcError : errorList) {
1349                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
1350                             + ", ErrorMessage: " + rpcError.getMessage());
1351                 }
1352             } else {
1353                 errorResponseList.add("Operation successful with no errors");
1354             }
1355             opBuilder.setResponse(errorResponseList);
1356             result.set(RpcResultBuilder.<CreateL3VPNOutput>success().withResult(opBuilder.build()).build());
1357         }
1358         return result;
1359     }
1360
1361     /**
1362      * It handles the invocations to the neutronvpn:getL3VPN RPC method.
1363      */
1364     @Override
1365     public ListenableFuture<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
1366
1367         GetL3VPNOutputBuilder opBuilder = new GetL3VPNOutputBuilder();
1368         SettableFuture<RpcResult<GetL3VPNOutput>> result = SettableFuture.create();
1369         Uuid inputVpnId = input.getId();
1370         List<VpnInstance> vpns = new ArrayList<>();
1371         List<L3vpnInstances> l3vpnList = new ArrayList<>();
1372
1373         try {
1374             if (inputVpnId == null) {
1375                 // get all vpns
1376                 InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class)
1377                         .build();
1378                 Optional<VpnInstances> optionalVpns =
1379                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1380                                 vpnsIdentifier);
1381                 if (optionalVpns.isPresent() && !optionalVpns.get().getVpnInstance().isEmpty()) {
1382                     for (VpnInstance vpn : optionalVpns.get().getVpnInstance()) {
1383                         // eliminating implicitly created (router and VLAN provider external network specific) VPNs
1384                         // from getL3VPN output
1385                         if (vpn.getIpv4Family().getRouteDistinguisher() != null) {
1386                             vpns.add(vpn);
1387                         }
1388                         if (vpn.getIpv6Family().getRouteDistinguisher() != null) {
1389                             vpns.add(vpn);
1390                         }
1391                     }
1392                 } else {
1393                     // No VPN present
1394                     opBuilder.setL3vpnInstances(l3vpnList);
1395                     result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1396                     return result;
1397                 }
1398             } else {
1399                 String name = inputVpnId.getValue();
1400                 InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
1401                         .child(VpnInstance.class, new VpnInstanceKey(name)).build();
1402                 // read VpnInstance Info
1403                 Optional<VpnInstance> optionalVpn =
1404                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1405                                 vpnIdentifier);
1406                 // eliminating implicitly created (router or VLAN provider external network specific) VPN from
1407                 // getL3VPN output
1408                 if (optionalVpn.isPresent() && (optionalVpn.get().getIpv4Family().getRouteDistinguisher() != null)
1409                         || (optionalVpn.get().getIpv6Family().getRouteDistinguisher() != null)) {
1410                     vpns.add(optionalVpn.get());
1411                 } else {
1412                     result.set(
1413                             RpcResultBuilder.<GetL3VPNOutput>failed().withWarning(ErrorType.PROTOCOL, "invalid-value",
1414                                     formatAndLog(LOG::error, "GetL3VPN failed because VPN {} is not present",
1415                                             name)).build());
1416                 }
1417             }
1418             for (VpnInstance vpnInstance : vpns) {
1419                 Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
1420                 // create VpnMaps id
1421                 L3vpnInstancesBuilder l3vpn = new L3vpnInstancesBuilder();
1422                 List<String> rd = Collections.EMPTY_LIST;
1423                 if (vpnInstance.getIpv4Family().getRouteDistinguisher() != null) {
1424                     rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1425                 } else if (vpnInstance.getIpv6Family().getRouteDistinguisher() != null) {
1426                     rd = vpnInstance.getIpv6Family().getRouteDistinguisher();
1427                 }
1428                 List<String> ertList = new ArrayList<>();
1429                 List<String> irtList = new ArrayList<>();
1430
1431                 if (vpnInstance.getIpv4Family().getVpnTargets() != null
1432                         || vpnInstance.getIpv6Family().getVpnTargets() != null) {
1433                     List<VpnTarget> vpnTargetList = Collections.EMPTY_LIST;
1434                     if (!vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget().isEmpty()) {
1435                         vpnTargetList = vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget();
1436                     } else if (!vpnInstance.getIpv6Family().getVpnTargets().getVpnTarget().isEmpty()) {
1437                         vpnTargetList = vpnInstance.getIpv6Family().getVpnTargets().getVpnTarget();
1438                     }
1439                     if (!vpnTargetList.isEmpty()) {
1440                         for (VpnTarget vpnTarget : vpnTargetList) {
1441                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
1442                                 ertList.add(vpnTarget.getVrfRTValue());
1443                             }
1444                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
1445                                 irtList.add(vpnTarget.getVrfRTValue());
1446                             }
1447                             if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
1448                                 ertList.add(vpnTarget.getVrfRTValue());
1449                                 irtList.add(vpnTarget.getVrfRTValue());
1450                             }
1451                         }
1452                     }
1453                 }
1454
1455                 l3vpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
1456
1457                 if (vpnInstance.getL3vni() != null) {
1458                     l3vpn.setL3vni(vpnInstance.getL3vni());
1459                 }
1460                 InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
1461                         .class, new VpnMapKey(vpnId)).build();
1462                 Optional<VpnMap> optionalVpnMap =
1463                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1464                                 vpnMapIdentifier);
1465                 if (optionalVpnMap.isPresent()) {
1466                     VpnMap vpnMap = optionalVpnMap.get();
1467                     List<Uuid> rtrIds = new ArrayList<>();
1468                     if (vpnMap.getRouterIds() != null && !vpnMap.getRouterIds().isEmpty()) {
1469                         for (RouterIds rtrId : vpnMap.getRouterIds()) {
1470                             rtrIds.add(rtrId.getRouterId());
1471                         }
1472                     }
1473                     l3vpn.setRouterIds(NeutronvpnUtils.getVpnInstanceRouterIdsList(rtrIds))
1474                             .setNetworkIds(vpnMap.getNetworkIds()).setTenantId(vpnMap.getTenantId())
1475                             .setName(vpnMap.getName());
1476
1477                 }
1478                 l3vpnList.add(l3vpn.build());
1479             }
1480
1481             opBuilder.setL3vpnInstances(l3vpnList);
1482             result.set(RpcResultBuilder.<GetL3VPNOutput>success().withResult(opBuilder.build()).build());
1483
1484         } catch (ReadFailedException ex) {
1485             result.set(RpcResultBuilder.<GetL3VPNOutput>failed().withError(ErrorType.APPLICATION,
1486                     formatAndLog(LOG::error, "GetVPN failed due to {}", ex.getMessage())).build());
1487         }
1488         return result;
1489     }
1490
1491     /**
1492      * It handles the invocations to the neutronvpn:deleteL3VPN RPC method.
1493      */
1494     @Override
1495     public ListenableFuture<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
1496
1497         DeleteL3VPNOutputBuilder opBuilder = new DeleteL3VPNOutputBuilder();
1498         SettableFuture<RpcResult<DeleteL3VPNOutput>> result = SettableFuture.create();
1499         List<RpcError> errorList = new ArrayList<>();
1500
1501         int failurecount = 0;
1502         int warningcount = 0;
1503         List<Uuid> vpns = input.getId();
1504         for (Uuid vpn : vpns) {
1505             RpcError error;
1506             String msg;
1507             try {
1508                 LOG.debug("L3VPN delete RPC: VpnID {}", vpn.getValue());
1509                 InstanceIdentifier<VpnInstance> vpnIdentifier =
1510                         InstanceIdentifier.builder(VpnInstances.class)
1511                             .child(VpnInstance.class, new VpnInstanceKey(vpn.getValue())).build();
1512                 Optional<VpnInstance> optionalVpn =
1513                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1514                                 vpnIdentifier);
1515                 if (optionalVpn.isPresent()) {
1516                     removeVpn(vpn);
1517                 } else {
1518                     errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-value",
1519                             formatAndLog(LOG::warn, "VPN with vpnid: {} does not exist", vpn.getValue())));
1520                     warningcount++;
1521                 }
1522             } catch (ReadFailedException ex) {
1523                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION,
1524                         formatAndLog(LOG::error, "Deletion of L3VPN failed when deleting for uuid {}", vpn.getValue()),
1525                         ex.getMessage()));
1526                 failurecount++;
1527             }
1528         }
1529         // if at least one succeeds; result is success
1530         // if none succeeds; result is failure
1531         if (failurecount + warningcount == vpns.size()) {
1532             result.set(RpcResultBuilder.<DeleteL3VPNOutput>failed().withRpcErrors(errorList).build());
1533         } else {
1534             List<String> errorResponseList = new ArrayList<>();
1535             if (!errorList.isEmpty()) {
1536                 for (RpcError rpcError : errorList) {
1537                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
1538                             + ", ErrorMessage: " + rpcError.getMessage());
1539                 }
1540             } else {
1541                 errorResponseList.add("Operation successful with no errors");
1542             }
1543             opBuilder.setResponse(errorResponseList);
1544             result.set(RpcResultBuilder.<DeleteL3VPNOutput>success().withResult(opBuilder.build()).build());
1545         }
1546         return result;
1547     }
1548
1549     public void createVpnInstanceForSubnet(Uuid subnetId) {
1550         LOG.debug("Creating/Updating L3 internalVPN for subnetID {} ", subnetId);
1551         createL3InternalVpn(subnetId, subnetId.getValue(), null, null, null, null, null, null);
1552     }
1553
1554     public void removeVpnInstanceForSubnet(Uuid subnetId) {
1555         LOG.debug("Removing vpn-instance for subnetID {} ", subnetId);
1556         removeVpn(subnetId);
1557     }
1558
1559     protected void addSubnetToVpn(@Nullable final Uuid vpnId, Uuid subnet, @Nullable final Uuid internetVpnId) {
1560         LOG.debug("addSubnetToVpn: Adding subnet {} to vpn {}", subnet.getValue(),
1561                   vpnId != null ? vpnId.getValue() : internetVpnId.getValue());
1562         Subnetmap sn = updateSubnetNode(subnet, null, vpnId, internetVpnId);
1563         if (sn == null) {
1564             LOG.error("addSubnetToVpn: subnetmap is null, cannot add subnet {} to VPN {}", subnet.getValue(),
1565                 vpnId != null ? vpnId.getValue() : internetVpnId.getValue());
1566             return;
1567         }
1568         if (vpnId != null) {
1569             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
1570             if (vpnMap == null) {
1571                 LOG.error("addSubnetToVpn: No vpnMap for vpnId {},"
1572                      + " cannot add subnet {} to VPN", vpnId.getValue(),
1573                     subnet.getValue());
1574                 return;
1575             }
1576             final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
1577             LOG.debug("addSubnetToVpn: VpnInstance {}", vpnInstance.toString());
1578             if (isVpnOfTypeL2(vpnInstance)) {
1579                 neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
1580                         NeutronEvpnUtils.Operation.ADD);
1581             }
1582         }
1583         if (internetVpnId != null) {
1584             VpnMap vpnMap = neutronvpnUtils.getVpnMap(internetVpnId);
1585             if (vpnMap == null) {
1586                 LOG.error("addSubnetToVpn: No vpnMap for InternetVpnId {}, cannot add "
1587                     + "subnet {} to VPN", internetVpnId.getValue(),
1588                     subnet.getValue());
1589                 return;
1590             }
1591         }
1592         final Uuid internetId = internetVpnId;
1593         // Check if there are ports on this subnet and add corresponding vpn-interfaces
1594         List<Uuid> portList = sn.getPortList();
1595         if (portList != null) {
1596             for (final Uuid portId : portList) {
1597                 String vpnInfName = portId.getValue();
1598                 VpnInterface vpnIface = VpnHelper.getVpnInterface(dataBroker, vpnInfName);
1599                 Port port = neutronvpnUtils.getNeutronPort(portId);
1600                 if (port == null) {
1601                     LOG.error("addSubnetToVpn: Cannot proceed with addSubnetToVpn for port {} in subnet {} "
1602                         + "since port is absent in Neutron config DS", portId.getValue(), subnet.getValue());
1603                     continue;
1604                 }
1605                 final Boolean isRouterInterface = port.getDeviceOwner()
1606                         .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) ? true : false;
1607                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> singletonList(
1608                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
1609                         Adjacencies portAdj = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, sn,
1610                                     vpnIface);
1611                         if (vpnIface == null) {
1612                             LOG.trace("addSubnetToVpn: create new VpnInterface for Port {}", vpnInfName);
1613                             Set<Uuid> listVpn = new HashSet<>();
1614                             if (vpnId != null) {
1615                                 listVpn.add(vpnId);
1616                             }
1617                             if (internetId != null) {
1618                                 listVpn.add(internetId);
1619                             }
1620                             writeVpnInterfaceToDs(listVpn,
1621                                     vpnInfName, portAdj, isRouterInterface, wrtConfigTxn);
1622                             if (sn.getRouterId() != null) {
1623                                 addToNeutronRouterInterfacesMap(sn.getRouterId(), portId.getValue());
1624                             }
1625                         } else {
1626                             LOG.trace("update VpnInterface for Port {} with adj {}", vpnInfName, portAdj);
1627                             if (vpnId != null) {
1628                                 updateVpnInterfaceWithAdjacencies(vpnId, vpnInfName, portAdj, wrtConfigTxn);
1629                             }
1630                             if (internetId != null) {
1631                                 updateVpnInterfaceWithAdjacencies(internetId, vpnInfName, portAdj, wrtConfigTxn);
1632                             }
1633                         }
1634                     }))
1635                 );
1636             }
1637         }
1638     }
1639
1640     protected void removeSubnetFromVpn(final Uuid vpnId, Uuid subnet, Uuid internetVpnId) {
1641         Preconditions.checkArgument(vpnId != null || internetVpnId != null,
1642                 "removeSubnetFromVpn: at least one VPN must be not null");
1643         LOG.debug("Removing subnet {} from vpn {}/{}", subnet.getValue(),
1644                   vpnId, internetVpnId);
1645         Subnetmap sn = neutronvpnUtils.getSubnetmap(subnet);
1646         if (sn == null) {
1647             LOG.error("removeSubnetFromVpn: Subnetmap for subnet {} not found", subnet.getValue());
1648             return;
1649         }
1650         VpnMap vpnMap = null;
1651         VpnInstance vpnInstance = null;
1652         if (vpnId != null) {
1653             vpnMap = neutronvpnUtils.getVpnMap(vpnId);
1654             if (vpnMap == null) {
1655                 LOG.error("No vpnMap for vpnId {}, cannot remove subnet {} from VPN",
1656                         vpnId.getValue(), subnet.getValue());
1657                 return;
1658             }
1659             vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
1660         }
1661         if (internetVpnId == null) {
1662             internetVpnId = sn.getInternetVpnId();
1663         }
1664         if (internetVpnId != null) {
1665             vpnMap = neutronvpnUtils.getVpnMap(internetVpnId);
1666             if (vpnMap == null) {
1667                 LOG.error("No vpnMap for vpnId {}, cannot remove subnet {}"
1668                         + " from Internet VPN",
1669                         internetVpnId.getValue(), subnet.getValue());
1670                 return;
1671             }
1672         }
1673         if (vpnInstance != null && isVpnOfTypeL2(vpnInstance)) {
1674             neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
1675                     NeutronEvpnUtils.Operation.DELETE);
1676         }
1677         boolean subnetVpnAssociation = false;
1678         if (vpnId != null && sn.getVpnId() != null
1679             && sn.getVpnId().getValue().equals(vpnId.getValue())) {
1680             subnetVpnAssociation = true;
1681         } else if (internetVpnId != null && sn.getInternetVpnId() != null
1682             && sn.getInternetVpnId().getValue().matches(internetVpnId.getValue())) {
1683             subnetVpnAssociation = true;
1684         }
1685         if (subnetVpnAssociation == false) {
1686             LOG.error("Removing subnet : Subnetmap is not in VPN {}/{}, owns {} and {}",
1687                       vpnId, internetVpnId, sn.getVpnId(), sn.getInternetVpnId());
1688             return;
1689         }
1690         // Check if there are ports on this subnet; remove corresponding vpn-interfaces
1691         List<Uuid> portList = sn.getPortList();
1692         final Uuid internetId = internetVpnId;
1693         if (portList != null) {
1694             for (final Uuid portId : portList) {
1695                 LOG.debug("withdrawing subnet IP {} from vpn-interface {}", sn.getSubnetIp(), portId.getValue());
1696                 final Port port = neutronvpnUtils.getNeutronPort(portId);
1697                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(),
1698                     () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
1699                             CONFIGURATION, tx -> {
1700                             if (port != null) {
1701                                 withdrawPortIpFromVpnIface(vpnId, internetId, port, sn, tx);
1702                             } else {
1703                                 LOG.warn(
1704                                         "Cannot proceed with withdrawPortIpFromVpnIface for port {} in subnet {} since "
1705                                                 + "port is absent in Neutron config DS", portId.getValue(),
1706                                         subnet.getValue());
1707                             }
1708                         })));
1709             }
1710         }
1711         //update subnet-vpn association
1712         removeFromSubnetNode(subnet, null, null, vpnId, null);
1713     }
1714
1715     protected void updateVpnInternetForSubnet(Subnetmap sm, Uuid vpn, boolean isBeingAssociated) {
1716         LOG.debug("updateVpnInternetForSubnet: {} subnet {} with BGPVPN Internet {} ",
1717              isBeingAssociated ? "associating" : "dissociating", sm.getSubnetIp(),
1718              vpn.getValue());
1719         Uuid internalVpnId = sm.getVpnId();
1720         if (internalVpnId == null) {
1721             LOG.error("updateVpnInternetForSubnet: can not find Internal or BGPVPN Id for subnet {}, bailing out",
1722                       sm.getId().getValue());
1723             return;
1724         }
1725         if (isBeingAssociated) {
1726             updateSubnetNode(sm.getId(), null, sm.getVpnId(), vpn);
1727         } else {
1728             updateSubnetNode(sm.getId(), null, sm.getVpnId(), null);
1729         }
1730
1731         jobCoordinator.enqueueJob("VPN-" + vpn.getValue(), () -> singletonList(
1732             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
1733                 if (isBeingAssociated) {
1734                     updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(
1735                             sm.getRouterInterfacePortId()), true, true, wrtConfigTxn);
1736                 } else {
1737                     removeVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()),
1738                                         wrtConfigTxn, sm);
1739                 }
1740                 }
1741             )));
1742
1743         // Check for ports on this subnet and update association of
1744         // corresponding vpn-interfaces to internet vpn
1745         List<Uuid> portList = sm.getPortList();
1746         if (portList != null) {
1747             for (Uuid port : portList) {
1748                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1749                         port.getValue(), isBeingAssociated);
1750                 jobCoordinator.enqueueJob("PORT-" + port.getValue(),
1751                     () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1752                         tx -> {
1753                             if (isBeingAssociated) {
1754                                 updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(port),
1755                                         true, false, tx);
1756                             } else {
1757                                 removeVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(port), tx, sm);
1758                             }
1759                         })));
1760             }
1761         }
1762     }
1763
1764     private Subnetmap updateVpnForSubnet(Uuid oldVpnId, Uuid newVpnId, Uuid subnet, boolean isBeingAssociated) {
1765         LOG.debug("Moving subnet {} from oldVpn {} to newVpn {} ", subnet.getValue(),
1766                 oldVpnId.getValue(), newVpnId.getValue());
1767         Uuid networkUuid = neutronvpnUtils.getSubnetmap(subnet).getNetworkId();
1768         Network network = neutronvpnUtils.getNeutronNetwork(networkUuid);
1769         boolean netIsExternal = NeutronvpnUtils.getIsExternal(network);
1770         Uuid vpnExtUuid = netIsExternal ? null
1771                 : neutronvpnUtils.getInternetvpnUuidBoundToSubnetRouter(subnet);
1772         Subnetmap sn = updateSubnetNode(subnet, null, newVpnId, vpnExtUuid);
1773         if (sn == null) {
1774             LOG.error("Updating subnet {} with newVpn {} failed", subnet.getValue(), newVpnId.getValue());
1775             return sn;
1776         }
1777
1778         //Update Router Interface first synchronously.
1779         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
1780         ListenableFuture<Void> future =
1781                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1782                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1783                         neutronvpnUtils.getNeutronPort(sn.getRouterInterfacePortId()),
1784                         isBeingAssociated, true, tx));
1785         Futures.addCallback(future, new FutureCallback<Void>() {
1786             @Override
1787             public void onSuccess(Void result) {
1788                 // Check for ports on this subnet and update association of
1789                 // corresponding vpn-interfaces to external vpn
1790                 List<Uuid> portList = sn.getPortList();
1791                 if (portList != null) {
1792                     for (Uuid port : portList) {
1793                         LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
1794                                 port.getValue(), isBeingAssociated);
1795                         jobCoordinator.enqueueJob("PORT-" + port.getValue(), () -> Collections.singletonList(
1796                                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1797                                     tx -> updateVpnInterface(newVpnId, oldVpnId,
1798                                             neutronvpnUtils.getNeutronPort(port), isBeingAssociated, false,
1799                                             tx))));
1800                     }
1801                 }
1802             }
1803
1804             @Override
1805             public void onFailure(Throwable throwable) {
1806                 LOG.error(
1807                         "Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, "
1808                                 + "returning",
1809                         sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId, throwable);
1810             }
1811         }, MoreExecutors.directExecutor());
1812
1813         return sn;
1814     }
1815
1816     public InstanceIdentifier<RouterInterfaces> getRouterInterfacesId(Uuid routerId) {
1817         return InstanceIdentifier.builder(RouterInterfacesMap.class)
1818                 .child(RouterInterfaces.class, new RouterInterfacesKey(routerId)).build();
1819     }
1820
1821     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1822         synchronized (routerId.getValue().intern()) {
1823             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1824             try {
1825                 Optional<RouterInterfaces> optRouterInterfaces =
1826                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1827                                 routerInterfacesId);
1828                 Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1829                     .setInterfaceId(interfaceName).build();
1830                 if (optRouterInterfaces.isPresent()) {
1831                     SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1832                             routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)),
1833                             routerInterface);
1834                 } else {
1835                     // TODO Shouldn't we be doing something with builder and interfaces?
1836 //                    RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
1837 //                    List<Interfaces> interfaces = new ArrayList<>();
1838 //                    interfaces.add(routerInterface);
1839
1840                     SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1841                             routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)),
1842                             routerInterface);
1843                 }
1844             } catch (ReadFailedException | TransactionCommitFailedException e) {
1845                 LOG.error("Error reading router interfaces for {}", routerInterfacesId, e);
1846             }
1847         }
1848     }
1849
1850     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
1851         synchronized (routerId.getValue().intern()) {
1852             InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
1853             try {
1854                 Optional<RouterInterfaces> optRouterInterfaces =
1855                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1856                                 routerInterfacesId);
1857                 Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
1858                     .setInterfaceId(interfaceName).build();
1859                 if (optRouterInterfaces.isPresent()) {
1860                     RouterInterfaces routerInterfaces = optRouterInterfaces.get();
1861                     List<Interfaces> interfaces = routerInterfaces.getInterfaces();
1862                     if (interfaces != null && interfaces.remove(routerInterface)) {
1863                         if (interfaces.isEmpty()) {
1864                             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1865                                     routerInterfacesId);
1866                         } else {
1867                             SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
1868                                     routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
1869                         }
1870                     }
1871                 }
1872             } catch (ReadFailedException | TransactionCommitFailedException e) {
1873                 LOG.error("Error reading the router interfaces for {}", routerInterfacesId, e);
1874             }
1875         }
1876     }
1877
1878     /**
1879      * Creates the corresponding static routes in the specified VPN. These static routes must be point to an
1880      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink. Otherwise the
1881      * route will be ignored.
1882      *
1883      * @param vpnName the VPN identifier
1884      * @param interVpnLinkRoutes The list of static routes
1885      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1886      */
1887     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1888                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1889         for (Routes route : interVpnLinkRoutes) {
1890             String nexthop = String.valueOf(route.getNexthop().getValue());
1891             String destination = String.valueOf(route.getDestination().getValue());
1892             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1893             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
1894                 AddStaticRouteInput rpcInput =
1895                         new AddStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1896                                 .setVpnInstanceName(vpnName.getValue())
1897                                 .build();
1898                 Future<RpcResult<AddStaticRouteOutput>> labelOuputFtr = vpnRpcService.addStaticRoute(rpcInput);
1899                 RpcResult<AddStaticRouteOutput> rpcResult;
1900                 try {
1901                     rpcResult = labelOuputFtr.get();
1902                     if (rpcResult.isSuccessful()) {
1903                         LOG.debug("Label generated for destination {} is: {}",
1904                                 destination, rpcResult.getResult().getLabel());
1905                     } else {
1906                         LOG.error("RPC call to add a static Route to {} with nexthop {} returned with errors {}",
1907                                 destination, nexthop, rpcResult.getErrors());
1908                     }
1909                 } catch (InterruptedException | ExecutionException e) {
1910                     LOG.error("Error happened while invoking addStaticRoute RPC for nexthop {} with destination {} "
1911                             + "for VPN {}", nexthop, destination, vpnName.getValue(), e);
1912                 }
1913             } else {
1914                 // Any other case is a fault.
1915                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1916                         String.valueOf(route.getDestination().getValue()), nexthop);
1917                 continue;
1918             }
1919         }
1920     }
1921
1922     /**
1923      * Removes the corresponding static routes from the specified VPN. These static routes point to an
1924      * InterVpnLink endpoint and the specified VPN must be the other end of the InterVpnLink.
1925      *
1926      * @param vpnName the VPN identifier
1927      * @param interVpnLinkRoutes The list of static routes
1928      * @param nexthopsXinterVpnLinks A Map with the correspondence nextHop-InterVpnLink
1929      */
1930     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
1931                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
1932         for (Routes route : interVpnLinkRoutes) {
1933             String nexthop = String.valueOf(route.getNexthop().getValue());
1934             String destination = String.valueOf(route.getDestination().getValue());
1935             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
1936             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
1937                 RemoveStaticRouteInput rpcInput =
1938                         new RemoveStaticRouteInputBuilder().setDestination(destination).setNexthop(nexthop)
1939                                 .setVpnInstanceName(vpnName.getValue())
1940                                 .build();
1941
1942                 ListenableFutures.addErrorLogging(JdkFutureAdapters.listenInPoolThread(
1943                         vpnRpcService.removeStaticRoute(rpcInput)), LOG, "Remove VPN routes");
1944             } else {
1945                 // Any other case is a fault.
1946                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
1947                         String.valueOf(route.getDestination().getValue()), nexthop);
1948                 continue;
1949             }
1950         }
1951     }
1952
1953     /*
1954      * Returns true if the specified nexthop is the other endpoint in an
1955      * InterVpnLink, regarding one of the VPN's point of view.
1956      */
1957     private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
1958         return
1959                 interVpnLink != null
1960                         && (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
1961                         && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop)
1962                         || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
1963                         && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop));
1964     }
1965
1966     @Nonnull
1967     protected List<Adjacency> getAdjacencyforExtraRoute(List<Routes> routeList, String fixedIp) {
1968         List<Adjacency> adjList = new ArrayList<>();
1969         Map<String, List<String>> adjMap = new HashMap<>();
1970         for (Routes route : routeList) {
1971             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
1972                 LOG.error("Incorrect input received for extra route. {}", route);
1973             } else {
1974                 String nextHop = String.valueOf(route.getNexthop().getValue());
1975                 String destination = String.valueOf(route.getDestination().getValue());
1976                 if (!nextHop.equals(fixedIp)) {
1977                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
1978                     continue;
1979                 }
1980                 LOG.trace("Adding extra route for destination {} with nexthop {} ", destination,
1981                         nextHop);
1982                 List<String> hops = adjMap.computeIfAbsent(destination, k -> new ArrayList<>());
1983                 if (!hops.contains(nextHop)) {
1984                     hops.add(nextHop);
1985                 }
1986             }
1987         }
1988
1989         for (Entry<String, List<String>> entry : adjMap.entrySet()) {
1990             final String destination = entry.getKey();
1991             final List<String> ipList = entry.getValue();
1992             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
1993                     .setAdjacencyType(AdjacencyType.ExtraRoute).setNextHopIpList(ipList)
1994                     .withKey(new AdjacencyKey(destination)).build();
1995             adjList.add(erAdj);
1996         }
1997         return adjList;
1998     }
1999
2000     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
2001         checkAlarmExtraRoutes(vpnId, routeList);
2002
2003         for (Routes route : routeList) {
2004             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
2005                 LOG.error("Incorrect input received for extra route. {}", route);
2006             } else {
2007                 String nextHop = String.valueOf(route.getNexthop().getValue());
2008                 String destination = String.valueOf(route.getDestination().getValue());
2009                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2010                         nextHop);
2011                 if (infName != null) {
2012                     LOG.trace("Updating extra route for destination {} onto vpn {} with nexthop {} and infName {}",
2013                         destination, vpnId.getValue(), nextHop, infName);
2014                     boolean isLockAcquired = false;
2015                     try {
2016                         InstanceIdentifier<VpnInterface> identifier = InstanceIdentifier.builder(VpnInterfaces.class)
2017                                 .child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2018                         InstanceIdentifier<Adjacency> path = identifier.augmentation(Adjacencies.class)
2019                             .child(Adjacency.class, new AdjacencyKey(destination));
2020                         Optional<Adjacency> existingAdjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2021                                 LogicalDatastoreType.CONFIGURATION, path);
2022                         if (existingAdjacency.isPresent()
2023                                 && existingAdjacency.get().getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2024                             LOG.error("The route with destination {} nextHop {} is already present as"
2025                                             + " a primary adjacency for interface {}. Skipping adjacency addition.",
2026                                     destination, nextHop, infName);
2027                             continue;
2028                         }
2029                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
2030                             .setNextHopIpList(Collections.singletonList(nextHop)).withKey(new AdjacencyKey(destination))
2031                             .setAdjacencyType(AdjacencyType.ExtraRoute).build();
2032                         isLockAcquired = interfaceLock.tryLock(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
2033                         SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2034                                 path, erAdj);
2035                     } catch (TransactionCommitFailedException e) {
2036                         LOG.error("exception in adding extra route with destination: {}, next hop: {}",
2037                             destination, nextHop, e);
2038                     } catch (ReadFailedException e) {
2039                         LOG.error("Exception on reading data-store ", e);
2040                     } finally {
2041                         if (isLockAcquired) {
2042                             interfaceLock.unlock(infName);
2043                         }
2044                     }
2045                 } else {
2046                     LOG.error("Unable to find VPN NextHop interface to apply extra-route destination {} on VPN {} "
2047                         + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2048                 }
2049             }
2050         }
2051     }
2052
2053     /**
2054      * This method setup or down an alarm about extra route fault.
2055      * When extra routes are configured, through a router, if the number of nexthops is greater than the number of
2056      * available RDs, then an alarm and an error is generated.<br>
2057      * <b>Be careful</b> the routeList could be changed.
2058      *
2059      * @param vpnId the vpnId of vpn to control.
2060      * @param routeList the list of router to check, it could be modified.
2061      */
2062     private void checkAlarmExtraRoutes(Uuid vpnId, List<Routes> routeList) {
2063         if (!neutronvpnAlarm.isAlarmEnabled()) {
2064             LOG.debug("checkAlarmExtraRoutes is not enable for vpnId {} routeList {}", vpnId, routeList);
2065             return;
2066         }
2067         VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(dataBroker, vpnId);
2068         if (vpnInstance == null || routeList == null || routeList.isEmpty() || !neutronvpnAlarm.isAlarmEnabled()) {
2069             LOG.debug("checkAlarmExtraRoutes have args null as following : vpnId {} routeList {}",
2070                     vpnId, routeList);
2071             return;
2072         }
2073         String primaryRd = neutronvpnUtils.getVpnRd(vpnId.getValue());
2074         if (primaryRd == null || primaryRd.equals(vpnId.getValue())) {
2075             LOG.debug("checkAlarmExtraRoutes. vpn {} is not a BGPVPN. cancel checkExtraRoute",
2076                     vpnId);
2077             return;
2078         }
2079         for (Routes route : routeList) {
2080             // count  the number of nexthops for each same route.getDestingation().getValue()
2081             String destination = String.valueOf(route.getDestination().getValue());
2082             String nextHop = String.valueOf(route.getNexthop().getValue());
2083             List<String> nextHopList = new ArrayList();
2084             nextHopList.add(nextHop);
2085             int nbNextHops = 0;
2086             for (Routes routeTmp : routeList) {
2087                 String routeDest = String.valueOf(routeTmp.getDestination().getValue());
2088                 if (!destination.equals(routeDest)) {
2089                     continue;
2090                 }
2091                 String routeNextH = String.valueOf(routeTmp.getNexthop().getValue());
2092                 if (nextHop.equals(routeNextH)) {
2093                     continue;
2094                 }
2095                 nbNextHops++;
2096                 nextHopList.add(new String(routeTmp.getNexthop().getValue()));
2097             }
2098             final List<String> rdList = new ArrayList<>();
2099             if (vpnInstance.getIpv4Family() != null
2100                     && vpnInstance.getIpv4Family().getRouteDistinguisher() != null) {
2101                 vpnInstance.getIpv4Family().getRouteDistinguisher().forEach(rd -> {
2102                     if (rd != null) {
2103                         rdList.add(rd);
2104                     }
2105                 });
2106             }
2107             if (vpnInstance.getIpv6Family() != null && vpnInstance.getIpv6Family().getRouteDistinguisher() != null) {
2108                 vpnInstance.getIpv6Family().getRouteDistinguisher().forEach(rd -> {
2109                     if (rd != null && !rdList.contains(rd)) {
2110                         rdList.add(rd);
2111                     }
2112                 });
2113             }
2114             // 1. VPN Instance Name
2115             String typeAlarm = "for vpnId: " + vpnId + " have exceeded next hops for prefixe";
2116
2117             // 2. Router ID
2118             List<Uuid> routerUuidList = neutronvpnUtils.getRouterIdListforVpn(vpnId);
2119             Uuid routerUuid = routerUuidList.get(0);
2120             StringBuilder detailsAlarm = new StringBuilder("routerUuid: ");
2121             detailsAlarm.append(routerUuid == null ? vpnId.toString() : routerUuid.getValue());
2122
2123             // 3. List of RDs associated with the VPN
2124             detailsAlarm.append(" List of RDs associated with the VPN: ");
2125             for (String s : rdList) {
2126                 detailsAlarm.append(s);
2127                 detailsAlarm.append(", ");
2128             }
2129
2130             // 4. Prefix in question
2131             detailsAlarm.append(" for prefix: ");
2132             detailsAlarm.append(route.getDestination().getValue());
2133
2134             // 5. List of NHs for the prefix
2135             detailsAlarm.append(" for nextHops: ");
2136             for (String s : nextHopList) {
2137                 detailsAlarm.append(s);
2138                 detailsAlarm.append(", ");
2139             }
2140
2141             if (rdList.size() < nbNextHops) {
2142                 neutronvpnAlarm.raiseNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2143             } else {
2144                 neutronvpnAlarm.clearNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
2145             }
2146         }
2147     }
2148
2149     // TODO Clean up the exception handling
2150     @SuppressWarnings("checkstyle:IllegalCatch")
2151     protected void removeAdjacencyforExtraRoute(Uuid vpnId, List<Routes> routeList) {
2152         for (Routes route : routeList) {
2153             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
2154                 boolean isLockAcquired = false;
2155                 String nextHop = String.valueOf(route.getNexthop().getValue());
2156                 String destination = String.valueOf(route.getDestination().getValue());
2157                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
2158                         nextHop);
2159                 if (infName == null) {
2160                     LOG.error("Unable to find VPN NextHop interface to remove extra-route destination {} on VPN {} "
2161                             + "with nexthop {}", destination, vpnId.getValue(), nextHop);
2162                     // Proceed to remove the next extra-route
2163                     continue;
2164                 }
2165                 LOG.trace("Removing extra route for destination {} on vpn {} with nexthop {} and infName {}",
2166                         destination, vpnId.getValue(), nextHop, infName);
2167
2168                 InstanceIdentifier<Adjacency> adjacencyIdentifier =
2169                         InstanceIdentifier.builder(VpnInterfaces.class)
2170                                 .child(VpnInterface.class, new VpnInterfaceKey(infName))
2171                                 .augmentation(Adjacencies.class)
2172                                 .child(Adjacency.class, new AdjacencyKey(destination))
2173                                 .build();
2174
2175                 try {
2176                     // Looking for existing prefix in MDSAL database
2177                     Optional<Adjacency> adjacency = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2178                             LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
2179                     boolean updateNextHops = false;
2180                     List<String> nextHopList = new ArrayList<>();
2181                     if (adjacency.isPresent()) {
2182                         List<String> nhListRead = adjacency.get().getNextHopIpList();
2183                         if (nhListRead.size() > 1) { // ECMP case
2184                             for (String nextHopRead : nhListRead) {
2185                                 if (nextHopRead.equals(nextHop)) {
2186                                     updateNextHops = true;
2187                                 } else {
2188                                     nextHopList.add(nextHopRead);
2189                                 }
2190                             }
2191                         }
2192                     }
2193
2194                     isLockAcquired = interfaceLock.tryLock(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
2195                     if (updateNextHops) {
2196                         // An update must be done, not including the current next hop
2197                         InstanceIdentifier<VpnInterface> vpnIfIdentifier = InstanceIdentifier.builder(
2198                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
2199                         Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
2200                                 .setNextHopIpList(nextHopList)
2201                                 .withKey(new AdjacencyKey(destination))
2202                                 .build();
2203                         Adjacencies erAdjs =
2204                                 new AdjacenciesBuilder().setAdjacency(Collections.singletonList(newAdj)).build();
2205                         VpnInterface vpnIf = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
2206                                 .addAugmentation(Adjacencies.class, erAdjs).build();
2207                         SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
2208                                 vpnIfIdentifier, vpnIf);
2209                     } else {
2210                         // Remove the whole route
2211                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
2212                                 adjacencyIdentifier);
2213                         LOG.trace("extra route {} deleted successfully", route);
2214                     }
2215                 } catch (TransactionCommitFailedException | ReadFailedException e) {
2216                     LOG.error("exception in deleting extra route with destination {} for interface {}",
2217                             destination, infName, e);
2218                 } finally {
2219                     if (isLockAcquired) {
2220                         interfaceLock.unlock(infName);
2221                     }
2222                 }
2223             } else {
2224                 LOG.error("Incorrect input received for extra route: {}", route);
2225             }
2226         }
2227     }
2228
2229     public void removeVpn(Uuid vpnId) {
2230         // read VPNMaps
2231         VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2232         List<RouterIds> routerIdsList = vpnMap != null ? vpnMap.getRouterIds() : null;
2233         // dissociate router
2234         if (routerIdsList != null && !routerIdsList.isEmpty()) {
2235             for (RouterIds routerId : routerIdsList) {
2236                 dissociateRouterFromVpn(vpnId, routerId.getRouterId());
2237             }
2238             List<Uuid> rtrIdsList = routerIdsList.stream().map(routerId -> routerId.getRouterId())
2239                     .collect(Collectors.toList());
2240             if (rtrIdsList.contains(vpnId) && vpnMap.getNetworkIds() != null) {
2241                 // dissociate networks
2242                 dissociateNetworksFromVpn(vpnId, vpnMap.getNetworkIds());
2243             }
2244         }
2245         // remove entire vpnMaps node
2246         deleteVpnMapsNode(vpnId);
2247
2248         // remove vpn-instance
2249         deleteVpnInstance(vpnId);
2250         LOG.debug("Deleted L3VPN with ID {}", vpnId.getValue());
2251     }
2252
2253     private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
2254         return vpnInstance != null && vpnInstance.getType() == VpnInstance.Type.L2;
2255     }
2256
2257     // TODO Clean up the exception handling
2258     @SuppressWarnings("checkstyle:IllegalCatch")
2259     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
2260         updateVpnMaps(vpnId, null, routerId, null, null);
2261         LOG.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
2262         List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
2263         for (Uuid subnetId : routerSubnets) {
2264             Subnetmap sn = updateVpnForSubnet(routerId, vpnId, subnetId, true);
2265             if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(sn, vpnId)) {
2266                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
2267                           NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()), true);
2268             }
2269         }
2270
2271         try {
2272             checkAndPublishRouterAssociatedtoVpnNotification(routerId, vpnId);
2273             LOG.debug("notification upon association of router {} to VPN {} published", routerId.getValue(),
2274                     vpnId.getValue());
2275         } catch (Exception e) {
2276             LOG.error("publishing of notification upon association of router {} to VPN {} failed : ", routerId
2277                     .getValue(), vpnId.getValue(), e);
2278         }
2279     }
2280
2281     protected void associateRouterToInternalVpn(Uuid vpnId, Uuid routerId) {
2282         List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
2283         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
2284         LOG.debug("Adding subnets to internal vpn {}", vpnId.getValue());
2285         for (Uuid subnet : routerSubnets) {
2286             IpVersionChoice version = NeutronvpnUtils
2287                    .getIpVersionFromSubnet(neutronvpnUtils.getSubnetmap(subnet));
2288             if (version.isIpVersionChosen(IpVersionChoice.IPV4)) {
2289                 addSubnetToVpn(vpnId, subnet, null);
2290             } else {
2291                 addSubnetToVpn(vpnId, subnet, internetVpnId);
2292             }
2293         }
2294     }
2295
2296     // TODO Clean up the exception handling
2297     @SuppressWarnings("checkstyle:IllegalCatch")
2298     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
2299
2300         List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
2301         boolean vpnInstanceIpVersionsRemoved = false;
2302         IpVersionChoice vpnInstanceIpVersionsToRemove = IpVersionChoice.UNDEFINED;
2303         for (Uuid subnetId : routerSubnets) {
2304             Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
2305             if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, vpnId)) {
2306                 vpnInstanceIpVersionsToRemove = vpnInstanceIpVersionsToRemove.addVersion(NeutronvpnUtils
2307                         .getIpVersionFromString(sn.getSubnetIp()));
2308                 vpnInstanceIpVersionsRemoved = true;
2309             }
2310             LOG.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
2311             updateVpnForSubnet(vpnId, routerId, subnetId, false);
2312         }
2313
2314         if (vpnInstanceIpVersionsRemoved) {
2315             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), vpnInstanceIpVersionsToRemove, false);
2316         }
2317         clearFromVpnMaps(vpnId, routerId, null);
2318         try {
2319             checkAndPublishRouterDisassociatedFromVpnNotification(routerId, vpnId);
2320             LOG.debug("notification upon disassociation of router {} from VPN {} published", routerId.getValue(),
2321                     vpnId.getValue());
2322         } catch (Exception e) {
2323             LOG.error("publishing of notification upon disassociation of router {} from VPN {} failed : ", routerId
2324                     .getValue(), vpnId.getValue(), e);
2325         }
2326     }
2327
2328     /**
2329      * Parses and associates networks list with given VPN.
2330      *
2331      * @param vpnId Uuid of given VPN.
2332      * @param networkList List list of network Ids (Uuid), which will be associated.
2333      * @return list of formatted strings with detailed error messages.
2334      */
2335     @Nonnull
2336     protected List<String> associateNetworksToVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
2337         List<String> failedNwList = new ArrayList<>();
2338         HashSet<Uuid> passedNwList = new HashSet<>();
2339         if (networkList.isEmpty()) {
2340             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
2341             failedNwList.add(String.format("Failed to associate networks with VPN %s as given networks list is empty",
2342                     vpnId.getValue()));
2343             return failedNwList;
2344         }
2345         VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
2346         if (vpnInstance == null) {
2347             LOG.error("associateNetworksToVpn: Can not find vpnInstance for VPN {} in ConfigDS", vpnId.getValue());
2348             failedNwList.add(String.format("Failed to associate network: can not found vpnInstance for VPN %s "
2349                                            + "in ConfigDS", vpnId.getValue()));
2350             return failedNwList;
2351         }
2352         try {
2353             if (isVpnOfTypeL2(vpnInstance) && neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance)) {
2354                 LOG.error("associateNetworksToVpn: EVPN {} supports only one network to be associated with",
2355                           vpnId.getValue());
2356                 failedNwList.add(String.format("Failed to associate network: EVPN %s supports only one network to be "
2357                                                + "associated with", vpnId.getValue()));
2358                 return failedNwList;
2359             }
2360             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2361             for (Uuid nw : networkList) {
2362                 Network network = neutronvpnUtils.getNeutronNetwork(nw);
2363                 if (network == null) {
2364                     LOG.error("associateNetworksToVpn: Network {} not found in ConfigDS", nw.getValue());
2365                     failedNwList.add(String.format("Failed to associate network: network %s not found in ConfigDS",
2366                                                    nw.getValue()));
2367                     continue;
2368                 }
2369                 NetworkProviderExtension providerExtension = network.augmentation(NetworkProviderExtension.class);
2370                 if (providerExtension.getSegments() != null && providerExtension.getSegments().size() > 1) {
2371                     LOG.error("associateNetworksToVpn: MultiSegmented network {} not supported in BGPVPN {}",
2372                               nw.getValue(), vpnId.getValue());
2373                     failedNwList.add(String.format("Failed to associate multisegmented network %s with BGPVPN %s",
2374                                                    nw.getValue(), vpnId.getValue()));
2375                     continue;
2376                 }
2377                 Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2378                 if (networkVpnId != null) {
2379                     LOG.error("associateNetworksToVpn: Network {} already associated with another VPN {}",
2380                               nw.getValue(), networkVpnId.getValue());
2381                     failedNwList.add(String.format("Failed to associate network %s as it is already associated to "
2382                                                    + "another VPN %s", nw.getValue(), networkVpnId.getValue()));
2383                     continue;
2384                 }
2385                 if (neutronvpnUtils.getIsExternal(network) && !associateExtNetworkToVpn(vpnId, network)) {
2386                     LOG.error("associateNetworksToVpn: Failed to associate Provider Network {} with VPN {}",
2387                             nw.getValue(), vpnId.getValue());
2388                     failedNwList.add(String.format("Failed to associate Provider Network %s with VPN %s",
2389                             nw.getValue(), vpnId.getValue()));
2390                     continue;
2391                 }
2392                 List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
2393                 if (subnetmapList == null || subnetmapList.isEmpty()) {
2394                     passedNwList.add(nw);
2395                     continue;
2396                 }
2397                 if (vpnManager.checkForOverlappingSubnets(nw, subnetmapList, vpnId, routeTargets, failedNwList)) {
2398                     continue;
2399                 }
2400                 for (Subnetmap subnetmap : subnetmapList) {
2401                     Uuid subnetId = subnetmap.getId();
2402                     Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
2403                     if (subnetVpnId != null) {
2404                         LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {}"
2405                                 + " as it is already associated", subnetId.getValue(), subnetVpnId.getValue());
2406                         failedNwList.add(String.format("Failed to associate subnet %s with VPN %s"
2407                                 + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
2408                         continue;
2409                     }
2410                     if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(subnetmap, vpnId)) {
2411                         neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
2412                                 NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp()), true);
2413                     }
2414                     if (!neutronvpnUtils.getIsExternal(network)) {
2415                         LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
2416                                 vpnId.getValue());
2417                         addSubnetToVpn(vpnId, subnetId, null);
2418                         vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2419                                 vpnId.getValue());
2420                         passedNwList.add(nw);
2421                     }
2422                 }
2423                 passedNwList.add(nw);
2424             }
2425         } catch (ReadFailedException e) {
2426             LOG.error("associateNetworksToVpn: Failed to associate VPN {} with networks {}: ", vpnId.getValue(),
2427                     networkList, e);
2428             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
2429                     networkList, e));
2430         }
2431         updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
2432         LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList.toString(), vpnId.getValue());
2433         return failedNwList;
2434     }
2435
2436     private boolean associateExtNetworkToVpn(@Nonnull Uuid vpnId, @Nonnull Network extNet) {
2437         VpnInstanceOpDataEntry vpnOpDataEntry = neutronvpnUtils.getVpnInstanceOpDataEntryFromVpnId(vpnId.getValue());
2438         if (vpnOpDataEntry == null) {
2439             LOG.error("associateExtNetworkToVpn: can not find VpnOpDataEntry for VPN {}", vpnId.getValue());
2440             return false;
2441         }
2442         if (!addExternalNetworkToVpn(extNet, vpnId)) {
2443             return false;
2444         }
2445         if (!vpnOpDataEntry.getBgpvpnType().equals(BgpvpnType.BGPVPNInternet)) {
2446             LOG.info("associateExtNetworkToVpn: set type {} for VPN {}", BgpvpnType.BGPVPNInternet, vpnId.getValue());
2447             neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, vpnId);
2448         }
2449         for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet)) {
2450             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2451             if (sm == null) {
2452                 LOG.error("associateExtNetworkToVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2453                 continue;
2454             }
2455             updateVpnInternetForSubnet(sm, vpnId, true);
2456             if (!vpnOpDataEntry.isIpv6Configured()
2457                     && NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp()) == IpVersionChoice.IPV6) {
2458                 LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
2459                 neutronvpnUtils.updateVpnInstanceWithFallback(vpnId.getValue(), true);
2460             }
2461         }
2462         return true;
2463     }
2464
2465     /**
2466      * Parses and disassociates networks list from given VPN.
2467      *
2468      * @param vpnId Uuid of given VPN.
2469      * @param networkList List list of network Ids (Uuid), which will be disassociated.
2470      * @return list of formatted strings with detailed error messages.
2471      */
2472     @Nonnull
2473     protected List<String> dissociateNetworksFromVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
2474         List<String> failedNwList = new ArrayList<>();
2475         HashSet<Uuid> passedNwList = new HashSet<>();
2476         if (networkList.isEmpty()) {
2477             LOG.error("dissociateNetworksFromVpn: Failed as networks list is empty");
2478             failedNwList.add(String.format("Failed to disassociate networks from VPN %s as networks list is empty",
2479                              vpnId.getValue()));
2480             return failedNwList;
2481         }
2482         for (Uuid nw : networkList) {
2483             List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
2484             if (networkSubnets == null) {
2485                 passedNwList.add(nw);
2486                 continue;
2487             }
2488             Network network = neutronvpnUtils.getNeutronNetwork(nw);
2489             if (network == null) {
2490                 LOG.error("dissociateNetworksFromVpn: Network {} not found in ConfigDS");
2491                 failedNwList.add(String.format("Failed to disassociate network %s as is not found in ConfigDS",
2492                         nw.getValue()));
2493                 continue;
2494             }
2495             Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
2496             if (networkVpnId == null) {
2497                 LOG.error("dissociateNetworksFromVpn: Network {} is not associated to any VPN", nw.getValue());
2498                 failedNwList.add(String.format("Failed to disassociate network %s as is not associated to any VPN",
2499                                                nw.getValue()));
2500                 continue;
2501             }
2502             if (!vpnId.equals(networkVpnId)) {
2503                 LOG.error("dissociateNetworksFromVpn: Network {} is associated to another VPN {} instead of given {}",
2504                           nw.getValue(), networkVpnId.getValue(), vpnId.getValue());
2505                 failedNwList.add(String.format("Failed to disassociate network %s as it is associated to another "
2506                                 + "vpn %s instead of given %s", nw.getValue(), networkVpnId.getValue(),
2507                                 vpnId.getValue()));
2508                 continue;
2509             }
2510             if (NeutronvpnUtils.getIsExternal(network)) {
2511                 if (disassociateExtNetworkFromVpn(vpnId, network)) {
2512                     passedNwList.add(nw);
2513                     continue;
2514                 } else {
2515                     LOG.error("dissociateNetworksFromVpn: Failed to withdraw Provider Network {} from VPN {}",
2516                               nw.getValue(), vpnId.getValue());
2517                     failedNwList.add(String.format("Failed to withdraw Provider Network %s from VPN %s", nw.getValue(),
2518                                                    vpnId.getValue()));
2519                     continue;
2520                 }
2521             }
2522             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
2523             for (Uuid subnet : networkSubnets) {
2524                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
2525                 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(subnetmap, vpnId)) {
2526                     IpVersionChoice ipVersionsToRemove = IpVersionChoice.UNDEFINED;
2527                     IpVersionChoice ipVersion = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
2528                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
2529                         ipVersionsToRemove.addVersion(ipVersion), false);
2530                 }
2531                 LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
2532                           vpnId.getValue());
2533                 removeSubnetFromVpn(vpnId, subnet, null);
2534                 vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
2535                         vpnId.getValue());
2536                 passedNwList.add(nw);
2537             }
2538         }
2539         clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
2540         LOG.info("Network(s) {} disassociated from L3VPN {} successfully", passedNwList.toString(),
2541                 vpnId.getValue());
2542         return failedNwList;
2543     }
2544
2545     private boolean disassociateExtNetworkFromVpn(@Nonnull Uuid vpnId, @Nonnull Network extNet) {
2546         if (!removeExternalNetworkFromVpn(extNet)) {
2547             return false;
2548         }
2549         // check, if there is another Provider Networks associated with given VPN
2550         List<Uuid> vpnNets = getNetworksForVpn(vpnId);
2551         if (vpnNets != null) {
2552             for (Uuid netId : vpnNets) {
2553                 if (NeutronvpnUtils.getIsExternal(getNeutronNetwork(netId))) {
2554                     LOG.error("dissociateExtNetworkFromVpn: Internet VPN {} is still associated with Provider Network "
2555                             + "{}", vpnId.getValue(), netId.getValue());
2556                     return true;
2557                 }
2558             }
2559         }
2560         LOG.info("disassociateExtNetworkFromVpn: set type {} for VPN {}",
2561                 VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, vpnId.getValue());
2562         neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, vpnId);
2563         for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet)) {
2564             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
2565             if (sm == null) {
2566                 LOG.error("disassociateExtNetworkFromVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
2567                 continue;
2568             }
2569             updateVpnInternetForSubnet(sm, vpnId, false);
2570         }
2571         neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
2572         LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}", vpnId.getValue());
2573         neutronvpnUtils.updateVpnInstanceWithFallback(vpnId.getValue(), false);
2574         return true;
2575     }
2576
2577     /**
2578      * It handles the invocations to the neutronvpn:associateNetworks RPC method.
2579      */
2580     @Override
2581     // TODO Clean up the exception handling
2582     @SuppressWarnings("checkstyle:IllegalCatch")
2583     public ListenableFuture<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
2584
2585         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
2586         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
2587         StringBuilder returnMsg = new StringBuilder();
2588         Uuid vpnId = input.getVpnId();
2589
2590         try {
2591             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2592                 LOG.debug("associateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2593                         input.getNetworkId().toString());
2594                 List<Uuid> netIds = input.getNetworkId();
2595                 if (netIds != null && !netIds.isEmpty()) {
2596                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
2597                     if (!failed.isEmpty()) {
2598                         returnMsg.append(failed);
2599                     }
2600                 }
2601             } else {
2602                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2603             }
2604             if (returnMsg.length() != 0) {
2605                 opBuilder.setResponse(
2606                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2607                                 "associate Networks to vpn {} failed due to {}", vpnId.getValue(), returnMsg));
2608                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().withResult(opBuilder.build()).build());
2609             } else {
2610                 result.set(RpcResultBuilder.<AssociateNetworksOutput>success().build());
2611             }
2612         } catch (Exception ex) {
2613             result.set(RpcResultBuilder.<AssociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2614                     formatAndLog(LOG::error, "associate Networks to vpn {} failed due to {}",
2615                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2616         }
2617         LOG.debug("associateNetworks returns..");
2618         return result;
2619     }
2620
2621     /**
2622      * It handles the invocations to the neutronvpn:associateRouter RPC method.
2623      */
2624     @Override
2625     public ListenableFuture<RpcResult<AssociateRouterOutput>> associateRouter(AssociateRouterInput input) {
2626
2627         SettableFuture<RpcResult<AssociateRouterOutput>> result = SettableFuture.create();
2628         LOG.debug("associateRouter {}", input);
2629         StringBuilder returnMsg = new StringBuilder();
2630         Uuid vpnId = input.getVpnId();
2631         List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input.RouterIds>
2632                 routerIds = input.getRouterIds();
2633         Preconditions.checkArgument(!routerIds.isEmpty(), "associateRouter: RouterIds list is empty!");
2634         Preconditions.checkNotNull(vpnId, "associateRouter; VpnId not found!");
2635         Preconditions.checkNotNull(vpnId, "associateRouter; RouterIds not found!");
2636         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input
2637                 .RouterIds routerId : routerIds) {
2638             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
2639             Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2640             if (vpnMap != null) {
2641                 if (rtr != null) {
2642                     Uuid extVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2643                     if (vpnMap.getRouterIds() != null && vpnMap.getRouterIds().size() > 1) {
2644                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
2645                                 .append(routerId.getRouterId());
2646                     } else if (extVpnId != null) {
2647                         returnMsg.append("router ").append(routerId.getRouterId()).append(" already associated to "
2648                                 + "another VPN ").append(extVpnId.getValue());
2649                     } else {
2650                         LOG.debug("associateRouter RPC: VpnId {}, routerId {}", vpnId.getValue(),
2651                                 routerId.getRouterId());
2652                         associateRouterToVpn(vpnId, routerId.getRouterId());
2653                     }
2654                 } else {
2655                     returnMsg.append("router not found : ").append(routerId.getRouterId());
2656                 }
2657             } else {
2658                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2659             }
2660             if (returnMsg.length() != 0) {
2661                 result.set(RpcResultBuilder.<AssociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
2662                         "invalid-value", formatAndLog(LOG::error, "associate router to vpn {} failed "
2663                                 + "due to {}", routerId.getRouterId(), returnMsg)).build());
2664             } else {
2665                 result.set(RpcResultBuilder.success(new AssociateRouterOutputBuilder().build()).build());
2666             }
2667         }
2668         LOG.debug("associateRouter returns..");
2669         return result;
2670     }
2671
2672     /**
2673      * It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
2674      */
2675     @Override
2676     // TODO Clean up the exception handling
2677     @SuppressWarnings("checkstyle:IllegalCatch")
2678     public ListenableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
2679         GetFixedIPsForNeutronPortInput input) {
2680         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
2681         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
2682         Uuid portId = input.getPortId();
2683         StringBuilder returnMsg = new StringBuilder();
2684         try {
2685             List<String> fixedIPList = new ArrayList<>();
2686             Port port = neutronvpnUtils.getNeutronPort(portId);
2687             if (port != null) {
2688                 List<FixedIps> fixedIPs = port.getFixedIps();
2689                 for (FixedIps ip : fixedIPs) {
2690                     fixedIPList.add(String.valueOf(ip.getIpAddress().getValue()));
2691                 }
2692             } else {
2693                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
2694             }
2695             if (returnMsg.length() != 0) {
2696                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withWarning(ErrorType.PROTOCOL,
2697                         "invalid-value",
2698                         formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port failed due to {}",
2699                                 returnMsg)).build());
2700             } else {
2701                 opBuilder.setFixedIPs(fixedIPList);
2702                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().withResult(opBuilder.build())
2703                         .build());
2704                 result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>success().build());
2705             }
2706         } catch (Exception ex) {
2707             result.set(RpcResultBuilder.<GetFixedIPsForNeutronPortOutput>failed().withError(ErrorType.APPLICATION,
2708                     formatAndLog(LOG::error, "Retrieval of FixedIPList for neutron port {} failed due to {}",
2709                             portId.getValue(), ex.getMessage(), ex)).build());
2710         }
2711         return result;
2712     }
2713
2714     /**
2715      * It handles the invocations to the neutronvpn:dissociateNetworks RPC method.
2716      */
2717     @Override
2718     // TODO Clean up the exception handling
2719     @SuppressWarnings("checkstyle:IllegalCatch")
2720     public ListenableFuture<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
2721
2722         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
2723         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
2724
2725         LOG.debug("dissociateNetworks {}", input);
2726         StringBuilder returnMsg = new StringBuilder();
2727         Uuid vpnId = input.getVpnId();
2728
2729         try {
2730             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2731                 LOG.debug("dissociateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
2732                         input.getNetworkId().toString());
2733                 List<Uuid> netIds = input.getNetworkId();
2734                 if (netIds != null && !netIds.isEmpty()) {
2735                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
2736                     if (!failed.isEmpty()) {
2737                         returnMsg.append(failed);
2738                     }
2739                 }
2740             } else {
2741                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
2742             }
2743             if (returnMsg.length() != 0) {
2744                 opBuilder.setResponse(
2745                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
2746                                 "dissociate Networks to vpn {} failed due to {}", vpnId.getValue(),
2747                                 returnMsg));
2748                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
2749             } else {
2750                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
2751             }
2752         } catch (Exception ex) {
2753             result.set(RpcResultBuilder.<DissociateNetworksOutput>failed().withError(ErrorType.APPLICATION,
2754                     formatAndLog(LOG::error, "dissociate Networks to vpn {} failed due to {}",
2755                             input.getVpnId().getValue(), ex.getMessage(), ex)).build());
2756         }
2757         LOG.debug("dissociateNetworks returns..");
2758         return result;
2759     }
2760
2761     /**
2762      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
2763      */
2764     @Override
2765     // TODO Clean up the exception handling
2766     @SuppressWarnings("checkstyle:IllegalCatch")
2767     public ListenableFuture<RpcResult<DissociateRouterOutput>> dissociateRouter(DissociateRouterInput input) {
2768
2769         SettableFuture<RpcResult<DissociateRouterOutput>> result = SettableFuture.create();
2770
2771         LOG.debug("dissociateRouter {}", input);
2772         StringBuilder returnMsg = new StringBuilder();
2773         Uuid vpnId = input.getVpnId();
2774         List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2775                 .RouterIds> routerIdList = input.getRouterIds();
2776         String routerIdsString = "";
2777         Preconditions.checkArgument(!routerIdList.isEmpty(), "dissociateRouter: RouterIds list is empty!");
2778         Preconditions.checkNotNull(vpnId, "dissociateRouter: vpnId not found!");
2779         Preconditions.checkNotNull(routerIdList, "dissociateRouter: routerIdList not found!");
2780         if (neutronvpnUtils.getVpnMap(vpnId) != null) {
2781             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
2782                     .RouterIds routerId : routerIdList) {
2783                 try {
2784                     if (routerId != null) {
2785                         routerIdsString += routerId.getRouterId() + ", ";
2786                         Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
2787                         if (rtr != null) {
2788                             Uuid routerVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
2789                             if (routerVpnId == null) {
2790                                 returnMsg.append("input router ").append(routerId.getRouterId())
2791                                         .append(" not associated to any vpn yet");
2792                             } else if (vpnId.equals(routerVpnId)) {
2793                                 dissociateRouterFromVpn(vpnId, routerId.getRouterId());
2794                             } else {
2795                                 returnMsg.append("input router ").append(routerId.getRouterId())
2796                                         .append(" associated to vpn ")
2797                                         .append(routerVpnId.getValue()).append("instead of the vpn given as input");
2798                             }
2799                         } else {
2800                             returnMsg.append("router not found : ").append(routerId.getRouterId());
2801                         }
2802                     }
2803                     if (returnMsg.length() != 0) {
2804                         result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
2805                                 "invalid-value", formatAndLog(LOG::error, "dissociate router {} to "
2806                                                 + "vpn {} failed due to {}", routerId.getRouterId(), vpnId.getValue(),
2807                                         returnMsg)).build());
2808                     } else {
2809                         result.set(RpcResultBuilder.success(new DissociateRouterOutputBuilder().build()).build());
2810                     }
2811                 } catch (Exception ex) {
2812                     result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withError(ErrorType.APPLICATION,
2813                             formatAndLog(LOG::error, "disssociate router {} to vpn {} failed due to {}",
2814                                     routerId.getRouterId(), vpnId.getValue(), ex.getMessage(), ex)).build());
2815                 }
2816             }
2817         } else {
2818             returnMsg.append("VPN not found : ").append(vpnId.getValue());
2819         }
2820
2821         LOG.debug("dissociateRouter returns..");
2822         return result;
2823     }
2824
2825     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
2826         // check if the router is associated to some VPN
2827         Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
2828         Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
2829         if (vpnId != null) {
2830             // remove existing external vpn interfaces
2831             for (Uuid subnetId : routerSubnetIds) {
2832                 removeSubnetFromVpn(vpnId, subnetId, internetVpnId);
2833             }
2834             clearFromVpnMaps(vpnId, routerId, null);
2835         } else {
2836             // remove existing internal vpn interfaces
2837             for (Uuid subnetId : routerSubnetIds) {
2838                 removeSubnetFromVpn(routerId, subnetId, internetVpnId);
2839             }
2840         }
2841         // delete entire vpnMaps node for internal VPN
2842         deleteVpnMapsNode(routerId);
2843
2844         // delete vpn-instance for internal VPN
2845         deleteVpnInstance(routerId);
2846     }
2847
2848     protected Subnet getNeutronSubnet(Uuid subnetId) {
2849         return neutronvpnUtils.getNeutronSubnet(subnetId);
2850     }
2851
2852     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
2853         Subnet sn = neutronvpnUtils.getNeutronSubnet(subnetId);
2854         if (null != sn) {
2855             return sn.getGatewayIp();
2856         }
2857         return null;
2858     }
2859
2860
2861     protected Network getNeutronNetwork(Uuid networkId) {
2862         return neutronvpnUtils.getNeutronNetwork(networkId);
2863     }
2864
2865     protected Port getNeutronPort(String name) {
2866         return neutronvpnUtils.getNeutronPort(new Uuid(name));
2867     }
2868
2869     protected Port getNeutronPort(Uuid portId) {
2870         return neutronvpnUtils.getNeutronPort(portId);
2871     }
2872
2873     protected Uuid getNetworkForSubnet(Uuid subnetId) {
2874         return neutronvpnUtils.getNetworkForSubnet(subnetId);
2875     }
2876
2877     protected List<Uuid> getNetworksForVpn(Uuid vpnId) {
2878         return neutronvpnUtils.getNetworksForVpn(vpnId);
2879     }
2880
2881     /**
2882      * Implementation of the "vpnservice:neutron-ports-show" Karaf CLI command.
2883      *
2884      * @return a List of String to be printed on screen
2885      * @throws ReadFailedException if there was a problem reading from the data store
2886      */
2887     public List<String> showNeutronPortsCLI() throws ReadFailedException {
2888         List<String> result = new ArrayList<>();
2889         result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", "Port ID", "Mac Address", "Prefix Length",
2890             "IP Address"));
2891         result.add("-------------------------------------------------------------------------------------------");
2892         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
2893
2894         Optional<Ports> ports = syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
2895         if (ports.isPresent() && ports.get().getPort() != null) {
2896             for (Port port : ports.get().getPort()) {
2897                 List<FixedIps> fixedIPs = port.getFixedIps();
2898                 if (fixedIPs != null && !fixedIPs.isEmpty()) {
2899                     List<String> ipList = new ArrayList<>();
2900                     for (FixedIps fixedIp : fixedIPs) {
2901                         IpAddress ipAddress = fixedIp.getIpAddress();
2902                         if (ipAddress.getIpv4Address() != null) {
2903                             ipList.add(ipAddress.getIpv4Address().getValue());
2904                         } else {
2905                             ipList.add(ipAddress.getIpv6Address().getValue());
2906                         }
2907                     }
2908                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
2909                             .getMacAddress().getValue(), neutronvpnUtils.getIPPrefixFromPort(port),
2910                             ipList.toString()));
2911                 } else {
2912                     result.add(String.format(" %-36s  %-19s  %-13s  %-20s ", port.getUuid().getValue(), port
2913                             .getMacAddress().getValue(), "Not Assigned", "Not Assigned"));
2914                 }
2915             }
2916         }
2917
2918         return result;
2919     }
2920
2921     /**
2922      * Implementation of the "vpnservice:l3vpn-config-show" karaf CLI command.
2923      *
2924      * @param vpnuuid Uuid of the VPN whose config must be shown
2925      * @return formatted output list
2926      * @throws InterruptedException if there was a thread related problem getting the data to display
2927      * @throws ExecutionException if there was any other problem getting the data to display
2928      */
2929     public List<String> showVpnConfigCLI(Uuid vpnuuid) throws InterruptedException, ExecutionException {
2930         List<String> result = new ArrayList<>();
2931         if (vpnuuid == null) {
2932             result.add("");
2933             result.add("Displaying VPN config for all VPNs");
2934             result.add("To display VPN config for a particular VPN, use the following syntax");
2935             result.add(getshowVpnConfigCLIHelp());
2936         }
2937         RpcResult<GetL3VPNOutput> rpcResult = getL3VPN(new GetL3VPNInputBuilder().setId(vpnuuid).build()).get();
2938         if (rpcResult.isSuccessful()) {
2939             result.add("");
2940             result.add(String.format(" %-37s %-37s %-7s ", "VPN ID", "Tenant ID", "RD"));
2941             result.add("");
2942             result.add(String.format(" %-80s ", "Import-RTs"));
2943             result.add("");
2944             result.add(String.format(" %-80s ", "Export-RTs"));
2945             result.add("");
2946             result.add(String.format(" %-76s ", "Subnet IDs"));
2947             result.add("");
2948             result.add("------------------------------------------------------------------------------------");
2949             result.add("");
2950             List<L3vpnInstances> vpnList = rpcResult.getResult().getL3vpnInstances();
2951             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
2952                     .rev150602.VpnInstance vpn : vpnList) {
2953                 String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
2954                         : "\"                 " + "                  \"";
2955                 result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
2956                         vpn.getRouteDistinguisher()));
2957                 result.add("");
2958                 result.add(String.format(" %-80s ", vpn.getImportRT()));
2959                 result.add("");
2960                 result.add(String.format(" %-80s ", vpn.getExportRT()));
2961                 result.add("");
2962
2963                 Uuid vpnid = vpn.getId();
2964                 List<Uuid> subnetList = neutronvpnUtils.getSubnetsforVpn(vpnid);
2965                 if (!subnetList.isEmpty()) {
2966                     for (Uuid subnetuuid : subnetList) {
2967                         result.add(String.format(" %-76s ", subnetuuid.getValue()));
2968                     }
2969                 } else {
2970                     result.add(String.format(" %-76s ", "\"                                    \""));
2971                 }
2972                 result.add("");
2973                 result.add("----------------------------------------");
2974                 result.add("");
2975             }
2976         } else {
2977             String errortag = rpcResult.getErrors().iterator().next().getTag();
2978             if (Objects.equals(errortag, "")) {
2979                 result.add("");
2980                 result.add("No VPN has been configured yet");
2981             } else if (Objects.equals(errortag, "invalid-value")) {
2982                 result.add("");
2983                 result.add("VPN " + vpnuuid.getValue() + " is not present");
2984             } else {
2985                 result.add("error getting VPN info : " + rpcResult.getErrors());
2986                 result.add(getshowVpnConfigCLIHelp());
2987             }
2988         }
2989         return result;
2990     }
2991
2992     protected void createExternalVpnInterfaces(Uuid extNetId) {
2993         if (extNetId == null) {
2994             LOG.error("createExternalVpnInterfaces: external network is null");
2995             return;
2996         }
2997
2998         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
2999         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3000             LOG.error("No external ports attached to external network {}", extNetId.getValue());
3001             return;
3002         }
3003
3004         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3005             for (String elanInterface : extElanInterfaces) {
3006                 createExternalVpnInterface(extNetId, elanInterface, tx);
3007             }
3008         }), LOG, "Error creating external VPN interfaces for {}", extNetId);
3009     }
3010
3011     // TODO Clean up the exception handling
3012     @SuppressWarnings("checkstyle:IllegalCatch")
3013     protected void removeExternalVpnInterfaces(Uuid extNetId) {
3014         Collection<String> extElanInterfaces = elanService.getExternalElanInterfaces(extNetId.getValue());
3015         if (extElanInterfaces == null || extElanInterfaces.isEmpty()) {
3016             LOG.error("No external ports attached for external network {}", extNetId.getValue());
3017             return;
3018         }
3019         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3020             for (String elanInterface : extElanInterfaces) {
3021                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
3022                         .buildVpnInterfaceIdentifier(elanInterface);
3023                 LOG.info("Removing vpn interface {}", elanInterface);
3024                 tx.delete(vpnIfIdentifier);
3025             }
3026         }), LOG, "Error removing external VPN interfaces for {}", extNetId);
3027     }
3028
3029     private void createExternalVpnInterface(Uuid vpnId, String infName,
3030                                             TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
3031         writeVpnInterfaceToDs(Collections.singletonList(vpnId), infName, null,
3032                 false /* not a router iface */, wrtConfigTxn);
3033     }
3034
3035     // TODO Clean up the exception handling
3036     @SuppressWarnings("checkstyle:IllegalCatch")
3037     private void writeVpnInterfaceToDs(@Nonnull Collection<Uuid> vpnIdList, String infName, Adjacencies adjacencies,
3038             Boolean isRouterInterface, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
3039         if (vpnIdList.isEmpty() || infName == null) {
3040             LOG.error("vpn id or interface is null");
3041             return;
3042         }
3043         if (wrtConfigTxn == null) {
3044             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
3045                 tx -> writeVpnInterfaceToDs(vpnIdList, infName, adjacencies, isRouterInterface, tx)), LOG,
3046                 "Error writing VPN interface");
3047             return;
3048         }
3049         List<VpnInstanceNames> vpnIdListStruct = new ArrayList<>();
3050         for (Uuid vpnId: vpnIdList) {
3051             VpnInstanceNames vpnInstance = VpnHelper.getVpnInterfaceVpnInstanceNames(vpnId.getValue(),
3052                                    AssociatedSubnetType.V4AndV6Subnets);
3053             vpnIdListStruct.add(vpnInstance);
3054         }
3055
3056         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3057         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
3058                 .setName(infName)
3059                 .setVpnInstanceNames(vpnIdListStruct)
3060                 .setRouterInterface(isRouterInterface);
3061         if (adjacencies != null) {
3062             vpnb.addAugmentation(Adjacencies.class, adjacencies);
3063         }
3064         VpnInterface vpnIf = vpnb.build();
3065         try {
3066             LOG.info("Creating vpn interface {}", vpnIf);
3067             wrtConfigTxn.put(vpnIfIdentifier, vpnIf);
3068         } catch (Exception ex) {
3069             LOG.error("Creation of vpninterface {} failed", infName, ex);
3070         }
3071     }
3072
3073     private void updateVpnInterfaceWithAdjacencies(Uuid vpnId, String infName, Adjacencies adjacencies,
3074                                                    TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
3075         if (vpnId == null || infName == null) {
3076             LOG.error("vpn id or interface is null");
3077             return;
3078         }
3079         if (wrtConfigTxn == null) {
3080             LOG.error("updateVpnInterfaceWithAdjancies called with wrtConfigTxn as null");
3081             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
3082                 updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, tx);
3083             }), LOG, "Error updating VPN interface with adjacencies");
3084             return;
3085         }
3086
3087         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
3088         boolean isLockAcquired = false;
3089         try {
3090             isLockAcquired = interfaceLock.tryLock(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
3091             Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker
3092                     .syncReadOptional(dataBroker, LogicalDatastoreType
3093                     .CONFIGURATION, vpnIfIdentifier);
3094             if (optionalVpnInterface.isPresent()) {
3095                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get());
3096                 LOG.debug("Updating vpn interface {} with new adjacencies", infName);
3097
3098                 if (adjacencies == null) {
3099                     if (isLockAcquired) {
3100                         interfaceLock.unlock(infName);
3101                     }
3102                     return;
3103                 }
3104                 vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
3105                 if (optionalVpnInterface.get().getVpnInstanceNames() != null) {
3106                     List<VpnInstanceNames> listVpnInstances = new ArrayList<>(
3107                         optionalVpnInterface.get().getVpnInstanceNames());
3108                     if (listVpnInstances.isEmpty() || !VpnHelper
3109                         .doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpnInstances)) {
3110                         VpnInstanceNames vpnInstance = VpnHelper
3111                              .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
3112                         listVpnInstances.add(vpnInstance);
3113                         vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3114                     }
3115                 } else {
3116                     VpnInstanceNames vpnInstance = VpnHelper
3117                          .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
3118                     List<VpnInstanceNames> listVpnInstances = new ArrayList<>();
3119                     listVpnInstances.add(vpnInstance);
3120                     vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
3121                 }
3122                 LOG.info("Updating vpn interface {} with new adjacencies", infName);
3123                 wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
3124             }
3125         } catch (IllegalStateException | ReadFailedException ex) {
3126             LOG.error("Update of vpninterface {} failed", infName, ex);
3127         } finally {
3128             if (isLockAcquired) {
3129                 interfaceLock.unlock(infName);
3130             }
3131         }
3132     }
3133
3134     private String getshowVpnConfigCLIHelp() {
3135         StringBuilder help = new StringBuilder("Usage:");
3136         help.append("display vpn-config [-vid/--vpnid <id>]");
3137         return help.toString();
3138     }
3139
3140     private void checkAndPublishRouterAssociatedtoVpnNotification(Uuid routerId, Uuid vpnId) throws
3141             InterruptedException {
3142         RouterAssociatedToVpn routerAssociatedToVpn = new RouterAssociatedToVpnBuilder().setRouterId(routerId)
3143                 .setVpnId(vpnId).build();
3144         LOG.info("publishing notification upon association of router to VPN");
3145         notificationPublishService.putNotification(routerAssociatedToVpn);
3146     }
3147
3148     private void checkAndPublishRouterDisassociatedFromVpnNotification(Uuid routerId, Uuid vpnId) throws
3149             InterruptedException {
3150         RouterDisassociatedFromVpn routerDisassociatedFromVpn =
3151             new RouterDisassociatedFromVpnBuilder().setRouterId(routerId).setVpnId(vpnId).build();
3152         LOG.info("publishing notification upon disassociation of router from VPN");
3153         notificationPublishService.putNotification(routerDisassociatedFromVpn);
3154     }
3155
3156     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
3157         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
3158     }
3159
3160     @Override
3161     public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
3162         return neutronEvpnManager.createEVPN(input);
3163     }
3164
3165     @Override
3166     public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
3167         return neutronEvpnManager.getEVPN(input);
3168     }
3169
3170     @Override
3171     public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
3172         return neutronEvpnManager.deleteEVPN(input);
3173     }
3174
3175     private boolean addExternalNetworkToVpn(Network extNet, Uuid vpnId) {
3176         Uuid extNetId = extNet.getUuid();
3177         InstanceIdentifier<Networks> extNetIdentifier = InstanceIdentifier.builder(ExternalNetworks.class)
3178                 .child(Networks.class, new NetworksKey(extNetId)).build();
3179
3180         try {
3181             Optional<Networks> optionalExtNets =
3182                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3183                                                                  extNetIdentifier);
3184             if (!optionalExtNets.isPresent()) {
3185                 LOG.error("addExternalNetworkToVpn: Provider Network {} is not present in ConfigDS",
3186                           extNetId.getValue());
3187                 return false;
3188             }
3189             NetworksBuilder builder = new NetworksBuilder(optionalExtNets.get());
3190             builder.setVpnid(vpnId);
3191             Networks networks = builder.build();
3192             // Add Networks object to the ExternalNetworks list
3193             LOG.trace("addExternalNetworkToVpn: Set VPN Id {} for Provider Network {}", vpnId.getValue(),
3194                       extNetId.getValue());
3195             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetIdentifier,
3196                                                   networks);
3197             return true;
3198         } catch (TransactionCommitFailedException | ReadFailedException ex) {
3199             LOG.error("addExternalNetworkToVpn: Failed to set VPN Id {} to Provider Network {}: ", vpnId.getValue(),
3200                       extNetId.getValue(), ex);
3201         }
3202         return false;
3203     }
3204
3205     private boolean removeExternalNetworkFromVpn(Network extNet) {
3206         Uuid extNetId = extNet.getUuid();
3207         InstanceIdentifier<Networks> extNetsId = InstanceIdentifier.builder(ExternalNetworks.class)
3208             .child(Networks.class, new NetworksKey(extNetId)).build();
3209         try {
3210             Optional<Networks> optionalNets =
3211                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
3212                             extNetsId);
3213             NetworksBuilder builder = null;
3214             if (optionalNets.isPresent()) {
3215                 builder = new NetworksBuilder(optionalNets.get());
3216             } else {
3217                 LOG.error("removeExternalNetworkFromVpn: Provider Network {} is not present in the ConfigDS",
3218                         extNetId.getValue());
3219                 return false;
3220             }
3221             builder.setVpnid(null);
3222             Networks networks = builder.build();
3223             LOG.info("removeExternalNetworkFromVpn: Withdraw VPN Id from Provider Network {} node",
3224                     extNetId.getValue());
3225             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, extNetsId, networks);
3226             return true;
3227         } catch (TransactionCommitFailedException | ReadFailedException ex) {
3228             LOG.error("removeExternalNetworkFromVpn: Failed to withdraw VPN Id from Provider Network node {}: ",
3229                     extNetId.getValue(), ex);
3230         }
3231         return false;
3232     }
3233
3234     private Optional<String> getExistingOperationalVpn(String primaryRd) {
3235         Optional<String> existingVpnName = Optional.of(primaryRd);
3236         Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataOptional;
3237         try {
3238             vpnInstanceOpDataOptional = SingleTransactionDataBroker
3239                 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
3240                     neutronvpnUtils.getVpnOpDataIdentifier(primaryRd));
3241         } catch (ReadFailedException e) {
3242             LOG.error("getExistingOperationalVpn: Exception while checking operational status of vpn with rd {}",
3243                     primaryRd, e);
3244             /*Read failed. We don't know if a VPN exists or not.
3245             * Return primaryRd to halt caller execution, to be safe.*/
3246             return existingVpnName;
3247         }
3248         if (vpnInstanceOpDataOptional.isPresent()) {
3249             existingVpnName = Optional.of(vpnInstanceOpDataOptional.get().getVpnInstanceName());
3250         } else {
3251             existingVpnName = Optional.absent();
3252         }
3253         return existingVpnName;
3254     }
3255
3256     private String formatAndLog(Consumer<String> logger, String template, Object arg) {
3257         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
3258     }
3259
3260     private String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
3261         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
3262     }
3263
3264     private String formatAndLog(Consumer<String> logger, String template, Object... args) {
3265         return logAndReturnMessage(logger, MessageFormatter.arrayFormat(template, args));
3266     }
3267
3268     private String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
3269         String message = tuple.getMessage();
3270         logger.accept(message);
3271         return message;
3272     }
3273 }