Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Nov 2003 10:47:25 -0800 (PST)
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 43000 for review
Message-ID:  <200311241847.hAOIlPen018004@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=43000

Change 43000 by sam@sam_ebb on 2003/11/24 10:47:10

	replace MT_TAG use in dummynet with m_tag's

Affected files ...

.. //depot/projects/netperf/sys/net/if_ethersubr.c#12 edit
.. //depot/projects/netperf/sys/netinet/ip_dummynet.c#19 edit
.. //depot/projects/netperf/sys/netinet/ip_dummynet.h#4 edit
.. //depot/projects/netperf/sys/netinet/ip_input.c#25 edit
.. //depot/projects/netperf/sys/netinet/ip_output.c#18 edit

Differences ...

==== //depot/projects/netperf/sys/net/if_ethersubr.c#12 (text+ko) ====

@@ -323,12 +323,7 @@
 int
 ether_output_frame(struct ifnet *ifp, struct mbuf *m)
 {
-	struct ip_fw *rule = NULL;
-
-	/* Extract info from dummynet tag, ignore others */
-	for (; m->m_type == MT_TAG; m = m->m_next)
-		if (m->m_flags == PACKET_TAG_DUMMYNET)
-			rule = ((struct dn_pkt *)m)->rule;
+	struct ip_fw *rule = ip_dn_find_rule(m);
 
 	if (rule == NULL && BDG_ACTIVE(ifp)) {
 		/*
@@ -613,14 +608,7 @@
 #if defined(NETATALK)
 	struct llc *l;
 #endif
-	struct ip_fw *rule = NULL;
-
-	/* Extract info from dummynet tag, ignore others */
-	for (;m->m_type == MT_TAG; m = m->m_next)
-		if (m->m_flags == PACKET_TAG_DUMMYNET) {
-			rule = ((struct dn_pkt *)m)->rule;
-			ifp = m->m_next->m_pkthdr.rcvif;
-		}
+	struct ip_fw *rule = ip_dn_find_rule(m);
 
 	KASSERT(ifp != NULL, ("ether_demux: NULL interface pointer"));
 

==== //depot/projects/netperf/sys/netinet/ip_dummynet.c#19 (text+ko) ====

@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.74 2003/11/23 18:13:41 sam Exp $
+ * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.73 2003/11/08 23:36:31 sam Exp $
  */
 
 #define	DUMMYNET_DEBUG
@@ -405,6 +405,22 @@
  */
 
 /*
+ * Return the mbuf tag holding the dummynet state.  As an optimization
+ * this is assumed to be the first tag on the list.  If this turns out
+ * wrong we'll need to search the list.
+ */
+static struct dn_pkt_tag *
+dn_tag_get(struct mbuf *m)
+{
+    struct m_tag *mtag = m_tag_first(m);
+    KASSERT(mtag != NULL &&
+	    mtag->m_tag_cookie == MTAG_ABI_COMPAT &&
+	    mtag->m_tag_id == PACKET_TAG_DUMMYNET,
+	    ("packet on dummynet queue w/o dummynet tag!"));
+    return (struct dn_pkt_tag *)(mtag+1);
+}
+
+/*
  * Scheduler functions:
  *
  * transmit_event() is called when the delay-line needs to enter
@@ -425,87 +441,85 @@
 static void
 transmit_event(struct dn_pipe *pipe)
 {
-    struct dn_pkt *pkt ;
+    struct mbuf *m ;
+    struct dn_pkt_tag *pkt ;
 
     DUMMYNET_LOCK_ASSERT();
 
-    while ( (pkt = pipe->head) && DN_KEY_LEQ(pkt->output_time, curr_time) ) {
+    while ( (m = pipe->head) ) {
+	pkt = dn_tag_get(m);
+	if ( !DN_KEY_LEQ(pkt->output_time, curr_time) )
+	    break;
 	/*
 	 * first unlink, then call procedures, since ip_input() can invoke
 	 * ip_output() and viceversa, thus causing nested calls
 	 */
-	pipe->head = DN_NEXT(pkt) ;
+	pipe->head = m->m_nextpkt ;
 
 	/* XXX: drop the lock for now to avoid LOR's */
 	DUMMYNET_UNLOCK();
-	/*
-	 * The actual mbuf is preceded by a struct dn_pkt, resembling an mbuf
-	 * (NOT A REAL one, just a small block of malloc'ed memory) with
-	 *     m_type = MT_TAG, m_flags = PACKET_TAG_DUMMYNET
-	 *     dn_m (m_next) = actual mbuf to be processed by ip_input/output
-	 * and some other fields.
-	 * The block IS FREED HERE because it contains parameters passed
-	 * to the called routine.
-	 */
 	switch (pkt->dn_dir) {
 	case DN_TO_IP_OUT:
-	    (void)ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL, NULL);
-	    rt_unref (pkt->ro.ro_rt, __func__) ;
+	    (void)ip_output(m, NULL, NULL, pkt->flags, NULL, NULL);
 	    break ;
 
 	case DN_TO_IP_IN :
-	    ip_input((struct mbuf *)pkt) ;
+	    ip_input(m) ;
 	    break ;
 
 	case DN_TO_BDG_FWD :
-	    if (!BDG_LOADED) {
+	    /*
+	     * The bridge requires/assumes the Ethernet header is
+	     * contiguous in the first mbuf header.  Insure this is true.
+	     */
+	    if (BDG_LOADED) {
+		if (m->m_len < ETHER_HDR_LEN &&
+		    (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
+		    printf("dummynet/bridge: pullup fail, dropping pkt\n");
+		    break;
+		}
+		m = bdg_forward_ptr(m, pkt->ifp);
+	    } else {
 		/* somebody unloaded the bridge module. Drop pkt */
 		/* XXX rate limit */
 		printf("dummynet: dropping bridged packet trapped in pipe\n");
-		m_freem(pkt->dn_m);
+	    }
+	    if (m)
+		m_freem(m);
+	    break;
+
+	case DN_TO_ETH_DEMUX:
+	    /*
+	     * The Ethernet code assumes the Ethernet header is
+	     * contiguous in the first mbuf header.  Insure this is true.
+	     */
+	    if (m->m_len < ETHER_HDR_LEN &&
+		(m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
+		printf("dummynet/ether: pullup fail, dropping pkt\n");
 		break;
-	    } /* fallthrough */
-	case DN_TO_ETH_DEMUX:
-	    {
-		struct mbuf *m = (struct mbuf *)pkt ;
-
-		if (pkt->dn_m->m_len < ETHER_HDR_LEN &&
-		    (pkt->dn_m = m_pullup(pkt->dn_m, ETHER_HDR_LEN)) == NULL) {
-		    printf("dummynet/bridge: pullup fail, dropping pkt\n");
-		    break;
-		}
-		/*
-		 * bdg_forward() wants a pointer to the pseudo-mbuf-header, but
-		 * on return it will supply the pointer to the actual packet
-		 * (originally pkt->dn_m, but could be something else now) if
-		 * it has not consumed it.
-		 */
-		if (pkt->dn_dir == DN_TO_BDG_FWD) {
-		    m = bdg_forward_ptr(m, pkt->ifp);
-		    if (m)
-			m_freem(m);
-		} else
-		    ether_demux(NULL, m); /* which consumes the mbuf */
 	    }
+	    ether_demux(m->m_pkthdr.rcvif, m); /* which consumes the mbuf */
 	    break ;
+
 	case DN_TO_ETH_OUT:
-	    ether_output_frame(pkt->ifp, (struct mbuf *)pkt);
+	    ether_output_frame(pkt->ifp, m);
 	    break;
 
 	default:
 	    printf("dummynet: bad switch %d!\n", pkt->dn_dir);
-	    m_freem(pkt->dn_m);
+	    m_freem(m);
 	    break ;
 	}
-	free(pkt, M_DUMMYNET);
 	DUMMYNET_LOCK();
     }
     /* if there are leftover packets, put into the heap for next event */
-    if ( (pkt = pipe->head) )
-         heap_insert(&extract_heap, pkt->output_time, pipe ) ;
-    /* XXX should check errors on heap_insert, by draining the
-     * whole pipe p and hoping in the future we are more successful
-     */
+    if ( (m = pipe->head) ) {
+	pkt = dn_tag_get(m) ;
+	/* XXX should check errors on heap_insert, by draining the
+	 * whole pipe p and hoping in the future we are more successful
+	 */
+	heap_insert(&extract_heap, pkt->output_time, pipe ) ;
+    }
 }
 
 /*
@@ -513,8 +527,8 @@
  * before being able to transmit a packet. The credit is taken from
  * either a pipe (WF2Q) or a flow_queue (per-flow queueing)
  */
-#define SET_TICKS(pkt, q, p)	\
-    (pkt->dn_m->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \
+#define SET_TICKS(_m, q, p)	\
+    ((_m)->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \
 	    p->bandwidth ;
 
 /*
@@ -522,21 +536,23 @@
  * and put into delay line (p_queue)
  */
 static void
-move_pkt(struct dn_pkt *pkt, struct dn_flow_queue *q,
+move_pkt(struct mbuf *pkt, struct dn_flow_queue *q,
 	struct dn_pipe *p, int len)
 {
-    q->head = DN_NEXT(pkt) ;
+    struct dn_pkt_tag *dt = dn_tag_get(pkt);
+
+    q->head = pkt->m_nextpkt ;
     q->len-- ;
     q->len_bytes -= len ;
 
-    pkt->output_time = curr_time + p->delay ;
+    dt->output_time = curr_time + p->delay ;
 
     if (p->head == NULL)
 	p->head = pkt;
     else
-	DN_NEXT(p->tail) = pkt;
+	p->tail->m_nextpkt = pkt;
     p->tail = pkt;
-    DN_NEXT(p->tail) = NULL;
+    p->tail->m_nextpkt = NULL;
 }
 
 /*
@@ -549,7 +565,7 @@
 static void
 ready_event(struct dn_flow_queue *q)
 {
-    struct dn_pkt *pkt;
+    struct mbuf *pkt;
     struct dn_pipe *p = q->fs->pipe ;
     int p_was_empty ;
 
@@ -571,7 +587,7 @@
      */
     q->numbytes += ( curr_time - q->sched_time ) * p->bandwidth;
     while ( (pkt = q->head) != NULL ) {
-	int len = pkt->dn_m->m_pkthdr.len;
+	int len = pkt->m_pkthdr.len;
 	int len_scaled = p->bandwidth ? len*8*hz : 0 ;
 	if (len_scaled > q->numbytes )
 	    break ;
@@ -639,9 +655,9 @@
     while ( p->numbytes >=0 && (sch->elements>0 || neh->elements >0) ) {
 	if (sch->elements > 0) { /* have some eligible pkts to send out */
 	    struct dn_flow_queue *q = sch->p[0].object ;
-	    struct dn_pkt *pkt = q->head;
+	    struct mbuf *pkt = q->head;
 	    struct dn_flow_set *fs = q->fs;
-	    u_int64_t len = pkt->dn_m->m_pkthdr.len;
+	    u_int64_t len = pkt->m_pkthdr.len;
 	    int len_scaled = p->bandwidth ? len*8*hz : 0 ;
 
 	    heap_extract(sch, NULL); /* remove queue from heap */
@@ -658,7 +674,7 @@
 		 * update F and position in backlogged queue, then
 		 * put flow in not_eligible_heap (we will fix this later).
 		 */
-		len = (q->head)->dn_m->m_pkthdr.len;
+		len = (q->head)->m_pkthdr.len;
 		q->F += (len<<MY_M)/(u_int64_t) fs->weight ;
 		if (DN_KEY_LEQ(q->S, p->V))
 		    heap_insert(neh, q->S, q);
@@ -713,7 +729,7 @@
 
 	if (p->bandwidth > 0)
 	    t = ( p->bandwidth -1 - p->numbytes) / p->bandwidth ;
-	p->tail->output_time += t ;
+	dn_tag_get(p->tail)->output_time += t ;
 	p->sched_time = curr_time ;
 	heap_insert(&wfq_ready_heap, curr_time + t, (void *)p);
 	/* XXX should check errors on heap_insert, and drain the whole
@@ -1116,7 +1132,8 @@
 static int
 dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
 {
-    struct dn_pkt *pkt;
+    struct dn_pkt_tag *pkt;
+    struct m_tag *mtag;
     struct dn_flow_set *fs;
     struct dn_pipe *pipe ;
     u_int64_t len = m->m_pkthdr.len ;
@@ -1124,7 +1141,9 @@
     int is_pipe;
 #if IPFW2
     ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs;
+#endif
 
+#if IPFW2
     if (cmd->opcode == O_LOG)
 	cmd += F_LEN(cmd);
     is_pipe = (cmd->opcode == O_PIPE);
@@ -1175,16 +1194,17 @@
 	goto dropit ;
 
     /* XXX expensive to zero, see if we can remove it*/
-    pkt = (struct dn_pkt *)malloc(sizeof (*pkt), M_DUMMYNET, M_NOWAIT|M_ZERO);
-    if ( pkt == NULL )
+    mtag = m_tag_get(PACKET_TAG_DUMMYNET,
+		sizeof(struct dn_pkt_tag), M_NOWAIT|M_ZERO);
+    if ( mtag == NULL )
 	goto dropit ;		/* cannot allocate packet header	*/
+    m_tag_prepend(m, mtag);	/* attach to mbuf chain */
+    m->m_nextpkt = NULL;
+
+    pkt = (struct dn_pkt_tag *)(mtag+1);
     /* ok, i can handle the pkt now... */
     /* build and enqueue packet + parameters */
-    pkt->hdr.mh_type = MT_TAG;
-    pkt->hdr.mh_flags = PACKET_TAG_DUMMYNET;
     pkt->rule = fwa->rule ;
-    DN_NEXT(pkt) = NULL;
-    pkt->dn_m = m;
     pkt->dn_dir = dir ;
 
     pkt->ifp = fwa->oif;
@@ -1206,14 +1226,14 @@
 	pkt->flags = fwa->flags;
     }
     if (q->head == NULL)
-	q->head = pkt;
+	q->head = m;
     else
-	DN_NEXT(q->tail) = pkt;
-    q->tail = pkt;
+	q->tail->m_nextpkt = m;
+    q->tail = m;
     q->len++;
     q->len_bytes += len ;
 
-    if ( q->head != pkt )	/* flow was not idle, we are done */
+    if ( q->head != m )		/* flow was not idle, we are done */
 	goto done;
     /*
      * If we reach this point the flow was previously idle, so we need
@@ -1226,7 +1246,7 @@
 	 */
 	dn_key t = 0 ;
 	if (pipe->bandwidth)
-	    t = SET_TICKS(pkt, q, pipe);
+	    t = SET_TICKS(m, q, pipe);
 	q->sched_time = curr_time ;
 	if (t == 0)	/* must process it now */
 	    ready_event( q );
@@ -1300,12 +1320,10 @@
  * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT)
  * Doing this would probably save us the initial bzero of dn_pkt
  */
-#define DN_FREE_PKT(pkt)	{		\
-	struct dn_pkt *n = pkt ;		\
-	rt_unref ( n->ro.ro_rt, __func__ ) ;	\
-	m_freem(n->dn_m);			\
-	pkt = DN_NEXT(n) ;			\
-	free(n, M_DUMMYNET) ;	}
+#define	DN_FREE_PKT(_m) do {				\
+	rt_unref(dn_tag_get(_m)->ro.ro_rt, __func__);	\
+	m_freem(_m);					\
+} while (0)
 
 /*
  * Dispose all packets and flow_queues on a flow_set.
@@ -1316,7 +1334,6 @@
 static void
 purge_flow_set(struct dn_flow_set *fs, int all)
 {
-    struct dn_pkt *pkt ;
     struct dn_flow_queue *q, *qn ;
     int i ;
 
@@ -1324,8 +1341,13 @@
 
     for (i = 0 ; i <= fs->rq_size ; i++ ) {
 	for (q = fs->rq[i] ; q ; q = qn ) {
-	    for (pkt = q->head ; pkt ; )
-		DN_FREE_PKT(pkt) ;
+	    struct mbuf *m, *mnext;
+
+	    mnext = q->head;
+	    while ((m = mnext) != NULL) {
+		mnext = m->m_nextpkt;
+		DN_FREE_PKT(m);
+	    }
 	    qn = q->next ;
 	    free(q, M_DUMMYNET);
 	}
@@ -1352,12 +1374,15 @@
 static void
 purge_pipe(struct dn_pipe *pipe)
 {
-    struct dn_pkt *pkt ;
+    struct mbuf *m, *mnext;
 
     purge_flow_set( &(pipe->fs), 1 );
 
-    for (pkt = pipe->head ; pkt ; )
-	DN_FREE_PKT(pkt) ;
+    mnext = pipe->head;
+    while ((m = mnext) != NULL) {
+	mnext = m->m_nextpkt;
+	DN_FREE_PKT(m);
+    }
 
     heap_free( &(pipe->scheduler_heap) );
     heap_free( &(pipe->not_eligible_heap) );
@@ -1412,13 +1437,15 @@
 {
     int i ;
     struct dn_flow_queue *q ;
-    struct dn_pkt *pkt ;
+    struct mbuf *m ;
 
     for (i = 0 ; i <= fs->rq_size ; i++) /* last one is ovflow */
 	for (q = fs->rq[i] ; q ; q = q->next )
-	    for (pkt = q->head ; pkt ; pkt = DN_NEXT(pkt) )
+	    for (m = q->head ; m ; m = m->m_nextpkt ) {
+		struct dn_pkt_tag *pkt = dn_tag_get(m) ;
 		if (pkt->rule == r)
 		    pkt->rule = ip_fw_default_rule ;
+	    }
 }
 /*
  * when a firewall rule is deleted, scan all queues and remove the flow-id
@@ -1428,8 +1455,9 @@
 dn_rule_delete(void *r)
 {
     struct dn_pipe *p ;
-    struct dn_pkt *pkt ;
     struct dn_flow_set *fs ;
+    struct dn_pkt_tag *pkt ;
+    struct mbuf *m ;
 
     DUMMYNET_LOCK();
     /*
@@ -1442,9 +1470,11 @@
     for ( p = all_pipes ; p ; p = p->next ) {
 	fs = &(p->fs) ;
 	dn_rule_delete_fs(fs, r);
-	for (pkt = p->head ; pkt ; pkt = DN_NEXT(pkt) )
+	for (m = p->head ; m ; m = m->m_nextpkt ) {
+	    pkt = dn_tag_get(m) ;
 	    if (pkt->rule == r)
 		pkt->rule = ip_fw_default_rule ;
+	}
     }
     DUMMYNET_UNLOCK();
 }
@@ -1718,7 +1748,7 @@
 {
     struct dn_flow_set *fs;
     struct dn_pipe *p;
-    struct dn_pkt *pkt;
+    struct mbuf *m, *mnext;
 
     DUMMYNET_LOCK_ASSERT();
 
@@ -1731,8 +1761,12 @@
 
     for (p = all_pipes; p; p= p->next ) {
 	purge_flow_set(&(p->fs), 0);
-	for (pkt = p->head ; pkt ; )
-	    DN_FREE_PKT(pkt) ;
+
+	mnext = p->head;
+	while ((m = mnext) != NULL) {
+	    mnext = m->m_nextpkt;
+	    DN_FREE_PKT(m);
+	}
 	p->head = p->tail = NULL ;
     }
 }

==== //depot/projects/netperf/sys/netinet/ip_dummynet.h#4 (text+ko) ====

@@ -111,24 +111,12 @@
 
 #ifdef _KERNEL
 /*
- * struct dn_pkt identifies a packet in the dummynet queue, but
- * is also used to tag packets passed back to the various destinations
- * (ip_input(), ip_output(), bdg_forward()  and so on).
- * As such the first part of the structure must be a struct m_hdr,
- * followed by dummynet-specific parameters. The m_hdr must be
- * initialized with
- *   mh_type	= MT_TAG;
- *   mh_flags	= PACKET_TYPE_DUMMYNET;
- *   mh_next	= <pointer to the actual mbuf>
- *
- * mh_nextpkt, mh_data are free for dummynet use (mh_nextpkt is used to
- * build a linked list of packets in a dummynet queue).
+ * Packets processed by dummynet have an mbuf tag associated with
+ * them that carries their dummynet state.  This is used within
+ * the dummynet code as well as outside when checking for special
+ * processing requirements.
  */
-struct dn_pkt {
-    struct m_hdr hdr ;
-#define DN_NEXT(x)	(struct dn_pkt *)(x)->hdr.mh_nextpkt
-#define dn_m	hdr.mh_next	/* packet to be forwarded */
-
+struct dn_pkt_tag {
     struct ip_fw *rule;		/* matching rule */
     int dn_dir;			/* action when packet comes out. */
 #define DN_TO_IP_OUT	1
@@ -217,7 +205,7 @@
     struct dn_flow_queue *next ;
     struct ipfw_flow_id id ;
 
-    struct dn_pkt *head, *tail ;	/* queue of packets */
+    struct mbuf *head, *tail ;	/* queue of packets */
     u_int len ;
     u_int len_bytes ;
     u_long numbytes ;		/* credit for transmission (dynamic queues) */
@@ -330,7 +318,7 @@
     int bandwidth;		/* really, bytes/tick.	*/
     int	delay ;			/* really, ticks	*/
 
-    struct	dn_pkt *head, *tail ;	/* packets in delay line */
+    struct	mbuf *head, *tail ;	/* packets in delay line */
 
     /* WF2Q+ */
     struct dn_heap scheduler_heap ; /* top extract - key Finish time*/
@@ -365,4 +353,13 @@
 #define	DUMMYNET_LOADED	(ip_dn_io_ptr != NULL)
 #endif
 
+/*
+ * Return the IPFW rule associated with the dummynet tag; if any.
+ */
+static __inline struct ip_fw *
+ip_dn_find_rule(struct mbuf *m)
+{
+	struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
+	return mtag ?  ((struct dn_pkt_tag *)(mtag+1))->rule : NULL;
+}
 #endif /* _IP_DUMMYNET_H */

==== //depot/projects/netperf/sys/netinet/ip_input.c#25 (text+ko) ====

@@ -318,7 +318,6 @@
 
 	args.eh = NULL;
 	args.oif = NULL;
-	args.rule = NULL;
 	args.divert_rule = 0;			/* divert cookie */
 	args.next_hop = NULL;
 
@@ -340,10 +339,6 @@
 			    m->_m_tag_id);
 			break;
 
-		case PACKET_TAG_DUMMYNET:
-			args.rule = ((struct dn_pkt *)m)->rule;
-			break;
-
 		case PACKET_TAG_DIVERT:
 			args.divert_rule = (intptr_t)m->m_hdr.mh_data & 0xffff;
 			break;
@@ -363,6 +358,7 @@
 		if (m0->m_nextpkt == (struct mbuf *)1)
 			m_free(m0);
 	}
+	args.rule = ip_dn_find_rule(m);
 
 	M_ASSERTPKTHDR(m);
 

==== //depot/projects/netperf/sys/netinet/ip_output.c#18 (text+ko) ====

@@ -143,6 +143,7 @@
 	int isbroadcast, sw_csum;
 	struct in_addr pkt_dst;
 	struct route iproute;
+	struct m_tag *dummytag;		/* dummynet packet tag */
 #ifdef IPSEC
 	struct socket *so;
 	struct secpolicy *sp = NULL;
@@ -169,21 +170,6 @@
 			    m0->_m_tag_id);
 			break;
 
-		case PACKET_TAG_DUMMYNET:
-			/*
-			 * the packet was already tagged, so part of the
-			 * processing was already done, and we need to go down.
-			 * Get parameters from the header.
-			 */
-			args.rule = ((struct dn_pkt *)m0)->rule;
-			opt = NULL ;
-			ro = & ( ((struct dn_pkt *)m0)->ro ) ;
-			imo = NULL ;
-			dst = ((struct dn_pkt *)m0)->dn_dst ;
-			ifp = ((struct dn_pkt *)m0)->ifp ;
-			flags = ((struct dn_pkt *)m0)->flags ;
-			break;
-
 		case PACKET_TAG_DIVERT:
 			args.divert_rule = (intptr_t)m0->m_data & 0xffff;
 			break;
@@ -210,7 +196,34 @@
 	if (inp != NULL)
 		INP_LOCK_ASSERT(inp);
 
-	if (args.rule != NULL) {	/* dummynet already saw us */
+	/*
+	 * When packet comes from dummynet restore state from
+	 * previous processing instead of the header.  Yech!
+	 *
+	 * XXX add conditional compilation?
+	 */
+	dummytag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
+	if (dummytag != NULL) {
+		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
+
+		/*
+		 * NB: the route in the tag is known to have a
+		 * reference that must be free'd, but doing this
+		 * before the storage is reclaimed is painful due
+		 * to some of the contorted code in this routine.
+		 * So instead unlink the tag from the mbuf so it
+		 * doesn't get reclaimed and do the cleanup explicitly
+		 * below.  We should be able to do this automatically
+		 * using a uma dtor method when m_tag's can be
+		 * allocated from zones.
+		 */
+		m_tag_unlink(m, dummytag);
+
+		args.rule = dt->rule;
+		ro = &dt->ro;
+		dst = dt->dn_dst;
+		ifp = dt->ifp;
+
 		ip = mtod(m, struct ip *);
 		hlen = ip->ip_hl << 2 ;
 		if (ro->ro_rt)
@@ -1081,6 +1094,12 @@
 		RTFREE(ro->ro_rt);
 		ro->ro_rt = NULL;
 	}
+	if (dummytag) {
+		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
+		if (dt->ro.ro_rt)
+			RTFREE(dt->ro.ro_rt);
+		m_tag_free(dummytag);
+	}
 #ifdef IPSEC
 	if (sp != NULL) {
 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200311241847.hAOIlPen018004>