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