aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/lguest
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2008-07-29 10:58:33 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-07-28 19:58:33 -0400
commitdec6a2be085f046d42eb0bdce95ecb73de526429 (patch)
tree0e2bd1576b32167259bb8d290f134c1b7eb1017a /Documentation/lguest
parent34bdaab44dd5dac861b0d23bc29b147b569e5783 (diff)
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>
Diffstat (limited to 'Documentation/lguest')
-rw-r--r--Documentation/lguest/lguest.c122
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
1266static u32 str2ip(const char *ipaddr) 1266static 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
1275static 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. */
1300static void configure_device(int fd, const char *devname, u32 ipaddr, 1316static 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
1334static 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 1349static 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. */
1329static 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. */
1379static 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[] = {
1698static void usage(void) 1754static 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}