The branch main has been updated by emaste:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=8ef7beb29edd1afc4931424eadb0e1c6a7f3c364

commit 8ef7beb29edd1afc4931424eadb0e1c6a7f3c364
Author:     Gleb Smirnoff <gleb...@freebsd.org>
AuthorDate: 2022-01-27 05:58:50 +0000
Commit:     Ed Maste <ema...@freebsd.org>
CommitDate: 2022-05-05 18:38:07 +0000

    dummynet: use m_rcvif_serialize/restore when queueing packets
    
    This fixed panic with interface being removed while packet
    was sitting on a queue.  This allows to pass all dummynet
    tests including forthcoming dummynet:ipfw_interface_removal
    and dummynet:pf_interface_removal and demonstrates use of
    m_rcvif_serialize() and m_rcvif_restore().
    
    Reviewed by:            kp
    Differential revision:  https://reviews.freebsd.org/D33267
    
    (cherry picked from commit 165746f4e4bf54c5902a103c2d4a3455e651c58f)
---
 sys/netpfil/ipfw/dn_aqm_codel.c      |  8 +++++++-
 sys/netpfil/ipfw/dn_aqm_pie.c        |  8 +++++++-
 sys/netpfil/ipfw/dn_sched.h          | 10 +++++++++-
 sys/netpfil/ipfw/dn_sched_fq_codel.h |  9 +++++++--
 sys/netpfil/ipfw/dn_sched_fq_pie.c   |  8 +++++++-
 sys/netpfil/ipfw/ip_dn_io.c          | 10 +++++++++-
 6 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/sys/netpfil/ipfw/dn_aqm_codel.c b/sys/netpfil/ipfw/dn_aqm_codel.c
index 79c6afd8b635..2f6d145485c6 100644
--- a/sys/netpfil/ipfw/dn_aqm_codel.c
+++ b/sys/netpfil/ipfw/dn_aqm_codel.c
@@ -192,8 +192,9 @@ struct mbuf *
 codel_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts)
 {
        struct m_tag *mtag;
-       struct mbuf *m = q->mq.head;
+       struct mbuf *m;
 
+next:  m = q->mq.head;
        if (m == NULL)
                return m;
        q->mq.head = m->m_nextpkt;
@@ -213,6 +214,11 @@ codel_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts)
                *pkt_ts = *(aqm_time_t *)(mtag + 1);
                m_tag_delete(m,mtag); 
        }
+       if (m->m_pkthdr.rcvif != NULL &&
+           __predict_false(m_rcvif_restore(m) == NULL)) {
+               m_freem(m);
+               goto next;
+       }
 
        return m;
 }
diff --git a/sys/netpfil/ipfw/dn_aqm_pie.c b/sys/netpfil/ipfw/dn_aqm_pie.c
index 3b80d6e94d38..5c97568b751e 100644
--- a/sys/netpfil/ipfw/dn_aqm_pie.c
+++ b/sys/netpfil/ipfw/dn_aqm_pie.c
@@ -328,8 +328,9 @@ static struct mbuf *
 pie_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts, int getts)
 {
        struct m_tag *mtag;
-       struct mbuf *m = q->mq.head;
+       struct mbuf *m;
 
+next:  m = q->mq.head;
        if (m == NULL)
                return m;
        q->mq.head = m->m_nextpkt;
@@ -351,6 +352,11 @@ pie_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts, 
int getts)
                        m_tag_delete(m,mtag); 
                }
        }
+       if (m->m_pkthdr.rcvif != NULL &&
+           __predict_false(m_rcvif_restore(m) == NULL)) {
+               m_freem(m);
+               goto next;
+       }
        return m;
 }
 
diff --git a/sys/netpfil/ipfw/dn_sched.h b/sys/netpfil/ipfw/dn_sched.h
index 5c506c1d30ac..ef7242cd7355 100644
--- a/sys/netpfil/ipfw/dn_sched.h
+++ b/sys/netpfil/ipfw/dn_sched.h
@@ -170,7 +170,10 @@ int ipdn_bound_var(int *v, int dflt, int lo, int hi, const 
char *msg);
 static __inline struct mbuf*
 dn_dequeue(struct dn_queue *q)
 {
-       struct mbuf *m = q->mq.head;
+       struct mbuf *m;
+
+next:
+       m = q->mq.head;
        if (m == NULL)
                return NULL;
 #ifdef NEW_AQM
@@ -190,6 +193,11 @@ dn_dequeue(struct dn_queue *q)
        }
        if (q->ni.length == 0) /* queue is now idle */
                q->q_time = V_dn_cfg.curr_time;
