On 09/11/16(Wed) 12:18, Stuart Henderson wrote:
> On 2016/11/09 12:55, Martin Pieuchot wrote:
> > > 
> > > I'm using that, and I think many people using an IGP will be too (you
> > > want services - e.g. ssh, snmp, ntp, bgp - to stay working even when a
> > > physical interface is down - and at least where the IGP is OSPF you
> > > want those addresses hanging off an IFF_LOOPBACK interface, vether
> > > won't do). I bet the majority of people doing this use exactly lo1.
> > 
> > Can't you use lo99 for that purpose?
> 
> Yes, it's the sort of thing that people following OpenBSD development
> can do pretty easily. (Here it's only 12 machines and it's a change that
> can be made in advance so not too painful - though from past experience
> it would be wise to restart ospf{,6}d rather than just reload config for
> this change).
> 
> It might be quite painful for some isp or ixp if they only discover
> about the change after upgrading a remote machine though.

Fair point.  What about adding backward compatible goo to help people
doing the transition:

# ifconfig lo1 create 
# ifconfig vether0 rdomain 1
warning: lo1 cannot be used for rdomain 1
# ifconfig lo
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 32768
        index 8 priority 0 llprio 3
        groups: lo
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x8
        inet 127.0.0.1 netmask 0xff000000
lo1: flags=8008<LOOPBACK,MULTICAST> mtu 32768
        index 13 priority 0 llprio 3
        groups: lo
lo101: flags=8008<LOOPBACK,MULTICAST> rdomain 1 mtu 32768
        index 14 priority 0 llprio 3
        groups: lo


Diff below adds a warning if the lo(4) interface already exists and try
to use unit + 100.  This should be good enough to not break existing
setup and people won't be able to say there was no warning.

If you think something like that can help, then we can keep it until 6.1
or 6.2 is release.

> > > [...]
> > > Much of the diff would stand, but not the automatic interface creation.
> > 
> > That's the whole point of the diff.
> 
> In that case is anything needed at all other than a doc change? "If you
> want to connect to a local address in an rdomain, add an lo interface
> to that domain". (I misunderstood it as things getting confused and
> using lo0 when another interface should have been used.)

I think that a current.html entry is required.  

New version below also tweaks rdomain.4.

Index: sys/kern/init_main.c
===================================================================
RCS file: /cvs/src/sys/kern/init_main.c,v
retrieving revision 1.262
diff -u -p -r1.262 init_main.c
--- sys/kern/init_main.c        7 Nov 2016 00:26:32 -0000       1.262
+++ sys/kern/init_main.c        9 Nov 2016 10:39:13 -0000
@@ -389,6 +389,9 @@ main(void *framep)
        msginit();
 #endif
 
+       /* Create default routing table before attaching lo0. */
+       rtable_init();
+
        /* Attach pseudo-devices. */
        for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
                if (pdev->pdev_count > 0)
@@ -398,8 +401,6 @@ main(void *framep)
        crypto_init();
        swcr_init();
 #endif /* CRYPTO */
