2 * Copyright (c) 2015 - 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Iterator;
16 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import javax.annotation.PostConstruct;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
30 import org.opendaylight.genius.infra.Datastore.Configuration;
31 import org.opendaylight.genius.infra.Datastore.Operational;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.genius.infra.TransactionAdapter;
35 import org.opendaylight.genius.infra.TypedReadTransaction;
36 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
37 import org.opendaylight.genius.infra.TypedWriteTransaction;
38 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
39 import org.opendaylight.genius.mdsalutil.FlowEntity;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.UpgradeState;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
46 import org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer;
47 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
48 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
49 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
50 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
51 import org.opendaylight.netvirt.elanmanager.api.IElanService;
52 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
53 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
54 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
55 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
56 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
57 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
58 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
59 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
60 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
61 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
62 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
63 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
64 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
65 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetsAssociatedToRouteTargets;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTarget;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTargetKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.AssociatedSubnet;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.associated.subnet.AssociatedVpn;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
86 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
87 import org.opendaylight.yangtools.yang.common.RpcError;
88 import org.opendaylight.yangtools.yang.common.RpcResult;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
93 public class VpnManagerImpl implements IVpnManager {
95 private static final Logger LOG = LoggerFactory.getLogger(VpnManagerImpl.class);
96 private final DataBroker dataBroker;
97 private final ManagedNewTransactionRunner txRunner;
98 private final IdManagerService idManager;
99 private final IMdsalApiManager mdsalManager;
100 private final IElanService elanService;
101 private final IInterfaceManager interfaceManager;
102 private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
103 private final OdlInterfaceRpcService ifaceMgrRpcService;
104 private final IVpnLinkService ivpnLinkService;
105 private final IFibManager fibManager;
106 private final IBgpManager bgpManager;
107 private final InterVpnLinkCache interVpnLinkCache;
108 private final DataTreeEventCallbackRegistrar eventCallbacks;
109 private final UpgradeState upgradeState;
110 private final ItmRpcService itmRpcService;
111 private final VpnUtil vpnUtil;
114 public VpnManagerImpl(final DataBroker dataBroker,
115 final IdManagerService idManagerService,
116 final IMdsalApiManager mdsalManager,
117 final IElanService elanService,
118 final IInterfaceManager interfaceManager,
119 final VpnSubnetRouteHandler vpnSubnetRouteHandler,
120 final OdlInterfaceRpcService ifaceMgrRpcService,
121 final IVpnLinkService ivpnLinkService,
122 final IFibManager fibManager,
123 final IBgpManager bgpManager,
124 final InterVpnLinkCache interVpnLinkCache,
125 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar,
126 final UpgradeState upgradeState,
127 final ItmRpcService itmRpcService,
128 final VpnUtil vpnUtil) {
129 this.dataBroker = dataBroker;
130 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
131 this.idManager = idManagerService;
132 this.mdsalManager = mdsalManager;
133 this.elanService = elanService;
134 this.interfaceManager = interfaceManager;
135 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
136 this.ifaceMgrRpcService = ifaceMgrRpcService;
137 this.ivpnLinkService = ivpnLinkService;
138 this.fibManager = fibManager;
139 this.bgpManager = bgpManager;
140 this.interVpnLinkCache = interVpnLinkCache;
141 this.eventCallbacks = dataTreeEventCallbackRegistrar;
142 this.upgradeState = upgradeState;
143 this.itmRpcService = itmRpcService;
144 this.vpnUtil = vpnUtil;
148 public void start() {
149 LOG.info("{} start", getClass().getSimpleName());
153 private void createIdPool() {
154 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
155 .setPoolName(VpnConstants.VPN_IDPOOL_NAME)
156 .setLow(VpnConstants.VPN_IDPOOL_LOW)
157 .setHigh(VpnConstants.VPN_IDPOOL_HIGH)
160 Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
161 if (result != null && result.get().isSuccessful()) {
162 LOG.info("Created IdPool for VPN Service");
164 } catch (InterruptedException | ExecutionException e) {
165 LOG.error("Failed to create idPool for VPN Service", e);
168 // Now an IdPool for InterVpnLink endpoint's pseudo ports
169 CreateIdPoolInput createPseudoLporTagPool =
170 new CreateIdPoolInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
171 .setLow(VpnConstants.LOWER_PSEUDO_LPORT_TAG)
172 .setHigh(VpnConstants.UPPER_PSEUDO_LPORT_TAG)
175 Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPseudoLporTagPool);
176 if (result.get().isSuccessful()) {
177 LOG.debug("Created IdPool for Pseudo Port tags");
179 Collection<RpcError> errors = result.get().getErrors();
180 StringBuilder errMsg = new StringBuilder();
181 for (RpcError err : errors) {
182 errMsg.append(err.getMessage()).append("\n");
184 LOG.error("IdPool creation for PseudoPort tags failed. Reasons: {}", errMsg);
186 } catch (InterruptedException | ExecutionException e) {
187 LOG.error("Failed to create idPool for Pseudo Port tags", e);
192 public void addExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
193 Long l3vni, RouteOrigin origin, String intfName, Adjacency operationalAdj, VrfEntry.EncapType encapType,
194 TypedWriteTransaction<Configuration> confTx) {
195 addExtraRoute(vpnName, destination, nextHop, rd, routerID, l3vni, origin, intfName, operationalAdj, encapType,
196 TransactionAdapter.toWriteTransaction(confTx));
200 public void addExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
201 Long l3vni, RouteOrigin origin, String intfName, Adjacency operationalAdj,
202 VrfEntry.EncapType encapType, WriteTransaction writeConfigTxn) {
203 if (writeConfigTxn == null) {
204 String finalNextHop = nextHop;
205 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
206 addExtraRoute(vpnName, destination, finalNextHop, rd, routerID, l3vni, origin, intfName, operationalAdj,
208 LOG, "Error adding extra route");
212 //add extra route to vpn mapping; advertise with nexthop as tunnel ip
213 vpnUtil.syncUpdate(LogicalDatastoreType.OPERATIONAL,
214 VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, rd != null ? rd : routerID,
216 VpnUtil.getVpnToExtraroute(destination, Collections.singletonList(nextHop)));
218 BigInteger dpnId = null;
219 if (intfName != null && !intfName.isEmpty()) {
220 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
221 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
222 if (nextHopIp == null || nextHopIp.isEmpty()) {
223 LOG.error("addExtraRoute: NextHop for interface {} is null / empty."
224 + " Failed advertising extra route for rd {} prefix {} dpn {}", intfName, rd, destination,
231 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
233 // TODO: This is a limitation to be stated in docs. When configuring static route to go to
234 // another VPN, there can only be one nexthop or, at least, the nexthop to the interVpnLink should be in
236 Optional<InterVpnLinkDataComposite> optVpnLink = interVpnLinkCache.getInterVpnLinkByEndpoint(nextHop);
237 if (optVpnLink.isPresent() && optVpnLink.get().isActive()) {
238 InterVpnLinkDataComposite interVpnLink = optVpnLink.get();
239 // If the nexthop is the endpoint of Vpn2, then prefix must be advertised to Vpn1 in DC-GW, with nexthops
240 // pointing to the DPNs where Vpn1 is instantiated. LFIB in these DPNS must have a flow entry, with lower
241 // priority, where if Label matches then sets the lportTag of the Vpn2 endpoint and goes to LportDispatcher
242 // This is like leaking one of the Vpn2 routes towards Vpn1
243 String srcVpnUuid = interVpnLink.getVpnNameByIpAddress(nextHop);
244 String dstVpnUuid = interVpnLink.getOtherVpnNameByIpAddress(nextHop);
245 String dstVpnRd = vpnUtil.getVpnRd(dstVpnUuid);
246 long newLabel = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
247 VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
249 LOG.error("addExtraRoute: Unable to fetch label from Id Manager. Bailing out of adding intervpnlink"
250 + " route for destination {}", destination);
253 ivpnLinkService.leakRoute(interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel, RouteOrigin.STATIC);
255 Optional<Routes> optVpnExtraRoutes = VpnExtraRouteHelper
256 .getVpnExtraroutes(dataBroker, vpnName, rd != null ? rd : routerID, destination);
257 if (optVpnExtraRoutes.isPresent()) {
258 List<String> nhList = optVpnExtraRoutes.get().getNexthopIpList();
259 if (nhList != null && nhList.size() > 1) {
260 // If nhList is greater than one for vpnextraroute, a call to populatefib doesn't update vrfentry.
261 fibManager.refreshVrfEntry(primaryRd, destination);
263 L3vpnInput input = new L3vpnInput().setNextHop(operationalAdj).setNextHopIp(nextHop).setL3vni(l3vni)
264 .setPrimaryRd(primaryRd).setVpnName(vpnName).setDpnId(dpnId)
265 .setEncapType(encapType).setRd(rd).setRouteOrigin(origin);
266 L3vpnRegistry.getRegisteredPopulator(encapType).populateFib(input, writeConfigTxn);
273 public void delExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
274 String intfName, TypedWriteTransaction<Configuration> confTx, TypedWriteTransaction<Operational> operTx) {
275 delExtraRoute(vpnName, destination, nextHop, rd, routerID, intfName,
276 TransactionAdapter.toWriteTransaction(confTx), TransactionAdapter.toWriteTransaction(operTx));
280 public void delExtraRoute(String vpnName, String destination, String nextHop, String rd, String routerID,
281 String intfName, WriteTransaction writeConfigTxn, WriteTransaction writeOperTx) {
282 if (writeConfigTxn == null) {
283 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
284 delExtraRoute(vpnName, destination, nextHop, rd, routerID, intfName, tx, writeOperTx);
285 }), LOG, "Error deleting extra route");
288 if (writeOperTx == null) {
289 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
290 delExtraRoute(vpnName, destination, nextHop, rd, routerID, intfName, writeConfigTxn, tx);
291 }), LOG, "Error deleting extra route");
294 BigInteger dpnId = null;
295 String tunnelIp = nextHop;
296 if (intfName != null && !intfName.isEmpty()) {
297 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
298 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
299 if (nextHopIp == null || nextHopIp.isEmpty()) {
300 LOG.error("delExtraRoute: NextHop for interface {} is null / empty."
301 + " Failed advertising extra route for rd {} prefix {} dpn {}", intfName, rd, destination,
304 tunnelIp = nextHopIp;
307 String primaryRd = vpnUtil.getVpnRd(vpnName);
308 removePrefixFromBGP(vpnName, primaryRd, rd, intfName, destination, nextHop, tunnelIp, dpnId,
309 writeConfigTxn, writeOperTx);
310 LOG.info("delExtraRoute: Removed extra route {} from interface {} for rd {}", destination, intfName, rd);
312 // add FIB route directly
313 fibManager.removeOrUpdateFibEntry(routerID, destination, tunnelIp, writeConfigTxn);
314 LOG.info("delExtraRoute: Removed extra route {} from interface {} for rd {}", destination, intfName,
320 public void removePrefixFromBGP(String vpnName, String primaryRd, String extraRouteRd, String vpnInterfaceName,
321 String prefix, String nextHop, String nextHopTunnelIp, BigInteger dpnId,
322 TypedWriteTransaction<Configuration> confTx,
323 TypedWriteTransaction<Operational> operTx) {
324 removePrefixFromBGP(vpnName, primaryRd, extraRouteRd, vpnInterfaceName, prefix, nextHop, nextHopTunnelIp,
325 dpnId, TransactionAdapter.toWriteTransaction(confTx), TransactionAdapter.toWriteTransaction(operTx));
328 // TODO Clean up the exception handling
330 @SuppressWarnings("checkstyle:IllegalCatch")
331 public void removePrefixFromBGP(String vpnName, String primaryRd, String extraRouteRd, String vpnInterfaceName,
332 String prefix, String nextHop, String nextHopTunnelIp, BigInteger dpnId, WriteTransaction writeConfigTxn,
333 WriteTransaction writeOperTx) {
335 String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
336 synchronized (vpnNamePrefixKey.intern()) {
337 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, extraRouteRd, vpnInterfaceName, prefix,
338 nextHop, nextHopTunnelIp, writeOperTx)) {
341 fibManager.removeOrUpdateFibEntry(primaryRd, prefix, nextHopTunnelIp, writeConfigTxn);
342 if (VpnUtil.isEligibleForBgp(extraRouteRd, vpnName, dpnId, null /*networkName*/)) {
343 // TODO: Might be needed to include nextHop here
344 bgpManager.withdrawPrefix(extraRouteRd, prefix);
347 LOG.info("removePrefixFromBGP: VPN WITHDRAW: Removed Fib Entry rd {} prefix {} nexthop {}", extraRouteRd,
349 } catch (RuntimeException e) {
350 LOG.error("removePrefixFromBGP: Delete prefix {} rd {} nextHop {} failed", prefix, extraRouteRd, nextHop);
355 public boolean isVPNConfigured() {
356 InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class).build();
358 Optional<VpnInstances> optionalVpns =
359 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
361 if (!optionalVpns.isPresent()
362 || optionalVpns.get().getVpnInstance() == null
363 || optionalVpns.get().getVpnInstance().isEmpty()) {
364 LOG.trace("isVPNConfigured: No VPNs configured.");
367 } catch (ReadFailedException e) {
368 throw new RuntimeException("Error reading VPN " + vpnsIdentifier, e);
370 LOG.trace("isVPNConfigured: VPNs are configured on the system.");
375 public void addSubnetMacIntoVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
376 BigInteger dpnId, TypedWriteTransaction<Configuration> confTx)
377 throws ExecutionException, InterruptedException {
378 setupSubnetMacInVpnInstance(vpnName, subnetVpnName, srcMacAddress, dpnId,
379 (vpnId, dpId, subnetVpnId) -> addGwMac(srcMacAddress, confTx, vpnId, dpId, subnetVpnId));
383 public void addSubnetMacIntoVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
384 BigInteger dpnId, WriteTransaction tx) throws ExecutionException, InterruptedException {
385 setupSubnetMacInVpnInstance(vpnName, subnetVpnName, srcMacAddress, dpnId,
386 (vpnId, dpId, subnetVpnId) -> addGwMac(srcMacAddress, tx, vpnId, dpId, subnetVpnId));
390 public void removeSubnetMacFromVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
391 BigInteger dpnId, TypedReadWriteTransaction<Configuration> confTx)
392 throws ExecutionException, InterruptedException {
393 setupSubnetMacInVpnInstance(vpnName, subnetVpnName, srcMacAddress, dpnId,
394 (vpnId, dpId, subnetVpnId) -> removeGwMac(srcMacAddress, confTx, vpnId, dpId, subnetVpnId));
398 public void removeSubnetMacFromVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
399 BigInteger dpnId, WriteTransaction tx) throws ExecutionException, InterruptedException {
400 setupSubnetMacInVpnInstance(vpnName, subnetVpnName, srcMacAddress, dpnId,
401 (vpnId, dpId, subnetVpnId) -> removeGwMac(srcMacAddress, tx, vpnId, dpId, subnetVpnId));
405 private interface VpnInstanceSubnetMacSetupMethod {
406 void process(long vpnId, BigInteger dpId, long subnetVpnId) throws InterruptedException, ExecutionException;
409 private void setupSubnetMacInVpnInstance(String vpnName, String subnetVpnName, String srcMacAddress,
410 BigInteger dpnId, VpnInstanceSubnetMacSetupMethod consumer)
411 throws ExecutionException, InterruptedException {
412 if (vpnName == null) {
413 LOG.warn("Cannot setup subnet MAC {} on DPN {}, null vpnName", srcMacAddress, dpnId);
417 long vpnId = vpnUtil.getVpnId(vpnName);
418 long subnetVpnId = vpnUtil.getVpnId(subnetVpnName);
419 if (dpnId.equals(BigInteger.ZERO)) {
420 /* Apply the MAC on all DPNs in a VPN */
421 for (BigInteger dpId : vpnUtil.getDpnsOnVpn(vpnName)) {
422 consumer.process(vpnId, dpId, subnetVpnId);
425 consumer.process(vpnId, dpnId, subnetVpnId);
429 private void addGwMac(String srcMacAddress, WriteTransaction tx, long vpnId, BigInteger dpId, long subnetVpnId) {
430 FlowEntity flowEntity = vpnUtil.buildL3vpnGatewayFlow(dpId, srcMacAddress, vpnId, subnetVpnId);
431 mdsalManager.addFlowToTx(flowEntity, tx);
434 private void addGwMac(String srcMacAddress, TypedWriteTransaction<Configuration> tx, long vpnId, BigInteger dpId,
436 FlowEntity flowEntity = vpnUtil.buildL3vpnGatewayFlow(dpId, srcMacAddress, vpnId, subnetVpnId);
437 mdsalManager.addFlow(tx, flowEntity);
440 private void removeGwMac(String srcMacAddress, WriteTransaction tx, long vpnId, BigInteger dpId, long subnetVpnId) {
441 FlowEntity flowEntity = vpnUtil.buildL3vpnGatewayFlow(dpId, srcMacAddress, vpnId, subnetVpnId);
442 mdsalManager.removeFlowToTx(flowEntity, tx);
445 private void removeGwMac(String srcMacAddress, TypedReadWriteTransaction<Configuration> tx, long vpnId,
446 BigInteger dpId, long subnetVpnId) throws ExecutionException, InterruptedException {
447 mdsalManager.removeFlow(tx, dpId,
448 VpnUtil.getL3VpnGatewayFlowRef(NwConstants.L3_GW_MAC_TABLE, dpId, vpnId, srcMacAddress, subnetVpnId),
449 NwConstants.L3_GW_MAC_TABLE);
453 public void addRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
454 String subnetVpnName, TypedWriteTransaction<Configuration> confTx)
455 throws ExecutionException, InterruptedException {
456 setupRouterGwMacFlow(routerName, routerGwMac, dpnId, extNetworkId,
457 vpnId -> addSubnetMacIntoVpnInstance(vpnId, subnetVpnName, routerGwMac, dpnId, confTx), "Installing");
461 public void addRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
462 String subnetVpnName, WriteTransaction writeTx) throws ExecutionException, InterruptedException {
463 setupRouterGwMacFlow(routerName, routerGwMac, dpnId, extNetworkId, writeTx,
464 (vpnId, tx) -> addSubnetMacIntoVpnInstance(vpnId, subnetVpnName, routerGwMac, dpnId, tx), "Installing");
468 public void removeRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
469 String subnetVpnName, TypedReadWriteTransaction<Configuration> confTx)
470 throws ExecutionException, InterruptedException {
471 setupRouterGwMacFlow(routerName, routerGwMac, dpnId, extNetworkId,
472 vpnId -> removeSubnetMacFromVpnInstance(vpnId, subnetVpnName, routerGwMac, dpnId, confTx), "Removing");
476 public void removeRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
477 String subnetVpnName, WriteTransaction writeTx) throws ExecutionException, InterruptedException {
478 setupRouterGwMacFlow(routerName, routerGwMac, dpnId, extNetworkId, writeTx,
479 (vpnId, tx) -> removeSubnetMacFromVpnInstance(vpnId, subnetVpnName, routerGwMac, dpnId, tx), "Removing");
483 private interface RouterGwMacFlowSetupMethod {
484 void process(String vpnId, WriteTransaction tx) throws InterruptedException, ExecutionException;
487 private void setupRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
488 WriteTransaction writeTx, RouterGwMacFlowSetupMethod consumer, String operation)
489 throws ExecutionException, InterruptedException {
490 if (routerGwMac == null) {
491 LOG.warn("Failed to handle router GW flow in GW-MAC table. MAC address is missing for router-id {}",
496 if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
497 LOG.info("setupRouterGwMacFlow: DPN id is missing for router-id {}",
502 Uuid vpnId = vpnUtil.getExternalNetworkVpnId(extNetworkId);
504 LOG.warn("Network {} is not associated with VPN", extNetworkId.getValue());
508 LOG.info("{} router GW MAC flow for router-id {} on switch {}", operation, routerName, dpnId);
509 if (writeTx == null) {
510 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
511 tx -> consumer.process(vpnId.getValue(), tx)), LOG, "Commit transaction");
513 consumer.process(vpnId.getValue(), writeTx);
517 private void setupRouterGwMacFlow(String routerName, String routerGwMac, BigInteger dpnId, Uuid extNetworkId,
518 InterruptibleCheckedConsumer<String, ExecutionException> consumer, String operation)
519 throws ExecutionException, InterruptedException {
520 if (routerGwMac == null) {
521 LOG.warn("Failed to handle router GW flow in GW-MAC table. MAC address is missing for router-id {}",
526 if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
527 LOG.info("setupRouterGwMacFlow: DPN id is missing for router-id {}",
532 Uuid vpnId = vpnUtil.getExternalNetworkVpnId(extNetworkId);
534 LOG.warn("Network {} is not associated with VPN", extNetworkId.getValue());
538 LOG.info("{} router GW MAC flow for router-id {} on switch {}", operation, routerName, dpnId);
539 consumer.accept(vpnId.getValue());
543 public void addArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
544 BigInteger dpnId, Uuid extNetworkId, WriteTransaction writeTx) {
545 addArpResponderFlowsToExternalNetworkIps(id, fixedIps, macAddress, dpnId, extNetworkId);
548 public void addArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
549 BigInteger dpnId, Uuid extNetworkId) {
551 if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
552 LOG.warn("Failed to install arp responder flows for router {}. DPN id is missing.", id);
556 String extInterfaceName = elanService.getExternalElanInterface(extNetworkId.getValue(), dpnId);
557 if (extInterfaceName != null) {
558 doAddArpResponderFlowsToExternalNetworkIps(
559 id, fixedIps, macAddress, dpnId, extInterfaceName);
563 LOG.warn("Failed to install responder flows for {}. No external interface found for DPN id {}", id, dpnId);
565 if (!upgradeState.isUpgradeInProgress()) {
569 // The following through the end of the function deals with an upgrade scenario where the neutron configuration
570 // is restored before the OVS switches reconnect. In such a case, the elan-dpn-interfaces entries will be
571 // missing from the operational data store. In order to mitigate this we use DataTreeEventCallbackRegistrar
572 // to wait for the exact operational md-sal object we need to contain the external interface we need.
574 LOG.info("Upgrade in process, waiting for an external interface to appear on dpn {} for elan {}",
575 dpnId, extNetworkId.getValue());
577 InstanceIdentifier<DpnInterfaces> dpnInterfacesIid =
578 elanService.getElanDpnInterfaceOperationalDataPath(extNetworkId.getValue(), dpnId);
580 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.OPERATIONAL, dpnInterfacesIid, (unused, alsoUnused) -> {
581 LOG.info("Reattempting write of arp responder for external interfaces for external network {}",
583 DpnInterfaces dpnInterfaces = elanService.getElanInterfaceInfoByElanDpn(extNetworkId.getValue(), dpnId);
584 if (dpnInterfaces == null) {
585 LOG.error("Could not retrieve DpnInterfaces for {}, {}", extNetworkId.getValue(), dpnId);
586 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
589 String extIfc = null;
590 for (String dpnInterface : dpnInterfaces.getInterfaces()) {
591 if (interfaceManager.isExternalInterface(dpnInterface)) {
592 extIfc = dpnInterface;
597 if (extIfc == null) {
598 if (upgradeState.isUpgradeInProgress()) {
599 LOG.info("External interface not found yet in elan {} on dpn {}, keep waiting",
600 extNetworkId.getValue(), dpnInterfaces);
601 return DataTreeEventCallbackRegistrar.NextAction.CALL_AGAIN;
603 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
607 final String extIfcFinal = extIfc;
608 doAddArpResponderFlowsToExternalNetworkIps(id, fixedIps, macAddress, dpnId, extIfcFinal);
610 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
616 public void addArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
617 BigInteger dpnId, String extInterfaceName, int lportTag) {
618 if (fixedIps == null || fixedIps.isEmpty()) {
619 LOG.debug("No external IPs defined for {}", id);
623 LOG.info("Installing ARP responder flows for {} fixed-ips {} on switch {}", id, fixedIps, dpnId);
625 for (String fixedIp : fixedIps) {
626 IpVersionChoice ipVersionChoice = VpnUtil.getIpVersionFromString(fixedIp);
627 if (ipVersionChoice == IpVersionChoice.IPV6) {
630 installArpResponderFlowsToExternalNetworkIp(macAddress, dpnId, extInterfaceName, lportTag,
635 private void doAddArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
636 BigInteger dpnId, String extInterfaceName) {
637 Interface extInterfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, extInterfaceName);
638 if (extInterfaceState == null) {
639 LOG.debug("No interface state found for interface {}. Delaying responder flows for {}", extInterfaceName,
644 Integer lportTag = extInterfaceState.getIfIndex();
645 if (lportTag == null) {
646 LOG.debug("No Lport tag found for interface {}. Delaying flows for router-id {}", extInterfaceName, id);
650 if (macAddress == null) {
652 LOG.debug("Failed to install arp responder flows for router-gateway-ip {} for router {}."
653 + "External Gw MacAddress is missing.", fixedIps, id);
657 addArpResponderFlowsToExternalNetworkIps(id, fixedIps, macAddress, dpnId, extInterfaceName, lportTag);
661 public void removeArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps, String macAddress,
662 BigInteger dpnId, Uuid extNetworkId) {
664 if (dpnId == null || BigInteger.ZERO.equals(dpnId)) {
665 LOG.warn("Failed to remove arp responder flows for router {}. DPN id is missing.", id);
669 String extInterfaceName = elanService.getExternalElanInterface(extNetworkId.getValue(), dpnId);
670 if (extInterfaceName == null) {
671 LOG.warn("Failed to remove responder flows for {}. No external interface found for DPN id {}", id, dpnId);
675 Interface extInterfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, extInterfaceName);
676 if (extInterfaceState == null) {
677 LOG.debug("No interface state found for interface {}. Delaying responder flows for {}", extInterfaceName,
682 Integer lportTag = extInterfaceState.getIfIndex();
683 if (lportTag == null) {
684 LOG.debug("No Lport tag found for interface {}. Delaying flows for router-id {}", extInterfaceName, id);
688 if (macAddress == null) {
690 LOG.debug("Failed to remove arp responder flows for router-gateway-ip {} for router {}."
691 + "External Gw MacAddress is missing.", fixedIps, id);
695 removeArpResponderFlowsToExternalNetworkIps(id, fixedIps, dpnId,
696 extInterfaceName, lportTag);
700 public void removeArpResponderFlowsToExternalNetworkIps(String id, Collection<String> fixedIps,
701 BigInteger dpnId, String extInterfaceName, int lportTag) {
702 if (fixedIps == null || fixedIps.isEmpty()) {
703 LOG.debug("No external IPs defined for {}", id);
707 LOG.info("Removing ARP responder flows for {} fixed-ips {} on switch {}", id, fixedIps, dpnId);
709 for (String fixedIp : fixedIps) {
710 removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, extInterfaceName);
715 public String getPrimaryRdFromVpnInstance(VpnInstance vpnInstance) {
716 return VpnUtil.getPrimaryRd(vpnInstance);
719 private void installArpResponderFlowsToExternalNetworkIp(String macAddress, BigInteger dpnId,
720 String extInterfaceName, int lportTag, String fixedIp) {
721 // reset the split-horizon bit to allow traffic to be sent back to the
723 List<Instruction> instructions = new ArrayList<>();
725 new InstructionWriteMetadata(BigInteger.ZERO, MetaDataUtil.METADATA_MASK_SH_FLAG).buildInstruction(1));
727 ArpResponderUtil.getExtInterfaceInstructions(interfaceManager, itmRpcService, extInterfaceName,
728 fixedIp, macAddress));
729 ArpReponderInputBuilder builder = new ArpReponderInputBuilder().setDpId(dpnId)
730 .setInterfaceName(extInterfaceName).setSpa(fixedIp).setSha(macAddress).setLportTag(lportTag);
731 builder.setInstructions(instructions);
732 elanService.addArpResponderFlow(builder.buildForInstallFlow());
735 private void removeArpResponderFlowsToExternalNetworkIp(BigInteger dpnId, Integer lportTag, String fixedIp,
736 String extInterfaceName) {
737 ArpResponderInput arpInput = new ArpReponderInputBuilder().setDpId(dpnId).setInterfaceName(extInterfaceName)
738 .setSpa(fixedIp).setLportTag(lportTag).buildForRemoveFlow();
739 elanService.removeArpResponderFlow(arpInput);
743 public void onSubnetAddedToVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
744 vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
748 public void onSubnetDeletedFromVpn(Subnetmap subnetmap, boolean isBgpVpn) {
749 vpnSubnetRouteHandler.onSubnetDeletedFromVpn(subnetmap, isBgpVpn);
753 public VpnInstance getVpnInstance(DataBroker broker, String vpnInstanceName) {
754 return vpnUtil.getVpnInstance(vpnInstanceName);
758 public String getVpnRd(TypedReadTransaction<Configuration> confTx, String vpnName) {
759 return VpnUtil.getVpnRd(confTx, vpnName);
763 public String getVpnRd(DataBroker broker, String vpnName) {
764 return vpnUtil.getVpnRd(vpnName);
768 public VpnPortipToPort getNeutronPortFromVpnPortFixedIp(TypedReadTransaction<Configuration> confTx, String vpnName,
770 return vpnUtil.getNeutronPortFromVpnPortFixedIp(confTx, vpnName, fixedIp);
774 public VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
775 return vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, fixedIp);
779 public Set<VpnTarget> getRtListForVpn(String vpnName) {
780 return vpnUtil.getRtListForVpn(vpnName);
784 public void updateRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName) {
785 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
786 for (VpnTarget rt : routeTargets) {
787 String rtValue = rt.getVrfRTValue();
788 switch (rt.getVrfRTType()) {
789 case ImportExtcommunity:
790 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName,
791 tx, false/*isAssociationRemoved*/);
793 case ExportExtcommunity:
794 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName,
795 tx, false/*isAssociationRemoved*/);
798 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName,
799 tx, false/*isAssociationRemoved*/);
800 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName,
801 tx, false/*isAssociationRemoved*/);
804 LOG.error("updateRouteTargetsToSubnetAssociation: Invalid rt-type {} for vpn {}"
805 + " subnet-cidr {}", rt.getVrfRTType(), vpnName, cidr);
809 }), LOG, "updateRouteTargetsToSubnetAssociation: Failed for vpn {} subnet-cidr {}", vpnName, cidr);
810 LOG.info("updateRouteTargetsToSubnetAssociation: Updated RT to subnet association for vpn {} cidr {}",
815 public void removeRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName) {
816 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
817 for (VpnTarget rt : routeTargets) {
818 String rtValue = rt.getVrfRTValue();
819 switch (rt.getVrfRTType()) {
820 case ImportExtcommunity:
821 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName, tx,
822 true/*isAssociationRemoved*/);
824 case ExportExtcommunity:
825 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName, tx,
826 true/*isAssociationRemoved*/);
829 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName, tx,
830 true/*isAssociationRemoved*/);
831 addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName, tx,
832 true/*isAssociationRemoved*/);
835 LOG.error("removeRouteTargetsToSubnetAssociation: Invalid route-target type {} for vpn {}"
836 + " subnet-cidr {}", rt.getVrfRTType(), vpnName, cidr);
840 }), LOG, "removeRouteTargetsToSubnetAssociation: Failed for vpn {} subnet-cidr {}", vpnName, cidr);
841 LOG.info("removeRouteTargetsToSubnetAssociation: vpn {} cidr {}", vpnName, cidr);
844 private boolean doesExistingVpnsHaveConflictingSubnet(Set<VpnTarget> routeTargets, String subnetCidr) {
845 Set<RouteTarget> routeTargetSet = vpnUtil.getRouteTargetSet(routeTargets);
846 for (RouteTarget routerTarget : routeTargetSet) {
847 if (routerTarget.getAssociatedSubnet() != null) {
848 for (int i = 0; i < routerTarget.getAssociatedSubnet().size(); i++) {
849 AssociatedSubnet associatedSubnet = routerTarget.getAssociatedSubnet().get(i);
850 if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(), subnetCidr)) {
853 if (routerTarget.getRtType() == RouteTarget.RtType.ERT) {
854 /* Check if there are multiple exports for the input iRT value (iRT in routeTargets)
855 * Example : (1) iRT=A eRT=B subnet-range=S1; OK
856 * (2) iRT=A eRT=B subnet-range=S1; OK
857 * (3) iRT=B eRT=A subnet-range=S2; NOK
858 * Check if (1) and (2) are importing the same subnet-range routes to (3) */
859 List<AssociatedVpn> multipleAssociatedVpn = associatedSubnet.getAssociatedVpn();
860 if (multipleAssociatedVpn != null && multipleAssociatedVpn.size() > 1) {
861 LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect complete overlap"
862 + " for subnet CIDR {} for rt {} rtType {}", subnetCidr, routerTarget.getRt(),
863 routerTarget.getRtType());
866 for (int j = i + 1; j < routerTarget.getAssociatedSubnet().size(); j++) {
867 if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(),
868 routerTarget.getAssociatedSubnet().get(j).getCidr())) {
869 LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect paartial"
870 + " overlap for subnet CIDR {} for rt {} rtType {}", subnetCidr,
871 routerTarget.getRt(), routerTarget.getRtType());
877 /* Check if there are indirect EXPORTS for the eRT value (eRT in routeTargets)
878 * Example : (1) iRT=A eRT=B subnet-range=S1; OK
879 * (2) iRT=B eRT=A subnet-range=S2; OK
880 * (3) iRT=A eRT=B subnet-range=S1; NOK
881 * If associatedSubnet is non-null for a routeTarget in (2),
882 * it may have already imported routes from (1) */
883 if (routerTarget.getRtType() == RouteTarget.RtType.IRT) {
885 Optional<RouteTarget> indirectRts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
886 LogicalDatastoreType.OPERATIONAL, VpnUtil.getRouteTargetsIdentifier(
887 routerTarget.getRt(), RouteTarget.RtType.ERT));
888 if (indirectRts.isPresent() && routerTarget.getAssociatedSubnet() != null) {
889 for (AssociatedSubnet associatedSubnet : indirectRts.get().getAssociatedSubnet()) {
890 if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(), subnetCidr)) {
891 LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect overlap for"
892 + " subnet CIDR {} for rt {} rtType {}", subnetCidr, routerTarget.getRt(),
893 routerTarget.getRtType());
898 } catch (ReadFailedException e) {
899 LOG.error("doesExistingVpnsHaveConflictingSubnet: Failed to read route targets to subnet"
900 + "association for rt {} type {} subnet-cidr {}", routerTarget.getRt(),
901 RouteTarget.RtType.ERT, subnetCidr);
902 return true; //Fail subnet association to avoid further damage to the data-stores
906 LOG.info("doesExistingVpnsHaveConflictingSubnet: No prior associated subnets for rtVal {} rtType {}",
907 routerTarget.getRt(), routerTarget.getRtType());
913 private void addSubnetAssociationOperationToTx(String rt, RouteTarget.RtType rtType, String cidr,
914 String vpnName, ReadWriteTransaction tx,
915 boolean isAssociationRemoved)
916 throws InterruptedException, ExecutionException {
917 if (isAssociationRemoved) {
918 //Remove RT-Subnet-Vpn Association
919 Optional<AssociatedSubnet> associatedSubnet = tx.read(LogicalDatastoreType.OPERATIONAL,
920 VpnUtil.getAssociatedSubnetIdentifier(rt, rtType, cidr)).get();
921 boolean deleteParent = false;
922 if (associatedSubnet.isPresent()) {
923 List<AssociatedVpn> associatedVpns = associatedSubnet.get().getAssociatedVpn();
924 if (associatedVpns == null || associatedVpns.isEmpty()) {
927 for (Iterator<AssociatedVpn> iterator = associatedVpns.iterator(); iterator.hasNext();) {
928 AssociatedVpn associatedVpn = (AssociatedVpn) iterator.next();
929 if (associatedVpn.getName().equals(vpnName)) {
934 if (associatedVpns.isEmpty()) {
940 deleteParentForSubnetToVpnAssocication(rt, rtType, cidr, tx);
942 //Some other VPNs are also part of this rtVal, rtType and subnetCidr combination.
943 //Delete only this AssociatedVpn Object
944 tx.delete(LogicalDatastoreType.OPERATIONAL,
945 VpnUtil.getAssociatedSubnetAndVpnIdentifier(rt, rtType, cidr, vpnName));
946 LOG.debug("addSubnetAssocOperationToTx: Removed vpn {} from association rt {} rtType {} cidr {}",
947 vpnName, rt, rtType, cidr);
950 //Add RT-Subnet-Vpn Association
951 tx.put(LogicalDatastoreType.OPERATIONAL,
952 VpnUtil.getAssociatedSubnetAndVpnIdentifier(rt, rtType, cidr, vpnName),
953 VpnUtil.buildAssociatedSubnetAndVpn(vpnName), true);
957 private void deleteParentForSubnetToVpnAssocication(String rt, RouteTarget.RtType rtType,
958 String cidr, ReadWriteTransaction tx)
959 throws InterruptedException, ExecutionException {
960 //Check if you need to delete rtVal+rtType or just the subnetCidr
961 InstanceIdentifier<RouteTarget> rtIdentifier = InstanceIdentifier
962 .builder(SubnetsAssociatedToRouteTargets.class).child(RouteTarget.class,
963 new RouteTargetKey(rt, rtType)).build();
964 Optional<RouteTarget> rtToSubnetsAssociation = tx.read(LogicalDatastoreType.OPERATIONAL,
966 if (rtToSubnetsAssociation.isPresent()) {
967 List<AssociatedSubnet> associatedSubnets = rtToSubnetsAssociation.get().getAssociatedSubnet();
968 if (associatedSubnets != null && !associatedSubnets.isEmpty()) {
969 for (Iterator<AssociatedSubnet> iterator = associatedSubnets.iterator(); iterator.hasNext(); ) {
970 if (iterator.next().getCidr().equals(cidr)) {
975 if (associatedSubnets.isEmpty()) {
976 //The entire rt to subnet association is empty
977 //Delete the RouteTarget object
978 tx.delete(LogicalDatastoreType.OPERATIONAL, rtIdentifier);
979 LOG.debug("deleteParentForSubnetToVpnAssocication: Removed rt {} rtType {} from association,",
982 //Some other VPNs are also part of this rtVal, rtType combination
983 //Delete only this AssociatedSubnet
984 tx.delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getAssociatedSubnetIdentifier(rt, rtType,
986 LOG.debug("deleteParentForSubnetToVpnAssocication: Removed cidr {} from association rt {}"
987 + " rtType {}", cidr, rt, rtType);
994 public boolean checkForOverlappingSubnets(Uuid network, List<Subnetmap> subnetmapList, Uuid vpn,
995 Set<VpnTarget> routeTargets, List<String> failedNwList) {
996 for (int i = 0; i < subnetmapList.size(); i++) {
997 //Check if any other subnet that is already part of a different vpn with same rt, has overlapping CIDR
998 if (checkExistingSubnetWithSameRoutTargets(routeTargets, vpn, subnetmapList.get(i), failedNwList)) {
1005 private boolean checkExistingSubnetWithSameRoutTargets(Set<VpnTarget> routeTargets, Uuid vpn, Subnetmap subnetmap,
1006 List<String> failedNwList) {
1007 String cidr = String.valueOf(subnetmap.getSubnetIp());
1008 boolean subnetExistsWithSameRt = doesExistingVpnsHaveConflictingSubnet(routeTargets, cidr);
1009 if (subnetExistsWithSameRt) {
1010 failedNwList.add(String.format("Another subnet with the same/overlapping cidr %s as subnet %s"
1011 + " is already associated to a vpn with routeTargets %s. Ignoring subnet addition to vpn"
1012 + " %s", cidr, subnetmap.getId().getValue(), routeTargets.toString(), vpn.getValue()));
1014 return subnetExistsWithSameRt;