From patchwork Mon May 14 14:23:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Kiselev X-Patchwork-Id: 40008 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B17471C8A2; Mon, 14 May 2018 16:23:51 +0200 (CEST) Received: from mail-lf0-f65.google.com (mail-lf0-f65.google.com [209.85.215.65]) by dpdk.org (Postfix) with ESMTP id B989C1C89C for ; Mon, 14 May 2018 16:23:50 +0200 (CEST) Received: by mail-lf0-f65.google.com with SMTP id n18-v6so11838935lfh.10 for ; Mon, 14 May 2018 07:23:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:message-id:to:subject:mime-version :content-transfer-encoding; bh=0qYcFlEUqeHXtkXpRTQ/HC4p3cJCNx5p5+rXI5npE3o=; b=ALJO6P9g++5ByJ1ck0yS4KC1aafzbAcTxKUz6KF0sb5Q1g+bSoxvcUY4vsoLokXEDB go5SbatkX8Xc7KdRyEiEA2825ukbdZ3NEN97S0pAYgZSE98C2PyZhyVJdRuINlD+rzr4 f1Lik05Bs4e+QsIXmok+/7oy9dZ91Bv4H/30QRoAuHTQSMH8aCUk3XrkGQlHy16H5iid ym/SiKkYxbMIYa/xcclRU+GJYV73gEH3nKr7cR2LkRaaZlCepL9zWWEF6nMaAe7J+jnK JBQW/MlA/7NM7kWbKLkVXZFIQcN+RZMXlN3t4a1hf/SQKcI7TQnK1KZcarTC4bVDE3DU pIUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:message-id:to:subject:mime-version :content-transfer-encoding; bh=0qYcFlEUqeHXtkXpRTQ/HC4p3cJCNx5p5+rXI5npE3o=; b=Uzdn1jKzZbdP5g3mZZCHg4WkYyGtgo3uECLqkxFpgkZ7tmHe6GXK5BjHYp404sVIh1 tpgFTCdNFpSttYm346o2i3WliZ2aJP8JdN6nVWixLLu+8fPvWxd1vsqc2E9Zz/p8ke0k Bb3MqDZI7FGfx594Q3n35welh0vYbL15YiokvKqz7V81NDEGutHu24cyepD05xJJvE/H RexqEu+UnQqfx9p3aBOLVj7ZdNOxL3TZ3LZEd2nHLcHNlX05/dIyy3f5xtOCqYnz9S2c Y4tiohWdKFXz0ef4b0yfQ+iarVQ2fTCA54ZWfNes7z3NWJAtBnHKJbq/uZFCiGscLTfP DTYg== X-Gm-Message-State: ALKqPwdssvBEhIGJNADjmPI3LuM8v5OwBloyAsGVI5dWwgVIVNUN89ho 38NbespYaDUtimgzaKk7FSSfXXQO X-Google-Smtp-Source: AB8JxZovqNbk3qSBJtdW5bcPp3bmBgEOKKUeTsXHjVdFyN4pETtSruyN+JMB/WSi/ipu6xkvUmKn6Q== X-Received: by 2002:a2e:7213:: with SMTP id n19-v6mr4691435ljc.71.1526307829890; Mon, 14 May 2018 07:23:49 -0700 (PDT) Received: from al ([2001:470:1f0b:1460:a17e:62ec:4af:cc43]) by smtp.gmail.com with ESMTPSA id d73-v6sm2415718lfd.50.2018.05.14.07.23.48 for (version=TLS1_1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 May 2018 07:23:49 -0700 (PDT) Date: Mon, 14 May 2018 17:23:45 +0300 From: Alex Kiselev Message-ID: <2310632874.20180514172345@gmail.com> To: dev@dpdk.org MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH] librte_ip_frag: mbuf count, expiration X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Hi. This patch adds two features to the librte_ip_frag library: 1) it keeps track of number of mbufs holded in the fragmentation table. rte_frag_table_mbuf_count() There might be situations (kind of attack when a lot of fragmented packets are sent to a dpdk application in order to flood the fragmentation table) when no additional mbufs must be added to the fragmentations table since it already contains to many of them. Currently there is no way to determine the number of mbufs holded int the fragmentation table. 2) Fragmented packets are supposed to live no longer than max_cycles, but the lib deletes an expired packet only occasionally when it scans a bucket to find an empty slot when adding a new packet. Therefore a fragment might sit in the table forever. This patch add rte_frag_table_del_expired_entries() that scans list recently used packets and delete the expired ones. --- lib/librte_ip_frag/ip_frag_common.h | 30 +++++++++++++++---- lib/librte_ip_frag/ip_frag_internal.c | 31 +++++++------------- lib/librte_ip_frag/rte_ip_frag.h | 31 +++++++++++++++++++- lib/librte_ip_frag/rte_ip_frag_common.c | 50 ++++++++++++++++++++++++++++++++ lib/librte_ip_frag/rte_ipv4_reassembly.c | 2 +- lib/librte_ip_frag/rte_ipv6_reassembly.c | 2 +- 6 files changed, 116 insertions(+), 30 deletions(-) diff --git a/lib/librte_ip_frag/ip_frag_common.h b/lib/librte_ip_frag/ip_frag_common.h index 9f56196..fdc2085 100644 --- a/lib/librte_ip_frag/ip_frag_common.h +++ b/lib/librte_ip_frag/ip_frag_common.h @@ -43,6 +43,12 @@ #define IP_FRAG_LOG(lvl, fmt, args...) do {} while(0) #endif /* IP_FRAG_DEBUG */ +#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 */ + #define IPV4_KEYLEN 1 #define IPV6_KEYLEN 4 @@ -55,9 +61,9 @@ "%08" PRIx64 "%08" PRIx64 "%08" PRIx64 "%08" PRIx64 /* 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, - uint16_t ofs, uint16_t len, uint16_t more_frags); +struct rte_mbuf * ip_frag_process(struct rte_ip_frag_tbl *tbl, + struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, + struct rte_mbuf *mb, uint16_t ofs, uint16_t len, uint16_t more_frags); struct ip_frag_pkt * ip_frag_find(struct rte_ip_frag_tbl *tbl, struct rte_ip_frag_death_row *dr, @@ -71,8 +77,6 @@ struct ip_frag_pkt * ip_frag_lookup(struct rte_ip_frag_tbl *tbl, struct rte_mbuf *ipv4_frag_reassemble(struct ip_frag_pkt *fp); struct rte_mbuf *ipv6_frag_reassemble(struct ip_frag_pkt *fp); - - /* * misc frag key functions */ @@ -114,7 +118,8 @@ ip_frag_key_cmp(const struct ip_frag_key * k1, const struct ip_frag_key * k2) /* put fragment on death row */ static inline void -ip_frag_free(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr) +ip_frag_free(struct rte_ip_frag_tbl *tbl, struct ip_frag_pkt *fp, + struct rte_ip_frag_death_row *dr) { uint32_t i, k; @@ -123,6 +128,7 @@ ip_frag_free(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr) if (fp->frags[i].mb != NULL) { dr->row[k++] = fp->frags[i].mb; fp->frags[i].mb = NULL; + tbl->nb_mbufs --; } } @@ -178,4 +184,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(tbl, 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 46c44ff..7cdcdfc 100644 --- a/lib/librte_ip_frag/ip_frag_internal.c +++ b/lib/librte_ip_frag/ip_frag_internal.c @@ -43,23 +43,7 @@ #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, @@ -76,7 +60,7 @@ static inline void ip_frag_tbl_reuse(struct rte_ip_frag_tbl *tbl, struct rte_ip_frag_death_row *dr, struct ip_frag_pkt *fp, uint64_t tms) { - ip_frag_free(fp, dr); + ip_frag_free(tbl, fp, dr); ip_frag_reset(fp, tms); TAILQ_REMOVE(&tbl->lru, fp, lru); TAILQ_INSERT_TAIL(&tbl->lru, fp, lru); @@ -135,8 +119,9 @@ ipv6_frag_hash(const struct ip_frag_key *key, uint32_t *v1, uint32_t *v2) } struct rte_mbuf * -ip_frag_process(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, - struct rte_mbuf *mb, uint16_t ofs, uint16_t len, uint16_t more_frags) +ip_frag_process(struct rte_ip_frag_tbl *tbl, struct ip_frag_pkt *fp, + struct rte_ip_frag_death_row *dr, struct rte_mbuf *mb, uint16_t ofs, + uint16_t len, uint16_t more_frags) { uint32_t idx; @@ -194,7 +179,7 @@ ip_frag_process(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, fp->frags[IP_LAST_FRAG_IDX].len); /* free all fragments, invalidate the entry. */ - ip_frag_free(fp, dr); + ip_frag_free(tbl, fp, dr); ip_frag_key_invalidate(&fp->key); IP_FRAG_MBUF2DR(dr, mb); @@ -204,6 +189,7 @@ ip_frag_process(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, fp->frags[idx].ofs = ofs; fp->frags[idx].len = len; fp->frags[idx].mb = mb; + tbl->nb_mbufs++; mb = NULL; @@ -252,7 +238,10 @@ ip_frag_process(struct ip_frag_pkt *fp, struct rte_ip_frag_death_row *dr, fp->frags[IP_LAST_FRAG_IDX].len); /* free associated resources. */ - ip_frag_free(fp, dr); + ip_frag_free(tbl, fp, dr); + } + else { + tbl->nb_mbufs -= fp->last_idx; } /* we are done with that entry, invalidate it. */ diff --git a/lib/librte_ip_frag/rte_ip_frag.h b/lib/librte_ip_frag/rte_ip_frag.h index 0144164..bc6becd 100644 --- a/lib/librte_ip_frag/rte_ip_frag.h +++ b/lib/librte_ip_frag/rte_ip_frag.h @@ -94,10 +94,12 @@ struct ip_frag_pkt { #define IP_FRAG_DEATH_ROW_LEN 32 /**< death row size (in packets) */ +#define IP_FRAG_DEATH_ROW_MBUF_LEN (IP_FRAG_DEATH_ROW_LEN * (IP_MAX_FRAG_NUM + 1)) + /** mbuf death row (packets to be freed) */ struct rte_ip_frag_death_row { uint32_t cnt; /**< number of mbufs currently on death row */ - struct rte_mbuf *row[IP_FRAG_DEATH_ROW_LEN * (IP_MAX_FRAG_NUM + 1)]; + struct rte_mbuf *row[IP_FRAG_DEATH_ROW_MBUF_LEN]; /**< mbufs to be freed */ }; @@ -122,6 +124,7 @@ struct rte_ip_frag_tbl { uint32_t bucket_entries; /**< hash associativity. */ uint32_t nb_entries; /**< total size of the table. */ uint32_t nb_buckets; /**< num of associativity lines. */ + uint32_t nb_mbufs; /**< num of mbufs holded in the tbl. */ struct ip_frag_pkt *last; /**< last used entry. */ struct ip_pkt_list lru; /**< LRU list for table entries. */ struct ip_frag_tbl_stat stat; /**< statistics counters. */ @@ -354,6 +357,32 @@ void rte_ip_frag_free_death_row(struct rte_ip_frag_death_row *dr, void rte_ip_frag_table_statistics_dump(FILE * f, const struct rte_ip_frag_tbl *tbl); +/** + * Number of mbufs holded in the fragmentation table. + * + * @param tbl + * Fragmentation table + * + * @return + * Number of mbufs holded in the fragmentation table. + */ +static inline uint32_t +rte_frag_table_mbuf_count(const struct rte_ip_frag_tbl *tbl) +{ + return tbl->nb_mbufs; +} + +/* + */ +void +rte_frag_table_del_expired_entries(struct rte_ip_frag_tbl *tbl, + struct rte_ip_frag_death_row *dr, uint64_t tms); + +#ifdef RTE_IP_FRAG_DEBUG +void +rte_frag_table_print(struct rte_ip_frag_tbl *tbl); +#endif /* RTE_IP_FRAG_DEBUG */ + #ifdef __cplusplus } #endif diff --git a/lib/librte_ip_frag/rte_ip_frag_common.c b/lib/librte_ip_frag/rte_ip_frag_common.c index 8460f8e..b9a67f4 100644 --- a/lib/librte_ip_frag/rte_ip_frag_common.c +++ b/lib/librte_ip_frag/rte_ip_frag_common.c @@ -104,6 +104,7 @@ rte_ip_frag_table_create(uint32_t bucket_num, uint32_t bucket_entries, tbl->nb_buckets = bucket_num; tbl->bucket_entries = bucket_entries; tbl->entry_mask = (tbl->nb_entries - 1) & ~(tbl->bucket_entries - 1); + tbl->nb_mbufs = 0; TAILQ_INIT(&(tbl->lru)); return tbl; @@ -150,3 +151,52 @@ rte_ip_frag_table_statistics_dump(FILE *f, const struct rte_ip_frag_tbl *tbl) fail_nospace, fail_total - fail_nospace); } + +/* + * + */ +void +rte_frag_table_del_expired_entries(struct rte_ip_frag_tbl *tbl, + struct rte_ip_frag_death_row *dr, uint64_t tms) +{ + uint64_t max_cycles; + struct ip_frag_pkt *fp; + + max_cycles = tbl->max_cycles; + + TAILQ_FOREACH(fp, &tbl->lru, lru) + if (max_cycles + fp->start < tms) { + /* check that death row has enough space */ + if (IP_FRAG_DEATH_ROW_MBUF_LEN - dr->cnt >= fp->last_idx) + ip_frag_tbl_del(tbl, dr, fp); + else + return; + } + else { + return; + } +} + +#ifdef RTE_IP_FRAG_DEBUG + +void +rte_frag_table_print(struct rte_ip_frag_tbl *tbl) +{ + uint32_t i, cnt; + printf("entries in use: %u, mbuf holded %u\n", tbl->use_entries, + tbl->nb_mbufs); + struct ip_frag_pkt *fp; + TAILQ_FOREACH(fp, &tbl->lru, lru) + if (!ip_frag_key_is_empty(&fp->key)) { + + /* cnt mbufs in the packet */ + cnt = 0; + for (i=0; i!=fp->last_idx; i++) + if (fp->frags[i].mb != NULL) + cnt++; + + printf("start %"PRIu64", mbuf cnt %u\n", fp->start, cnt); + } +} + +#endif /* RTE_IP_FRAG_DEBUG */ \ No newline at end of file diff --git a/lib/librte_ip_frag/rte_ipv4_reassembly.c b/lib/librte_ip_frag/rte_ipv4_reassembly.c index 040bd70..4bb0dce 100644 --- a/lib/librte_ip_frag/rte_ipv4_reassembly.c +++ b/lib/librte_ip_frag/rte_ipv4_reassembly.c @@ -173,7 +173,7 @@ rte_ipv4_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl, /* process the fragmented packet. */ - mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len, ip_flag); + mb = ip_frag_process(tbl, fp, dr, mb, ip_ofs, ip_len, ip_flag); ip_frag_inuse(tbl, fp); IP_FRAG_LOG(DEBUG, "%s:%d:\n" diff --git a/lib/librte_ip_frag/rte_ipv6_reassembly.c b/lib/librte_ip_frag/rte_ipv6_reassembly.c index dde58cb..b374d39 100644 --- a/lib/librte_ip_frag/rte_ipv6_reassembly.c +++ b/lib/librte_ip_frag/rte_ipv6_reassembly.c @@ -213,7 +213,7 @@ rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl, /* process the fragmented packet. */ - mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len, + mb = ip_frag_process(tbl, fp, dr, mb, ip_ofs, ip_len, MORE_FRAGS(frag_hdr->frag_data)); ip_frag_inuse(tbl, fp);