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