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;
};