From 58a7bf124cc2b20e069bb89f2fd9ea5c1b7049c2 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Thu, 9 Sep 2021 01:18:58 +0200 Subject: [PATCH] sctp: cleanup timewait handling for vtags MFC after: 1 week --- sys/netinet/sctp_pcb.c | 161 ++++++++++++----------------------------- sys/netinet/sctp_pcb.h | 10 +-- 2 files changed, 49 insertions(+), 122 deletions(-) diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index ee5308ff6192..82b7157c7ad7 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -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 diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index f93e8f11b3e4..a3d0b489eb82 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -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); */