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