qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] patch for allowing automated IP assignment based on MAC
@ 2005-04-23 22:08 jamal
  0 siblings, 0 replies; only message in thread
From: jamal @ 2005-04-23 22:08 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1311 bytes --]

Folks,

Played a little bit with qemu 0.6.1; looks very interesting - still need
to discover more. 

I am trying to use the same image for multiple qemu guests but it was
kind of annoying to customize images... So what this patch allows is to
have something along the lines of:


-nics 2 -macaddr0 00:11:a:0:2:19 -macaddr1 00:11:a:0:1:19 -ID1 1 -ID2 2 
on the command line to create eth0 and eth1 on the booted qemu
with two interfaces:
       Eth0: MAC 00:11:a:0:2:19 - IP 10.0.2.25
       Eth1: MAC 00:11:a:0:1:19 - IP 10.0.1.25

This way if i pass different parameters for the next time i boot or if i
boot a second qemu i can use different IP addresses.

On the guest fs you will need a little utility i am attaching - code
could use some cleanup to look at the MAC addresses and convert them to
IP addresses. You pass the device name to it. I compiled it and put it
in /sbin/eth2ip; my scripts to bring up devices first call it
as /sbin/eth2ip ethx. It takes the device, ifconfigs it up then attaches
an IP address extracted from the MAC address to it.

Theres probably an easy way to do this - but i am just in the process of
discovering qemu - so please let me know. 
Else if it doesnt exist and you like this patch please apply it. 
I am not on the list so please CC me on any responses.

cheers,
jamal

[-- Attachment #2: ethmac2ip.c --]
[-- Type: text/x-csrc, Size: 5186 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <errno.h>
#undef __KERNEL__
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <signal.h>
#include <linux/types.h>

#define NIPQUAD(addr) \
	((unsigned char *) &addr)[0], \
	((unsigned char *) &addr)[1], \
	((unsigned char *) &addr)[2], \
	((unsigned char *) &addr)[3]

int
get_ctl_fd(void)
{
	int s_errno;
	int fd;

	fd = socket(PF_INET, SOCK_DGRAM, 0);
	if (fd >= 0)
		return fd;
	s_errno = errno;
	fd = socket(PF_PACKET, SOCK_DGRAM, 0);
	if (fd >= 0)
		return fd;
	fd = socket(PF_INET6, SOCK_DGRAM, 0);
	if (fd >= 0)
		return fd;
	errno = s_errno;
	perror("Cannot create control socket");
	return -1;
}

int
get_flags(char *intf)
{
	struct ifreq ifr;
	int sk = get_ctl_fd();
	if (sk < 0)
		return -1;
	memset(&ifr, 0, sizeof ifr);
	strncpy(ifr.ifr_name, intf, sizeof (ifr.ifr_name));
	if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
		fprintf(stderr, "error getting device %s: ", intf);
		close(sk);
		return -1;
	}

	close(sk);
	return ifr.ifr_flags;
}

int
do_chflags(char *dev, __u32 flags, __u32 mask)
{
	struct ifreq ifr;
	int fd;
	int err;

	strcpy(ifr.ifr_name, dev);
	fd = get_ctl_fd();
	if (fd < 0)
		return -1;
	err = ioctl(fd, SIOCGIFFLAGS, &ifr);
	if (err) {
		perror("SIOCGIFFLAGS");
		close(fd);
		return -1;
	}
	if ((ifr.ifr_flags ^ flags) & mask) {
		ifr.ifr_flags &= ~mask;
		ifr.ifr_flags |= mask & flags;
		err = ioctl(fd, SIOCSIFFLAGS, &ifr);
		if (err)
			perror("SIOCSIFFLAGS");
	}
	close(fd);
	return err;
}

int
set_admin_up(char *dev, __u32 flags, __u32 mask)
{
	mask |= IFF_UP;
	flags |= IFF_UP;
	return do_chflags(dev, flags, mask);
}

int
set_admin_down(char *dev, __u32 flags, __u32 mask)
{
	mask |= IFF_UP;
	flags &= ~IFF_UP;
	return do_chflags(dev, flags, mask);
}

int
print_hw_addr(char *smac)
{
	printf(" %x:%x:%x:%x:%x:%x ", smac[0] & 0xff,
	       smac[1] & 0xff, smac[2] & 0xff, smac[3] & 0xff, smac[4] & 0xff,
	       smac[5] & 0xff);
}

int
get_hw_addr(char *name, char *smac)
{
	struct ifreq ifr;

	int s = get_ctl_fd();
	if (s < 0)
		return -1;

	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));

	if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
		fprintf(stderr, "ioctl(SIOCGIFHWADDR): %s", name);
		return -1;
	}

	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
		fprintf(stderr, "interface %s is not Ethernet!", name);
		return -1;
	}

	memcpy(smac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);

	//print_hw_addr(smac);

	return 0;

}
static 
__inline__ __u32 inet_make_mask(int logmask)
{
	if (logmask)
		return htonl(~((1<<(32-logmask))-1));
	return 0;
}


