From nobody Wed Sep 10 23:58:54 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04ED8C6FD18 for ; Sat, 22 Apr 2023 08:40:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229625AbjDVIkE (ORCPT ); Sat, 22 Apr 2023 04:40:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51452 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229473AbjDVIkC (ORCPT ); Sat, 22 Apr 2023 04:40:02 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9A5871994; Sat, 22 Apr 2023 01:40:00 -0700 (PDT) Received: by linux.microsoft.com (Postfix, from userid 1134) id 0569E21C2545; Sat, 22 Apr 2023 01:40:00 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0569E21C2545 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1682152800; bh=VEMv19VsFYu0/sUIM41GNUHBY0LwuKMqLTFv9LCfBjE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rB8VNgiRTaa8tbB7LjOquBfI4zSk9kx1fOvK3itSJemJhlSslv5R58yOrGPQkVGeP eMDTCAu9teBork4qL42KCHvdShoPAGgrbjwx1kB12ctdj3Nws5mtmghkpEibHxedbc EdKKKStbC3BI37rZgavdcb2c1vuMXhauzUXYbTPY= From: Shradha Gupta To: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org Cc: Shradha Gupta , "K. Y. Srinivasan" , Haiyang Zhang , Stephen Hemminger , Wei Liu , Dexuan Cui , Long Li , Michael Kelley Subject: [PATCH v2] hv/hv_kvp_daemon: Add support for keyfile config based connection profile in NM Date: Sat, 22 Apr 2023 01:39:43 -0700 Message-Id: <1682152783-21787-1-git-send-email-shradhagupta@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: =?ISO-8859-1?Q?=20<=1B[200~?= =?ISO-8859-1?Q?=1B[201~>?= References: =?ISO-8859-1?Q?=20<=1B[200~?= =?ISO-8859-1?Q?=1B[201~>?= Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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) instead of ifcfg format. This configuration is stored in a temp file which is 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_se= t_ifconfig.sh Debian's implementation could be found here: https://github.com/endlessm/linux/blob/master/debian/cloud-tools/hv_set_ifc= onfig The next part of this support is to let the Distro vendors consume these modified implementations to the new configuration format. Tested-on: Rhel9, Rhel 8.6 (Hyper-V, Azure) Signed-off-by: Shradha Gupta --- Changes in v2: * Corrected the patch description to exclude bugzilla reference --- tools/hv/hv_kvp_daemon.c | 252 ++++++++++++++++-------------------- tools/hv/hv_set_ifconfig.sh | 42 +++--- 2 files changed, 136 insertions(+), 158 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 27f5e7dfc2f7..7f68f9f69fda 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -1004,46 +1004,6 @@ static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value = *kvp_ip_val) return error; } =20 -static int expand_ipv6(char *addr, int type) -{ - int ret; - struct in6_addr v6_addr; - - ret =3D inet_pton(AF_INET6, addr, &v6_addr); - - if (ret !=3D 1) { - if (type =3D=3D NETMASK) - return 1; - return 0; - } - - sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x", - (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], - (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], - (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], - (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], - (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], - (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], - (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], - (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); - - return 1; - -} - -static int is_ipv4(char *addr) -{ - int ret; - struct in_addr ipv4_addr; - - ret =3D inet_pton(AF_INET, addr, &ipv4_addr); - - if (ret =3D=3D 1) - return 1; - return 0; -} - static int parse_ip_val_buffer(char *in_buf, int *offset, char *out_buf, int out_len) { @@ -1092,80 +1052,80 @@ static int kvp_write_file(FILE *f, char *s1, char *= s2, char *s3) return 0; } =20 - -static int process_ip_string(FILE *f, char *ip_string, int type) +static int kvp_subnet_to_plen(char *subnet_addr_str) { - int error =3D 0; - char addr[INET6_ADDRSTRLEN]; - int i =3D 0; - int j =3D 0; - char str[256]; - char sub_str[13]; - int offset =3D 0; + int plen =3D 0; + struct in_addr subnet_addr4; + struct in6_addr subnet_addr6; =20 - memset(addr, 0, sizeof(addr)); + /* + * Convert subnet address to binary representation + */ + if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) =3D=3D 1) { =20 - while (parse_ip_val_buffer(ip_string, &offset, addr, - (MAX_IP_ADDR_SIZE * 2))) { + uint32_t subnet_mask =3D ntohl(subnet_addr4.s_addr); =20 - sub_str[0] =3D 0; - if (is_ipv4(addr)) { - switch (type) { - case IPADDR: - snprintf(str, sizeof(str), "%s", "IPADDR"); - break; - case NETMASK: - snprintf(str, sizeof(str), "%s", "NETMASK"); - break; - case GATEWAY: - snprintf(str, sizeof(str), "%s", "GATEWAY"); - break; - case DNS: - snprintf(str, sizeof(str), "%s", "DNS"); - break; - } + while (subnet_mask & 0x80000000) { =20 - if (type =3D=3D DNS) { - snprintf(sub_str, sizeof(sub_str), "%d", ++i); - } else if (type =3D=3D GATEWAY && i =3D=3D 0) { - ++i; - } else { - snprintf(sub_str, sizeof(sub_str), "%d", i++); - } + plen++; + subnet_mask <<=3D 1; + } + } else if (inet_pton(AF_INET6, subnet_addr_str, &subnet_addr6) =3D=3D 1) { =20 + const uint8_t *subnet_mask =3D subnet_addr6.s6_addr; + int i =3D 0; =20 - } else if (expand_ipv6(addr, type)) { - switch (type) { - case IPADDR: - snprintf(str, sizeof(str), "%s", "IPV6ADDR"); - break; - case NETMASK: - snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); - break; - case GATEWAY: - snprintf(str, sizeof(str), "%s", - "IPV6_DEFAULTGW"); - break; - case DNS: - snprintf(str, sizeof(str), "%s", "DNS"); - break; - } + while (i < 16 && subnet_mask[i] =3D=3D 0xff) { =20 - if (type =3D=3D DNS) { - snprintf(sub_str, sizeof(sub_str), "%d", ++i); - } else if (j =3D=3D 0) { - ++j; - } else { - snprintf(sub_str, sizeof(sub_str), "_%d", j++); + plen +=3D 8; + i++; + } + if (i < 16) { + + uint8_t mask_byte =3D subnet_mask[i]; + + while (mask_byte & 0x80) { + + plen++; + mask_byte <<=3D 1; } - } else { - return HV_INVALIDARG; } + } else { + return -1; + } =20 - error =3D kvp_write_file(f, str, sub_str, addr); - if (error) + return plen; +} + +static int process_ip_string(FILE *f, char *ip_string, char *subnet) +{ + int error =3D 0; + char addr[INET6_ADDRSTRLEN]; + char subnet_addr[INET6_ADDRSTRLEN]; + int i =3D 0; + int ip_offset =3D 0, subnet_offset =3D 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))) { + + plen =3D kvp_subnet_to_plen((char *)subnet_addr); + if (plen < 0) + return plen; + + error =3D fprintf(f, "address%d=3D%s/%d\n", ++i, (char *)addr, + plen); + if (error < 0) return error; + memset(addr, 0, sizeof(addr)); + memset(subnet_addr, 0, sizeof(subnet_addr)); } =20 return 0; @@ -1199,26 +1159,29 @@ static int kvp_set_ip_info(char *if_name, struct hv= _kvp_ipaddr_value *new_val) * * Here is the format of the ip configuration file: * - * HWADDR=3Dmacaddr - * DEVICE=3Dinterface name - * BOOTPROTO=3D (where is "dhcp" if DHCP is configur= ed - * or "none" if no boot-time protocol should be use= d) + * [ethernet] + * mac-address=3Dmacaddr + * [connection] + * interface-name=3Dinterface name + * + * [ipv4] + * method=3D (where is "auto" if DHCP is configured + * or "manual" if no boot-time protocol should be u= sed) * - * IPADDR0=3Dipaddr1 - * IPADDR1=3Dipaddr2 - * IPADDRx=3Dipaddry (where y =3D x + 1) + * address1=3Dipaddr1/plen + * address2=3Dipaddr2/plen * - * NETMASK0=3Dnetmask1 - * NETMASKx=3Dnetmasky (where y =3D x + 1) + * gateway=3Dgateway1;gateway2 * - * GATEWAY=3Dipaddr1 - * GATEWAYx=3Dipaddry (where y =3D x + 1) + * dns=3Ddns1;dns2 * - * DNSx=3Dipaddrx (where first DNS address is tagged as DNS1 etc) + * [ipv6] + * address1=3Dipaddr1/plen + * address2=3Dipaddr2/plen * - * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be - * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as - * IPV6NETMASK. + * gateway=3Dgateway1;gateway2 + * + * dns=3Ddns1;dns2 * * The host can specify multiple ipv4 and ipv6 addresses to be * configured for the interface. Furthermore, the configuration @@ -1248,12 +1211,20 @@ static int kvp_set_ip_info(char *if_name, struct hv= _kvp_ipaddr_value *new_val) goto setval_error; } =20 - error =3D kvp_write_file(file, "HWADDR", "", mac_addr); - free(mac_addr); + error =3D fprintf(file, "\n[connection]\n"); + if (error < 0) + goto setval_error; + + error =3D kvp_write_file(file, "interface-name", "", if_name); if (error) goto setval_error; =20 - error =3D kvp_write_file(file, "DEVICE", "", if_name); + error =3D fprintf(file, "\n[ethernet]\n"); + if (error < 0) + goto setval_error; + + error =3D kvp_write_file(file, "mac-address", "", mac_addr); + free(mac_addr); if (error) goto setval_error; =20 @@ -1263,36 +1234,43 @@ 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. */ - if (new_val->dhcp_enabled) { - error =3D kvp_write_file(file, "BOOTPROTO", "", "dhcp"); - if (error) - goto setval_error; + if (new_val->addr_family =3D=3D ADDR_FAMILY_IPV6) { =20 + error =3D fprintf(file, "\n[ipv6]\n"); + if (error < 0) + goto setval_error; } else { - error =3D kvp_write_file(file, "BOOTPROTO", "", "none"); - if (error) + + error =3D fprintf(file, "\n[ipv4]\n"); + if (error < 0) goto setval_error; + + if (new_val->dhcp_enabled) { + error =3D kvp_write_file(file, "method", "", "auto"); + if (error < 0) + goto setval_error; + } else { + error =3D kvp_write_file(file, "method", "", "manual"); + if (error < 0) + goto setval_error; + } } =20 /* * Write the configuration for ipaddress, netmask, gateway and - * name servers. + * name services */ - - error =3D process_ip_string(file, (char *)new_val->ip_addr, IPADDR); - if (error) + error =3D process_ip_string(file, (char *)new_val->ip_addr, + (char *)new_val->sub_net); + if (error < 0) goto setval_error; =20 - error =3D process_ip_string(file, (char *)new_val->sub_net, NETMASK); - if (error) + error =3D fprintf(file, "gateway=3D%s\n", (char *)new_val->gate_way); + if (error < 0) goto setval_error; =20 - error =3D process_ip_string(file, (char *)new_val->gate_way, GATEWAY); - if (error) - goto setval_error; - - error =3D process_ip_string(file, (char *)new_val->dns_addr, DNS); - if (error) + error =3D fprintf(file, "dns=3D%s\n", (char *)new_val->dns_addr); + if (error < 0) goto setval_error; =20 fclose(file); diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh index d10fe35b7f25..22238767ef7e 100755 --- a/tools/hv/hv_set_ifconfig.sh +++ b/tools/hv/hv_set_ifconfig.sh @@ -20,26 +20,29 @@ # # Here is the format of the ip configuration file: # -# HWADDR=3Dmacaddr -# DEVICE=3Dinterface name -# BOOTPROTO=3D (where is "dhcp" if DHCP is configured -# or "none" if no boot-time protocol should be used) +# [ethernet] +# mac-address=3Dmacaddr +# [connection] +# interface-name=3Dinterface name # -# IPADDR0=3Dipaddr1 -# IPADDR1=3Dipaddr2 -# IPADDRx=3Dipaddry (where y =3D x + 1) +# [ipv4] +# method=3D (where is "auto" if DHCP is configured +# or "manual" if no boot-time protocol should be use= d) # -# NETMASK0=3Dnetmask1 -# NETMASKx=3Dnetmasky (where y =3D x + 1) +# address1=3Dipaddr1/plen +# address=3Dipaddr2/plen # -# GATEWAY=3Dipaddr1 -# GATEWAYx=3Dipaddry (where y =3D x + 1) +# gateway=3Dgateway1;gateway2 # -# DNSx=3Dipaddrx (where first DNS address is tagged as DNS1 etc) +# dns=3Ddns1; # -# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be -# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as -# IPV6NETMASK. +# [ipv6] +# address1=3Dipaddr1/plen +# address2=3Dipaddr1/plen +# +# gateway=3Dgateway1;gateway2 +# +# dns=3Ddns1;dns2 # # The host can specify multiple ipv4 and ipv6 addresses to be # configured for the interface. Furthermore, the configuration @@ -50,13 +53,10 @@ =20 =20 =20 -echo "IPV6INIT=3Dyes" >> $1 -echo "NM_CONTROLLED=3Dno" >> $1 -echo "PEERDNS=3Dyes" >> $1 -echo "ONBOOT=3Dyes" >> $1 - +sed '/\[connection]\/a autoconnect=3Dtrue' $1 =20 -cp $1 /etc/sysconfig/network-scripts/ +chmod 600 $1 +cp $1 /etc/NetworkManager/system-connections/ =20 =20 interface=3D$(echo $1 | awk -F - '{ print $2 }') --=20 2.37.2