get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 48149,
    "url": "http://patches.dpdk.org/api/patches/48149/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1542326031-5263-8-git-send-email-konstantin.ananyev@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": "<1542326031-5263-8-git-send-email-konstantin.ananyev@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1542326031-5263-8-git-send-email-konstantin.ananyev@intel.com",
    "date": "2018-11-15T23:53:49",
    "name": "[7/9] ipsec: rework SA replay window/SQN for MT environment",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b6f3a86e45948a38590d80e6a58a57df27b86a15",
    "submitter": {
        "id": 33,
        "url": "http://patches.dpdk.org/api/people/33/?format=api",
        "name": "Ananyev, Konstantin",
        "email": "konstantin.ananyev@intel.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/1542326031-5263-8-git-send-email-konstantin.ananyev@intel.com/mbox/",
    "series": [
        {
            "id": 2457,
            "url": "http://patches.dpdk.org/api/series/2457/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=2457",
            "date": "2018-11-15T23:53:49",
            "name": null,
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/2457/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/48149/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/48149/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 A5C0C58EC;\n\tFri, 16 Nov 2018 00:54:18 +0100 (CET)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id 11A484D27\n\tfor <dev@dpdk.org>; Fri, 16 Nov 2018 00:54:09 +0100 (CET)",
            "from orsmga007.jf.intel.com ([10.7.209.58])\n\tby orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t15 Nov 2018 15:54:09 -0800",
            "from sivswdev08.ir.intel.com (HELO localhost.localdomain)\n\t([10.237.217.47])\n\tby orsmga007.jf.intel.com with ESMTP; 15 Nov 2018 15:54:08 -0800"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.56,238,1539673200\"; d=\"scan'208\";a=\"89697385\"",
        "From": "Konstantin Ananyev <konstantin.ananyev@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "Konstantin Ananyev <konstantin.ananyev@intel.com>",
        "Date": "Thu, 15 Nov 2018 23:53:49 +0000",
        "Message-Id": "<1542326031-5263-8-git-send-email-konstantin.ananyev@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": "<1535129598-27301-1-git-send-email-konstantin.ananyev@intel.com>",
        "References": "<1535129598-27301-1-git-send-email-konstantin.ananyev@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 7/9] ipsec: rework SA replay window/SQN for MT\n\tenvironment",
        "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": "With these changes functions:\n  - rte_ipsec_pkt_crypto_prepare\n  - rte_ipsec_pkt_process\n can be safely used in MT environment, as long as the user can guarantee\n that they obey multiple readers/single writer model for SQN+replay_window\n operations.\n To be more specific:\n for outbound SA there are no restrictions.\n for inbound SA the caller has to guarantee that at any given moment\n only one thread is executing rte_ipsec_pkt_process() for given SA.\n Note that it is caller responsibility to maintain correct order\n of packets to be processed.\n\nSigned-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\n---\n lib/librte_ipsec/ipsec_sqn.h    | 113 +++++++++++++++++++++++++++++++-\n lib/librte_ipsec/rte_ipsec_sa.h |  27 ++++++++\n lib/librte_ipsec/sa.c           |  23 +++++--\n lib/librte_ipsec/sa.h           |  21 +++++-\n 4 files changed, 176 insertions(+), 8 deletions(-)",
    "diff": "diff --git a/lib/librte_ipsec/ipsec_sqn.h b/lib/librte_ipsec/ipsec_sqn.h\nindex a33ff9cca..ee5e35978 100644\n--- a/lib/librte_ipsec/ipsec_sqn.h\n+++ b/lib/librte_ipsec/ipsec_sqn.h\n@@ -15,6 +15,8 @@\n \n #define IS_ESN(sa)\t((sa)->sqn_mask == UINT64_MAX)\n \n+#define\tSQN_ATOMIC(sa)\t((sa)->type & RTE_IPSEC_SATP_SQN_ATOM)\n+\n /*\n  * gets SQN.hi32 bits, SQN supposed to be in network byte order.\n  */\n@@ -140,8 +142,12 @@ esn_outb_update_sqn(struct rte_ipsec_sa *sa, uint32_t *num)\n \tuint64_t n, s, sqn;\n \n \tn = *num;\n-\tsqn = sa->sqn.outb + n;\n-\tsa->sqn.outb = sqn;\n+\tif (SQN_ATOMIC(sa))\n+\t\tsqn = (uint64_t)rte_atomic64_add_return(&sa->sqn.outb.atom, n);\n+\telse {\n+\t\tsqn = sa->sqn.outb.raw + n;\n+\t\tsa->sqn.outb.raw = sqn;\n+\t}\n \n \t/* overflow */\n \tif (sqn > sa->sqn_mask) {\n@@ -231,4 +237,107 @@ rsn_size(uint32_t nb_bucket)\n \treturn sz;\n }\n \n+/**\n+ * Copy replay window and SQN.\n+ */\n+static inline void\n+rsn_copy(const struct rte_ipsec_sa *sa, uint32_t dst, uint32_t src)\n+{\n+\tuint32_t i, n;\n+\tstruct replay_sqn *d;\n+\tconst struct replay_sqn *s;\n+\n+\td = sa->sqn.inb.rsn[dst];\n+\ts = sa->sqn.inb.rsn[src];\n+\n+\tn = sa->replay.nb_bucket;\n+\n+\td->sqn = s->sqn;\n+\tfor (i = 0; i != n; i++)\n+\t\td->window[i] = s->window[i];\n+}\n+\n+/**\n+ * Get RSN for read-only access.\n+ */\n+static inline struct replay_sqn *\n+rsn_acquire(struct rte_ipsec_sa *sa)\n+{\n+\tuint32_t n;\n+\tstruct replay_sqn *rsn;\n+\n+\tn = sa->sqn.inb.rdidx;\n+\trsn = sa->sqn.inb.rsn[n];\n+\n+\tif (!SQN_ATOMIC(sa))\n+\t\treturn rsn;\n+\n+\t/* check there are no writers */\n+\twhile (rte_rwlock_read_trylock(&rsn->rwl) < 0) {\n+\t\trte_pause();\n+\t\tn = sa->sqn.inb.rdidx;\n+\t\trsn = sa->sqn.inb.rsn[n];\n+\t\trte_compiler_barrier();\n+\t}\n+\n+\treturn rsn;\n+}\n+\n+/**\n+ * Release read-only access for RSN.\n+ */\n+static inline void\n+rsn_release(struct rte_ipsec_sa *sa, struct replay_sqn *rsn)\n+{\n+\tif (SQN_ATOMIC(sa))\n+\t\trte_rwlock_read_unlock(&rsn->rwl);\n+}\n+\n+/**\n+ * Start RSN update.\n+ */\n+static inline struct replay_sqn *\n+rsn_update_start(struct rte_ipsec_sa *sa)\n+{\n+\tuint32_t k, n;\n+\tstruct replay_sqn *rsn;\n+\n+\tn = sa->sqn.inb.wridx;\n+\n+\t/* no active writers */\n+\tRTE_ASSERT(n == sa->sqn.inb.rdidx);\n+\n+\tif (!SQN_ATOMIC(sa))\n+\t\treturn sa->sqn.inb.rsn[n];\n+\n+\tk = REPLAY_SQN_NEXT(n);\n+\tsa->sqn.inb.wridx = k;\n+\n+\trsn = sa->sqn.inb.rsn[k];\n+\trte_rwlock_write_lock(&rsn->rwl);\n+\trsn_copy(sa, k, n);\n+\n+\treturn rsn;\n+}\n+\n+/**\n+ * Finish RSN update.\n+ */\n+static inline void\n+rsn_update_finish(struct rte_ipsec_sa *sa, struct replay_sqn *rsn)\n+{\n+\tuint32_t n;\n+\n+\tif (!SQN_ATOMIC(sa))\n+\t\treturn;\n+\n+\tn = sa->sqn.inb.wridx;\n+\tRTE_ASSERT(n != sa->sqn.inb.rdidx);\n+\tRTE_ASSERT(rsn - sa->sqn.inb.rsn == n);\n+\n+\trte_rwlock_write_unlock(&rsn->rwl);\n+\tsa->sqn.inb.rdidx = n;\n+}\n+\n+\n #endif /* _IPSEC_SQN_H_ */\ndiff --git a/lib/librte_ipsec/rte_ipsec_sa.h b/lib/librte_ipsec/rte_ipsec_sa.h\nindex 4e36fd99b..35a0afec1 100644\n--- a/lib/librte_ipsec/rte_ipsec_sa.h\n+++ b/lib/librte_ipsec/rte_ipsec_sa.h\n@@ -53,6 +53,27 @@ struct rte_ipsec_sa_prm {\n \t */\n };\n \n+/**\n+ * Indicates that SA will(/will not) need an 'atomic' access\n+ * to sequence number and replay window.\n+ * 'atomic' here means:\n+ * functions:\n+ *  - rte_ipsec_pkt_crypto_prepare\n+ *  - rte_ipsec_pkt_process\n+ * can be safely used in MT environment, as long as the user can guarantee\n+ * that they obey multiple readers/single writer model for SQN+replay_window\n+ * operations.\n+ * To be more specific:\n+ * for outbound SA there are no restrictions.\n+ * for inbound SA the caller has to guarantee that at any given moment\n+ * only one thread is executing rte_ipsec_pkt_process() for given SA.\n+ * Note that it is caller responsibility to maintain correct order\n+ * of packets to be processed.\n+ * In other words - it is a caller responsibility to serialize process()\n+ * invocations.\n+ */\n+#define\tRTE_IPSEC_SAFLAG_SQN_ATOM\t(1ULL << 0)\n+\n /**\n  * SA type is an 64-bit value that contain the following information:\n  * - IP version (IPv4/IPv6)\n@@ -60,6 +81,7 @@ struct rte_ipsec_sa_prm {\n  * - inbound/outbound\n  * - mode (TRANSPORT/TUNNEL)\n  * - for TUNNEL outer IP version (IPv4/IPv6)\n+ * - are SA SQN operations 'atomic'\n  * ...\n  */\n \n@@ -68,6 +90,7 @@ enum {\n \tRTE_SATP_LOG_PROTO,\n \tRTE_SATP_LOG_DIR,\n \tRTE_SATP_LOG_MODE,\n+\tRTE_SATP_LOG_SQN = RTE_SATP_LOG_MODE + 2,\n \tRTE_SATP_LOG_NUM\n };\n \n@@ -88,6 +111,10 @@ enum {\n #define RTE_IPSEC_SATP_MODE_TUNLV4\t(1ULL << RTE_SATP_LOG_MODE)\n #define RTE_IPSEC_SATP_MODE_TUNLV6\t(2ULL << RTE_SATP_LOG_MODE)\n \n+#define RTE_IPSEC_SATP_SQN_MASK\t\t(1ULL << RTE_SATP_LOG_SQN)\n+#define RTE_IPSEC_SATP_SQN_RAW\t\t(0ULL << RTE_SATP_LOG_SQN)\n+#define RTE_IPSEC_SATP_SQN_ATOM\t\t(1ULL << RTE_SATP_LOG_SQN)\n+\n /**\n  * get type of given SA\n  * @return\ndiff --git a/lib/librte_ipsec/sa.c b/lib/librte_ipsec/sa.c\nindex 00b3c8044..d35ed836b 100644\n--- a/lib/librte_ipsec/sa.c\n+++ b/lib/librte_ipsec/sa.c\n@@ -90,6 +90,9 @@ ipsec_sa_size(uint32_t wsz, uint64_t type, uint32_t *nb_bucket)\n \t*nb_bucket = n;\n \n \tsz = rsn_size(n);\n+\tif ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)\n+\t\tsz *= REPLAY_SQN_NUM;\n+\n \tsz += sizeof(struct rte_ipsec_sa);\n \treturn sz;\n }\n@@ -136,6 +139,12 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm)\n \t\t\ttp |= RTE_IPSEC_SATP_IPV4;\n \t}\n \n+\t/* interpret flags */\n+\tif (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)\n+\t\ttp |= RTE_IPSEC_SATP_SQN_ATOM;\n+\telse\n+\t\ttp |= RTE_IPSEC_SATP_SQN_RAW;\n+\n \treturn tp;\n }\n \n@@ -159,7 +168,7 @@ esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)\n static void\n esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)\n {\n-\tsa->sqn.outb = 1;\n+\tsa->sqn.outb.raw = 1;\n \n \t/* these params may differ with new algorithms support */\n \tsa->ctp.auth.offset = hlen;\n@@ -305,7 +314,10 @@ rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,\n \t\tsa->replay.win_sz = prm->replay_win_sz;\n \t\tsa->replay.nb_bucket = nb;\n \t\tsa->replay.bucket_index_mask = sa->replay.nb_bucket - 1;\n-\t\tsa->sqn.inb = (struct replay_sqn *)(sa + 1);\n+\t\tsa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);\n+\t\tif ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)\n+\t\t\tsa->sqn.inb.rsn[1] = (struct replay_sqn *)\n+\t\t\t\t((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb));\n \t}\n \n \treturn sz;\n@@ -810,7 +822,7 @@ inb_pkt_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],\n \tstruct rte_mbuf *dr[num];\n \n \tsa = ss->sa;\n-\trsn = sa->sqn.inb;\n+\trsn = rsn_acquire(sa);\n \n \tk = 0;\n \tfor (i = 0; i != num; i++) {\n@@ -829,6 +841,8 @@ inb_pkt_prepare(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],\n \t\t}\n \t}\n \n+\trsn_release(sa, rsn);\n+\n \t/* update cops */\n \tlksd_none_cop_prepare(ss, mb, cop, k);\n \n@@ -973,7 +987,7 @@ esp_inb_rsn_update(struct rte_ipsec_sa *sa, const uint32_t sqn[],\n \tuint32_t i, k;\n \tstruct replay_sqn *rsn;\n \n-\trsn = sa->sqn.inb;\n+\trsn = rsn_update_start(sa);\n \n \tk = 0;\n \tfor (i = 0; i != num; i++) {\n@@ -983,6 +997,7 @@ esp_inb_rsn_update(struct rte_ipsec_sa *sa, const uint32_t sqn[],\n \t\t\tdr[i - k] = mb[i];\n \t}\n \n+\trsn_update_finish(sa, rsn);\n \treturn k;\n }\n \ndiff --git a/lib/librte_ipsec/sa.h b/lib/librte_ipsec/sa.h\nindex 050a6d7ae..7dc9933f1 100644\n--- a/lib/librte_ipsec/sa.h\n+++ b/lib/librte_ipsec/sa.h\n@@ -5,6 +5,8 @@\n #ifndef _SA_H_\n #define _SA_H_\n \n+#include <rte_rwlock.h>\n+\n #define IPSEC_MAX_HDR_SIZE\t64\n #define IPSEC_MAX_IV_SIZE\t16\n #define IPSEC_MAX_IV_QWORD\t(IPSEC_MAX_IV_SIZE / sizeof(uint64_t))\n@@ -28,7 +30,11 @@ union sym_op_data {\n \t};\n };\n \n+#define REPLAY_SQN_NUM\t\t2\n+#define REPLAY_SQN_NEXT(n)\t((n) ^ 1)\n+\n struct replay_sqn {\n+\trte_rwlock_t rwl;\n \tuint64_t sqn;\n \t__extension__ uint64_t window[0];\n };\n@@ -66,10 +72,21 @@ struct rte_ipsec_sa {\n \n \t/*\n \t * sqn and replay window\n+\t * In case of SA handled by multiple threads *sqn* cacheline\n+\t * could be shared by multiple cores.\n+\t * To minimise perfomance impact, we try to locate in a separate\n+\t * place from other frequently accesed data.\n \t */\n \tunion {\n-\t\tuint64_t outb;\n-\t\tstruct replay_sqn *inb;\n+\t\tunion {\n+\t\t\trte_atomic64_t atom;\n+\t\t\tuint64_t raw;\n+\t\t} outb;\n+\t\tstruct {\n+\t\t\tuint32_t rdidx; /* read index */\n+\t\t\tuint32_t wridx; /* write index */\n+\t\t\tstruct replay_sqn *rsn[REPLAY_SQN_NUM];\n+\t\t} inb;\n \t} sqn;\n \n } __rte_cache_aligned;\n",
    "prefixes": [
        "7/9"
    ]
}