[libvirt] [PATCH 4/5] macvtap support for libvirt -- helper code

Stefan Berger stefanb at us.ibm.com
Thu Feb 11 13:14:17 UTC 2010


Daniel Veillard <veillard at redhat.com> wrote on 02/11/2010 06:08:15 AM:

[...]
> > +int openMacvtapTap(virConnectPtr conn,
> > +                   const char *ifname,
> > +                   const unsigned char *macaddress,
> > +                   const char *linkdev,
> > +                   int mode,
> > +                   char **res_ifname);
> > +
> > +int delMacvtapByMACAddress(virConnectPtr conn,
> > +                           const unsigned char *macaddress,
> > +                           int *hasBusyDev);
> > +
> > +#endif /* WITH_MACVTAP */
> > +
> > +#define MACVTAP_MODE_PRIVATE_STR  "private"
> > +#define MACVTAP_MODE_VEPA_STR     "vepa"
> > +#define MACVTAP_MODE_BRIDGE_STR   "bridge"
> > +
> > +
> > +#endif
> 
> minor suggestion: #endif /* __UTIL_MACVTAP_H__ */

Fixed in upcoming patch.

[...]
> > +
> > +#define VIR_FROM_THIS VIR_FROM_NONE
> > +
> > +#define ReportError(conn, code, fmt...)    \
> > +        virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__,  \
> > +                               __FUNCTION__, __LINE__, fmt)
> 
>   Hum, I would suggest to use VIR_FROM_NET instead of VIR_FROM_NONE,
> or add a specific virErrorDomain enum in virterror.h (and associated
> code in virterror.c). I think VIR_FROM_NET is the simplest for now.

Fixed in upcoming patch.

> 
> > +#define MACVTAP_NAME_PREFIX   "macvtap"
> > +#define MACVTAP_NAME_PATTERN   "macvtap%d"
> > +
> > +static int nlOpen(virConnectPtr conn)
> > +{
> > +    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
> > +    if (fd < 0)
> > +        virReportSystemError(conn, errno,
> > +                             "%s",_("cannot open netlink socket"));
> > +    return fd;
> > +}
> > +
>   the function signature will change in the rebase as others in the code
>   too


True.

> 
> > +static void nlClose(int fd)
> > +{
> > +    close(fd);
> > +}
> > +
> > +
> > +static
> > +int nlComm(virConnectPtr conn,
> > +           struct nlmsghdr *nlmsg,
> > +           char *respbuf, int *respbuflen)
> > +{
> > +    int rc = 0;
> > +    struct sockaddr_nl nladdr = {
> > +            .nl_family = AF_NETLINK,
> > +            .nl_pid    = 0,
> > +            .nl_groups = 0,
> > +    };
> > +    char rcvbuf[1024];
> > +    ssize_t nbytes;
> > +    size_t tocopy;
> > +    int fd = nlOpen(conn);
> > +
> > +    if (fd < 0)
> > +        return -1;
> > +
> > +    nlmsg->nlmsg_flags |= NLM_F_ACK;
> > +
> > +    nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0,
> > +                    (struct sockaddr *)&nladdr, sizeof(nladdr));
> > +    if (nbytes < 0) {
> > +        virReportSystemError(conn, errno,
> > +                             "%s", _("cannot send to netlink 
socket"));
> > +        rc = -1;
> > +        goto err_exit;
> > +    }
> > +
> > +    memset(rcvbuf, 0x0, sizeof(rcvbuf));
> > +    while (1) {
> > +        socklen_t addrlen = sizeof(nladdr);
> > +        nbytes = recvfrom(fd, &rcvbuf, sizeof(rcvbuf), 0,
> > +                          (struct sockaddr *)&nladdr, &addrlen);
> > +        if (nbytes < 0) {
> > +            if (errno == EAGAIN || errno == EINTR)
> > +                continue;
> > +            virReportSystemError(conn, errno, "%s",
> > +                                 _("error receiving from netlink 
socket"));
> > +            rc = -1;
> > +            goto err_exit;
> > +        }
> > +
> > +        tocopy = (nbytes < *respbuflen) ? nbytes : *respbuflen;
> > +        memcpy(respbuf, rcvbuf, tocopy);
> > +        *respbuflen = tocopy;
> > +        break;
> > +    }
> > +
> > +err_exit:
> > +    nlClose(fd);
> > +    return rc;
> > +}
> 
>   Hum ... I don't see why we need rcvbuf here, we could make the 
recvfrom
> directly from respbuf with the respbuflen size, and no need to allocate
> one KB on stack. Also if for some reason one expect a large response
> packet there caller will be in control instead of a fixed size arbitrary
> limit in the function. The only case I could come to justifying this is
> if the caller want to truncate the response or if netlink force using
> a 1KB buffer input size.

In the next patch I'll write into the provided receive buffer.

> 
> [...]
> > +static int
> > +link_add(virConnectPtr conn,
> > +         const char *type,
> > +         const unsigned char *macaddress, int macaddrsize,
> > +         const char *ifname,
> > +         const char *srcdev,
> > +         uint32_t macvlan_mode,
> > +         int *retry)
> > +{
> > +    char nlmsgbuf[1024], recvbuf[1024];
> > +    struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
> > +    struct nlmsgerr *err;
> > +    char rtattbuf[256];
> > +    struct rtattr *rta, *rta1, *li;
> > +    struct ifinfomsg i = { .ifi_family = AF_UNSPEC };

[...]

> > +
> > +    if (macvlan_mode > 0) {
> > +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), 
IFLA_INFO_DATA,
> > +                           NULL, 0);
> > +        if (!rta)
> > +            goto buffer_too_small;
> > +
> > +        if (!(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, 
> rta->rta_len)))
> > +            goto buffer_too_small;
> > +
> > +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), 
IFLA_MACVLAN_MODE,
> > +                           &macvlan_mode, sizeof(macvlan_mode));
> > +        if (!rta)
> > +            goto buffer_too_small;
> > +
> > +        if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
> > +            goto buffer_too_small;
> > +
> > +        rta1->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)rta1;
> > +    }
> > +
> > +    li->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)li;
> 
>   I must admit that I'm again a bit surprized by the buffer handling.
> There is a function to append stuff on a buffer, so all this code could
> be changed to use dymanic allocation easilly and not be stuck on a fixed
> buffer size allocated on stack (a couple of buffers even). since we call
> nlComm below, we already have 3KB of stack allocated buffers piled up
> and honnestly none of this is required as far as I understand.

