Reorganize the list of addresses associated with an interface and group them

based on the address family. This should help to recognize interfaces with
multiple AF (e.g. ipv4 and ipv6) with many aliases or additional addresses. The
order of addresses inside a single group is strictly preserved.

Improve the scope_id output for AF_INET6 families, as the
current approach uses hexadecimal string that is basically the ID of an
interface, whilst this information is already depicted by getnameinfo(3) call.
Therefore, now ifconfig just prints the scope of address as it is defined in
2.4 of RFC 2373.

PR:		197270
Approved by:	bapt
MFC after:	2 weeks
This commit is contained in:
Vsevolod Stakhov 2015-02-02 13:03:04 +00:00
parent 8b1ce3297a
commit 35c73e51cc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=278080
2 changed files with 196 additions and 5 deletions

View File

@ -166,6 +166,33 @@ setip6eui64(const char *cmd, int dummy __unused, int s,
freeifaddrs(ifap); freeifaddrs(ifap);
} }
static void
in6_print_scope(uint8_t *a)
{
const char *sname = NULL;
uint16_t val;
val = (a[0] << 4) + ((a[1] & 0xc0) >> 4);
if ((val & 0xff0) == 0xff0)
sname = "Multicast";
else {
switch(val) {
case 0xfe8:
sname = "Link";
break;
case 0xfec:
sname = "Site";
break;
default:
sname = "Global";
break;
}
}
printf("scope: %s ", sname);
}
static void static void
in6_status(int s __unused, const struct ifaddrs *ifa) in6_status(int s __unused, const struct ifaddrs *ifa)
{ {
@ -257,9 +284,7 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0) if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
printf("prefer_source "); printf("prefer_source ");
if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id) in6_print_scope((uint8_t *)&((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr);
printf("scopeid 0x%x ",
((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id);
if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
printf("pltime "); printf("pltime ");

View File

@ -47,6 +47,7 @@ static const char rcsid[] =
#include <sys/time.h> #include <sys/time.h>
#include <sys/module.h> #include <sys/module.h>
#include <sys/linker.h> #include <sys/linker.h>
#include <sys/queue.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if.h> #include <net/if.h>
@ -110,6 +111,15 @@ static void af_other_status(int);
static struct option *opts = NULL; static struct option *opts = NULL;
struct ifa_order_elt {
int if_order;
int af_orders[255];
struct ifaddrs *ifa;
TAILQ_ENTRY(ifa_order_elt) link;
};
TAILQ_HEAD(ifa_queue, ifa_order_elt);
void void
opt_register(struct option *p) opt_register(struct option *p)
{ {
@ -141,16 +151,162 @@ usage(void)
exit(1); exit(1);
} }
static int
calcorders(struct ifaddrs *ifa, struct ifa_queue *q)
{
unsigned int ord, af, ifa_ord;
struct ifaddrs *prev;
struct ifa_order_elt *cur;
prev = NULL;
cur = NULL;
ord = 0;
ifa_ord = 0;
while (ifa != NULL) {
if (prev == NULL || strcmp(ifa->ifa_name, prev->ifa_name) != 0) {
cur = calloc(1, sizeof(*cur));
if (cur == NULL)
return (-1);
TAILQ_INSERT_TAIL(q, cur, link);
cur->if_order = ifa_ord ++;
cur->ifa = ifa;
ord = 0;
}
if (ifa->ifa_addr) {
af = ifa->ifa_addr->sa_family;
if (af < sizeof(cur->af_orders) / sizeof(cur->af_orders[0]) &&
cur->af_orders[af] == 0)
cur->af_orders[af] = ++ord;
}
prev = ifa;
ifa = ifa->ifa_next;
}
return (0);
}
static int
cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q)
{
int ret;
unsigned int af1, af2;
struct ifa_order_elt *cur, *e1, *e2;
e1 = e2 = NULL;
ret = strcmp(a->ifa_name, b->ifa_name);
if (ret != 0) {
/* We need to find elements corresponding to these different names */
TAILQ_FOREACH(cur, q, link) {
if (e1 && e2)
break;
if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0)
e1 = cur;
else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0)
e2 = cur;
}
if (!e1 || !e2)
return (0);
else
return (e1->if_order - e2->if_order);
} else if (a->ifa_addr != NULL && b->ifa_addr != NULL) {
TAILQ_FOREACH(cur, q, link) {
if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) {
e1 = cur;
break;
}
}
if (!e1)
return (0);
af1 = a->ifa_addr->sa_family;
af2 = b->ifa_addr->sa_family;
if (af1 < sizeof(e1->af_orders) / sizeof(e1->af_orders[0]) &&
af2 < sizeof(e1->af_orders) / sizeof(e1->af_orders[0]))
return (e1->af_orders[af2] - e1->af_orders[af1]);
}
return (0);
}
static struct ifaddrs *
sortifaddrs(struct ifaddrs *list,
int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *),
struct ifa_queue *q)
{
struct ifaddrs *right, *temp, *last, *result, *next, *tail;
right = list;
temp = list;
last = list;
result = NULL;
next = NULL;
tail = NULL;
if (!list || !list->ifa_next)
return (list);
while (temp && temp->ifa_next) {
last = right;
right = right->ifa_next;
temp = temp->ifa_next->ifa_next;
}
last->ifa_next = NULL;
list = sortifaddrs(list, compare, q);
right = sortifaddrs(right, compare, q);
while (list || right) {
if (!right) {
next = list;
list = list->ifa_next;
} else if (!list) {
next = right;
right = right->ifa_next;
} else if (compare(list, right, q) <= 0) {
next = list;
list = list->ifa_next;
} else {
next = right;
right = right->ifa_next;
}
if (!result)
result = next;
else
tail->ifa_next = next;
tail = next;
}
return (result);
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int c, all, namesonly, downonly, uponly; int c, all, namesonly, downonly, uponly;
const struct afswtch *afp = NULL; const struct afswtch *afp = NULL;
int ifindex; int ifindex;
struct ifaddrs *ifap, *ifa; struct ifaddrs *ifap, *sifap, *ifa;
struct ifreq paifr; struct ifreq paifr;
const struct sockaddr_dl *sdl; const struct sockaddr_dl *sdl;
char options[1024], *cp, *namecp = NULL; char options[1024], *cp, *namecp = NULL;
struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q);
struct ifa_order_elt *cur, *tmp;
const char *ifname; const char *ifname;
struct option *p; struct option *p;
size_t iflen; size_t iflen;
@ -285,9 +441,19 @@ main(int argc, char *argv[])
if (getifaddrs(&ifap) != 0) if (getifaddrs(&ifap) != 0)
err(EXIT_FAILURE, "getifaddrs"); err(EXIT_FAILURE, "getifaddrs");
cp = NULL; cp = NULL;
if (calcorders(ifap, &q) != 0)
err(EXIT_FAILURE, "calcorders");
sifap = sortifaddrs(ifap, cmpifaddrs, &q);
TAILQ_FOREACH_SAFE(cur, &q, link, tmp)
free(cur);
ifindex = 0; ifindex = 0;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { for (ifa = sifap; ifa; ifa = ifa->ifa_next) {
memset(&paifr, 0, sizeof(paifr)); memset(&paifr, 0, sizeof(paifr));
strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {