examples/l3fwd: reorganise multi hash lookup
[dpdk.git] / examples / l3fwd / l3fwd_em_hlm.h
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5  *   Copyright(c) 2017, Linaro Limited
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #ifndef __L3FWD_EM_HLM_H__
36 #define __L3FWD_EM_HLM_H__
37
38 #include "l3fwd_sse.h"
39 #include "l3fwd_em_hlm_sse.h"
40
41 static __rte_always_inline void
42 em_get_dst_port_ipv4x8(struct lcore_conf *qconf, struct rte_mbuf *m[8],
43                 uint8_t portid, uint16_t dst_port[8])
44 {
45         int32_t ret[8];
46         union ipv4_5tuple_host key[8];
47
48         get_ipv4_5tuple(m[0], mask0.x, &key[0]);
49         get_ipv4_5tuple(m[1], mask0.x, &key[1]);
50         get_ipv4_5tuple(m[2], mask0.x, &key[2]);
51         get_ipv4_5tuple(m[3], mask0.x, &key[3]);
52         get_ipv4_5tuple(m[4], mask0.x, &key[4]);
53         get_ipv4_5tuple(m[5], mask0.x, &key[5]);
54         get_ipv4_5tuple(m[6], mask0.x, &key[6]);
55         get_ipv4_5tuple(m[7], mask0.x, &key[7]);
56
57         const void *key_array[8] = {&key[0], &key[1], &key[2], &key[3],
58                                 &key[4], &key[5], &key[6], &key[7]};
59
60         rte_hash_lookup_bulk(qconf->ipv4_lookup_struct, &key_array[0], 8, ret);
61
62         dst_port[0] = (uint8_t) ((ret[0] < 0) ?
63                         portid : ipv4_l3fwd_out_if[ret[0]]);
64         dst_port[1] = (uint8_t) ((ret[1] < 0) ?
65                         portid : ipv4_l3fwd_out_if[ret[1]]);
66         dst_port[2] = (uint8_t) ((ret[2] < 0) ?
67                         portid : ipv4_l3fwd_out_if[ret[2]]);
68         dst_port[3] = (uint8_t) ((ret[3] < 0) ?
69                         portid : ipv4_l3fwd_out_if[ret[3]]);
70         dst_port[4] = (uint8_t) ((ret[4] < 0) ?
71                         portid : ipv4_l3fwd_out_if[ret[4]]);
72         dst_port[5] = (uint8_t) ((ret[5] < 0) ?
73                         portid : ipv4_l3fwd_out_if[ret[5]]);
74         dst_port[6] = (uint8_t) ((ret[6] < 0) ?
75                         portid : ipv4_l3fwd_out_if[ret[6]]);
76         dst_port[7] = (uint8_t) ((ret[7] < 0) ?
77                         portid : ipv4_l3fwd_out_if[ret[7]]);
78
79         if (dst_port[0] >= RTE_MAX_ETHPORTS ||
80                         (enabled_port_mask & 1 << dst_port[0]) == 0)
81                 dst_port[0] = portid;
82
83         if (dst_port[1] >= RTE_MAX_ETHPORTS ||
84                         (enabled_port_mask & 1 << dst_port[1]) == 0)
85                 dst_port[1] = portid;
86
87         if (dst_port[2] >= RTE_MAX_ETHPORTS ||
88                         (enabled_port_mask & 1 << dst_port[2]) == 0)
89                 dst_port[2] = portid;
90
91         if (dst_port[3] >= RTE_MAX_ETHPORTS ||
92                         (enabled_port_mask & 1 << dst_port[3]) == 0)
93                 dst_port[3] = portid;
94
95         if (dst_port[4] >= RTE_MAX_ETHPORTS ||
96                         (enabled_port_mask & 1 << dst_port[4]) == 0)
97                 dst_port[4] = portid;
98
99         if (dst_port[5] >= RTE_MAX_ETHPORTS ||
100                         (enabled_port_mask & 1 << dst_port[5]) == 0)
101                 dst_port[5] = portid;
102
103         if (dst_port[6] >= RTE_MAX_ETHPORTS ||
104                         (enabled_port_mask & 1 << dst_port[6]) == 0)
105                 dst_port[6] = portid;
106
107         if (dst_port[7] >= RTE_MAX_ETHPORTS ||
108                         (enabled_port_mask & 1 << dst_port[7]) == 0)
109                 dst_port[7] = portid;
110
111 }
112
113 static __rte_always_inline void
114 em_get_dst_port_ipv6x8(struct lcore_conf *qconf, struct rte_mbuf *m[8],
115                 uint8_t portid, uint16_t dst_port[8])
116 {
117         int32_t ret[8];
118         union ipv6_5tuple_host key[8];
119
120         get_ipv6_5tuple(m[0], mask1.x, mask2.x, &key[0]);
121         get_ipv6_5tuple(m[1], mask1.x, mask2.x, &key[1]);
122         get_ipv6_5tuple(m[2], mask1.x, mask2.x, &key[2]);
123         get_ipv6_5tuple(m[3], mask1.x, mask2.x, &key[3]);
124         get_ipv6_5tuple(m[4], mask1.x, mask2.x, &key[4]);
125         get_ipv6_5tuple(m[5], mask1.x, mask2.x, &key[5]);
126         get_ipv6_5tuple(m[6], mask1.x, mask2.x, &key[6]);
127         get_ipv6_5tuple(m[7], mask1.x, mask2.x, &key[7]);
128
129         const void *key_array[8] = {&key[0], &key[1], &key[2], &key[3],
130                         &key[4], &key[5], &key[6], &key[7]};
131
132         rte_hash_lookup_bulk(qconf->ipv6_lookup_struct, &key_array[0], 8, ret);
133
134         dst_port[0] = (uint8_t) ((ret[0] < 0) ?
135                         portid : ipv6_l3fwd_out_if[ret[0]]);
136         dst_port[1] = (uint8_t) ((ret[1] < 0) ?
137                         portid : ipv6_l3fwd_out_if[ret[1]]);
138         dst_port[2] = (uint8_t) ((ret[2] < 0) ?
139                         portid : ipv6_l3fwd_out_if[ret[2]]);
140         dst_port[3] = (uint8_t) ((ret[3] < 0) ?
141                         portid : ipv6_l3fwd_out_if[ret[3]]);
142         dst_port[4] = (uint8_t) ((ret[4] < 0) ?
143                         portid : ipv6_l3fwd_out_if[ret[4]]);
144         dst_port[5] = (uint8_t) ((ret[5] < 0) ?
145                         portid : ipv6_l3fwd_out_if[ret[5]]);
146         dst_port[6] = (uint8_t) ((ret[6] < 0) ?
147                         portid : ipv6_l3fwd_out_if[ret[6]]);
148         dst_port[7] = (uint8_t) ((ret[7] < 0) ?
149                         portid : ipv6_l3fwd_out_if[ret[7]]);
150
151         if (dst_port[0] >= RTE_MAX_ETHPORTS ||
152                         (enabled_port_mask & 1 << dst_port[0]) == 0)
153                 dst_port[0] = portid;
154
155         if (dst_port[1] >= RTE_MAX_ETHPORTS ||
156                         (enabled_port_mask & 1 << dst_port[1]) == 0)
157                 dst_port[1] = portid;
158
159         if (dst_port[2] >= RTE_MAX_ETHPORTS ||
160                         (enabled_port_mask & 1 << dst_port[2]) == 0)
161                 dst_port[2] = portid;
162
163         if (dst_port[3] >= RTE_MAX_ETHPORTS ||
164                         (enabled_port_mask & 1 << dst_port[3]) == 0)
165                 dst_port[3] = portid;
166
167         if (dst_port[4] >= RTE_MAX_ETHPORTS ||
168                         (enabled_port_mask & 1 << dst_port[4]) == 0)
169                 dst_port[4] = portid;
170
171         if (dst_port[5] >= RTE_MAX_ETHPORTS ||
172                         (enabled_port_mask & 1 << dst_port[5]) == 0)
173                 dst_port[5] = portid;
174
175         if (dst_port[6] >= RTE_MAX_ETHPORTS ||
176                         (enabled_port_mask & 1 << dst_port[6]) == 0)
177                 dst_port[6] = portid;
178
179         if (dst_port[7] >= RTE_MAX_ETHPORTS ||
180                         (enabled_port_mask & 1 << dst_port[7]) == 0)
181                 dst_port[7] = portid;
182
183 }
184
185 static __rte_always_inline uint16_t
186 em_get_dst_port(const struct lcore_conf *qconf, struct rte_mbuf *pkt,
187                 uint8_t portid)
188 {
189         uint8_t next_hop;
190         struct ipv4_hdr *ipv4_hdr;
191         struct ipv6_hdr *ipv6_hdr;
192         uint32_t tcp_or_udp;
193         uint32_t l3_ptypes;
194
195         tcp_or_udp = pkt->packet_type & (RTE_PTYPE_L4_TCP | RTE_PTYPE_L4_UDP);
196         l3_ptypes = pkt->packet_type & RTE_PTYPE_L3_MASK;
197
198         if (tcp_or_udp && (l3_ptypes == RTE_PTYPE_L3_IPV4)) {
199
200                 /* Handle IPv4 headers.*/
201                 ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
202                                 sizeof(struct ether_hdr));
203
204                 next_hop = em_get_ipv4_dst_port(ipv4_hdr, portid,
205                                 qconf->ipv4_lookup_struct);
206
207                 if (next_hop >= RTE_MAX_ETHPORTS ||
208                                 (enabled_port_mask & 1 << next_hop) == 0)
209                         next_hop = portid;
210
211                 return next_hop;
212
213         } else if (tcp_or_udp && (l3_ptypes == RTE_PTYPE_L3_IPV6)) {
214
215                 /* Handle IPv6 headers.*/
216                 ipv6_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv6_hdr *,
217                                 sizeof(struct ether_hdr));
218
219                 next_hop = em_get_ipv6_dst_port(ipv6_hdr, portid,
220                                 qconf->ipv6_lookup_struct);
221
222                 if (next_hop >= RTE_MAX_ETHPORTS ||
223                                 (enabled_port_mask & 1 << next_hop) == 0)
224                         next_hop = portid;
225
226                 return next_hop;
227
228         }
229
230         return portid;
231 }
232
233 /*
234  * Buffer optimized handling of packets, invoked
235  * from main_loop.
236  */
237 static inline void
238 l3fwd_em_send_packets(int nb_rx, struct rte_mbuf **pkts_burst,
239                 uint8_t portid, struct lcore_conf *qconf)
240 {
241         int32_t j;
242         uint16_t dst_port[MAX_PKT_BURST];
243
244         /*
245          * Send nb_rx - nb_rx%8 packets
246          * in groups of 8.
247          */
248         int32_t n = RTE_ALIGN_FLOOR(nb_rx, 8);
249
250         for (j = 0; j < n; j += 8) {
251
252                 uint32_t pkt_type =
253                         pkts_burst[j]->packet_type &
254                         pkts_burst[j+1]->packet_type &
255                         pkts_burst[j+2]->packet_type &
256                         pkts_burst[j+3]->packet_type &
257                         pkts_burst[j+4]->packet_type &
258                         pkts_burst[j+5]->packet_type &
259                         pkts_burst[j+6]->packet_type &
260                         pkts_burst[j+7]->packet_type;
261
262                 uint32_t l3_type = pkt_type & RTE_PTYPE_L3_MASK;
263                 uint32_t tcp_or_udp = pkt_type &
264                         (RTE_PTYPE_L4_TCP | RTE_PTYPE_L4_UDP);
265
266                 if (tcp_or_udp && (l3_type == RTE_PTYPE_L3_IPV4)) {
267
268                         em_get_dst_port_ipv4x8(qconf, &pkts_burst[j], portid,
269                                                &dst_port[j]);
270
271                 } else if (tcp_or_udp && (l3_type == RTE_PTYPE_L3_IPV6)) {
272
273                         em_get_dst_port_ipv6x8(qconf, &pkts_burst[j], portid,
274                                                &dst_port[j]);
275
276                 } else {
277                         dst_port[j]   = em_get_dst_port(qconf, pkts_burst[j],
278                                                         portid);
279                         dst_port[j+1] = em_get_dst_port(qconf, pkts_burst[j+1],
280                                                         portid);
281                         dst_port[j+2] = em_get_dst_port(qconf, pkts_burst[j+2],
282                                                         portid);
283                         dst_port[j+3] = em_get_dst_port(qconf, pkts_burst[j+3],
284                                                         portid);
285                         dst_port[j+4] = em_get_dst_port(qconf, pkts_burst[j+4],
286                                                         portid);
287                         dst_port[j+5] = em_get_dst_port(qconf, pkts_burst[j+5],
288                                                         portid);
289                         dst_port[j+6] = em_get_dst_port(qconf, pkts_burst[j+6],
290                                                         portid);
291                         dst_port[j+7] = em_get_dst_port(qconf, pkts_burst[j+7],
292                                                         portid);
293                 }
294         }
295
296         for (; j < nb_rx; j++)
297                 dst_port[j] = em_get_dst_port(qconf, pkts_burst[j], portid);
298
299         send_packets_multi(qconf, pkts_burst, dst_port, nb_rx);
300
301 }
302 #endif /* __L3FWD_EM_HLM_H__ */