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