+       if (m->m_pkthdr.rcvif != NULL &&
+           __predict_false(m_rcvif_restore(m) == NULL)) {
+               m_freem(m);
+               goto next;
+       }
        return m;
 }
 
diff --git a/sys/netpfil/ipfw/dn_sched_fq_codel.h 
b/sys/netpfil/ipfw/dn_sched_fq_codel.h
index 2f82a63ca093..b84dfe7579fb 100644
--- a/sys/netpfil/ipfw/dn_sched_fq_codel.h
+++ b/sys/netpfil/ipfw/dn_sched_fq_codel.h
@@ -138,8 +138,9 @@ fq_update_stats(struct fq_codel_flow *q, struct fq_codel_si 
*si, int len,
 __inline static struct mbuf *
 fq_codel_extract_head(struct fq_codel_flow *q, aqm_time_t *pkt_ts, struct 
fq_codel_si *si)
 {
-       struct mbuf *m = q->mq.head;
+       struct mbuf *m;
 
+next:  m = q->mq.head;
        if (m == NULL)
                return m;
        q->mq.head = m->m_nextpkt;
@@ -159,7 +160,11 @@ fq_codel_extract_head(struct fq_codel_flow *q, aqm_time_t 
*pkt_ts, struct fq_cod
                *pkt_ts = *(aqm_time_t *)(mtag + 1);
                m_tag_delete(m,mtag); 
        }
-
+       if (m->m_pkthdr.rcvif != NULL &&
+           __predict_false(m_rcvif_restore(m) == NULL)) {
+               m_freem(m);
+               goto next;
+       }
        return m;
 }
 
diff --git a/sys/netpfil/ipfw/dn_sched_fq_pie.c 
b/sys/netpfil/ipfw/dn_sched_fq_pie.c
index 65a6dd74b92f..f6bb4b6fe6de 100644
--- a/sys/netpfil/ipfw/dn_sched_fq_pie.c
+++ b/sys/netpfil/ipfw/dn_sched_fq_pie.c
@@ -338,8 +338,9 @@ __inline static struct mbuf *
 fq_pie_extract_head(struct fq_pie_flow *q, aqm_time_t *pkt_ts,
        struct fq_pie_si *si, int getts)
 {
-       struct mbuf *m = q->mq.head;
+       struct mbuf *m;
 
+next:  m = q->mq.head;
        if (m == NULL)
                return m;
        q->mq.head = m->m_nextpkt;
@@ -361,6 +362,11 @@ fq_pie_extract_head(struct fq_pie_flow *q, aqm_time_t 
*pkt_ts,
                        m_tag_delete(m,mtag); 
                }
        }
+       if (m->m_pkthdr.rcvif != NULL &&
+           __predict_false(m_rcvif_restore(m) == NULL)) {
+               m_freem(m);
+               goto next;
+       }
        return m;
 }
 
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index 11ad498505f4..824e7450fb8f 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -500,6 +500,8 @@ dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
                goto drop;
        if (f->plr && random() < f->plr)
                goto drop;
+       if (m->m_pkthdr.rcvif != NULL)
+               m_rcvif_serialize(m);
 #ifdef NEW_AQM
        /* Call AQM enqueue function */
        if (q->fs->aqmfp)
@@ -548,7 +550,11 @@ transmit_event(struct mq *q, struct delay_line *dline, 
uint64_t now)
                        break;
                dline->mq.head = m->m_nextpkt;
                dline->mq.count--;
-               mq_append(q, m);
+               if (m->m_pkthdr.rcvif != NULL &&
+                 __predict_false(m_rcvif_restore(m) == NULL))
+                       m_freem(m);
+               else
+                       mq_append(q, m);
        }
        if (m != NULL) {
                dline->oid.subtype = 1; /* in heap */
@@ -617,6 +623,8 @@ serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t 
now)
                si->credit -= len_scaled;
                /* Move packet in the delay line */
                dn_tag_get(m)->output_time = V_dn_cfg.curr_time + s->link.delay 
;
+               if (m->m_pkthdr.rcvif != NULL)
+                       m_rcvif_serialize(m);
                mq_append(&si->dline.mq, m);
        }
 

Reply via email to