@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
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
@@ -1197,7 +1264,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1197
1264
* in a given distro to configure the interface and so are free
1198
1265
* ignore information that may not be relevant.
1199
1266
*
1200
- * Here is the format of the ip configuration file:
1267
+ * Here is the ifcfg format of the ip configuration file:
1201
1268
*
1202
1269
* HWADDR=macaddr
1203
1270
* DEVICE=interface name
@@ -1220,21 +1287,62 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1220
1287
* tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1221
1288
* IPV6NETMASK.
1222
1289
*
1290
+ * Here is the keyfile format of the ip configuration file:
1291
+ *
1292
+ * [ethernet]
1293
+ * mac-address=macaddr
1294
+ * [connection]
1295
+ * interface-name=interface name
1296
+ *
1297
+ * [ipv4]
1298
+ * method=<protocol> (where <protocol> is "auto" if DHCP is configured
1299
+ * or "manual" if no boot-time protocol should be used)
1300
+ *
1301
+ * address1=ipaddr1/plen
1302
+ * address2=ipaddr2/plen
1303
+ *
1304
+ * gateway=gateway1;gateway2
1305
+ *
1306
+ * dns=dns1;dns2
1307
+ *
1308
+ * [ipv6]
1309
+ * address1=ipaddr1/plen
1310
+ * address2=ipaddr2/plen
1311
+ *
1312
+ * gateway=gateway1;gateway2
1313
+ *
1314
+ * dns=dns1;dns2
1315
+ *
1223
1316
* The host can specify multiple ipv4 and ipv6 addresses to be
1224
1317
* configured for the interface. Furthermore, the configuration
1225
1318
* needs to be persistent. A subsequent GET call on the interface
1226
1319
* is expected to return the configuration that is set via the SET
1227
1320
* call.
1228
1321
*/
1229
1322
1230
- snprintf (if_file , sizeof (if_file ), "%s%s%s" , KVP_CONFIG_LOC ,
1231
- "/ifcfg-" , if_name );
1323
+ /*
1324
+ * We are populating both ifcfg and nmconnection files
1325
+ */
1326
+ snprintf (if_filename , sizeof (if_filename ), "%s%s%s" , KVP_CONFIG_LOC ,
1327
+ "/ifcfg-" , if_name );
1232
1328
1233
- file = fopen (if_file , "w" );
1329
+ ifcfg_file = fopen (if_filename , "w" );
1234
1330
1235
- if (file == NULL ) {
1331
+ if (! ifcfg_file ) {
1236
1332
syslog (LOG_ERR , "Failed to open config file; error: %d %s" ,
1237
- errno , strerror (errno ));
1333
+ errno , strerror (errno ));
1334
+ return HV_E_FAIL ;
1335
+ }
1336
+
1337
+ snprintf (nm_filename , sizeof (nm_filename ), "%s%s%s%s" , KVP_CONFIG_LOC ,
1338
+ "/" , if_name , ".nmconnection" );
1339
+
1340
+ nmfile = fopen (nm_filename , "w" );
1341
+
1342
+ if (!nmfile ) {
1343
+ syslog (LOG_ERR , "Failed to open config file; error: %d %s" ,
1344
+ errno , strerror (errno ));
1345
+ fclose (ifcfg_file );
1238
1346
return HV_E_FAIL ;
1239
1347
}
1240
1348
@@ -1248,62 +1356,123 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1248
1356
goto setval_error ;
1249
1357
}
1250
1358
1251
- error = kvp_write_file (file , "HWADDR" , "" , mac_addr );
1252
- free (mac_addr );
1359
+ error = kvp_write_file (ifcfg_file , "HWADDR" , "" , mac_addr );
1360
+ if (error < 0 )
1361
+ goto setmac_error ;
1362
+
1363
+ error = kvp_write_file (ifcfg_file , "DEVICE" , "" , if_name );
1364
+ if (error < 0 )
1365
+ goto setmac_error ;
1366
+
1367
+ error = fprintf (nmfile , "\n[connection]\n" );
1368
+ if (error < 0 )
1369
+ goto setmac_error ;
1370
+
1371
+ error = kvp_write_file (nmfile , "interface-name" , "" , if_name );
1253
1372
if (error )
1254
- goto setval_error ;
1373
+ goto setmac_error ;
1255
1374
1256
- error = kvp_write_file (file , "DEVICE" , "" , if_name );
1375
+ error = fprintf (nmfile , "\n[ethernet]\n" );
1376
+ if (error < 0 )
1377
+ goto setmac_error ;
1378
+
1379
+ error = kvp_write_file (nmfile , "mac-address" , "" , mac_addr );
1257
1380
if (error )
1258
- goto setval_error ;
1381
+ goto setmac_error ;
1382
+
1383
+ free (mac_addr );
1259
1384
1260
1385
/*
1261
1386
* The dhcp_enabled flag is only for IPv4. In the case the host only
1262
1387
* injects an IPv6 address, the flag is true, but we still need to
1263
1388
* proceed to parse and pass the IPv6 information to the
1264
1389
* disto-specific script hv_set_ifconfig.
1265
1390
*/
1391
+
1392
+ /*
1393
+ * First populate the ifcfg file format
1394
+ */
1266
1395
if (new_val -> dhcp_enabled ) {
1267
- error = kvp_write_file (file , "BOOTPROTO" , "" , "dhcp" );
1396
+ error = kvp_write_file (ifcfg_file , "BOOTPROTO" , "" , "dhcp" );
1268
1397
if (error )
1269
1398
goto setval_error ;
1270
-
1271
1399
} else {
1272
- error = kvp_write_file (file , "BOOTPROTO" , "" , "none" );
1400
+ error = kvp_write_file (ifcfg_file , "BOOTPROTO" , "" , "none" );
1273
1401
if (error )
1274
1402
goto setval_error ;
1275
1403
}
1276
1404
1277
- /*
1278
- * Write the configuration for ipaddress, netmask, gateway and
1279
- * name servers.
1280
- */
1281
-
1282
- error = process_ip_string (file , (char * )new_val -> ip_addr , IPADDR );
1405
+ error = process_ip_string (ifcfg_file , (char * )new_val -> ip_addr ,
1406
+ IPADDR );
1283
1407
if (error )
1284
1408
goto setval_error ;
1285
1409
1286
- error = process_ip_string (file , (char * )new_val -> sub_net , NETMASK );
1410
+ error = process_ip_string (ifcfg_file , (char * )new_val -> sub_net ,
1411
+ NETMASK );
1287
1412
if (error )
1288
1413
goto setval_error ;
1289
1414
1290
- error = process_ip_string (file , (char * )new_val -> gate_way , GATEWAY );
1415
+ error = process_ip_string (ifcfg_file , (char * )new_val -> gate_way ,
1416
+ GATEWAY );
1291
1417
if (error )
1292
1418
goto setval_error ;
1293
1419
1294
- error = process_ip_string (file , (char * )new_val -> dns_addr , DNS );
1420
+ error = process_ip_string (ifcfg_file , (char * )new_val -> dns_addr , DNS );
1295
1421
if (error )
1296
1422
goto setval_error ;
1297
1423
1298
- fclose (file );
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
+
1435
+ /*
1436
+ * Now we populate the keyfile format
1437
+ */
1438
+
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" );
1445
+ if (error < 0 )
1446
+ goto setval_error ;
1447
+ }
1448
+
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 ;
1457
+
1458
+ error = fprintf (nmfile , "gateway=%s\n" , (char * )new_val -> gate_way );
1459
+ if (error < 0 )
1460
+ goto setval_error ;
1461
+
1462
+ error = fprintf (nmfile , "dns=%s\n" , (char * )new_val -> dns_addr );
1463
+ if (error < 0 )
1464
+ goto setval_error ;
1465
+
1466
+ fclose (nmfile );
1467
+ fclose (ifcfg_file );
1299
1468
1300
1469
/*
1301
1470
* Now that we have populated the configuration file,
1302
1471
* invoke the external script to do its magic.
1303
1472
*/
1304
1473
1305
- str_len = snprintf (cmd , sizeof (cmd ), KVP_SCRIPTS_PATH "%s %s" ,
1306
- "hv_set_ifconfig" , if_file );
1474
+ str_len = snprintf (cmd , sizeof (cmd ), KVP_SCRIPTS_PATH "%s %s %s " ,
1475
+ "hv_set_ifconfig" , if_filename , nm_filename );
1307
1476
/*
1308
1477
* This is a little overcautious, but it's necessary to suppress some
1309
1478
* 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
1485
1317
1486
if (system (cmd )) {
1318
1487
syslog (LOG_ERR , "Failed to execute cmd '%s'; error: %d %s" ,
1319
- cmd , errno , strerror (errno ));
1488
+ cmd , errno , strerror (errno ));
1320
1489
return HV_E_FAIL ;
1321
1490
}
1322
1491
return 0 ;
1323
-
1492
+ setmac_error :
1493
+ free (mac_addr );
1324
1494
setval_error :
1325
1495
syslog (LOG_ERR , "Failed to write config file" );
1326
- fclose (file );
1496
+ fclose (ifcfg_file );
1497
+ fclose (nmfile );
1327
1498
return error ;
1328
1499
}
1329
1500
0 commit comments