-
-       rtable_init();
 
        /*
         * Initialize protocols.  Block reception of incoming packets
Index: sys/net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.458
diff -u -p -r1.458 if.c
--- sys/net/if.c        8 Nov 2016 10:47:10 -0000       1.458
+++ sys/net/if.c        9 Nov 2016 14:00:52 -0000
@@ -258,7 +258,6 @@ struct srp_gc if_ifp_gc = SRP_GC_INITIAL
 struct srp_gc if_map_gc = SRP_GC_INITIALIZER(if_map_dtor, NULL);
 
 struct ifnet_head ifnet = TAILQ_HEAD_INITIALIZER(ifnet);
-unsigned int lo0ifidx;
 
 void
 if_idxmap_init(unsigned int limit)
@@ -1350,12 +1349,7 @@ p2p_rtrequest(struct ifnet *ifp, int req
 
                KASSERT(ifa == rt->rt_ifa);
 
-               /*
-                * XXX Since lo0 is in the default rdomain we should not
-                * (ab)use it for any route related to an interface of a
-                * different rdomain.
-                */
-               lo0ifp = if_get(lo0ifidx);
+               lo0ifp = if_get(rtable_loindex(ifp->if_rdomain));
                KASSERT(lo0ifp != NULL);
                TAILQ_FOREACH(lo0ifa, &lo0ifp->if_addrlist, ifa_list) {
                        if (lo0ifa->ifa_addr->sa_family ==
@@ -1438,7 +1432,7 @@ if_up(struct ifnet *ifp)
 
 #ifdef INET6
        /* Userland expects the kernel to set ::1 on lo0. */
-       if (ifp->if_index == lo0ifidx)
+       if (ifp->if_index == rtable_loindex(0))
                in6_ifattach(ifp);
 #endif
 
@@ -1605,14 +1599,44 @@ if_setrdomain(struct ifnet *ifp, int rdo
        if (rdomain < 0 || rdomain > RT_TABLEID_MAX)
                return (EINVAL);
 
-       /* make sure that the routing table exists */
+       /*
+        * Create the routing table if it does not exist, including its
+        * loopback interface with unit == rdomain.
+        */
        if (!rtable_exists(rdomain)) {
+               struct ifnet *loifp;
+               char loifname[IFNAMSIZ];
+               unsigned int unit = rdomain;
+
+again:
+               snprintf(loifname, sizeof(loifname), "lo%u", unit);
+               if ((error = if_clone_create(loifname, 0))) {
+                       /*
+                        * Backward compatibility for 6.0 and earlier setups
+                        * using rdomain without lo(4) interface.
+                        */
+                       if (error == EEXIST && unit == rdomain) {
+                               printf("warning: lo%u cannot be used for"
+                                   " rdomain %d\n", unit, rdomain);
+                               unit += 100;
+                               goto again;
+                       }
+                       return (error);
+               }
+
+               if ((loifp = ifunit(loifname)) == NULL)
+                       return (ENXIO);
+
                s = splsoftnet();
                if ((error = rtable_add(rdomain)) == 0)
-                       rtable_l2set(rdomain, rdomain);
+                       rtable_l2set(rdomain, rdomain, loifp->if_index);
                splx(s);
-               if (error)
+               if (error) {
+                       if_clone_destroy(loifname);
                        return (error);
+               }
+
+               loifp->if_rdomain = rdomain;
        }
 
        /* make sure that the routing table is a real rdomain */
Index: sys/net/if_loop.c
===================================================================
RCS file: /cvs/src/sys/net/if_loop.c,v
retrieving revision 1.76
diff -u -p -r1.76 if_loop.c
--- sys/net/if_loop.c   13 Apr 2016 11:41:15 -0000      1.76
+++ sys/net/if_loop.c   9 Nov 2016 10:39:13 -0000
@@ -121,6 +121,7 @@
 #include <net/if_var.h>
 #include <net/if_types.h>
 #include <net/netisr.h>
+#include <net/rtable.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -182,7 +183,7 @@ loop_clone_create(struct if_clone *ifc, 
        if (unit == 0) {
                if_attachhead(ifp);
                if_addgroup(ifp, ifc->ifc_name);
-               lo0ifidx = ifp->if_index;
+               rtable_l2set(0, 0, ifp->if_index);
        } else
                if_attach(ifp);
        if_alloc_sadl(ifp);
@@ -195,7 +196,7 @@ loop_clone_create(struct if_clone *ifc, 
 int
 loop_clone_destroy(struct ifnet *ifp)
 {
-       if (ifp->if_index == lo0ifidx)
+       if (ifp->if_index == rtable_loindex(ifp->if_rdomain))
                return (EPERM);
 
        if_detach(ifp);
Index: sys/net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.76
diff -u -p -r1.76 if_var.h
--- sys/net/if_var.h    8 Nov 2016 10:46:05 -0000       1.76
+++ sys/net/if_var.h    9 Nov 2016 10:39:13 -0000
@@ -291,7 +291,6 @@ int         niq_enlist(struct niqueue *, struct
     sysctl_mq((_n), (_l), (_op), (_olp), (_np), (_nl), &(_niq)->ni_q)
 
 extern struct ifnet_head ifnet;
-extern unsigned int lo0ifidx;
 extern struct taskq *softnettq;
 
 void   if_start(struct ifnet *);
Index: sys/net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.335
diff -u -p -r1.335 route.c
--- sys/net/route.c     9 Nov 2016 09:04:48 -0000       1.335
+++ sys/net/route.c     9 Nov 2016 10:39:13 -0000
@@ -197,8 +197,6 @@ route_init(void)
        while (rt_hashjitter == 0)
                rt_hashjitter = arc4random();
 
-       if (rtable_add(0) != 0)
-               panic("route_init rtable_add");
 #ifdef BFD
        bfdinit();
 #endif
Index: sys/net/rtable.c
===================================================================
RCS file: /cvs/src/sys/net/rtable.c,v
retrieving revision 1.52
diff -u -p -r1.52 rtable.c
--- sys/net/rtable.c    7 Sep 2016 09:36:49 -0000       1.52
+++ sys/net/rtable.c    9 Nov 2016 10:40:41 -0000
@@ -1,7 +1,7 @@
 /*     $OpenBSD: rtable.c,v 1.52 2016/09/07 09:36:49 mpi Exp $ */
 
 /*
- * Copyright (c) 2014-2015 Martin Pieuchot
+ * Copyright (c) 2014-2016 Martin Pieuchot
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -41,7 +41,7 @@
  *     afmap               rtmap/dommp
  *   -----------          ---------     -----
  *   |   0     |--------> | 0 | 0 | ... | 0 |  Array mapping rtableid (=index)
- *   -----------          ---------     -----   to rdomain (=value).
+ *   -----------          ---------     -----   to rdomain/loopback (=value).
  *   | AF_INET |.
  *   ----------- `.       .---------.     .---------.
  *       ...      `----> | rtable0 | ... | rtableN |   Array of pointers for
@@ -59,10 +59,20 @@ struct rtmap {
        void             **tbl;
 };
 
-/* Array of rtableid -> rdomain mapping. */
+/*
+ * Array of rtableid -> rdomain mapping.
+ *
+ * Only used for the first index as describbed above.
+ */
 struct dommp {
        unsigned int       limit;
-       unsigned int      *dom;
+       /*
+        * Array to get the routing domain and loopback interface related to
+        * a routing table. Format:
+        *
+        * 8 unused bits | 16 bits for loopback index | 8 bits for rdomain
+        */
+       unsigned int      *value;
 };
 
 unsigned int      rtmap_limit = 0;
@@ -146,6 +156,8 @@ rtable_init(void)
        unsigned int     keylen = 0;
        int              i;
 
+       KASSERT(sizeof(struct rtmap) == sizeof(struct dommp));
+
        /* We use index 0 for the rtable/rdomain map. */
        af2idx_max = 1;
        memset(af2idx, 0, sizeof(af2idx));
@@ -173,6 +185,9 @@ rtable_init(void)
            M_WAITOK|M_ZERO);
 
        rtmap_init();
+
+       if (rtable_add(0) != 0)
+               panic("unable to create default routing table");
 }
 
 int
@@ -221,7 +236,7 @@ rtable_add(unsigned int id)
 
        /* Use main rtable/rdomain by default. */
        dmm = srp_get_locked(&afmap[0]);
-       dmm->dom[id] = 0;
+       dmm->value[id] = 0;
 
        return (0);
 }
@@ -272,24 +287,42 @@ rtable_l2(unsigned int rtableid)
 
        dmm = srp_enter(&sr, &afmap[0]);
        if (rtableid < dmm->limit)
-               rdomain = dmm->dom[rtableid];
+               rdomain = (dmm->value[rtableid] & RT_TABLEID_MASK);
        srp_leave(&sr);
 
        return (rdomain);
 }
 
+unsigned int
+rtable_loindex(unsigned int rtableid)
+{
+       struct dommp    *dmm;
+       unsigned int     loifidx = 0;
+       struct srp_ref   sr;
+
+       dmm = srp_enter(&sr, &afmap[0]);
+       if (rtableid < dmm->limit)
+               loifidx = (dmm->value[rtableid] >> RT_TABLEID_BITS);
+       srp_leave(&sr);
+
+       return (loifidx);
+}
+
 void
-rtable_l2set(unsigned int rtableid, unsigned int rdomain)
+rtable_l2set(unsigned int rtableid, unsigned int rdomain, unsigned int loifidx)
 {
        struct dommp    *dmm;
+       unsigned int     value;
 
        KERNEL_ASSERT_LOCKED();
 
        if (!rtable_exists(rtableid) || !rtable_exists(rdomain))
                return;
 
+       value = (rdomain & RT_TABLEID_MASK) | (loifidx << RT_TABLEID_BITS);
+
        dmm = srp_get_locked(&afmap[0]);
-       dmm->dom[rtableid] = rdomain;
+       dmm->value[rtableid] = value;
 }
 
 #ifndef ART
Index: sys/net/rtable.h
===================================================================
RCS file: /cvs/src/sys/net/rtable.h,v
retrieving revision 1.16
diff -u -p -r1.16 rtable.h
--- sys/net/rtable.h    7 Sep 2016 09:36:49 -0000       1.16
+++ sys/net/rtable.h    9 Nov 2016 10:39:58 -0000
@@ -1,7 +1,7 @@
 /*     $OpenBSD: rtable.h,v 1.16 2016/09/07 09:36:49 mpi Exp $ */
 
 /*
- * Copyright (c) 2014-2015 Martin Pieuchot
+ * Copyright (c) 2014-2016 Martin Pieuchot
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -54,7 +54,8 @@ void           rtable_init(void);
 int             rtable_exists(unsigned int);
 int             rtable_add(unsigned int);
 unsigned int    rtable_l2(unsigned int);
-void            rtable_l2set(unsigned int, unsigned int);
+unsigned int    rtable_loindex(unsigned int);
+void            rtable_l2set(unsigned int, unsigned int, unsigned int);
 
 struct rtentry *rtable_lookup(unsigned int, struct sockaddr *,
                     struct sockaddr *, struct sockaddr *, uint8_t);
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.327
diff -u -p -r1.327 ip_output.c
--- sys/netinet/ip_output.c     4 Sep 2016 17:18:56 -0000       1.327
+++ sys/netinet/ip_output.c     9 Nov 2016 10:39:13 -0000
@@ -211,7 +211,7 @@ reroute:
 
                ia = ifatoia(ro->ro_rt->rt_ifa);
                if (ISSET(ro->ro_rt->rt_flags, RTF_LOCAL))
-                       ifp = if_get(lo0ifidx);
+                       ifp = if_get(rtable_loindex(m->m_pkthdr.ph_rtableid));
                else
                        ifp = if_get(ro->ro_rt->rt_ifidx);
                if (ifp == NULL) {
Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.168
diff -u -p -r1.168 ip6_input.c
--- sys/netinet6/ip6_input.c    24 Aug 2016 09:41:12 -0000      1.168
+++ sys/netinet6/ip6_input.c    9 Nov 2016 10:44:11 -0000
@@ -210,10 +210,11 @@ ip6_input(struct mbuf *m)
                        ip6stat.ip6s_mext1++;
        } else {
                if (m->m_next) {
-                       if (m->m_flags & M_LOOP) {
-                               ip6stat.ip6s_m2m[lo0ifidx]++;   /*XXX*/
-                       } else if (ifp->if_index < nitems(ip6stat.ip6s_m2m))
-                               ip6stat.ip6s_m2m[ifp->if_index]++;
+                       int ifidx = m->m_pkthdr.ph_ifidx;
+                       if (m->m_flags & M_LOOP)
+                               ifidx = rtable_loindex(m->m_pkthdr.ph_rtableid);
+                       if (ifidx < nitems(ip6stat.ip6s_m2m))
+                               ip6stat.ip6s_m2m[ifidx]++;
                        else
                                ip6stat.ip6s_m2m[0]++;
                } else
