Date: Wed, 18 Nov 2009 09:49:12 +0000 From: "Robert N. M. Watson" <rwatson@freebsd.org> To: Xin LI <delphij@gmail.com> Cc: FreeBSD Net <freebsd-net@FreeBSD.org>, Brooks Davis <brooks@freebsd.org>, John Baldwin <jhb@FreeBSD.org>, "M. Warner Losh" <imp@bsdimp.com>, Antoine Brodin <antoine.brodin@laposte.net> Subject: Re: [PATCH FOR REVIEW] interface description (revised) Message-ID: <01D9CB64-F04C-4506-ACF2-1DE459FC69CD@freebsd.org> In-Reply-To: <a78074950911171839u3e3fb4f1oae4aa3fc79f1b152@mail.gmail.com> References: <a78074950911171839u3e3fb4f1oae4aa3fc79f1b152@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On 18 Nov 2009, at 02:39, Xin LI wrote:
> Here is the revised implementation for the interface description
> feature, based on feedback from src-all@.
Hi Xin Li,
Thanks for the updated patch. This looks significantly improved. =
Comments inline.
> --- contrib/libpcap/inet.c (revision 199463)
> +++ contrib/libpcap/inet.c (working copy)
> @@ -403,22 +403,30 @@ add_addr_to_iflist(pcap_if_t **alldevs, const =
char
> pcap_addr_t *curaddr, *prevaddr, *nextaddr;
> #ifdef SIOCGIFDESCR
> struct ifreq ifrdesc;
> +#ifndef IFDESCRSIZE
> +#define _IFDESCRSIZE 64
> + char ifdescr[_IFDESCRSIZE];
> +#else
> char ifdescr[IFDESCRSIZE];
> +#endif
> int s;
> -#endif
> =20
> -#ifdef SIOCGIFDESCR
I'm pretty sure the intent here is that 'int s' be defined regardless of =
SIOCGIFDESCR, it would be worth confirming that these patches applied to =
a pre-SIOCGIFDESCR tcpdump compile correctly. We will want to upstream =
these patches to the vendor so we should make sure the changes are =
acceptable there.
> + descr =3D reallocf(descr, descrlen);
> + if (descr !=3D NULL) {
> + do {
> + ifr.ifr_buffer.buffer =3D descr;
> + ifr.ifr_buffer.length =3D descrlen;
> + if (ioctl(s, SIOCGIFDESCR, &ifr) =3D=3D 0) {
> + if (strlen(descr) > 0)
> + printf("\tdescription: %s\n", descr);
> + break;
> + }
> + if (errno =3D=3D ENAMETOOLONG) {
> + descrlen *=3D 2;
> + descr =3D reallocf(descr, descrlen);
> + }
> + } while ((errno =3D=3D ENAMETOOLONG) && (descr !=3D =
NULL));
> + }
The error non-handling throughout ifconfig worries me; on the whole, =
your patch seems consistent with the existing model, but here I wonder =
if we should be printing a warning if reallocf() fails? Perhaps the =
above loop could be restructured so that there is only a single calling =
point to reallocf -- perhaps while ((descr =3D reallocf()) !=3D NULL) { =
... }? It might make the invariants a bit more clear.
> + DEF_CMD_ARG("description", setifdescr),
> + DEF_CMD_ARG("descr", setifdescr),
> + DEF_CMD("-description", 0, unsetifdescr),
> + DEF_CMD("-descr", 0, unsetifdescr),
Does having two undocumented short-form aliases make this more usable? =
We should either document them or not have them, I guess.
> -.Dd June 18, 2004
> +.Dd November 26, 2009
Curious choice of dates. :-)
> +.It Dv SIOCGIFDESCR
> +Get the interface description, returned in the
> +.Va buffer
> +field of
> +.Va ifru_buffer
> +struct.
> +The user supplied buffer length should defined in the
> +.Va length
> +field of
> +.Va ifru_buffer
> +struct passed in as parameter.
> +.It Dv SIOCSIFDESCR
> +Set the interface description to the value of the
> +.Va buffer
> +field of
> +.Va ifru_buffer
> +struct, with
> +.Va length
> +field specifying its length.
No mention of nul's in the man page yet, but the code now seems much =
more consistent about including nul's throughout.
> + case SIOCGIFDESCR:
> + error =3D 0;
> + if (ifr->ifr_buffer.length > ifdescr_maxlen) {
> + error =3D ENOMEM;
> + break;
> + }
I have three worries about this comparison:
(1) ifdescr_maxlen is signed, perhaps it should be unsigned?
(2) ifdescr_maxlen could be reduced between SIOCSIFDESCR and =
SIOCGIFDESCR, in which case you can no longer query an interface =
description even though the kernel is still storing it.
(3) The loop logic in the userland ifconfig tool assumes that it is OK =
to ask for more bytes than the largest description, so it doubles the =
buffer each time it loops. This means that it may overshoot =
ifdescr_maxlen leading to the call failing even though a large enough =
buffer has been passed.
One of the reasons that potentially unbounded kernel buffers are so =
awkward is that they lead to live-locky logic looping trying to grow a =
buffer using sleeping allocation while grabbing and releasing locks =
trying to get a buffer that's large enough. Most of the time the other =
theoretical thread you're racing with won't exist, but this still has to =
be handled because someday it will. I suggest a loop in which you create =
an sbuf to match the current length of ifp->if_description, and then =
after the loop ends and you have a copy, see if it fits in userspace. =
99.9999% of the time, userspace will have passed a big enough buffer, =
and the loop won't be exercised growing the kernel buffer.
> + else {
> + if (ifr->ifr_buffer.length <=3D =
sbuf_len(ifp->if_description))
> + error =3D ENAMETOOLONG;
This may be more clear if it's written as "< =
sbuf_len(ifp->if_description) + 1". However, if you make the above =
changes, this goes away, or is at least refactored.
> + /*
> + * Copy 1 more byte to make sure that the =
copyout is NUL
Often in the BSD source code, the character is 'nul' and the pointer is =
'NULL'.
> --- sys/net/if_var.h (revision 199463)
> +++ sys/net/if_var.h (working copy)
> @@ -205,7 +205,8 @@ struct ifnet {
> * be used with care where binary compatibility is required.
> */
> char if_cspare[3];
> - void *if_pspare[8];
> + void *if_pspare[7];
> + struct sbuf *if_description; /* interface description */
> int if_ispare[4];
> };
I think the conclusion here was that the ifnet spares were a mistake, =
but I'm not sure how we decided to resolve that mistake. Should we first =
remove the spares in one commit, and then just append new fields in a =
separate commit? (Brooks?)
> Some limitations:
> * Not yet able to send announce through route socket. I need to
> figure out a proper way to do this, maybe a future feature;
> * 32-bit vs 64-bit API compatibility. Since the kernel has to copy
> in a string, is there a clean way to do this? I think we will also
> need to deal with similar issue with SIOCSIFNAME as well.
I'm not sure there's a clean way to deal with it; pointers embedded in =
ioctl arguments are becoming more of a problem, so I wonder if the =
answer isn't to stop introducing any new ones. The Mac OS X kernel is a =
bit more thorough than us in implementing ioctls, since they more =
aggressively select kernel based on hardware, and contains a lot of =
fairly awkward compatibility code switching on whether the process is a =
32-bit or 64-bit process and then selecting the right data structure.
Maybe John has some thoughts on how to handle that.
Robert=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?01D9CB64-F04C-4506-ACF2-1DE459FC69CD>
