sctp: cleanup timewait handling for vtags

MFC after:	1 week
This commit is contained in:
Michael Tuexen 2021-09-09 01:18:58 +02:00
parent 103b207536
commit 58a7bf124c
2 changed files with 49 additions and 122 deletions

View file

@ -4497,99 +4497,70 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr)
return (-2);
}
void
sctp_delete_from_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
static bool
sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport, uint32_t now)
{
struct sctpvtaghead *chain;
struct sctp_tagblock *twait_block;
int found = 0;
int i;
SCTP_INP_INFO_RLOCK_ASSERT();
chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
if ((twait_block->vtag_block[i].v_tag == tag) &&
if ((twait_block->vtag_block[i].tv_sec_at_expire >= now) &&
(twait_block->vtag_block[i].v_tag == tag) &&
(twait_block->vtag_block[i].lport == lport) &&
(twait_block->vtag_block[i].rport == rport)) {
twait_block->vtag_block[i].tv_sec_at_expire = 0;
twait_block->vtag_block[i].v_tag = 0;
twait_block->vtag_block[i].lport = 0;
twait_block->vtag_block[i].rport = 0;
found = 1;
break;
return (true);
}
}
if (found)
break;
}
return (false);
}
int
sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
static void
sctp_set_vtag_block(struct sctp_timewait *vtag_block, uint32_t time,
uint32_t tag, uint16_t lport, uint16_t rport)
{
struct sctpvtaghead *chain;
struct sctp_tagblock *twait_block;
int found = 0;
int i;
SCTP_INP_INFO_WLOCK();
chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
if ((twait_block->vtag_block[i].v_tag == tag) &&
(twait_block->vtag_block[i].lport == lport) &&
(twait_block->vtag_block[i].rport == rport)) {
found = 1;
break;
}
}
if (found)
break;
}
SCTP_INP_INFO_WUNLOCK();
return (found);
vtag_block->tv_sec_at_expire = time;
vtag_block->v_tag = tag;
vtag_block->lport = lport;
vtag_block->rport = rport;
}
void
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport)
static void
sctp_add_vtag_to_timewait(uint32_t tag, uint16_t lport, uint16_t rport)
{
struct sctpvtaghead *chain;
struct sctp_tagblock *twait_block;
struct timeval now;
int set, i;
uint32_t time;
int i;
bool set;
if (time == 0) {
/* Its disabled */
return;
}
SCTP_INP_INFO_WLOCK_ASSERT();
(void)SCTP_GETTIME_TIMEVAL(&now);
time = now.tv_sec + SCTP_BASE_SYSCTL(sctp_vtag_time_wait);
chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
set = 0;
set = false;
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
/* Block(s) present, lets find space, and expire on the fly */
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
if ((twait_block->vtag_block[i].v_tag == 0) &&
!set) {
twait_block->vtag_block[i].tv_sec_at_expire =
now.tv_sec + time;
twait_block->vtag_block[i].v_tag = tag;
twait_block->vtag_block[i].lport = lport;
twait_block->vtag_block[i].rport = rport;
set = 1;
} else if ((twait_block->vtag_block[i].v_tag) &&
((long)twait_block->vtag_block[i].tv_sec_at_expire < now.tv_sec)) {
/* Audit expires this guy */
twait_block->vtag_block[i].tv_sec_at_expire = 0;
twait_block->vtag_block[i].v_tag = 0;
twait_block->vtag_block[i].lport = 0;
twait_block->vtag_block[i].rport = 0;
if (set == 0) {
/* Reuse it for my new tag */
twait_block->vtag_block[i].tv_sec_at_expire = now.tv_sec + time;
twait_block->vtag_block[i].v_tag = tag;
twait_block->vtag_block[i].lport = lport;
twait_block->vtag_block[i].rport = rport;
set = 1;
if ((twait_block->vtag_block[i].v_tag == 0) && !set) {
sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport);
set = true;
continue;
}
if ((twait_block->vtag_block[i].v_tag != 0) &&
(twait_block->vtag_block[i].tv_sec_at_expire < (uint32_t)now.tv_sec)) {
if (set) {
/* Audit expires this guy */
sctp_set_vtag_block(twait_block->vtag_block + i, 0, 0, 0, 0);
} else {
/* Reuse it for the new tag */
sctp_set_vtag_block(twait_block->vtag_block + i, time, tag, lport, rport);
set = true;
}
}
}
@ -4610,10 +4581,7 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
}
memset(twait_block, 0, sizeof(struct sctp_tagblock));
LIST_INSERT_HEAD(chain, twait_block, sctp_nxt_tagblock);
twait_block->vtag_block[0].tv_sec_at_expire = now.tv_sec + time;
twait_block->vtag_block[0].v_tag = tag;
twait_block->vtag_block[0].lport = lport;
twait_block->vtag_block[0].rport = rport;
sctp_set_vtag_block(twait_block->vtag_block, time, tag, lport, rport);
}
}
@ -4906,8 +4874,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
/* pull from vtag hash */
LIST_REMOVE(stcb, sctp_asocs);
sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_BASE_SYSCTL(sctp_vtag_time_wait),
inp->sctp_lport, stcb->rport);
sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport);
/*
* Now restop the timers to be sure this is paranoia at is finest!
@ -6697,24 +6664,15 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
}
}
int
bool
sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now)
{
/*
* This function serves two purposes. It will see if a TAG can be
* re-used and return 1 for yes it is ok and 0 for don't use that
* tag. A secondary function it will do is purge out old tags that
* can be removed.
*/
struct sctpvtaghead *chain;
struct sctp_tagblock *twait_block;
struct sctpasochead *head;
struct sctp_tcb *stcb;
int i;
bool result;
SCTP_INP_INFO_RLOCK();
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag,
SCTP_BASE_INFO(hashasocmark))];
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))];
LIST_FOREACH(stcb, head, sctp_asocs) {
/*
* We choose not to lock anything here. TCB's can't be
@ -6733,40 +6691,15 @@ sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *
if (stcb->sctp_ep->sctp_lport != lport) {
continue;
}
/* Its a used tag set */
SCTP_INP_INFO_RUNLOCK();
return (0);
}
}
chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
/* Now what about timed wait ? */
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
/*
* Block(s) are present, lets see if we have this tag in the
* list
*/
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
if (twait_block->vtag_block[i].v_tag == 0) {
/* not used */
continue;
} else if ((long)twait_block->vtag_block[i].tv_sec_at_expire <
now->tv_sec) {
/* Audit expires this guy */
twait_block->vtag_block[i].tv_sec_at_expire = 0;
twait_block->vtag_block[i].v_tag = 0;
twait_block->vtag_block[i].lport = 0;
twait_block->vtag_block[i].rport = 0;
} else if ((twait_block->vtag_block[i].v_tag == tag) &&
(twait_block->vtag_block[i].lport == lport) &&
(twait_block->vtag_block[i].rport == rport)) {
/* Bad tag, sorry :< */
SCTP_INP_INFO_RUNLOCK();
return (0);
}
/* The tag is currently used, so don't use it. */
result = false;
goto out;
}
}
result = !sctp_is_in_timewait(tag, lport, rport, (uint32_t)now->tv_sec);
out:
SCTP_INP_INFO_RUNLOCK();
return (1);
return (result);
}
static void

View file

@ -580,13 +580,6 @@ sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int);
void sctp_delete_from_timewait(uint32_t, uint16_t, uint16_t);
int sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport);
void
sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport);
void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);
void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);
@ -612,7 +605,8 @@ int
sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *,
struct sctp_nets *);
int sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *);
bool
sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *);
/* void sctp_drain(void); */