On Tue, Jun 09, 2020 at 10:02:06AM +0200, Remi Locherer wrote:
> On Tue, Jun 09, 2020 at 09:17:31AM +0200, Claudio Jeker wrote:
> > On Tue, Jun 09, 2020 at 08:44:42AM +0200, Remi Locherer wrote:
> > > 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?
> > 
> > Why do you think the route counts are needed? You fetch all routing tables
> > to count them in userland. The sysctl for doing that is expensive and
> > especially on systems with full tables will make this command slow.
> > If this is something we really want then the kernel should track and
> > provide the count.
> 
> These counters are of interest for operators. But I agree that counting
> the routes in userland is unfortunate. But I don't know how bad it is.
> Is a lock involved in the kernel when dumping the full table?

I did some homework and figured out, that dumping a routing table takes the
NET_LOCK. So it's not just inefficient counting all routes in userland it
might have a negative impact on the system.

Below my new proposal without the counters. I still think it would be good
to have those counters. Maybe I'll try to find a solution for that.

twister ..in/netstat$ obj/netstat -R 
Rdomain 0
  Interfaces: lo0 iwm0 re0 enc0 pflog0
  Routing tables: 0 6 7 77

Rdomain 100
  Interfaces: vether100 lo100 vether101 vether102 vether103 vether104 vether105 
vether106 vether107 vether108 vether109
  Routing tables: 100

Rdomain 255
  Interfaces: vether255 lo255
  Routing tables: 255

twister ..in/netstat$



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   10 Jun 2020 20:08:28 -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,8 @@ void        rt_stats(void);
 void   pr_rthdr(int, int);
 void   pr_encaphdr(void);
 void   pr_family(int);
+
+void   rdomainpr(void);
 
 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     10 Jun 2020 19:49:02 -0000
@@ -51,6 +51,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <ifaddrs.h>
 
 #include "netstat.h"
 
@@ -346,4 +347,69 @@ 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:");
+               for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) {
+                       if (rtt_dom[rtt] == rdom)
+                               printf(" %i", rtt);
+               }
+               printf("\n\n");
+               free(rdom_if[rdom]);
+       }
 }

Reply via email to