Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+257 -50
+14 -6
arch/x86/hyperv/hv_init.c
··· 7 7 * Author : K. Y. Srinivasan <kys@microsoft.com> 8 8 */ 9 9 10 + #define pr_fmt(fmt) "Hyper-V: " fmt 11 + 10 12 #include <linux/efi.h> 11 13 #include <linux/types.h> 12 14 #include <linux/bitfield.h> ··· 193 191 struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; 194 192 195 193 if (!hv_reenlightenment_available()) { 196 - pr_warn("Hyper-V: reenlightenment support is unavailable\n"); 194 + pr_warn("reenlightenment support is unavailable\n"); 197 195 return; 198 196 } 199 197 ··· 396 394 local_irq_restore(flags); 397 395 } 398 396 397 + #if IS_ENABLED(CONFIG_HYPERV_VTL_MODE) 399 398 static u8 __init get_vtl(void) 400 399 { 401 400 u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_REGISTERS; ··· 419 416 if (hv_result_success(ret)) { 420 417 ret = output->as64.low & HV_X64_VTL_MASK; 421 418 } else { 422 - pr_err("Failed to get VTL(%lld) and set VTL to zero by default.\n", ret); 423 - ret = 0; 419 + pr_err("Failed to get VTL(error: %lld) exiting...\n", ret); 420 + BUG(); 424 421 } 425 422 426 423 local_irq_restore(flags); 427 424 return ret; 428 425 } 426 + #else 427 + static inline u8 get_vtl(void) { return 0; } 428 + #endif 429 429 430 430 /* 431 431 * This function is to be invoked early in the boot sequence after the ··· 570 564 if (cpu_feature_enabled(X86_FEATURE_IBT) && 571 565 *(u32 *)hv_hypercall_pg != gen_endbr()) { 572 566 setup_clear_cpu_cap(X86_FEATURE_IBT); 573 - pr_warn("Hyper-V: Disabling IBT because of Hyper-V bug\n"); 567 + pr_warn("Disabling IBT because of Hyper-V bug\n"); 574 568 } 575 569 #endif 576 570 ··· 610 604 hv_query_ext_cap(0); 611 605 612 606 /* Find the VTL */ 613 - if (!ms_hyperv.paravisor_present && hv_isolation_type_snp()) 614 - ms_hyperv.vtl = get_vtl(); 607 + ms_hyperv.vtl = get_vtl(); 608 + 609 + if (ms_hyperv.vtl > 0) /* non default VTL */ 610 + hv_vtl_early_init(); 615 611 616 612 return; 617 613
+1 -2
arch/x86/hyperv/hv_vtl.c
··· 215 215 return hv_vtl_bringup_vcpu(vp_id, start_eip); 216 216 } 217 217 218 - static int __init hv_vtl_early_init(void) 218 + int __init hv_vtl_early_init(void) 219 219 { 220 220 /* 221 221 * `boot_cpu_has` returns the runtime feature support, ··· 230 230 231 231 return 0; 232 232 } 233 - early_initcall(hv_vtl_early_init);
+2
arch/x86/include/asm/mshyperv.h
··· 340 340 341 341 #ifdef CONFIG_HYPERV_VTL_MODE 342 342 void __init hv_vtl_init_platform(void); 343 + int __init hv_vtl_early_init(void); 343 344 #else 344 345 static inline void __init hv_vtl_init_platform(void) {} 346 + static inline int __init hv_vtl_early_init(void) { return 0; } 345 347 #endif 346 348 347 349 #include <asm-generic/mshyperv.h>
+1 -1
include/asm-generic/mshyperv.h
··· 36 36 u32 nested_features; 37 37 u32 max_vp_index; 38 38 u32 max_lp_index; 39 + u8 vtl; 39 40 union { 40 41 u32 isolation_config_a; 41 42 struct { ··· 55 54 }; 56 55 }; 57 56 u64 shared_gpa_boundary; 58 - u8 vtl; 59 57 }; 60 58 extern struct ms_hyperv_info ms_hyperv; 61 59 extern bool hv_nested;
+206 -35
tools/hv/hv_kvp_daemon.c
··· 1171 1171 return 0; 1172 1172 } 1173 1173 1174 + /* 1175 + * Only IPv4 subnet strings needs to be converted to plen 1176 + * For IPv6 the subnet is already privided in plen format 1177 + */ 1178 + static int kvp_subnet_to_plen(char *subnet_addr_str) 1179 + { 1180 + int plen = 0; 1181 + struct in_addr subnet_addr4; 1182 + 1183 + /* 1184 + * Convert subnet address to binary representation 1185 + */ 1186 + if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) { 1187 + uint32_t subnet_mask = ntohl(subnet_addr4.s_addr); 1188 + 1189 + while (subnet_mask & 0x80000000) { 1190 + plen++; 1191 + subnet_mask <<= 1; 1192 + } 1193 + } else { 1194 + return -1; 1195 + } 1196 + 1197 + return plen; 1198 + } 1199 + 1200 + static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet, 1201 + int is_ipv6) 1202 + { 1203 + char addr[INET6_ADDRSTRLEN]; 1204 + char subnet_addr[INET6_ADDRSTRLEN]; 1205 + int error, i = 0; 1206 + int ip_offset = 0, subnet_offset = 0; 1207 + int plen; 1208 + 1209 + memset(addr, 0, sizeof(addr)); 1210 + memset(subnet_addr, 0, sizeof(subnet_addr)); 1211 + 1212 + while (parse_ip_val_buffer(ip_string, &ip_offset, addr, 1213 + (MAX_IP_ADDR_SIZE * 2)) && 1214 + parse_ip_val_buffer(subnet, 1215 + &subnet_offset, 1216 + subnet_addr, 1217 + (MAX_IP_ADDR_SIZE * 1218 + 2))) { 1219 + if (!is_ipv6) 1220 + plen = kvp_subnet_to_plen((char *)subnet_addr); 1221 + else 1222 + plen = atoi(subnet_addr); 1223 + 1224 + if (plen < 0) 1225 + return plen; 1226 + 1227 + error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr, 1228 + plen); 1229 + if (error < 0) 1230 + return error; 1231 + 1232 + memset(addr, 0, sizeof(addr)); 1233 + memset(subnet_addr, 0, sizeof(subnet_addr)); 1234 + } 1235 + 1236 + return 0; 1237 + } 1238 + 1174 1239 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 1175 1240 { 1176 1241 int error = 0; 1177 - char if_file[PATH_MAX]; 1178 - FILE *file; 1242 + char if_filename[PATH_MAX]; 1243 + char nm_filename[PATH_MAX]; 1244 + FILE *ifcfg_file, *nmfile; 1179 1245 char cmd[PATH_MAX]; 1246 + int is_ipv6 = 0; 1180 1247 char *mac_addr; 1181 1248 int str_len; 1182 1249 ··· 1264 1197 * in a given distro to configure the interface and so are free 1265 1198 * ignore information that may not be relevant. 1266 1199 * 1267 - * Here is the format of the ip configuration file: 1200 + * Here is the ifcfg format of the ip configuration file: 1268 1201 * 1269 1202 * HWADDR=macaddr 1270 1203 * DEVICE=interface name ··· 1287 1220 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as 1288 1221 * IPV6NETMASK. 1289 1222 * 1223 + * Here is the keyfile format of the ip configuration file: 1224 + * 1225 + * [ethernet] 1226 + * mac-address=macaddr 1227 + * [connection] 1228 + * interface-name=interface name 1229 + * 1230 + * [ipv4] 1231 + * method=<protocol> (where <protocol> is "auto" if DHCP is configured 1232 + * or "manual" if no boot-time protocol should be used) 1233 + * 1234 + * address1=ipaddr1/plen 1235 + * address2=ipaddr2/plen 1236 + * 1237 + * gateway=gateway1;gateway2 1238 + * 1239 + * dns=dns1;dns2 1240 + * 1241 + * [ipv6] 1242 + * address1=ipaddr1/plen 1243 + * address2=ipaddr2/plen 1244 + * 1245 + * gateway=gateway1;gateway2 1246 + * 1247 + * dns=dns1;dns2 1248 + * 1290 1249 * The host can specify multiple ipv4 and ipv6 addresses to be 1291 1250 * configured for the interface. Furthermore, the configuration 1292 1251 * needs to be persistent. A subsequent GET call on the interface ··· 1320 1227 * call. 1321 1228 */ 1322 1229 1323 - snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, 1324 - "/ifcfg-", if_name); 1230 + /* 1231 + * We are populating both ifcfg and nmconnection files 1232 + */ 1233 + snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC, 1234 + "/ifcfg-", if_name); 1325 1235 1326 - file = fopen(if_file, "w"); 1236 + ifcfg_file = fopen(if_filename, "w"); 1327 1237 1328 - if (file == NULL) { 1238 + if (!ifcfg_file) { 1329 1239 syslog(LOG_ERR, "Failed to open config file; error: %d %s", 1330 - errno, strerror(errno)); 1240 + errno, strerror(errno)); 1241 + return HV_E_FAIL; 1242 + } 1243 + 1244 + snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC, 1245 + "/", if_name, ".nmconnection"); 1246 + 1247 + nmfile = fopen(nm_filename, "w"); 1248 + 1249 + if (!nmfile) { 1250 + syslog(LOG_ERR, "Failed to open config file; error: %d %s", 1251 + errno, strerror(errno)); 1252 + fclose(ifcfg_file); 1331 1253 return HV_E_FAIL; 1332 1254 } 1333 1255 ··· 1356 1248 goto setval_error; 1357 1249 } 1358 1250 1359 - error = kvp_write_file(file, "HWADDR", "", mac_addr); 1360 - free(mac_addr); 1361 - if (error) 1362 - goto setval_error; 1251 + error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr); 1252 + if (error < 0) 1253 + goto setmac_error; 1363 1254 1364 - error = kvp_write_file(file, "DEVICE", "", if_name); 1255 + error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name); 1256 + if (error < 0) 1257 + goto setmac_error; 1258 + 1259 + error = fprintf(nmfile, "\n[connection]\n"); 1260 + if (error < 0) 1261 + goto setmac_error; 1262 + 1263 + error = kvp_write_file(nmfile, "interface-name", "", if_name); 1365 1264 if (error) 1366 - goto setval_error; 1265 + goto setmac_error; 1266 + 1267 + error = fprintf(nmfile, "\n[ethernet]\n"); 1268 + if (error < 0) 1269 + goto setmac_error; 1270 + 1271 + error = kvp_write_file(nmfile, "mac-address", "", mac_addr); 1272 + if (error) 1273 + goto setmac_error; 1274 + 1275 + free(mac_addr); 1367 1276 1368 1277 /* 1369 1278 * The dhcp_enabled flag is only for IPv4. In the case the host only ··· 1388 1263 * proceed to parse and pass the IPv6 information to the 1389 1264 * disto-specific script hv_set_ifconfig. 1390 1265 */ 1266 + 1267 + /* 1268 + * First populate the ifcfg file format 1269 + */ 1391 1270 if (new_val->dhcp_enabled) { 1392 - error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); 1271 + error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp"); 1393 1272 if (error) 1394 1273 goto setval_error; 1395 - 1396 1274 } else { 1397 - error = kvp_write_file(file, "BOOTPROTO", "", "none"); 1275 + error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none"); 1398 1276 if (error) 1277 + goto setval_error; 1278 + } 1279 + 1280 + error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr, 1281 + IPADDR); 1282 + if (error) 1283 + goto setval_error; 1284 + 1285 + error = process_ip_string(ifcfg_file, (char *)new_val->sub_net, 1286 + NETMASK); 1287 + if (error) 1288 + goto setval_error; 1289 + 1290 + error = process_ip_string(ifcfg_file, (char *)new_val->gate_way, 1291 + GATEWAY); 1292 + if (error) 1293 + goto setval_error; 1294 + 1295 + error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS); 1296 + if (error) 1297 + goto setval_error; 1298 + 1299 + if (new_val->addr_family == ADDR_FAMILY_IPV6) { 1300 + error = fprintf(nmfile, "\n[ipv6]\n"); 1301 + if (error < 0) 1302 + goto setval_error; 1303 + is_ipv6 = 1; 1304 + } else { 1305 + error = fprintf(nmfile, "\n[ipv4]\n"); 1306 + if (error < 0) 1307 + goto setval_error; 1308 + } 1309 + 1310 + /* 1311 + * Now we populate the keyfile format 1312 + */ 1313 + 1314 + if (new_val->dhcp_enabled) { 1315 + error = kvp_write_file(nmfile, "method", "", "auto"); 1316 + if (error < 0) 1317 + goto setval_error; 1318 + } else { 1319 + error = kvp_write_file(nmfile, "method", "", "manual"); 1320 + if (error < 0) 1399 1321 goto setval_error; 1400 1322 } 1401 1323 1402 1324 /* 1403 1325 * Write the configuration for ipaddress, netmask, gateway and 1404 - * name servers. 1326 + * name services 1405 1327 */ 1406 - 1407 - error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); 1408 - if (error) 1328 + error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr, 1329 + (char *)new_val->sub_net, is_ipv6); 1330 + if (error < 0) 1409 1331 goto setval_error; 1410 1332 1411 - error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); 1412 - if (error) 1333 + error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way); 1334 + if (error < 0) 1413 1335 goto setval_error; 1414 1336 1415 - error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); 1416 - if (error) 1337 + error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr); 1338 + if (error < 0) 1417 1339 goto setval_error; 1418 1340 1419 - error = process_ip_string(file, (char *)new_val->dns_addr, DNS); 1420 - if (error) 1421 - goto setval_error; 1422 - 1423 - fclose(file); 1341 + fclose(nmfile); 1342 + fclose(ifcfg_file); 1424 1343 1425 1344 /* 1426 1345 * Now that we have populated the configuration file, 1427 1346 * invoke the external script to do its magic. 1428 1347 */ 1429 1348 1430 - str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s", 1431 - "hv_set_ifconfig", if_file); 1349 + str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s %s", 1350 + "hv_set_ifconfig", if_filename, nm_filename); 1432 1351 /* 1433 1352 * This is a little overcautious, but it's necessary to suppress some 1434 1353 * false warnings from gcc 8.0.1. ··· 1485 1316 1486 1317 if (system(cmd)) { 1487 1318 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", 1488 - cmd, errno, strerror(errno)); 1319 + cmd, errno, strerror(errno)); 1489 1320 return HV_E_FAIL; 1490 1321 } 1491 1322 return 0; 1492 - 1323 + setmac_error: 1324 + free(mac_addr); 1493 1325 setval_error: 1494 1326 syslog(LOG_ERR, "Failed to write config file"); 1495 - fclose(file); 1327 + fclose(ifcfg_file); 1328 + fclose(nmfile); 1496 1329 return error; 1497 1330 } 1498 1331
+33 -6
tools/hv/hv_set_ifconfig.sh
··· 18 18 # 19 19 # This example script is based on a RHEL environment. 20 20 # 21 - # Here is the format of the ip configuration file: 21 + # Here is the ifcfg format of the ip configuration file: 22 22 # 23 23 # HWADDR=macaddr 24 24 # DEVICE=interface name 25 25 # BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured 26 - # or "none" if no boot-time protocol should be used) 26 + # or "none" if no boot-time protocol should be used) 27 27 # 28 28 # IPADDR0=ipaddr1 29 29 # IPADDR1=ipaddr2 ··· 41 41 # tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as 42 42 # IPV6NETMASK. 43 43 # 44 + # Here is the keyfile format of the ip configuration file: 45 + # 46 + # [ethernet] 47 + # mac-address=macaddr 48 + # [connection] 49 + # interface-name=interface name 50 + # 51 + # [ipv4] 52 + # method=<protocol> (where <protocol> is "auto" if DHCP is configured 53 + # or "manual" if no boot-time protocol should be used) 54 + # 55 + # address1=ipaddr1/plen 56 + # address=ipaddr2/plen 57 + # 58 + # gateway=gateway1;gateway2 59 + # 60 + # dns=dns1; 61 + # 62 + # [ipv6] 63 + # address1=ipaddr1/plen 64 + # address2=ipaddr1/plen 65 + # 66 + # gateway=gateway1;gateway2 67 + # 68 + # dns=dns1;dns2 69 + # 44 70 # The host can specify multiple ipv4 and ipv6 addresses to be 45 71 # configured for the interface. Furthermore, the configuration 46 72 # needs to be persistent. A subsequent GET call on the interface ··· 74 48 # call. 75 49 # 76 50 77 - 78 - 79 51 echo "IPV6INIT=yes" >> $1 80 52 echo "NM_CONTROLLED=no" >> $1 81 53 echo "PEERDNS=yes" >> $1 82 54 echo "ONBOOT=yes" >> $1 83 55 84 - 85 56 cp $1 /etc/sysconfig/network-scripts/ 86 57 58 + chmod 600 $2 59 + interface=$(echo $2 | awk -F - '{ print $2 }') 60 + filename="${2##*/}" 87 61 88 - interface=$(echo $1 | awk -F - '{ print $2 }') 62 + sed '/\[connection\]/a autoconnect=true' $2 > /etc/NetworkManager/system-connections/${filename} 63 + 89 64 90 65 /sbin/ifdown $interface 2>/dev/null 91 66 /sbin/ifup $interface 2>/dev/null