xref: /f-stack/dpdk/examples/l3fwd/l3fwd_neon.h (revision 4418919f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2018 Intel Corporation.
3  * Copyright(c) 2017-2018 Linaro Limited.
4  */
5 
6 #ifndef _L3FWD_NEON_H_
7 #define _L3FWD_NEON_H_
8 
9 #include "l3fwd.h"
10 #include "l3fwd_common.h"
11 
12 /*
13  * Update source and destination MAC addresses in the ethernet header.
14  * Perform RFC1812 checks and updates for IPV4 packets.
15  */
16 static inline void
processx4_step3(struct rte_mbuf * pkt[FWDSTEP],uint16_t dst_port[FWDSTEP])17 processx4_step3(struct rte_mbuf *pkt[FWDSTEP], uint16_t dst_port[FWDSTEP])
18 {
19 	uint32x4_t te[FWDSTEP];
20 	uint32x4_t ve[FWDSTEP];
21 	uint32_t *p[FWDSTEP];
22 
23 	p[0] = rte_pktmbuf_mtod(pkt[0], uint32_t *);
24 	p[1] = rte_pktmbuf_mtod(pkt[1], uint32_t *);
25 	p[2] = rte_pktmbuf_mtod(pkt[2], uint32_t *);
26 	p[3] = rte_pktmbuf_mtod(pkt[3], uint32_t *);
27 
28 	ve[0] = vreinterpretq_u32_s32(val_eth[dst_port[0]]);
29 	te[0] = vld1q_u32(p[0]);
30 
31 	ve[1] = vreinterpretq_u32_s32(val_eth[dst_port[1]]);
32 	te[1] = vld1q_u32(p[1]);
33 
34 	ve[2] = vreinterpretq_u32_s32(val_eth[dst_port[2]]);
35 	te[2] = vld1q_u32(p[2]);
36 
37 	ve[3] = vreinterpretq_u32_s32(val_eth[dst_port[3]]);
38 	te[3] = vld1q_u32(p[3]);
39 
40 	/* Update last 4 bytes */
41 	ve[0] = vsetq_lane_u32(vgetq_lane_u32(te[0], 3), ve[0], 3);
42 	ve[1] = vsetq_lane_u32(vgetq_lane_u32(te[1], 3), ve[1], 3);
43 	ve[2] = vsetq_lane_u32(vgetq_lane_u32(te[2], 3), ve[2], 3);
44 	ve[3] = vsetq_lane_u32(vgetq_lane_u32(te[3], 3), ve[3], 3);
45 
46 	vst1q_u32(p[0], ve[0]);
47 	vst1q_u32(p[1], ve[1]);
48 	vst1q_u32(p[2], ve[2]);
49 	vst1q_u32(p[3], ve[3]);
50 
51 	rfc1812_process((struct rte_ipv4_hdr *)
52 			((struct rte_ether_hdr *)p[0] + 1),
53 			&dst_port[0], pkt[0]->packet_type);
54 	rfc1812_process((struct rte_ipv4_hdr *)
55 			((struct rte_ether_hdr *)p[1] + 1),
56 			&dst_port[1], pkt[1]->packet_type);
57 	rfc1812_process((struct rte_ipv4_hdr *)
58 			((struct rte_ether_hdr *)p[2] + 1),
59 			&dst_port[2], pkt[2]->packet_type);
60 	rfc1812_process((struct rte_ipv4_hdr *)
61 			((struct rte_ether_hdr *)p[3] + 1),
62 			&dst_port[3], pkt[3]->packet_type);
63 }
64 
65 /*
66  * Group consecutive packets with the same destination port in bursts of 4.
67  * Suppose we have array of destionation ports:
68  * dst_port[] = {a, b, c, d,, e, ... }
69  * dp1 should contain: <a, b, c, d>, dp2: <b, c, d, e>.
70  * We doing 4 comparisons at once and the result is 4 bit mask.
71  * This mask is used as an index into prebuild array of pnum values.
72  */
73 static inline uint16_t *
port_groupx4(uint16_t pn[FWDSTEP+1],uint16_t * lp,uint16x8_t dp1,uint16x8_t dp2)74 port_groupx4(uint16_t pn[FWDSTEP + 1], uint16_t *lp, uint16x8_t dp1,
75 	     uint16x8_t dp2)
76 {
77 	union {
78 		uint16_t u16[FWDSTEP + 1];
79 		uint64_t u64;
80 	} *pnum = (void *)pn;
81 
82 	int32_t v;
83 	uint16x8_t mask = {1, 2, 4, 8, 0, 0, 0, 0};
84 
85 	dp1 = vceqq_u16(dp1, dp2);
86 	dp1 = vandq_u16(dp1, mask);
87 	v = vaddvq_u16(dp1);
88 
89 	/* update last port counter. */
90 	lp[0] += gptbl[v].lpv;
91 	rte_compiler_barrier();
92 
93 	/* if dest port value has changed. */
94 	if (v != GRPMSK) {
95 		pnum->u64 = gptbl[v].pnum;
96 		pnum->u16[FWDSTEP] = 1;
97 		lp = pnum->u16 + gptbl[v].idx;
98 	}
99 
100 	return lp;
101 }
102 
103 /**
104  * Process one packet:
105  * Update source and destination MAC addresses in the ethernet header.
106  * Perform RFC1812 checks and updates for IPV4 packets.
107  */
108 static inline void
process_packet(struct rte_mbuf * pkt,uint16_t * dst_port)109 process_packet(struct rte_mbuf *pkt, uint16_t *dst_port)
110 {
111 	struct rte_ether_hdr *eth_hdr;
112 	uint32x4_t te, ve;
113 
114 	eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
115 
116 	te = vld1q_u32((uint32_t *)eth_hdr);
117 	ve = vreinterpretq_u32_s32(val_eth[dst_port[0]]);
118 
119 
120 	rfc1812_process((struct rte_ipv4_hdr *)(eth_hdr + 1), dst_port,
121 			pkt->packet_type);
122 
123 	ve = vcopyq_laneq_u32(ve, 3, te, 3);
124 	vst1q_u32((uint32_t *)eth_hdr, ve);
125 }
126 
127 /**
128  * Send packets burst from pkts_burst to the ports in dst_port array
129  */
130 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)131 send_packets_multi(struct lcore_conf *qconf, struct rte_mbuf **pkts_burst,
132 		uint16_t dst_port[MAX_PKT_BURST], int nb_rx)
133 {
134 	int32_t k;
135 	int j = 0;
136 	uint16_t dlp;
137 	uint16_t *lp;
138 	uint16_t pnum[MAX_PKT_BURST + 1];
139 
140 	/*
141 	 * Finish packet processing and group consecutive
142 	 * packets with the same destination port.
143 	 */
144 	k = RTE_ALIGN_FLOOR(nb_rx, FWDSTEP);
145 	if (k != 0) {
146 		uint16x8_t dp1, dp2;
147 
148 		lp = pnum;
149 		lp[0] = 1;
150 
151 		processx4_step3(pkts_burst, dst_port);
152 
153 		/* dp1: <d[0], d[1], d[2], d[3], ... > */
154 		dp1 = vld1q_u16(dst_port);
155 
156 		for (j = FWDSTEP; j != k; j += FWDSTEP) {
157 			processx4_step3(&pkts_burst[j], &dst_port[j]);
158 
159 			/*
160 			 * dp2:
161 			 * <d[j-3], d[j-2], d[j-1], d[j], ... >
162 			 */
163 			dp2 = vld1q_u16(&dst_port[j - FWDSTEP + 1]);
164 			lp  = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2);
165 
166 			/*
167 			 * dp1:
168 			 * <d[j], d[j+1], d[j+2], d[j+3], ... >
169 			 */
170 			dp1 = vextq_u16(dp2, dp1, FWDSTEP - 1);
171 		}
172 
173 		/*
174 		 * dp2: <d[j-3], d[j-2], d[j-1], d[j-1], ... >
175 		 */
176 		dp2 = vextq_u16(dp1, dp1, 1);
177 		dp2 = vsetq_lane_u16(vgetq_lane_u16(dp2, 2), dp2, 3);
178 		lp  = port_groupx4(&pnum[j - FWDSTEP], lp, dp1, dp2);
179 
180 		/*
181 		 * remove values added by the last repeated
182 		 * dst port.
183 		 */
184 		lp[0]--;
185 		dlp = dst_port[j - 1];
186 	} else {
187 		/* set dlp and lp to the never used values. */
188 		dlp = BAD_PORT - 1;
189 		lp = pnum + MAX_PKT_BURST;
190 	}
191 
192 	/* Process up to last 3 packets one by one. */
193 	switch (nb_rx % FWDSTEP) {
194 	case 3:
195 		process_packet(pkts_burst[j], dst_port + j);
196 		GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j);
197 		j++;
198 		/* fallthrough */
199 	case 2:
200 		process_packet(pkts_burst[j], dst_port + j);
201 		GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j);
202 		j++;
203 		/* fallthrough */
204 	case 1:
205 		process_packet(pkts_burst[j], dst_port + j);
206 		GROUP_PORT_STEP(dlp, dst_port, lp, pnum, j);
207 		j++;
208 	}
209 
210 	/*
211 	 * Send packets out, through destination port.
212 	 * Consecutive packets with the same destination port
213 	 * are already grouped together.
214 	 * If destination port for the packet equals BAD_PORT,
215 	 * then free the packet without sending it out.
216 	 */
217 	for (j = 0; j < nb_rx; j += k) {
218 
219 		int32_t m;
220 		uint16_t pn;
221 
222 		pn = dst_port[j];
223 		k = pnum[j];
224 
225 		if (likely(pn != BAD_PORT))
226 			send_packetsx4(qconf, pn, pkts_burst + j, k);
227 		else
228 			for (m = j; m != j + k; m++)
229 				rte_pktmbuf_free(pkts_burst[m]);
230 
231 	}
232 }
233 
234 #endif /* _L3FWD_NEON_H_ */
235