Index: sys/netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.216
diff -u -p -r1.216 ip6_output.c
--- sys/netinet6/ip6_output.c   19 Sep 2016 18:09:09 -0000      1.216
+++ sys/netinet6/ip6_output.c   9 Nov 2016 10:39:13 -0000
@@ -460,7 +460,7 @@ reroute:
                        goto bad;
                }
                if (ISSET(rt->rt_flags, RTF_LOCAL))
-                       ifp = if_get(lo0ifidx);
+                       ifp = if_get(rtable_loindex(m->m_pkthdr.ph_rtableid));
                else
                        ifp = if_get(rt->rt_ifidx);
        } else {
Index: sys/sys/socket.h
===================================================================
RCS file: /cvs/src/sys/sys/socket.h,v
retrieving revision 1.92
diff -u -p -r1.92 socket.h
--- sys/sys/socket.h    28 Sep 2016 18:50:20 -0000      1.92
+++ sys/sys/socket.h    9 Nov 2016 10:39:13 -0000
@@ -143,7 +143,9 @@ struct      splice {
 /*
  * Maximum number of alternate routing tables
  */
-#define        RT_TABLEID_MAX  255
+#define        RT_TABLEID_MAX          255
+#define        RT_TABLEID_BITS         8
+#define        RT_TABLEID_MASK         0xff
 
 #endif /* __BSD_VISIBLE */
 
Index: share/man/man9/rtable_add.9
===================================================================
RCS file: /cvs/src/share/man/man9/rtable_add.9,v
retrieving revision 1.7
diff -u -p -r1.7 rtable_add.9
--- share/man/man9/rtable_add.9 11 Dec 2015 16:08:30 -0000      1.7
+++ share/man/man9/rtable_add.9 9 Nov 2016 10:39:13 -0000
@@ -21,6 +21,7 @@
 .Sh NAME
 .Nm rtable_add ,
 .Nm rtable_exists ,
+.Nm rtable_loindex ,
 .Nm rtable_l2 ,
 .Nm rtable_l2set
 .Nd routing tables and routing domains interface
@@ -31,6 +32,8 @@
 .Ft int
 .Fn rtable_exists "unsigned int id"
 .Ft unsigned int
+.Fn rtable_loindex "unsigned int id"
+.Ft unsigned int
 .Fn rtable_l2 "unsigned int id"
 .Ft void
 .Fn rtable_l2set "unsigned int id" "unsigned int rdomain"
@@ -53,6 +56,11 @@ if routing table with ID
 exists,
 .Fa 0
 otherwise.
+.It Fn rtable_loindex "unsigned int id"
+Return the default
+.Xr lo 4
+interface index for the routing table with ID of
+.Fa id .
 .It Fn rtable_l2 "unsigned int id"
 Get the routing domain of routing table with ID of
 .Fa id .
@@ -65,6 +73,7 @@ under the routing domain with ID of
 .Sh CONTEXT
 .Fn rtable_add ,
 .Fn rtable_exists ,
+.Fn rtable_loindex ,
 .Fn rtable_l2 ,
 and
 .Fn task_l2set
@@ -82,5 +91,6 @@ already exists.
 Memory could not be allocated to extend the list of routing domains.
 .El
 .Sh SEE ALSO
+.Xr lo 4 ,
 .Xr route 4 ,
 .Xr route 8
Index: share/man/man4/rdomain.4
===================================================================
RCS file: /cvs/src/share/man/man4/rdomain.4,v
retrieving revision 1.8
diff -u -p -r1.8 rdomain.4
--- share/man/man4/rdomain.4    4 Jul 2015 07:51:03 -0000       1.8
+++ share/man/man4/rdomain.4    9 Nov 2016 13:56:18 -0000
@@ -78,7 +78,10 @@ When an interface is assigned to a non-e
 it gets created automatically.
 At the same time an
 .Nm rtable
-with the same ID gets created and assigned to the new domain.
+with the same ID and a
+.Xr lo 4
+interface with a unit number equals to ID get created and assigned to the new
+domain.
 .Pp
 The highest ID that can be used for an
 .Nm rdomain
@@ -87,7 +90,6 @@ is 255.
 Set up em0 and lo4 onto rdomain 4:
 .Bd -literal -offset indent
 # ifconfig em0 rdomain 4
-# ifconfig lo4 rdomain 4
 # ifconfig lo4 inet 127.0.0.1/8
 # ifconfig em0 192.0.2.100/24
 .Ed
@@ -114,6 +116,7 @@ match out on rdomain 4 to !$internal_net
 .Ed
 .Sh SEE ALSO
 .Xr ps 1 ,
+.Xr lo 4 ,
 .Xr route 4 ,
 .Xr pf.conf 5 ,
 .Xr ifconfig 8 ,

Reply via email to