PERFORCE change 43000 for review
Sam Leffler
sam at FreeBSD.org
Mon Nov 24 10:47:28 PST 2003
http://perforce.freebsd.org/chv.cgi?CH=43000
Change 43000 by sam at 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,
More information about the p4-projects
mailing list