lguest: Support assigning a MAC address

If you've got a nice DHCP configuration which maps MAC
addresses to specific IP addresses, then you're going to
want to start your guest with one of those MAC addresses.

Also, in Fedora, we have persistent network interface naming
based on the MAC address, so with randomly assigned
addresses you're soon going to hit eth13. Who knows what
will happen then!

Allow assigning a MAC address to the network interface with
e.g.

--tunnet=bridge:eth0:00:FF:95:6B:DA:3D

or:

--tunnet=192.168.121.1:00:FF:95:6B:DA:3D

which is pretty unintelligable, but ...

(includes Rusty's minor rework)

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

authored by

Mark McLoughlin and committed by
Rusty Russell
dec6a2be 34bdaab4

+89 -33
+89 -33
Documentation/lguest/lguest.c
··· 1265 1266 static u32 str2ip(const char *ipaddr) 1267 { 1268 - unsigned int byte[4]; 1269 1270 - sscanf(ipaddr, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]); 1271 - return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3]; 1272 } 1273 1274 /* This code is "adapted" from libbridge: it attaches the Host end of the ··· 1304 errx(1, "interface %s does not exist!", if_name); 1305 1306 strncpy(ifr.ifr_name, br_name, IFNAMSIZ); 1307 ifr.ifr_ifindex = ifidx; 1308 if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) 1309 err(1, "can't add %s to bridge %s", if_name, br_name); ··· 1313 /* This sets up the Host end of the network device with an IP address, brings 1314 * it up so packets will flow, the copies the MAC address into the hwaddr 1315 * pointer. */ 1316 - static void configure_device(int fd, const char *devname, u32 ipaddr, 1317 - unsigned char hwaddr[6]) 1318 { 1319 struct ifreq ifr; 1320 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; 1321 1322 - /* Don't read these incantations. Just cut & paste them like I did! */ 1323 memset(&ifr, 0, sizeof(ifr)); 1324 - strcpy(ifr.ifr_name, devname); 1325 sin->sin_family = AF_INET; 1326 sin->sin_addr.s_addr = htonl(ipaddr); 1327 if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) 1328 - err(1, "Setting %s interface address", devname); 1329 ifr.ifr_flags = IFF_UP; 1330 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) 1331 - err(1, "Bringing interface %s up", devname); 1332 1333 /* SIOC stands for Socket I/O Control. G means Get (vs S for Set 1334 * above). IF means Interface, and HWADDR is hardware address. 1335 * Simple! */ 1336 if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) 1337 - err(1, "getting hw address for %s", devname); 1338 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); 1339 } 1340 1341 - /*L:195 Our network is a Host<->Guest network. This can either use bridging or 1342 - * routing, but the principle is the same: it uses the "tun" device to inject 1343 - * packets into the Host as if they came in from a normal network card. We 1344 - * just shunt packets between the Guest and the tun device. */ 1345 - static void setup_tun_net(const char *arg) 1346 { 1347 - struct device *dev; 1348 struct ifreq ifr; 1349 - int netfd, ipfd; 1350 - u32 ip; 1351 - const char *br_name = NULL; 1352 - struct virtio_net_config conf; 1353 1354 /* We open the /dev/net/tun device and tell it we want a tap device. A 1355 * tap device is like a tun device, only somehow different. To tell 1356 * the truth, I completely blundered my way through this code, but it 1357 * works now! */ 1358 netfd = open_or_die("/dev/net/tun", O_RDWR); 1359 - memset(&ifr, 0, sizeof(ifr)); 1360 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 1361 strcpy(ifr.ifr_name, "tap%d"); 1362 if (ioctl(netfd, TUNSETIFF, &ifr) != 0) 1363 err(1, "configuring /dev/net/tun"); 1364 /* We don't need checksums calculated for packets coming in this 1365 * device: trust us! */ 1366 ioctl(netfd, TUNSETNOCSUM, 1); 1367 1368 /* First we create a new network device. */ 1369 dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); ··· 1403 1404 /* If the command line was --tunnet=bridge:<name> do bridging. */ 1405 if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { 1406 - ip = INADDR_ANY; 1407 - br_name = arg + strlen(BRIDGE_PFX); 1408 - add_to_bridge(ipfd, ifr.ifr_name, br_name); 1409 - } else /* It is an IP address to set up the device with */ 1410 ip = str2ip(arg); 1411 1412 - /* Set up the tun device, and get the mac address for the interface. */ 1413 - configure_device(ipfd, ifr.ifr_name, ip, conf.mac); 1414 1415 /* Tell Guest what MAC address to use. */ 1416 add_feature(dev, VIRTIO_NET_F_MAC); ··· 1435 /* We don't need the socket any more; setup is done. */ 1436 close(ipfd); 1437 1438 - verbose("device %u: tun net %u.%u.%u.%u\n", 1439 - devices.device_num++, 1440 - (u8)(ip>>24),(u8)(ip>>16),(u8)(ip>>8),(u8)ip); 1441 - if (br_name) 1442 - verbose("attached to bridge: %s\n", br_name); 1443 } 1444 1445 /* Our block (disk) device should be really simple: the Guest asks for a block ··· 1754 static void usage(void) 1755 { 1756 errx(1, "Usage: lguest [--verbose] " 1757 - "[--tunnet=(<ipaddr>|bridge:<bridgename>)\n" 1758 "|--block=<filename>|--initrd=<filename>]...\n" 1759 "<mem-in-mb> vmlinux [args...]"); 1760 }
··· 1265 1266 static u32 str2ip(const char *ipaddr) 1267 { 1268 + unsigned int b[4]; 1269 1270 + if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) 1271 + errx(1, "Failed to parse IP address '%s'", ipaddr); 1272 + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; 1273 + } 1274 + 1275 + static void str2mac(const char *macaddr, unsigned char mac[6]) 1276 + { 1277 + unsigned int m[6]; 1278 + if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", 1279 + &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) 1280 + errx(1, "Failed to parse mac address '%s'", macaddr); 1281 + mac[0] = m[0]; 1282 + mac[1] = m[1]; 1283 + mac[2] = m[2]; 1284 + mac[3] = m[3]; 1285 + mac[4] = m[4]; 1286 + mac[5] = m[5]; 1287 } 1288 1289 /* This code is "adapted" from libbridge: it attaches the Host end of the ··· 1289 errx(1, "interface %s does not exist!", if_name); 1290 1291 strncpy(ifr.ifr_name, br_name, IFNAMSIZ); 1292 + ifr.ifr_name[IFNAMSIZ-1] = '\0'; 1293 ifr.ifr_ifindex = ifidx; 1294 if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) 1295 err(1, "can't add %s to bridge %s", if_name, br_name); ··· 1297 /* This sets up the Host end of the network device with an IP address, brings 1298 * it up so packets will flow, the copies the MAC address into the hwaddr 1299 * pointer. */ 1300 + static void configure_device(int fd, const char *tapif, u32 ipaddr) 1301 { 1302 struct ifreq ifr; 1303 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; 1304 1305 memset(&ifr, 0, sizeof(ifr)); 1306 + strcpy(ifr.ifr_name, tapif); 1307 + 1308 + /* Don't read these incantations. Just cut & paste them like I did! */ 1309 sin->sin_family = AF_INET; 1310 sin->sin_addr.s_addr = htonl(ipaddr); 1311 if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) 1312 + err(1, "Setting %s interface address", tapif); 1313 ifr.ifr_flags = IFF_UP; 1314 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) 1315 + err(1, "Bringing interface %s up", tapif); 1316 + } 1317 + 1318 + static void get_mac(int fd, const char *tapif, unsigned char hwaddr[6]) 1319 + { 1320 + struct ifreq ifr; 1321 + 1322 + memset(&ifr, 0, sizeof(ifr)); 1323 + strcpy(ifr.ifr_name, tapif); 1324 1325 /* SIOC stands for Socket I/O Control. G means Get (vs S for Set 1326 * above). IF means Interface, and HWADDR is hardware address. 1327 * Simple! */ 1328 if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) 1329 + err(1, "getting hw address for %s", tapif); 1330 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); 1331 } 1332 1333 + static int get_tun_device(char tapif[IFNAMSIZ]) 1334 { 1335 struct ifreq ifr; 1336 + int netfd; 1337 + 1338 + /* Start with this zeroed. Messy but sure. */ 1339 + memset(&ifr, 0, sizeof(ifr)); 1340 1341 /* We open the /dev/net/tun device and tell it we want a tap device. A 1342 * tap device is like a tun device, only somehow different. To tell 1343 * the truth, I completely blundered my way through this code, but it 1344 * works now! */ 1345 netfd = open_or_die("/dev/net/tun", O_RDWR); 1346 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 1347 strcpy(ifr.ifr_name, "tap%d"); 1348 if (ioctl(netfd, TUNSETIFF, &ifr) != 0) 1349 err(1, "configuring /dev/net/tun"); 1350 + 1351 /* We don't need checksums calculated for packets coming in this 1352 * device: trust us! */ 1353 ioctl(netfd, TUNSETNOCSUM, 1); 1354 + 1355 + memcpy(tapif, ifr.ifr_name, IFNAMSIZ); 1356 + return netfd; 1357 + } 1358 + 1359 + /*L:195 Our network is a Host<->Guest network. This can either use bridging or 1360 + * routing, but the principle is the same: it uses the "tun" device to inject 1361 + * packets into the Host as if they came in from a normal network card. We 1362 + * just shunt packets between the Guest and the tun device. */ 1363 + static void setup_tun_net(char *arg) 1364 + { 1365 + struct device *dev; 1366 + int netfd, ipfd; 1367 + u32 ip = INADDR_ANY; 1368 + bool bridging = false; 1369 + char tapif[IFNAMSIZ], *p; 1370 + struct virtio_net_config conf; 1371 + 1372 + netfd = get_tun_device(tapif); 1373 1374 /* First we create a new network device. */ 1375 dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); ··· 1365 1366 /* If the command line was --tunnet=bridge:<name> do bridging. */ 1367 if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { 1368 + arg += strlen(BRIDGE_PFX); 1369 + bridging = true; 1370 + } 1371 + 1372 + /* A mac address may follow the bridge name or IP address */ 1373 + p = strchr(arg, ':'); 1374 + if (p) { 1375 + str2mac(p+1, conf.mac); 1376 + *p = '\0'; 1377 + } else { 1378 + p = arg + strlen(arg); 1379 + /* None supplied; query the randomly assigned mac. */ 1380 + get_mac(ipfd, tapif, conf.mac); 1381 + } 1382 + 1383 + /* arg is now either an IP address or a bridge name */ 1384 + if (bridging) 1385 + add_to_bridge(ipfd, tapif, arg); 1386 + else 1387 ip = str2ip(arg); 1388 1389 + /* Set up the tun device. */ 1390 + configure_device(ipfd, tapif, ip); 1391 1392 /* Tell Guest what MAC address to use. */ 1393 add_feature(dev, VIRTIO_NET_F_MAC); ··· 1382 /* We don't need the socket any more; setup is done. */ 1383 close(ipfd); 1384 1385 + devices.device_num++; 1386 + 1387 + if (bridging) 1388 + verbose("device %u: tun %s attached to bridge: %s\n", 1389 + devices.device_num, tapif, arg); 1390 + else 1391 + verbose("device %u: tun %s: %s\n", 1392 + devices.device_num, tapif, arg); 1393 } 1394 1395 /* Our block (disk) device should be really simple: the Guest asks for a block ··· 1698 static void usage(void) 1699 { 1700 errx(1, "Usage: lguest [--verbose] " 1701 + "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n" 1702 "|--block=<filename>|--initrd=<filename>]...\n" 1703 "<mem-in-mb> vmlinux [args...]"); 1704 }