The thing with the netlink messages is that their content needs to be 
'nested', meaning that you 
add data to a netlink message parameter, depending on availability of 
parameters in the function, 
i.e., test for macvlan_mode > 0, and only later on you can determine how 
large the size of the 
nested information was. Above I am setting the li pointer in the 
nlAppend() call. Later on only 
I set the size of the nested information in the li->rta_len = ... line. So 
the pointer for li better
not have changed while reallocating the target message buffer for example.

It's true that the size of the buffers is rather generous. I could limit 
them to around 128 bytes if
that's better. At least that is sufficient.

> > +
> > +    snprintf(path, sizeof(path), "/sys/class/net/%s/ifindex", 
ifname);
> 
>   virBuildPathInternal could be another way, in any case one should
>   check the return value

Checking return value in next patch.

> 
> > +    file = fopen(path, "r");
> > +
> > +    if (!file) {
> > +        virReportSystemError(conn, errno,
> > +                             _("cannot open macvtap file %s to 
determine "
> > +                               "interface index"), path);
> > +        return -1;
> > +    }
> > +
> > +    if (fscanf(file, "%d", &ifindex) != 1) {
> > +        virReportSystemError(conn, errno,
> > +                             "%s",_("cannot determine macvtap's 
> tap device "
> > +                             "interface index"));
> > +        fclose(file);
> > +        return -1;
> > +    }
> > +
> > +    fclose(file);
> > +
> > +    snprintf(tapname, sizeof(tapname), "/dev/tap%d", ifindex);
> > +
> > +    while (1) {
> > +        // may need to wait for udev to be done
> > +        tapfd = open(tapname, O_RDWR);
> > +        if (tapfd < 0 && retries--) {
> > +            usleep(20000);
> > +            continue;
> > +        }
> > +        break;
> > +    }
> 
>   hum, the function should check retries > 0 argument otherwise this
> could hang the daemon.

Changed this.

> 
> > +    if (tapfd < 0)
> > +        virReportSystemError(conn, errno,
> > +                             _("cannot open macvtap tap device %s"),
> > +                             tapname);
> > +
> > +    return tapfd;
> > +}
> 
>   okay, I'm not too convinced by the buffer management code, but that
> could be cleaned up in a later pach, so ACK

I'll shrink the sizes of the buffers. Want to be careful about dynamic 
allocation
of the buffers in this case, though.

   Stefan


> 
> Daniel
> 
> -- 
> Daniel Veillard      | libxml Gnome XML XSLT toolkit  
http://xmlsoft.org/
> daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
> http://veillard.com/ | virtualization library  http://libvirt.org/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20100211/a79f008e/attachment-0001.htm>


More information about the libvir-list mailing list