On Mon, Jun 08, 2020 at 10:10:17PM +0200, Remi Locherer wrote:
> Hi,
>
> to my knowledge there is no easy way to list all active rdomains or
> routing tables. Other platforms have "show vrf" or similar commands
> for an overview.
>
> Here is my attempt at such a view for OpenBSD:
Updated diff with small changes:
- Print inet instead of Internet (input deraadt)
- Removed padding before rdomain id.
- Changed man page wording.
twister ..in/netstat$ obj/netstat -R
Rdomain 0
Interfaces: lo0 iwm0 re0 enc0 pflog0 mpe0
Routing tables:
0: inet 8, inet6 45, mpls 1
3: inet 1, inet6 0, mpls 0
7: inet 130309, inet6 10000, mpls 0
Rdomain 77
Interfaces: vether77 lo77
Routing tables:
77: inet 0, inet6 0, mpls 0
Rdomain 122
Interfaces: vether122 lo122 pair122 vether1122 vether1123 vether1124
vether1125 vether1126 vether1127
Routing tables:
122: inet 24, inet6 0, mpls 0
Rdomain 255
Interfaces: vether255 lo255
Routing tables:
255: inet 3, inet6 0, mpls 0
twister ..in/netstat$
OK?
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/netstat/main.c,v
retrieving revision 1.116
diff -u -p -r1.116 main.c
--- main.c 28 Apr 2019 17:59:51 -0000 1.116
+++ main.c 30 May 2020 17:59:33 -0000
@@ -127,7 +127,7 @@ main(int argc, char *argv[])
tableid = getrtable();
while ((ch = getopt(argc, argv,
- "AaBbc:deFf:ghI:iLlM:mN:np:P:qrsT:tuvW:w:")) != -1)
+ "AaBbc:deFf:ghI:iLlM:mN:np:P:qRrsT:tuvW:w:")) != -1)
switch (ch) {
case 'A':
Aflag = 1;
@@ -225,6 +225,9 @@ main(int argc, char *argv[])
case 'q':
qflag = 1;
break;
+ case 'R':
+ Rflag = 1;
+ break;
case 'r':
rflag = 1;
break;
@@ -318,6 +321,11 @@ main(int argc, char *argv[])
mroutepr();
if (af == AF_INET6 || af == AF_UNSPEC)
mroute6pr();
+ exit(0);
+ }
+
+ if (Rflag) {
+ rdomainpr();
exit(0);
}
Index: netstat.1
===================================================================
RCS file: /cvs/src/usr.bin/netstat/netstat.1,v
retrieving revision 1.86
diff -u -p -r1.86 netstat.1
--- netstat.1 17 Apr 2019 20:34:21 -0000 1.86
+++ netstat.1 8 Jun 2020 20:42:46 -0000
@@ -74,6 +74,8 @@
.Op Fl i | I Ar interface
.Nm
.Op Fl W Ar interface
+.Nm
+.Op Fl R
.Sh DESCRIPTION
The
.Nm
@@ -267,6 +269,8 @@ Otherwise the states of the matching soc
Only show interfaces that have seen packets (or bytes if
.Fl b
is specified).
+.It Fl R
+List all rdomains with associated interfaces and routing tables.
.It Fl r
Show the routing tables.
The output is explained in more detail below.
Index: netstat.h
===================================================================
RCS file: /cvs/src/usr.bin/netstat/netstat.h,v
retrieving revision 1.74
diff -u -p -r1.74 netstat.h
--- netstat.h 28 Apr 2019 17:59:51 -0000 1.74
+++ netstat.h 7 Jun 2020 22:03:10 -0000
@@ -57,6 +57,7 @@ int pflag; /* show given protocol */
int Pflag; /* show given PCB */
int qflag; /* only display non-zero values for output */
int rflag; /* show routing tables (or routing stats) */
+int Rflag; /* show rdomain and rtable summary */
int sflag; /* show protocol statistics */
int tflag; /* show i/f watchdog timers */
int vflag; /* be verbose */
@@ -112,6 +113,9 @@ void rt_stats(void);
void pr_rthdr(int, int);
void pr_encaphdr(void);
void pr_family(int);
+
+void rdomainpr(void);
+void rttsummarypr(int);
void ip6_stats(char *);
void icmp6_stats(char *);
Index: route.c
===================================================================
RCS file: /cvs/src/usr.bin/netstat/route.c,v
retrieving revision 1.104
diff -u -p -r1.104 route.c
--- route.c 28 Jun 2019 13:35:02 -0000 1.104
+++ route.c 9 Jun 2020 06:36:29 -0000
@@ -51,6 +51,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <ifaddrs.h>
#include "netstat.h"
@@ -346,4 +347,117 @@ rt_stats(void)
rtstat.rts_unreach, plural(rtstat.rts_unreach));
printf("\t%u use%s of a wildcard route\n",
rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
+}
+
+/*
+ * Print rdomain and rtable summary
+ */
+
+void
+rdomainpr(void)
+{
+ struct if_data *ifd;
+ struct ifaddrs *ifap, *ifa;
+ struct rt_tableinfo info;
+
+ int rtt_dom[RT_TABLEID_MAX+1];
+ int mib[6], rdom, rtt;
+ size_t len;
+ char *old, *rdom_if[RT_TABLEID_MAX+1] = { };
+
+ getifaddrs(&ifap);
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ ifd = ifa->ifa_data;
+ if (rdom_if[ifd->ifi_rdomain] == NULL) {
+ if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s",
+ ifa->ifa_name) == -1)
+ exit(1);
+ } else {
+ old = rdom_if[ifd->ifi_rdomain];
+ if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s %s",
+ old, ifa->ifa_name) == -1)
+ exit(1);
+ free(old);
+ }
+ }
+ freeifaddrs(ifap);
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_TABLE;
+
+ len = sizeof(info);
+ for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) {
+ mib[5] = rtt;
+ if (sysctl(mib, 6, &info, &len, NULL, 0) == -1)
+ rtt_dom[rtt] = -1;
+ else
+ rtt_dom[rtt] = info.rti_domainid;
+ }
+
+ for (rdom = 0; rdom <= RT_TABLEID_MAX; rdom++) {
+ if (rdom_if[rdom] == NULL)
+ continue;
+ printf("Rdomain %i\n", rdom);
+ printf(" Interfaces: %s\n", rdom_if[rdom]);
+ printf(" Routing tables:\n");
+ for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) {
+ if (rtt_dom[rtt] == rdom)
+ rttsummarypr(rtt);
+ }
+ printf("\n");
+ free(rdom_if[rdom]);
+ }
+}
+
+void
+rttsummarypr(int tableid)
+{
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+ char *buf = NULL, *next, *lim = NULL;
+ size_t needed;
+ int mib[7], mcnt;
+ int inet = 0, inet6 = 0, mpls = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = af;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ mib[6] = tableid;
+ mcnt = 7;
+
+ needed = get_sysctl(mib, mcnt, &buf);
+ lim = buf + needed;
+
+ if (buf) {
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+
+ sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
+ switch(sa->sa_family) {
+ case AF_INET:
+ inet++;
+ break;
+ case AF_INET6:
+ inet6++;
+ break;
+ case AF_MPLS:
+ mpls++;
+ break;
+ }
+ }
+ }
+ free(buf);
+
+ printf(" %3i: inet %7i, inet6 %7i, mpls %7i\n", tableid,
+ inet, inet6, mpls);
}