+ static boolean isL3VpnOverVxLan(Long l3Vni) {
+ return l3Vni != null && l3Vni != 0;
+ }
+
+ static boolean isEvpnOverVxLan(Long l2Vni) { //To be used by RT2
+ return l2Vni != null && l2Vni != 0;
+ }
+
+ /**
+ * Retrieves the primary rd of a vpn instance
+ * Primary rd will be the first rd in the list of rds configured for a vpn instance
+ * If rd list is empty, primary rd will be vpn instance name
+ * Use this function only during create operation cycles. For other operations, use getVpnRd() method.
+ *
+ * @param dataBroker dataBroker service reference
+ * @param vpnName Name of the VPN
+ * @return the primary rd of the VPN
+ */
+ public static String getPrimaryRd(DataBroker dataBroker, String vpnName) {
+ // Retrieves the VPN Route Distinguisher by its Vpn instance name
+ String rd = getVpnRd(dataBroker, vpnName);
+ if (rd != null) {
+ return rd;
+ }
+ InstanceIdentifier<VpnInstance> id = getVpnInstanceIdentifier(vpnName);
+ Optional<VpnInstance> vpnInstance = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+ if (vpnInstance.isPresent()) {
+ return getPrimaryRd(vpnInstance.get());
+ }
+ return vpnName;
+ }
+
+ /**
+ * Retrieves the primary rd of a vpn instance
+ * Primary rd will be the first rd in the list of rds configured for a vpn instance
+ * If rd list is empty, primary rd will be vpn instance name
+ * Use this function only during create operation cycles. For other operations, use getVpnRd() method.
+ *
+ * @param vpnInstance Config Vpn Instance Object
+ * @return the primary rd of the VPN
+ */
+ public static String getPrimaryRd(VpnInstance vpnInstance) {
+ List<String> rds = null;
+ if (vpnInstance != null) {
+ rds = getListOfRdsFromVpnInstance(vpnInstance);
+ }
+ return rds == null || rds.isEmpty() ? vpnInstance.getVpnInstanceName() : rds.get(0);
+ }
+
+ public static boolean isBgpVpn(String vpnName, String primaryRd) {
+ return !vpnName.equals(primaryRd);
+ }
+
+ static java.util.Optional<String> allocateRdForExtraRouteAndUpdateUsedRdsMap(
+ DataBroker dataBroker, long vpnId, @Nullable Long parentVpnId, String prefix, String vpnName,
+ String nextHop, BigInteger dpnId, WriteTransaction writeOperTxn) {
+ //Check if rd is already allocated for this extraroute behind the same VM. If yes, reuse it.
+ //This is particularly useful during reboot scenarios.
+ java.util.Optional<String> allocatedRd = VpnExtraRouteHelper
+ .getRdAllocatedForExtraRoute(dataBroker, vpnId, prefix, nextHop);
+ if (allocatedRd.isPresent()) {
+ return java.util.Optional.of(allocatedRd.get());
+ }
+
+ //Check if rd is already allocated for this extraroute behind the same CSS. If yes, reuse it
+ List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, prefix);
+ for (String usedRd : usedRds) {
+ Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
+ vpnName, usedRd, prefix);
+ if (vpnExtraRoutes.isPresent()) {
+ String nextHopIp = vpnExtraRoutes.get().getNexthopIpList().get(0);
+ // In case of VPN importing the routes, the interface is not present in the VPN
+ // and has to be fetched from the VPN from which it imports
+ Optional<Prefixes> prefixToInterface =
+ getPrefixToInterface(dataBroker, parentVpnId != null ? parentVpnId : vpnId, nextHopIp);
+ if (prefixToInterface.isPresent() && dpnId.equals(prefixToInterface.get().getDpnId())) {
+ syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
+ VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHop),
+ getRdsBuilder(nextHop, usedRd).build());
+ return java.util.Optional.of(usedRd);
+ }
+ }
+ }
+ List<String> availableRds = getVpnRdsFromVpnInstanceConfig(dataBroker, vpnName);
+ String rd;
+ if (availableRds.isEmpty()) {
+ rd = dpnId.toString();
+ LOG.debug("Internal vpn {} Returning DpnId {} as rd", vpnName, rd);
+ } else {
+ LOG.trace(
+ "Removing used rds {} from available rds {} vpnid {} . prefix is {} , vpname- {}, dpnId- {},"
+ + " adj - {}", usedRds, availableRds, vpnId, prefix, vpnName, dpnId);
+ availableRds.removeAll(usedRds);
+ if (availableRds.isEmpty()) {
+ LOG.error("No rd available from VpnInstance to allocate for prefix {}", prefix);
+ return java.util.Optional.empty();
+ }
+ // If rd is not allocated for this prefix or if extra route is behind different OVS, select a new rd.
+ rd = availableRds.get(0);
+ }
+ syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
+ VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHop),
+ getRdsBuilder(nextHop, rd).build());
+ return java.util.Optional.ofNullable(rd);
+ }
+
+ static String getVpnNamePrefixKey(String vpnName, String prefix) {
+ return vpnName + VpnConstants.SEPARATOR + prefix;
+ }
+
+ static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
+ return InstanceIdentifier.builder(VpnInterfaces.class)
+ .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName))
+ .augmentation(Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
+ }
+
+ public static List<String> getIpsListFromExternalIps(List<ExternalIps> externalIps) {
+ if (externalIps == null) {
+ return Collections.emptyList();
+ }
+
+ return externalIps.stream().map(ExternalIps::getIpAddress).collect(Collectors.toList());
+ }
+
+ static void bindService(final String vpnInstanceName, final String interfaceName, DataBroker dataBroker,
+ boolean isTunnelInterface, JobCoordinator jobCoordinator) {
+ jobCoordinator.enqueueJob(interfaceName,
+ () -> {
+ WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+ BoundServices serviceInfo = isTunnelInterface
+ ? VpnUtil.getBoundServicesForTunnelInterface(vpnInstanceName, interfaceName)
+ : getBoundServicesForVpnInterface(dataBroker, vpnInstanceName, interfaceName);
+ writeTxn.put(LogicalDatastoreType.CONFIGURATION, InterfaceUtils.buildServiceId(interfaceName,
+ ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
+ serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS);
+ return Collections.singletonList(writeTxn.submit());
+ });
+ }
+
+ static BoundServices getBoundServicesForVpnInterface(DataBroker broker, String vpnName, String interfaceName) {
+ List<Instruction> instructions = new ArrayList<>();
+ int instructionKey = 0;
+ final long vpnId = VpnUtil.getVpnId(broker, vpnName);
+ List<Action> actions = Collections.singletonList(
+ new ActionRegLoad(0, VpnConstants.VPN_REG_ID, 0, VpnConstants.VPN_ID_LENGTH, vpnId).buildAction());
+ instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
+ instructions.add(
+ MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
+ MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
+ instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_GW_MAC_TABLE,
+ ++instructionKey));
+ BoundServices serviceInfo = InterfaceUtils.getBoundServices(
+ String.format("%s.%s.%s", "vpn", vpnName, interfaceName),
+ ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX),
+ VpnConstants.DEFAULT_FLOW_PRIORITY, NwConstants.COOKIE_VM_INGRESS_TABLE, instructions);
+ return serviceInfo;
+ }
+
+ static BoundServices getBoundServicesForTunnelInterface(String vpnName, String interfaceName) {
+ int instructionKey = 0;
+ List<Instruction> instructions = new ArrayList<>();
+ instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(
+ NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, ++instructionKey));
+ BoundServices serviceInfo = InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",
+ vpnName, interfaceName),
+ ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+ NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE), VpnConstants.DEFAULT_FLOW_PRIORITY,
+ NwConstants.COOKIE_VM_INGRESS_TABLE, instructions);
+ return serviceInfo;
+ }
+
+ static void unbindService(DataBroker dataBroker, final String vpnInterfaceName, boolean isInterfaceStateDown,
+ JobCoordinator jobCoordinator) {
+ if (!isInterfaceStateDown) {
+ jobCoordinator.enqueueJob(vpnInterfaceName,
+ () -> {
+ WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+ writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
+ InterfaceUtils.buildServiceId(vpnInterfaceName,
+ ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+ NwConstants.L3VPN_SERVICE_INDEX)));
+
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(writeTxn.submit());
+ return futures;
+ });
+ }
+ }
+
+ static FlowEntity buildFlowEntity(BigInteger dpnId, short tableId, String flowId) {
+ return new FlowEntityBuilder()
+ .setDpnId(dpnId)
+ .setTableId(tableId)
+ .setFlowId(flowId)
+ .build();
+ }
+
+ static VrfEntryBase.EncapType getEncapType(boolean isVxLan) {
+ return isVxLan ? VrfEntryBase.EncapType.Vxlan : VrfEntryBase.EncapType.Mplsgre;
+ }
+
+ static org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets
+ .Subnets getExternalSubnet(DataBroker dataBroker, Uuid subnetId) {
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets
+ .Subnets> subnetsIdentifier = InstanceIdentifier.builder(ExternalSubnets.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets
+ .Subnets.class, new SubnetsKey(subnetId)).build();
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets>
+ optionalSubnets = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
+ return optionalSubnets.isPresent() ? optionalSubnets.get() : null;
+ }
+
+ static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
+ Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId.getValue());
+ if (externalRouter != null && externalRouter.getExternalIps() != null) {
+ for (ExternalIps externalIp : externalRouter.getExternalIps()) {
+ if (externalIp.getIpAddress().equals(ip)) {
+ return externalIp.getSubnetId();
+ }
+ }
+ }
+ return null;
+ }
+
+ static boolean isExternalSubnetVpn(String vpnName, String subnetId) {
+ return vpnName.equals(subnetId);
+ }
+
+ static Boolean getIsExternal(Network network) {
+ return network.getAugmentation(NetworkL3Extension.class) != null
+ && network.getAugmentation(NetworkL3Extension.class).isExternal();
+ }
+
+ @SuppressWarnings("checkstyle:linelength")
+ static Network getNeutronNetwork(DataBroker broker, Uuid networkId) {
+ Network network = null;
+ LOG.debug("getNeutronNetwork for {}", networkId.getValue());
+ InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class).child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks.class).child(
+ Network.class, new NetworkKey(networkId));
+ Optional<Network> net = read(broker, LogicalDatastoreType.CONFIGURATION, inst);
+ if (net.isPresent()) {
+ network = net.get();
+ }
+ return network;
+ }
+
+ public static boolean isEligibleForBgp(String rd, String vpnName, BigInteger dpnId, String networkName) {
+ if (rd != null) {
+ if (vpnName != null && rd.equals(vpnName)) {
+ return false;
+ }
+ if (dpnId != null && rd.equals(dpnId.toString())) {
+ return false;
+ }
+ if (networkName != null && rd.equals(networkName)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ static String getFibFlowRef(BigInteger dpnId, short tableId, String vpnName, int priority) {
+ return VpnConstants.FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
+ + NwConstants.FLOWID_SEPARATOR + vpnName + NwConstants.FLOWID_SEPARATOR + priority;
+ }
+
+ static void removeExternalTunnelDemuxFlows(String vpnName, DataBroker broker, IMdsalApiManager mdsalManager) {
+ LOG.info("Removing external tunnel flows for vpn {}", vpnName);
+ for (BigInteger dpnId: NWUtil.getOperativeDPNs(broker)) {
+ LOG.debug("Removing external tunnel flows for vpn {} from dpn {}", vpnName, dpnId);
+ String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+ vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
+ FlowEntity flowEntity = VpnUtil.buildFlowEntity(dpnId,
+ NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef);
+ mdsalManager.removeFlow(flowEntity);
+ }
+ }
+
+ public static boolean isVpnPendingDelete(DataBroker broker, String rd) {
+ VpnInstanceOpDataEntry vpnInstanceOpData = getVpnInstanceOpData(broker, rd);
+ boolean isVpnPendingDelete = false;
+ if (vpnInstanceOpData == null
+ || vpnInstanceOpData.getVpnState() == VpnInstanceOpDataEntry.VpnState.PendingDelete) {
+ isVpnPendingDelete = true;
+ }
+ return isVpnPendingDelete;
+ }
+
+ public static List<VpnInstanceOpDataEntry> getVpnsImportingMyRoute(final DataBroker broker, final String vpnName) {
+ List<VpnInstanceOpDataEntry> vpnsToImportRoute = new ArrayList<>();
+
+ final String vpnRd = getVpnRd(broker, vpnName);
+ if (vpnRd == null) {
+ LOG.error("getVpnsImportingMyRoute: vpn {} not present in config DS.", vpnName);
+ return vpnsToImportRoute;
+ }
+ final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, vpnRd);
+ if (vpnInstanceOpDataEntry == null) {
+ LOG.error("getVpnsImportingMyRoute: Could not retrieve vpn instance op data for {}"
+ + " to check for vpns importing the routes", vpnName);
+ return vpnsToImportRoute;
+ }
+
+ Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
+ if (input.getVpnInstanceName() == null) {
+ LOG.error("getVpnsImportingMyRoute.excludeVpn: Received vpn instance with rd {} without a name.",
+ input.getVrfId());
+ return false;
+ }
+ return !input.getVpnInstanceName().equals(vpnName);
+ };
+
+ Predicate<VpnInstanceOpDataEntry> matchRTs = input -> {
+ Iterable<String> commonRTs =
+ intersection(getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ExportExtcommunity),
+ getRts(input, VpnTarget.VrfRTType.ImportExtcommunity));
+ return Iterators.size(commonRTs.iterator()) > 0;
+ };
+
+ vpnsToImportRoute = getAllVpnInstanceOpData(broker)
+ .stream()
+ .filter(excludeVpn)
+ .filter(matchRTs)
+ .collect(Collectors.toList());
+ return vpnsToImportRoute;
+ }
+
+ public static List<String> getRts(VpnInstanceOpDataEntry vpnInstance, VpnTarget.VrfRTType rtType) {
+ String name = vpnInstance.getVpnInstanceName();
+ List<String> rts = new ArrayList<>();
+ VpnTargets targets = vpnInstance.getVpnTargets();
+ if (targets == null) {
+ LOG.info("getRts: vpn targets not available for {}", name);
+ return rts;
+ }
+ List<VpnTarget> vpnTargets = targets.getVpnTarget();
+ if (vpnTargets == null) {
+ LOG.info("getRts: vpnTarget values not available for {}", name);
+ return rts;
+ }
+ for (VpnTarget target : vpnTargets) {
+ //TODO: Check for RT type is Both
+ if (target.getVrfRTType().equals(rtType) || target.getVrfRTType().equals(VpnTarget.VrfRTType.Both)) {
+ String rtValue = target.getVrfRTValue();
+ rts.add(rtValue);
+ }
+ }
+ return rts;
+ }
+
+ public static <T> Iterable<T> intersection(final Collection<T> collection1, final Collection<T> collection2) {
+ Set<T> intersection = new HashSet<>(collection1);
+ intersection.retainAll(collection2);
+ return intersection;
+ }
+
+ /** Get Subnetmap from its Uuid.
+ * @param broker the data broker for look for data
+ * @param subnetUuid the subnet's Uuid
+ * @return the Subnetmap of Uuid or null if it is not found
+ */
+ public static Subnetmap getSubnetmapFromItsUuid(DataBroker broker, Uuid subnetUuid) {
+ Subnetmap sn = null;
+ InstanceIdentifier<Subnetmap> id = buildSubnetmapIdentifier(subnetUuid);
+ Optional<Subnetmap> optionalSn = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (optionalSn.isPresent()) {
+ sn = optionalSn.get();
+ }
+ return sn;
+ }
+
+ public static boolean isSubnetPartOfVpn(Subnetmap sn, String vpnName) {
+ if (vpnName == null || sn == null || sn.getVpnId() == null) {
+ return false;
+ }
+ if (sn.getVpnId().getValue().equals(vpnName)) {
+ return true;
+ } else if (sn.getInternetVpnId() != null
+ && sn.getInternetVpnId().getValue().equals(vpnName)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isAdjacencyEligibleToVpnInternet(DataBroker dataBroker, Adjacency adjacency) {
+ // returns true if BGPVPN Internet and adjacency is IPv6, false otherwise
+ boolean adjacencyEligible = true;
+ if (adjacency.getAdjacencyType() == AdjacencyType.ExtraRoute) {
+ if (FibHelper.isIpv6Prefix(adjacency.getIpAddress())) {
+ return adjacencyEligible;
+ }
+ return false;
+ } else if (adjacency.getSubnetId() == null) {
+ return adjacencyEligible;
+ }
+ Subnetmap sn = VpnUtil.getSubnetmapFromItsUuid(
+ dataBroker, adjacency.getSubnetId());
+ if (sn != null && sn.getInternetVpnId() != null) {
+ adjacencyEligible = false;
+ }
+ return adjacencyEligible;
+ }
+
+ public static boolean isAdjacencyEligibleToVpn(DataBroker dataBroker, Adjacency adjacency,
+ String vpnName, String interfaceName) {
+ // returns true if BGPVPN Internet and adjacency is IPv6, false otherwise
+ boolean adjacencyEligible = true;
+ // if BGPVPN internet, return false if subnetmap has not internetVpnId() filled in
+ if (isBgpVpnInternet(dataBroker, vpnName)) {
+ return isAdjacencyEligibleToVpnInternet(dataBroker, adjacency);
+ }
+ return adjacencyEligible;
+ }
+
+ public static String getInternetVpnFromVpnInstanceList(DataBroker dataBroker,
+ List<VpnInstanceNames> vpnInstanceList) {
+ for (VpnInstanceNames vpnInstance : vpnInstanceList) {
+ String vpnName = vpnInstance.getVpnName();
+ if (isBgpVpnInternet(dataBroker, vpnName)) {
+ return vpnName;
+ }
+ }
+ return null;
+ }
+
+ /** Get boolean true if vpn is bgpvpn internet, false otherwise.
+ * @param dataBroker databroker for transaction
+ * @param vpnName name of the input VPN
+ * @return true or false
+ */
+ public static boolean isBgpVpnInternet(DataBroker dataBroker, String vpnName) {
+ String primaryRd = getVpnRd(dataBroker, vpnName);
+ if (primaryRd == null) {
+ LOG.error("isBgpVpnInternet VPN {}."
+ + "Primary RD not found", vpnName);
+ return false;
+ }
+ InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(primaryRd)).build();
+
+ Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
+ read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ if (!vpnInstanceOpDataEntryOptional.isPresent()) {
+ LOG.error("isBgpVpnInternet VPN {}."
+ + "VpnInstanceOpDataEntry not found", vpnName);
+ return false;
+ }
+ LOG.debug("isBgpVpnInternet VPN {}."
+ + "Successfully VpnInstanceOpDataEntry.getBgpvpnType {}",
+ vpnName, vpnInstanceOpDataEntryOptional.get().getBgpvpnType());
+ if (vpnInstanceOpDataEntryOptional.get().getBgpvpnType() == VpnInstanceOpDataEntry
+ .BgpvpnType.BGPVPNInternet) {
+ return true;
+ }
+ return false;
+ }
+
+ /**Get IpVersionChoice from String IP like x.x.x.x or an representation IPv6.
+ * @param ipAddress String of an representation IP address V4 or V6
+ * @return the IpVersionChoice of the version or IpVersionChoice.UNDEFINED otherwise
+ */
+ public static IpVersionChoice getIpVersionFromString(String ipAddress) {
+ IpVersionChoice ipchoice = IpVersionChoice.UNDEFINED;
+ int indexIpAddress = ipAddress.indexOf('/');
+ if (indexIpAddress >= 0) {
+ ipAddress = ipAddress.substring(0, indexIpAddress);
+ }
+ try {
+ InetAddress address = InetAddress.getByName(ipAddress);
+ if (address instanceof Inet4Address) {
+ return IpVersionChoice.IPV4;
+ } else if (address instanceof Inet6Address) {
+ return IpVersionChoice.IPV6;
+ }
+ } catch (UnknownHostException | SecurityException e) {
+ ipchoice = IpVersionChoice.UNDEFINED;
+ }
+ return ipchoice;
+ }
+