From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1DPSyX-0003kb-SP for qemu-devel@nongnu.org; Sat, 23 Apr 2005 18:19:45 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1DPSyW-0003kP-SO for qemu-devel@nongnu.org; Sat, 23 Apr 2005 18:19:45 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DPSyW-0008Ow-P4 for qemu-devel@nongnu.org; Sat, 23 Apr 2005 18:19:44 -0400 Received: from [209.197.145.104] (helo=mx01.cybersurf.com) by monty-python.gnu.org with esmtp (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.34) id 1DPSrZ-0008OP-8x for qemu-devel@nongnu.org; Sat, 23 Apr 2005 18:12:33 -0400 Received: from mail.cyberus.ca ([209.197.145.21]) by mx01.cybersurf.com with esmtp (Exim 4.30) id 1DPSni-0006Yb-D5 for qemu-devel@nongnu.org; Sat, 23 Apr 2005 16:08:34 -0600 Received: from cpe0030ab124d2f-cm014500000962.cpe.net.cable.rogers.com ([24.103.99.32] helo=[10.0.0.229]) by mail.cyberus.ca with esmtp (Exim 4.20) id 1DPSnj-0004s0-Ky for qemu-devel@nongnu.org; Sat, 23 Apr 2005 18:08:35 -0400 From: jamal Content-Type: multipart/mixed; boundary="=-rC7SFtz9JzCyUvCWzJPe" Date: Sat, 23 Apr 2005 18:08:30 -0400 Message-Id: <1114294110.7669.130.camel@localhost.localdomain> Mime-Version: 1.0 Subject: [Qemu-devel] patch for allowing automated IP assignment based on MAC Reply-To: hadi@cyberus.ca, qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --=-rC7SFtz9JzCyUvCWzJPe Content-Type: text/plain Content-Transfer-Encoding: 7bit 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 --=-rC7SFtz9JzCyUvCWzJPe Content-Disposition: attachment; filename=ethmac2ip.c Content-Type: text/x-csrc; name=ethmac2ip.c; charset=UTF-8 Content-Transfer-Encoding: 7bit #include #include #include #include #include #include #undef __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; } --=-rC7SFtz9JzCyUvCWzJPe Content-Disposition: attachment; filename=qemu-p Content-Type: text/plain; name=qemu-p; charset=UTF-8 Content-Transfer-Encoding: 7bit --- 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; --=-rC7SFtz9JzCyUvCWzJPe--