On Wednesday 18 November 2009 4:49:12 am Robert N. M. Watson wrote: > On 18 Nov 2009, at 02:39, Xin LI wrote: > > + 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.
I've found the 'descr' shortcut useful when using a similar patch of this on 7 FWIW. > > + case SIOCGIFDESCR: > > + error = 0; > > + if (ifr->ifr_buffer.length > ifdescr_maxlen) { > > + error = 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. I would use either of the following strategies: 1) Don't check ifdescr_maxlen when fetching a description, only when setting it. If a sysadmin decides to shorten the maximum description length, then they should perhaps shorten any really long descriptions to match. In practice I suspect that sysadmins will not change this on the fly and this policy gives the sanest user experience IMO. 2) Truncate the description copied out to ifdescr_maxlen chars. Also, I'm not sure that using an sbuf rather than a plain char * is actually buying you anything here. You aren't building a string which sbuf is good for. Instead, you are just copying strings around. I would probably not use sbuf at all and would just use copyin/copyout. One issue with 1) for the current code is that you are using it to avoid having userland ask for a really large buffer. Instead, I would change the code to just do something like this (assuming you have a char *): char *buf; size_t len; case SIOCFIGDESCR: error = 0; IF_AFDATA_RLOCK(ifp); for (buf = NULL; buf; ) { if (ifp->if_description == NULL) { error = ENOMSG; break; } len = strlen(ifp->if_description) + 1; IF_AFDATA_RUNLOCK(ifp); buf = malloc(len, M_TEMP, M_WAITOK); IF_AFDATA_RLOCK(ifp); if (len < strlen(description + 1) { free(buf, M_TEMP); buf = NULL; } } if (error == 0) strcpy(buf, ifp->if_desciption); IF_AFDATA_RUNLOCK(ifp); if (error == 0) { if (len > ifr->ifr_buffer.length) error = ENAMETOOLONG; else error = copyout(buf, ifr->ifr_buffer.buffer, len); } if (buf != NULL) free(buf, M_TEMP); break; However, this is a bit complicated, and to be honest, I don't think interface descriptions are a critical path. Robert has already said before that IF_AFDATA_RLOCK() isn't really the "correct" lock but is being abused for this. Given that, I would probably just add a single global sx lock. This has the added advantage that you can just use copyin/copyout directly and skip all the extra complication. I don't think we need the extra concurrency for interface descriptions to make this so complicated. If you used a global sx lock with a simple string for descriptions, the code would end up looking like this: static struct sx ifdescr_lock; SX_SYSINIT(&ifdescr_lock, "ifnet descr"); static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions"); char *buf; size_t len; case SIOCGIFDESCR: error = 0; sx_slock(&ifdescr_lock); if (ifp->if_description == NULL) error = ENOMSG; else { len = strlen(ifp->if_description) + 1; if (ifr->ifr_buffer.length < len) error = ENAMETOOLONG; else error = copyout(ifr->ifr_buffer.buffer, ifp->if_description, len); } sx_sunlock(&ifdescr_lock); break; case SIOCSIFDESCR: error = priv_check(); if (error) break; if (ifr->ifr_buffer.length > ifdescr_maxlen) return (ENAMETOOLONG); buf = malloc(ifr->ifr_buffer.length, M_IFDESCR, M_WAITOK | M_ZERO); error = copyin(ifr->ifr_buffer.buffer, buf, ifr->ifr_buffer.length - 1); if (error) { free(buf, M_IFDESCR); break; } sx_xlock(&ifdescr_lock); ifp->if_description = buf; sx_xunlock(&ifdescr_lock); break; Note that this takes approach 1) from above, but it is also a moot point now since the 'get' ioctl doesn't allocate memory anymore. > > 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. I wouldn't worry about 32-bit compat for this ioctl. The main consumer of this ioctl is going to be ifconfig which will be a native binary. If someone encounters a situation where they need 32-bit compat, then it can be added at that time. -- John Baldwin _______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"