Commit b711538a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-fixes-signed-20231009' of...

Merge tag 'hyperv-fixes-signed-20231009' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv fixes from Wei Liu:

 - fixes for Hyper-V VTL code (Saurabh Sengar and Olaf Hering)

 - fix hv_kvp_daemon to support keyfile based connection profile
   (Shradha Gupta)

* tag 'hyperv-fixes-signed-20231009' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  hv/hv_kvp_daemon:Support for keyfile based connection profile
  hyperv: reduce size of ms_hyperv_info
  x86/hyperv: Add common print prefix "Hyper-V" in hv_init
  x86/hyperv: Remove hv_vtl_early_init initcall
  x86/hyperv: Restrict get_vtl to only VTL platforms
parents 832b5d0b 42999c90
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* Author : K. Y. Srinivasan <kys@microsoft.com> * Author : K. Y. Srinivasan <kys@microsoft.com>
*/ */
#define pr_fmt(fmt) "Hyper-V: " fmt
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
...@@ -191,7 +193,7 @@ void set_hv_tscchange_cb(void (*cb)(void)) ...@@ -191,7 +193,7 @@ void set_hv_tscchange_cb(void (*cb)(void))
struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
if (!hv_reenlightenment_available()) { if (!hv_reenlightenment_available()) {
pr_warn("Hyper-V: reenlightenment support is unavailable\n"); pr_warn("reenlightenment support is unavailable\n");
return; return;
} }
...@@ -394,6 +396,7 @@ static void __init hv_get_partition_id(void) ...@@ -394,6 +396,7 @@ static void __init hv_get_partition_id(void)
local_irq_restore(flags); local_irq_restore(flags);
} }
#if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
static u8 __init get_vtl(void) static u8 __init get_vtl(void)
{ {
u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_REGISTERS; u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_REGISTERS;
...@@ -416,13 +419,16 @@ static u8 __init get_vtl(void) ...@@ -416,13 +419,16 @@ static u8 __init get_vtl(void)
if (hv_result_success(ret)) { if (hv_result_success(ret)) {
ret = output->as64.low & HV_X64_VTL_MASK; ret = output->as64.low & HV_X64_VTL_MASK;
} else { } else {
pr_err("Failed to get VTL(%lld) and set VTL to zero by default.\n", ret); pr_err("Failed to get VTL(error: %lld) exiting...\n", ret);
ret = 0; BUG();
} }
local_irq_restore(flags); local_irq_restore(flags);
return ret; return ret;
} }
#else
static inline u8 get_vtl(void) { return 0; }
#endif
/* /*
* This function is to be invoked early in the boot sequence after the * This function is to be invoked early in the boot sequence after the
...@@ -564,7 +570,7 @@ void __init hyperv_init(void) ...@@ -564,7 +570,7 @@ void __init hyperv_init(void)
if (cpu_feature_enabled(X86_FEATURE_IBT) && if (cpu_feature_enabled(X86_FEATURE_IBT) &&
*(u32 *)hv_hypercall_pg != gen_endbr()) { *(u32 *)hv_hypercall_pg != gen_endbr()) {
setup_clear_cpu_cap(X86_FEATURE_IBT); setup_clear_cpu_cap(X86_FEATURE_IBT);
pr_warn("Hyper-V: Disabling IBT because of Hyper-V bug\n"); pr_warn("Disabling IBT because of Hyper-V bug\n");
} }
#endif #endif
...@@ -604,8 +610,10 @@ void __init hyperv_init(void) ...@@ -604,8 +610,10 @@ void __init hyperv_init(void)
hv_query_ext_cap(0); hv_query_ext_cap(0);
/* Find the VTL */ /* Find the VTL */
if (!ms_hyperv.paravisor_present && hv_isolation_type_snp()) ms_hyperv.vtl = get_vtl();
ms_hyperv.vtl = get_vtl();
if (ms_hyperv.vtl > 0) /* non default VTL */
hv_vtl_early_init();
return; return;
......
...@@ -215,7 +215,7 @@ static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip) ...@@ -215,7 +215,7 @@ static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip)
return hv_vtl_bringup_vcpu(vp_id, start_eip); return hv_vtl_bringup_vcpu(vp_id, start_eip);
} }
static int __init hv_vtl_early_init(void) int __init hv_vtl_early_init(void)
{ {
/* /*
* `boot_cpu_has` returns the runtime feature support, * `boot_cpu_has` returns the runtime feature support,
...@@ -230,4 +230,3 @@ static int __init hv_vtl_early_init(void) ...@@ -230,4 +230,3 @@ static int __init hv_vtl_early_init(void)
return 0; return 0;
} }
early_initcall(hv_vtl_early_init);
...@@ -340,8 +340,10 @@ static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; } ...@@ -340,8 +340,10 @@ static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
#ifdef CONFIG_HYPERV_VTL_MODE #ifdef CONFIG_HYPERV_VTL_MODE
void __init hv_vtl_init_platform(void); void __init hv_vtl_init_platform(void);
int __init hv_vtl_early_init(void);
#else #else
static inline void __init hv_vtl_init_platform(void) {} static inline void __init hv_vtl_init_platform(void) {}
static inline int __init hv_vtl_early_init(void) { return 0; }
#endif #endif
#include <asm-generic/mshyperv.h> #include <asm-generic/mshyperv.h>
......
...@@ -36,6 +36,7 @@ struct ms_hyperv_info { ...@@ -36,6 +36,7 @@ struct ms_hyperv_info {
u32 nested_features; u32 nested_features;
u32 max_vp_index; u32 max_vp_index;
u32 max_lp_index; u32 max_lp_index;
u8 vtl;
union { union {
u32 isolation_config_a; u32 isolation_config_a;
struct { struct {
...@@ -54,7 +55,6 @@ struct ms_hyperv_info { ...@@ -54,7 +55,6 @@ struct ms_hyperv_info {
}; };
}; };
u64 shared_gpa_boundary; u64 shared_gpa_boundary;
u8 vtl;
}; };
extern struct ms_hyperv_info ms_hyperv; extern struct ms_hyperv_info ms_hyperv;
extern bool hv_nested; extern bool hv_nested;
......
...@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type) ...@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
return 0; 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) static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
{ {
int error = 0; int error = 0;
char if_file[PATH_MAX]; char if_filename[PATH_MAX];
FILE *file; char nm_filename[PATH_MAX];
FILE *ifcfg_file, *nmfile;
char cmd[PATH_MAX]; char cmd[PATH_MAX];
int is_ipv6 = 0;
char *mac_addr; char *mac_addr;
int str_len; int str_len;
...@@ -1197,7 +1264,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) ...@@ -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 * in a given distro to configure the interface and so are free
* ignore information that may not be relevant. * 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 * HWADDR=macaddr
* DEVICE=interface name * DEVICE=interface name
...@@ -1220,6 +1287,32 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) ...@@ -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 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
* IPV6NETMASK. * 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 * The host can specify multiple ipv4 and ipv6 addresses to be
* configured for the interface. Furthermore, the configuration * configured for the interface. Furthermore, the configuration
* needs to be persistent. A subsequent GET call on the interface * 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) ...@@ -1227,14 +1320,29 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
* call. * 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", 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; return HV_E_FAIL;
} }
...@@ -1248,14 +1356,31 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) ...@@ -1248,14 +1356,31 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
goto setval_error; goto setval_error;
} }
error = kvp_write_file(file, "HWADDR", "", mac_addr); error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr);
free(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) 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) 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 * 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) ...@@ -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 * proceed to parse and pass the IPv6 information to the
* disto-specific script hv_set_ifconfig. * disto-specific script hv_set_ifconfig.
*/ */
/*
* First populate the ifcfg file format
*/
if (new_val->dhcp_enabled) { if (new_val->dhcp_enabled) {
error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp");
if (error) if (error)
goto setval_error; goto setval_error;
} else { } else {
error = kvp_write_file(file, "BOOTPROTO", "", "none"); error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none");
if (error) if (error)
goto setval_error; goto setval_error;
} }
/* error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr,
* Write the configuration for ipaddress, netmask, gateway and IPADDR);
* name servers.
*/
error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
if (error) if (error)
goto setval_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) if (error)
goto setval_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) if (error)
goto setval_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) if (error)
goto setval_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, * Now that we have populated the configuration file,
* invoke the external script to do its magic. * invoke the external script to do its magic.
*/ */
str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s", str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s %s",
"hv_set_ifconfig", if_file); "hv_set_ifconfig", if_filename, nm_filename);
/* /*
* This is a little overcautious, but it's necessary to suppress some * This is a little overcautious, but it's necessary to suppress some
* false warnings from gcc 8.0.1. * 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) ...@@ -1316,14 +1485,16 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
if (system(cmd)) { if (system(cmd)) {
syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
cmd, errno, strerror(errno)); cmd, errno, strerror(errno));
return HV_E_FAIL; return HV_E_FAIL;
} }
return 0; return 0;
setmac_error:
free(mac_addr);
setval_error: setval_error:
syslog(LOG_ERR, "Failed to write config file"); syslog(LOG_ERR, "Failed to write config file");
fclose(file); fclose(ifcfg_file);
fclose(nmfile);
return error; return error;
} }
......
...@@ -18,12 +18,12 @@ ...@@ -18,12 +18,12 @@
# #
# This example script is based on a RHEL environment. # 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 # HWADDR=macaddr
# DEVICE=interface name # DEVICE=interface name
# BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured # 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 # IPADDR0=ipaddr1
# IPADDR1=ipaddr2 # IPADDR1=ipaddr2
...@@ -41,6 +41,32 @@ ...@@ -41,6 +41,32 @@
# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
# IPV6NETMASK. # 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 # The host can specify multiple ipv4 and ipv6 addresses to be
# configured for the interface. Furthermore, the configuration # configured for the interface. Furthermore, the configuration
# needs to be persistent. A subsequent GET call on the interface # needs to be persistent. A subsequent GET call on the interface
...@@ -48,18 +74,19 @@ ...@@ -48,18 +74,19 @@
# call. # call.
# #
echo "IPV6INIT=yes" >> $1 echo "IPV6INIT=yes" >> $1
echo "NM_CONTROLLED=no" >> $1 echo "NM_CONTROLLED=no" >> $1
echo "PEERDNS=yes" >> $1 echo "PEERDNS=yes" >> $1
echo "ONBOOT=yes" >> $1 echo "ONBOOT=yes" >> $1
cp $1 /etc/sysconfig/network-scripts/ cp $1 /etc/sysconfig/network-scripts/
chmod 600 $2
interface=$(echo $2 | awk -F - '{ print $2 }')
filename="${2##*/}"
sed '/\[connection\]/a autoconnect=true' $2 > /etc/NetworkManager/system-connections/${filename}
interface=$(echo $1 | awk -F - '{ print $2 }')
/sbin/ifdown $interface 2>/dev/null /sbin/ifdown $interface 2>/dev/null
/sbin/ifup $interface 2>/dev/null /sbin/ifup $interface 2>/dev/null
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment