Skip to content

Commit f971f6d

Browse files
Shradha Guptaliuw
authored andcommitted
hv/hv_kvp_daemon: Handle IPv4 and Ipv6 combination for keyfile format
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) Co-developed-by: Ani Sinha <[email protected]> Signed-off-by: Ani Sinha <[email protected]> Signed-off-by: Shradha Gupta <[email protected]> Reviewed-by: Easwar Hariharan <[email protected]> Tested-by: Ani Sinha <[email protected]> Reviewed-by: Ani Sinha <[email protected]> Link: https://lore.kernel.org/r/1711115162-11629-1-git-send-email-shradhagupta@linux.microsoft.com Signed-off-by: Wei Liu <[email protected]> Message-ID: <1711115162-11629-1-git-send-email-shradhagupta@linux.microsoft.com>
1 parent d9ea7a3 commit f971f6d

File tree

1 file changed

+172
-41
lines changed

1 file changed

+172
-41
lines changed

tools/hv/hv_kvp_daemon.c

Lines changed: 172 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ enum {
7676
DNS
7777
};
7878

79+
enum {
80+
IPV4 = 1,
81+
IPV6,
82+
IP_TYPE_MAX
83+
};
84+
7985
static int in_hand_shake;
8086

8187
static char *os_name = "";
@@ -102,6 +108,11 @@ static struct utsname uts_buf;
102108

103109
#define MAX_FILE_NAME 100
104110
#define ENTRIES_PER_BLOCK 50
111+
/*
112+
* Change this entry if the number of addresses increases in future
113+
*/
114+
#define MAX_IP_ENTRIES 64
115+
#define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
105116

106117
struct kvp_record {
107118
char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
11711182
return 0;
11721183
}
11731184

1185+
int ip_version_check(const char *input_addr)
1186+
{
1187+
struct in6_addr addr;
1188+
1189+
if (inet_pton(AF_INET, input_addr, &addr))
1190+
return IPV4;
1191+
else if (inet_pton(AF_INET6, input_addr, &addr))
1192+
return IPV6;
1193+
1194+
return -EINVAL;
1195+
}
1196+
11741197
/*
11751198
* Only IPv4 subnet strings needs to be converted to plen
11761199
* For IPv6 the subnet is already privided in plen format
@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
11971220
return plen;
11981221
}
11991222

1223+
static int process_dns_gateway_nm(FILE *f, char *ip_string, int type,
1224+
int ip_sec)
1225+
{
1226+
char addr[INET6_ADDRSTRLEN], *output_str;
1227+
int ip_offset = 0, error = 0, ip_ver;
1228+
char *param_name;
1229+
1230+
if (type == DNS)
1231+
param_name = "dns";
1232+
else if (type == GATEWAY)
1233+
param_name = "gateway";
1234+
else
1235+
return -EINVAL;
1236+
1237+
output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char));
1238+
if (!output_str)
1239+
return -ENOMEM;
1240+
1241+
while (1) {
1242+
memset(addr, 0, sizeof(addr));
1243+
1244+
if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
1245+
(MAX_IP_ADDR_SIZE * 2)))
1246+
break;
1247+
1248+
ip_ver = ip_version_check(addr);
1249+
if (ip_ver < 0)
1250+
continue;
1251+
1252+
if ((ip_ver == IPV4 && ip_sec == IPV4) ||
1253+
(ip_ver == IPV6 && ip_sec == IPV6)) {
1254+
/*
1255+
* do a bound check to avoid out-of bound writes
1256+
*/
1257+
if ((OUTSTR_BUF_SIZE - strlen(output_str)) >
1258+
(strlen(addr) + 1)) {
1259+
strncat(output_str, addr,
1260+
OUTSTR_BUF_SIZE -
1261+
strlen(output_str) - 1);
1262+
strncat(output_str, ",",
1263+
OUTSTR_BUF_SIZE -
1264+
strlen(output_str) - 1);
1265+
}
1266+
} else {
1267+
continue;
1268+
}
1269+
}
1270+
1271+
if (strlen(output_str)) {
1272+
/*
1273+
* This is to get rid of that extra comma character
1274+
* in the end of the string
1275+
*/
1276+
output_str[strlen(output_str) - 1] = '\0';
1277+
error = fprintf(f, "%s=%s\n", param_name, output_str);
1278+
}
1279+
1280+
free(output_str);
1281+
return error;
1282+
}
1283+
12001284
static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
1201-
int is_ipv6)
1285+
int ip_sec)
12021286
{
12031287
char addr[INET6_ADDRSTRLEN];
12041288
char subnet_addr[INET6_ADDRSTRLEN];
1205-
int error, i = 0;
1289+
int error = 0, i = 0;
12061290
int ip_offset = 0, subnet_offset = 0;
1207-
int plen;
1291+
int plen, ip_ver;
12081292

12091293
memset(addr, 0, sizeof(addr));
12101294
memset(subnet_addr, 0, sizeof(subnet_addr));
@@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
12161300
subnet_addr,
12171301
(MAX_IP_ADDR_SIZE *
12181302
2))) {
1219-
if (!is_ipv6)
1303+
ip_ver = ip_version_check(addr);
1304+
if (ip_ver < 0)
1305+
continue;
1306+
1307+
if (ip_ver == IPV4 && ip_sec == IPV4)
12201308
plen = kvp_subnet_to_plen((char *)subnet_addr);
1221-
else
1309+
else if (ip_ver == IPV6 && ip_sec == IPV6)
12221310
plen = atoi(subnet_addr);
1311+
else
1312+
continue;
12231313

12241314
if (plen < 0)
12251315
return plen;
@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
12331323
memset(subnet_addr, 0, sizeof(subnet_addr));
12341324
}
12351325