#define satosin(sa)  ((struct sockaddr_in *) (sa))
int
add_ifa(char *intf, __u32 NiIPAddr, __u32 NetMask)
{
	int sk;
	struct ifreq ifr;
	__u32 bcastMask = (NiIPAddr & NetMask) | ~NetMask;

	sk = get_ctl_fd();
	if (sk < 0)
		return -1;

	memset(&ifr, 0, sizeof ifr);
	strncpy(ifr.ifr_name, intf, IFNAMSIZ - 1);

	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
	satosin(&ifr.ifr_addr)->sin_addr.s_addr = NiIPAddr;

	if (0 > ioctl(sk, SIOCSIFADDR, (char *) &ifr)) {
		printf("Failed SIOCSIFADDR on %s\n", intf);
		close(sk);
		return -1;
	}
	//                    
	//   Set new Network Mask.
	//
	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
	satosin(&ifr.ifr_addr)->sin_addr.s_addr = bcastMask;
	//
	if (NiIPAddr && (0 > ioctl(sk, SIOCSIFBRDADDR, (char *) &ifr))) {
		printf("Failed SIOCSIFBRDADDR on %s\n", intf);
		close(sk);
		return -1;
	}
	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
	satosin(&ifr.ifr_addr)->sin_addr.s_addr = NetMask;
	if (NiIPAddr && (0 > ioctl(sk, SIOCSIFNETMASK, (char *) &ifr))) {
		printf("Failed SIOCSIFNETMASK on %s\n", intf);
		close(sk);
		return -1;
	}

	close(sk);
	return 0;
}

// set ip address from MAC
// smac[6] 
// get_hw_addr("eth0",&smac);
// build ipfrommac
//__u32 netmask = inet_make_mask(24);
// ret = add_ifa("eth0", ipfrommac[0], netmask);
// set_admin_up("eth0",0.0);

int
main(int argc, char *argv[])
{
	char smac[6];
	__u32 ethip = 0;
	__u32 netmask = inet_make_mask(24);

	if (argc != 2) {
		fprintf(stderr,"Device name is needed\n");
		exit(0);
	}
// argv[1] contains the eth device name
	int ret = get_hw_addr(argv[1], smac);
	if (ret < 0) {
		fprintf(stderr,"Failed to get mac address of %s\n",argv[1]);
		exit(0);
	}
	print_hw_addr(smac);
	fprintf(stdout, "IP address %d.%d.%d.%d\n",
		smac[2] & 0xff, smac[3] & 0xff, smac[4] & 0xff, smac[5] & 0xff);

	ethip |= smac[5] & 0xff;
	ethip <<= 8;
	ethip |= smac[4] & 0xff;
	ethip <<= 8;
	ethip |= smac[3] & 0xff;
	ethip <<= 8;
	ethip |= smac[2] & 0xff;

	fprintf(stdout,"converted IP %d.%d.%d.%d\n", NIPQUAD(ethip));
	ret = add_ifa(argv[1], ethip, netmask);
	if (ret < 0) {
		fprintf(stderr,"Failed to set IP  address of %s\n",argv[1]);
		exit(0);
	}
	ret = set_admin_up(argv[1], 0, 0);
	if (ret < 0) {
		fprintf(stderr,"Failed to bring up %s\n",argv[1]);
		exit(0);
	}

	return ret;
}

