DPDK patches and discussions
 help / color / mirror / Atom feed
From: Tanzeel Ahmed <tanxeel1.ahmed@gmail.com>
To: Thomas Monjalon <thomas@monjalon.net>,
	Tanzeel Ahmed <tanzeelahmed713@gmail.com>,
	 "olivier.matz@6wind.com" <olivier.matz@6wind.com>
Cc: dev@dpdk.org
Subject: Re: [PATCH v5] lib/net: add MPLS insert and strip functionality
Date: Fri, 23 Jun 2023 00:47:53 +0500	[thread overview]
Message-ID: <CAAJ7kpLGqJx=Yt9q_BZfXFyHLSGCsUajvEGiYt6CweTQ4-F_rA@mail.gmail.com> (raw)
In-Reply-To: <20230610201710.929-1-tanxeel1.ahmed@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 12150 bytes --]

Hi, @olivier.matz@6wind.com <olivier.matz@6wind.com>

On Sun, 11 Jun 2023, 1:17 am Tanzeel-inline, <tanxeel1.ahmed@gmail.com>
wrote:

> None of the foundational NICs currently supports MPLS insertion and
> stripping, this functionality can help users who rely on MPLS in their
> network application.
>
> Signed-off-by: Tanzeel Ahmed <tanxeel1.ahmed@gmail.com>
>
> ---
>
> This patch is new version of [PATCH] lib/net: added push MPLS header API.
> I have also added the MPLS strip functionality to address the question
> asked in last patch.
>
> > To be honest, I have some doubts about the usefulness of the patch,
> > especially the function that strips all the MPLS headers.
>
> I believe it serves a practical purpose, in scenarios involving tapped
> traffic where MPLS headers
> have not been stripped.
> While some headers in the lib/net folder have well-defined functions,
> others are limited to their
> structure alone. It would be advantageous to have basic functions
> available for all headers.
>
> > I think the function should only strip the first MPLS header, it is
> > symmetric with the previous function, and more flexible.
>
> You are right, stripping one header is more flexible.
> I updated the function to return 1, in case of stripping last MPLS header.
>
> v5:
> * Updated the MPLS strip function to strip one header at a time.
> * Added the unit test cases.
>
> v4:
> * Removed extra void cast.
> * rte_pktmbuf_append/mtod now return void*.
>   The memmove result is casted to rte_ether_hdr*.
>
> v3:
> * fixed patch check failure issue
>
> v2:
> * marked experimental
> * coding style fixed
> * changed rte_memcpy to memcpy
> * mpls header marked as const in parameter
> * added MPLS stripping functionality
> ---
>  app/test/meson.build |   2 +
>  app/test/test_mpls.c | 180 +++++++++++++++++++++++++++++++++++++++++++
>  lib/net/rte_mpls.h   | 106 +++++++++++++++++++++++++
>  3 files changed, 288 insertions(+)
>  create mode 100644 app/test/test_mpls.c
>
> diff --git a/app/test/meson.build b/app/test/meson.build
> index f34d19e3c3..548349399f 100644
> --- a/app/test/meson.build
> +++ b/app/test/meson.build
> @@ -95,6 +95,7 @@ test_sources = files(
>          'test_meter.c',
>          'test_mcslock.c',
>          'test_mp_secondary.c',
> +        'test_mpls.c',
>          'test_per_lcore.c',
>          'test_pflock.c',
>          'test_pmd_perf.c',
> @@ -205,6 +206,7 @@ fast_tests = [
>          ['mempool_autotest', false, true],
>          ['memzone_autotest', false, true],
>          ['meter_autotest', true, true],
> +        ['mpls_autotest', false, true],
>          ['multiprocess_autotest', false, false],
>          ['per_lcore_autotest', true, true],
>          ['pflock_autotest', true, true],
> diff --git a/app/test/test_mpls.c b/app/test/test_mpls.c
> new file mode 100644
> index 0000000000..8ff701f6e0
> --- /dev/null
> +++ b/app/test/test_mpls.c
> @@ -0,0 +1,180 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2010-2014 Intel Corporation
> + */
> +
> +#include "test.h"
> +
> +#include <string.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +
> +#include <rte_common.h>
> +#include <rte_memory.h>
> +#include <rte_memcpy.h>
> +#include <rte_mbuf.h>
> +#include <rte_malloc.h>
> +#include <rte_ether.h>
> +#include <rte_mpls.h>
> +
> +#define MEMPOOL_CACHE_SIZE      32
> +#define MBUF_DATA_SIZE          2048
> +#define NB_MBUF                 128
> +
> +static int
> +test_mpls_fail_push(struct rte_mbuf *m)
> +{
> +       struct rte_mpls_hdr mpls;
> +
> +       /* create dummy MPLS header */
> +       mpls.tag_msb = 1;
> +       mpls.tag_lsb = 2;
> +       mpls.bs = 1;
> +       mpls.tc = 1;
> +       mpls.ttl = 255;
> +
> +       /* push first MPLS header */
> +       if (rte_mpls_push_over_l2(m, &mpls) != 0)
> +               return 0;
> +       return -1;
> +}
> +
> +static int
> +test_mpls_push(struct rte_mbuf *m)
> +{
> +       struct rte_mpls_hdr mpls;
> +
> +       /* create dummy MPLS header */
> +       mpls.tag_msb = 1;
> +       mpls.tag_lsb = 2;
> +       mpls.bs = 1;
> +       mpls.tc = 1;
> +       mpls.ttl = 255;
> +
> +       /* push first MPLS header */
> +       if (rte_mpls_push_over_l2(m, &mpls) != 0) {
> +               printf("Failed to insert mpls 1\n");
> +               return -1;
> +       }
> +       if (rte_pktmbuf_pkt_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN) {
> +               printf("Bad pkt length after inserting first mpls
> header\n");
> +               return -1;
> +       }
> +
> +       /* push second MPLS header*/
> +       if (rte_mpls_push_over_l2(m, &mpls) != 0) {
> +               printf("failed to insert mpls 1\n");
> +               return -1;
> +       }
> +       if (rte_pktmbuf_pkt_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN *
> 2) {
> +               printf("bad pkt length after inserting second mpls
> header\n");
> +               return -1;
> +       }
> +       return 0;
> +}
> +
> +static int
> +test_mpls_fail_strip(struct rte_mbuf *m)
> +{
> +       /* strip MPLS headers */
> +       if (rte_mpls_strip_over_l2(m) != 0)
> +               return 0;
> +       return -1;
> +}
> +
> +static int
> +test_mpls_strip(struct rte_mbuf *m)
> +{
> +       /* strip MPLS headers */
> +       return rte_mpls_strip_over_l2(m);
> +}
> +
> +static int
> +test_mpls(void)
> +{
> +       int ret = -1;
> +       struct rte_mempool *pktmbuf_pool = NULL;
> +       struct rte_mbuf *m = NULL;
> +       char *data;
> +       struct rte_ether_hdr eh;
> +
> +       /* create pktmbuf pool */
> +       pktmbuf_pool = rte_pktmbuf_pool_create("test_mpls_pool",
> +                       NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
> +                       SOCKET_ID_ANY);
> +
> +       if (pktmbuf_pool == NULL) {
> +               printf("cannot allocate mbuf pool\n");
> +               goto err;
> +       }
> +
> +    /* allocate mbuf from pool */
> +       m = rte_pktmbuf_alloc(pktmbuf_pool);
> +       if (m == NULL) {
> +               printf("mbuf alloc failed\n");
> +               goto err;
> +       }
> +       if (rte_pktmbuf_data_len(m) != 0) {
> +               printf("mbuf alloc bad length\n");
> +               goto err;
> +       }
> +
> +       if (test_mpls_fail_push(m) < 0) {
> +               printf("test_mpls_fail_push() failed\n");
> +               goto err;
> +       }
> +
> +       if (test_mpls_fail_strip(m) < 0) {
> +               printf("test_mpls_fail_strip() failed\n");
> +               goto err;
> +       }
> +
> +       /* create a dummy ethernet header */
> +       memset(&eh.src_addr, 0, RTE_ETHER_ADDR_LEN);
> +       memset(&eh.dst_addr, 0, RTE_ETHER_ADDR_LEN);
> +       eh.ether_type = rte_be_to_cpu_16(RTE_ETHER_TYPE_IPV4);
> +
> +       /* append ethernet header into mbuf */
> +       data = rte_pktmbuf_append(m, RTE_ETHER_HDR_LEN);
> +       if (data == NULL) {
> +               printf("cannot append data\n");
> +               goto err;
> +       }
> +       if (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN) {
> +               printf("bad pkt data length\n");
> +               goto err;
> +       }
> +       memcpy(data, &eh, RTE_ETHER_HDR_LEN);
> +
> +       if (test_mpls_push(m) < 0) {
> +               printf("test_mpls_push() failed\n");
> +               goto err;
> +       }
> +
> +       if (test_mpls_strip(m) < 0) {
> +               printf("test_mpls_push() failed\n");
> +               goto err;
> +       }
> +       if (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN) {
> +               printf("bad pkt data length after stripping first MPLS
> header\n");
> +               goto err;
> +       }
> +
> +       if (test_mpls_strip(m) < 0) {
> +               printf("test_mpls_push() failed\n");
> +               goto err;
> +       }
> +       if (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN) {
> +               printf("bad pkt data length after stripping second MPLS
> header\n");
> +               goto err;
> +       }
> +       ret = 0;
> +err:
> +       if (m)
> +               rte_pktmbuf_free(m);
> +       if (pktmbuf_pool)
> +               rte_mempool_free(pktmbuf_pool);
> +       return ret;
> +}
> +
> +REGISTER_TEST_COMMAND(mpls_autotest, test_mpls);
> diff --git a/lib/net/rte_mpls.h b/lib/net/rte_mpls.h
> index 3e8cb90ec3..a2072cdd10 100644
> --- a/lib/net/rte_mpls.h
> +++ b/lib/net/rte_mpls.h
> @@ -13,6 +13,8 @@
>
>  #include <stdint.h>
>  #include <rte_byteorder.h>
> +#include <rte_ether.h>
> +#include <rte_mbuf.h>
>
>  #ifdef __cplusplus
>  extern "C" {
> @@ -36,6 +38,110 @@ struct rte_mpls_hdr {
>         uint8_t  ttl;       /**< Time to live. */
>  } __rte_packed;
>
> +#define RTE_MPLS_HLEN 4 /**< Length of MPLS header. */
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Insert MPLS header into the packet.
> + * If it's the first MPLS header to be inserted in the packet,
> + *  - Update the ether type.
> + *  - Set the MPLS bottom-of-stack bit to 1.
> + *
> + * @param m
> + *   The pointer to the mbuf.
> + * @param mp
> + *   The pointer to the MPLS header.
> + * @return
> + *   0 on success, -1 on error.
> + */
> +__rte_experimental
> +static inline int
> +rte_mpls_push_over_l2(struct rte_mbuf *m, const struct rte_mpls_hdr *mp)
> +{
> +       struct rte_ether_hdr *oh, *nh;
> +       struct rte_mpls_hdr *mph;
> +
> +       /* Can't insert header if mbuf is shared */
> +       if (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1)
> +               return -EINVAL;
> +
> +       /* Can't insert header if ethernet frame doesn't exist */
> +       if (rte_pktmbuf_data_len(m) < RTE_ETHER_HDR_LEN)
> +               return -EINVAL;
> +
> +       oh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
> +       nh = (struct rte_ether_hdr *)(void *)
> +               rte_pktmbuf_prepend(m, sizeof(struct rte_mpls_hdr));
> +       if (nh == NULL)
> +               return -ENOSPC;
> +
> +       memmove(nh, oh, RTE_ETHER_HDR_LEN);
> +
> +       /* Copy the MPLS header after ethernet frame */
> +       mph = rte_pktmbuf_mtod_offset(m, struct rte_mpls_hdr *,
> +                       sizeof(struct rte_ether_hdr));
> +       memcpy(mph, mp, RTE_MPLS_HLEN);
> +
> +       mph->tag_msb = rte_cpu_to_be_16(mp->tag_msb);
> +
> +       /* If first MPLS header, update ether type and bottom-of-stack bit
> */
> +       if (nh->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) {
> +               nh->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS);
> +               mph->bs = 1;
> +       } else {
> +               mph->bs = 0;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Strip MPLS header from the packet without updating the ether type.
> + *
> + * @param m
> + *   The pointer to the mbuf.
> + * @return
> + *   1 if last MPLS header is stripped,
> + *   0 on success,
> + *   -1 on error.
> + */
> +__rte_experimental
> +static inline int
> +rte_mpls_strip_over_l2(struct rte_mbuf *m)
> +{
> +       struct rte_ether_hdr *eh = rte_pktmbuf_mtod(m, struct
> rte_ether_hdr *);
> +       struct rte_mpls_hdr *mph;
> +       int result = 0;
> +
> +       /* Can't strip header if mbuf is shared */
> +       if (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1)
> +               return -EINVAL;
> +
> +       /* Can't strip header if packet length is smaller */
> +       if (rte_pktmbuf_data_len(m) < RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN)
> +               return -EINVAL;
> +
> +       if (eh->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS))
> +               return -1;
> +
> +       /* Stripping MPLS header */
> +       mph = rte_pktmbuf_mtod_offset(m, struct rte_mpls_hdr *,
> +               sizeof(struct rte_ether_hdr));
> +       if (mph->bs & 1)
> +               result = 1;
> +       memmove(
> +               rte_pktmbuf_adj(m, sizeof(struct rte_mpls_hdr)),
> +               eh, sizeof(struct rte_ether_hdr));
> +       eh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
> +
> +       return result;
> +}
> +
>  #ifdef __cplusplus
>  }
>  #endif
> --
> 2.34.1
>
>

[-- Attachment #2: Type: text/html, Size: 15681 bytes --]

      reply	other threads:[~2023-06-22 19:48 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-19 22:43 [PATCH v2] " Tanzeel-inline
2023-02-24 11:25 ` [PATCH v3] " Tanzeel-inline
2023-02-24 16:29   ` Stephen Hemminger
2023-02-25 13:53 ` [PATCH v4] " Tanzeel-inline
2023-03-09 18:35   ` Tanzeel Ahmed
2023-04-18 13:18     ` Tanzeel Ahmed
2023-05-20 19:53       ` Tanzeel Ahmed
2023-06-05  9:31   ` Olivier Matz
2023-06-10 20:17 ` [PATCH v5] " Tanzeel-inline
2023-06-22 19:47   ` Tanzeel Ahmed [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAAJ7kpLGqJx=Yt9q_BZfXFyHLSGCsUajvEGiYt6CweTQ4-F_rA@mail.gmail.com' \
    --to=tanxeel1.ahmed@gmail.com \
    --cc=dev@dpdk.org \
    --cc=olivier.matz@6wind.com \
    --cc=tanzeelahmed713@gmail.com \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).