diff options
Diffstat (limited to 'hpvd-hv-hv_kvp_daemon-Support-for-keyfile-based-connectio.patch')
-rw-r--r-- | hpvd-hv-hv_kvp_daemon-Support-for-keyfile-based-connectio.patch | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/hpvd-hv-hv_kvp_daemon-Support-for-keyfile-based-connectio.patch b/hpvd-hv-hv_kvp_daemon-Support-for-keyfile-based-connectio.patch new file mode 100644 index 0000000..1bbad06 --- /dev/null +++ b/hpvd-hv-hv_kvp_daemon-Support-for-keyfile-based-connectio.patch @@ -0,0 +1,426 @@ +From 626a1af79f67bd9150dd6ff496d0dbbfb93bc320 Mon Sep 17 00:00:00 2001 +From: Shradha Gupta <shradhagupta@linux.microsoft.com> +Date: Mon, 9 Oct 2023 03:38:40 -0700 +Subject: [PATCH 1/4] hv/hv_kvp_daemon:Support for keyfile based connection + profile + +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: [1/4] 0cb079b0cc30bef47bddd193e262dfa52b7f2874 (anisinha/centos-hyperv-daemons) + +Ifcfg config file support in NetworkManger is deprecated. This patch +provides support for the new keyfile config format for connection +profiles in NetworkManager. The patch modifies the hv_kvp_daemon code +to generate the new network configuration in keyfile +format(.ini-style format) along with a ifcfg format configuration. +The ifcfg format configuration is also retained to support easy +backward compatibility for distro vendors. These configurations are +stored in temp files which are further translated using the +hv_set_ifconfig.sh script. This script is implemented by individual +distros based on the network management commands supported. +For example, RHEL's implementation could be found here: +https://gitlab.com/redhat/centos-stream/src/hyperv-daemons/-/blob/c9s/hv_set_ifconfig.sh +Debian's implementation could be found here: +https://github.com/endlessm/linux/blob/master/debian/cloud-tools/hv_set_ifconfig + +The next part of this support is to let the Distro vendors consume +these modified implementations to the new configuration format. + +Cherry-picked from upstream linux +kernel commit 42999c904612 ("hv/hv_kvp_daemon:Support for keyfile based connection profile") +Tested-on: Rhel9(Hyper-V, Azure)(nm and ifcfg files verified) +Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com> +Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com> +Reviewed-by: Ani Sinha <anisinha@redhat.com> +Signed-off-by: Wei Liu <wei.liu@kernel.org> +Link: https://lore.kernel.org/r/1696847920-31125-1-git-send-email-shradhagupta@linux.microsoft.com +--- + hv_kvp_daemon.c | 233 +++++++++++++++++++++++++++++++++++++++------ + hv_set_ifconfig.sh | 30 +++++- + 2 files changed, 230 insertions(+), 33 deletions(-) + +diff --git a/hv_kvp_daemon.c b/hv_kvp_daemon.c +index 2ad9af3..d50b4e8 100644 +--- a/hv_kvp_daemon.c ++++ b/hv_kvp_daemon.c +@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type) + return 0; + } + ++/* ++ * Only IPv4 subnet strings needs to be converted to plen ++ * For IPv6 the subnet is already privided in plen format ++ */ ++static int kvp_subnet_to_plen(char *subnet_addr_str) ++{ ++ int plen = 0; ++ struct in_addr subnet_addr4; ++ ++ /* ++ * Convert subnet address to binary representation ++ */ ++ if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) { ++ uint32_t subnet_mask = ntohl(subnet_addr4.s_addr); ++ ++ while (subnet_mask & 0x80000000) { ++ plen++; ++ subnet_mask <<= 1; ++ } ++ } else { ++ return -1; ++ } ++ ++ return plen; ++} ++ ++static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet, ++ int is_ipv6) ++{ ++ char addr[INET6_ADDRSTRLEN]; ++ char subnet_addr[INET6_ADDRSTRLEN]; ++ int error, i = 0; ++ int ip_offset = 0, subnet_offset = 0; ++ int plen; ++ ++ memset(addr, 0, sizeof(addr)); ++ memset(subnet_addr, 0, sizeof(subnet_addr)); ++ ++ while (parse_ip_val_buffer(ip_string, &ip_offset, addr, ++ (MAX_IP_ADDR_SIZE * 2)) && ++ parse_ip_val_buffer(subnet, ++ &subnet_offset, ++ subnet_addr, ++ (MAX_IP_ADDR_SIZE * ++ 2))) { ++ if (!is_ipv6) ++ plen = kvp_subnet_to_plen((char *)subnet_addr); ++ else ++ plen = atoi(subnet_addr); ++ ++ if (plen < 0) ++ return plen; ++ ++ error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr, ++ plen); ++ if (error < 0) ++ return error; ++ ++ memset(addr, 0, sizeof(addr)); ++ memset(subnet_addr, 0, sizeof(subnet_addr)); ++ } ++ ++ return 0; ++} ++ + static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + { + int error = 0; +- char if_file[PATH_MAX]; +- FILE *file; ++ 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; + +@@ -1197,7 +1264,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + * in a given distro to configure the interface and so are free + * ignore information that may not be relevant. + * +- * Here is the format of the ip configuration file: ++ * Here is the ifcfg format of the ip configuration file: + * + * HWADDR=macaddr + * DEVICE=interface name +@@ -1220,6 +1287,32 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as + * IPV6NETMASK. + * ++ * Here is the keyfile format of the ip configuration file: ++ * ++ * [ethernet] ++ * mac-address=macaddr ++ * [connection] ++ * interface-name=interface name ++ * ++ * [ipv4] ++ * method=<protocol> (where <protocol> is "auto" if DHCP is configured ++ * or "manual" if no boot-time protocol should be used) ++ * ++ * address1=ipaddr1/plen ++ * address2=ipaddr2/plen ++ * ++ * gateway=gateway1;gateway2 ++ * ++ * dns=dns1;dns2 ++ * ++ * [ipv6] ++ * address1=ipaddr1/plen ++ * address2=ipaddr2/plen ++ * ++ * gateway=gateway1;gateway2 ++ * ++ * dns=dns1;dns2 ++ * + * The host can specify multiple ipv4 and ipv6 addresses to be + * configured for the interface. Furthermore, the configuration + * needs to be persistent. A subsequent GET call on the interface +@@ -1227,14 +1320,29 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + * call. + */ + +- snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, +- "/ifcfg-", if_name); ++ /* ++ * We are populating both ifcfg and nmconnection files ++ */ ++ snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC, ++ "/ifcfg-", if_name); + +- file = fopen(if_file, "w"); ++ ifcfg_file = fopen(if_filename, "w"); + +- if (file == NULL) { ++ if (!ifcfg_file) { + syslog(LOG_ERR, "Failed to open config file; error: %d %s", +- errno, strerror(errno)); ++ errno, strerror(errno)); ++ return HV_E_FAIL; ++ } ++ ++ snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC, ++ "/", if_name, ".nmconnection"); ++ ++ nmfile = fopen(nm_filename, "w"); ++ ++ if (!nmfile) { ++ syslog(LOG_ERR, "Failed to open config file; error: %d %s", ++ errno, strerror(errno)); ++ fclose(ifcfg_file); + return HV_E_FAIL; + } + +@@ -1248,14 +1356,31 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + goto setval_error; + } + +- error = kvp_write_file(file, "HWADDR", "", mac_addr); +- free(mac_addr); ++ error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr); ++ if (error < 0) ++ goto setmac_error; ++ ++ error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name); ++ if (error < 0) ++ goto setmac_error; ++ ++ error = fprintf(nmfile, "\n[connection]\n"); ++ if (error < 0) ++ goto setmac_error; ++ ++ error = kvp_write_file(nmfile, "interface-name", "", if_name); + if (error) +- goto setval_error; ++ goto setmac_error; + +- error = kvp_write_file(file, "DEVICE", "", if_name); ++ error = fprintf(nmfile, "\n[ethernet]\n"); ++ if (error < 0) ++ goto setmac_error; ++ ++ error = kvp_write_file(nmfile, "mac-address", "", mac_addr); + if (error) +- goto setval_error; ++ goto setmac_error; ++ ++ free(mac_addr); + + /* + * The dhcp_enabled flag is only for IPv4. In the case the host only +@@ -1263,47 +1388,91 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + * proceed to parse and pass the IPv6 information to the + * disto-specific script hv_set_ifconfig. + */ ++ ++ /* ++ * First populate the ifcfg file format ++ */ + if (new_val->dhcp_enabled) { +- error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); ++ error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp"); + if (error) + goto setval_error; +- + } else { +- error = kvp_write_file(file, "BOOTPROTO", "", "none"); ++ error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none"); + if (error) + goto setval_error; + } + +- /* +- * Write the configuration for ipaddress, netmask, gateway and +- * name servers. +- */ +- +- error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); ++ error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr, ++ IPADDR); + if (error) + goto setval_error; + +- error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); ++ error = process_ip_string(ifcfg_file, (char *)new_val->sub_net, ++ NETMASK); + if (error) + goto setval_error; + +- error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); ++ error = process_ip_string(ifcfg_file, (char *)new_val->gate_way, ++ GATEWAY); + if (error) + goto setval_error; + +- error = process_ip_string(file, (char *)new_val->dns_addr, DNS); ++ error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS); + if (error) + goto setval_error; + +- fclose(file); ++ 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 ++ */ ++ ++ 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"); ++ 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; ++ ++ error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way); ++ if (error < 0) ++ goto setval_error; ++ ++ error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr); ++ if (error < 0) ++ goto setval_error; ++ ++ fclose(nmfile); ++ fclose(ifcfg_file); + + /* + * Now that we have populated the configuration file, + * invoke the external script to do its magic. + */ + +- str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s", +- "hv_set_ifconfig", if_file); ++ str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s %s", ++ "hv_set_ifconfig", if_filename, nm_filename); + /* + * This is a little overcautious, but it's necessary to suppress some + * false warnings from gcc 8.0.1. +@@ -1316,14 +1485,16 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) + + if (system(cmd)) { + syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", +- cmd, errno, strerror(errno)); ++ cmd, errno, strerror(errno)); + return HV_E_FAIL; + } + return 0; +- ++setmac_error: ++ free(mac_addr); + setval_error: + syslog(LOG_ERR, "Failed to write config file"); +- fclose(file); ++ fclose(ifcfg_file); ++ fclose(nmfile); + return error; + } + +diff --git a/hv_set_ifconfig.sh b/hv_set_ifconfig.sh +index fe7fccf..35aae6f 100644 +--- a/hv_set_ifconfig.sh ++++ b/hv_set_ifconfig.sh +@@ -18,12 +18,12 @@ + # + # This example script is based on a RHEL environment. + # +-# Here is the format of the ip configuration file: ++# Here is the ifcfg format of the ip configuration file: + # + # HWADDR=macaddr + # DEVICE=interface name + # BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured +-# or "none" if no boot-time protocol should be used) ++# or "none" if no boot-time protocol should be used) + # + # IPADDR0=ipaddr1 + # IPADDR1=ipaddr2 +@@ -41,6 +41,32 @@ + # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as + # IPV6NETMASK. + # ++# Here is the keyfile format of the ip configuration file: ++# ++# [ethernet] ++# mac-address=macaddr ++# [connection] ++# interface-name=interface name ++# ++# [ipv4] ++# method=<protocol> (where <protocol> is "auto" if DHCP is configured ++# or "manual" if no boot-time protocol should be used) ++# ++# address1=ipaddr1/plen ++# address=ipaddr2/plen ++# ++# gateway=gateway1;gateway2 ++# ++# dns=dns1; ++# ++# [ipv6] ++# address1=ipaddr1/plen ++# address2=ipaddr1/plen ++# ++# gateway=gateway1;gateway2 ++# ++# dns=dns1;dns2 ++# + # The host can specify multiple ipv4 and ipv6 addresses to be + # configured for the interface. Furthermore, the configuration + # needs to be persistent. A subsequent GET call on the interface +-- +2.39.3 + |