Rework SPX segment reassembly, which was originally based on our TCP

reassembly but failed to be modernized over time:

- Use queue(9).
- Specifically allocate queue entries of type M_SPXREASSQ to point at
  member mbufs, rather than casting mbuf data to 'spx_q'.
- Maintain the mbuf pointer as part of the queue entry so that we can
  later free the mbuf without using dtom().
This commit is contained in:
Robert Watson 2009-06-20 18:24:25 +00:00
parent 046a577d69
commit c28aedefd8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=194547
4 changed files with 55 additions and 57 deletions

View File

@ -91,8 +91,9 @@ struct spx {
struct spxhdr si_s; struct spxhdr si_s;
} __packed; } __packed;
struct spx_q { struct spx_q {
struct spx_q *si_next; struct mbuf *sq_msi;
struct spx_q *si_prev; struct spx *sq_si;
LIST_ENTRY(spx_q) sq_entry;
}; };
#define SI(x) ((struct spx *)x) #define SI(x) ((struct spx *)x)
#define si_sum si_i.ipx_sum #define si_sum si_i.ipx_sum
@ -114,7 +115,7 @@ struct spx_q {
* SPX control block, one per connection * SPX control block, one per connection
*/ */
struct spxpcb { struct spxpcb {
struct spx_q s_q; /* queue for out-of-order receipt */ LIST_HEAD(, spx_q) s_q; /* queue for out-of-order receipt */
struct ipxpcb *s_ipxpcb; /* backpointer to internet pcb */ struct ipxpcb *s_ipxpcb; /* backpointer to internet pcb */
u_char s_state; u_char s_state;
u_char s_flags; u_char s_flags;

View File

@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/mutex.h> #include <sys/mutex.h>
@ -92,24 +93,7 @@ __FBSDID("$FreeBSD$");
static int spx_use_delack = 0; static int spx_use_delack = 0;
static int spxrexmtthresh = 3; static int spxrexmtthresh = 3;
static __inline void MALLOC_DEFINE(M_SPXREASSQ, "spxreassq", "SPX reassembly queue entry");
spx_insque(struct spx_q *element, struct spx_q *head)
{
element->si_next = head->si_next;
element->si_prev = head;
head->si_next = element;
element->si_next->si_prev = element;
}
static void
spx_remque(struct spx_q *element)
{
element->si_next->si_prev = element->si_prev;
element->si_prev->si_next = element->si_next;
element->si_prev = NULL;
}
/* /*
* Flesh pending queued segments on SPX close. * Flesh pending queued segments on SPX close.
@ -117,15 +101,12 @@ spx_remque(struct spx_q *element)
void void
spx_reass_flush(struct spxpcb *cb) spx_reass_flush(struct spxpcb *cb)
{ {
struct spx_q *s; struct spx_q *q;
struct mbuf *m;
s = cb->s_q.si_next; while ((q = LIST_FIRST(&cb->s_q)) != NULL) {
while (s != &(cb->s_q)) { LIST_REMOVE(q, sq_entry);
s = s->si_next; m_freem(q->sq_msi);
spx_remque(s); free(q, M_SPXREASSQ);
m = dtom(s);
m_freem(m);
} }
} }
@ -136,7 +117,7 @@ void
spx_reass_init(struct spxpcb *cb) spx_reass_init(struct spxpcb *cb)
{ {
cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; LIST_INIT(&cb->s_q);
} }
/* /*
@ -145,9 +126,9 @@ spx_reass_init(struct spxpcb *cb)
* suppresses duplicates. * suppresses duplicates.
*/ */
int int
spx_reass(struct spxpcb *cb, struct spx *si) spx_reass(struct spxpcb *cb, struct mbuf *msi, struct spx *si)
{ {
struct spx_q *q; struct spx_q *q, *q_new, *q_temp;
struct mbuf *m; struct mbuf *m;
struct socket *so = cb->s_ipxpcb->ipxp_socket; struct socket *so = cb->s_ipxpcb->ipxp_socket;
char packetp = cb->s_flags & SF_HI; char packetp = cb->s_flags & SF_HI;
@ -352,17 +333,26 @@ spx_reass(struct spxpcb *cb, struct spx *si)
* Loop through all packets queued up to insert in appropriate * Loop through all packets queued up to insert in appropriate
* sequence. * sequence.
*/ */
for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { q_new = malloc(sizeof(*q_new), M_SPXREASSQ, M_NOWAIT | M_ZERO);
if (si->si_seq == SI(q)->si_seq) { if (q_new == NULL)
return (1);
q_new->sq_si = si;
q_new->sq_msi = msi;
LIST_FOREACH(q, &cb->s_q, sq_entry) {
if (si->si_seq == q->sq_si->si_seq) {
free(q_new, M_SPXREASSQ);
spxstat.spxs_rcvduppack++; spxstat.spxs_rcvduppack++;
return (1); return (1);
} }
if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { if (SSEQ_LT(si->si_seq, q->sq_si->si_seq)) {
spxstat.spxs_rcvoopack++; spxstat.spxs_rcvoopack++;
break; break;
} }
} }
spx_insque((struct spx_q *)si, q->si_prev); if (q != NULL)
LIST_INSERT_BEFORE(q, q_new, sq_entry);
else
LIST_INSERT_HEAD(&cb->s_q, q_new, sq_entry);
/* /*
* If this packet is urgent, inform process * If this packet is urgent, inform process
@ -381,25 +371,31 @@ spx_reass(struct spxpcb *cb, struct spx *si)
* and present all acknowledged data to user; if in packet interface * and present all acknowledged data to user; if in packet interface
* mode, show packet headers. * mode, show packet headers.
*/ */
for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { LIST_FOREACH_SAFE(q, &cb->s_q, sq_entry, q_temp) {
if (SI(q)->si_seq == cb->s_ack) { struct spx *qsi;
struct mbuf *mqsi;
qsi = q->sq_si;
mqsi = q->sq_msi;
if (qsi->si_seq == cb->s_ack) {
cb->s_ack++; cb->s_ack++;
m = dtom(q); if (qsi->si_cc & SPX_OB) {
if (SI(q)->si_cc & SPX_OB) {
cb->s_oobflags &= ~SF_IOOB; cb->s_oobflags &= ~SF_IOOB;
if (so->so_rcv.sb_cc) if (so->so_rcv.sb_cc)
so->so_oobmark = so->so_rcv.sb_cc; so->so_oobmark = so->so_rcv.sb_cc;
else else
so->so_rcv.sb_state |= SBS_RCVATMARK; so->so_rcv.sb_state |= SBS_RCVATMARK;
} }
q = q->si_prev; LIST_REMOVE(q, sq_entry);
spx_remque(q->si_next); free(q, M_SPXREASSQ);
wakeup = 1; wakeup = 1;
spxstat.spxs_rcvpack++; spxstat.spxs_rcvpack++;
#ifdef SF_NEWCALL #ifdef SF_NEWCALL
if (cb->s_flags2 & SF_NEWCALL) { if (cb->s_flags2 & SF_NEWCALL) {
struct spxhdr *sp = mtod(m, struct spxhdr *); struct spxhdr *sp =
mtod(mqsi, struct spxhdr *);
u_char dt = sp->spx_dt; u_char dt = sp->spx_dt;
spx_newchecks[4]++; spx_newchecks[4]++;
if (dt != cb->s_rhdr.spx_dt) { if (dt != cb->s_rhdr.spx_dt) {
struct mbuf *mm = struct mbuf *mm =
@ -417,31 +413,32 @@ spx_reass(struct spxpcb *cb, struct spx *si)
} }
} }
if (sp->spx_cc & SPX_OB) { if (sp->spx_cc & SPX_OB) {
MCHTYPE(m, MT_OOBDATA); MCHTYPE(mqsi, MT_OOBDATA);
spx_newchecks[1]++; spx_newchecks[1]++;
so->so_oobmark = 0; so->so_oobmark = 0;
so->so_rcv.sb_state &= ~SBS_RCVATMARK; so->so_rcv.sb_state &= ~SBS_RCVATMARK;
} }
if (packetp == 0) { if (packetp == 0) {
m->m_data += SPINC; mqsi->m_data += SPINC;
m->m_len -= SPINC; mqsi->m_len -= SPINC;
m->m_pkthdr.len -= SPINC; mqsi->m_pkthdr.len -= SPINC;
} }
if ((sp->spx_cc & SPX_EM) || packetp) { if ((sp->spx_cc & SPX_EM) || packetp) {
sbappendrecord_locked(&so->so_rcv, m); sbappendrecord_locked(&so->so_rcv,
mqsi);
spx_newchecks[9]++; spx_newchecks[9]++;
} else } else
sbappend_locked(&so->so_rcv, m); sbappend_locked(&so->so_rcv, mqsi);
} else } else
#endif #endif
if (packetp) if (packetp)
sbappendrecord_locked(&so->so_rcv, m); sbappendrecord_locked(&so->so_rcv, mqsi);
else { else {
cb->s_rhdr = *mtod(m, struct spxhdr *); cb->s_rhdr = *mtod(mqsi, struct spxhdr *);
m->m_data += SPINC; mqsi->m_data += SPINC;
m->m_len -= SPINC; mqsi->m_len -= SPINC;
m->m_pkthdr.len -= SPINC; mqsi->m_pkthdr.len -= SPINC;
sbappend_locked(&so->so_rcv, m); sbappend_locked(&so->so_rcv, mqsi);
} }
} else } else
break; break;

View File

@ -378,7 +378,7 @@ spx_input(struct mbuf *m, struct ipxpcb *ipxp)
m->m_pkthdr.len -= sizeof(struct ipx); m->m_pkthdr.len -= sizeof(struct ipx);
m->m_data += sizeof(struct ipx); m->m_data += sizeof(struct ipx);
if (spx_reass(cb, si)) if (spx_reass(cb, m, si))
m_freem(m); m_freem(m);
if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
spx_output(cb, NULL); spx_output(cb, NULL);

View File

@ -152,7 +152,7 @@ extern struct spx_istat spx_istat;
extern u_short spx_newchecks[50]; extern u_short spx_newchecks[50];
int spx_output(struct spxpcb *cb, struct mbuf *m0); int spx_output(struct spxpcb *cb, struct mbuf *m0);
int spx_reass(struct spxpcb *cb, struct spx *si); int spx_reass(struct spxpcb *cb, struct mbuf *msi, struct spx *si);
void spx_reass_flush(struct spxpcb *cb); void spx_reass_flush(struct spxpcb *cb);
void spx_reass_init(struct spxpcb *cb); void spx_reass_init(struct spxpcb *cb);
#endif #endif