diff --git a/bridge/br_common.h b/bridge/br_common.h index 169a162d..41eb0dc3 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -1,3 +1,6 @@ +#define MDB_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry)))) + extern int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); diff --git a/bridge/mdb.c b/bridge/mdb.c index 24c49035..09d4b225 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -49,7 +49,7 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr) } static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, - struct nlmsghdr *n) + struct nlmsghdr *n, struct rtattr **tb) { SPRINT_BUF(abuf); const void *src; @@ -66,20 +66,29 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, (e->state & MDB_PERMANENT) ? "permanent" : "temp"); if (e->vid) fprintf(f, " vid %hu", e->vid); + if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER])); + fprintf(f, "%4i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec/10000); + } fprintf(f, "\n"); } static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr, struct nlmsghdr *n) { + struct rtattr *etb[MDBA_MDB_EATTR_MAX + 1]; + struct br_mdb_entry *e; struct rtattr *i; int rem; - struct br_mdb_entry *e; rem = RTA_PAYLOAD(attr); for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { e = RTA_DATA(i); - print_mdb_entry(f, ifindex, e, n); + parse_rtattr(etb, MDBA_MDB_EATTR_MAX, MDB_RTA(RTA_DATA(i)), + RTA_PAYLOAD(i) - RTA_ALIGN(sizeof(*e))); + print_mdb_entry(f, ifindex, e, n, etb); } } diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index efd416e7..0e98edf4 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -503,6 +503,11 @@ With the option, the command becomes verbose. It prints out the ports known to have a connected router. +.PP +With the +.B -statistics +option, the command displays timer values for mdb entries. + .SH bridge vlan - VLAN filter list .B vlan