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:
parent
046a577d69
commit
c28aedefd8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=194547
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user