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