<br><tt><font size=2>Daniel Veillard <veillard@redhat.com> wrote
on 02/11/2010 06:08:15 AM:<br>
</font></tt>
<br><tt><font size=2>[...]</font></tt>
<br><tt><font size=2>> > +int openMacvtapTap(virConnectPtr conn,<br>
> > +                  
const char *ifname,<br>
> > +                  
const unsigned char *macaddress,<br>
> > +                  
const char *linkdev,<br>
> > +                  
int mode,<br>
> > +                  
char **res_ifname);<br>
> > +<br>
> > +int delMacvtapByMACAddress(virConnectPtr conn,<br>
> > +                  
        const unsigned char *macaddress,<br>
> > +                  
        int *hasBusyDev);<br>
> > +<br>
> > +#endif /* WITH_MACVTAP */<br>
> > +<br>
> > +#define MACVTAP_MODE_PRIVATE_STR  "private"<br>
> > +#define MACVTAP_MODE_VEPA_STR     "vepa"<br>
> > +#define MACVTAP_MODE_BRIDGE_STR   "bridge"<br>
> > +<br>
> > +<br>
> > +#endif<br>
> <br>
> minor suggestion: #endif /* __UTIL_MACVTAP_H__ */</font></tt>
<br>
<br><tt><font size=2>Fixed in upcoming patch.</font></tt>
<br>
<br><tt><font size=2>[...]</font></tt>
<br><tt><font size=2>> > +<br>
> > +#define VIR_FROM_THIS VIR_FROM_NONE<br>
> > +<br>
> > +#define ReportError(conn, code, fmt...)      
                     
     \<br>
> > +        virReportErrorHelper(conn, VIR_FROM_NONE,
code, __FILE__,        \<br>
> > +                  
            __FUNCTION__, __LINE__, fmt)<br>
