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