//clear removed networks
if (!oldNetworks.isEmpty()) {
LOG.trace("Removing old networks {} ", oldNetworks);
- nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
+ List<String> errorMessages = nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("handleNetworksUpdate: dissociate old Networks not part of bgpvpn update,"
+ + " from vpn {} failed due to {}", vpnId.getValue(), errorMessages);
+ }
}
//add new (Delta) Networks
if (!newNetworks.isEmpty()) {
LOG.trace("Adding delta New networks {} ", newNetworks);
- nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
+ List<String> errorMessages = nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("handleNetworksUpdate: associate new Networks not part of original bgpvpn,"
+ + " to vpn {} failed due to {}", vpnId.getValue(), errorMessages);
+ }
}
}
} else {
//add new Networks
LOG.trace("Adding New networks {} ", newNetworks);
- nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
+ List<String> errorMessages = nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("handleNetworksUpdate: associate new Networks to vpn {} failed due to {}",
+ vpnId.getValue(), errorMessages);
+ }
}
} else if (oldNetworks != null && !oldNetworks.isEmpty()) {
LOG.trace("Removing old networks {} ", oldNetworks);
- nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
-
+ List<String> errorMessages = nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("handleNetworksUpdate: dissociate old Networks from vpn {} failed due to {}",
+ vpnId.getValue(), errorMessages);
+ }
}
}
import com.google.common.base.Optional;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
private final NeutronvpnManager nvpnManager;
private final NeutronExternalSubnetHandler externalSubnetHandler;
private final NeutronvpnUtils neutronvpnUtils;
+ private final IVpnManager vpnManager;
@Inject
public NeutronSubnetChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
- final NeutronExternalSubnetHandler externalSubnetHandler, final NeutronvpnUtils neutronvpnUtils) {
+ final NeutronExternalSubnetHandler externalSubnetHandler, final NeutronvpnUtils neutronvpnUtils,
+ final IVpnManager vpnManager) {
super(Subnet.class, NeutronSubnetChangeListener.class);
this.dataBroker = dataBroker;
this.nvpnManager = neutronvpnManager;
this.externalSubnetHandler = externalSubnetHandler;
this.neutronvpnUtils = neutronvpnUtils;
+ this.vpnManager = vpnManager;
}
@Override
subnetId.getValue(), network);
return;
}
- handleNeutronSubnetDeleted(subnetId, networkId);
+ handleNeutronSubnetDeleted(subnetId, networkId, String.valueOf(input.getCidr().getValue()));
externalSubnetHandler.handleExternalSubnetRemoved(network, subnetId);
neutronvpnUtils.removeFromSubnetCache(input);
}
createSubnetToNetworkMapping(subnetId, networkId);
}
- private void handleNeutronSubnetDeleted(Uuid subnetId, Uuid networkId) {
+ private void handleNeutronSubnetDeleted(Uuid subnetId, Uuid networkId, String subnetCidr) {
Uuid vpnId = neutronvpnUtils.getVpnForNetwork(networkId);
if (vpnId != null) {
- nvpnManager.removeSubnetFromVpn(vpnId, subnetId, null /* internet-vpn-id */);
+ LOG.warn("Subnet {} deleted without disassociating network {} from VPN {}. Ideally, please disassociate "
+ + "network from VPN before deleting neutron subnet.", subnetId.getValue(), networkId.getValue(),
+ vpnId.getValue());
+ Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnetId);
+ if (subnetmap != null) {
+ nvpnManager.removeSubnetFromVpn(vpnId, subnetId, null /* internet-vpn-id */);
+ } else {
+ LOG.error("Subnetmap for subnet {} not found", subnetId.getValue());
+ }
+ Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+ if (!routeTargets.isEmpty()) {
+ vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetCidr, subnetId.getValue());
+ }
}
if (networkId != null) {
deleteSubnetToNetworkMapping(subnetId, networkId);
private final NeutronEvpnUtils neutronEvpnUtils;
private final JobCoordinator jobCoordinator;
private final NeutronvpnUtils neutronvpnUtils;
+ private final IVpnManager vpnManager;
private final ConcurrentHashMap<Uuid, Uuid> unprocessedPortsMap = new ConcurrentHashMap<>();
private final NeutronvpnAlarms neutronvpnAlarm = new NeutronvpnAlarms();
private final KeyedLocks<Uuid> vpnLock = new KeyedLocks<>();
neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager, jobCoordinator);
this.jobCoordinator = jobCoordinator;
this.neutronvpnUtils = neutronvpnUtils;
+ this.vpnManager = vpnManager;
configureFeatures();
}
+ "associated with", vpnId.getValue()));
return failedNwList;
}
+ Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
for (Uuid nw : networkList) {
Network network = neutronvpnUtils.getNeutronNetwork(nw);
if (network == null) {
nw.getValue(), vpnId.getValue()));
continue;
}
- List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
- if (networkSubnets == null) {
+ List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
+ if (subnetmapList == null || subnetmapList.isEmpty()) {
passedNwList.add(nw);
continue;
}
- for (Uuid subnet : networkSubnets) {
- Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnet);
+ if (vpnManager.checkForOverlappingSubnets(nw, subnetmapList, vpnId, routeTargets, failedNwList)) {
+ continue;
+ }
+ for (Subnetmap subnetmap : subnetmapList) {
+ Uuid subnetId = subnetmap.getId();
+ Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
if (subnetVpnId != null) {
- LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {} as it is already "
- + "associated", subnet.getValue(), subnetVpnId.getValue());
- failedNwList.add(String.format("Failed to associate subnet %s with VPN %s as it is already "
- + "associated", subnet.getValue(), vpnId.getValue()));
+ LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {}"
+ + " as it is already associated", subnetId.getValue(), subnetVpnId.getValue());
+ failedNwList.add(String.format("Failed to associate subnet %s with VPN %s"
+ + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
continue;
}
- Subnetmap sm = neutronvpnUtils.getSubnetmap(subnet);
- if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(sm, vpnId)) {
+ if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(subnetmap, vpnId)) {
neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
- NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp()), true);
+ NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp()), true);
}
if (!neutronvpnUtils.getIsExternal(network)) {
- LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnet.getValue(),
+ LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
vpnId.getValue());
- addSubnetToVpn(vpnId, subnet, null);
+ addSubnetToVpn(vpnId, subnetId, null);
+ vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
+ vpnId.getValue());
+ passedNwList.add(nw);
}
}
passedNwList.add(nw);
return failedNwList;
}
for (Uuid nw : networkList) {
+ List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
+ if (networkSubnets == null) {
+ passedNwList.add(nw);
+ continue;
+ }
Network network = neutronvpnUtils.getNeutronNetwork(nw);
if (network == null) {
LOG.error("dissociateNetworksFromVpn: Network {} not found in ConfigDS");
continue;
}
}
- List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
- if (networkSubnets == null) {
- passedNwList.add(nw);
- continue;
- }
+ Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
for (Uuid subnet : networkSubnets) {
- Subnetmap sm = neutronvpnUtils.getSubnetmap(subnet);
- if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sm, vpnId)) {
+ Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
+ if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(subnetmap, vpnId)) {
IpVersionChoice ipVersionsToRemove = IpVersionChoice.UNDEFINED;
- IpVersionChoice ipVersion = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+ IpVersionChoice ipVersion = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
ipVersionsToRemove.addVersion(ipVersion), false);
}
LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
vpnId.getValue());
removeSubnetFromVpn(vpnId, subnet, null);
+ vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
+ vpnId.getValue());
passedNwList.add(nw);
}
}
if (sn.isPresent()) {
subnet = sn.get();
+ addToSubnetCache(subnet);
}
return subnet;
}
.child(Routers.class).child(Router.class, new RouterKey(routerUuid));
return routerInstanceIdentifier;
}
+
+ List<Subnetmap> getSubnetmapListFromNetworkId(Uuid networkId) {
+ List<Uuid> subnetIdList = getSubnetIdsFromNetworkId(networkId);
+ if (subnetIdList != null) {
+ List<Subnetmap> subnetmapList = new ArrayList<>();
+ for (Uuid subnetId : subnetIdList) {
+ Subnetmap subnetmap = getSubnetmap(subnetId);
+ if (subnetmap != null) {
+ subnetmapList.add(subnetmap);
+ } else {
+ LOG.error("getSubnetmapListFromNetworkId: subnetmap is null for subnet {} belonging to network {}",
+ subnetId.getValue(), networkId.getValue());
+ }
+ }
+ return subnetmapList;
+ }
+ LOG.error("getSubnetmapListFromNetworkId: Failed as subnetIdList is null for network {}",
+ networkId.getValue());
+ return null;
+ }
}
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
String getVpnRd(DataBroker broker, String vpnName);
VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp);
+
+ void updateRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName);
+
+ void removeRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName);
+
+ boolean checkForOverlappingSubnets(Uuid network, List<Subnetmap> subnetmapList, Uuid vpn,
+ Set<VpnTarget> routeTargets, List<String> failedNwList);
+
+ Set<VpnTarget> getRtListForVpn(String vpnName);
}
leaf learnt-vpn-vip-event-id { type string; }
}
}
+
+ /* rt to subnets map */
+ container subnets-associated-to-route-targets {
+ config false;
+ list route-target {
+ key "rt rt-type";
+ leaf rt { type string; }
+ leaf rt-type {
+ type enumeration {
+ enum iRT {
+ value "0";
+ }
+ enum eRT {
+ value "1";
+ }
+ }
+ }
+ list associated-subnet {
+ key cidr;
+ leaf cidr { type string; }
+ list associated-vpn {
+ key "name";
+ leaf name { type string; }
+ }
+ }
+ }
+ }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
private final DataBroker dataBroker;
private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
private final VpnUtil vpnUtil;
+ private final IVpnManager vpnManager;
@Inject
public SubnetmapChangeListener(final DataBroker dataBroker, final VpnSubnetRouteHandler vpnSubnetRouteHandler,
- VpnUtil vpnUtil) {
+ VpnUtil vpnUtil, IVpnManager vpnManager) {
super(Subnetmap.class, SubnetmapChangeListener.class);
this.dataBroker = dataBroker;
this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
this.vpnUtil = vpnUtil;
+ this.vpnManager = vpnManager;
}
@PostConstruct
elanInstanceName, subnetId.getValue());
return;
}
- if (subnetmap.getVpnId() != null) {
- boolean isBgpVpn = !subnetmap.getVpnId().equals(subnetmap.getRouterId());
+ Uuid vpnId = subnetmap.getVpnId();
+ if (vpnId != null) {
+ boolean isBgpVpn = !vpnId.equals(subnetmap.getRouterId());
LOG.info("SubnetMapChangeListener:add: subnetmap {} with elanTag {} to VPN {}", subnetmap, elanTag,
- subnetmap.getVpnId());
+ vpnId);
vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
+ if (isBgpVpn && subnetmap.getRouterId() == null) {
+ Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+ if (!routeTargets.isEmpty()) {
+ synchronized (subnetmap.getSubnetIp().intern()) {
+ vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
+ vpnId.getValue());
+ }
+ }
+ }
}
}
interfaces = interfacelistIter.next();
if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
- return;
+ continue;
}
intfName = interfaces.getInterfaceName();
VpnInterface vpnInterface =
interfaces = interfacelistIter.next();
if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
- return;
+ continue;
}
intfName = interfaces.getInterfaceName();
VpnInterface vpnInterface =
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetsAssociatedToRouteTargets;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTarget;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTargetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.AssociatedSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.associated.subnet.AssociatedVpn;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
public VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
return vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, fixedIp);
}
+
+ @Override
+ public Set<VpnTarget> getRtListForVpn(String vpnName) {
+ return vpnUtil.getRtListForVpn(vpnName);
+ }
+
+ @Override
+ public void updateRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName) {
+ ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+ for (VpnTarget rt : routeTargets) {
+ String rtValue = rt.getVrfRTValue();
+ switch (rt.getVrfRTType()) {
+ case ImportExtcommunity:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName,
+ tx, false/*isAssociationRemoved*/);
+ break;
+ case ExportExtcommunity:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName,
+ tx, false/*isAssociationRemoved*/);
+ break;
+ case Both:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName,
+ tx, false/*isAssociationRemoved*/);
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName,
+ tx, false/*isAssociationRemoved*/);
+ break;
+ default:
+ LOG.error("updateRouteTargetsToSubnetAssociation: Invalid rt-type {} for vpn {}"
+ + " subnet-cidr {}", rt.getVrfRTType(), vpnName, cidr);
+ break;
+ }
+ }
+ }), LOG, "updateRouteTargetsToSubnetAssociation: Failed for vpn {} subnet-cidr {}", vpnName, cidr);
+ LOG.info("updateRouteTargetsToSubnetAssociation: Updated RT to subnet association for vpn {} cidr {}",
+ vpnName, cidr);
+ }
+
+ @Override
+ public void removeRouteTargetsToSubnetAssociation(Set<VpnTarget> routeTargets, String cidr, String vpnName) {
+ ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+ for (VpnTarget rt : routeTargets) {
+ String rtValue = rt.getVrfRTValue();
+ switch (rt.getVrfRTType()) {
+ case ImportExtcommunity:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName, tx,
+ true/*isAssociationRemoved*/);
+ break;
+ case ExportExtcommunity:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName, tx,
+ true/*isAssociationRemoved*/);
+ break;
+ case Both:
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.IRT, cidr, vpnName, tx,
+ true/*isAssociationRemoved*/);
+ addSubnetAssociationOperationToTx(rtValue, RouteTarget.RtType.ERT, cidr, vpnName, tx,
+ true/*isAssociationRemoved*/);
+ break;
+ default:
+ LOG.error("removeRouteTargetsToSubnetAssociation: Invalid route-target type {} for vpn {}"
+ + " subnet-cidr {}", rt.getVrfRTType(), vpnName, cidr);
+ break;
+ }
+ }
+ }), LOG, "removeRouteTargetsToSubnetAssociation: Failed for vpn {} subnet-cidr {}", vpnName, cidr);
+ LOG.info("removeRouteTargetsToSubnetAssociation: vpn {} cidr {}", vpnName, cidr);
+ }
+
+ private boolean doesExistingVpnsHaveConflictingSubnet(Set<VpnTarget> routeTargets, String subnetCidr) {
+ Set<RouteTarget> routeTargetSet = vpnUtil.getRouteTargetSet(routeTargets);
+ for (RouteTarget routerTarget : routeTargetSet) {
+ if (routerTarget.getAssociatedSubnet() != null) {
+ for (int i = 0; i < routerTarget.getAssociatedSubnet().size(); i++) {
+ AssociatedSubnet associatedSubnet = routerTarget.getAssociatedSubnet().get(i);
+ if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(), subnetCidr)) {
+ return true;
+ }
+ if (routerTarget.getRtType() == RouteTarget.RtType.ERT) {
+ /* Check if there are multiple exports for the input iRT value (iRT in routeTargets)
+ * Example : (1) iRT=A eRT=B subnet-range=S1; OK
+ * (2) iRT=A eRT=B subnet-range=S1; OK
+ * (3) iRT=B eRT=A subnet-range=S2; NOK
+ * Check if (1) and (2) are importing the same subnet-range routes to (3) */
+ List<AssociatedVpn> multipleAssociatedVpn = associatedSubnet.getAssociatedVpn();
+ if (multipleAssociatedVpn != null && multipleAssociatedVpn.size() > 1) {
+ LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect complete overlap"
+ + " for subnet CIDR {} for rt {} rtType {}", subnetCidr, routerTarget.getRt(),
+ routerTarget.getRtType());
+ return true;
+ }
+ for (int j = i + 1; j < routerTarget.getAssociatedSubnet().size(); j++) {
+ if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(),
+ routerTarget.getAssociatedSubnet().get(j).getCidr())) {
+ LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect paartial"
+ + " overlap for subnet CIDR {} for rt {} rtType {}", subnetCidr,
+ routerTarget.getRt(), routerTarget.getRtType());
+ return true;
+ }
+ }
+ }
+ }
+ /* Check if there are indirect EXPORTS for the eRT value (eRT in routeTargets)
+ * Example : (1) iRT=A eRT=B subnet-range=S1; OK
+ * (2) iRT=B eRT=A subnet-range=S2; OK
+ * (3) iRT=A eRT=B subnet-range=S1; NOK
+ * If associatedSubnet is non-null for a routeTarget in (2),
+ * it may have already imported routes from (1) */
+ if (routerTarget.getRtType() == RouteTarget.RtType.IRT) {
+ try {
+ Optional<RouteTarget> indirectRts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+ LogicalDatastoreType.OPERATIONAL, VpnUtil.getRouteTargetsIdentifier(
+ routerTarget.getRt(), RouteTarget.RtType.ERT));
+ if (indirectRts.isPresent() && routerTarget.getAssociatedSubnet() != null) {
+ for (AssociatedSubnet associatedSubnet : indirectRts.get().getAssociatedSubnet()) {
+ if (VpnUtil.areSubnetsOverlapping(associatedSubnet.getCidr(), subnetCidr)) {
+ LOG.error("doesExistingVpnsHaveConflictingSubnet: There is an indirect overlap for"
+ + " subnet CIDR {} for rt {} rtType {}", subnetCidr, routerTarget.getRt(),
+ routerTarget.getRtType());
+ return true;
+ }
+ }
+ }
+ } catch (ReadFailedException e) {
+ LOG.error("doesExistingVpnsHaveConflictingSubnet: Failed to read route targets to subnet"
+ + "association for rt {} type {} subnet-cidr {}", routerTarget.getRt(),
+ RouteTarget.RtType.ERT, subnetCidr);
+ return true; //Fail subnet association to avoid further damage to the data-stores
+ }
+ }
+ } else {
+ LOG.info("doesExistingVpnsHaveConflictingSubnet: No prior associated subnets for rtVal {} rtType {}",
+ routerTarget.getRt(), routerTarget.getRtType());
+ }
+ }
+ return false;
+ }
+
+ private void addSubnetAssociationOperationToTx(String rt, RouteTarget.RtType rtType, String cidr,
+ String vpnName, ReadWriteTransaction tx,
+ boolean isAssociationRemoved)
+ throws InterruptedException, ExecutionException {
+ if (isAssociationRemoved) {
+ //Remove RT-Subnet-Vpn Association
+ Optional<AssociatedSubnet> associatedSubnet = tx.read(LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getAssociatedSubnetIdentifier(rt, rtType, cidr)).get();
+ boolean deleteParent = false;
+ if (associatedSubnet.isPresent()) {
+ List<AssociatedVpn> associatedVpns = associatedSubnet.get().getAssociatedVpn();
+ if (associatedVpns == null || associatedVpns.isEmpty()) {
+ deleteParent = true;
+ } else {
+ for (Iterator<AssociatedVpn> iterator = associatedVpns.iterator(); iterator.hasNext();) {
+ AssociatedVpn associatedVpn = (AssociatedVpn) iterator.next();
+ if (associatedVpn.getName().equals(vpnName)) {
+ iterator.remove();
+ break;
+ }
+ }
+ if (associatedVpns.isEmpty()) {
+ deleteParent = true;
+ }
+ }
+ }
+ if (deleteParent) {
+ deleteParentForSubnetToVpnAssocication(rt, rtType, cidr, tx);
+ } else {
+ //Some other VPNs are also part of this rtVal, rtType and subnetCidr combination.
+ //Delete only this AssociatedVpn Object
+ tx.delete(LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getAssociatedSubnetAndVpnIdentifier(rt, rtType, cidr, vpnName));
+ LOG.debug("addSubnetAssocOperationToTx: Removed vpn {} from association rt {} rtType {} cidr {}",
+ vpnName, rt, rtType, cidr);
+ }
+ } else {
+ //Add RT-Subnet-Vpn Association
+ tx.put(LogicalDatastoreType.OPERATIONAL,
+ VpnUtil.getAssociatedSubnetAndVpnIdentifier(rt, rtType, cidr, vpnName),
+ VpnUtil.buildAssociatedSubnetAndVpn(vpnName), true);
+ }
+ }
+
+ private void deleteParentForSubnetToVpnAssocication(String rt, RouteTarget.RtType rtType,
+ String cidr, ReadWriteTransaction tx)
+ throws InterruptedException, ExecutionException {
+ //Check if you need to delete rtVal+rtType or just the subnetCidr
+ InstanceIdentifier<RouteTarget> rtIdentifier = InstanceIdentifier
+ .builder(SubnetsAssociatedToRouteTargets.class).child(RouteTarget.class,
+ new RouteTargetKey(rt, rtType)).build();
+ Optional<RouteTarget> rtToSubnetsAssociation = tx.read(LogicalDatastoreType.OPERATIONAL,
+ rtIdentifier).get();
+ if (rtToSubnetsAssociation.isPresent()) {
+ List<AssociatedSubnet> associatedSubnets = rtToSubnetsAssociation.get().getAssociatedSubnet();
+ if (associatedSubnets != null && !associatedSubnets.isEmpty()) {
+ for (Iterator<AssociatedSubnet> iterator = associatedSubnets.iterator(); iterator.hasNext(); ) {
+ if (iterator.next().getCidr().equals(cidr)) {
+ iterator.remove();
+ break;
+ }
+ }
+ if (associatedSubnets.isEmpty()) {
+ //The entire rt to subnet association is empty
+ //Delete the RouteTarget object
+ tx.delete(LogicalDatastoreType.OPERATIONAL, rtIdentifier);
+ LOG.debug("deleteParentForSubnetToVpnAssocication: Removed rt {} rtType {} from association,",
+ rt, rtType);
+ } else {
+ //Some other VPNs are also part of this rtVal, rtType combination
+ //Delete only this AssociatedSubnet
+ tx.delete(LogicalDatastoreType.OPERATIONAL, VpnUtil.getAssociatedSubnetIdentifier(rt, rtType,
+ cidr));
+ LOG.debug("deleteParentForSubnetToVpnAssocication: Removed cidr {} from association rt {}"
+ + " rtType {}", cidr, rt, rtType);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean checkForOverlappingSubnets(Uuid network, List<Subnetmap> subnetmapList, Uuid vpn,
+ Set<VpnTarget> routeTargets, List<String> failedNwList) {
+ for (int i = 0; i < subnetmapList.size(); i++) {
+ //Check if any other subnet that is already part of a different vpn with same rt, has overlapping CIDR
+ if (checkExistingSubnetWithSameRoutTargets(routeTargets, vpn, subnetmapList.get(i), failedNwList)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkExistingSubnetWithSameRoutTargets(Set<VpnTarget> routeTargets, Uuid vpn, Subnetmap subnetmap,
+ List<String> failedNwList) {
+ String cidr = String.valueOf(subnetmap.getSubnetIp());
+ boolean subnetExistsWithSameRt = doesExistingVpnsHaveConflictingSubnet(routeTargets, cidr);
+ if (subnetExistsWithSameRt) {
+ failedNwList.add(String.format("Another subnet with the same/overlapping cidr %s as subnet %s"
+ + " is already associated to a vpn with routeTargets %s. Ignoring subnet addition to vpn"
+ + " %s", cidr, subnetmap.getId().getValue(), routeTargets.toString(), vpn.getValue()));
+ }
+ return subnetExistsWithSameRt;
+ }
}
import com.google.common.base.Optional;
import com.google.common.collect.Iterators;
+import com.google.common.net.InetAddresses;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import java.math.BigInteger;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetsAssociatedToRouteTargets;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInterfaceOpData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTarget;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.RouteTargetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.AssociatedSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.AssociatedSubnetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.associated.subnet.AssociatedVpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.associated.subnet.AssociatedVpnBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnets.associated.to.route.targets.route.target.associated.subnet.AssociatedVpnKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
LOG.error("Failed to send NS packet to ELAN group, input={}", input, e);
}
}
+
+ Set<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget>
+ getRtListForVpn(String vpnName) {
+ Set<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets
+ .VpnTarget> rtList = new HashSet<>();
+ InstanceIdentifier<VpnInstance> vpnInstanceId = InstanceIdentifier.builder(VpnInstances.class)
+ .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
+ Optional<VpnInstance> vpnInstanceOptional = read(LogicalDatastoreType.CONFIGURATION, vpnInstanceId);
+ if (vpnInstanceOptional.isPresent()) {
+ org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets
+ vpnTargets = vpnInstanceOptional.get().getIpv4Family().getVpnTargets();
+ if (vpnTargets != null && vpnTargets.getVpnTarget() != null) {
+ rtList.addAll(vpnTargets.getVpnTarget());
+ }
+ }
+ else {
+ LOG.error("getRtListForVpn: Vpn Instance {} not present in config DS", vpnName);
+ }
+ return rtList;
+ }
+
+ static InstanceIdentifier<AssociatedVpn> getAssociatedSubnetAndVpnIdentifier(String rt, RouteTarget.RtType rtType,
+ String cidr, String vpnName) {
+ return InstanceIdentifier.builder(SubnetsAssociatedToRouteTargets.class).child(RouteTarget.class,
+ new RouteTargetKey(rt, rtType)).child(AssociatedSubnet.class, new AssociatedSubnetKey(cidr))
+ .child(AssociatedVpn.class, new AssociatedVpnKey(vpnName)).build();
+ }
+
+ static InstanceIdentifier<AssociatedSubnet> getAssociatedSubnetIdentifier(String rt, RouteTarget.RtType rtType,
+ String cidr) {
+ return InstanceIdentifier.builder(SubnetsAssociatedToRouteTargets.class).child(RouteTarget.class,
+ new RouteTargetKey(rt, rtType)).child(AssociatedSubnet.class, new AssociatedSubnetKey(cidr)).build();
+ }
+
+ static AssociatedVpn buildAssociatedSubnetAndVpn(String vpnName) {
+ return new AssociatedVpnBuilder().setName(vpnName).build();
+ }
+
+ static InstanceIdentifier<RouteTarget> getRouteTargetsIdentifier(String rt, RouteTarget.RtType rtType) {
+ return InstanceIdentifier.builder(SubnetsAssociatedToRouteTargets.class)
+ .child(RouteTarget.class, new RouteTargetKey(rt, rtType)).build();
+ }
+
+ Set<RouteTarget> getRouteTargetSet(Set<org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815
+ .vpn.af.config.vpntargets.VpnTarget> vpnTargets) {
+ Set<RouteTarget> routeTargetSet = new HashSet<>();
+ for (org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets
+ .VpnTarget rt : vpnTargets) {
+ String rtValue = rt.getVrfRTValue();
+ switch (rt.getVrfRTType()) {
+ case ImportExtcommunity: {
+ Optional<RouteTarget> exportRouteTargetOptional = read(LogicalDatastoreType.OPERATIONAL,
+ getRouteTargetsIdentifier(rtValue, RouteTarget.RtType.ERT));
+ if (exportRouteTargetOptional.isPresent()) {
+ routeTargetSet.add(exportRouteTargetOptional.get());
+ }
+ break;
+ }
+ case ExportExtcommunity: {
+ Optional<RouteTarget> importRouteTargetOptional = read(LogicalDatastoreType.OPERATIONAL,
+ getRouteTargetsIdentifier(rtValue, RouteTarget.RtType.IRT));
+ if (importRouteTargetOptional.isPresent()) {
+ routeTargetSet.add(importRouteTargetOptional.get());
+ }
+ break;
+ }
+ case Both: {
+ Optional<RouteTarget> exportRouteTargetOptional = read(LogicalDatastoreType.OPERATIONAL,
+ getRouteTargetsIdentifier(rtValue, RouteTarget.RtType.ERT));
+ if (exportRouteTargetOptional.isPresent()) {
+ routeTargetSet.add(exportRouteTargetOptional.get());
+ }
+ Optional<RouteTarget> importRouteTargetOptional = read(LogicalDatastoreType.OPERATIONAL,
+ getRouteTargetsIdentifier(rtValue, RouteTarget.RtType.IRT));
+ if (importRouteTargetOptional.isPresent()) {
+ routeTargetSet.add(importRouteTargetOptional.get());
+ }
+ break;
+ }
+ default:
+ LOG.error("getRouteTargetSet: Invalid rt-type {}", rt.getVrfRTType());
+ }
+ }
+ return routeTargetSet;
+ }
+
+ /*
+ TODO: (vivek/kiran): Subnet overlap in a VPN detection logic should use subnet allocation pools if available
+ rather than only CIDR.
+ Also the Subnet overlap in a VPN detection logic to be addressed for router-based-l3vpns.
+ */
+ static boolean areSubnetsOverlapping(String cidr1, String cidr2) {
+ String[] ipaddressValues1 = cidr1.split("/");
+ int address1 = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues1[0]));
+ int cidrPart1 = Integer.parseInt(ipaddressValues1[1]);
+ String[] ipaddressValues2 = cidr2.split("/");
+ int address2 = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues2[0]));
+ int cidrPart2 = Integer.parseInt(ipaddressValues2[1]);
+ int comparedValue = 0;
+ int netmask = 0;
+ if (cidrPart1 <= cidrPart2) {
+ for (int j = 0; j < cidrPart1; ++j) {
+ netmask |= (1 << 31 - j);
+ }
+ int prefix = address2 & netmask;
+ comparedValue = address1 ^ prefix;
+ } else {
+ for (int j = 0; j < cidrPart2; ++j) {
+ netmask |= (1 << 31 - j);
+ }
+ int prefix = address1 & netmask;
+ comparedValue = address2 ^ prefix;
+ }
+ if (comparedValue == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}