1236-
return 0;
1326+
return error;
12371327
}
12381328

12391329
static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
12401330
{
1241-
int error = 0;
1331+
int error = 0, ip_ver;
12421332
char if_filename[PATH_MAX];
12431333
char nm_filename[PATH_MAX];
12441334
FILE *ifcfg_file, *nmfile;
12451335
char cmd[PATH_MAX];
1246-
int is_ipv6 = 0;
12471336
char *mac_addr;
12481337
int str_len;
12491338

@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
14211510
if (error)
14221511
goto setval_error;
14231512

1424-
if (new_val->addr_family & ADDR_FAMILY_IPV6) {
1425-
error = fprintf(nmfile, "\n[ipv6]\n");
1426-
if (error < 0)
1427-
goto setval_error;
1428-
is_ipv6 = 1;
1429-
} else {
1430-
error = fprintf(nmfile, "\n[ipv4]\n");
1431-
if (error < 0)
1432-
goto setval_error;
1433-
}
1434-
14351513
/*
14361514
* Now we populate the keyfile format
1515+
*
1516+
* The keyfile format expects the IPv6 and IPv4 configuration in
1517+
* different sections. Therefore we iterate through the list twice,
1518+
* once to populate the IPv4 section and the next time for IPv6
14371519
*/
1520+
ip_ver = IPV4;
1521+
do {
1522+
if (ip_ver == IPV4) {
1523+
error = fprintf(nmfile, "\n[ipv4]\n");
1524+
if (error < 0)
1525+
goto setval_error;
1526+
} else {
1527+
error = fprintf(nmfile, "\n[ipv6]\n");
1528+
if (error < 0)
1529+
goto setval_error;
1530+
}
14381531

1439-
if (new_val->dhcp_enabled) {
1440-
error = kvp_write_file(nmfile, "method", "", "auto");
1441-
if (error < 0)
1442-
goto setval_error;
1443-
} else {
1444-
error = kvp_write_file(nmfile, "method", "", "manual");
1532+
/*
1533+
* Write the configuration for ipaddress, netmask, gateway and
1534+
* name services
1535+
*/
1536+
error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
1537+
(char *)new_val->sub_net,
1538+
ip_ver);
14451539
if (error < 0)
14461540
goto setval_error;
1447-
}
14481541

1449-
/*
1450-
* Write the configuration for ipaddress, netmask, gateway and
1451-
* name services
1452-
*/
1453-
error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
1454-
(char *)new_val->sub_net, is_ipv6);
1455-
if (error < 0)
1456-
goto setval_error;
1542+
/*
1543+
* As dhcp_enabled is only valid for ipv4, we do not set dhcp
1544+
* methods for ipv6 based on dhcp_enabled flag.
1545+
*
1546+
* For ipv4, set method to manual only when dhcp_enabled is
1547+
* false and specific ipv4 addresses are configured. If neither
1548+
* dhcp_enabled is true and no ipv4 addresses are configured,
1549+
* set method to 'disabled'.
1550+
*
1551+
* For ipv6, set method to manual when we configure ipv6
1552+
* addresses. Otherwise set method to 'auto' so that SLAAC from
1553+
* RA may be used.
1554+
*/
1555+
if (ip_ver == IPV4) {
1556+
if (new_val->dhcp_enabled) {
1557+
error = kvp_write_file(nmfile, "method", "",
1558+
"auto");
1559+
if (error < 0)
1560+
goto setval_error;
1561+
} else if (error) {
1562+
error = kvp_write_file(nmfile, "method", "",
1563+
"manual");
1564+
if (error < 0)
1565+
goto setval_error;
1566+
} else {
1567+
error = kvp_write_file(nmfile, "method", "",
1568+
"disabled");
1569+
if (error < 0)
1570+
goto setval_error;
1571+
}
1572+
} else if (ip_ver == IPV6) {
1573+
if (error) {
1574+
error = kvp_write_file(nmfile, "method", "",
1575+
"manual");
1576+
if (error < 0)
1577+
goto setval_error;
1578+
} else {
1579+
error = kvp_write_file(nmfile, "method", "",
1580+
"auto");
1581+
if (error < 0)
1582+
goto setval_error;
1583+
}
1584+
}
14571585

1458-
/* we do not want ipv4 addresses in ipv6 section and vice versa */
1459-
if (is_ipv6 != is_ipv4((char *)new_val->gate_way)) {
1460-
error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way);
1586+
error = process_dns_gateway_nm(nmfile,
1587+
(char *)new_val->gate_way,
1588+
GATEWAY, ip_ver);
14611589
if (error < 0)
14621590
goto setval_error;
1463-
}
14641591

1465-
if (is_ipv6 != is_ipv4((char *)new_val->dns_addr)) {
1466-
error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr);
1592+
error = process_dns_gateway_nm(nmfile,
1593+
(char *)new_val->dns_addr, DNS,
1594+
ip_ver);
14671595
if (error < 0)
14681596
goto setval_error;
1469-
}
1597+
1598+
ip_ver++;
1599+
} while (ip_ver < IP_TYPE_MAX);
1600+
14701601
fclose(nmfile);
14711602
fclose(ifcfg_file);
14721603

0 commit comments

Comments
 (0)