Function rte_ip_frag_sweep_table() enables callers to incrementally sweep IP frament tables for incomplete, expired fragments.
rte_ip_frag_sweep_table() is needed to identify never-to-be-completed fragments during DDoS attacks. Signed-off-by: Qiaobin Fu <qiaob...@bu.edu> Reviewed-by: Cody Doucette <douce...@bu.edu> Reviewed-by: Michel Machado <mic...@digirati.com.br> --- lib/librte_ip_frag/ip_frag_common.h | 18 +++++++++++++++++ lib/librte_ip_frag/ip_frag_internal.c | 18 ----------------- lib/librte_ip_frag/rte_ip_frag.h | 17 ++++++++++++++++ lib/librte_ip_frag/rte_ip_frag_common.c | 26 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/lib/librte_ip_frag/ip_frag_common.h b/lib/librte_ip_frag/ip_frag_common.h index 197acf8d8..ef869182d 100644 --- a/lib/librte_ip_frag/ip_frag_common.h +++ b/lib/librte_ip_frag/ip_frag_common.h @@ -25,6 +25,12 @@ #define IPv6_KEY_BYTES_FMT \ "%08" PRIx64 "%08" PRIx64 "%08" PRIx64 "%08" PRIx64 +#ifdef RTE_LIBRTE_IP_FRAG_TBL_STAT +#define IP_FRAG_TBL_STAT_UPDATE(s, f, v) ((s)->f += (v)) +#else +#define IP_FRAG_TBL_STAT_UPDATE(s, f, v) do {} while (0) +#endif /* IP_FRAG_TBL_STAT */ + /* internal functions declarations */ struct rte_mbuf * ip_frag_process(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, struct rte_mbuf *mb, @@ -149,4 +155,16 @@ ip_frag_reset(struct ip_frag_pkt *fp, uint64_t tms) fp->frags[IP_FIRST_FRAG_IDX] = zero_frag; } +/* frag table helper functions */ +static inline void +ip_frag_tbl_del(struct rte_ip_frag_tbl *tbl, struct rte_ip_frag_death_row *dr, + struct ip_frag_pkt *fp) +{ + ip_frag_free(fp, dr); + ip_frag_key_invalidate(&fp->key); + TAILQ_REMOVE(&tbl->lru, fp, lru); + tbl->use_entries--; + IP_FRAG_TBL_STAT_UPDATE(&tbl->stat, del_num, 1); +} + #endif /* _IP_FRAG_COMMON_H_ */ diff --git a/lib/librte_ip_frag/ip_frag_internal.c b/lib/librte_ip_frag/ip_frag_internal.c index 2560c7713..97470a872 100644 --- a/lib/librte_ip_frag/ip_frag_internal.c +++ b/lib/librte_ip_frag/ip_frag_internal.c @@ -14,24 +14,6 @@ #define IP_FRAG_TBL_POS(tbl, sig) \ ((tbl)->pkt + ((sig) & (tbl)->entry_mask)) -#ifdef RTE_LIBRTE_IP_FRAG_TBL_STAT -#define IP_FRAG_TBL_STAT_UPDATE(s, f, v) ((s)->f += (v)) -#else -#define IP_FRAG_TBL_STAT_UPDATE(s, f, v) do {} while (0) -#endif /* IP_FRAG_TBL_STAT */ - -/* local frag table helper functions */ -static inline void -ip_frag_tbl_del(struct rte_ip_frag_tbl *tbl, struct rte_ip_frag_death_row *dr, - struct ip_frag_pkt *fp) -{ - ip_frag_free(fp, dr); - ip_frag_key_invalidate(&fp->key); - TAILQ_REMOVE(&tbl->lru, fp, lru); - tbl->use_entries--; - IP_FRAG_TBL_STAT_UPDATE(&tbl->stat, del_num, 1); -} - static inline void ip_frag_tbl_add(struct rte_ip_frag_tbl *tbl, struct ip_frag_pkt *fp, const struct ip_frag_key *key, uint64_t tms) diff --git a/lib/librte_ip_frag/rte_ip_frag.h b/lib/librte_ip_frag/rte_ip_frag.h index b3f3f78df..79443096c 100644 --- a/lib/librte_ip_frag/rte_ip_frag.h +++ b/lib/librte_ip_frag/rte_ip_frag.h @@ -146,6 +146,23 @@ struct rte_ip_frag_tbl * rte_ip_frag_table_create(uint32_t bucket_num, uint32_t bucket_entries, uint32_t max_entries, uint64_t max_cycles, int socket_id); +/** + * Sweep the IP fragmentation table for expired segments. + * + * @param tbl + * Fragmentation table to sweep. + * @param dr + * Death row to free buffers to + * @param next + * Pointer to the bucket iterator. + * Should be 0 to start sweeping the fragmentation table. + * Bucket iterator is incremented after each call of this function. + * @return + * 0 if successful. -EINVAL if the parameters are invalid. + */ +int rte_ip_frag_sweep_table(struct rte_ip_frag_tbl *tbl, + struct rte_ip_frag_death_row *dr, uint32_t *next); + /** * Free allocated IP fragmentation table. * diff --git a/lib/librte_ip_frag/rte_ip_frag_common.c b/lib/librte_ip_frag/rte_ip_frag_common.c index 659a17951..53325ddae 100644 --- a/lib/librte_ip_frag/rte_ip_frag_common.c +++ b/lib/librte_ip_frag/rte_ip_frag_common.c @@ -7,6 +7,7 @@ #include <rte_memory.h> #include <rte_log.h> +#include <rte_cycles.h> #include "ip_frag_common.h" @@ -93,6 +94,31 @@ rte_ip_frag_table_destroy(struct rte_ip_frag_tbl *tbl) rte_free(tbl); } +/* Sweep the IP fragmentation table. */ +int +rte_ip_frag_sweep_table(struct rte_ip_frag_tbl *tbl, + struct rte_ip_frag_death_row *dr, uint32_t *next) +{ + uint32_t i; + uint64_t cur_tsc = rte_rdtsc(); + struct ip_frag_pkt *pkt; + + if (tbl == NULL || dr == NULL || next == NULL || + (*next * tbl->bucket_entries >= tbl->nb_entries)) + return -EINVAL; + + pkt = tbl->pkt + *next * tbl->bucket_entries; + for (i = 0; i < tbl->bucket_entries; i++) { + if (tbl->max_cycles + pkt[i].start < cur_tsc) + ip_frag_tbl_del(tbl, dr, pkt + i); + } + + *next = (*next + 1) * tbl->bucket_entries >= tbl->nb_entries ? + 0 : *next + 1; + + return 0; +} + /* dump frag table statistics to file */ void rte_ip_frag_table_statistics_dump(FILE *f, const struct rte_ip_frag_tbl *tbl) -- 2.17.1