diff mbox series

[ovs-dev,RFC,v6,05/11] dp-packet: Handle multi-seg mbufs in helper funcs.

Message ID 1526491963-45108-6-git-send-email-tiago.lam@intel.com
State Changes Requested
Delegated to: Ian Stokes
Headers show
Series Support multi-segment mbufs | expand

Commit Message

Lam, Tiago May 16, 2018, 5:32 p.m. UTC
Most helper functions in dp-packet assume that the data held by a
dp_packet is contiguous, and perform operations such as pointer
arithmetic under that assumption. However, with the introduction of
multi-segment mbufs, where data is non-contiguous, such assumptions are
no longer possible. Some examples of Such helper functions are
dp_packet_tail(), dp_packet_tailroom(), dp_packet_end(),
dp_packet_get_allocated() and dp_packet_at().

Thus, instead of assuming contiguous data in dp_packet, they  now
iterate over the (non-contiguous) data in mbufs to perform their
calculations.

Co-authored-by: Mark Kavanagh <mark.b.kavanagh@intel.com>

Signed-off-by: Mark Kavanagh <mark.b.kavanagh@intel.com>
Signed-off-by: Tiago Lam <tiago.lam@intel.com>
---
 lib/dp-packet.h | 235 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 188 insertions(+), 47 deletions(-)
diff mbox series

Patch

diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index 0bc367a..35ee6df 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -133,6 +133,8 @@  static inline void *dp_packet_at(const struct dp_packet *, size_t offset,
                                  size_t size);
 static inline void *dp_packet_at_assert(const struct dp_packet *,
                                         size_t offset, size_t size);
+static inline void * dp_packet_at_offset(const struct dp_packet *b,
+                                         size_t offset);
 static inline void *dp_packet_tail(const struct dp_packet *);
 static inline void *dp_packet_end(const struct dp_packet *);
 
@@ -180,40 +182,6 @@  dp_packet_delete(struct dp_packet *b)
     }
 }
 
-/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
- * byte 'offset'.  Otherwise, returns a null pointer. */
-static inline void *
-dp_packet_at(const struct dp_packet *b, size_t offset, size_t size)
-{
-    return offset + size <= dp_packet_size(b)
-           ? (char *) dp_packet_data(b) + offset
-           : NULL;
-}
-
-/* Returns a pointer to byte 'offset' in 'b', which must contain at least
- * 'offset + size' bytes of data. */
-static inline void *
-dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size)
-{
-    ovs_assert(offset + size <= dp_packet_size(b));
-    return ((char *) dp_packet_data(b)) + offset;
-}
-
-/* Returns a pointer to byte following the last byte of data in use in 'b'. */
-static inline void *
-dp_packet_tail(const struct dp_packet *b)
-{
-    return (char *) dp_packet_data(b) + dp_packet_size(b);
-}
-
-/* Returns a pointer to byte following the last byte allocated for use (but
- * not necessarily in use) in 'b'. */
-static inline void *
-dp_packet_end(const struct dp_packet *b)
-{
-    return (char *) dp_packet_base(b) + dp_packet_get_allocated(b);
-}
-
 /* Returns the number of bytes of headroom in 'b', that is, the number of bytes
  * of unused space in dp_packet 'b' before the data that is in use.  (Most
  * commonly, the data in a dp_packet is at its beginning, and thus the
@@ -224,12 +192,50 @@  dp_packet_headroom(const struct dp_packet *b)
     return (char *) dp_packet_data(b) - (char *) dp_packet_base(b);
 }
 
+#ifdef DPDK_NETDEV
+static inline struct rte_mbuf *
+dp_packet_mbuf_tail(const struct dp_packet *b)
+{
+    struct rte_mbuf *buf = CONST_CAST(struct rte_mbuf *, &b->mbuf);
+    if (b->source == DPBUF_DPDK) {
+
+        /* Find last segment where data ends, meaning the tail of the chained
+           mbufs is there */
+        while (buf) {
+            if (rte_pktmbuf_mtod(buf, char *) + buf->buf_len !=
+                rte_pktmbuf_mtod_offset(buf, char *, buf->data_len)) {
+                break;
+            }
+
+            buf = buf->next;
+        }
+
+        return buf;
+    } else {
+        return buf;
+    }
+}
+#endif
+
 /* Returns the number of bytes that may be appended to the tail end of
  * dp_packet 'b' before the dp_packet must be reallocated. */
 static inline size_t
 dp_packet_tailroom(const struct dp_packet *b)
 {
+#ifdef DPDK_NETDEV
+    struct rte_mbuf *mbuf = dp_packet_mbuf_tail(b);
+
+    size_t tailroom = 0;
+    while (mbuf) {
+        tailroom += rte_pktmbuf_tailroom(mbuf);
+
+        mbuf = mbuf->next;
+    }
+
+    return tailroom;
+#else
     return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b);
+#endif
 }
 
 /* Clears any data from 'b'. */
@@ -355,10 +361,37 @@  dp_packet_set_l4(struct dp_packet *b, void *l4)
 static inline size_t
 dp_packet_l4_size(const struct dp_packet *b)
 {
+#ifdef DPDK_NETDEV
+    if (b->l4_ofs == UINT16_MAX) {
+        return 0;
+    }
+
+    struct rte_mbuf *hmbuf = CONST_CAST(struct rte_mbuf *, &b->mbuf);
+    struct rte_mbuf *tmbuf = dp_packet_tail(b);
+
+    size_t l4_size = 0;
+    if (hmbuf == tmbuf) {
+        l4_size = hmbuf->data_len - b->l4_ofs;
+    } else {
+        l4_size = hmbuf->data_len - b->l4_ofs;
+        hmbuf = hmbuf->next;
+
+        while (hmbuf) {
+            l4_size += tmbuf->data_len;
+
+            hmbuf = hmbuf->next;
+        }
+    }
+
+    l4_size -= dp_packet_l2_pad_size(b);
+
+    return l4_size;
+#else
     return b->l4_ofs != UINT16_MAX
         ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b)
         - dp_packet_l2_pad_size(b)
         : 0;
