[Toybox] [CLEANUP] ifconfig commit 866
Rob Landley
rob at landley.net
Sun Jan 5 14:05:54 PST 2014
Bigger one than the last two:
http://landley.net/hg/toybox/rev/866
In this round, we delete the standalone global iface_list_head and add a
GLOBALS() block with void *iface_list. (We have a pointer to a list,
saying we have a pointer to a list_head is silly. The list head is just
the first node in the list...)
Combine "typedef struct _proc_net_dev_info {...}
WHY_IS_THIS_CAPITALIZED" and "typedef struct _iface_list {...}
CAPITAL_LETTERS_MEAN_MACRO" into a single "struct iface_list" which is
much shorter and not a typedef, plus avoids an extra layer of
indirection with nested structures so you can say "il->transmit_fifo"
instead of "l_ptr->dev_info.transmit_fifo". (Do that a dozen times in
the same function's arguments, it adds up.) The name of the new struct
comes from the old iface_list_head, that went away but we're keeping the
name for the struct it was a list of.
Retain the comment that the netdevice man page has lots of relevant info
on this stuff.
We're inlining or replacing a bunch of stuff this time around. The old
symbols that went away are field_format, iface_flags_str,
omit_whitespace(), print_iface_flags(), print_media(), and clear_list().
I'll mention each again at the point it's was called.
Replace clear_list() with llist_traverse(free). Collate two similar
hex_to_binary() calls (with identical error messages) into a single call
using ? : operator for the single differing argument; no point
duplicating the function call and marshaling those other arguments twice.
(An aside on rough cost estimates: a function call takes roughly
sizeof(long), and marshalling an argument ballparks to sizeof(the
argument). The ? : isn't without cost but we've already _got_ the test
so moving the test into the parameter instead of around the function
call is a wash. If I had to guess I'd say a ? : is maybe as expensive as
a function call with no arguments or return value, but all this stuff
varies per target and compiler version and so on. This is just so I have
some vague idea what's more or less expensive. Mostly, it's not having
the code say the same thing twice. Maybe some optimizers are smart
enough to collate it themselves these days, but I still don't like
redundant code.)
The get_proc_info() version field: the version field is for dealing with
data from different /proc/net/dev versions. How old are these versions,
has any of them been exported since 3.x came out? Let's see:
/proc/net/dev is exported from linux/net/core/net-procfs.c where the
relevant functions are dev_seq_show() (printing the header) and
dev_seq_printf_stats() (printing the numbers). According to git
annotate, that recently (feb 2013) moved from net/core/dev.c (commit
900ff8c63214) so we use the old "git annotate ${VERSION}^1 -- filename"
trick, and _that_ says the part of dev_seq_show() that's printing out
the header hasn't changed since 2003 (so an old version would be 2.4
kernel). So we may be calculating the contents differently, but we
haven't relabeled the fields so we shouldn't have to parse them
differently. Let's confirm though, dev_seq_printf_stats() has several
commits since then. Let's see, 28172739f0a2 was "fix 64 bit counters on
32 bit arches", not a format change. Annotate before _that_, and commit
be1f3c2c027c was "64 bit statistics on 32 bit architectures",
2d13bafeba24 is potentially relevant "ensure there is always a space
between : and the first number" (but we do a strsep on the : so aren't
confused if there isn't), eeda3fd64f75 is "replace dev->stats() with
get_dev_stats()" (different function, same data), 5a1b5898ee9e is just
reindenting this block...
And at that point, the actual printf block dates back to 2002, so again
before 2.6 shipped. So we only care about the most recent version.
Back to get_proc_info() in ifconfig.c: we zap the version argument, and
it's using the new struct iface_list. Zap the memset because the only
caller did an xzalloc() so we know it's zeroed. Inline
omit_whitespace(). Tidy up a block using iface_list and combine _4_
lines of curly brackets into a single "} else thingy;"
Now that version's gone, field_format[] doesn't need to be an array. It
never needed to be a global. It can just be a normal sscanf() inline
format string. And we can collapse the 17 line sscanf() into a 7 line
sscanf(), and eliminate the if(version) after it because the above
exercise proved we should never have to care on a kernel shipped in the
last 10 years.
Convert add_iface_to_list() to struct iface_list, using the TT instance
instead of the standalone global. Same for get_device_info(), no other
changes there.
In get_device_info we have #ifdef SIOCGIFMAP and we go back to the
kernel to see how long that's been there: it's
include/uapi/linux/sockios.h which I'm not even going to annotate but
just log to see when that was moved into uapi... commit 607ca46e97a1, an
using the _big_ linux git tree that goes all the way back to 0.0.1, the
line #definining SIOCGIFMAP is from 1994. So we can safely yank the #ifdef.
get_ifconfig_info(): pretty much a complete rewrite of this function. We
don't need to do version detection, so just make it a single loop
reading the file, skipping the first two lines of header, running each
of the rest through get_proc_info(), add_iface_to_list(), setting it
non-virtual, and calling get-device_info().
print_hw_addr() and print_ip_addr() just convert to struct iface_list,
no other changes.
print_media(): just delete it and remove the call from
display_ifconfig(). The function exists to identify the type of ethernet
cable connection plugged into the card, but the table (ahem, if/else
staircase) only has entries for 10baseT and 100baseT. Does anybody still
care about distinguishing between 10base2 (coax) and 10baseT (cat5)? Or
about whether or not your 100baseT connection is T or TX or FX? Can
anybody tell me what that difference _means_? The man page can't:
media type
Set the physical port or medium type to be used by the device.
Not all devices can change this setting, and those that can vary
in what values they support. Typical values for type are
10base2 (thin Ethernet), 10baseT (twisted-pair 10Mbps Ethernet),
AUI (external transceiver) and so on. The special medium type
of auto can be used to tell the driver to auto-sense the media.
Again, not all drivers can do this.
Note we're not _setting_ it, we're just reading it. I dug around in the
kernel source a bit (since these values are defined in
linux/netdevice.h) and found drivers/net/ethernet/sis/sis900.c going:
/* we switch on the ifmap->port field. I couldn't find anything
* like a definition or standard for the values of that field.
* I think the meaning of those values is device specific. But
* since I would like to change the media type via the ifconfig
* command I use the definition from linux/netdevice.h
* (which seems to be different from the ifport(pcmcia) definition) */
Git annotate says that comment's from 2001, so even _then_ this was
obsolete (overtaken by "auto"). So I'm yanking the function, which never
applied to wireless or gigabit interfaces anyway. (I could have redone
it as a small inline string array, but it doesn't seem worth keeping.)
print_iv6_addr(): convert to struct iface_list, replace stack buf[] with
toybuf, and some curly bracket/whitespace cleanups. Remove a memset
inet_ntop doesn't care about, combine two xprintf() calls into one, and
replace an xprintf() with an xputc().
display_ifconfig(): Convert to struct iface_list. We don't need a local
variable copy of int hw_type now that getting it out of the structure is
less of a pain. Remove the call to print_media because we deleted that
function as useless.
Inline print_iface_flags(), which also sucks in the global
iface_flags_str[]. Instead of calling the function, locally test
ifrflags, declare a string array inside the if {} block, and loop
through it here. This means we can delete print_iface_flags() and
iface_flags_str[] because that was the only user.
The rest of this function looks more changed than it is, it's all just
these changes repeated a lot:
1) replace lptr->dev_info. with il->
2) replace %10s with %10c (and change its argument from " " to ' ')
3) replace local hw_type with il->hw_type.
4) combine consecutive xprintf() calls into a single xprintf() call.
5) whitespace (remove newline after if() when it'll fit on one line)
The %s to %c padding change means we don't need an empty string
constant, marshalling int instead of pointer is slightly cheaper on 64
bit platforms, and it saves a dereference. (A rounding error "while I
was there" cleanup.)
readconf(): The bit with the "Escape duplicate values" is a classic loop
simplification: we don't need a match_found variable if our iterator
variable will be null if it hit the end of the list and won't if it
broke out early. So as long as I had to convert IFACE_LIST to struct
iface_list anyway, I went ahead and turned:
IFACE_LIST *list_ptr;
int match_found = 0;
for(list_ptr = iface_list_head; list_ptr != NULL; list_ptr =
list_ptr->next) {
//if interface already in the list then donot add it in the list.
if(!strcmp(ifre->ifr_name, list_ptr->dev_info.ifrname)) {
match_found = 1;
break;
}
}
if(!match_found) {
into:
struct iface_list *il;
for(il = TT.iface_list; il; il = il->next)
if(!strcmp(ifre->ifr_name, il->ifrname)) break;
if(!il) {
10 lines into 4 lines, and one of those 4 is blank. Yes I removed a
comment, but this whole thing is right after the "Escape duplicate
values" comment.
show_iface(): more IFACE_LIST -> struct iface_list conversion, and
another loop that doesn't need is_dev_found when if (!il) tells us
whether or not we hit the end.
The "error getting device info" message just becomes a perror_msg() with
the interface name and the errno string. "Interface" had "problem". Yes,
maybe ENODEV won't have quite the error string we want, but it'll be
slightly wrong in the correctly internationalized language.
Moving struct iface_list up a block level means it can replace two local
IFACE_LIST variables. Their scopes don't overlap, so they can reuse the
same variable safely.
And at the end of the patch, clear_list() went away as mentioned earlier.
More information about the Toybox
mailing list