get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/108720/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 108720,
    "url": "http://patches.dpdk.org/api/patches/108720/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1647328926-17118-1-git-send-email-chcchc88@163.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1647328926-17118-1-git-send-email-chcchc88@163.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1647328926-17118-1-git-send-email-chcchc88@163.com",
    "date": "2022-03-15T07:22:06",
    "name": "[v4] ip_frag: add IPv4 options fragment and test data",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "aad3b7b3bfed2cd50872662f2e8c579a6eb73b62",
    "submitter": {
        "id": 2371,
        "url": "http://patches.dpdk.org/api/people/2371/?format=api",
        "name": "Huichao Cai",
        "email": "chcchc88@163.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1647328926-17118-1-git-send-email-chcchc88@163.com/mbox/",
    "series": [
        {
            "id": 22149,
            "url": "http://patches.dpdk.org/api/series/22149/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=22149",
            "date": "2022-03-15T07:22:06",
            "name": "[v4] ip_frag: add IPv4 options fragment and test data",
            "version": 4,
            "mbox": "http://patches.dpdk.org/series/22149/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/108720/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/108720/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 14D47A00BE;\n\tTue, 15 Mar 2022 08:22:27 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 9DEF740395;\n\tTue, 15 Mar 2022 08:22:26 +0100 (CET)",
            "from m12-14.163.com (m12-14.163.com [220.181.12.14])\n by mails.dpdk.org (Postfix) with ESMTP id A32F34014F\n for <dev@dpdk.org>; Tue, 15 Mar 2022 08:22:23 +0100 (CET)",
            "from bogon.localdomain (unknown [36.111.88.33])\n by smtp10 (Coremail) with SMTP id DsCowACX4IOqPjBi8OhtBQ--.132S2;\n Tue, 15 Mar 2022 15:22:20 +0800 (CST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com;\n s=s110527; h=From:Subject:Date:Message-Id; bh=rWmW60RYgD8Dp9MAqZ\n bX6W2wsDgEQzg0XvNcuXeZEaU=; b=Egapg/67MpL+7IhWw9Q5F89IBI/fZNRsfR\n eto/I29Hi6qaZSHI35EP/agz76eNOXpS3GzrkVsNq1Hb8gNdKsiDAgGxVqGkIesV\n 5i7hRqdy4k7xTs2lQjBW+xtW1wTHW7vUpODYdcQHxU8bu81VhoRAvs+nj/HZjk1n\n /m/gFKYqM=",
        "From": "Huichao Cai <chcchc88@163.com>",
        "To": "dev@dpdk.org",
        "Cc": "konstantin.ananyev@intel.com",
        "Subject": "[PATCH v4] ip_frag: add IPv4 options fragment and test data",
        "Date": "Tue, 15 Mar 2022 15:22:06 +0800",
        "Message-Id": "<1647328926-17118-1-git-send-email-chcchc88@163.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1645413440-3431-1-git-send-email-chcchc88@163.com>",
        "References": "<1645413440-3431-1-git-send-email-chcchc88@163.com>",
        "X-CM-TRANSID": "DsCowACX4IOqPjBi8OhtBQ--.132S2",
        "X-Coremail-Antispam": "1Uf129KBjvAXoW3KFW5Gw4UXr15Jw4fJr4ruFg_yoW8Wr4DCo\n ZrWwn8tw1vgry2yrWkCr1IvFy8Ww4Yk347tws0qF4ruw1xCas8Gws3uw45Zw1UZr45KryY\n yas7X3W3XayvyFs7n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3\n AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxU7D73DUUUU",
        "X-Originating-IP": "[36.111.88.33]",
        "X-CM-SenderInfo": "pfkfuxrfyyqiywtou0bp/1tbitw3EF1aEOOr1-AAAsg",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "According to RFC791,the options may appear or not in datagrams.\nThey must be implemented by all IP modules (host and gateways).\nWhat is optional is their transmission in any particular datagram,\nnot their implementation.So we have to deal with it during the\nfragmenting process.Add some test data for the IPv4 header optional\nfield fragmenting.\n\nSigned-off-by: Huichao Cai <chcchc88@163.com>\n---\n app/test/test_ipfrag.c               | 319 ++++++++++++++++++++++++++++++++---\n lib/ip_frag/rte_ip_frag.h            |   6 +\n lib/ip_frag/rte_ipv4_fragmentation.c |  70 +++++++-\n 3 files changed, 372 insertions(+), 23 deletions(-)",
    "diff": "diff --git a/app/test/test_ipfrag.c b/app/test/test_ipfrag.c\nindex 1ced25a..f6ff2d0 100644\n--- a/app/test/test_ipfrag.c\n+++ b/app/test/test_ipfrag.c\n@@ -18,10 +18,109 @@\n #define NUM_MBUFS 128\n #define BURST 32\n \n+#define IPV4_IPOPT_MANUAL\n+\n+#ifdef IPV4_IPOPT_MANUAL\n+uint8_t expected_first_frag_ipv4_opts_copied[] = {\n+\t0x07, 0x0b, 0x04, 0x00,\n+\t0x00, 0x00, 0x00, 0x00,\n+\t0x00, 0x00, 0x00, 0x83,\n+\t0x07, 0x04, 0xc0, 0xa8,\n+\t0xe3, 0x96, 0x00, 0x00,\n+};\n+\n+uint8_t expected_sub_frag_ipv4_opts_copied[] = {\n+\t0x83, 0x07, 0x04, 0xc0,\n+\t0xa8, 0xe3, 0x96, 0x00,\n+};\n+\n+uint8_t expected_first_frag_ipv4_opts_nocopied[] = {\n+\t0x07, 0x0b, 0x04, 0x00,\n+\t0x00, 0x00, 0x00, 0x00,\n+\t0x00, 0x00, 0x00, 0x00,\n+};\n+\n+uint8_t expected_sub_frag_ipv4_opts_nocopied[0];\n+#else\n+/**\n+ * IPv4 Options\n+ */\n+struct test_ipv4_opt {\n+\t__extension__\n+\tunion {\n+\t\tuint8_t type;\t\t    /**< option type */\n+\t\tstruct {\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\t\t\tuint8_t number:5;   /**< option number */\n+\t\t\tuint8_t category:2; /**< option class */\n+\t\t\tuint8_t copied:1;   /**< option copy flag */\n+#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN\n+\t\t\tuint8_t copied:1;   /**< option copy flag */\n+\t\t\tuint8_t category:2; /**< option class */\n+\t\t\tuint8_t number:5;   /**< option number */\n+#endif\n+\t\t} s_type;\n+\t};\n+\tuint8_t length;\t\t\t    /**< option length */\n+\tuint8_t pointer;\t\t    /**< option pointer */\n+\tuint8_t data[37];\t\t    /**< option data */\n+} __rte_packed;\n+\n+struct test_ipv4_opt test_ipv4_opts_copied[] = {\n+\t{\n+\t\t.s_type.copied = 0,\n+\t\t.s_type.category = 0,\n+\t\t.s_type.number = 7,\n+\t\t.length = 11,\n+\t\t.pointer = 4,\n+\t},\n+\t{\n+\t\t.s_type.copied = 1,\n+\t\t.s_type.category = 0,\n+\t\t.s_type.number = 3,\n+\t\t.length = 7,\n+\t\t.pointer = 4,\n+\t\t.data[0] = 0xc0,\n+\t\t.data[1] = 0xa8,\n+\t\t.data[2] = 0xe3,\n+\t\t.data[3] = 0x96,\n+\t},\n+};\n+\n+struct test_ipv4_opt test_ipv4_opts_nocopied[] = {\n+\t{\n+\t\t.s_type.copied = 0,\n+\t\t.s_type.category = 0,\n+\t\t.s_type.number = 7,\n+\t\t.length = 11,\n+\t\t.pointer = 4,\n+\t},\n+};\n+#endif\n+\n+struct test_opt_data {\n+\tbool is_first_frag;\t\t /**< offset is 0 */\n+\tbool opt_copied;\t\t /**< ip option copied flag */\n+\tuint16_t len;\t\t\t /**< option data len */\n+\tuint8_t data[RTE_IPV4_IPOPT_MAX_LEN]; /**< option data */\n+};\n+\n static struct rte_mempool *pkt_pool,\n \t\t\t  *direct_pool,\n \t\t\t  *indirect_pool;\n \n+static inline void\n+hex_to_str(uint8_t *hex, uint16_t len, char *str)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < len; i++) {\n+\t\tsprintf(str, \"%02x\", hex[i]);\n+\t\tstr += 2;\n+\t}\n+\t*str = 0;\n+}\n+\n static int\n setup_buf_pool(void)\n {\n@@ -88,23 +187,108 @@ static void ut_teardown(void)\n {\n }\n \n+static inline void\n+test_get_ipv4_opt(bool is_first_frag, bool opt_copied,\n+\tstruct test_opt_data *expected_opt)\n+{\n+#ifdef IPV4_IPOPT_MANUAL\n+\tif (is_first_frag) {\n+\t\tif (opt_copied) {\n+\t\t\texpected_opt->len =\n+\t\t\t\tsizeof(expected_first_frag_ipv4_opts_copied);\n+\t\t\trte_memcpy(expected_opt->data,\n+\t\t\t\texpected_first_frag_ipv4_opts_copied,\n+\t\t\t\tsizeof(expected_first_frag_ipv4_opts_copied));\n+\t\t} else {\n+\t\t\texpected_opt->len =\n+\t\t\t\tsizeof(expected_first_frag_ipv4_opts_nocopied);\n+\t\t\trte_memcpy(expected_opt->data,\n+\t\t\t\texpected_first_frag_ipv4_opts_nocopied,\n+\t\t\t\tsizeof(expected_first_frag_ipv4_opts_nocopied));\n+\t\t}\n+\t} else {\n+\t\tif (opt_copied) {\n+\t\t\texpected_opt->len =\n+\t\t\t\tsizeof(expected_sub_frag_ipv4_opts_copied);\n+\t\t\trte_memcpy(expected_opt->data,\n+\t\t\t\texpected_sub_frag_ipv4_opts_copied,\n+\t\t\t\tsizeof(expected_sub_frag_ipv4_opts_copied));\n+\t\t} else {\n+\t\t\texpected_opt->len =\n+\t\t\t\tsizeof(expected_sub_frag_ipv4_opts_nocopied);\n+\t\t\trte_memcpy(expected_opt->data,\n+\t\t\t\texpected_sub_frag_ipv4_opts_nocopied,\n+\t\t\t\tsizeof(expected_sub_frag_ipv4_opts_nocopied));\n+\t\t}\n+\t}\n+#else\n+\tuint16_t i;\n+\tuint16_t pos = 0;\n+\texpected_opt->len = 0;\n+\tstruct test_ipv4_opt *opts = NULL;\n+\tuint16_t opt_num;\n+\n+\tif (opt_copied) {\n+\t\topts = test_ipv4_opts_copied;\n+\t\topt_num = RTE_DIM(test_ipv4_opts_copied);\n+\t} else {\n+\t\topts = test_ipv4_opts_nocopied;\n+\t\topt_num = RTE_DIM(test_ipv4_opts_nocopied);\n+\t}\n+\n+\tfor (i = 0; i < opt_num; i++) {\n+\t\tif (unlikely(pos + opts[i].length >\n+\t\t\t\tRTE_IPV4_IPOPT_MAX_LEN))\n+\t\t\treturn;\n+\n+\t\tif (is_first_frag) {\n+\t\t\trte_memcpy(expected_opt->data + pos, &opts[i],\n+\t\t\t\topts[i].length);\n+\t\t\texpected_opt->len += opts[i].length;\n+\t\t\tpos += opts[i].length;\n+\t\t} else {\n+\t\t\tif (opts[i].s_type.copied) {\n+\t\t\t\trte_memcpy(expected_opt->data + pos,\n+\t\t\t\t\t&opts[i],\n+\t\t\t\t\topts[i].length);\n+\t\t\t\texpected_opt->len += opts[i].length;\n+\t\t\t\tpos += opts[i].length;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\texpected_opt->len = RTE_ALIGN_CEIL(expected_opt->len, 4);\n+\tmemset(expected_opt->data + pos, RTE_IPV4_IPOPT_EOL,\n+\t\texpected_opt->len - pos);\n+#endif\n+}\n+\n static void\n-v4_allocate_packet_of(struct rte_mbuf *b, int fill,\n-\t\t      size_t s, int df, uint8_t mf, uint16_t off,\n-\t\t      uint8_t ttl, uint8_t proto, uint16_t pktid)\n+v4_allocate_packet_of(struct rte_mbuf *b, int fill, size_t s,\n+\tint df, uint8_t mf, uint16_t off, uint8_t ttl, uint8_t proto,\n+\tuint16_t pktid, bool have_opt, bool is_first_frag, bool opt_copied)\n {\n \t/* Create a packet, 2k bytes long */\n \tb->data_off = 0;\n \tchar *data = rte_pktmbuf_mtod(b, char *);\n-\trte_be16_t fragment_offset = 0;\t/**< fragmentation offset */\n+\trte_be16_t fragment_offset = 0;\t/* fragmentation offset */\n+\tuint16_t iph_len;\n+\tstruct test_opt_data opt;\n \n-\tmemset(data, fill, sizeof(struct rte_ipv4_hdr) + s);\n+\topt.len = 0;\n+\n+\tif (have_opt)\n+\t\ttest_get_ipv4_opt(is_first_frag, opt_copied, &opt);\n+\n+\tiph_len = sizeof(struct rte_ipv4_hdr) + opt.len;\n+\tmemset(data, fill, iph_len + s);\n \n \tstruct rte_ipv4_hdr *hdr = (struct rte_ipv4_hdr *)data;\n \n-\thdr->version_ihl = 0x45; /* standard IP header... */\n+\thdr->version_ihl = 0x40; /* ipv4 */\n+\thdr->version_ihl += (iph_len / 4);\n \thdr->type_of_service = 0;\n-\tb->pkt_len = s + sizeof(struct rte_ipv4_hdr);\n+\tb->pkt_len = s + iph_len;\n \tb->data_len = b->pkt_len;\n \thdr->total_length = rte_cpu_to_be_16(b->pkt_len);\n \thdr->packet_id = rte_cpu_to_be_16(pktid);\n@@ -131,6 +315,8 @@ static void ut_teardown(void)\n \thdr->hdr_checksum = 0;\n \thdr->src_addr = rte_cpu_to_be_32(0x8080808);\n \thdr->dst_addr = rte_cpu_to_be_32(0x8080404);\n+\n+\trte_memcpy(hdr + 1, opt.data, opt.len);\n }\n \n static void\n@@ -187,6 +373,45 @@ static void ut_teardown(void)\n \t}\n }\n \n+static inline void\n+test_get_frag_opt(struct rte_mbuf **mb, int32_t num,\n+\tstruct test_opt_data *opt, int ipv, bool opt_copied)\n+{\n+\tint32_t i;\n+\n+\tfor (i = 0; i < num; i++) {\n+\t\tif (ipv == 4) {\n+\t\t\tstruct rte_ipv4_hdr *iph =\n+\t\t\t    rte_pktmbuf_mtod(mb[i], struct rte_ipv4_hdr *);\n+\t\t\tuint16_t header_len = (iph->version_ihl &\n+\t\t\t\tRTE_IPV4_HDR_IHL_MASK) *\n+\t\t\t\tRTE_IPV4_IHL_MULTIPLIER;\n+\t\t\tuint16_t opt_len = header_len -\n+\t\t\t\tsizeof(struct rte_ipv4_hdr);\n+\n+\t\t\topt->opt_copied = opt_copied;\n+\n+\t\t\tif ((rte_be_to_cpu_16(iph->fragment_offset) &\n+\t\t\t\t    RTE_IPV4_HDR_OFFSET_MASK) == 0)\n+\t\t\t\topt->is_first_frag = true;\n+\t\t\telse\n+\t\t\t\topt->is_first_frag = false;\n+\n+\t\t\tif (likely(opt_len <= RTE_IPV4_IPOPT_MAX_LEN)) {\n+\t\t\t\tchar *iph_opt = rte_pktmbuf_mtod_offset(mb[i],\n+\t\t\t\t    char *, sizeof(struct rte_ipv4_hdr));\n+\t\t\t\topt->len = opt_len;\n+\t\t\t\trte_memcpy(opt->data, iph_opt, opt_len);\n+\t\t\t} else {\n+\t\t\t\topt->len = RTE_IPV4_IPOPT_MAX_LEN;\n+\t\t\t\tmemset(opt->data, RTE_IPV4_IPOPT_EOL,\n+\t\t\t\t    sizeof(opt->data));\n+\t\t\t}\n+\t\t\topt++;\n+\t\t}\n+\t}\n+}\n+\n static int\n test_ip_frag(void)\n {\n@@ -206,32 +431,52 @@ static void ut_teardown(void)\n \t\tuint16_t pkt_id;\n \t\tint      expected_frags;\n \t\tuint16_t expected_fragment_offset[BURST];\n+\t\tbool have_opt;\n+\t\tbool is_first_frag;\n+\t\tbool opt_copied;\n \t} tests[] = {\n \t\t {4, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,\n-\t\t  {0x2000, 0x009D}},\n+\t\t  {0x2000, 0x009D}, false},\n \t\t {4, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, 0,            2,\n-\t\t  {0x2000, 0x009D}},\n+\t\t  {0x2000, 0x009D}, false},\n \t\t {4,  600, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       3,\n-\t\t  {0x2000, 0x2048, 0x0090}},\n+\t\t  {0x2000, 0x2048, 0x0090}, false},\n \t\t {4, 4, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,    -EINVAL},\n \t\t {4, 600, 1400, 1, 0, 0, 64, IPPROTO_ICMP, RND_ID, -ENOTSUP},\n \t\t {4, 600, 1400, 0, 0, 0, 0, IPPROTO_ICMP, RND_ID,         3,\n-\t\t  {0x2000, 0x2048, 0x0090}},\n+\t\t  {0x2000, 0x2046, 0x008C}, true, true, true},\n+\t\t /* The first fragment */\n+\t\t {4, 68, 104, 0, 1, 0, 0, IPPROTO_ICMP, RND_ID,           5,\n+\t\t  {0x2000, 0x2003, 0x2006, 0x2009, 0x200C}, true, true, true},\n+\t\t /* The middle fragment */\n \t\t {4, 68, 104, 0, 1, 13, 0, IPPROTO_ICMP, RND_ID,          3,\n-\t\t  {0x200D, 0x2013, 0x2019}},\n-\n+\t\t  {0x200D, 0x2012, 0x2017}, true, false, true},\n+\t\t /* The last fragment */\n+\t\t {4, 68, 104, 0, 0, 26, 0, IPPROTO_ICMP, RND_ID,          3,\n+\t\t  {0x201A, 0x201F, 0x0024}, true, false, true},\n+\t\t /* The first fragment */\n+\t\t {4, 68, 104, 0, 1, 0, 0, IPPROTO_ICMP, RND_ID,           4,\n+\t\t  {0x2000, 0x2004, 0x2008, 0x200C}, true, true, false},\n+\t\t /* The middle fragment */\n+\t\t {4, 68, 104, 0, 1, 13, 0, IPPROTO_ICMP, RND_ID,          3,\n+\t\t  {0x200D, 0x2013, 0x2019}, true, false, false},\n+\t\t /* The last fragment */\n+\t\t {4, 68, 104, 0, 0, 26, 0, IPPROTO_ICMP, RND_ID,          3,\n+\t\t  {0x201A, 0x2020, 0x0026}, true, false, false},\n \t\t {6, 1280, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,\n-\t\t  {0x0001, 0x04D0}},\n+\t\t  {0x0001, 0x04D0}, false},\n \t\t {6, 1300, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,       2,\n-\t\t  {0x0001, 0x04E0}},\n+\t\t  {0x0001, 0x04E0}, false},\n \t\t {6, 4, 1400, 0, 0, 0, 64, IPPROTO_ICMP, RND_ID,    -EINVAL},\n \t\t {6, 1300, 1400, 0, 0, 0, 0, IPPROTO_ICMP, RND_ID,        2,\n-\t\t  {0x0001, 0x04E0}},\n+\t\t  {0x0001, 0x04E0}, false},\n \t};\n \n \tfor (i = 0; i < RTE_DIM(tests); i++) {\n \t\tint32_t len = 0;\n \t\tuint16_t fragment_offset[BURST];\n+\t\tstruct test_opt_data opt_res[BURST];\n+\t\tstruct test_opt_data opt_exp;\n \t\tuint16_t pktid = tests[i].pkt_id;\n \t\tstruct rte_mbuf *pkts_out[BURST];\n \t\tstruct rte_mbuf *b = rte_pktmbuf_alloc(pkt_pool);\n@@ -250,7 +495,10 @@ static void ut_teardown(void)\n \t\t\t\t\t      tests[i].set_of,\n \t\t\t\t\t      tests[i].ttl,\n \t\t\t\t\t      tests[i].proto,\n-\t\t\t\t\t      pktid);\n+\t\t\t\t\t      pktid,\n+\t\t\t\t\t      tests[i].have_opt,\n+\t\t\t\t\t      tests[i].is_first_frag,\n+\t\t\t\t\t      tests[i].opt_copied);\n \t\t} else if (tests[i].ipv == 6) {\n \t\t\tv6_allocate_packet_of(b, 0x41414141,\n \t\t\t\t\t      tests[i].pkt_size,\n@@ -275,17 +523,20 @@ static void ut_teardown(void)\n \t\tif (len > 0) {\n \t\t\ttest_get_offset(pkts_out, len,\n \t\t\t    fragment_offset, tests[i].ipv);\n+\t\t\tif (tests[i].have_opt)\n+\t\t\t\ttest_get_frag_opt(pkts_out, len, opt_res,\n+\t\t\t\t\ttests[i].ipv, tests[i].opt_copied);\n \t\t\ttest_free_fragments(pkts_out, len);\n \t\t}\n \n-\t\tprintf(\"%zd: checking %d with %d\\n\", i, len,\n+\t\tprintf(\"[check frag number]%zd: checking %d with %d\\n\", i, len,\n \t\t       tests[i].expected_frags);\n \t\tRTE_TEST_ASSERT_EQUAL(len, tests[i].expected_frags,\n \t\t\t\t      \"Failed case %zd.\\n\", i);\n \n \t\tif (len > 0) {\n \t\t\tfor (j = 0; j < (size_t)len; j++) {\n-\t\t\t\tprintf(\"%zd-%zd: checking %d with %d\\n\",\n+\t\t\t\tprintf(\"[check offset]%zd-%zd: checking %d with %d\\n\",\n \t\t\t\t    i, j, fragment_offset[j],\n \t\t\t\t    rte_cpu_to_be_16(\n \t\t\t\t\ttests[i].expected_fragment_offset[j]));\n@@ -294,6 +545,36 @@ static void ut_teardown(void)\n \t\t\t\t\ttests[i].expected_fragment_offset[j]),\n \t\t\t\t    \"Failed case %zd.\\n\", i);\n \t\t\t}\n+\n+\t\t\tif (tests[i].have_opt && (tests[i].ipv == 4)) {\n+\t\t\t\tfor (j = 0; j < (size_t)len; j++) {\n+\t\t\t\t\tchar opt_res_str[2 *\n+\t\t\t\t\t\tRTE_IPV4_IPOPT_MAX_LEN + 1];\n+\t\t\t\t\tchar opt_exp_str[2 *\n+\t\t\t\t\t\tRTE_IPV4_IPOPT_MAX_LEN + 1];\n+\n+\t\t\t\t\ttest_get_ipv4_opt(\n+\t\t\t\t\t\topt_res[j].is_first_frag,\n+\t\t\t\t\t\topt_res[j].opt_copied,\n+\t\t\t\t\t\t&opt_exp);\n+\t\t\t\t\thex_to_str(opt_res[j].data,\n+\t\t\t\t\t\topt_res[j].len,\n+\t\t\t\t\t\topt_res_str);\n+\t\t\t\t\thex_to_str(opt_exp.data,\n+\t\t\t\t\t\topt_exp.len,\n+\t\t\t\t\t\topt_exp_str);\n+\n+\t\t\t\t\tprintf(\n+\t\t\t\t\t\t\"[check ipv4 option]%zd-%zd: checking (len:%u)%s with (len:%u)%s\\n\",\n+\t\t\t\t\t\ti, j,\n+\t\t\t\t\t\topt_res[j].len, opt_res_str,\n+\t\t\t\t\t\topt_exp.len, opt_exp_str);\n+\t\t\t\t\t\tRTE_TEST_ASSERT_SUCCESS(\n+\t\t\t\t\t\t\tstrcmp(opt_res_str,\n+\t\t\t\t\t\t\t\topt_exp_str),\n+\t\t\t\t\t\t\"Failed case %zd.\\n\", i);\n+\t\t\t\t}\n+\t\t\t}\n \t\t}\n \n \t}\ndiff --git a/lib/ip_frag/rte_ip_frag.h b/lib/ip_frag/rte_ip_frag.h\nindex 7d2abe1..f337d1e 100644\n--- a/lib/ip_frag/rte_ip_frag.h\n+++ b/lib/ip_frag/rte_ip_frag.h\n@@ -27,6 +27,12 @@\n \n struct rte_mbuf;\n \n+/* IP options */\n+#define RTE_IPV4_IPOPT_EOL       0\n+#define RTE_IPV4_IPOPT_NOP       1\n+#define RTE_IPV4_IPOPT_COPIED(v) ((v) & 0x80)\n+#define RTE_IPV4_IPOPT_MAX_LEN   40\n+\n /** death row size (in packets) */\n #define RTE_IP_FRAG_DEATH_ROW_LEN 32\n \ndiff --git a/lib/ip_frag/rte_ipv4_fragmentation.c b/lib/ip_frag/rte_ipv4_fragmentation.c\nindex 2e7739d..1e655a7 100644\n--- a/lib/ip_frag/rte_ipv4_fragmentation.c\n+++ b/lib/ip_frag/rte_ipv4_fragmentation.c\n@@ -22,6 +22,8 @@\n \n #define\tIPV4_HDR_FO_ALIGN\t\t\t(1 << RTE_IPV4_HDR_FO_SHIFT)\n \n+#define IPV4_HDR_MAX_LEN\t\t\t60\n+\n static inline void __fill_ipv4hdr_frag(struct rte_ipv4_hdr *dst,\n \t\tconst struct rte_ipv4_hdr *src, uint16_t header_len,\n \t\tuint16_t len, uint16_t fofs, uint16_t dofs, uint32_t mf)\n@@ -41,6 +43,49 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)\n \t\trte_pktmbuf_free(mb[i]);\n }\n \n+static inline uint16_t __create_ipopt_frag_hdr(uint8_t *iph,\n+\tuint16_t ipopt_len, uint8_t *ipopt_frag_hdr)\n+{\n+\tuint16_t len = ipopt_len;\n+\tstruct rte_ipv4_hdr *iph_opt = (struct rte_ipv4_hdr *)ipopt_frag_hdr;\n+\n+\tipopt_len = 0;\n+\trte_memcpy(ipopt_frag_hdr, iph, sizeof(struct rte_ipv4_hdr));\n+\tipopt_frag_hdr += sizeof(struct rte_ipv4_hdr);\n+\n+\tuint8_t *p_opt = iph + sizeof(struct rte_ipv4_hdr);\n+\n+\twhile (len > 0) {\n+\t\tif (unlikely(*p_opt == RTE_IPV4_IPOPT_NOP)) {\n+\t\t\tlen--;\n+\t\t\tp_opt++;\n+\t\t\tcontinue;\n+\t\t} else if (unlikely(*p_opt == RTE_IPV4_IPOPT_EOL))\n+\t\t\tbreak;\n+\n+\t\tif (unlikely(p_opt[1] < 2 || p_opt[1] > len))\n+\t\t\tbreak;\n+\n+\t\tif (RTE_IPV4_IPOPT_COPIED(*p_opt)) {\n+\t\t\trte_memcpy(ipopt_frag_hdr + ipopt_len,\n+\t\t\t\tp_opt, p_opt[1]);\n+\t\t\tipopt_len += p_opt[1];\n+\t\t}\n+\n+\t\tlen -= p_opt[1];\n+\t\tp_opt += p_opt[1];\n+\t}\n+\n+\tlen = RTE_ALIGN_CEIL(ipopt_len, RTE_IPV4_IHL_MULTIPLIER);\n+\tmemset(ipopt_frag_hdr + ipopt_len,\n+\t\tRTE_IPV4_IPOPT_EOL, len - ipopt_len);\n+\tipopt_len = len;\n+\tiph_opt->ihl = (sizeof(struct rte_ipv4_hdr) + ipopt_len) /\n+\t\tRTE_IPV4_IHL_MULTIPLIER;\n+\n+\treturn ipopt_len;\n+}\n+\n /**\n  * IPv4 fragmentation.\n  *\n@@ -76,6 +121,8 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)\n \tuint32_t more_in_segs;\n \tuint16_t fragment_offset, flag_offset, frag_size, header_len;\n \tuint16_t frag_bytes_remaining;\n+\tuint8_t ipopt_frag_hdr[IPV4_HDR_MAX_LEN];\n+\tuint16_t ipopt_len;\n \n \t/*\n \t * Formal parameter checking.\n@@ -118,6 +165,10 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)\n \tout_pkt_pos = 0;\n \tfragment_offset = 0;\n \n+\tipopt_len = header_len - sizeof(struct rte_ipv4_hdr);\n+\tif (unlikely(ipopt_len > RTE_IPV4_IPOPT_MAX_LEN))\n+\t\treturn -EINVAL;\n+\n \tmore_in_segs = 1;\n \twhile (likely(more_in_segs)) {\n \t\tstruct rte_mbuf *out_pkt = NULL, *out_seg_prev = NULL;\n@@ -188,10 +239,21 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)\n \t\t    (uint16_t)out_pkt->pkt_len,\n \t\t    flag_offset, fragment_offset, more_in_segs);\n \n-\t\tfragment_offset = (uint16_t)(fragment_offset +\n-\t\t    out_pkt->pkt_len - header_len);\n-\n-\t\tout_pkt->l3_len = header_len;\n+\t\tif (unlikely((fragment_offset == 0) && (ipopt_len) &&\n+\t\t\t    ((flag_offset & RTE_IPV4_HDR_OFFSET_MASK) == 0))) {\n+\t\t\tipopt_len = __create_ipopt_frag_hdr((uint8_t *)in_hdr,\n+\t\t\t\tipopt_len, ipopt_frag_hdr);\n+\t\t\tfragment_offset = (uint16_t)(fragment_offset +\n+\t\t\t\tout_pkt->pkt_len - header_len);\n+\t\t\tout_pkt->l3_len = header_len;\n+\n+\t\t\theader_len = sizeof(struct rte_ipv4_hdr) + ipopt_len;\n+\t\t\tin_hdr = (struct rte_ipv4_hdr *)ipopt_frag_hdr;\n+\t\t} else {\n+\t\t\tfragment_offset = (uint16_t)(fragment_offset +\n+\t\t\t\tout_pkt->pkt_len - header_len);\n+\t\t\tout_pkt->l3_len = header_len;\n+\t\t}\n \n \t\t/* Write the fragment to the output list */\n \t\tpkts_out[out_pkt_pos] = out_pkt;\n",
    "prefixes": [
        "v4"
    ]
}