From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 31D8AA04B1; Wed, 23 Sep 2020 20:08:38 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2F11B1DC36; Wed, 23 Sep 2020 20:07:20 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id B0F151DAB1 for ; Wed, 23 Sep 2020 20:07:00 +0200 (CEST) IronPort-SDR: O77c18JeSucHjdgYtui03udIsM+/X3qXCKYII5ghpqlbREjgHr+3KLy+1OstSKbkA2/bVV4HtO 2XzSB60veo6Q== X-IronPort-AV: E=McAfee;i="6000,8403,9753"; a="245809515" X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="245809515" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2020 11:07:00 -0700 IronPort-SDR: Km/yOQovs23GfX5bUcmfGO/hYP2LieLNpcyfHM6ugI8+/aR1G4wJz8Yc+J8YAjOktG3xb3/W8s GEnlmq8ryBLQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="305477855" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga003.jf.intel.com with ESMTP; 23 Sep 2020 11:06:59 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: thomas@monjalon.net, david.marchand@redhat.com Date: Wed, 23 Sep 2020 19:06:14 +0100 Message-Id: <20200923180645.55852-11-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200923180645.55852-1-cristian.dumitrescu@intel.com> References: <20200910152645.9342-2-cristian.dumitrescu@intel.com> <20200923180645.55852-1-cristian.dumitrescu@intel.com> Subject: [dpdk-dev] [PATCH v5 10/41] pipeline: add SWX Tx and emit instructions X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add header emit and packet transmission instructions. Emit adds to the output packet a header that is either generated (e.g. read from table entry by action) or extracted from the input packet. Tx ends the pipeline processing; discard is implemented by tx to special port. Signed-off-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_swx_pipeline.c | 328 +++++++++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index d7af80e39..19bf2761d 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -213,6 +213,9 @@ enum instruction_type { /* rx m.port_in */ INSTR_RX, + /* tx m.port_out */ + INSTR_TX, + /* extract h.header */ INSTR_HDR_EXTRACT, INSTR_HDR_EXTRACT2, @@ -222,6 +225,17 @@ enum instruction_type { INSTR_HDR_EXTRACT6, INSTR_HDR_EXTRACT7, INSTR_HDR_EXTRACT8, + + /* emit h.header */ + INSTR_HDR_EMIT, + INSTR_HDR_EMIT_TX, + INSTR_HDR_EMIT2_TX, + INSTR_HDR_EMIT3_TX, + INSTR_HDR_EMIT4_TX, + INSTR_HDR_EMIT5_TX, + INSTR_HDR_EMIT6_TX, + INSTR_HDR_EMIT7_TX, + INSTR_HDR_EMIT8_TX, }; struct instr_io { @@ -1635,6 +1649,114 @@ instr_rx_exec(struct rte_swx_pipeline *p) thread_yield(p); } +/* + * tx. + */ +static int +instr_tx_translate(struct rte_swx_pipeline *p, + struct action *action __rte_unused, + char **tokens, + int n_tokens, + struct instruction *instr, + struct instruction_data *data __rte_unused) +{ + struct field *f; + + CHECK(n_tokens == 2, EINVAL); + + f = metadata_field_parse(p, tokens[1]); + CHECK(f, EINVAL); + + instr->type = INSTR_TX; + instr->io.io.offset = f->offset / 8; + instr->io.io.n_bits = f->n_bits; + return 0; +} + +static inline void +emit_handler(struct thread *t) +{ + struct header_out_runtime *h0 = &t->headers_out[0]; + struct header_out_runtime *h1 = &t->headers_out[1]; + uint32_t offset = 0, i; + + /* No header change or header decapsulation. */ + if ((t->n_headers_out == 1) && + (h0->ptr + h0->n_bytes == t->ptr)) { + TRACE("Emit handler: no header change or header decap.\n"); + + t->pkt.offset -= h0->n_bytes; + t->pkt.length += h0->n_bytes; + + return; + } + + /* Header encapsulation (optionally, with prior header decasulation). */ + if ((t->n_headers_out == 2) && + (h1->ptr + h1->n_bytes == t->ptr) && + (h0->ptr == h0->ptr0)) { + uint32_t offset; + + TRACE("Emit handler: header encapsulation.\n"); + + offset = h0->n_bytes + h1->n_bytes; + memcpy(t->ptr - offset, h0->ptr, h0->n_bytes); + t->pkt.offset -= offset; + t->pkt.length += offset; + + return; + } + + /* Header insertion. */ + /* TBD */ + + /* Header extraction. */ + /* TBD */ + + /* For any other case. */ + TRACE("Emit handler: complex case.\n"); + + for (i = 0; i < t->n_headers_out; i++) { + struct header_out_runtime *h = &t->headers_out[i]; + + memcpy(&t->header_out_storage[offset], h->ptr, h->n_bytes); + offset += h->n_bytes; + } + + if (offset) { + memcpy(t->ptr - offset, t->header_out_storage, offset); + t->pkt.offset -= offset; + t->pkt.length += offset; + } +} + +static inline void +instr_tx_exec(struct rte_swx_pipeline *p); + +static inline void +instr_tx_exec(struct rte_swx_pipeline *p) +{ + struct thread *t = &p->threads[p->thread_id]; + struct instruction *ip = t->ip; + uint64_t port_id = METADATA_READ(t, ip->io.io.offset, ip->io.io.n_bits); + struct port_out_runtime *port = &p->out[port_id]; + struct rte_swx_pkt *pkt = &t->pkt; + + TRACE("[Thread %2u]: tx 1 pkt to port %u\n", + p->thread_id, + (uint32_t)port_id); + + /* Headers. */ + emit_handler(t); + + /* Packet. */ + port->pkt_tx(port->obj, pkt); + + /* Thread. */ + thread_ip_reset(p, t); + instr_rx_exec(p); +} + /* * extract. */ @@ -1797,6 +1919,185 @@ instr_hdr_extract8_exec(struct rte_swx_pipeline *p) thread_ip_inc(p); } +/* + * emit. + */ +static int +instr_hdr_emit_translate(struct rte_swx_pipeline *p, + struct action *action __rte_unused, + char **tokens, + int n_tokens, + struct instruction *instr, + struct instruction_data *data __rte_unused) +{ + struct header *h; + + CHECK(n_tokens == 2, EINVAL); + + h = header_parse(p, tokens[1]); + CHECK(h, EINVAL); + + instr->type = INSTR_HDR_EMIT; + instr->io.hdr.header_id[0] = h->id; + instr->io.hdr.struct_id[0] = h->struct_id; + instr->io.hdr.n_bytes[0] = h->st->n_bits / 8; + return 0; +} + +static inline void +__instr_hdr_emit_exec(struct rte_swx_pipeline *p, uint32_t n_emit); + +static inline void +__instr_hdr_emit_exec(struct rte_swx_pipeline *p, uint32_t n_emit) +{ + struct thread *t = &p->threads[p->thread_id]; + struct instruction *ip = t->ip; + uint32_t n_headers_out = t->n_headers_out; + struct header_out_runtime *ho = &t->headers_out[n_headers_out - 1]; + uint8_t *ho_ptr = NULL; + uint32_t ho_nbytes = 0, i; + + for (i = 0; i < n_emit; i++) { + uint32_t header_id = ip->io.hdr.header_id[i]; + uint32_t struct_id = ip->io.hdr.struct_id[i]; + uint32_t n_bytes = ip->io.hdr.n_bytes[i]; + + struct header_runtime *hi = &t->headers[header_id]; + uint8_t *hi_ptr = t->structs[struct_id]; + + TRACE("[Thread %2u]: emit header %u\n", + p->thread_id, + header_id); + + /* Headers. */ + if (!i) { + if (!t->n_headers_out) { + ho = &t->headers_out[0]; + + ho->ptr0 = hi->ptr0; + ho->ptr = hi_ptr; + + ho_ptr = hi_ptr; + ho_nbytes = n_bytes; + + n_headers_out = 1; + + continue; + } else { + ho_ptr = ho->ptr; + ho_nbytes = ho->n_bytes; + } + } + + if (ho_ptr + ho_nbytes == hi_ptr) { + ho_nbytes += n_bytes; + } else { + ho->n_bytes = ho_nbytes; + + ho++; + ho->ptr0 = hi->ptr0; + ho->ptr = hi_ptr; + + ho_ptr = hi_ptr; + ho_nbytes = n_bytes; + + n_headers_out++; + } + } + + ho->n_bytes = ho_nbytes; + t->n_headers_out = n_headers_out; +} + +static inline void +instr_hdr_emit_exec(struct rte_swx_pipeline *p) +{ + __instr_hdr_emit_exec(p, 1); + + /* Thread. */ + thread_ip_inc(p); +} + +static inline void +instr_hdr_emit_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 2 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 1); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit2_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 3 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 2); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit3_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 4 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 3); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit4_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 5 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 4); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit5_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 6 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 5); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit6_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 7 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 6); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit7_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 8 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 7); + instr_tx_exec(p); +} + +static inline void +instr_hdr_emit8_tx_exec(struct rte_swx_pipeline *p) +{ + TRACE("[Thread %2u] *** The next 9 instructions are fused. ***\n", + p->thread_id); + + __instr_hdr_emit_exec(p, 8); + instr_tx_exec(p); +} + #define RTE_SWX_INSTRUCTION_TOKENS_MAX 16 static int @@ -1842,6 +2143,14 @@ instr_translate(struct rte_swx_pipeline *p, instr, data); + if (!strcmp(tokens[tpos], "tx")) + return instr_tx_translate(p, + action, + &tokens[tpos], + n_tokens - tpos, + instr, + data); + if (!strcmp(tokens[tpos], "extract")) return instr_hdr_extract_translate(p, action, @@ -1850,6 +2159,14 @@ instr_translate(struct rte_swx_pipeline *p, instr, data); + if (!strcmp(tokens[tpos], "emit")) + return instr_hdr_emit_translate(p, + action, + &tokens[tpos], + n_tokens - tpos, + instr, + data); + CHECK(0, EINVAL); } @@ -1971,6 +2288,7 @@ typedef void (*instr_exec_t)(struct rte_swx_pipeline *); static instr_exec_t instruction_table[] = { [INSTR_RX] = instr_rx_exec, + [INSTR_TX] = instr_tx_exec, [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec, [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec, @@ -1980,6 +2298,16 @@ static instr_exec_t instruction_table[] = { [INSTR_HDR_EXTRACT6] = instr_hdr_extract6_exec, [INSTR_HDR_EXTRACT7] = instr_hdr_extract7_exec, [INSTR_HDR_EXTRACT8] = instr_hdr_extract8_exec, + + [INSTR_HDR_EMIT] = instr_hdr_emit_exec, + [INSTR_HDR_EMIT_TX] = instr_hdr_emit_tx_exec, + [INSTR_HDR_EMIT2_TX] = instr_hdr_emit2_tx_exec, + [INSTR_HDR_EMIT3_TX] = instr_hdr_emit3_tx_exec, + [INSTR_HDR_EMIT4_TX] = instr_hdr_emit4_tx_exec, + [INSTR_HDR_EMIT5_TX] = instr_hdr_emit5_tx_exec, + [INSTR_HDR_EMIT6_TX] = instr_hdr_emit6_tx_exec, + [INSTR_HDR_EMIT7_TX] = instr_hdr_emit7_tx_exec, + [INSTR_HDR_EMIT8_TX] = instr_hdr_emit8_tx_exec, }; static inline void -- 2.17.1