From e4380f4866091fd92a7a57667dd938a99144f9cd Mon Sep 17 00:00:00 2001 From: Jielong Zhou Date: Tue, 2 Jul 2019 20:53:44 +0800 Subject: l4p/tcp: fix removing overlapped data rte_pktmbuf_adj and rte_pktmbuf_trim don't support removing data more than one segment. We reimplemented these funtions to support removing multiple segments. Change-Id: I3e2d48310595ecae0acef0674ea2c78fa1068c5b Signed-off-by: Jielong Zhou Signed-off-by: Konstantin Ananyev --- lib/libtle_l4p/misc.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++ lib/libtle_l4p/tcp_ofo.h | 2 +- lib/libtle_l4p/tcp_rxtx.c | 10 ++--- 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/lib/libtle_l4p/misc.h b/lib/libtle_l4p/misc.h index 8be5dfe..327296f 100644 --- a/lib/libtle_l4p/misc.h +++ b/lib/libtle_l4p/misc.h @@ -510,6 +510,106 @@ _iovec_to_mbsegs(struct iovec *iv, uint32_t seglen, struct rte_mbuf *mb[], return i; } +/** + * Remove len bytes at the beginning of an mbuf. + * + * It's an enhancement version of rte_pktmbuf_abj which not support + * adjusting length greater than the length of the first segment. + * + * Returns a pointer to the new mbuf. If the + * length is greater than the total length of the mbuf, then the + * function will fail and return NULL, without modifying the mbuf. + * + * @param m + * The packet mbuf. + * @param len + * The amount of data to remove (in bytes). + * @return + * A pointer to the new start of the data. + */ +static inline struct rte_mbuf * +_rte_pktmbuf_adj(struct rte_mbuf *m, uint32_t len) +{ + struct rte_mbuf *next; + uint32_t remain, plen; + uint16_t segs; + + if (unlikely(len > m->pkt_len)) + return NULL; + + plen = m->pkt_len; + remain = len; + segs = m->nb_segs; + /* don't free last segment */ + while (remain >= m->data_len && m->next) { + next = m->next; + remain -= m->data_len; + segs--; + rte_pktmbuf_free_seg(m); + m = next; + } + + if (remain) { + m->data_len = (uint16_t)(m->data_len - remain); + m->data_off = (uint16_t)(m->data_off + remain); + } + + m->pkt_len = plen - len; + m->nb_segs = segs; + return m; +} + +/** + * Remove len bytes of data at the end of the mbuf. + * + * It's an enhancement version of rte_pktmbuf_trim, which not support + * removing length greater than the length of the last segment. + * + * @param m + * The packet mbuf. + * @param len + * The amount of data to remove (in bytes). + * @return + * - 0: On success. + * - -1: On error. + */ +static inline int +_rte_pktmbuf_trim(struct rte_mbuf *m, uint32_t len) +{ + struct rte_mbuf *last, *next, *tmp; + uint32_t remain; + uint16_t segs; + + if (unlikely(len > m->pkt_len)) + return -1; + + tmp = m; + /* find the last segment will remain after trim */ + remain = m->pkt_len - len; + while (remain > tmp->data_len) { + remain -= tmp->data_len; + tmp = tmp->next; + } + + /* trim the remained last segment */ + tmp->data_len = remain; + + /* remove trimmed segments */ + segs = m->nb_segs; + last = tmp; + for (tmp = tmp->next; tmp != NULL; tmp = next) { + next = tmp->next; + rte_pktmbuf_free_seg(tmp); + segs--; + } + + last->next = NULL; + m->pkt_len -= len; + m->nb_segs = segs; + + return 0; +} + #ifdef __cplusplus } #endif diff --git a/lib/libtle_l4p/tcp_ofo.h b/lib/libtle_l4p/tcp_ofo.h index 3da388e..9d88266 100644 --- a/lib/libtle_l4p/tcp_ofo.h +++ b/lib/libtle_l4p/tcp_ofo.h @@ -276,7 +276,7 @@ _ofodb_enqueue(struct rte_ring *r, const struct ofodb *db, uint32_t *seq) pkt = db->obj[++i]; } else { /* pkt is partly overlapped */ - rte_pktmbuf_adj(pkt, *seq - begin); + db->obj[i] = _rte_pktmbuf_adj(pkt, *seq - begin); break; } } diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c index d1d2a16..a519645 100644 --- a/lib/libtle_l4p/tcp_rxtx.c +++ b/lib/libtle_l4p/tcp_rxtx.c @@ -973,7 +973,7 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st, } static inline int -data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen, +data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf **mb, uint32_t hlen, uint32_t *seqn, uint32_t *plen) { uint32_t len, n, seq; @@ -981,7 +981,7 @@ data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen, seq = *seqn; len = *plen; - rte_pktmbuf_adj(mb, hlen); + rte_pktmbuf_adj(*mb, hlen); if (len == 0) return -ENODATA; /* cut off the start of the packet */ @@ -990,7 +990,7 @@ data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen, if (n >= len) return -ENODATA; - rte_pktmbuf_adj(mb, n); + *mb = _rte_pktmbuf_adj(*mb, n); *seqn = seq + n; *plen = len - n; } @@ -1097,7 +1097,7 @@ rx_fin(struct tle_tcp_stream *s, uint32_t state, if (plen != 0) { - ret = data_pkt_adjust(&s->tcb, mb, hlen, &seq, &plen); + ret = data_pkt_adjust(&s->tcb, &mb, hlen, &seq, &plen); if (ret != 0) return ret; if (rx_data_enqueue(s, seq, plen, &mb, 1) != 1) @@ -1303,7 +1303,7 @@ rx_data_ack(struct tle_tcp_stream *s, struct dack_info *tack, if (ret == 0) { /* skip duplicate data, if any */ - ret = data_pkt_adjust(&s->tcb, mb[i], hlen, + ret = data_pkt_adjust(&s->tcb, &mb[i], hlen, &seq, &plen); } -- cgit 1.2.3-korg