@@ -1171,12 +1171,79 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
11711171 return 0 ;
11721172}
11731173
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+
11741239static int kvp_set_ip_info (char * if_name , struct hv_kvp_ipaddr_value * new_val )
11751240{
11761241 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 ;
11791245 char cmd [PATH_MAX ];
1246+ int is_ipv6 = 0 ;
11801247 char * mac_addr ;
11811248 int str_len ;
11821249
@@ -1197,7 +1264,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
11971264 * in a given distro to configure the interface and so are free
11981265 * ignore information that may not be relevant.
11991266 *
1200- * Here is the format of the ip configuration file:
1267+ * Here is the ifcfg format of the ip configuration file:
12011268 *
12021269 * HWADDR=macaddr
12031270 * DEVICE=interface name
@@ -1220,21 +1287,62 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
12201287 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
12211288 * IPV6NETMASK.
12221289 *
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+ *
12231316 * The host can specify multiple ipv4 and ipv6 addresses to be
12241317 * configured for the interface. Furthermore, the configuration
12251318 * needs to be persistent. A subsequent GET call on the interface
12261319 * is expected to return the configuration that is set via the SET
12271320 * call.
12281321 */
12291322
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 );
12321328
1233- file = fopen (if_file , "w" );
1329+ ifcfg_file = fopen (if_filename , "w" );
12341330
1235- if (file == NULL ) {
1331+ if (! ifcfg_file ) {
12361332 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 );
12381346 return HV_E_FAIL ;
12391347 }
12401348
@@ -1248,62 +1356,123 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
12481356 goto setval_error ;
12491357 }
12501358
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 );
12531372 if (error )
1254- goto setval_error ;
1373+ goto setmac_error ;
12551374
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 );
12571380 if (error )
1258- goto setval_error ;
1381+ goto setmac_error ;
1382+
1383+ free (mac_addr );
12591384
12601385 /*
12611386 * The dhcp_enabled flag is only for IPv4. In the case the host only
12621387 * injects an IPv6 address, the flag is true, but we still need to
12631388 * proceed to parse and pass the IPv6 information to the
12641389 * disto-specific script hv_set_ifconfig.
12651390 */
1391+
1392+ /*
1393+ * First populate the ifcfg file format
1394+ */
12661395 if (new_val -> dhcp_enabled ) {
1267- error = kvp_write_file (file , "BOOTPROTO" , "" , "dhcp" );
1396+ error = kvp_write_file (ifcfg_file , "BOOTPROTO" , "" , "dhcp" );
12681397 if (error )
12691398 goto setval_error ;
1270-
12711399 } else {
1272- error = kvp_write_file (file , "BOOTPROTO" , "" , "none" );
1400+ error = kvp_write_file (ifcfg_file , "BOOTPROTO" , "" , "none" );
12731401 if (error )
12741402 goto setval_error ;
12751403 }
12761404
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 );
12831407 if (error )
12841408 goto setval_error ;
12851409
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 );
12871412 if (error )
12881413 goto setval_error ;
12891414
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 );
12911417 if (error )
12921418 goto setval_error ;
12931419
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 );
12951421 if (error )
12961422 goto setval_error ;
12971423
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 );
12991468
13001469 /*
13011470 * Now that we have populated the configuration file,
13021471 * invoke the external script to do its magic.
13031472 */
13041473
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 );
13071476 /*
13081477 * This is a little overcautious, but it's necessary to suppress some
13091478 * 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)
13161485
13171486 if (system (cmd )) {
13181487 syslog (LOG_ERR , "Failed to execute cmd '%s'; error: %d %s" ,
1319- cmd , errno , strerror (errno ));
1488+ cmd , errno , strerror (errno ));
13201489 return HV_E_FAIL ;
13211490 }
13221491 return 0 ;
1323-
1492+ setmac_error :
1493+ free (mac_addr );
13241494setval_error :
13251495 syslog (LOG_ERR , "Failed to write config file" );
1326- fclose (file );
1496+ fclose (ifcfg_file );
1497+ fclose (nmfile );
13271498 return error ;
13281499}
13291500
0 commit comments