aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJielong Zhou <jielong.zjl@antfin.com>2019-07-02 20:53:44 +0800
committerKonstantin Ananyev <konstantin.ananyev@intel.com>2019-08-13 13:27:56 +0100
commite4380f4866091fd92a7a57667dd938a99144f9cd (patch)
tree817010bea3e2cae296298d049b5224598e81c856
parent17f6b7ad23f52784f0a6897480d7a6050806aa65 (diff)
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 <jielong.zjl@antfin.com> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
-rw-r--r--lib/libtle_l4p/misc.h100
-rw-r--r--lib/libtle_l4p/tcp_ofo.h2
-rw-r--r--lib/libtle_l4p/tcp_rxtx.c10
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);
}