From patchwork Mon Jun 11 16:21:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Lam, Tiago" X-Patchwork-Id: 927775 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 414JJQ4BRhz9rvt for ; Tue, 12 Jun 2018 02:24:54 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EB5FB1153; Mon, 11 Jun 2018 16:22:02 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E92211062 for ; Mon, 11 Jun 2018 16:22:01 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 2F5A6711 for ; Mon, 11 Jun 2018 16:22:00 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Jun 2018 09:21:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,502,1520924400"; d="scan'208";a="62210730" Received: from silpixa00399125.ir.intel.com ([10.237.223.34]) by fmsmga004.fm.intel.com with ESMTP; 11 Jun 2018 09:21:58 -0700 From: Tiago Lam To: ovs-dev@openvswitch.org Date: Mon, 11 Jun 2018 17:21:22 +0100 Message-Id: <1528734090-220990-7-git-send-email-tiago.lam@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528734090-220990-1-git-send-email-tiago.lam@intel.com> References: <1528734090-220990-1-git-send-email-tiago.lam@intel.com> X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: i.maximets@samsung.com Subject: [ovs-dev] [PATCH v8 06/13] dp-packet: Handle multi-seg mbufs in helper funcs. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org 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. Finally, dp_packet_use__() has also been modified to perform the initialisation of the packet (and setting the source) before continuing to set its size and data length, which now depends on the type of packet. Co-authored-by: Mark Kavanagh Signed-off-by: Mark Kavanagh Signed-off-by: Tiago Lam --- lib/dp-packet.c | 4 +- lib/dp-packet.h | 242 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 197 insertions(+), 49 deletions(-) diff --git a/lib/dp-packet.c b/lib/dp-packet.c index 782e7c2..2aaeaae 100644 --- a/lib/dp-packet.c +++ b/lib/dp-packet.c @@ -41,11 +41,11 @@ static void dp_packet_use__(struct dp_packet *b, void *base, size_t allocated, enum dp_packet_source source) { + dp_packet_init__(b, allocated, source); + dp_packet_set_base(b, base); dp_packet_set_data(b, base); dp_packet_set_size(b, 0); - - dp_packet_init__(b, allocated, source); } /* Initializes 'b' as an empty dp_packet that contains the 'allocated' bytes of diff --git a/lib/dp-packet.h b/lib/dp-packet.h index c301ed5..272597f 100644 --- a/lib/dp-packet.h +++ b/lib/dp-packet.h @@ -133,6 +133,10 @@ 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); +#ifdef DPDK_NETDEV +static inline void * dp_packet_at_offset(const struct dp_packet *b, + size_t offset); +#endif static inline void *dp_packet_tail(const struct dp_packet *); static inline void *dp_packet_end(const struct dp_packet *); @@ -180,40 +184,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 @@ -229,6 +199,14 @@ dp_packet_headroom(const struct dp_packet *b) static inline size_t dp_packet_tailroom(const struct dp_packet *b) { +#ifdef DPDK_NETDEV + if (b->source == DPBUF_DPDK) { + struct rte_mbuf *tmbuf = CONST_CAST(struct rte_mbuf *, &b->mbuf); + tmbuf = rte_pktmbuf_lastseg(tmbuf); + + return rte_pktmbuf_tailroom(tmbuf); + } +#endif return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); } @@ -236,8 +214,13 @@ dp_packet_tailroom(const struct dp_packet *b) static inline void dp_packet_clear(struct dp_packet *b) { +#ifdef DPDK_NETDEV + dp_packet_set_size(b, 0); + rte_pktmbuf_reset(&b->mbuf); +#else dp_packet_set_data(b, dp_packet_base(b)); dp_packet_set_size(b, 0); +#endif } /* Removes 'size' bytes from the head end of 'b', which must contain at least @@ -252,12 +235,32 @@ dp_packet_pull(struct dp_packet *b, size_t size) return data; } +#ifdef DPDK_NETDEV +/* Similar to dp_packet_try_pull() but doesn't actually pull any code, only + * returns true or false if it would be possible to actually pull any code. + * Valid for dp_packets carrying mbufs only. */ +static inline bool +dp_packet_mbuf_may_pull(const struct dp_packet *b, size_t size) { + if (size > b->mbuf.data_len) { + return false; + } + + return true; +} +#endif + /* If 'b' has at least 'size' bytes of data, removes that many bytes from the * head end of 'b' and returns the first byte removed. Otherwise, returns a * null pointer without modifying 'b'. */ static inline void * dp_packet_try_pull(struct dp_packet *b, size_t size) { +#ifdef DPDK_NETDEV + if (!dp_packet_mbuf_may_pull(b, size)) { + return NULL; + } +#endif + return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size ? dp_packet_pull(b, size) : NULL; } @@ -311,6 +314,12 @@ dp_packet_set_l2_pad_size(struct dp_packet *b, uint8_t pad_size) static inline void * dp_packet_l2_5(const struct dp_packet *b) { +#ifdef DPDK_NETDEV + if (!dp_packet_mbuf_may_pull(b, b->l2_5_ofs)) { + return NULL; + } +#endif + return b->l2_5_ofs != UINT16_MAX ? (char *) dp_packet_data(b) + b->l2_5_ofs : NULL; @@ -327,6 +336,12 @@ dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) static inline void * dp_packet_l3(const struct dp_packet *b) { +#ifdef DPDK_NETDEV + if (!dp_packet_mbuf_may_pull(b, b->l3_ofs)) { + return NULL; + } +#endif + return b->l3_ofs != UINT16_MAX ? (char *) dp_packet_data(b) + b->l3_ofs : NULL; @@ -341,6 +356,12 @@ dp_packet_set_l3(struct dp_packet *b, void *l3) static inline void * dp_packet_l4(const struct dp_packet *b) { +#ifdef DPDK_NETDEV + if (!dp_packet_mbuf_may_pull(b, b->l4_ofs)) { + return NULL; + } +#endif + return b->l4_ofs != UINT16_MAX ? (char *) dp_packet_data(b) + b->l4_ofs : NULL; @@ -355,10 +376,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 * @@ -491,7 +539,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 @@ -499,7 +547,107 @@ 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 */ + buf = rte_pktmbuf_lastseg(buf); + } + + 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 (char *) buf->buf_addr + 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) { @@ -518,34 +666,34 @@ dp_packet_size(const struct dp_packet *b) return b->size_; } -static inline void -dp_packet_set_size(struct dp_packet *b, uint32_t v) +static inline uint16_t +dp_packet_get_allocated(const struct dp_packet *b) { - b->size_ = v; + return b->allocated_; } -static inline uint16_t -__packet_data(const struct dp_packet *b) +static inline void +dp_packet_set_allocated(struct dp_packet *b, uint16_t s) { - return b->data_ofs; + b->allocated_ = s; } static inline void -__packet_set_data(struct dp_packet *b, uint16_t v) +dp_packet_set_size(struct dp_packet *b, uint32_t v) { - b->data_ofs = v; + b->size_ = v; } static inline uint16_t -dp_packet_get_allocated(const struct dp_packet *b) +__packet_data(const struct dp_packet *b) { - return b->allocated_; + return b->data_ofs; } static inline void -dp_packet_set_allocated(struct dp_packet *b, uint16_t s) +__packet_set_data(struct dp_packet *b, uint16_t v) { - b->allocated_ = s; + b->data_ofs = v; } #endif