<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>