+#endif
 }
 
 static inline const void *
@@ -485,7 +518,7 @@  __packet_set_data(struct dp_packet *b, uint16_t v)
 static inline uint16_t
 dp_packet_get_allocated(const struct dp_packet *b)
 {
-    return b->mbuf.buf_len;
+    return b->mbuf.nb_segs * b->mbuf.buf_len;
 }
 
 static inline void
@@ -493,7 +526,115 @@  dp_packet_set_allocated(struct dp_packet *b, uint16_t s)
 {
     b->mbuf.buf_len = s;
 }
+
+static inline void *
+dp_packet_at_offset(const struct dp_packet *b, size_t offset)
+{
+    if (b->source == DPBUF_DPDK) {
+        struct rte_mbuf *buf = CONST_CAST(struct rte_mbuf *, &b->mbuf);
+
+        while (buf && offset > buf->data_len) {
+            offset -= buf->data_len;
+
+            buf = buf->next;
+        }
+        return buf ? rte_pktmbuf_mtod_offset(buf, char *, offset) : NULL;
+    } else {
+        return (char *) dp_packet_data(b) + offset;
+    }
+}
+
+/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
+ * byte 'offset'.  Otherwise, returns a null pointer. */
+static inline void *
+dp_packet_at(const struct dp_packet *b, size_t offset, size_t size)
+{
+    return offset + size <= dp_packet_size(b)
+        ? dp_packet_at_offset(b, offset)
+        : NULL;
+}
+
+/* Returns a pointer to byte 'offset' in 'b', which must contain at least
+ * 'offset + size' bytes of data. */
+static inline void *
+dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size)
+{
+    ovs_assert(offset + size <= dp_packet_size(b));
+    return dp_packet_at_offset(b, offset);
+}
+
+/* Returns a pointer to byte following the last byte of data in use in 'b'. */
+static inline void *
+dp_packet_tail(const struct dp_packet *b)
+{
+    struct rte_mbuf *buf = CONST_CAST(struct rte_mbuf *, &b->mbuf);
+    if (b->source == DPBUF_DPDK) {
+
+        /* Find last segment where data ends, meaning the tail of the chained
+           mbufs is there */
+        while (buf) {
+            if (rte_pktmbuf_mtod(buf, char *) + buf->buf_len !=
+                rte_pktmbuf_mtod_offset(buf, char *, buf->data_len)) {
+                break;
+            }
+
+            buf = buf->next;
+        }
+    }
+
+    return rte_pktmbuf_mtod_offset(buf, void *, buf->data_len);
+}
+
+/* Returns a pointer to byte following the last byte allocated for use (but
+ * not necessarily in use) in 'b'. */
+static inline void *
+dp_packet_end(const struct dp_packet *b)
+{
+    if (b->source == DPBUF_DPDK) {
+        struct rte_mbuf *buf = CONST_CAST(struct rte_mbuf *, &(b->mbuf));
+
+        buf = rte_pktmbuf_lastseg(buf);
+
+        return rte_pktmbuf_mtod(buf, char *) + buf->buf_len;
+    } else {
+        return (char *) dp_packet_base(b) + dp_packet_get_allocated(b);
+    }
+}
 #else
+/* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
+ * byte 'offset'.  Otherwise, returns a null pointer. */
+static inline void *
+dp_packet_at(const struct dp_packet *b, size_t offset, size_t size)
+{
+    return offset + size <= dp_packet_size(b)
+           ? (char *) dp_packet_data(b) + offset
+           : NULL;
+}
+
+/* Returns a pointer to byte 'offset' in 'b', which must contain at least
+ * 'offset + size' bytes of data. */
+static inline void *
+dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size)
+{
+    ovs_assert(offset + size <= dp_packet_size(b));
+    return ((char *) dp_packet_data(b)) + offset;
+}
+
+/* Returns a pointer to byte following the last byte of data in use in 'b'. */
+static inline void *
+dp_packet_tail(const struct dp_packet *b)
+{
+    return (char *) dp_packet_data(b) + dp_packet_size(b);
+}
+
+/* Returns a pointer to byte following the last byte allocated for use (but
+ * not necessarily in use) in 'b'. */
+static inline void *
+dp_packet_end(const struct dp_packet *b)
+{
+    return (char *) dp_packet_base(b) + dp_packet_get_allocated(b);
+}
+
 static inline void *
 dp_packet_base(const struct dp_packet *b)
 {
@@ -506,6 +647,18 @@  dp_packet_set_base(struct dp_packet *b, void *d)
     b->base_ = d;
 }
 
+static inline uint16_t
+dp_packet_get_allocated(const struct dp_packet *b)
+{
+    return b->allocated_;
+}
+
+static inline void
+dp_packet_set_allocated(struct dp_packet *b, uint16_t s)
+{
+    b->allocated_ = s;
+}
+
 static inline uint32_t
 dp_packet_size(const struct dp_packet *b)
 {
@@ -529,18 +682,6 @@  __packet_set_data(struct dp_packet *b, uint16_t v)
 {
     b->data_ofs = v;
 }
-
-static inline uint16_t
-dp_packet_get_allocated(const struct dp_packet *b)
-{
-    return b->allocated_;
-}
-
-static inline void
-dp_packet_set_allocated(struct dp_packet *b, uint16_t s)
-{
-    b->allocated_ = s;
-}
 #endif
 
 static inline void