get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 55410,
    "url": "http://patches.dpdk.org/api/patches/55410/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20190626132617.10576-3-mariuszx.drost@intel.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": "<20190626132617.10576-3-mariuszx.drost@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20190626132617.10576-3-mariuszx.drost@intel.com",
    "date": "2019-06-26T13:26:17",
    "name": "[v2,2/2] examples/ipsec-secgw: fix not working inline ipsec modes",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "0715bb1fb202f181e3b69f0f4d37cfc8e8bdb420",
    "submitter": {
        "id": 1334,
        "url": "http://patches.dpdk.org/api/people/1334/?format=api",
        "name": "Mariusz Drost",
        "email": "mariuszx.drost@intel.com"
    },
    "delegate": {
        "id": 6690,
        "url": "http://patches.dpdk.org/api/users/6690/?format=api",
        "username": "akhil",
        "first_name": "akhil",
        "last_name": "goyal",
        "email": "gakhil@marvell.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20190626132617.10576-3-mariuszx.drost@intel.com/mbox/",
    "series": [
        {
            "id": 5177,
            "url": "http://patches.dpdk.org/api/series/5177/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=5177",
            "date": "2019-06-26T13:26:15",
            "name": "fixes for inline-crypto ipsec",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/5177/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/55410/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/55410/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 252052C6D;\n\tWed, 26 Jun 2019 15:29:23 +0200 (CEST)",
            "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby dpdk.org (Postfix) with ESMTP id C5A512BB5\n\tfor <dev@dpdk.org>; Wed, 26 Jun 2019 15:29:18 +0200 (CEST)",
            "from fmsmga001.fm.intel.com ([10.253.24.23])\n\tby orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t26 Jun 2019 06:29:18 -0700",
            "from mdrostx-mobl.ger.corp.intel.com ([10.103.104.107])\n\tby fmsmga001.fm.intel.com with ESMTP; 26 Jun 2019 06:29:16 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.63,420,1557212400\"; d=\"scan'208\";a=\"183173213\"",
        "From": "Mariusz Drost <mariuszx.drost@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "akhil.goyal@nxp.com, Mariusz Drost <mariuszx.drost@intel.com>,\n\tKonstantin Ananyev <konstantin.ananyev@intel.com>",
        "Date": "Wed, 26 Jun 2019 15:26:17 +0200",
        "Message-Id": "<20190626132617.10576-3-mariuszx.drost@intel.com>",
        "X-Mailer": "git-send-email 2.21.0.windows.1",
        "In-Reply-To": "<20190626132617.10576-1-mariuszx.drost@intel.com>",
        "References": "<??20190604100644.13724-1-mariuszx.drost@intel.com>\n\t<20190626132617.10576-1-mariuszx.drost@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v2 2/2] examples/ipsec-secgw: fix not working\n\tinline ipsec modes",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<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\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Application ipsec-secgw is not working for IPv4 transport mode and for\nIPv6 both transport and tunnel mode.\n\nIPv6 tunnel mode is not working due to wrongly assigned fields of\nsecurity association patterns, as it was IPv4, during creation of\ninline crypto session.\n\nIPv6 and IPv4 transport mode is iterating through security capabilities\nuntil it reaches tunnel, which causes session to be created as tunnel,\ninstead of transport. Another issue, is that config file does not\nprovide source and destination ip addresses for transport mode, which\nare required by NIC to perform inline crypto. It uses default addresses\nstored in security association (all zeroes), which causes dropped\npackages.\n\nTo fix that, reorganization of code in create_session() is needed,\nto behave appropriately to given protocol (IPv6/IPv4). Change in\niteration through security capabilities is also required, to check\nfor expected mode (not only tunnel).\n\nFor lack of addresses issue, some resolving mechanism is needed.\nApproach is to store addresses in security association, as it is\nfor tunnel mode. Difference is that they are obtained from sp rules,\ninstead of config file. To do that, sp[4/6]_spi_present() function\nis used to find addresses based on spi value, and then stored in\ncorresponding sa rule. This approach assumes, that every sp rule\nfor inline crypto have valid addresses, as well as range of addresses\nis not supported.\n\nNew flags for ipsec_sa structure are required to distinguish between\nIPv4 and IPv6 transport modes. Because of that, there is need to\nchange all checks done on these flags, so they work as expected.\n\nFixes: ec17993a145a (\"examples/ipsec-secgw: support security offload\")\nFixes: 9a0752f498d2 (\"net/ixgbe: enable inline IPsec\")\n\nSigned-off-by: Mariusz Drost <mariuszx.drost@intel.com>\nAcked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\nTested-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\n---\n examples/ipsec-secgw/esp.c   |  17 ++--\n examples/ipsec-secgw/ipsec.c |  21 +++--\n examples/ipsec-secgw/ipsec.h |  29 ++++++-\n examples/ipsec-secgw/sa.c    | 160 +++++++++++++++++++++++++----------\n examples/ipsec-secgw/sp4.c   |  24 +++++-\n examples/ipsec-secgw/sp6.c   |  42 ++++++++-\n 6 files changed, 225 insertions(+), 68 deletions(-)",
    "diff": "diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c\nindex f11d095ba..d6d7b1256 100644\n--- a/examples/ipsec-secgw/esp.c\n+++ b/examples/ipsec-secgw/esp.c\n@@ -192,7 +192,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,\n \t\t}\n \t}\n \n-\tif (unlikely(sa->flags == TRANSPORT)) {\n+\tif (unlikely(IS_TRANSPORT(sa->flags))) {\n \t\tip = rte_pktmbuf_mtod(m, struct ip *);\n \t\tip4 = (struct ip *)rte_pktmbuf_adj(m,\n \t\t\t\tsizeof(struct rte_esp_hdr) + sa->iv_len);\n@@ -233,13 +233,13 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,\n \n \tip4 = rte_pktmbuf_mtod(m, struct ip *);\n \tif (likely(ip4->ip_v == IPVERSION)) {\n-\t\tif (unlikely(sa->flags == TRANSPORT)) {\n+\t\tif (unlikely(IS_TRANSPORT(sa->flags))) {\n \t\t\tip_hdr_len = ip4->ip_hl * 4;\n \t\t\tnlp = ip4->ip_p;\n \t\t} else\n \t\t\tnlp = IPPROTO_IPIP;\n \t} else if (ip4->ip_v == IP6_VERSION) {\n-\t\tif (unlikely(sa->flags == TRANSPORT)) {\n+\t\tif (unlikely(IS_TRANSPORT(sa->flags))) {\n \t\t\t/* XXX No option headers supported */\n \t\t\tip_hdr_len = sizeof(struct ip6_hdr);\n \t\t\tip6 = (struct ip6_hdr *)ip4;\n@@ -257,14 +257,13 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,\n \t\t\tip_hdr_len + 2, sa->block_size);\n \tpad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);\n \n-\tRTE_ASSERT(sa->flags == IP4_TUNNEL || sa->flags == IP6_TUNNEL ||\n-\t\t\tsa->flags == TRANSPORT);\n+\tRTE_ASSERT(IS_TUNNEL(sa->flags) || IS_TRANSPORT(sa->flags));\n \n-\tif (likely(sa->flags == IP4_TUNNEL))\n+\tif (likely(IS_IP4_TUNNEL(sa->flags)))\n \t\tip_hdr_len = sizeof(struct ip);\n-\telse if (sa->flags == IP6_TUNNEL)\n+\telse if (IS_IP6_TUNNEL(sa->flags))\n \t\tip_hdr_len = sizeof(struct ip6_hdr);\n-\telse if (sa->flags != TRANSPORT) {\n+\telse if (!IS_TRANSPORT(sa->flags)) {\n \t\tRTE_LOG(ERR, IPSEC_ESP, \"Unsupported SA flags: 0x%x\\n\",\n \t\t\t\tsa->flags);\n \t\treturn -EINVAL;\n@@ -291,7 +290,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,\n \t\trte_prefetch0(padding);\n \t}\n \n-\tswitch (sa->flags) {\n+\tswitch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {\n \tcase IP4_TUNNEL:\n \t\tip4 = ip4ip_outbound(m, sizeof(struct rte_esp_hdr) + sa->iv_len,\n \t\t\t\t&sa->src, &sa->dst);\ndiff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c\nindex 7b8533077..d1cbdc38d 100644\n--- a/examples/ipsec-secgw/ipsec.c\n+++ b/examples/ipsec-secgw/ipsec.c\n@@ -23,7 +23,7 @@ set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)\n \tif (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {\n \t\tstruct rte_security_ipsec_tunnel_param *tunnel =\n \t\t\t\t&ipsec->tunnel;\n-\t\tif (sa->flags == IP4_TUNNEL) {\n+\t\tif (IS_IP4_TUNNEL(sa->flags)) {\n \t\t\ttunnel->type =\n \t\t\t\tRTE_SECURITY_IPSEC_TUNNEL_IPV4;\n \t\t\ttunnel->ipv4.ttl = IPDEFTTL;\n@@ -83,8 +83,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)\n \t\t\t\t.options = { 0 },\n \t\t\t\t.direction = sa->direction,\n \t\t\t\t.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,\n-\t\t\t\t.mode = (sa->flags == IP4_TUNNEL ||\n-\t\t\t\t\t\tsa->flags == IP6_TUNNEL) ?\n+\t\t\t\t.mode = (IS_TUNNEL(sa->flags)) ?\n \t\t\t\t\tRTE_SECURITY_IPSEC_SA_MODE_TUNNEL :\n \t\t\t\t\tRTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,\n \t\t\t} },\n@@ -134,7 +133,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)\n \t\t\t\t    sec_cap->protocol ==\n \t\t\t\t\tRTE_SECURITY_PROTOCOL_IPSEC &&\n \t\t\t\t    sec_cap->ipsec.mode ==\n-\t\t\t\t\tRTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&\n+\t\t\t\t\tsess_conf.ipsec.mode &&\n \t\t\t\t    sec_cap->ipsec.direction == sa->direction)\n \t\t\t\t\tbreak;\n \t\t\t\tsec_cap++;\n@@ -150,16 +149,20 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)\n \t\t\tsa->security_ctx = ctx;\n \t\t\tsa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;\n \n-\t\t\tsa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;\n-\t\t\tsa->pattern[1].mask = &rte_flow_item_ipv4_mask;\n-\t\t\tif (sa->flags & IP6_TUNNEL) {\n+\t\t\tif (IS_IP6(sa->flags)) {\n+\t\t\t\tsa->pattern[1].mask = &rte_flow_item_ipv6_mask;\n+\t\t\t\tsa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;\n \t\t\t\tsa->pattern[1].spec = &sa->ipv6_spec;\n+\n \t\t\t\tmemcpy(sa->ipv6_spec.hdr.dst_addr,\n \t\t\t\t\tsa->dst.ip.ip6.ip6_b, 16);\n \t\t\t\tmemcpy(sa->ipv6_spec.hdr.src_addr,\n \t\t\t\t       sa->src.ip.ip6.ip6_b, 16);\n-\t\t\t} else {\n+\t\t\t} else if (IS_IP4(sa->flags)) {\n+\t\t\t\tsa->pattern[1].mask = &rte_flow_item_ipv4_mask;\n+\t\t\t\tsa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;\n \t\t\t\tsa->pattern[1].spec = &sa->ipv4_spec;\n+\n \t\t\t\tsa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;\n \t\t\t\tsa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;\n \t\t\t}\n@@ -303,7 +306,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)\n \t\t\t\t    sec_cap->protocol ==\n \t\t\t\t\tRTE_SECURITY_PROTOCOL_IPSEC &&\n \t\t\t\t    sec_cap->ipsec.mode ==\n-\t\t\t\t\tRTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&\n+\t\t\t\t\tsess_conf.ipsec.mode &&\n \t\t\t\t    sec_cap->ipsec.direction == sa->direction)\n \t\t\t\t\tbreak;\n \t\t\t\tsec_cap++;\ndiff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h\nindex e9272d74b..88bd24dc1 100644\n--- a/examples/ipsec-secgw/ipsec.h\n+++ b/examples/ipsec-secgw/ipsec.h\n@@ -101,6 +101,8 @@ struct ipsec_sa {\n #define IP4_TUNNEL (1 << 0)\n #define IP6_TUNNEL (1 << 1)\n #define TRANSPORT  (1 << 2)\n+#define IP4_TRANSPORT (1 << 3)\n+#define IP6_TRANSPORT (1 << 4)\n \tstruct ip_addr src;\n \tstruct ip_addr dst;\n \tuint8_t cipher_key[MAX_KEY_SIZE];\n@@ -139,6 +141,27 @@ struct ipsec_mbuf_metadata {\n \tuint8_t buf[32];\n } __rte_cache_aligned;\n \n+#define IS_TRANSPORT(flags) ((flags) & TRANSPORT)\n+\n+#define IS_TUNNEL(flags) ((flags) & (IP4_TUNNEL | IP6_TUNNEL))\n+\n+#define IS_IP4(flags) ((flags) & (IP4_TUNNEL | IP4_TRANSPORT))\n+\n+#define IS_IP6(flags) ((flags) & (IP6_TUNNEL | IP6_TRANSPORT))\n+\n+#define IS_IP4_TUNNEL(flags) ((flags) & IP4_TUNNEL)\n+\n+#define IS_IP6_TUNNEL(flags) ((flags) & IP6_TUNNEL)\n+\n+/*\n+ * Macro for getting ipsec_sa flags statuses without version of protocol\n+ * used for transport (IP4_TRANSPORT and IP6_TRANSPORT flags).\n+ */\n+#define WITHOUT_TRANSPORT_VERSION(flags) \\\n+\t\t((flags) & (IP4_TUNNEL | \\\n+\t\t\tIP6_TUNNEL | \\\n+\t\t\tTRANSPORT))\n+\n struct cdev_qp {\n \tuint16_t id;\n \tuint16_t qp;\n@@ -283,9 +306,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id);\n  * or -ENOENT otherwise.\n  */\n int\n-sp4_spi_present(uint32_t spi, int inbound);\n+sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],\n+\t\t\tuint32_t mask[2]);\n int\n-sp6_spi_present(uint32_t spi, int inbound);\n+sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],\n+\t\t\tuint32_t mask[2]);\n \n /*\n  * Search through SA entries for given SPI.\ndiff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c\nindex 8d47d1def..e3c809d89 100644\n--- a/examples/ipsec-secgw/sa.c\n+++ b/examples/ipsec-secgw/sa.c\n@@ -27,6 +27,10 @@\n \n #define IPDEFTTL 64\n \n+#define IP4_FULL_MASK (sizeof(((struct ip_addr *)NULL)->ip.ip4) * CHAR_BIT)\n+\n+#define IP6_FULL_MASK (sizeof(((struct ip_addr *)NULL)->ip.ip6.ip6) * CHAR_BIT)\n+\n struct supported_cipher_algo {\n \tconst char *keyword;\n \tenum rte_crypto_cipher_algorithm algo;\n@@ -468,7 +472,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\tif (status->status < 0)\n \t\t\t\treturn;\n \n-\t\t\tif (rule->flags == IP4_TUNNEL) {\n+\t\t\tif (IS_IP4_TUNNEL(rule->flags)) {\n \t\t\t\tstruct in_addr ip;\n \n \t\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti],\n@@ -480,7 +484,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\t\t\treturn;\n \t\t\t\trule->src.ip.ip4 = rte_bswap32(\n \t\t\t\t\t(uint32_t)ip.s_addr);\n-\t\t\t} else if (rule->flags == IP6_TUNNEL) {\n+\t\t\t} else if (IS_IP6_TUNNEL(rule->flags)) {\n \t\t\t\tstruct in6_addr ip;\n \n \t\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n@@ -492,7 +496,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\t\t\treturn;\n \t\t\t\tmemcpy(rule->src.ip.ip6.ip6_b,\n \t\t\t\t\tip.s6_addr, 16);\n-\t\t\t} else if (rule->flags == TRANSPORT) {\n+\t\t\t} else if (IS_TRANSPORT(rule->flags)) {\n \t\t\t\tAPP_CHECK(0, status, \"unrecognized input \"\n \t\t\t\t\t\"\\\"%s\\\"\", tokens[ti]);\n \t\t\t\treturn;\n@@ -511,7 +515,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\tif (status->status < 0)\n \t\t\t\treturn;\n \n-\t\t\tif (rule->flags == IP4_TUNNEL) {\n+\t\t\tif (IS_IP4_TUNNEL(rule->flags)) {\n \t\t\t\tstruct in_addr ip;\n \n \t\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti],\n@@ -523,7 +527,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\t\t\treturn;\n \t\t\t\trule->dst.ip.ip4 = rte_bswap32(\n \t\t\t\t\t(uint32_t)ip.s_addr);\n-\t\t\t} else if (rule->flags == IP6_TUNNEL) {\n+\t\t\t} else if (IS_IP6_TUNNEL(rule->flags)) {\n \t\t\t\tstruct in6_addr ip;\n \n \t\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n@@ -534,7 +538,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,\n \t\t\t\tif (status->status < 0)\n \t\t\t\t\treturn;\n \t\t\t\tmemcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16);\n-\t\t\t} else if (rule->flags == TRANSPORT) {\n+\t\t\t} else if (IS_TRANSPORT(rule->flags)) {\n \t\t\t\tAPP_CHECK(0, status, \"unrecognized \"\n \t\t\t\t\t\"input \\\"%s\\\"\",\ttokens[ti]);\n \t\t\t\treturn;\n@@ -663,7 +667,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)\n \n \tprintf(\"mode:\");\n \n-\tswitch (sa->flags) {\n+\tswitch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {\n \tcase IP4_TUNNEL:\n \t\tprintf(\"IP4Tunnel \");\n \t\tuint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);\n@@ -774,6 +778,93 @@ check_eth_dev_caps(uint16_t portid, uint32_t inbound)\n \treturn 0;\n }\n \n+/*\n+ * Helper function, tries to determine next_proto for SPI\n+ * by searching though SP rules.\n+ */\n+static int\n+get_spi_proto(uint32_t spi, enum rte_security_ipsec_sa_direction dir,\n+\t\tstruct ip_addr ip_addr[2], uint32_t mask[2])\n+{\n+\tint32_t rc4, rc6;\n+\n+\trc4 = sp4_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS,\n+\t\t\t\tip_addr, mask);\n+\trc6 = sp6_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS,\n+\t\t\t\tip_addr, mask);\n+\n+\tif (rc4 >= 0) {\n+\t\tif (rc6 >= 0) {\n+\t\t\tRTE_LOG(ERR, IPSEC,\n+\t\t\t\t\"%s: SPI %u used simultaeously by \"\n+\t\t\t\t\"IPv4(%d) and IPv6 (%d) SP rules\\n\",\n+\t\t\t\t__func__, spi, rc4, rc6);\n+\t\t\treturn -EINVAL;\n+\t\t} else\n+\t\t\treturn IPPROTO_IPIP;\n+\t} else if (rc6 < 0) {\n+\t\tRTE_LOG(ERR, IPSEC,\n+\t\t\t\"%s: SPI %u is not used by any SP rule\\n\",\n+\t\t\t__func__, spi);\n+\t\treturn -EINVAL;\n+\t} else\n+\t\treturn IPPROTO_IPV6;\n+}\n+\n+/*\n+ * Helper function for getting source and destination IP addresses\n+ * from SP. Needed for inline crypto transport mode, as addresses are not\n+ * provided in config file for that mode. It checks if SP for current SA exists,\n+ * and based on what type of protocol is returned, it stores appropriate\n+ * addresses got from SP into SA.\n+ */\n+static int\n+sa_add_address_inline_crypto(struct ipsec_sa *sa)\n+{\n+\tint protocol;\n+\tstruct ip_addr ip_addr[2];\n+\tuint32_t mask[2];\n+\n+\tprotocol = get_spi_proto(sa->spi, sa->direction, ip_addr, mask);\n+\tif (protocol < 0)\n+\t\treturn protocol;\n+\telse if (protocol == IPPROTO_IPIP) {\n+\t\tsa->flags |= IP4_TRANSPORT;\n+\t\tif (mask[0] == IP4_FULL_MASK &&\n+\t\t\t\tmask[1] == IP4_FULL_MASK &&\n+\t\t\t\tip_addr[0].ip.ip4 != 0 &&\n+\t\t\t\tip_addr[1].ip.ip4 != 0) {\n+\n+\t\t\tsa->src.ip.ip4 = ip_addr[0].ip.ip4;\n+\t\t\tsa->dst.ip.ip4 = ip_addr[1].ip.ip4;\n+\t\t} else {\n+\t\t\tRTE_LOG(ERR, IPSEC,\n+\t\t\t\"%s: No valid address or mask entry in\"\n+\t\t\t\" IPv4 SP rule for SPI %u\\n\",\n+\t\t\t__func__, sa->spi);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t} else if (protocol == IPPROTO_IPV6) {\n+\t\tsa->flags |= IP6_TRANSPORT;\n+\t\tif (mask[0] == IP6_FULL_MASK &&\n+\t\t\t\tmask[1] == IP6_FULL_MASK &&\n+\t\t\t\t(ip_addr[0].ip.ip6.ip6[0] != 0 ||\n+\t\t\t\tip_addr[0].ip.ip6.ip6[1] != 0) &&\n+\t\t\t\t(ip_addr[1].ip.ip6.ip6[0] != 0 ||\n+\t\t\t\tip_addr[1].ip.ip6.ip6[1] != 0)) {\n+\n+\t\t\tsa->src.ip.ip6 = ip_addr[0].ip.ip6;\n+\t\t\tsa->dst.ip.ip6 = ip_addr[1].ip.ip6;\n+\t\t} else {\n+\t\t\tRTE_LOG(ERR, IPSEC,\n+\t\t\t\"%s: No valid address or mask entry in\"\n+\t\t\t\" IPv6 SP rule for SPI %u\\n\",\n+\t\t\t__func__, sa->spi);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n \n static int\n sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],\n@@ -782,6 +873,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],\n \tstruct ipsec_sa *sa;\n \tuint32_t i, idx;\n \tuint16_t iv_length, aad_length;\n+\tint inline_status;\n \n \t/* for ESN upper 32 bits of SQN also need to be part of AAD */\n \taad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;\n@@ -807,10 +899,20 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],\n \t\t\t\tRTE_SECURITY_IPSEC_SA_DIR_INGRESS :\n \t\t\t\tRTE_SECURITY_IPSEC_SA_DIR_EGRESS;\n \n-\t\tswitch (sa->flags) {\n+\t\tswitch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {\n \t\tcase IP4_TUNNEL:\n \t\t\tsa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);\n \t\t\tsa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);\n+\t\t\tbreak;\n+\t\tcase TRANSPORT:\n+\t\t\tif (sa->type ==\n+\t\t\t\tRTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {\n+\t\t\t\tinline_status =\n+\t\t\t\t\tsa_add_address_inline_crypto(sa);\n+\t\t\t\tif (inline_status < 0)\n+\t\t\t\t\treturn inline_status;\n+\t\t\t}\n+\t\t\tbreak;\n \t\t}\n \n \t\tif (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {\n@@ -935,36 +1037,6 @@ fill_ipsec_app_sa_prm(struct rte_ipsec_sa_prm *prm,\n \tprm->replay_win_sz = app_prm->window_size;\n }\n \n-/*\n- * Helper function, tries to determine next_proto for SPI\n- * by searching though SP rules.\n- */\n-static int\n-get_spi_proto(uint32_t spi, enum rte_security_ipsec_sa_direction dir)\n-{\n-\tint32_t rc4, rc6;\n-\n-\trc4 = sp4_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS);\n-\trc6 = sp6_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS);\n-\n-\tif (rc4 >= 0) {\n-\t\tif (rc6 >= 0) {\n-\t\t\tRTE_LOG(ERR, IPSEC,\n-\t\t\t\t\"%s: SPI %u used simultaeously by \"\n-\t\t\t\t\"RTE_IPV4(%d) and IPv6 (%d) SP rules\\n\",\n-\t\t\t\t__func__, spi, rc4, rc6);\n-\t\t\treturn -EINVAL;\n-\t\t} else\n-\t\t\treturn IPPROTO_IPIP;\n-\t} else if (rc6 < 0) {\n-\t\tRTE_LOG(ERR, IPSEC,\n-\t\t\t\"%s: SPI %u is not used by any SP rule\\n\",\n-\t\t\t__func__, spi);\n-\t\treturn -EINVAL;\n-\t} else\n-\t\treturn IPPROTO_IPV6;\n-}\n-\n static int\n fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,\n \tconst struct rte_ipv4_hdr *v4, struct rte_ipv6_hdr *v6)\n@@ -976,7 +1048,7 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,\n \t * probably not the optimal way, but there seems nothing\n \t * better right now.\n \t */\n-\trc = get_spi_proto(ss->spi, ss->direction);\n+\trc = get_spi_proto(ss->spi, ss->direction, NULL, NULL);\n \tif (rc < 0)\n \t\treturn rc;\n \n@@ -988,16 +1060,16 @@ fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,\n \tprm->ipsec_xform.salt = ss->salt;\n \tprm->ipsec_xform.direction = ss->direction;\n \tprm->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;\n-\tprm->ipsec_xform.mode = (ss->flags == TRANSPORT) ?\n+\tprm->ipsec_xform.mode = (IS_TRANSPORT(ss->flags)) ?\n \t\tRTE_SECURITY_IPSEC_SA_MODE_TRANSPORT :\n \t\tRTE_SECURITY_IPSEC_SA_MODE_TUNNEL;\n \n-\tif (ss->flags == IP4_TUNNEL) {\n+\tif (IS_IP4_TUNNEL(ss->flags)) {\n \t\tprm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;\n \t\tprm->tun.hdr_len = sizeof(*v4);\n \t\tprm->tun.next_proto = rc;\n \t\tprm->tun.hdr = v4;\n-\t} else if (ss->flags == IP6_TUNNEL) {\n+\t} else if (IS_IP6_TUNNEL(ss->flags)) {\n \t\tprm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV6;\n \t\tprm->tun.hdr_len = sizeof(*v6);\n \t\tprm->tun.next_proto = rc;\n@@ -1051,7 +1123,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)\n \t\t.proto = IPPROTO_ESP,\n \t};\n \n-\tif (lsa->flags == IP6_TUNNEL) {\n+\tif (IS_IP6_TUNNEL(lsa->flags)) {\n \t\tmemcpy(v6.src_addr, lsa->src.ip.ip6.ip6_b, sizeof(v6.src_addr));\n \t\tmemcpy(v6.dst_addr, lsa->dst.ip.ip6.ip6_b, sizeof(v6.dst_addr));\n \t}\n@@ -1240,7 +1312,7 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,\n \tif (rte_be_to_cpu_32(esp->spi) != sa->spi)\n \t\treturn;\n \n-\tswitch (sa->flags) {\n+\tswitch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {\n \tcase IP4_TUNNEL:\n \t\tsrc4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));\n \t\tif ((ip->ip_v == IPVERSION) &&\ndiff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c\nindex ca9ee7f24..3871c6cc1 100644\n--- a/examples/ipsec-secgw/sp4.c\n+++ b/examples/ipsec-secgw/sp4.c\n@@ -17,6 +17,18 @@\n \n #define MAX_ACL_RULE_NUM\t1024\n \n+#define IPV4_DST_FROM_SP(acr) \\\n+\t\t(rte_cpu_to_be_32((acr).field[DST_FIELD_IPV4].value.u32))\n+\n+#define IPV4_SRC_FROM_SP(acr) \\\n+\t\t(rte_cpu_to_be_32((acr).field[SRC_FIELD_IPV4].value.u32))\n+\n+#define IPV4_DST_MASK_FROM_SP(acr) \\\n+\t\t((acr).field[DST_FIELD_IPV4].mask_range.u32)\n+\n+#define IPV4_SRC_MASK_FROM_SP(acr) \\\n+\t\t((acr).field[SRC_FIELD_IPV4].mask_range.u32)\n+\n /*\n  * Rule and trace formats definitions.\n  */\n@@ -552,7 +564,8 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)\n  * Search though SP rules for given SPI.\n  */\n int\n-sp4_spi_present(uint32_t spi, int inbound)\n+sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],\n+\t\t\tuint32_t mask[2])\n {\n \tuint32_t i, num;\n \tconst struct acl4_rules *acr;\n@@ -566,8 +579,15 @@ sp4_spi_present(uint32_t spi, int inbound)\n \t}\n \n \tfor (i = 0; i != num; i++) {\n-\t\tif (acr[i].data.userdata == spi)\n+\t\tif (acr[i].data.userdata == spi) {\n+\t\t\tif (NULL != ip_addr && NULL != mask) {\n+\t\t\t\tip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(acr[i]);\n+\t\t\t\tip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(acr[i]);\n+\t\t\t\tmask[0] = IPV4_SRC_MASK_FROM_SP(acr[i]);\n+\t\t\t\tmask[1] = IPV4_DST_MASK_FROM_SP(acr[i]);\n+\t\t\t}\n \t\t\treturn i;\n+\t\t}\n \t}\n \n \treturn -ENOENT;\ndiff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c\nindex 76be3d3e9..d8be6b1bd 100644\n--- a/examples/ipsec-secgw/sp6.c\n+++ b/examples/ipsec-secgw/sp6.c\n@@ -17,6 +17,36 @@\n \n #define MAX_ACL_RULE_NUM\t1024\n \n+#define IPV6_FROM_SP(acr, fidx_low, fidx_high) \\\n+\t\t(((uint64_t)(acr).field[(fidx_high)].value.u32 << 32) | \\\n+\t\t(acr).field[(fidx_low)].value.u32)\n+\n+#define IPV6_DST_FROM_SP(addr, acr) do {\\\n+\t\t(addr).ip.ip6.ip6[0] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \\\n+\t\t\t\t\t\tIP6_DST1, IP6_DST0));\\\n+\t\t(addr).ip.ip6.ip6[1] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \\\n+\t\t\t\t\t\tIP6_DST3, IP6_DST2));\\\n+\t\t} while (0)\n+\n+#define IPV6_SRC_FROM_SP(addr, acr) do {\\\n+\t\t(addr).ip.ip6.ip6[0] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \\\n+\t\t\t\t\t\t\tIP6_SRC1, IP6_SRC0));\\\n+\t\t(addr).ip.ip6.ip6[1] = rte_cpu_to_be_64(IPV6_FROM_SP((acr), \\\n+\t\t\t\t\t\t\tIP6_SRC3, IP6_SRC2));\\\n+\t\t} while (0)\n+\n+#define IPV6_DST_MASK_FROM_SP(mask, acr) \\\n+\t\t((mask) = (acr).field[IP6_DST0].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_DST1].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_DST2].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_DST3].mask_range.u32)\n+\n+#define IPV6_SRC_MASK_FROM_SP(mask, acr) \\\n+\t\t((mask) = (acr).field[IP6_SRC0].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_SRC1].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_SRC2].mask_range.u32 + \\\n+\t\t\t(acr).field[IP6_SRC3].mask_range.u32)\n+\n enum {\n \tIP6_PROTO,\n \tIP6_SRC0,\n@@ -666,7 +696,8 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)\n  * Search though SP rules for given SPI.\n  */\n int\n-sp6_spi_present(uint32_t spi, int inbound)\n+sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],\n+\t\t\tuint32_t mask[2])\n {\n \tuint32_t i, num;\n \tconst struct acl6_rules *acr;\n@@ -680,8 +711,15 @@ sp6_spi_present(uint32_t spi, int inbound)\n \t}\n \n \tfor (i = 0; i != num; i++) {\n-\t\tif (acr[i].data.userdata == spi)\n+\t\tif (acr[i].data.userdata == spi) {\n+\t\t\tif (NULL != ip_addr && NULL != mask) {\n+\t\t\t\tIPV6_SRC_FROM_SP(ip_addr[0], acr[i]);\n+\t\t\t\tIPV6_DST_FROM_SP(ip_addr[1], acr[i]);\n+\t\t\t\tIPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);\n+\t\t\t\tIPV6_DST_MASK_FROM_SP(mask[1], acr[i]);\n+\t\t\t}\n \t\t\treturn i;\n+\t\t}\n \t}\n \n \treturn -ENOENT;\n",
    "prefixes": [
        "v2",
        "2/2"
    ]
}