From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-qk1-f193.google.com (mail-qk1-f193.google.com [209.85.222.193]) by dpdk.org (Postfix) with ESMTP id 792445592 for ; Tue, 9 Apr 2019 21:06:40 +0200 (CEST) Received: by mail-qk1-f193.google.com with SMTP id z76so10948216qkb.12 for ; Tue, 09 Apr 2019 12:06:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:reply-to; bh=AxiKphG82uiqiMvMNBUOW46rprdwlz2bWijFChj0I00=; b=XPKIafs4yAUSI0J+OkaBGjYhdoBcacHaWOS3IPVOVluDKmZWIGv8BoZ5h5GBwTYl2x 5EgnbQo2gdfxyAmWpeBrKg/UvWPF+fVupxdli9qa7T5RhvndGi1m+H0Xbz0ZXxlMDusP u1gCggXhf6N0z0no/y2DuJyyyPELSSHzGNa+tqCCrEy9uYv8DgCy3VQLNTT+/PZuiIYG iN92THYNwJDms+EuTBToF40/yXHKUDrDTIgewq/4LZVgTv/glaA6gMALqyqBU021eC/F yoiF7TygIz+rgq/+zL9V8NS0CTwVej/ROm/yQNYTT/B4caHt7TJwF+IK6myAcHQuu8OL xZjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:reply-to; bh=AxiKphG82uiqiMvMNBUOW46rprdwlz2bWijFChj0I00=; b=Npuzo7u+8UZ4oA9KNJp8WuejBibc2+XgDGByBwNLsZWTvOfonbqa1UQAY9k0vm+D5k 7Ugi6EAl5y7w0o753VvG22raWL0x6H73chLJNvwNXmFGLM6JR+nPoAcsplnPyG4nQbur +VEdED7x4hO9uD3RQ+m3os1kt/rPV2iJpr1zqvsw11ppKcA/XpiI1W6mTSupt4gx4bIJ y+WHxSEJ4ilsMysm5+Dux4L4HrcqOkOESG8sF2Lc7oRAPV03e20k78Sun1K2GEo4nRcZ 14L/UP2pbu3reqNxB0Msja/jcayY5eTD5I9uvkMvbQamYLZjFdn+JM694mH+18/GU/eZ QYgA== X-Gm-Message-State: APjAAAWetOmheWELzs1msY1Dcz7JMzzb64zHKwfjOa47N9iYgswKjkXx Opgdl3XyHC6oD13LfYJj56p/hFkrVoc= X-Google-Smtp-Source: APXvYqwzBI6cfbZEzCTopb4+yTSP+BbLYJ8+buVU5dBa1SEQLqRYutKwT4EepQU5ecdMROni7NPl2Q== X-Received: by 2002:a37:4f95:: with SMTP id d143mr30222430qkb.253.1554836799343; Tue, 09 Apr 2019 12:06:39 -0700 (PDT) Received: from csz25116.canlab.ibm.com ([199.246.40.57]) by smtp.gmail.com with ESMTPSA id q23sm17934789qkc.16.2019.04.09.12.06.37 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Apr 2019 12:06:38 -0700 (PDT) From: Vivian Kong X-Google-Original-From: Vivian Kong To: dev@dpdk.org Date: Tue, 9 Apr 2019 15:06:23 -0400 Message-Id: <20190409190630.31975-6-vivkong@ca.ibm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190409190630.31975-1-vivkong@ca.ibm.com> References: <20190409190630.31975-1-vivkong@ca.ibm.com> Subject: [dpdk-dev] [RFC 05/12] examples/l3fwd: add support for s390x architecture X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: vivkong@ca.ibm.com List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:06:41 -0000 Add s390x specific implementation. Signed-off-by: Vivian Kong --- examples/l3fwd/l3fwd_em.c | 8 + examples/l3fwd/l3fwd_lpm_s390x.h | 137 ++++++++++++++++ examples/l3fwd/l3fwd_s390x.h | 259 +++++++++++++++++++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 examples/l3fwd/l3fwd_lpm_s390x.h create mode 100644 examples/l3fwd/l3fwd_s390x.h diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c index fa8f82be6..a486a9c57 100644 --- a/examples/l3fwd/l3fwd_em.c +++ b/examples/l3fwd/l3fwd_em.c @@ -240,6 +240,14 @@ em_mask_key(void *key, xmm_t mask) return vec_and(data, mask); } +#elif defined(RTE_MACHINE_CPUFLAG_ZARCH) +static inline xmm_t +em_mask_key(void *key, xmm_t mask) +{ + xmm_t data = (xmm_t) vec_xld2(0, (unsigned int *)(key)); + + return data + mask; +} #else #error No vector engine (SSE, NEON, ALTIVEC) available, check your toolchain #endif diff --git a/examples/l3fwd/l3fwd_lpm_s390x.h b/examples/l3fwd/l3fwd_lpm_s390x.h new file mode 100644 index 000000000..858f696ba --- /dev/null +++ b/examples/l3fwd/l3fwd_lpm_s390x.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2016 Intel Corporation. + * (c) Copyright IBM Corp. 2017, 2019 + */ +#ifndef __L3FWD_LPM_S390X_H__ +#define __L3FWD_LPM_S390X_H__ + +#include "l3fwd_s390x.h" + +typedef unsigned char vector_unsigned_char + __attribute__((vector_size(16*sizeof(unsigned char)))); + +/* + * Read packet_type and destination IPV4 addresses from 4 mbufs. + */ +static inline void +processx4_step1(struct rte_mbuf *pkt[FWDSTEP], + vector_unsigned_int *dip, + uint32_t *ipv4_flag) +{ + struct ipv4_hdr *ipv4_hdr; + struct ether_hdr *eth_hdr; + uint32_t x0, x1, x2, x3; + + eth_hdr = rte_pktmbuf_mtod(pkt[0], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x0 = ipv4_hdr->dst_addr; + ipv4_flag[0] = pkt[0]->packet_type & RTE_PTYPE_L3_IPV4; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[1], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x1 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[1]->packet_type; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[2], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x2 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[2]->packet_type; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[3], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x3 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[3]->packet_type; + + rte_compiler_barrier(); + dip[0] = (vector_unsigned_int){x0, x1, x2, x3}; +} + +/* + * Lookup into LPM for destination port. + * If lookup fails, use incoming port (portid) as destination port. + */ +static inline void +processx4_step2(const struct lcore_conf *qconf, + vector_unsigned_int dip, + uint32_t ipv4_flag, + uint8_t portid, + struct rte_mbuf *pkt[FWDSTEP], + uint16_t dprt[FWDSTEP]) +{ + rte_xmm_t dst; + const vector_unsigned_char bswap_mask = (vector_unsigned_char){ + 3, 2, 1, 0, + 7, 6, 5, 4, + 11, 10, 9, 8, + 15, 14, 13, 12}; + + /* Byte swap 4 IPV4 addresses. */ + dip = (vector_unsigned_int)vec_perm(*(vector_unsigned_char *)&dip, + (vector_unsigned_char){}, bswap_mask); + + /* if all 4 packets are IPV4. */ + if (likely(ipv4_flag)) { + rte_lpm_lookupx4(qconf->ipv4_lookup_struct, (xmm_t)dip, + (uint32_t *)&dst, portid); + /* get rid of unused upper 16 bit for each dport. */ + dst.x = (xmm_t)vec_packs(dst.x, dst.x); + *(uint64_t *)dprt = dst.u64[0]; + } else { + dst.x = (xmm_t)dip; + dprt[0] = lpm_get_dst_port_with_ipv4(qconf, pkt[0], + dst.u32[0], portid); + dprt[1] = lpm_get_dst_port_with_ipv4(qconf, pkt[1], + dst.u32[1], portid); + dprt[2] = lpm_get_dst_port_with_ipv4(qconf, pkt[2], + dst.u32[2], portid); + dprt[3] = lpm_get_dst_port_with_ipv4(qconf, pkt[3], + dst.u32[3], portid); + } +} + +/* + * Buffer optimized handling of packets, invoked + * from main_loop. + */ +static inline void +l3fwd_lpm_send_packets(int nb_rx, struct rte_mbuf **pkts_burst, + uint8_t portid, struct lcore_conf *qconf) +{ + int32_t j; + uint16_t dst_port[MAX_PKT_BURST]; + vector_unsigned_int dip[MAX_PKT_BURST / FWDSTEP]; + uint32_t ipv4_flag[MAX_PKT_BURST / FWDSTEP]; + const int32_t k = RTE_ALIGN_FLOOR(nb_rx, FWDSTEP); + + for (j = 0; j != k; j += FWDSTEP) + processx4_step1(&pkts_burst[j], &dip[j / FWDSTEP], + &ipv4_flag[j / FWDSTEP]); + + for (j = 0; j != k; j += FWDSTEP) + processx4_step2(qconf, dip[j / FWDSTEP], + ipv4_flag[j / FWDSTEP], + portid, &pkts_burst[j], &dst_port[j]); + + /* Classify last up to 3 packets one by one */ + switch (nb_rx % FWDSTEP) { + case 3: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + case 2: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + case 1: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + } + + send_packets_multi(qconf, pkts_burst, dst_port, nb_rx); +} + +#endif /* __L3FWD_LPM_S390X_H__ */ diff --git a/examples/l3fwd/l3fwd_s390x.h b/examples/l3fwd/l3fwd_s390x.h new file mode 100644 index 000000000..d027092a4 --- /dev/null +++ b/examples/l3fwd/l3fwd_s390x.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2016 Intel Corporation. + * (c) Copyright IBM Corp. 2017, 2019 + */ +#ifndef _L3FWD_S390X_H_ +#define _L3FWD_S390X_H_ + +#include "l3fwd.h" +#include "l3fwd_common.h" + +#define vec_sro(a, b) vec_srb(a, (b) << 64) // Vector Shift Right by Octet +typedef unsigned int vector_unsigned_int + __attribute__((vector_size(4*sizeof(unsigned int)))); +typedef unsigned short vector_unsigned_short + __attribute__((vector_size(8*sizeof(unsigned short)))); + +/* + * Update source and destination MAC addresses in the ethernet header. + * Perform RFC1812 checks and updates for IPV4 packets. + */ +static inline void +processx4_step3(struct rte_mbuf *pkt[FWDSTEP], uint16_t dst_port[FWDSTEP]) +{ + vector_unsigned_int te[FWDSTEP]; + vector_unsigned_int ve[FWDSTEP]; + vector_unsigned_int *p[FWDSTEP]; + + p[0] = rte_pktmbuf_mtod(pkt[0], vector_unsigned_int *); + p[1] = rte_pktmbuf_mtod(pkt[1], vector_unsigned_int *); + p[2] = rte_pktmbuf_mtod(pkt[2], vector_unsigned_int *); + p[3] = rte_pktmbuf_mtod(pkt[3], vector_unsigned_int *); + + ve[0] = (vector_unsigned_int)val_eth[dst_port[0]]; + te[0] = *p[0]; + + ve[1] = (vector_unsigned_int)val_eth[dst_port[1]]; + te[1] = *p[1]; + + ve[2] = (vector_unsigned_int)val_eth[dst_port[2]]; + te[2] = *p[2]; + + ve[3] = (vector_unsigned_int)val_eth[dst_port[3]]; + te[3] = *p[3]; + + /* Update first 12 bytes, keep rest bytes intact. */ + te[0] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[0], + (vector_unsigned_short)te[0], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + te[1] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[1], + (vector_unsigned_short)te[1], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + te[2] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[2], + (vector_unsigned_short)te[2], + (vector_unsigned_short) {0, 0, 0, 0, 0, + 0, 0xffff, 0xffff}); + + te[3] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[3], + (vector_unsigned_short)te[3], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + *p[0] = te[0]; + *p[1] = te[1]; + *p[2] = te[2]; + *p[3] = te[3]; + + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[0] + 1), + &dst_port[0], pkt[0]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[1] + 1), + &dst_port[1], pkt[1]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[2] + 1), + &dst_port[2], pkt[2]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[3] + 1), + &dst_port[3], pkt[3]->packet_type); +} + +/* + * Group consecutive packets with the same destination port in bursts of 4. + * Suppose we have array of destination ports: + * dst_port[] = {a, b, c, d,, e, ... } + * dp1 should contain: , dp2: . + * We doing 4 comparisons at once and the result is 4 bit mask. + * This mask is used as an index into prebuild array of pnum values. + */ +static inline uint16_t * +port_groupx4(uint16_t pn[FWDSTEP + 1], uint16_t *lp, vector_unsigned_short dp1, + vector_unsigned_short dp2) +{ + union { + uint16_t u16[FWDSTEP + 1]; + uint64_t u64; + } *pnum = (void *)pn; + + int32_t v; + + v = vec_any_eq(dp1, dp2); + + + /* update last port counter. */ + lp[0] += gptbl[v].lpv; + + /* if dest port value has changed. */ + if (v != GRPMSK) { + pnum->u64 = gptbl[v].pnum; + pnum->u16[FWDSTEP] = 1; + lp = pnum->u16 + gptbl[v].idx; + } + + return lp; +} + +/** + * Process one packet: + * Update source and destination MAC addresses in the ethernet header. + * Perform RFC1812 checks and updates for IPV4 packets. + */ +static inline void +process_packet(struct rte_mbuf *pkt, uint16_t *dst_port) +{ + struct ether_hdr *eth_hdr; + vector_unsigned_int te, ve; + + eth_hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + + te = *(vector_unsigned_int *)eth_hdr; + ve = (vector_unsigned_int)val_eth[dst_port[0]]; + + rfc1812_process((struct ipv4_hdr *)(eth_hdr + 1), dst_port, + pkt->packet_type); + + /* dynamically vec_sel te and ve for MASK_ETH (0x3f) */ + te = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve, + (vector_unsigned_short)te, + (vector_unsigned_short){0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + *(vector_unsigned_int *)eth_hdr = te; +} + +/** + * Send packets burst from pkts_burst to the ports in dst_port array + */ +static __rte_always_inline void +send_packets_multi(struct lcore_conf *qconf, struct rte_mbuf **pkts_burst, + uint16_t dst_port[MAX_PKT_BURST], int nb_rx) +{ + int32_t k; + int j = 0; + uint16_t dlp; + uint16_t *lp; + uint16_t pnum[MAX_PKT_BURST + 1]; + + /* + * Finish packet processing and group consecutive + * packets with the same destination port. + */ + k = RTE_ALIGN_FLOOR(nb_rx, FWDSTEP); + if (k != 0) { + vector_unsigned_short dp1, dp2; + + lp = pnum; + lp[0] = 1; + + processx4_step3(pkts_burst, dst_port); + + /* dp1: */ + dp1 = *(vector_unsigned_short *)dst_port; + + for (j = FWDSTEP; j != k; j += FWDSTEP) { + processx4_step3(&pkts_burst[j], &dst_port[j]); + + /* + * dp2: + * + */ + dp2 = *((vector_unsigned_short *) + &dst_port[j - FWDSTEP + 1]); + lp = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2); + + /* + * dp1: + * + */ + dp1 = vec_sro(dp2, (vector unsigned char) { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, (FWDSTEP - 1) * sizeof(dst_port[0])}); + } + + /* + * dp2: + */ + dp2 = vec_perm(dp1, (vector_unsigned_short){}, + (vector unsigned char) {0xf9}); + lp = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2); + + /* + * remove values added by the last repeated + * dst port. + */ + lp[0]--; + dlp = dst_port[j - 1]; + } else { + /* set dlp and lp to the never used values. */ + dlp = BAD_PORT - 1; + lp = pnum + MAX_PKT_BURST; + } + + /* Process up to last 3 packets one by one. */ + switch (nb_rx % FWDSTEP) { + case 3: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + /* fall-through */ + case 2: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + /* fall-through */ + case 1: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + } + + /* + * Send packets out, through destination port. + * Consecutive packets with the same destination port + * are already grouped together. + * If destination port for the packet equals BAD_PORT, + * then free the packet without sending it out. + */ + for (j = 0; j < nb_rx; j += k) { + + int32_t m; + uint16_t pn; + + pn = dst_port[j]; + k = pnum[j]; + + if (likely(pn != BAD_PORT)) + send_packetsx4(qconf, pn, pkts_burst + j, k); + else + for (m = j; m != j + k; m++) + rte_pktmbuf_free(pkts_burst[m]); + + } +} + +#endif /* _L3FWD_S390X_H_ */ -- 2.17.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by dpdk.space (Postfix) with ESMTP id 89FD0A0096 for ; Tue, 9 Apr 2019 21:07:34 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7F7255B1E; Tue, 9 Apr 2019 21:06:53 +0200 (CEST) Received: from mail-qk1-f193.google.com (mail-qk1-f193.google.com [209.85.222.193]) by dpdk.org (Postfix) with ESMTP id 792445592 for ; Tue, 9 Apr 2019 21:06:40 +0200 (CEST) Received: by mail-qk1-f193.google.com with SMTP id z76so10948216qkb.12 for ; Tue, 09 Apr 2019 12:06:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:reply-to; bh=AxiKphG82uiqiMvMNBUOW46rprdwlz2bWijFChj0I00=; b=XPKIafs4yAUSI0J+OkaBGjYhdoBcacHaWOS3IPVOVluDKmZWIGv8BoZ5h5GBwTYl2x 5EgnbQo2gdfxyAmWpeBrKg/UvWPF+fVupxdli9qa7T5RhvndGi1m+H0Xbz0ZXxlMDusP u1gCggXhf6N0z0no/y2DuJyyyPELSSHzGNa+tqCCrEy9uYv8DgCy3VQLNTT+/PZuiIYG iN92THYNwJDms+EuTBToF40/yXHKUDrDTIgewq/4LZVgTv/glaA6gMALqyqBU021eC/F yoiF7TygIz+rgq/+zL9V8NS0CTwVej/ROm/yQNYTT/B4caHt7TJwF+IK6myAcHQuu8OL xZjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:reply-to; bh=AxiKphG82uiqiMvMNBUOW46rprdwlz2bWijFChj0I00=; b=Npuzo7u+8UZ4oA9KNJp8WuejBibc2+XgDGByBwNLsZWTvOfonbqa1UQAY9k0vm+D5k 7Ugi6EAl5y7w0o753VvG22raWL0x6H73chLJNvwNXmFGLM6JR+nPoAcsplnPyG4nQbur +VEdED7x4hO9uD3RQ+m3os1kt/rPV2iJpr1zqvsw11ppKcA/XpiI1W6mTSupt4gx4bIJ y+WHxSEJ4ilsMysm5+Dux4L4HrcqOkOESG8sF2Lc7oRAPV03e20k78Sun1K2GEo4nRcZ 14L/UP2pbu3reqNxB0Msja/jcayY5eTD5I9uvkMvbQamYLZjFdn+JM694mH+18/GU/eZ QYgA== X-Gm-Message-State: APjAAAWetOmheWELzs1msY1Dcz7JMzzb64zHKwfjOa47N9iYgswKjkXx Opgdl3XyHC6oD13LfYJj56p/hFkrVoc= X-Google-Smtp-Source: APXvYqwzBI6cfbZEzCTopb4+yTSP+BbLYJ8+buVU5dBa1SEQLqRYutKwT4EepQU5ecdMROni7NPl2Q== X-Received: by 2002:a37:4f95:: with SMTP id d143mr30222430qkb.253.1554836799343; Tue, 09 Apr 2019 12:06:39 -0700 (PDT) Received: from csz25116.canlab.ibm.com ([199.246.40.57]) by smtp.gmail.com with ESMTPSA id q23sm17934789qkc.16.2019.04.09.12.06.37 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Apr 2019 12:06:38 -0700 (PDT) From: Vivian Kong X-Google-Original-From: Vivian Kong To: dev@dpdk.org Date: Tue, 9 Apr 2019 15:06:23 -0400 Message-Id: <20190409190630.31975-6-vivkong@ca.ibm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190409190630.31975-1-vivkong@ca.ibm.com> References: <20190409190630.31975-1-vivkong@ca.ibm.com> Subject: [dpdk-dev] [RFC 05/12] examples/l3fwd: add support for s390x architecture X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: vivkong@ca.ibm.com List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Content-Type: text/plain; charset="UTF-8" Message-ID: <20190409190623.-qjL-eCvyfKRe41WXBTE8MBFI55wKuz55w3m3d6Ek_w@z> Add s390x specific implementation. Signed-off-by: Vivian Kong --- examples/l3fwd/l3fwd_em.c | 8 + examples/l3fwd/l3fwd_lpm_s390x.h | 137 ++++++++++++++++ examples/l3fwd/l3fwd_s390x.h | 259 +++++++++++++++++++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 examples/l3fwd/l3fwd_lpm_s390x.h create mode 100644 examples/l3fwd/l3fwd_s390x.h diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c index fa8f82be6..a486a9c57 100644 --- a/examples/l3fwd/l3fwd_em.c +++ b/examples/l3fwd/l3fwd_em.c @@ -240,6 +240,14 @@ em_mask_key(void *key, xmm_t mask) return vec_and(data, mask); } +#elif defined(RTE_MACHINE_CPUFLAG_ZARCH) +static inline xmm_t +em_mask_key(void *key, xmm_t mask) +{ + xmm_t data = (xmm_t) vec_xld2(0, (unsigned int *)(key)); + + return data + mask; +} #else #error No vector engine (SSE, NEON, ALTIVEC) available, check your toolchain #endif diff --git a/examples/l3fwd/l3fwd_lpm_s390x.h b/examples/l3fwd/l3fwd_lpm_s390x.h new file mode 100644 index 000000000..858f696ba --- /dev/null +++ b/examples/l3fwd/l3fwd_lpm_s390x.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2016 Intel Corporation. + * (c) Copyright IBM Corp. 2017, 2019 + */ +#ifndef __L3FWD_LPM_S390X_H__ +#define __L3FWD_LPM_S390X_H__ + +#include "l3fwd_s390x.h" + +typedef unsigned char vector_unsigned_char + __attribute__((vector_size(16*sizeof(unsigned char)))); + +/* + * Read packet_type and destination IPV4 addresses from 4 mbufs. + */ +static inline void +processx4_step1(struct rte_mbuf *pkt[FWDSTEP], + vector_unsigned_int *dip, + uint32_t *ipv4_flag) +{ + struct ipv4_hdr *ipv4_hdr; + struct ether_hdr *eth_hdr; + uint32_t x0, x1, x2, x3; + + eth_hdr = rte_pktmbuf_mtod(pkt[0], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x0 = ipv4_hdr->dst_addr; + ipv4_flag[0] = pkt[0]->packet_type & RTE_PTYPE_L3_IPV4; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[1], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x1 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[1]->packet_type; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[2], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x2 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[2]->packet_type; + + rte_compiler_barrier(); + eth_hdr = rte_pktmbuf_mtod(pkt[3], struct ether_hdr *); + ipv4_hdr = (struct ipv4_hdr *)(eth_hdr + 1); + x3 = ipv4_hdr->dst_addr; + ipv4_flag[0] &= pkt[3]->packet_type; + + rte_compiler_barrier(); + dip[0] = (vector_unsigned_int){x0, x1, x2, x3}; +} + +/* + * Lookup into LPM for destination port. + * If lookup fails, use incoming port (portid) as destination port. + */ +static inline void +processx4_step2(const struct lcore_conf *qconf, + vector_unsigned_int dip, + uint32_t ipv4_flag, + uint8_t portid, + struct rte_mbuf *pkt[FWDSTEP], + uint16_t dprt[FWDSTEP]) +{ + rte_xmm_t dst; + const vector_unsigned_char bswap_mask = (vector_unsigned_char){ + 3, 2, 1, 0, + 7, 6, 5, 4, + 11, 10, 9, 8, + 15, 14, 13, 12}; + + /* Byte swap 4 IPV4 addresses. */ + dip = (vector_unsigned_int)vec_perm(*(vector_unsigned_char *)&dip, + (vector_unsigned_char){}, bswap_mask); + + /* if all 4 packets are IPV4. */ + if (likely(ipv4_flag)) { + rte_lpm_lookupx4(qconf->ipv4_lookup_struct, (xmm_t)dip, + (uint32_t *)&dst, portid); + /* get rid of unused upper 16 bit for each dport. */ + dst.x = (xmm_t)vec_packs(dst.x, dst.x); + *(uint64_t *)dprt = dst.u64[0]; + } else { + dst.x = (xmm_t)dip; + dprt[0] = lpm_get_dst_port_with_ipv4(qconf, pkt[0], + dst.u32[0], portid); + dprt[1] = lpm_get_dst_port_with_ipv4(qconf, pkt[1], + dst.u32[1], portid); + dprt[2] = lpm_get_dst_port_with_ipv4(qconf, pkt[2], + dst.u32[2], portid); + dprt[3] = lpm_get_dst_port_with_ipv4(qconf, pkt[3], + dst.u32[3], portid); + } +} + +/* + * Buffer optimized handling of packets, invoked + * from main_loop. + */ +static inline void +l3fwd_lpm_send_packets(int nb_rx, struct rte_mbuf **pkts_burst, + uint8_t portid, struct lcore_conf *qconf) +{ + int32_t j; + uint16_t dst_port[MAX_PKT_BURST]; + vector_unsigned_int dip[MAX_PKT_BURST / FWDSTEP]; + uint32_t ipv4_flag[MAX_PKT_BURST / FWDSTEP]; + const int32_t k = RTE_ALIGN_FLOOR(nb_rx, FWDSTEP); + + for (j = 0; j != k; j += FWDSTEP) + processx4_step1(&pkts_burst[j], &dip[j / FWDSTEP], + &ipv4_flag[j / FWDSTEP]); + + for (j = 0; j != k; j += FWDSTEP) + processx4_step2(qconf, dip[j / FWDSTEP], + ipv4_flag[j / FWDSTEP], + portid, &pkts_burst[j], &dst_port[j]); + + /* Classify last up to 3 packets one by one */ + switch (nb_rx % FWDSTEP) { + case 3: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + case 2: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + case 1: + dst_port[j] = lpm_get_dst_port(qconf, pkts_burst[j], portid); + j++; + /* fall-through */ + } + + send_packets_multi(qconf, pkts_burst, dst_port, nb_rx); +} + +#endif /* __L3FWD_LPM_S390X_H__ */ diff --git a/examples/l3fwd/l3fwd_s390x.h b/examples/l3fwd/l3fwd_s390x.h new file mode 100644 index 000000000..d027092a4 --- /dev/null +++ b/examples/l3fwd/l3fwd_s390x.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2016 Intel Corporation. + * (c) Copyright IBM Corp. 2017, 2019 + */ +#ifndef _L3FWD_S390X_H_ +#define _L3FWD_S390X_H_ + +#include "l3fwd.h" +#include "l3fwd_common.h" + +#define vec_sro(a, b) vec_srb(a, (b) << 64) // Vector Shift Right by Octet +typedef unsigned int vector_unsigned_int + __attribute__((vector_size(4*sizeof(unsigned int)))); +typedef unsigned short vector_unsigned_short + __attribute__((vector_size(8*sizeof(unsigned short)))); + +/* + * Update source and destination MAC addresses in the ethernet header. + * Perform RFC1812 checks and updates for IPV4 packets. + */ +static inline void +processx4_step3(struct rte_mbuf *pkt[FWDSTEP], uint16_t dst_port[FWDSTEP]) +{ + vector_unsigned_int te[FWDSTEP]; + vector_unsigned_int ve[FWDSTEP]; + vector_unsigned_int *p[FWDSTEP]; + + p[0] = rte_pktmbuf_mtod(pkt[0], vector_unsigned_int *); + p[1] = rte_pktmbuf_mtod(pkt[1], vector_unsigned_int *); + p[2] = rte_pktmbuf_mtod(pkt[2], vector_unsigned_int *); + p[3] = rte_pktmbuf_mtod(pkt[3], vector_unsigned_int *); + + ve[0] = (vector_unsigned_int)val_eth[dst_port[0]]; + te[0] = *p[0]; + + ve[1] = (vector_unsigned_int)val_eth[dst_port[1]]; + te[1] = *p[1]; + + ve[2] = (vector_unsigned_int)val_eth[dst_port[2]]; + te[2] = *p[2]; + + ve[3] = (vector_unsigned_int)val_eth[dst_port[3]]; + te[3] = *p[3]; + + /* Update first 12 bytes, keep rest bytes intact. */ + te[0] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[0], + (vector_unsigned_short)te[0], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + te[1] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[1], + (vector_unsigned_short)te[1], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + te[2] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[2], + (vector_unsigned_short)te[2], + (vector_unsigned_short) {0, 0, 0, 0, 0, + 0, 0xffff, 0xffff}); + + te[3] = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve[3], + (vector_unsigned_short)te[3], + (vector_unsigned_short) {0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + *p[0] = te[0]; + *p[1] = te[1]; + *p[2] = te[2]; + *p[3] = te[3]; + + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[0] + 1), + &dst_port[0], pkt[0]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[1] + 1), + &dst_port[1], pkt[1]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[2] + 1), + &dst_port[2], pkt[2]->packet_type); + rfc1812_process((struct ipv4_hdr *)((struct ether_hdr *)p[3] + 1), + &dst_port[3], pkt[3]->packet_type); +} + +/* + * Group consecutive packets with the same destination port in bursts of 4. + * Suppose we have array of destination ports: + * dst_port[] = {a, b, c, d,, e, ... } + * dp1 should contain: , dp2: . + * We doing 4 comparisons at once and the result is 4 bit mask. + * This mask is used as an index into prebuild array of pnum values. + */ +static inline uint16_t * +port_groupx4(uint16_t pn[FWDSTEP + 1], uint16_t *lp, vector_unsigned_short dp1, + vector_unsigned_short dp2) +{ + union { + uint16_t u16[FWDSTEP + 1]; + uint64_t u64; + } *pnum = (void *)pn; + + int32_t v; + + v = vec_any_eq(dp1, dp2); + + + /* update last port counter. */ + lp[0] += gptbl[v].lpv; + + /* if dest port value has changed. */ + if (v != GRPMSK) { + pnum->u64 = gptbl[v].pnum; + pnum->u16[FWDSTEP] = 1; + lp = pnum->u16 + gptbl[v].idx; + } + + return lp; +} + +/** + * Process one packet: + * Update source and destination MAC addresses in the ethernet header. + * Perform RFC1812 checks and updates for IPV4 packets. + */ +static inline void +process_packet(struct rte_mbuf *pkt, uint16_t *dst_port) +{ + struct ether_hdr *eth_hdr; + vector_unsigned_int te, ve; + + eth_hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + + te = *(vector_unsigned_int *)eth_hdr; + ve = (vector_unsigned_int)val_eth[dst_port[0]]; + + rfc1812_process((struct ipv4_hdr *)(eth_hdr + 1), dst_port, + pkt->packet_type); + + /* dynamically vec_sel te and ve for MASK_ETH (0x3f) */ + te = (vector_unsigned_int)vec_sel( + (vector_unsigned_short)ve, + (vector_unsigned_short)te, + (vector_unsigned_short){0, 0, 0, 0, + 0, 0, 0xffff, 0xffff}); + + *(vector_unsigned_int *)eth_hdr = te; +} + +/** + * Send packets burst from pkts_burst to the ports in dst_port array + */ +static __rte_always_inline void +send_packets_multi(struct lcore_conf *qconf, struct rte_mbuf **pkts_burst, + uint16_t dst_port[MAX_PKT_BURST], int nb_rx) +{ + int32_t k; + int j = 0; + uint16_t dlp; + uint16_t *lp; + uint16_t pnum[MAX_PKT_BURST + 1]; + + /* + * Finish packet processing and group consecutive + * packets with the same destination port. + */ + k = RTE_ALIGN_FLOOR(nb_rx, FWDSTEP); + if (k != 0) { + vector_unsigned_short dp1, dp2; + + lp = pnum; + lp[0] = 1; + + processx4_step3(pkts_burst, dst_port); + + /* dp1: */ + dp1 = *(vector_unsigned_short *)dst_port; + + for (j = FWDSTEP; j != k; j += FWDSTEP) { + processx4_step3(&pkts_burst[j], &dst_port[j]); + + /* + * dp2: + * + */ + dp2 = *((vector_unsigned_short *) + &dst_port[j - FWDSTEP + 1]); + lp = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2); + + /* + * dp1: + * + */ + dp1 = vec_sro(dp2, (vector unsigned char) { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, (FWDSTEP - 1) * sizeof(dst_port[0])}); + } + + /* + * dp2: + */ + dp2 = vec_perm(dp1, (vector_unsigned_short){}, + (vector unsigned char) {0xf9}); + lp = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2); + + /* + * remove values added by the last repeated + * dst port. + */ + lp[0]--; + dlp = dst_port[j - 1]; + } else { + /* set dlp and lp to the never used values. */ + dlp = BAD_PORT - 1; + lp = pnum + MAX_PKT_BURST; + } + + /* Process up to last 3 packets one by one. */ + switch (nb_rx % FWDSTEP) { + case 3: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + /* fall-through */ + case 2: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + /* fall-through */ + case 1: + process_packet(pkts_burst[j], dst_port + j); + GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j); + j++; + } + + /* + * Send packets out, through destination port. + * Consecutive packets with the same destination port + * are already grouped together. + * If destination port for the packet equals BAD_PORT, + * then free the packet without sending it out. + */ + for (j = 0; j < nb_rx; j += k) { + + int32_t m; + uint16_t pn; + + pn = dst_port[j]; + k = pnum[j]; + + if (likely(pn != BAD_PORT)) + send_packetsx4(qconf, pn, pkts_burst + j, k); + else + for (m = j; m != j + k; m++) + rte_pktmbuf_free(pkts_burst[m]); + + } +} + +#endif /* _L3FWD_S390X_H_ */ -- 2.17.1