[-- Attachment #3: qemu-p --]
[-- Type: text/plain, Size: 10511 bytes --]

--- qemu-0.6.1/vl.c	2004-11-14 15:51:33.000000000 -0500
+++ qemu-0.6.1-mod/vl.c	2005-04-23 18:33:03.000000000 -0500
@@ -1622,10 +1622,10 @@
     qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque);
 }
 
-static int net_tun_init(NetDriverState *nd)
+static int net_tun_init(NetDriverState *nd, int *IDs,char *IP)
 {
     int pid, status;
-    char *args[3];
+    char *args[6];
     char **parg;
 
     nd->fd = tun_open(nd->ifname, sizeof(nd->ifname));
@@ -1636,9 +1636,16 @@
     pid = fork();
     if (pid >= 0) {
         if (pid == 0) {
+	    char a[5],b[5];
             parg = args;
             *parg++ = network_script;
             *parg++ = nd->ifname;
+            sprintf(a, "%d", *IDs);
+            *parg++ = a;
+            IDs++;
+            sprintf(b, "%d", *IDs);
+            *parg++ = b;
+            *parg++ = IP;
             *parg++ = NULL;
             execv(network_script, args);
             exit(1);
@@ -2512,6 +2519,14 @@
            "Network options:\n"
            "-nics n         simulate 'n' network cards [default=1]\n"
            "-macaddr addr   set the mac address of the first interface\n"
+           "-macaddr0 addr  set the mac address of the first interface\n"
+           "-macaddr1 addr  set the mac address of the second interface\n"
+           "-macaddr2 addr  set the mac address of the third interface\n"
+           "-macaddr3 addr  set the mac address of the fourth interface\n"
+           "-macaddr4 addr  set the mac address of the fifth interface\n"
+           "-macaddr5 addr  set the mac address of the sixth interface\n"
+           "-ID1 identifier  extra ID passed to host script\n"
+           "-ID2 identifier  extra ID passed to host script\n"
            "-n script       set tap/tun network init script [default=%s]\n"
            "-tun-fd fd      use this fd as already opened tap/tun interface\n"
 #ifdef CONFIG_SLIRP
@@ -2593,7 +2608,15 @@
     QEMU_OPTION_enable_audio,
 
     QEMU_OPTION_nics,
+    QEMU_OPTION_ID1,
+    QEMU_OPTION_ID2,
     QEMU_OPTION_macaddr,
+    QEMU_OPTION_macaddr0,
+    QEMU_OPTION_macaddr1,
+    QEMU_OPTION_macaddr2,
+    QEMU_OPTION_macaddr3,
+    QEMU_OPTION_macaddr4,
+    QEMU_OPTION_macaddr5,
     QEMU_OPTION_n,
     QEMU_OPTION_tun_fd,
     QEMU_OPTION_user_net,
@@ -2649,7 +2672,15 @@
     { "enable-audio", 0, QEMU_OPTION_enable_audio },
 
     { "nics", HAS_ARG, QEMU_OPTION_nics},
+    { "ID1", HAS_ARG, QEMU_OPTION_ID1},
+    { "ID2", HAS_ARG, QEMU_OPTION_ID2},
     { "macaddr", HAS_ARG, QEMU_OPTION_macaddr},
+    { "macaddr0", HAS_ARG, QEMU_OPTION_macaddr0},
+    { "macaddr1", HAS_ARG, QEMU_OPTION_macaddr1},
+    { "macaddr2", HAS_ARG, QEMU_OPTION_macaddr2},
+    { "macaddr3", HAS_ARG, QEMU_OPTION_macaddr3},
+    { "macaddr4", HAS_ARG, QEMU_OPTION_macaddr4},
+    { "macaddr5", HAS_ARG, QEMU_OPTION_macaddr4},
     { "n", HAS_ARG, QEMU_OPTION_n },
     { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd },
 #ifdef CONFIG_SLIRP
@@ -2747,6 +2778,7 @@
     int use_gdbstub, gdbstub_port;
 #endif
     int i, has_cdrom;
+    int IDs[2];
     int snapshot, linux_boot;
     CPUState *env;
     const char *initrd_filename;
@@ -2756,6 +2788,7 @@
     int cyls, heads, secs;
     int start_emulation = 1;
     uint8_t macaddr[6];
+    uint8_t macaddrs[6][6];
     int net_if_type, nb_tun_fds, tun_fds[MAX_NICS];
     int optind;
     const char *r, *optarg;
@@ -2805,6 +2838,15 @@
     macaddr[3] = 0x12;
     macaddr[4] = 0x34;
     macaddr[5] = 0x56;
+    /* default IDs are 0 */
+    IDs[0]=IDs[1]=0;
+
+    for (i = 0; i < 6; i++) {
+	    int j;
+	    for (j = 0; j < 6; j++) {
+		    macaddrs[i][j] = 0xFF;
+	    }
+    }
     
     optind = 1;
     for(;;) {
@@ -2932,6 +2974,16 @@
                     exit(1);
                 }
                 break;
+            case QEMU_OPTION_ID1:
+                {
+			IDs[0]=atoi(optarg);
+                }
+                break;
+            case QEMU_OPTION_ID2:
+                {
+			IDs[1]=atoi(optarg);
+                }
+                break;
             case QEMU_OPTION_macaddr:
                 {
                     const char *p;
@@ -2953,6 +3005,126 @@
                     }
                 }
                 break;
+            case QEMU_OPTION_macaddr0:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[0][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_macaddr1:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[1][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_macaddr2:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[2][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_macaddr3:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[3][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_macaddr4:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[4][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
+            case QEMU_OPTION_macaddr5:
+                {
+                    const char *p;
+                    int i;
+                    p = optarg;
+                    for(i = 0; i < 6; i++) {
+                        macaddrs[5][i] = strtol(p, (char **)&p, 16);
+                        if (i == 5) {
+                            if (*p != '\0') 
+                                goto macaddr_error;
+                        } else {
+                            if (*p != ':') {
+                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
+                                exit(1);
+                            }
+                            p++;
+                        }
+                    }
+                }
+                break;
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
 		tftp_prefix = optarg;
@@ -3132,13 +3304,25 @@
     for(i = 0; i < nb_nics; i++) {
         NetDriverState *nd = &nd_table[i];
         nd->index = i;
+	char IP[256];
+	memset(IP,0,256);
         /* init virtual mac address */
-        nd->macaddr[0] = macaddr[0];
-        nd->macaddr[1] = macaddr[1];
-        nd->macaddr[2] = macaddr[2];
-        nd->macaddr[3] = macaddr[3];
-        nd->macaddr[4] = macaddr[4];
-        nd->macaddr[5] = macaddr[5] + i;
+	if (macaddrs[i][0] == 0xFF) {
+             nd->macaddr[0] = macaddr[0];
+             nd->macaddr[1] = macaddr[1];
+             nd->macaddr[2] = macaddr[2];
+             nd->macaddr[3] = macaddr[3];
+             nd->macaddr[4] = macaddr[4];
+             nd->macaddr[5] = macaddr[5] + i;
+	} else {
+             nd->macaddr[0] = macaddrs[i][0];
+             nd->macaddr[1] = macaddrs[i][1];
+             nd->macaddr[2] = macaddrs[i][2];
+             nd->macaddr[3] = macaddrs[i][3];
+             nd->macaddr[4] = macaddrs[i][4];
+             nd->macaddr[5] = macaddrs[i][5];
+	     sprintf(IP, "%d.%d.%d.%d", nd->macaddr[2],nd->macaddr[3],nd->macaddr[4],nd->macaddr[5]);
+	}
         switch(net_if_type) {
 #if defined(CONFIG_SLIRP)
         case NET_IF_USER:
@@ -3150,7 +3334,7 @@
             if (i < nb_tun_fds) {
                 net_fd_init(nd, tun_fds[i]);
             } else {
-                if (net_tun_init(nd) < 0)
+                if (net_tun_init(nd, IDs,IP) < 0)
                     net_dummy_init(nd);
             }
             break;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-04-23 22:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-23 22:08 [Qemu-devel] patch for allowing automated IP assignment based on MAC jamal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).