xref: /freebsd/sys/contrib/dpdk_rte_lpm/rte_lpm.h (revision 537d134373141c2d25bfb24af6d661d0e6102927)
1*537d1343SAlexander V. Chernikov /* SPDX-License-Identifier: BSD-3-Clause
2*537d1343SAlexander V. Chernikov  * Copyright(c) 2010-2014 Intel Corporation
3*537d1343SAlexander V. Chernikov  */
4*537d1343SAlexander V. Chernikov 
5*537d1343SAlexander V. Chernikov #ifndef _RTE_LPM_H_
6*537d1343SAlexander V. Chernikov #define _RTE_LPM_H_
7*537d1343SAlexander V. Chernikov 
8*537d1343SAlexander V. Chernikov /**
9*537d1343SAlexander V. Chernikov  * @file
10*537d1343SAlexander V. Chernikov  * RTE Longest Prefix Match (LPM)
11*537d1343SAlexander V. Chernikov  */
12*537d1343SAlexander V. Chernikov 
13*537d1343SAlexander V. Chernikov /*
14*537d1343SAlexander V. Chernikov #include <errno.h>
15*537d1343SAlexander V. Chernikov #include <sys/queue.h>
16*537d1343SAlexander V. Chernikov #include <stdint.h>
17*537d1343SAlexander V. Chernikov #include <stdlib.h>
18*537d1343SAlexander V. Chernikov #include <rte_branch_prediction.h>
19*537d1343SAlexander V. Chernikov #include <rte_byteorder.h>
20*537d1343SAlexander V. Chernikov #include <rte_config.h>
21*537d1343SAlexander V. Chernikov #include <rte_memory.h>
22*537d1343SAlexander V. Chernikov #include <rte_common.h>
23*537d1343SAlexander V. Chernikov #include <rte_vect.h>
24*537d1343SAlexander V. Chernikov */
25*537d1343SAlexander V. Chernikov #include "rte_branch_prediction.h"
26*537d1343SAlexander V. Chernikov 
27*537d1343SAlexander V. Chernikov #ifdef __cplusplus
28*537d1343SAlexander V. Chernikov extern "C" {
29*537d1343SAlexander V. Chernikov #endif
30*537d1343SAlexander V. Chernikov 
31*537d1343SAlexander V. Chernikov /** Max number of characters in LPM name. */
32*537d1343SAlexander V. Chernikov #define RTE_LPM_NAMESIZE                16
33*537d1343SAlexander V. Chernikov 
34*537d1343SAlexander V. Chernikov /** Maximum depth value possible for IPv4 LPM. */
35*537d1343SAlexander V. Chernikov #define RTE_LPM_MAX_DEPTH               32
36*537d1343SAlexander V. Chernikov 
37*537d1343SAlexander V. Chernikov /** @internal Total number of tbl24 entries. */
38*537d1343SAlexander V. Chernikov #define RTE_LPM_TBL24_NUM_ENTRIES       (1 << 24)
39*537d1343SAlexander V. Chernikov 
40*537d1343SAlexander V. Chernikov /** @internal Number of entries in a tbl8 group. */
41*537d1343SAlexander V. Chernikov #define RTE_LPM_TBL8_GROUP_NUM_ENTRIES  256
42*537d1343SAlexander V. Chernikov 
43*537d1343SAlexander V. Chernikov /** @internal Max number of tbl8 groups in the tbl8. */
44*537d1343SAlexander V. Chernikov #define RTE_LPM_MAX_TBL8_NUM_GROUPS         (1 << 24)
45*537d1343SAlexander V. Chernikov 
46*537d1343SAlexander V. Chernikov /** @internal Total number of tbl8 groups in the tbl8. */
47*537d1343SAlexander V. Chernikov #define RTE_LPM_TBL8_NUM_GROUPS         256
48*537d1343SAlexander V. Chernikov 
49*537d1343SAlexander V. Chernikov /** @internal Total number of tbl8 entries. */
50*537d1343SAlexander V. Chernikov #define RTE_LPM_TBL8_NUM_ENTRIES        (RTE_LPM_TBL8_NUM_GROUPS * \
51*537d1343SAlexander V. Chernikov 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES)
52*537d1343SAlexander V. Chernikov 
53*537d1343SAlexander V. Chernikov /** @internal Macro to enable/disable run-time checks. */
54*537d1343SAlexander V. Chernikov #if defined(RTE_LIBRTE_LPM_DEBUG)
55*537d1343SAlexander V. Chernikov #define RTE_LPM_RETURN_IF_TRUE(cond, retval) do { \
56*537d1343SAlexander V. Chernikov 	if (cond) return (retval);                \
57*537d1343SAlexander V. Chernikov } while (0)
58*537d1343SAlexander V. Chernikov #else
59*537d1343SAlexander V. Chernikov #define RTE_LPM_RETURN_IF_TRUE(cond, retval)
60*537d1343SAlexander V. Chernikov #endif
61*537d1343SAlexander V. Chernikov 
62*537d1343SAlexander V. Chernikov /** @internal bitmask with valid and valid_group fields set */
63*537d1343SAlexander V. Chernikov #define RTE_LPM_VALID_EXT_ENTRY_BITMASK 0x03000000
64*537d1343SAlexander V. Chernikov 
65*537d1343SAlexander V. Chernikov /** Bitmask used to indicate successful lookup */
66*537d1343SAlexander V. Chernikov #define RTE_LPM_LOOKUP_SUCCESS          0x01000000
67*537d1343SAlexander V. Chernikov 
68*537d1343SAlexander V. Chernikov #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
69*537d1343SAlexander V. Chernikov /** @internal Tbl24 entry structure. */
70*537d1343SAlexander V. Chernikov __extension__
71*537d1343SAlexander V. Chernikov struct rte_lpm_tbl_entry {
72*537d1343SAlexander V. Chernikov 	/**
73*537d1343SAlexander V. Chernikov 	 * Stores Next hop (tbl8 or tbl24 when valid_group is not set) or
74*537d1343SAlexander V. Chernikov 	 * a group index pointing to a tbl8 structure (tbl24 only, when
75*537d1343SAlexander V. Chernikov 	 * valid_group is set)
76*537d1343SAlexander V. Chernikov 	 */
77*537d1343SAlexander V. Chernikov 	uint32_t next_hop    :24;
78*537d1343SAlexander V. Chernikov 	/* Using single uint8_t to store 3 values. */
79*537d1343SAlexander V. Chernikov 	uint32_t valid       :1;   /**< Validation flag. */
80*537d1343SAlexander V. Chernikov 	/**
81*537d1343SAlexander V. Chernikov 	 * For tbl24:
82*537d1343SAlexander V. Chernikov 	 *  - valid_group == 0: entry stores a next hop
83*537d1343SAlexander V. Chernikov 	 *  - valid_group == 1: entry stores a group_index pointing to a tbl8
84*537d1343SAlexander V. Chernikov 	 * For tbl8:
85*537d1343SAlexander V. Chernikov 	 *  - valid_group indicates whether the current tbl8 is in use or not
86*537d1343SAlexander V. Chernikov 	 */
87*537d1343SAlexander V. Chernikov 	uint32_t valid_group :1;
88*537d1343SAlexander V. Chernikov 	uint32_t depth       :6; /**< Rule depth. */
89*537d1343SAlexander V. Chernikov };
90*537d1343SAlexander V. Chernikov 
91*537d1343SAlexander V. Chernikov #else
92*537d1343SAlexander V. Chernikov 
93*537d1343SAlexander V. Chernikov __extension__
94*537d1343SAlexander V. Chernikov struct rte_lpm_tbl_entry {
95*537d1343SAlexander V. Chernikov 	uint32_t depth       :6;
96*537d1343SAlexander V. Chernikov 	uint32_t valid_group :1;
97*537d1343SAlexander V. Chernikov 	uint32_t valid       :1;
98*537d1343SAlexander V. Chernikov 	uint32_t next_hop    :24;
99*537d1343SAlexander V. Chernikov 
100*537d1343SAlexander V. Chernikov };
101*537d1343SAlexander V. Chernikov 
102*537d1343SAlexander V. Chernikov #endif
103*537d1343SAlexander V. Chernikov 
104*537d1343SAlexander V. Chernikov /** LPM configuration structure. */
105*537d1343SAlexander V. Chernikov struct rte_lpm_config {
106*537d1343SAlexander V. Chernikov 	uint32_t max_rules;      /**< Max number of rules. */
107*537d1343SAlexander V. Chernikov 	uint32_t number_tbl8s;   /**< Number of tbl8s to allocate. */
108*537d1343SAlexander V. Chernikov 	int flags;               /**< This field is currently unused. */
109*537d1343SAlexander V. Chernikov };
110*537d1343SAlexander V. Chernikov 
111*537d1343SAlexander V. Chernikov /** @internal Rule structure. */
112*537d1343SAlexander V. Chernikov struct rte_lpm_rule {
113*537d1343SAlexander V. Chernikov 	uint32_t ip; /**< Rule IP address. */
114*537d1343SAlexander V. Chernikov 	uint32_t next_hop; /**< Rule next hop. */
115*537d1343SAlexander V. Chernikov };
116*537d1343SAlexander V. Chernikov 
117*537d1343SAlexander V. Chernikov /** @internal Contains metadata about the rules table. */
118*537d1343SAlexander V. Chernikov struct rte_lpm_rule_info {
119*537d1343SAlexander V. Chernikov 	uint32_t used_rules; /**< Used rules so far. */
120*537d1343SAlexander V. Chernikov 	uint32_t first_rule; /**< Indexes the first rule of a given depth. */
121*537d1343SAlexander V. Chernikov };
122*537d1343SAlexander V. Chernikov 
123*537d1343SAlexander V. Chernikov struct nhop_object;
124*537d1343SAlexander V. Chernikov struct rte_lpm_external {
125*537d1343SAlexander V. Chernikov 	struct nhop_object	**nh_idx;	/**< # -> idx mappings  */
126*537d1343SAlexander V. Chernikov 	uint32_t		default_idx;	/* nhop index of default route */
127*537d1343SAlexander V. Chernikov 	uint32_t		fibnum;		/* fib index */
128*537d1343SAlexander V. Chernikov };
129*537d1343SAlexander V. Chernikov 
130*537d1343SAlexander V. Chernikov /** @internal LPM structure. */
131*537d1343SAlexander V. Chernikov struct rte_lpm {
132*537d1343SAlexander V. Chernikov 	/* LPM metadata. */
133*537d1343SAlexander V. Chernikov 	struct rte_lpm_external ext;
134*537d1343SAlexander V. Chernikov 	char name[RTE_LPM_NAMESIZE];        /**< Name of the lpm. */
135*537d1343SAlexander V. Chernikov 	uint32_t max_rules; /**< Max. balanced rules per lpm. */
136*537d1343SAlexander V. Chernikov 	uint32_t number_tbl8s; /**< Number of tbl8s. */
137*537d1343SAlexander V. Chernikov 	struct rte_lpm_rule_info rule_info[RTE_LPM_MAX_DEPTH]; /**< Rule info table. */
138*537d1343SAlexander V. Chernikov 
139*537d1343SAlexander V. Chernikov 	/* LPM Tables. */
140*537d1343SAlexander V. Chernikov 	struct rte_lpm_tbl_entry tbl24[RTE_LPM_TBL24_NUM_ENTRIES]
141*537d1343SAlexander V. Chernikov 			__rte_cache_aligned; /**< LPM tbl24 table. */
142*537d1343SAlexander V. Chernikov 	struct rte_lpm_tbl_entry *tbl8; /**< LPM tbl8 table. */
143*537d1343SAlexander V. Chernikov 	struct rte_lpm_rule *rules_tbl; /**< LPM rules. */
144*537d1343SAlexander V. Chernikov };
145*537d1343SAlexander V. Chernikov 
146*537d1343SAlexander V. Chernikov /**
147*537d1343SAlexander V. Chernikov  * Create an LPM object.
148*537d1343SAlexander V. Chernikov  *
149*537d1343SAlexander V. Chernikov  * @param name
150*537d1343SAlexander V. Chernikov  *   LPM object name
151*537d1343SAlexander V. Chernikov  * @param socket_id
152*537d1343SAlexander V. Chernikov  *   NUMA socket ID for LPM table memory allocation
153*537d1343SAlexander V. Chernikov  * @param config
154*537d1343SAlexander V. Chernikov  *   Structure containing the configuration
155*537d1343SAlexander V. Chernikov  * @return
156*537d1343SAlexander V. Chernikov  *   Handle to LPM object on success, NULL otherwise with rte_errno set
157*537d1343SAlexander V. Chernikov  *   to an appropriate values. Possible rte_errno values include:
158*537d1343SAlexander V. Chernikov  *    - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure
159*537d1343SAlexander V. Chernikov  *    - E_RTE_SECONDARY - function was called from a secondary process instance
160*537d1343SAlexander V. Chernikov  *    - EINVAL - invalid parameter passed to function
161*537d1343SAlexander V. Chernikov  *    - ENOSPC - the maximum number of memzones has already been allocated
162*537d1343SAlexander V. Chernikov  *    - EEXIST - a memzone with the same name already exists
163*537d1343SAlexander V. Chernikov  *    - ENOMEM - no appropriate memory area found in which to create memzone
164*537d1343SAlexander V. Chernikov  */
165*537d1343SAlexander V. Chernikov struct rte_lpm *
166*537d1343SAlexander V. Chernikov rte_lpm_create(const char *name, int socket_id,
167*537d1343SAlexander V. Chernikov 		const struct rte_lpm_config *config);
168*537d1343SAlexander V. Chernikov 
169*537d1343SAlexander V. Chernikov /**
170*537d1343SAlexander V. Chernikov  * Find an existing LPM object and return a pointer to it.
171*537d1343SAlexander V. Chernikov  *
172*537d1343SAlexander V. Chernikov  * @param name
173*537d1343SAlexander V. Chernikov  *   Name of the lpm object as passed to rte_lpm_create()
174*537d1343SAlexander V. Chernikov  * @return
175*537d1343SAlexander V. Chernikov  *   Pointer to lpm object or NULL if object not found with rte_errno
176*537d1343SAlexander V. Chernikov  *   set appropriately. Possible rte_errno values include:
177*537d1343SAlexander V. Chernikov  *    - ENOENT - required entry not available to return.
178*537d1343SAlexander V. Chernikov  */
179*537d1343SAlexander V. Chernikov struct rte_lpm *
180*537d1343SAlexander V. Chernikov rte_lpm_find_existing(const char *name);
181*537d1343SAlexander V. Chernikov 
182*537d1343SAlexander V. Chernikov /**
183*537d1343SAlexander V. Chernikov  * Free an LPM object.
184*537d1343SAlexander V. Chernikov  *
185*537d1343SAlexander V. Chernikov  * @param lpm
186*537d1343SAlexander V. Chernikov  *   LPM object handle
187*537d1343SAlexander V. Chernikov  * @return
188*537d1343SAlexander V. Chernikov  *   None
189*537d1343SAlexander V. Chernikov  */
190*537d1343SAlexander V. Chernikov void
191*537d1343SAlexander V. Chernikov rte_lpm_free(struct rte_lpm *lpm);
192*537d1343SAlexander V. Chernikov 
193*537d1343SAlexander V. Chernikov /**
194*537d1343SAlexander V. Chernikov  * Add a rule to the LPM table.
195*537d1343SAlexander V. Chernikov  *
196*537d1343SAlexander V. Chernikov  * @param lpm
197*537d1343SAlexander V. Chernikov  *   LPM object handle
198*537d1343SAlexander V. Chernikov  * @param ip
199*537d1343SAlexander V. Chernikov  *   IP of the rule to be added to the LPM table
200*537d1343SAlexander V. Chernikov  * @param depth
201*537d1343SAlexander V. Chernikov  *   Depth of the rule to be added to the LPM table
202*537d1343SAlexander V. Chernikov  * @param next_hop
203*537d1343SAlexander V. Chernikov  *   Next hop of the rule to be added to the LPM table
204*537d1343SAlexander V. Chernikov  * @return
205*537d1343SAlexander V. Chernikov  *   0 on success, negative value otherwise
206*537d1343SAlexander V. Chernikov  */
207*537d1343SAlexander V. Chernikov int
208*537d1343SAlexander V. Chernikov rte_lpm_add(struct rte_lpm *lpm, uint32_t ip, uint8_t depth, uint32_t next_hop);
209*537d1343SAlexander V. Chernikov 
210*537d1343SAlexander V. Chernikov /**
211*537d1343SAlexander V. Chernikov  * Check if a rule is present in the LPM table,
212*537d1343SAlexander V. Chernikov  * and provide its next hop if it is.
213*537d1343SAlexander V. Chernikov  *
214*537d1343SAlexander V. Chernikov  * @param lpm
215*537d1343SAlexander V. Chernikov  *   LPM object handle
216*537d1343SAlexander V. Chernikov  * @param ip
217*537d1343SAlexander V. Chernikov  *   IP of the rule to be searched
218*537d1343SAlexander V. Chernikov  * @param depth
219*537d1343SAlexander V. Chernikov  *   Depth of the rule to searched
220*537d1343SAlexander V. Chernikov  * @param next_hop
221*537d1343SAlexander V. Chernikov  *   Next hop of the rule (valid only if it is found)
222*537d1343SAlexander V. Chernikov  * @return
223*537d1343SAlexander V. Chernikov  *   1 if the rule exists, 0 if it does not, a negative value on failure
224*537d1343SAlexander V. Chernikov  */
225*537d1343SAlexander V. Chernikov int
226*537d1343SAlexander V. Chernikov rte_lpm_is_rule_present(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
227*537d1343SAlexander V. Chernikov uint32_t *next_hop);
228*537d1343SAlexander V. Chernikov 
229*537d1343SAlexander V. Chernikov /**
230*537d1343SAlexander V. Chernikov  * Delete a rule from the LPM table.
231*537d1343SAlexander V. Chernikov  *
232*537d1343SAlexander V. Chernikov  * @param lpm
233*537d1343SAlexander V. Chernikov  *   LPM object handle
234*537d1343SAlexander V. Chernikov  * @param ip
235*537d1343SAlexander V. Chernikov  *   IP of the rule to be deleted from the LPM table
236*537d1343SAlexander V. Chernikov  * @param depth
237*537d1343SAlexander V. Chernikov  *   Depth of the rule to be deleted from the LPM table
238*537d1343SAlexander V. Chernikov  * @param psub_rule_depth
239*537d1343SAlexander V. Chernikov  *   Pointer to depth of the parent rule
240*537d1343SAlexander V. Chernikov  * @param sub_rule_nhop
241*537d1343SAlexander V. Chernikov  *   Pinter to the parent rule nexthop index
242*537d1343SAlexander V. Chernikov  * @return
243*537d1343SAlexander V. Chernikov  *   0 on success, negative value otherwise
244*537d1343SAlexander V. Chernikov  */
245*537d1343SAlexander V. Chernikov int
246*537d1343SAlexander V. Chernikov rte_lpm_delete(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
247*537d1343SAlexander V. Chernikov 	uint8_t sub_rule_depth, uint32_t sub_rule_nhop);
248*537d1343SAlexander V. Chernikov 
249*537d1343SAlexander V. Chernikov /**
250*537d1343SAlexander V. Chernikov  * Delete all rules from the LPM table.
251*537d1343SAlexander V. Chernikov  *
252*537d1343SAlexander V. Chernikov  * @param lpm
253*537d1343SAlexander V. Chernikov  *   LPM object handle
254*537d1343SAlexander V. Chernikov  */
255*537d1343SAlexander V. Chernikov void
256*537d1343SAlexander V. Chernikov rte_lpm_delete_all(struct rte_lpm *lpm);
257*537d1343SAlexander V. Chernikov 
258*537d1343SAlexander V. Chernikov /**
259*537d1343SAlexander V. Chernikov  * Lookup an IP into the LPM table.
260*537d1343SAlexander V. Chernikov  *
261*537d1343SAlexander V. Chernikov  * @param lpm
262*537d1343SAlexander V. Chernikov  *   LPM object handle
263*537d1343SAlexander V. Chernikov  * @param ip
264*537d1343SAlexander V. Chernikov  *   IP to be looked up in the LPM table
265*537d1343SAlexander V. Chernikov  * @param next_hop
266*537d1343SAlexander V. Chernikov  *   Next hop of the most specific rule found for IP (valid on lookup hit only)
267*537d1343SAlexander V. Chernikov  * @return
268*537d1343SAlexander V. Chernikov  *   -EINVAL for incorrect arguments, -ENOENT on lookup miss, 0 on lookup hit
269*537d1343SAlexander V. Chernikov  */
270*537d1343SAlexander V. Chernikov static inline int
rte_lpm_lookup(struct rte_lpm * lpm,uint32_t ip,uint32_t * next_hop)271*537d1343SAlexander V. Chernikov rte_lpm_lookup(struct rte_lpm *lpm, uint32_t ip, uint32_t *next_hop)
272*537d1343SAlexander V. Chernikov {
273*537d1343SAlexander V. Chernikov 	unsigned tbl24_index = (ip >> 8);
274*537d1343SAlexander V. Chernikov 	uint32_t tbl_entry;
275*537d1343SAlexander V. Chernikov 	const uint32_t *ptbl;
276*537d1343SAlexander V. Chernikov 
277*537d1343SAlexander V. Chernikov 	/* DEBUG: Check user input arguments. */
278*537d1343SAlexander V. Chernikov 	RTE_LPM_RETURN_IF_TRUE(((lpm == NULL) || (next_hop == NULL)), -EINVAL);
279*537d1343SAlexander V. Chernikov 
280*537d1343SAlexander V. Chernikov 	/* Copy tbl24 entry */
281*537d1343SAlexander V. Chernikov 	ptbl = (const uint32_t *)(&lpm->tbl24[tbl24_index]);
282*537d1343SAlexander V. Chernikov 	tbl_entry = *ptbl;
283*537d1343SAlexander V. Chernikov 
284*537d1343SAlexander V. Chernikov 	/* Memory ordering is not required in lookup. Because dataflow
285*537d1343SAlexander V. Chernikov 	 * dependency exists, compiler or HW won't be able to re-order
286*537d1343SAlexander V. Chernikov 	 * the operations.
287*537d1343SAlexander V. Chernikov 	 */
288*537d1343SAlexander V. Chernikov 	/* Copy tbl8 entry (only if needed) */
289*537d1343SAlexander V. Chernikov 	if (unlikely((tbl_entry & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
290*537d1343SAlexander V. Chernikov 			RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
291*537d1343SAlexander V. Chernikov 
292*537d1343SAlexander V. Chernikov 		unsigned tbl8_index = (uint8_t)ip +
293*537d1343SAlexander V. Chernikov 				(((uint32_t)tbl_entry & 0x00FFFFFF) *
294*537d1343SAlexander V. Chernikov 						RTE_LPM_TBL8_GROUP_NUM_ENTRIES);
295*537d1343SAlexander V. Chernikov 
296*537d1343SAlexander V. Chernikov 		ptbl = (const uint32_t *)&lpm->tbl8[tbl8_index];
297*537d1343SAlexander V. Chernikov 		tbl_entry = *ptbl;
298*537d1343SAlexander V. Chernikov 	}
299*537d1343SAlexander V. Chernikov 
300*537d1343SAlexander V. Chernikov 	*next_hop = ((uint32_t)tbl_entry & 0x00FFFFFF);
301*537d1343SAlexander V. Chernikov 	return (tbl_entry & RTE_LPM_LOOKUP_SUCCESS) ? 0 : -ENOENT;
302*537d1343SAlexander V. Chernikov }
303*537d1343SAlexander V. Chernikov 
304*537d1343SAlexander V. Chernikov /**
305*537d1343SAlexander V. Chernikov  * Lookup multiple IP addresses in an LPM table. This may be implemented as a
306*537d1343SAlexander V. Chernikov  * macro, so the address of the function should not be used.
307*537d1343SAlexander V. Chernikov  *
308*537d1343SAlexander V. Chernikov  * @param lpm
309*537d1343SAlexander V. Chernikov  *   LPM object handle
310*537d1343SAlexander V. Chernikov  * @param ips
311*537d1343SAlexander V. Chernikov  *   Array of IPs to be looked up in the LPM table
312*537d1343SAlexander V. Chernikov  * @param next_hops
313*537d1343SAlexander V. Chernikov  *   Next hop of the most specific rule found for IP (valid on lookup hit only).
314*537d1343SAlexander V. Chernikov  *   This is an array of two byte values. The most significant byte in each
315*537d1343SAlexander V. Chernikov  *   value says whether the lookup was successful (bitmask
316*537d1343SAlexander V. Chernikov  *   RTE_LPM_LOOKUP_SUCCESS is set). The least significant byte is the
317*537d1343SAlexander V. Chernikov  *   actual next hop.
318*537d1343SAlexander V. Chernikov  * @param n
319*537d1343SAlexander V. Chernikov  *   Number of elements in ips (and next_hops) array to lookup. This should be a
320*537d1343SAlexander V. Chernikov  *   compile time constant, and divisible by 8 for best performance.
321*537d1343SAlexander V. Chernikov  *  @return
322*537d1343SAlexander V. Chernikov  *   -EINVAL for incorrect arguments, otherwise 0
323*537d1343SAlexander V. Chernikov  */
324*537d1343SAlexander V. Chernikov #define rte_lpm_lookup_bulk(lpm, ips, next_hops, n) \
325*537d1343SAlexander V. Chernikov 		rte_lpm_lookup_bulk_func(lpm, ips, next_hops, n)
326*537d1343SAlexander V. Chernikov 
327*537d1343SAlexander V. Chernikov static inline int
rte_lpm_lookup_bulk_func(const struct rte_lpm * lpm,const uint32_t * ips,uint32_t * next_hops,const unsigned n)328*537d1343SAlexander V. Chernikov rte_lpm_lookup_bulk_func(const struct rte_lpm *lpm, const uint32_t *ips,
329*537d1343SAlexander V. Chernikov 		uint32_t *next_hops, const unsigned n)
330*537d1343SAlexander V. Chernikov {
331*537d1343SAlexander V. Chernikov 	unsigned i;
332*537d1343SAlexander V. Chernikov 	unsigned tbl24_indexes[n];
333*537d1343SAlexander V. Chernikov 	const uint32_t *ptbl;
334*537d1343SAlexander V. Chernikov 
335*537d1343SAlexander V. Chernikov 	/* DEBUG: Check user input arguments. */
336*537d1343SAlexander V. Chernikov 	RTE_LPM_RETURN_IF_TRUE(((lpm == NULL) || (ips == NULL) ||
337*537d1343SAlexander V. Chernikov 			(next_hops == NULL)), -EINVAL);
338*537d1343SAlexander V. Chernikov 
339*537d1343SAlexander V. Chernikov 	for (i = 0; i < n; i++) {
340*537d1343SAlexander V. Chernikov 		tbl24_indexes[i] = ips[i] >> 8;
341*537d1343SAlexander V. Chernikov 	}
342*537d1343SAlexander V. Chernikov 
343*537d1343SAlexander V. Chernikov 	for (i = 0; i < n; i++) {
344*537d1343SAlexander V. Chernikov 		/* Simply copy tbl24 entry to output */
345*537d1343SAlexander V. Chernikov 		ptbl = (const uint32_t *)&lpm->tbl24[tbl24_indexes[i]];
346*537d1343SAlexander V. Chernikov 		next_hops[i] = *ptbl;
347*537d1343SAlexander V. Chernikov 
348*537d1343SAlexander V. Chernikov 		/* Overwrite output with tbl8 entry if needed */
349*537d1343SAlexander V. Chernikov 		if (unlikely((next_hops[i] & RTE_LPM_VALID_EXT_ENTRY_BITMASK) ==
350*537d1343SAlexander V. Chernikov 				RTE_LPM_VALID_EXT_ENTRY_BITMASK)) {
351*537d1343SAlexander V. Chernikov 
352*537d1343SAlexander V. Chernikov 			unsigned tbl8_index = (uint8_t)ips[i] +
353*537d1343SAlexander V. Chernikov 					(((uint32_t)next_hops[i] & 0x00FFFFFF) *
354*537d1343SAlexander V. Chernikov 					 RTE_LPM_TBL8_GROUP_NUM_ENTRIES);
355*537d1343SAlexander V. Chernikov 
356*537d1343SAlexander V. Chernikov 			ptbl = (const uint32_t *)&lpm->tbl8[tbl8_index];
357*537d1343SAlexander V. Chernikov 			next_hops[i] = *ptbl;
358*537d1343SAlexander V. Chernikov 		}
359*537d1343SAlexander V. Chernikov 	}
360*537d1343SAlexander V. Chernikov 	return 0;
361*537d1343SAlexander V. Chernikov }
362*537d1343SAlexander V. Chernikov 
363*537d1343SAlexander V. Chernikov /* Mask four results. */
364*537d1343SAlexander V. Chernikov #define	 RTE_LPM_MASKX4_RES	UINT64_C(0x00ffffff00ffffff)
365*537d1343SAlexander V. Chernikov 
366*537d1343SAlexander V. Chernikov /**
367*537d1343SAlexander V. Chernikov  * Lookup four IP addresses in an LPM table.
368*537d1343SAlexander V. Chernikov  *
369*537d1343SAlexander V. Chernikov  * @param lpm
370*537d1343SAlexander V. Chernikov  *   LPM object handle
371*537d1343SAlexander V. Chernikov  * @param ip
372*537d1343SAlexander V. Chernikov  *   Four IPs to be looked up in the LPM table
373*537d1343SAlexander V. Chernikov  * @param hop
374*537d1343SAlexander V. Chernikov  *   Next hop of the most specific rule found for IP (valid on lookup hit only).
375*537d1343SAlexander V. Chernikov  *   This is an 4 elements array of two byte values.
376*537d1343SAlexander V. Chernikov  *   If the lookup was successful for the given IP, then least significant byte
377*537d1343SAlexander V. Chernikov  *   of the corresponding element is the  actual next hop and the most
378*537d1343SAlexander V. Chernikov  *   significant byte is zero.
379*537d1343SAlexander V. Chernikov  *   If the lookup for the given IP failed, then corresponding element would
380*537d1343SAlexander V. Chernikov  *   contain default value, see description of then next parameter.
381*537d1343SAlexander V. Chernikov  * @param defv
382*537d1343SAlexander V. Chernikov  *   Default value to populate into corresponding element of hop[] array,
383*537d1343SAlexander V. Chernikov  *   if lookup would fail.
384*537d1343SAlexander V. Chernikov  */
385*537d1343SAlexander V. Chernikov #if 0
386*537d1343SAlexander V. Chernikov static inline void
387*537d1343SAlexander V. Chernikov rte_lpm_lookupx4(const struct rte_lpm *lpm, xmm_t ip, uint32_t hop[4],
388*537d1343SAlexander V. Chernikov 	uint32_t defv);
389*537d1343SAlexander V. Chernikov 
390*537d1343SAlexander V. Chernikov #if defined(RTE_ARCH_ARM) || defined(RTE_ARCH_ARM64)
391*537d1343SAlexander V. Chernikov #include "rte_lpm_neon.h"
392*537d1343SAlexander V. Chernikov #elif defined(RTE_ARCH_PPC_64)
393*537d1343SAlexander V. Chernikov #include "rte_lpm_altivec.h"
394*537d1343SAlexander V. Chernikov #else
395*537d1343SAlexander V. Chernikov #include "rte_lpm_sse.h"
396*537d1343SAlexander V. Chernikov #endif
397*537d1343SAlexander V. Chernikov #endif
398*537d1343SAlexander V. Chernikov 
399*537d1343SAlexander V. Chernikov #ifdef __cplusplus
400*537d1343SAlexander V. Chernikov }
401*537d1343SAlexander V. Chernikov #endif
402*537d1343SAlexander V. Chernikov 
403*537d1343SAlexander V. Chernikov #endif /* _RTE_LPM_H_ */
404