> <br>
>   Hum, I would suggest to use VIR_FROM_NET instead of VIR_FROM_NONE,<br>
> or add a specific virErrorDomain enum in virterror.h (and associated<br>
> code in virterror.c). I think VIR_FROM_NET is the simplest for now.</font></tt>
<br>
<br><tt><font size=2>Fixed in upcoming patch.</font></tt>
<br><tt><font size=2><br>
> <br>
> > +#define MACVTAP_NAME_PREFIX   "macvtap"<br>
> > +#define MACVTAP_NAME_PATTERN   "macvtap%d"<br>
> > +<br>
> > +static int nlOpen(virConnectPtr conn)<br>
> > +{<br>
> > +    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);<br>
> > +    if (fd < 0)<br>
> > +        virReportSystemError(conn, errno,<br>
> > +                  
          "%s",_("cannot open netlink
socket"));<br>
> > +    return fd;<br>
> > +}<br>
> > +<br>
>   the function signature will change in the rebase as others
in the code<br>
>   too</font></tt>
<br>
<br>
<br><tt><font size=2>True.</font></tt>
<br><tt><font size=2><br>
> <br>
> > +static void nlClose(int fd)<br>
> > +{<br>
> > +    close(fd);<br>
> > +}<br>
> > +<br>
> > +<br>
> > +static<br>
> > +int nlComm(virConnectPtr conn,<br>
> > +           struct nlmsghdr *nlmsg,<br>
> > +           char *respbuf, int *respbuflen)<br>
> > +{<br>
> > +    int rc = 0;<br>
> > +    struct sockaddr_nl nladdr = {<br>
> > +            .nl_family = AF_NETLINK,<br>
> > +            .nl_pid    =
0,<br>
> > +            .nl_groups = 0,<br>
> > +    };<br>
> > +    char rcvbuf[1024];<br>
> > +    ssize_t nbytes;<br>
> > +    size_t tocopy;<br>
> > +    int fd = nlOpen(conn);<br>
> > +<br>
> > +    if (fd < 0)<br>
> > +        return -1;<br>
> > +<br>
> > +    nlmsg->nlmsg_flags |= NLM_F_ACK;<br>
> > +<br>
> > +    nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len,
0,<br>
> > +                  
 (struct sockaddr *)&nladdr, sizeof(nladdr));<br>
> > +    if (nbytes < 0) {<br>
> > +        virReportSystemError(conn, errno,<br>
> > +                  
          "%s", _("cannot send
to netlink socket"));<br>
> > +        rc = -1;<br>
> > +        goto err_exit;<br>
> > +    }<br>
> > +<br>
> > +    memset(rcvbuf, 0x0, sizeof(rcvbuf));<br>
> > +    while (1) {<br>
> > +        socklen_t addrlen = sizeof(nladdr);<br>
> > +        nbytes = recvfrom(fd, &rcvbuf,
sizeof(rcvbuf), 0,<br>
> > +                  
       (struct sockaddr *)&nladdr, &addrlen);<br>
> > +        if (nbytes < 0) {<br>
> > +            if (errno == EAGAIN
|| errno == EINTR)<br>
> > +                continue;<br>
> > +            virReportSystemError(conn,
errno, "%s",<br>
> > +                  
              _("error receiving
from netlink socket"));<br>
> > +            rc = -1;<br>
> > +            goto err_exit;<br>
> > +        }<br>
> > +<br>
> > +        tocopy = (nbytes < *respbuflen)
? nbytes : *respbuflen;<br>
> > +        memcpy(respbuf, rcvbuf, tocopy);<br>
> > +        *respbuflen = tocopy;<br>
> > +        break;<br>
> > +    }<br>
> > +<br>
> > +err_exit:<br>
> > +    nlClose(fd);<br>
> > +    return rc;<br>
> > +}<br>
> <br>
>   Hum ... I don't see why we need rcvbuf here, we could make
the recvfrom<br>
> directly from respbuf with the respbuflen size, and no need to allocate<br>
> one KB on stack. Also if for some reason one expect a large response<br>
> packet there caller will be in control instead of a fixed size arbitrary<br>
> limit in the function. The only case I could come to justifying this
is<br>
> if the caller want to truncate the response or if netlink force using<br>
> a 1KB buffer input size.</font></tt>
<br>
<br><tt><font size=2>In the next patch I'll write into the provided receive
buffer.</font></tt>
<br><tt><font size=2><br>
> <br>
> [...]<br>
> > +static int<br>
> > +link_add(virConnectPtr conn,<br>
> > +         const char *type,<br>
> > +         const unsigned char *macaddress,
int macaddrsize,<br>
> > +         const char *ifname,<br>
> > +         const char *srcdev,<br>
> > +         uint32_t macvlan_mode,<br>
> > +         int *retry)<br>
> > +{<br>
> > +    char nlmsgbuf[1024], recvbuf[1024];<br>
> > +    struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf,
*resp;<br>
> > +    struct nlmsgerr *err;<br>
> > +    char rtattbuf[256];<br>
> > +    struct rtattr *rta, *rta1, *li;<br>
> > +    struct ifinfomsg i = { .ifi_family = AF_UNSPEC
};<br>
</font></tt>
<br><tt><font size=2>[...]</font></tt>
<br>
<br><tt><font size=2>> > +<br>
> > +    if (macvlan_mode > 0) {<br>
> > +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf),
IFLA_INFO_DATA,<br>
> > +                  
        NULL, 0);<br>
> > +        if (!rta)<br>
> > +            goto buffer_too_small;<br>
> > +<br>
> > +        if (!(rta1 = nlAppend(nlm, sizeof(nlmsgbuf),
rtattbuf, <br>
> rta->rta_len)))<br>
> > +            goto buffer_too_small;<br>
> > +<br>
> > +        rta = rtattrCreate(rtattbuf, sizeof(rtattbuf),
IFLA_MACVLAN_MODE,<br>
> > +                  
        &macvlan_mode, sizeof(macvlan_mode));<br>
> > +        if (!rta)<br>
> > +            goto buffer_too_small;<br>
> > +<br>
> > +        if (!nlAppend(nlm, sizeof(nlmsgbuf),
rtattbuf, rta->rta_len))<br>
> > +            goto buffer_too_small;<br>
> > +<br>
> > +        rta1->rta_len = (char *)nlm +
nlm->nlmsg_len - (char *)rta1;<br>
> > +    }<br>
> > +<br>
> > +    li->rta_len = (char *)nlm + nlm->nlmsg_len
- (char *)li;<br>
> <br>
>   I must admit that I'm again a bit surprized by the buffer handling.<br>
> There is a function to append stuff on a buffer, so all this code
could<br>
> be changed to use dymanic allocation easilly and not be stuck on a
fixed<br>
> buffer size allocated on stack (a couple of buffers even). since we
call<br>
> nlComm below, we already have 3KB of stack allocated buffers piled
up<br>
> and honnestly none of this is required as far as I understand.</font></tt>
<br>
<br><tt><font size=2>The thing with the netlink messages is that their
content needs to be 'nested', meaning that you </font></tt>
<br><tt><font size=2>add data to a netlink message parameter, depending
on availability of parameters in the function, </font></tt>
<br><tt><font size=2>i.e., test for macvlan_mode > 0, and only later
on you can determine how large the size of the </font></tt>
<br><tt><font size=2>nested information was. Above I am setting the li
pointer in the nlAppend() call. Later on only </font></tt>
<br><tt><font size=2>I set the size of the nested information in the li->rta_len
= ... line. So the pointer for li better</font></tt>
<br><tt><font size=2>not have changed while reallocating the target message
buffer for example.</font></tt>
<br>
<br><tt><font size=2>It's true that the size of the buffers is rather generous.
I could limit them to around 128 bytes if</font></tt>
<br><tt><font size=2>that's better. At least that is sufficient.</font></tt>
<br>
<br><tt><font size=2>> > +<br>
> > +    snprintf(path, sizeof(path), "/sys/class/net/%s/ifindex",
ifname);<br>
> <br>
>   virBuildPathInternal could be another way, in any case one
should<br>
>   check the return value</font></tt>
<br>
<br><tt><font size=2>Checking return value in next patch.</font></tt>
<br><tt><font size=2><br>
> <br>
> > +    file = fopen(path, "r");<br>
> > +<br>
> > +    if (!file) {<br>
> > +        virReportSystemError(conn, errno,<br>
> > +                  
          _("cannot open macvtap file %s
to determine "<br>
> > +                  
            "interface index"),
path);<br>
> > +        return -1;<br>
> > +    }<br>
> > +<br>
> > +    if (fscanf(file, "%d", &ifindex)
!= 1) {<br>
> > +        virReportSystemError(conn, errno,<br>
> > +                  
          "%s",_("cannot determine
macvtap's <br>
> tap device "<br>
> > +                  
          "interface index"));<br>
> > +        fclose(file);<br>
> > +        return -1;<br>
> > +    }<br>
> > +<br>
> > +    fclose(file);<br>
> > +<br>
> > +    snprintf(tapname, sizeof(tapname), "/dev/tap%d",
ifindex);<br>
> > +<br>
> > +    while (1) {<br>
> > +        // may need to wait for udev to
be done<br>
> > +        tapfd = open(tapname, O_RDWR);<br>
> > +        if (tapfd < 0 && retries--)
{<br>
> > +            usleep(20000);<br>
> > +            continue;<br>
> > +        }<br>
> > +        break;<br>
> > +    }<br>
> <br>
>   hum, the function should check retries > 0 argument otherwise
this<br>
> could hang the daemon.</font></tt>
<br>
<br><tt><font size=2>Changed this.</font></tt>
<br><tt><font size=2><br>
> <br>
> > +    if (tapfd < 0)<br>
> > +        virReportSystemError(conn, errno,<br>
> > +                  
          _("cannot open macvtap tap device
%s"),<br>
> > +                  
          tapname);<br>
> > +<br>
> > +    return tapfd;<br>
> > +}<br>
> <br>
>   okay, I'm not too convinced by the buffer management code,
but that<br>
> could be cleaned up in a later pach, so ACK</font></tt>
<br>
<br><tt><font size=2>I'll shrink the sizes of the buffers. Want to be careful
about dynamic allocation</font></tt>
<br><tt><font size=2>of the buffers in this case, though.</font></tt>
<br>
<br><tt><font size=2>   Stefan</font></tt>
<br>
<br><tt><font size=2><br>
> <br>
> Daniel<br>
> <br>
> -- <br>
> Daniel Veillard      | libxml Gnome XML XSLT toolkit
 </font></tt><a href=http://xmlsoft.org/><tt><font size=2>http://xmlsoft.org/</font></tt></a><tt><font size=2><br>
> daniel@veillard.com  | Rpmfind RPM search engine </font></tt><a href=http://rpmfind.net/><tt><font size=2>http://rpmfind.net/</font></tt></a><tt><font size=2><br>
> </font></tt><a href=http://veillard.com/><tt><font size=2>http://veillard.com/</font></tt></a><tt><font size=2>
| virtualization library  </font></tt><a href=http://libvirt.org/><tt><font size=2>http://libvirt.org/</font></tt></a><tt><font size=2><br>
</font></tt>