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