This patch is to allow solaris to create a tap device in qemu, using the 
modified
tun/tap driver at http://www.whiteboard.ne.jp/~admin2/tuntap.

I'm also including qemu_tap.c which is a setuid wrapper which sets up the
tap, uses /etc/qemu-ifup (included - modify for your environment) and a
start script (dsl.sh,  minimal, but shows what needs done).

To build qemu_tap, it's very simple.

gcc -o qemu_tap qemu_tap.c
sudo chown root qemu_tap
sudo chmod 4755 qemu_tap

The bridge code at http://www.whiteboard.ne.jp/~admin2/tuntap should
also work, and should only require /etc/qemu-ifup to contain the commands
to add the bridge, ie, no ifconfig should be needed.

Attachment: qemu-solaris-tap-patch
Description: Binary data

Attachment: qemu-ifup
Description: Binary data

/*
** qemu_tap.c:	SUID wrapper program to allow non-root user to use tap network
**              on Solaris, derived from qemu_tun.c by Sittichai Palansong
**              with guidance from the tap code he wrote in qemu/vl.c
**
** Modified by: Ben Taylor 
** Updated:		02/09/2007
**
** Author:      Sittichai Palanisong
** Updated:		05/20/2005
**
** You are expected to be able to write a shell script wrapper to invoke
** qemu with the right parameters for a tap device passed in as a file
** descriptor.  SUID privileges are only for setting the TAP device up for use.
**
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>
#include <stropts.h>
#include <net/if.h>

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif

#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif

#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif

#define TUNNEWPPA       (('T'<<16) | 0x0001)

int main(int argc, char *argv[])
{
    char buf[2048], ifname[10]="";
    int fd, len;
    int uid, pid, status;
    char tap_fd[32];
    char *args[4];
    char *qemu_script = "./qemu.sh";
    char *network_script = "/etc/qemu-ifup";

    if(argc > 1){
        qemu_script = argv[1];
    }

    uid = getuid();

    if( (fd = tap_alloc(ifname)) < 0 ){
        printf("Cannot allocate TAP device\n");
        exit(1);
    }

    /* try to launch network init script */
    args[0] = network_script;
    args[1] = ifname;
    args[2] = NULL;
    pid = fork();
    if (pid >= 0) {
        if (pid == 0) {
            /* child */
            execv(network_script, args);
            exit(1);
        }
        /* parent */
        while (waitpid(pid, &status, 0) != pid);
        if (!WIFEXITED(status) ||
            WEXITSTATUS(status) != 0) {
            fprintf(stderr, "%s: could not launch network script\n",
                    network_script);
            exit(1);
        }
    }

    /* now switch to back to calling user */
    if(setuid( uid) < 0){
       printf("Cannot switch to UID %d\n", uid);
       exit(1);
    }
    printf("Switch to UID %d\n", uid);

    /* try to launch qemu script*/
    sprintf( tap_fd, "%d", fd);
    args[0] = qemu_script;
    args[1] = "-t";
    args[2] = tap_fd;
    args[3] = NULL;

    printf("Invoking %s %s %s\n", args[0], args[1], args[2]);
    execv( qemu_script, args);
    exit(1);
}

/* 
 * Allocate TAP device, returns opened fd. 
 * Stores dev name in the first arg(must be large enough).
 */  
int tap_alloc(char *dev)
{
    int tap_fd, if_fd, ppa = -1;
    static int ip_fd = 0;
    char *ptr;
    static int arp_fd = 0;
    int ip_muxid, arp_muxid;
    struct strioctl  strioc_if, strioc_ppa;
    int link_type = I_PLINK;;
    struct lifreq ifr;
    char actual_name[32] = "";

    memset(&ifr, 0x0, sizeof(ifr));

    if ( *dev ) {
       ptr = dev;	
       while ( *ptr && !isdigit((int)*ptr) ) ptr++; 
       ppa = atoi(ptr);
    }

    /* Check if IP device was opened */
    if ( ip_fd )
       close(ip_fd);

    if ( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0 ) {
       syslog(LOG_ERR, "Can't open /dev/udp");
       return -1;
    }

    if ( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 0 ) {
       syslog(LOG_ERR, "Can't open /dev/tap");
       return -1;
    }

    /* Assign a new PPA and get its unit number. */
    strioc_ppa.ic_cmd = TUNNEWPPA;
    strioc_ppa.ic_timout = 0;
    strioc_ppa.ic_len = sizeof(ppa);
    strioc_ppa.ic_dp = (char *)&ppa;
    if ( (ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0 )
       syslog (LOG_ERR, "Can't assign new interface");

    if ( (if_fd = open("/dev/tap", O_RDWR, 0)) < 0 ) {
       syslog(LOG_ERR, "Can't open /dev/tap (2)");
       return -1;
    }
    if ( ioctl(if_fd, I_PUSH, "ip") < 0 ) {
       syslog(LOG_ERR, "Can't push IP module");
       return -1;
    }
    if ( ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0 )
        syslog(LOG_ERR, "Can't get flags\n");

    snprintf (actual_name, 32, "tap%d", ppa);
    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));

    ifr.lifr_ppa = ppa;
    /* Assign ppa according to the unit number returned by tun device */

    if ( ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0 )
        syslog (LOG_ERR, "Can't set PPA %d", ppa);
    if ( ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0 )
        syslog (LOG_ERR, "Can't get flags\n");
    /* Push arp module to if_fd */
    if ( ioctl (if_fd, I_PUSH, "arp") < 0 )
        syslog (LOG_ERR, "Can't push ARP module (2)");

    /* Push arp module to ip_fd */
    if ( ioctl (ip_fd, I_POP, NULL) < 0 )
        syslog (LOG_ERR, "I_POP failed\n");
    if ( ioctl (ip_fd, I_PUSH, "arp") < 0 )
        syslog (LOG_ERR, "Can't push ARP module (3)\n");
    /* Open arp_fd */
    if ( (arp_fd = open ("/dev/tap", O_RDWR, 0)) < 0 )
       syslog (LOG_ERR, "Can't open /dev/tap (3)");
    /* Push arp module to arp_fd */
    if ( ioctl (arp_fd, I_PUSH, "arp") < 0 )
       syslog (LOG_ERR, "Can't push ARP module (4)\n");

    /* Set ifname to arp */
    strioc_if.ic_cmd = SIOCSLIFNAME;
    strioc_if.ic_timout = 0;
    strioc_if.ic_len = sizeof(ifr);
    strioc_if.ic_dp = (char *)&ifr;
    if ( ioctl(arp_fd, I_STR, &strioc_if) < 0 ) {
        syslog (LOG_ERR, "Can't set ifname to arp\n");
    }

    if ( (ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0 ) {
       syslog(LOG_ERR, "Can't link TAP device to IP");
       return -1;
    }

    if ( (arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0 )
        syslog (LOG_ERR, "Can't link TAP device to ARP");

    close (if_fd);

    memset(&ifr, 0x0, sizeof(ifr));
    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
    ifr.lifr_ip_muxid  = ip_muxid;
    ifr.lifr_arp_muxid = arp_muxid;

    if ( ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0 )
    {
      ioctl (ip_fd, I_PUNLINK , arp_muxid);
      ioctl (ip_fd, I_PUNLINK, ip_muxid);
      syslog (LOG_ERR, "Can't set multiplexor id");
    }

    sprintf(dev, "tap%d", ppa);
    return tap_fd;
}

Attachment: dsl.sh
Description: Bourne shell script

_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to