mbuf: provide bulk allocation
[dpdk.git] / lib / librte_mbuf / rte_mbuf.h
index d7c9030..c1f6bc4 100644 (file)
@@ -728,6 +728,9 @@ typedef uint8_t  MARKER8[0];  /**< generic marker with 1B alignment */
 typedef uint64_t MARKER64[0]; /**< marker that allows us to overwrite 8 bytes
                                * with a single assignment */
 
+/** Opaque rte_mbuf_offload  structure declarations */
+struct rte_mbuf_offload;
+
 /**
  * The generic rte_mbuf, containing a packet mbuf.
  */
@@ -799,7 +802,10 @@ struct rte_mbuf {
                        /**< First 4 flexible bytes or FD ID, dependent on
                             PKT_RX_FDIR_* flag in ol_flags. */
                } fdir;           /**< Filter identifier if FDIR enabled */
-               uint32_t sched;   /**< Hierarchical scheduler */
+               struct {
+                       uint32_t lo;
+                       uint32_t hi;
+               } sched;          /**< Hierarchical scheduler */
                uint32_t usr;     /**< User defined tags. See rte_distributor_process() */
        } hash;                   /**< hash information */
 
@@ -808,7 +814,7 @@ struct rte_mbuf {
        uint16_t vlan_tci_outer;  /**< Outer VLAN Tag Control Identifier (CPU order) */
 
        /* second cache line - fields only used in slow path or on TX */
-       MARKER cacheline1 __rte_cache_aligned;
+       MARKER cacheline1 __rte_cache_min_aligned;
 
        union {
                void *userdata;   /**< Can be used for external metadata */
@@ -841,6 +847,9 @@ struct rte_mbuf {
 
        /** Timesync flags for use with IEEE1588. */
        uint16_t timesync;
+
+       /* Chain of off-load operations to perform on mbuf */
+       struct rte_mbuf_offload *offload_ops;
 } __rte_cache_aligned;
 
 static inline uint16_t rte_pktmbuf_priv_size(struct rte_mempool *mp);
@@ -1326,6 +1335,61 @@ static inline struct rte_mbuf *rte_pktmbuf_alloc(struct rte_mempool *mp)
        return m;
 }
 
+/**
+ * Allocate a bulk of mbufs, initialize refcnt and reset the fields to default
+ * values.
+ *
+ *  @param pool
+ *    The mempool from which mbufs are allocated.
+ *  @param mbufs
+ *    Array of pointers to mbufs
+ *  @param count
+ *    Array size
+ *  @return
+ *   - 0: Success
+ */
+static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool,
+        struct rte_mbuf **mbufs, unsigned count)
+{
+       unsigned idx = 0;
+       int rc;
+
+       rc = rte_mempool_get_bulk(pool, (void **)mbufs, count);
+       if (unlikely(rc))
+               return rc;
+
+       /* To understand duff's device on loop unwinding optimization, see
+        * https://en.wikipedia.org/wiki/Duff's_device.
+        * Here while() loop is used rather than do() while{} to avoid extra
+        * check if count is zero.
+        */
+       switch (count % 4) {
+       case 0:
+               while (idx != count) {
+                       RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0);
+                       rte_mbuf_refcnt_set(mbufs[idx], 1);
+                       rte_pktmbuf_reset(mbufs[idx]);
+                       idx++;
+       case 3:
+                       RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0);
+                       rte_mbuf_refcnt_set(mbufs[idx], 1);
+                       rte_pktmbuf_reset(mbufs[idx]);
+                       idx++;
+       case 2:
+                       RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0);
+                       rte_mbuf_refcnt_set(mbufs[idx], 1);
+                       rte_pktmbuf_reset(mbufs[idx]);
+                       idx++;
+       case 1:
+                       RTE_MBUF_ASSERT(rte_mbuf_refcnt_read(mbufs[idx]) == 0);
+                       rte_mbuf_refcnt_set(mbufs[idx], 1);
+                       rte_pktmbuf_reset(mbufs[idx]);
+                       idx++;
+               }
+       }
+       return 0;
+}
+
 /**
  * Attach packet mbuf to another packet mbuf.
  *
@@ -1621,6 +1685,27 @@ static inline struct rte_mbuf *rte_pktmbuf_lastseg(struct rte_mbuf *m)
  */
 #define rte_pktmbuf_mtod(m, t) rte_pktmbuf_mtod_offset(m, t, 0)
 
+/**
+ * A macro that returns the physical address that points to an offset of the
+ * start of the data in the mbuf
+ *
+ * @param m
+ *   The packet mbuf.
+ * @param o
+ *   The offset into the data to calculate address from.
+ */
+#define rte_pktmbuf_mtophys_offset(m, o) \
+       (phys_addr_t)((m)->buf_physaddr + (m)->data_off + (o))
+
+/**
+ * A macro that returns the physical address that points to the start of the
+ * data in the mbuf
+ *
+ * @param m
+ *   The packet mbuf.
+ */
+#define rte_pktmbuf_mtophys(m) rte_pktmbuf_mtophys_offset(m, 0)
+
 /**
  * A macro that returns the length of the packet.
  *
@@ -1774,6 +1859,44 @@ static inline int rte_pktmbuf_is_contiguous(const struct rte_mbuf *m)
        return !!(m->nb_segs == 1);
 }
 
+/**
+ * Chain an mbuf to another, thereby creating a segmented packet.
+ *
+ * Note: The implementation will do a linear walk over the segments to find
+ * the tail entry. For cases when there are many segments, it's better to
+ * chain the entries manually.
+ *
+ * @param head
+ *   The head of the mbuf chain (the first packet)
+ * @param tail
+ *   The mbuf to put last in the chain
+ *
+ * @return
+ *   - 0, on success.
+ *   - -EOVERFLOW, if the chain is full (256 entries)
+ */
+static inline int rte_pktmbuf_chain(struct rte_mbuf *head, struct rte_mbuf *tail)
+{
+       struct rte_mbuf *cur_tail;
+
+       /* Check for number-of-segments-overflow */
+       if (head->nb_segs + tail->nb_segs >= 1 << (sizeof(head->nb_segs) * 8))
+               return -EOVERFLOW;
+
+       /* Chain 'tail' onto the old tail */
+       cur_tail = rte_pktmbuf_lastseg(head);
+       cur_tail->next = tail;
+
+       /* accumulate number of segments and total length. */
+       head->nb_segs = (uint8_t)(head->nb_segs + tail->nb_segs);
+       head->pkt_len += tail->pkt_len;
+
+       /* pkt_len is only set in the head */
+       tail->pkt_len = tail->data_len;
+
+       return 0;
+}
+
 /**
  * Dump an mbuf structure to the console.
  *