On Wed, Oct 18, 2017 at 10:48:30AM +0200, Alexandr Nedvedicky wrote:
>     I think you also want to add if_ih_remove() to loop_clone_destroy().

Yes, thanks for catching that.

>     I feel it should be called after if_detach().

I disagree.  Other pseudo-interfaces call it before.  But more
importantly, if_ih_remove() calls refcnt_finalize() which sleeps
until all references are gone.  We should not detach the interface
before doing that.

correct?

Parts of the diff have been commited, so here is the rest with
if_ih_remove() added.

bluhm

Index: net/if_loop.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_loop.c,v
retrieving revision 1.81
diff -u -p -r1.81 if_loop.c
--- net/if_loop.c       19 Apr 2017 15:21:54 -0000      1.81
+++ net/if_loop.c       18 Oct 2017 17:15:29 -0000
@@ -143,6 +143,7 @@
 int    loioctl(struct ifnet *, u_long, caddr_t);
 void   loopattach(int);
 void   lortrequest(struct ifnet *, int, struct rtentry *);
+int    loinput(struct ifnet *, struct mbuf *, void *);
 int    looutput(struct ifnet *,
            struct mbuf *, struct sockaddr *, struct rtentry *);
 
@@ -191,6 +192,7 @@ loop_clone_create(struct if_clone *ifc, 
 #if NBPFILTER > 0
        bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
 #endif
+       if_ih_insert(ifp, loinput, NULL);
        return (0);
 }
 
@@ -200,6 +202,7 @@ loop_clone_destroy(struct ifnet *ifp)
        if (ifp->if_index == rtable_loindex(ifp->if_rdomain))
                return (EPERM);
 
+       if_ih_remove(ifp, loinput, NULL);
        if_detach(ifp);
 
        free(ifp, M_DEVBUF, sizeof(*ifp));
@@ -207,11 +210,26 @@ loop_clone_destroy(struct ifnet *ifp)
 }
 
 int
+loinput(struct ifnet *ifp, struct mbuf *m, void *cookie)
+{
+       int error;
+
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("%s: no header mbuf", __func__);
+
+       error = if_input_local(ifp, m, m->m_pkthdr.ph_family);
+       if (error)
+               ifp->if_ierrors++;
+
+       return (1);
+}
+
+int
 looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     struct rtentry *rt)
 {
        if ((m->m_flags & M_PKTHDR) == 0)
-               panic("looutput: no header mbuf");
+               panic("%s: no header mbuf", __func__);
 
        if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
                m_freem(m);
@@ -219,7 +237,16 @@ looutput(struct ifnet *ifp, struct mbuf 
                        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
        }
 
-       return (if_input_local(ifp, m, dst->sa_family));
+       /* Use the quick path only once to avoid stack overflow. */
+       if ((m->m_flags & M_LOOP) == 0)
+               return (if_input_local(ifp, m, dst->sa_family));
+
+       m->m_pkthdr.ph_family = dst->sa_family;
+       if (mq_enqueue(&ifp->if_inputqueue, m))
+               return ENOBUFS;
+       task_add(softnettq, ifp->if_inputtask);
+
+       return (0);
 }
 
 void
Index: sys/mbuf.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/mbuf.h,v
retrieving revision 1.231
diff -u -p -r1.231 mbuf.h
--- sys/mbuf.h  23 Jun 2017 11:18:12 -0000      1.231
+++ sys/mbuf.h  18 Oct 2017 17:03:14 -0000
@@ -134,6 +134,7 @@ struct      pkthdr {
        u_int                    ph_rtableid;   /* routing table id */
        u_int                    ph_ifidx;      /* rcv interface index */
        u_int8_t                 ph_loopcnt;    /* mbuf is looping in kernel */
+       u_int8_t                 ph_family;     /* af, used when queueing */
        struct pkthdr_pf         pf;
 };
 

Reply via email to