summaryrefslogtreecommitdiff
path: root/hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch
diff options
context:
space:
mode:
Diffstat (limited to 'hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch')
-rw-r--r--hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch335
1 files changed, 335 insertions, 0 deletions
diff --git a/hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch b/hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch
new file mode 100644
index 0000000..80c8394
--- /dev/null
+++ b/hpvd-hv-hv_kvp_daemon-Handle-IPv4-and-Ipv6-combination-fo.patch
@@ -0,0 +1,335 @@
+From d252f80372544b9b7e060b90bf5c5b0ccf6093d6 Mon Sep 17 00:00:00 2001
+From: Shradha Gupta <shradhagupta@linux.microsoft.com>
+Date: Fri, 22 Mar 2024 06:46:02 -0700
+Subject: [PATCH 3/4] hv/hv_kvp_daemon: Handle IPv4 and Ipv6 combination for
+ keyfile format
+
+RH-Author: Ani Sinha <anisinha@redhat.com>
+RH-MergeRequest: 8: hv/hv_kvp_daemon:Support for keyfile based connection profile
+RH-Jira: RHEL-9902
+RH-Acked-by: Cathy Avery <cavery@redhat.com>
+RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
+RH-Commit: [3/4] e164b6951b873467f8c87e0d01b1fd89326aa64e (anisinha/centos-hyperv-daemons)
+
+If the network configuration strings are passed as a combination of IPv4
+and IPv6 addresses, the current KVP daemon does not handle processing for
+the keyfile configuration format.
+With these changes, the keyfile config generation logic scans through the
+list twice to generate IPv4 and IPv6 sections for the configuration files
+to handle this support.
+
+Testcases ran:Rhel 9, Hyper-V VMs
+ (IPv4 only, IPv6 only, IPv4 and IPv6 combination)
+
+Cherry-picked from Linux kernel upstream commit
+f971f6dd3742d2 ("hv/hv_kvp_daemon: Handle IPv4 and Ipv6 combination for keyfile format")
+Co-developed-by: Ani Sinha <anisinha@redhat.com>
+Signed-off-by: Ani Sinha <anisinha@redhat.com>
+Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
+Reviewed-by: Easwar Hariharan <eahariha@linux.microsoft.com>
+Tested-by: Ani Sinha <anisinha@redhat.com>
+Reviewed-by: Ani Sinha <anisinha@redhat.com>
+Link: https://lore.kernel.org/r/1711115162-11629-1-git-send-email-shradhagupta@linux.microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Message-ID: <1711115162-11629-1-git-send-email-shradhagupta@linux.microsoft.com>
+---
+ hv_kvp_daemon.c | 213 ++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 172 insertions(+), 41 deletions(-)
+
+diff --git a/hv_kvp_daemon.c b/hv_kvp_daemon.c
+index 2f1862e..aa350d8 100644
+--- a/hv_kvp_daemon.c
++++ b/hv_kvp_daemon.c
+@@ -76,6 +76,12 @@ enum {
+ DNS
+ };
+
++enum {
++ IPV4 = 1,
++ IPV6,
++ IP_TYPE_MAX
++};
++
+ static int in_hand_shake;
+
+ static char *os_name = "";
+@@ -102,6 +108,11 @@ static struct utsname uts_buf;
+
+ #define MAX_FILE_NAME 100
+ #define ENTRIES_PER_BLOCK 50
++/*
++ * Change this entry if the number of addresses increases in future
++ */
++#define MAX_IP_ENTRIES 64
++#define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
+
+ struct kvp_record {
+ char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
+ return 0;
+ }
+
++int ip_version_check(const char *input_addr)
++{
++ struct in6_addr addr;
++
++ if (inet_pton(AF_INET, input_addr, &addr))
++ return IPV4;
++ else if (inet_pton(AF_INET6, input_addr, &addr))
++ return IPV6;
++
++ return -EINVAL;
++}
++
+ /*
+ * Only IPv4 subnet strings needs to be converted to plen
+ * For IPv6 the subnet is already privided in plen format
+@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
+ return plen;
+ }
+
++static int process_dns_gateway_nm(FILE *f, char *ip_string, int type,
++ int ip_sec)
++{
++ char addr[INET6_ADDRSTRLEN], *output_str;
++ int ip_offset = 0, error = 0, ip_ver;
++ char *param_name;
++
++ if (type == DNS)
++ param_name = "dns";
++ else if (type == GATEWAY)
++ param_name = "gateway";
++ else
++ return -EINVAL;
++
++ output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char));
++ if (!output_str)
++ return -ENOMEM;
++
++ while (1) {
++ memset(addr, 0, sizeof(addr));
++
++ if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
++ (MAX_IP_ADDR_SIZE * 2)))
++ break;
++
++ ip_ver = ip_version_check(addr);
++ if (ip_ver < 0)
++ continue;
++
++ if ((ip_ver == IPV4 && ip_sec == IPV4) ||
++ (ip_ver == IPV6 && ip_sec == IPV6)) {
++ /*
++ * do a bound check to avoid out-of bound writes
++ */
++ if ((OUTSTR_BUF_SIZE - strlen(output_str)) >
++ (strlen(addr) + 1)) {
++ strncat(output_str, addr,
++ OUTSTR_BUF_SIZE -
++ strlen(output_str) - 1);
++ strncat(output_str, ",",
++ OUTSTR_BUF_SIZE -
++ strlen(output_str) - 1);
++ }
++ } else {
++ continue;
++ }
++ }
++
++ if (strlen(output_str)) {
++ /*
++ * This is to get rid of that extra comma character
++ * in the end of the string
++ */
++ output_str[strlen(output_str) - 1] = '\0';
++ error = fprintf(f, "%s=%s\n", param_name, output_str);
++ }
++
++ free(output_str);
++ return error;
++}
++
+ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
+- int is_ipv6)
++ int ip_sec)
+ {
+ char addr[INET6_ADDRSTRLEN];
+ char subnet_addr[INET6_ADDRSTRLEN];
+- int error, i = 0;
++ int error = 0, i = 0;
+ int ip_offset = 0, subnet_offset = 0;
+- int plen;
++ int plen, ip_ver;
+
+ memset(addr, 0, sizeof(addr));
+ memset(subnet_addr, 0, sizeof(subnet_addr));
+@@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
+ subnet_addr,
+ (MAX_IP_ADDR_SIZE *
+ 2))) {
+- if (!is_ipv6)
++ ip_ver = ip_version_check(addr);
++ if (ip_ver < 0)
++ continue;
++
++ if (ip_ver == IPV4 && ip_sec == IPV4)
+ plen = kvp_subnet_to_plen((char *)subnet_addr);
+- else
++ else if (ip_ver == IPV6 && ip_sec == IPV6)
+ plen = atoi(subnet_addr);
++ else
++ continue;
+
+ if (plen < 0)
+ return plen;
+@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
+ memset(subnet_addr, 0, sizeof(subnet_addr));
+ }
+
+- return 0;
++ return error;
+ }
+
+ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
+ {
+- int error = 0;
++ int error = 0, ip_ver;
+ char if_filename[PATH_MAX];
+ char nm_filename[PATH_MAX];
+ FILE *ifcfg_file, *nmfile;
+ char cmd[PATH_MAX];
+- int is_ipv6 = 0;
+ char *mac_addr;
+ int str_len;
+
+@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
+ if (error)
+ goto setval_error;
+
+- if (new_val->addr_family & ADDR_FAMILY_IPV6) {
+- error = fprintf(nmfile, "\n[ipv6]\n");
+- if (error < 0)
+- goto setval_error;
+- is_ipv6 = 1;
+- } else {
+- error = fprintf(nmfile, "\n[ipv4]\n");
+- if (error < 0)
+- goto setval_error;
+- }
+-
+ /*
+ * Now we populate the keyfile format
++ *
++ * The keyfile format expects the IPv6 and IPv4 configuration in
++ * different sections. Therefore we iterate through the list twice,
++ * once to populate the IPv4 section and the next time for IPv6
+ */
++ ip_ver = IPV4;
++ do {
++ if (ip_ver == IPV4) {
++ error = fprintf(nmfile, "\n[ipv4]\n");
++ if (error < 0)
++ goto setval_error;
++ } else {
++ error = fprintf(nmfile, "\n[ipv6]\n");
++ if (error < 0)
++ goto setval_error;
++ }
+
+- if (new_val->dhcp_enabled) {
+- error = kvp_write_file(nmfile, "method", "", "auto");
+- if (error < 0)
+- goto setval_error;
+- } else {
+- error = kvp_write_file(nmfile, "method", "", "manual");
++ /*
++ * Write the configuration for ipaddress, netmask, gateway and
++ * name services
++ */
++ error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
++ (char *)new_val->sub_net,
++ ip_ver);
+ if (error < 0)
+ goto setval_error;
+- }
+
+- /*
+- * Write the configuration for ipaddress, netmask, gateway and
+- * name services
+- */
+- error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
+- (char *)new_val->sub_net, is_ipv6);
+- if (error < 0)
+- goto setval_error;
++ /*
++ * As dhcp_enabled is only valid for ipv4, we do not set dhcp
++ * methods for ipv6 based on dhcp_enabled flag.
++ *
++ * For ipv4, set method to manual only when dhcp_enabled is
++ * false and specific ipv4 addresses are configured. If neither
++ * dhcp_enabled is true and no ipv4 addresses are configured,
++ * set method to 'disabled'.
++ *
++ * For ipv6, set method to manual when we configure ipv6
++ * addresses. Otherwise set method to 'auto' so that SLAAC from
++ * RA may be used.
++ */
++ if (ip_ver == IPV4) {
++ if (new_val->dhcp_enabled) {
++ error = kvp_write_file(nmfile, "method", "",
++ "auto");
++ if (error < 0)
++ goto setval_error;
++ } else if (error) {
++ error = kvp_write_file(nmfile, "method", "",
++ "manual");
++ if (error < 0)
++ goto setval_error;
++ } else {
++ error = kvp_write_file(nmfile, "method", "",
++ "disabled");
++ if (error < 0)
++ goto setval_error;
++ }
++ } else if (ip_ver == IPV6) {
++ if (error) {
++ error = kvp_write_file(nmfile, "method", "",
++ "manual");
++ if (error < 0)
++ goto setval_error;
++ } else {
++ error = kvp_write_file(nmfile, "method", "",
++ "auto");
++ if (error < 0)
++ goto setval_error;
++ }
++ }
+
+- /* we do not want ipv4 addresses in ipv6 section and vice versa */
+- if (is_ipv6 != is_ipv4((char *)new_val->gate_way)) {
+- error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way);
++ error = process_dns_gateway_nm(nmfile,
++ (char *)new_val->gate_way,
++ GATEWAY, ip_ver);
+ if (error < 0)
+ goto setval_error;
+- }
+
+- if (is_ipv6 != is_ipv4((char *)new_val->dns_addr)) {
+- error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr);
++ error = process_dns_gateway_nm(nmfile,
++ (char *)new_val->dns_addr, DNS,
++ ip_ver);
+ if (error < 0)
+ goto setval_error;
+- }
++
++ ip_ver++;
++ } while (ip_ver < IP_TYPE_MAX);
++
+ fclose(nmfile);
+ fclose(ifcfg_file);
+
+--
+2.39.3
+