xref: /f-stack/dpdk/lib/librte_lpm/rte_lpm.c (revision 031be553)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <string.h>
35 #include <stdint.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <sys/queue.h>
40 
41 #include <rte_log.h>
42 #include <rte_branch_prediction.h>
43 #include <rte_common.h>
44 #include <rte_memory.h>        /* for definition of RTE_CACHE_LINE_SIZE */
45 #include <rte_malloc.h>
46 #include <rte_eal.h>
47 #include <rte_eal_memconfig.h>
48 #include <rte_per_lcore.h>
49 #include <rte_string_fns.h>
50 #include <rte_errno.h>
51 #include <rte_rwlock.h>
52 #include <rte_spinlock.h>
53 
54 #include "rte_lpm.h"
55 
56 TAILQ_HEAD(rte_lpm_list, rte_tailq_entry);
57 
58 static struct rte_tailq_elem rte_lpm_tailq = {
59 	.name = "RTE_LPM",
60 };
61 EAL_REGISTER_TAILQ(rte_lpm_tailq)
62 
63 #define MAX_DEPTH_TBL24 24
64 
65 enum valid_flag {
66 	INVALID = 0,
67 	VALID
68 };
69 
70 /* Macro to enable/disable run-time checks. */
71 #if defined(RTE_LIBRTE_LPM_DEBUG)
72 #include <rte_debug.h>
73 #define VERIFY_DEPTH(depth) do {                                \
74 	if ((depth == 0) || (depth > RTE_LPM_MAX_DEPTH))        \
75 		rte_panic("LPM: Invalid depth (%u) at line %d", \
76 				(unsigned)(depth), __LINE__);   \
77 } while (0)
78 #else
79 #define VERIFY_DEPTH(depth)
80 #endif
81 
82 /*
83  * Converts a given depth value to its corresponding mask value.
84  *
85  * depth  (IN)		: range = 1 - 32
86  * mask   (OUT)		: 32bit mask
87  */
88 static uint32_t __attribute__((pure))
89 depth_to_mask(uint8_t depth)
90 {
91 	VERIFY_DEPTH(depth);
92 
93 	/* To calculate a mask start with a 1 on the left hand side and right
94 	 * shift while populating the left hand side with 1's
95 	 */
96 	return (int)0x80000000 >> (depth - 1);
97 }
98 
99 /*
100  * Converts given depth value to its corresponding range value.
101  */
102 static inline uint32_t __attribute__((pure))
103 depth_to_range(uint8_t depth)
104 {
105 	VERIFY_DEPTH(depth);
106 
107 	/*
108 	 * Calculate tbl24 range. (Note: 2^depth = 1 << depth)
109 	 */
110 	if (depth <= MAX_DEPTH_TBL24)
111 		return 1 << (MAX_DEPTH_TBL24 - depth);
112 
113 	/* Else if depth is greater than 24 */
114 	return 1 << (RTE_LPM_MAX_DEPTH - depth);
115 }
116 
117 /*
118  * Find an existing lpm table and return a pointer to it.
119  */
120 struct rte_lpm_v20 *
121 rte_lpm_find_existing_v20(const char *name)
122 {
123 	struct rte_lpm_v20 *l = NULL;
124 	struct rte_tailq_entry *te;
125 	struct rte_lpm_list *lpm_list;
126 
127 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
128 
129 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
130 	TAILQ_FOREACH(te, lpm_list, next) {
131 		l = (struct rte_lpm_v20 *) te->data;
132 		if (strncmp(name, l->name, RTE_LPM_NAMESIZE) == 0)
133 			break;
134 	}
135 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
136 
137 	if (te == NULL) {
138 		rte_errno = ENOENT;
139 		return NULL;
140 	}
141 
142 	return l;
143 }
144 VERSION_SYMBOL(rte_lpm_find_existing, _v20, 2.0);
145 
146 struct rte_lpm *
147 rte_lpm_find_existing_v1604(const char *name)
148 {
149 	struct rte_lpm *l = NULL;
150 	struct rte_tailq_entry *te;
151 	struct rte_lpm_list *lpm_list;
152 
153 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
154 
155 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
156 	TAILQ_FOREACH(te, lpm_list, next) {
157 		l = (struct rte_lpm *) te->data;
158 		if (strncmp(name, l->name, RTE_LPM_NAMESIZE) == 0)
159 			break;
160 	}
161 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
162 
163 	if (te == NULL) {
164 		rte_errno = ENOENT;
165 		return NULL;
166 	}
167 
168 	return l;
169 }
170 BIND_DEFAULT_SYMBOL(rte_lpm_find_existing, _v1604, 16.04);
171 MAP_STATIC_SYMBOL(struct rte_lpm *rte_lpm_find_existing(const char *name),
172 		rte_lpm_find_existing_v1604);
173 
174 /*
175  * Allocates memory for LPM object
176  */
177 struct rte_lpm_v20 *
178 rte_lpm_create_v20(const char *name, int socket_id, int max_rules,
179 		__rte_unused int flags)
180 {
181 	char mem_name[RTE_LPM_NAMESIZE];
182 	struct rte_lpm_v20 *lpm = NULL;
183 	struct rte_tailq_entry *te;
184 	uint32_t mem_size;
185 	struct rte_lpm_list *lpm_list;
186 
187 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
188 
189 	RTE_BUILD_BUG_ON(sizeof(struct rte_lpm_tbl_entry_v20) != 2);
190 
191 	/* Check user arguments. */
192 	if ((name == NULL) || (socket_id < -1) || (max_rules == 0)) {
193 		rte_errno = EINVAL;
194 		return NULL;
195 	}
196 
197 	snprintf(mem_name, sizeof(mem_name), "LPM_%s", name);
198 
199 	/* Determine the amount of memory to allocate. */
200 	mem_size = sizeof(*lpm) + (sizeof(lpm->rules_tbl[0]) * max_rules);
201 
202 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
203 
204 	/* guarantee there's no existing */
205 	TAILQ_FOREACH(te, lpm_list, next) {
206 		lpm = (struct rte_lpm_v20 *) te->data;
207 		if (strncmp(name, lpm->name, RTE_LPM_NAMESIZE) == 0)
208 			break;
209 	}
210 	lpm = NULL;
211 	if (te != NULL) {
212 		rte_errno = EEXIST;
213 		goto exit;
214 	}
215 
216 	/* allocate tailq entry */
217 	te = rte_zmalloc("LPM_TAILQ_ENTRY", sizeof(*te), 0);
218 	if (te == NULL) {
219 		RTE_LOG(ERR, LPM, "Failed to allocate tailq entry\n");
220 		rte_errno = ENOMEM;
221 		goto exit;
222 	}
223 
224 	/* Allocate memory to store the LPM data structures. */
225 	lpm = (struct rte_lpm_v20 *)rte_zmalloc_socket(mem_name, mem_size,
226 			RTE_CACHE_LINE_SIZE, socket_id);
227 	if (lpm == NULL) {
228 		RTE_LOG(ERR, LPM, "LPM memory allocation failed\n");
229 		rte_free(te);
230 		rte_errno = ENOMEM;
231 		goto exit;
232 	}
233 
234 	/* Save user arguments. */
235 	lpm->max_rules = max_rules;
236 	snprintf(lpm->name, sizeof(lpm->name), "%s", name);
237 
238 	te->data = (void *) lpm;
239 
240 	TAILQ_INSERT_TAIL(lpm_list, te, next);
241 
242 exit:
243 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
244 
245 	return lpm;
246 }
247 VERSION_SYMBOL(rte_lpm_create, _v20, 2.0);
248 
249 struct rte_lpm *
250 rte_lpm_create_v1604(const char *name, int socket_id,
251 		const struct rte_lpm_config *config)
252 {
253 	char mem_name[RTE_LPM_NAMESIZE];
254 	struct rte_lpm *lpm = NULL;
255 	struct rte_tailq_entry *te;
256 	uint32_t mem_size, rules_size, tbl8s_size;
257 	struct rte_lpm_list *lpm_list;
258 
259 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
260 
261 	RTE_BUILD_BUG_ON(sizeof(struct rte_lpm_tbl_entry) != 4);
262 
263 	/* Check user arguments. */
264 	if ((name == NULL) || (socket_id < -1) || (config->max_rules == 0)
265 			|| config->number_tbl8s > RTE_LPM_MAX_TBL8_NUM_GROUPS) {
266 		rte_errno = EINVAL;
267 		return NULL;
268 	}
269 
270 	snprintf(mem_name, sizeof(mem_name), "LPM_%s", name);
271 
272 	/* Determine the amount of memory to allocate. */
273 	mem_size = sizeof(*lpm);
274 	rules_size = sizeof(struct rte_lpm_rule) * config->max_rules;
275 	tbl8s_size = (sizeof(struct rte_lpm_tbl_entry) *
276 			RTE_LPM_TBL8_GROUP_NUM_ENTRIES * config->number_tbl8s);
277 
278 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
279 
280 	/* guarantee there's no existing */
281 	TAILQ_FOREACH(te, lpm_list, next) {
282 		lpm = (struct rte_lpm *) te->data;
283 		if (strncmp(name, lpm->name, RTE_LPM_NAMESIZE) == 0)
284 			break;
285 	}
286 	lpm = NULL;
287 	if (te != NULL) {
288 		rte_errno = EEXIST;
289 		goto exit;
290 	}
291 
292 	/* allocate tailq entry */
293 	te = rte_zmalloc("LPM_TAILQ_ENTRY", sizeof(*te), 0);
294 	if (te == NULL) {
295 		RTE_LOG(ERR, LPM, "Failed to allocate tailq entry\n");
296 		rte_errno = ENOMEM;
297 		goto exit;
298 	}
299 
300 	/* Allocate memory to store the LPM data structures. */
301 	lpm = (struct rte_lpm *)rte_zmalloc_socket(mem_name, mem_size,
302 			RTE_CACHE_LINE_SIZE, socket_id);
303 	if (lpm == NULL) {
304 		RTE_LOG(ERR, LPM, "LPM memory allocation failed\n");
305 		rte_free(te);
306 		rte_errno = ENOMEM;
307 		goto exit;
308 	}
309 
310 	lpm->rules_tbl = (struct rte_lpm_rule *)rte_zmalloc_socket(NULL,
311 			(size_t)rules_size, RTE_CACHE_LINE_SIZE, socket_id);
312 
313 	if (lpm->rules_tbl == NULL) {
314 		RTE_LOG(ERR, LPM, "LPM rules_tbl memory allocation failed\n");
315 		rte_free(lpm);
316 		lpm = NULL;
317 		rte_free(te);
318 		rte_errno = ENOMEM;
319 		goto exit;
320 	}
321 
322 	lpm->tbl8 = (struct rte_lpm_tbl_entry *)rte_zmalloc_socket(NULL,
323 			(size_t)tbl8s_size, RTE_CACHE_LINE_SIZE, socket_id);
324 
325 	if (lpm->tbl8 == NULL) {
326 		RTE_LOG(ERR, LPM, "LPM tbl8 memory allocation failed\n");
327 		rte_free(lpm->rules_tbl);
328 		rte_free(lpm);
329 		lpm = NULL;
330 		rte_free(te);
331 		rte_errno = ENOMEM;
332 		goto exit;
333 	}
334 
335 	/* Save user arguments. */
336 	lpm->max_rules = config->max_rules;
337 	lpm->number_tbl8s = config->number_tbl8s;
338 	snprintf(lpm->name, sizeof(lpm->name), "%s", name);
339 
340 	te->data = (void *) lpm;
341 
342 	TAILQ_INSERT_TAIL(lpm_list, te, next);
343 
344 exit:
345 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
346 
347 	return lpm;
348 }
349 BIND_DEFAULT_SYMBOL(rte_lpm_create, _v1604, 16.04);
350 MAP_STATIC_SYMBOL(
351 	struct rte_lpm *rte_lpm_create(const char *name, int socket_id,
352 			const struct rte_lpm_config *config), rte_lpm_create_v1604);
353 
354 /*
355  * Deallocates memory for given LPM table.
356  */
357 void
358 rte_lpm_free_v20(struct rte_lpm_v20 *lpm)
359 {
360 	struct rte_lpm_list *lpm_list;
361 	struct rte_tailq_entry *te;
362 
363 	/* Check user arguments. */
364 	if (lpm == NULL)
365 		return;
366 
367 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
368 
369 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
370 
371 	/* find our tailq entry */
372 	TAILQ_FOREACH(te, lpm_list, next) {
373 		if (te->data == (void *) lpm)
374 			break;
375 	}
376 	if (te != NULL)
377 		TAILQ_REMOVE(lpm_list, te, next);
378 
379 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
380 
381 	rte_free(lpm);
382 	rte_free(te);
383 }
384 VERSION_SYMBOL(rte_lpm_free, _v20, 2.0);
385 
386 void
387 rte_lpm_free_v1604(struct rte_lpm *lpm)
388 {
389 	struct rte_lpm_list *lpm_list;
390 	struct rte_tailq_entry *te;
391 
392 	/* Check user arguments. */
393 	if (lpm == NULL)
394 		return;
395 
396 	lpm_list = RTE_TAILQ_CAST(rte_lpm_tailq.head, rte_lpm_list);
397 
398 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
399 
400 	/* find our tailq entry */
401 	TAILQ_FOREACH(te, lpm_list, next) {
402 		if (te->data == (void *) lpm)
403 			break;
404 	}
405 	if (te != NULL)
406 		TAILQ_REMOVE(lpm_list, te, next);
407 
408 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
409 
410 	rte_free(lpm->tbl8);
411 	rte_free(lpm->rules_tbl);
412 	rte_free(lpm);
413 	rte_free(te);
414 }
415 BIND_DEFAULT_SYMBOL(rte_lpm_free, _v1604, 16.04);
416 MAP_STATIC_SYMBOL(void rte_lpm_free(struct rte_lpm *lpm),
417 		rte_lpm_free_v1604);
418 
419 /*
420  * Adds a rule to the rule table.
421  *
422  * NOTE: The rule table is split into 32 groups. Each group contains rules that
423  * apply to a specific prefix depth (i.e. group 1 contains rules that apply to
424  * prefixes with a depth of 1 etc.). In the following code (depth - 1) is used
425  * to refer to depth 1 because even though the depth range is 1 - 32, depths
426  * are stored in the rule table from 0 - 31.
427  * NOTE: Valid range for depth parameter is 1 .. 32 inclusive.
428  */
429 static inline int32_t
430 rule_add_v20(struct rte_lpm_v20 *lpm, uint32_t ip_masked, uint8_t depth,
431 	uint8_t next_hop)
432 {
433 	uint32_t rule_gindex, rule_index, last_rule;
434 	int i;
435 
436 	VERIFY_DEPTH(depth);
437 
438 	/* Scan through rule group to see if rule already exists. */
439 	if (lpm->rule_info[depth - 1].used_rules > 0) {
440 
441 		/* rule_gindex stands for rule group index. */
442 		rule_gindex = lpm->rule_info[depth - 1].first_rule;
443 		/* Initialise rule_index to point to start of rule group. */
444 		rule_index = rule_gindex;
445 		/* Last rule = Last used rule in this rule group. */
446 		last_rule = rule_gindex + lpm->rule_info[depth - 1].used_rules;
447 
448 		for (; rule_index < last_rule; rule_index++) {
449 
450 			/* If rule already exists update its next_hop and return. */
451 			if (lpm->rules_tbl[rule_index].ip == ip_masked) {
452 				lpm->rules_tbl[rule_index].next_hop = next_hop;
453 
454 				return rule_index;
455 			}
456 		}
457 
458 		if (rule_index == lpm->max_rules)
459 			return -ENOSPC;
460 	} else {
461 		/* Calculate the position in which the rule will be stored. */
462 		rule_index = 0;
463 
464 		for (i = depth - 1; i > 0; i--) {
465 			if (lpm->rule_info[i - 1].used_rules > 0) {
466 				rule_index = lpm->rule_info[i - 1].first_rule
467 						+ lpm->rule_info[i - 1].used_rules;
468 				break;
469 			}
470 		}
471 		if (rule_index == lpm->max_rules)
472 			return -ENOSPC;
473 
474 		lpm->rule_info[depth - 1].first_rule = rule_index;
475 	}
476 
477 	/* Make room for the new rule in the array. */
478 	for (i = RTE_LPM_MAX_DEPTH; i > depth; i--) {
479 		if (lpm->rule_info[i - 1].first_rule
480 				+ lpm->rule_info[i - 1].used_rules == lpm->max_rules)
481 			return -ENOSPC;
482 
483 		if (lpm->rule_info[i - 1].used_rules > 0) {
484 			lpm->rules_tbl[lpm->rule_info[i - 1].first_rule
485 				+ lpm->rule_info[i - 1].used_rules]
486 					= lpm->rules_tbl[lpm->rule_info[i - 1].first_rule];
487 			lpm->rule_info[i - 1].first_rule++;
488 		}
489 	}
490 
491 	/* Add the new rule. */
492 	lpm->rules_tbl[rule_index].ip = ip_masked;
493 	lpm->rules_tbl[rule_index].next_hop = next_hop;
494 
495 	/* Increment the used rules counter for this rule group. */
496 	lpm->rule_info[depth - 1].used_rules++;
497 
498 	return rule_index;
499 }
500 
501 static inline int32_t
502 rule_add_v1604(struct rte_lpm *lpm, uint32_t ip_masked, uint8_t depth,
503 	uint32_t next_hop)
504 {
505 	uint32_t rule_gindex, rule_index, last_rule;
506 	int i;
507 
508 	VERIFY_DEPTH(depth);
509 
510 	/* Scan through rule group to see if rule already exists. */
511 	if (lpm->rule_info[depth - 1].used_rules > 0) {
512 
513 		/* rule_gindex stands for rule group index. */
514 		rule_gindex = lpm->rule_info[depth - 1].first_rule;
515 		/* Initialise rule_index to point to start of rule group. */
516 		rule_index = rule_gindex;
517 		/* Last rule = Last used rule in this rule group. */
518 		last_rule = rule_gindex + lpm->rule_info[depth - 1].used_rules;
519 
520 		for (; rule_index < last_rule; rule_index++) {
521 
522 			/* If rule already exists update its next_hop and return. */
523 			if (lpm->rules_tbl[rule_index].ip == ip_masked) {
524 				lpm->rules_tbl[rule_index].next_hop = next_hop;
525 
526 				return rule_index;
527 			}
528 		}
529 
530 		if (rule_index == lpm->max_rules)
531 			return -ENOSPC;
532 	} else {
533 		/* Calculate the position in which the rule will be stored. */
534 		rule_index = 0;
535 
536 		for (i = depth - 1; i > 0; i--) {
537 			if (lpm->rule_info[i - 1].used_rules > 0) {
538 				rule_index = lpm->rule_info[i - 1].first_rule
539 						+ lpm->rule_info[i - 1].used_rules;
540 				break;
541 			}
542 		}
543 		if (rule_index == lpm->max_rules)
544 			return -ENOSPC;
545 
546 		lpm->rule_info[depth - 1].first_rule = rule_index;
547 	}
548 
549 	/* Make room for the new rule in the array. */
550 	for (i = RTE_LPM_MAX_DEPTH; i > depth; i--) {
551 		if (lpm->rule_info[i - 1].first_rule
552 				+ lpm->rule_info[i - 1].used_rules == lpm->max_rules)
553 			return -ENOSPC;
554 
555 		if (lpm->rule_info[i - 1].used_rules > 0) {
556 			lpm->rules_tbl[lpm->rule_info[i - 1].first_rule
557 				+ lpm->rule_info[i - 1].used_rules]
558 					= lpm->rules_tbl[lpm->rule_info[i - 1].first_rule];
559 			lpm->rule_info[i - 1].first_rule++;
560 		}
561 	}
562 
563 	/* Add the new rule. */
564 	lpm->rules_tbl[rule_index].ip = ip_masked;
565 	lpm->rules_tbl[rule_index].next_hop = next_hop;
566 
567 	/* Increment the used rules counter for this rule group. */
568 	lpm->rule_info[depth - 1].used_rules++;
569 
570 	return rule_index;
571 }
572 
573 /*
574  * Delete a rule from the rule table.
575  * NOTE: Valid range for depth parameter is 1 .. 32 inclusive.
576  */
577 static inline void
578 rule_delete_v20(struct rte_lpm_v20 *lpm, int32_t rule_index, uint8_t depth)
579 {
580 	int i;
581 
582 	VERIFY_DEPTH(depth);
583 
584 	lpm->rules_tbl[rule_index] =
585 			lpm->rules_tbl[lpm->rule_info[depth - 1].first_rule
586 				+ lpm->rule_info[depth - 1].used_rules - 1];
587 
588 	for (i = depth; i < RTE_LPM_MAX_DEPTH; i++) {
589 		if (lpm->rule_info[i].used_rules > 0) {
590 			lpm->rules_tbl[lpm->rule_info[i].first_rule - 1] =
591 				lpm->rules_tbl[lpm->rule_info[i].first_rule
592 					+ lpm->rule_info[i].used_rules - 1];
593 			lpm->rule_info[i].first_rule--;
594 		}
595 	}
596 
597 	lpm->rule_info[depth - 1].used_rules--;
598 }
599 
600 static inline void
601 rule_delete_v1604(struct rte_lpm *lpm, int32_t rule_index, uint8_t depth)
602 {
603 	int i;
604 
605 	VERIFY_DEPTH(depth);
606 
607 	lpm->rules_tbl[rule_index] =
608 			lpm->rules_tbl[lpm->rule_info[depth - 1].first_rule
609 			+ lpm->rule_info[depth - 1].used_rules - 1];
610 
611 	for (i = depth; i < RTE_LPM_MAX_DEPTH; i++) {
612 		if (lpm->rule_info[i].used_rules > 0) {
613 			lpm->rules_tbl[lpm->rule_info[i].first_rule - 1] =
614 					lpm->rules_tbl[lpm->rule_info[i].first_rule
615 						+ lpm->rule_info[i].used_rules - 1];
616 			lpm->rule_info[i].first_rule--;
617 		}
618 	}
619 
620 	lpm->rule_info[depth - 1].used_rules--;
621 }
622 
623 /*
624  * Finds a rule in rule table.
625  * NOTE: Valid range for depth parameter is 1 .. 32 inclusive.
626  */
627 static inline int32_t
628 rule_find_v20(struct rte_lpm_v20 *lpm, uint32_t ip_masked, uint8_t depth)
629 {
630 	uint32_t rule_gindex, last_rule, rule_index;
631 
632 	VERIFY_DEPTH(depth);
633 
634 	rule_gindex = lpm->rule_info[depth - 1].first_rule;
635 	last_rule = rule_gindex + lpm->rule_info[depth - 1].used_rules;
636 
637 	/* Scan used rules at given depth to find rule. */
638 	for (rule_index = rule_gindex; rule_index < last_rule; rule_index++) {
639 		/* If rule is found return the rule index. */
640 		if (lpm->rules_tbl[rule_index].ip == ip_masked)
641 			return rule_index;
642 	}
643 
644 	/* If rule is not found return -EINVAL. */
645 	return -EINVAL;
646 }
647 
648 static inline int32_t
649 rule_find_v1604(struct rte_lpm *lpm, uint32_t ip_masked, uint8_t depth)
650 {
651 	uint32_t rule_gindex, last_rule, rule_index;
652 
653 	VERIFY_DEPTH(depth);
654 
655 	rule_gindex = lpm->rule_info[depth - 1].first_rule;
656 	last_rule = rule_gindex + lpm->rule_info[depth - 1].used_rules;
657 
658 	/* Scan used rules at given depth to find rule. */
659 	for (rule_index = rule_gindex; rule_index < last_rule; rule_index++) {
660 		/* If rule is found return the rule index. */
661 		if (lpm->rules_tbl[rule_index].ip == ip_masked)
662 			return rule_index;
663 	}
664 
665 	/* If rule is not found return -EINVAL. */
666 	return -EINVAL;
667 }
668 
669 /*
670  * Find, clean and allocate a tbl8.
671  */
672 static inline int32_t
673 tbl8_alloc_v20(struct rte_lpm_tbl_entry_v20 *tbl8)
674 {
675 	uint32_t group_idx; /* tbl8 group index. */
676 	struct rte_lpm_tbl_entry_v20 *tbl8_entry;
677 
678 	/* Scan through tbl8 to find a free (i.e. INVALID) tbl8 group. */
679 	for (group_idx = 0; group_idx < RTE_LPM_TBL8_NUM_GROUPS;
680 			group_idx++) {
681 		tbl8_entry = &tbl8[group_idx * RTE_LPM_TBL8_GROUP_NUM_ENTRIES];
682 		/* If a free tbl8 group is found clean it and set as VALID. */
683 		if (!tbl8_entry->valid_group) {
684 			memset(&tbl8_entry[0], 0,
685 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES *
686 					sizeof(tbl8_entry[0]));
687 
688 			tbl8_entry->valid_group = VALID;
689 
690 			/* Return group index for allocated tbl8 group. */
691 			return group_idx;
692 		}
693 	}
694 
695 	/* If there are no tbl8 groups free then return error. */
696 	return -ENOSPC;
697 }
698 
699 static inline int32_t
700 tbl8_alloc_v1604(struct rte_lpm_tbl_entry *tbl8, uint32_t number_tbl8s)
701 {
702 	uint32_t group_idx; /* tbl8 group index. */
703 	struct rte_lpm_tbl_entry *tbl8_entry;
704 
705 	/* Scan through tbl8 to find a free (i.e. INVALID) tbl8 group. */
706 	for (group_idx = 0; group_idx < number_tbl8s; group_idx++) {
707 		tbl8_entry = &tbl8[group_idx * RTE_LPM_TBL8_GROUP_NUM_ENTRIES];
708 		/* If a free tbl8 group is found clean it and set as VALID. */
709 		if (!tbl8_entry->valid_group) {
710 			memset(&tbl8_entry[0], 0,
711 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES *
712 					sizeof(tbl8_entry[0]));
713 
714 			tbl8_entry->valid_group = VALID;
715 
716 			/* Return group index for allocated tbl8 group. */
717 			return group_idx;
718 		}
719 	}
720 
721 	/* If there are no tbl8 groups free then return error. */
722 	return -ENOSPC;
723 }
724 
725 static inline void
726 tbl8_free_v20(struct rte_lpm_tbl_entry_v20 *tbl8, uint32_t tbl8_group_start)
727 {
728 	/* Set tbl8 group invalid*/
729 	tbl8[tbl8_group_start].valid_group = INVALID;
730 }
731 
732 static inline void
733 tbl8_free_v1604(struct rte_lpm_tbl_entry *tbl8, uint32_t tbl8_group_start)
734 {
735 	/* Set tbl8 group invalid*/
736 	tbl8[tbl8_group_start].valid_group = INVALID;
737 }
738 
739 static inline int32_t
740 add_depth_small_v20(struct rte_lpm_v20 *lpm, uint32_t ip, uint8_t depth,
741 		uint8_t next_hop)
742 {
743 	uint32_t tbl24_index, tbl24_range, tbl8_index, tbl8_group_end, i, j;
744 
745 	/* Calculate the index into Table24. */
746 	tbl24_index = ip >> 8;
747 	tbl24_range = depth_to_range(depth);
748 
749 	for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
750 		/*
751 		 * For invalid OR valid and non-extended tbl 24 entries set
752 		 * entry.
753 		 */
754 		if (!lpm->tbl24[i].valid || (lpm->tbl24[i].valid_group == 0 &&
755 				lpm->tbl24[i].depth <= depth)) {
756 
757 			struct rte_lpm_tbl_entry_v20 new_tbl24_entry = {
758 				.valid = VALID,
759 				.valid_group = 0,
760 				.depth = depth,
761 			};
762 			new_tbl24_entry.next_hop = next_hop;
763 
764 			/* Setting tbl24 entry in one go to avoid race
765 			 * conditions
766 			 */
767 			lpm->tbl24[i] = new_tbl24_entry;
768 
769 			continue;
770 		}
771 
772 		if (lpm->tbl24[i].valid_group == 1) {
773 			/* If tbl24 entry is valid and extended calculate the
774 			 *  index into tbl8.
775 			 */
776 			tbl8_index = lpm->tbl24[i].group_idx *
777 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
778 			tbl8_group_end = tbl8_index +
779 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
780 
781 			for (j = tbl8_index; j < tbl8_group_end; j++) {
782 				if (!lpm->tbl8[j].valid ||
783 						lpm->tbl8[j].depth <= depth) {
784 					struct rte_lpm_tbl_entry_v20
785 						new_tbl8_entry = {
786 						.valid = VALID,
787 						.valid_group = VALID,
788 						.depth = depth,
789 					};
790 					new_tbl8_entry.next_hop = next_hop;
791 
792 					/*
793 					 * Setting tbl8 entry in one go to avoid
794 					 * race conditions
795 					 */
796 					lpm->tbl8[j] = new_tbl8_entry;
797 
798 					continue;
799 				}
800 			}
801 		}
802 	}
803 
804 	return 0;
805 }
806 
807 static inline int32_t
808 add_depth_small_v1604(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
809 		uint32_t next_hop)
810 {
811 #define group_idx next_hop
812 	uint32_t tbl24_index, tbl24_range, tbl8_index, tbl8_group_end, i, j;
813 
814 	/* Calculate the index into Table24. */
815 	tbl24_index = ip >> 8;
816 	tbl24_range = depth_to_range(depth);
817 
818 	for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
819 		/*
820 		 * For invalid OR valid and non-extended tbl 24 entries set
821 		 * entry.
822 		 */
823 		if (!lpm->tbl24[i].valid || (lpm->tbl24[i].valid_group == 0 &&
824 				lpm->tbl24[i].depth <= depth)) {
825 
826 			struct rte_lpm_tbl_entry new_tbl24_entry = {
827 				.next_hop = next_hop,
828 				.valid = VALID,
829 				.valid_group = 0,
830 				.depth = depth,
831 			};
832 
833 			/* Setting tbl24 entry in one go to avoid race
834 			 * conditions
835 			 */
836 			lpm->tbl24[i] = new_tbl24_entry;
837 
838 			continue;
839 		}
840 
841 		if (lpm->tbl24[i].valid_group == 1) {
842 			/* If tbl24 entry is valid and extended calculate the
843 			 *  index into tbl8.
844 			 */
845 			tbl8_index = lpm->tbl24[i].group_idx *
846 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
847 			tbl8_group_end = tbl8_index +
848 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
849 
850 			for (j = tbl8_index; j < tbl8_group_end; j++) {
851 				if (!lpm->tbl8[j].valid ||
852 						lpm->tbl8[j].depth <= depth) {
853 					struct rte_lpm_tbl_entry
854 						new_tbl8_entry = {
855 						.valid = VALID,
856 						.valid_group = VALID,
857 						.depth = depth,
858 						.next_hop = next_hop,
859 					};
860 
861 					/*
862 					 * Setting tbl8 entry in one go to avoid
863 					 * race conditions
864 					 */
865 					lpm->tbl8[j] = new_tbl8_entry;
866 
867 					continue;
868 				}
869 			}
870 		}
871 	}
872 #undef group_idx
873 	return 0;
874 }
875 
876 static inline int32_t
877 add_depth_big_v20(struct rte_lpm_v20 *lpm, uint32_t ip_masked, uint8_t depth,
878 		uint8_t next_hop)
879 {
880 	uint32_t tbl24_index;
881 	int32_t tbl8_group_index, tbl8_group_start, tbl8_group_end, tbl8_index,
882 		tbl8_range, i;
883 
884 	tbl24_index = (ip_masked >> 8);
885 	tbl8_range = depth_to_range(depth);
886 
887 	if (!lpm->tbl24[tbl24_index].valid) {
888 		/* Search for a free tbl8 group. */
889 		tbl8_group_index = tbl8_alloc_v20(lpm->tbl8);
890 
891 		/* Check tbl8 allocation was successful. */
892 		if (tbl8_group_index < 0) {
893 			return tbl8_group_index;
894 		}
895 
896 		/* Find index into tbl8 and range. */
897 		tbl8_index = (tbl8_group_index *
898 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES) +
899 				(ip_masked & 0xFF);
900 
901 		/* Set tbl8 entry. */
902 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
903 			lpm->tbl8[i].depth = depth;
904 			lpm->tbl8[i].next_hop = next_hop;
905 			lpm->tbl8[i].valid = VALID;
906 		}
907 
908 		/*
909 		 * Update tbl24 entry to point to new tbl8 entry. Note: The
910 		 * ext_flag and tbl8_index need to be updated simultaneously,
911 		 * so assign whole structure in one go
912 		 */
913 
914 		struct rte_lpm_tbl_entry_v20 new_tbl24_entry = {
915 			.group_idx = (uint8_t)tbl8_group_index,
916 			.valid = VALID,
917 			.valid_group = 1,
918 			.depth = 0,
919 		};
920 
921 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
922 
923 	} /* If valid entry but not extended calculate the index into Table8. */
924 	else if (lpm->tbl24[tbl24_index].valid_group == 0) {
925 		/* Search for free tbl8 group. */
926 		tbl8_group_index = tbl8_alloc_v20(lpm->tbl8);
927 
928 		if (tbl8_group_index < 0) {
929 			return tbl8_group_index;
930 		}
931 
932 		tbl8_group_start = tbl8_group_index *
933 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
934 		tbl8_group_end = tbl8_group_start +
935 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
936 
937 		/* Populate new tbl8 with tbl24 value. */
938 		for (i = tbl8_group_start; i < tbl8_group_end; i++) {
939 			lpm->tbl8[i].valid = VALID;
940 			lpm->tbl8[i].depth = lpm->tbl24[tbl24_index].depth;
941 			lpm->tbl8[i].next_hop =
942 					lpm->tbl24[tbl24_index].next_hop;
943 		}
944 
945 		tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
946 
947 		/* Insert new rule into the tbl8 entry. */
948 		for (i = tbl8_index; i < tbl8_index + tbl8_range; i++) {
949 			lpm->tbl8[i].valid = VALID;
950 			lpm->tbl8[i].depth = depth;
951 			lpm->tbl8[i].next_hop = next_hop;
952 		}
953 
954 		/*
955 		 * Update tbl24 entry to point to new tbl8 entry. Note: The
956 		 * ext_flag and tbl8_index need to be updated simultaneously,
957 		 * so assign whole structure in one go.
958 		 */
959 
960 		struct rte_lpm_tbl_entry_v20 new_tbl24_entry = {
961 				.group_idx = (uint8_t)tbl8_group_index,
962 				.valid = VALID,
963 				.valid_group = 1,
964 				.depth = 0,
965 		};
966 
967 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
968 
969 	} else { /*
970 		* If it is valid, extended entry calculate the index into tbl8.
971 		*/
972 		tbl8_group_index = lpm->tbl24[tbl24_index].group_idx;
973 		tbl8_group_start = tbl8_group_index *
974 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
975 		tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
976 
977 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
978 
979 			if (!lpm->tbl8[i].valid ||
980 					lpm->tbl8[i].depth <= depth) {
981 				struct rte_lpm_tbl_entry_v20 new_tbl8_entry = {
982 					.valid = VALID,
983 					.depth = depth,
984 					.valid_group = lpm->tbl8[i].valid_group,
985 				};
986 				new_tbl8_entry.next_hop = next_hop;
987 				/*
988 				 * Setting tbl8 entry in one go to avoid race
989 				 * condition
990 				 */
991 				lpm->tbl8[i] = new_tbl8_entry;
992 
993 				continue;
994 			}
995 		}
996 	}
997 
998 	return 0;
999 }
1000 
1001 static inline int32_t
1002 add_depth_big_v1604(struct rte_lpm *lpm, uint32_t ip_masked, uint8_t depth,
1003 		uint32_t next_hop)
1004 {
1005 #define group_idx next_hop
1006 	uint32_t tbl24_index;
1007 	int32_t tbl8_group_index, tbl8_group_start, tbl8_group_end, tbl8_index,
1008 		tbl8_range, i;
1009 
1010 	tbl24_index = (ip_masked >> 8);
1011 	tbl8_range = depth_to_range(depth);
1012 
1013 	if (!lpm->tbl24[tbl24_index].valid) {
1014 		/* Search for a free tbl8 group. */
1015 		tbl8_group_index = tbl8_alloc_v1604(lpm->tbl8, lpm->number_tbl8s);
1016 
1017 		/* Check tbl8 allocation was successful. */
1018 		if (tbl8_group_index < 0) {
1019 			return tbl8_group_index;
1020 		}
1021 
1022 		/* Find index into tbl8 and range. */
1023 		tbl8_index = (tbl8_group_index *
1024 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES) +
1025 				(ip_masked & 0xFF);
1026 
1027 		/* Set tbl8 entry. */
1028 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1029 			lpm->tbl8[i].depth = depth;
1030 			lpm->tbl8[i].next_hop = next_hop;
1031 			lpm->tbl8[i].valid = VALID;
1032 		}
1033 
1034 		/*
1035 		 * Update tbl24 entry to point to new tbl8 entry. Note: The
1036 		 * ext_flag and tbl8_index need to be updated simultaneously,
1037 		 * so assign whole structure in one go
1038 		 */
1039 
1040 		struct rte_lpm_tbl_entry new_tbl24_entry = {
1041 			.group_idx = tbl8_group_index,
1042 			.valid = VALID,
1043 			.valid_group = 1,
1044 			.depth = 0,
1045 		};
1046 
1047 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
1048 
1049 	} /* If valid entry but not extended calculate the index into Table8. */
1050 	else if (lpm->tbl24[tbl24_index].valid_group == 0) {
1051 		/* Search for free tbl8 group. */
1052 		tbl8_group_index = tbl8_alloc_v1604(lpm->tbl8, lpm->number_tbl8s);
1053 
1054 		if (tbl8_group_index < 0) {
1055 			return tbl8_group_index;
1056 		}
1057 
1058 		tbl8_group_start = tbl8_group_index *
1059 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1060 		tbl8_group_end = tbl8_group_start +
1061 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1062 
1063 		/* Populate new tbl8 with tbl24 value. */
1064 		for (i = tbl8_group_start; i < tbl8_group_end; i++) {
1065 			lpm->tbl8[i].valid = VALID;
1066 			lpm->tbl8[i].depth = lpm->tbl24[tbl24_index].depth;
1067 			lpm->tbl8[i].next_hop =
1068 					lpm->tbl24[tbl24_index].next_hop;
1069 		}
1070 
1071 		tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
1072 
1073 		/* Insert new rule into the tbl8 entry. */
1074 		for (i = tbl8_index; i < tbl8_index + tbl8_range; i++) {
1075 			lpm->tbl8[i].valid = VALID;
1076 			lpm->tbl8[i].depth = depth;
1077 			lpm->tbl8[i].next_hop = next_hop;
1078 		}
1079 
1080 		/*
1081 		 * Update tbl24 entry to point to new tbl8 entry. Note: The
1082 		 * ext_flag and tbl8_index need to be updated simultaneously,
1083 		 * so assign whole structure in one go.
1084 		 */
1085 
1086 		struct rte_lpm_tbl_entry new_tbl24_entry = {
1087 				.group_idx = tbl8_group_index,
1088 				.valid = VALID,
1089 				.valid_group = 1,
1090 				.depth = 0,
1091 		};
1092 
1093 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
1094 
1095 	} else { /*
1096 		* If it is valid, extended entry calculate the index into tbl8.
1097 		*/
1098 		tbl8_group_index = lpm->tbl24[tbl24_index].group_idx;
1099 		tbl8_group_start = tbl8_group_index *
1100 				RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1101 		tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
1102 
1103 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1104 
1105 			if (!lpm->tbl8[i].valid ||
1106 					lpm->tbl8[i].depth <= depth) {
1107 				struct rte_lpm_tbl_entry new_tbl8_entry = {
1108 					.valid = VALID,
1109 					.depth = depth,
1110 					.next_hop = next_hop,
1111 					.valid_group = lpm->tbl8[i].valid_group,
1112 				};
1113 
1114 				/*
1115 				 * Setting tbl8 entry in one go to avoid race
1116 				 * condition
1117 				 */
1118 				lpm->tbl8[i] = new_tbl8_entry;
1119 
1120 				continue;
1121 			}
1122 		}
1123 	}
1124 #undef group_idx
1125 	return 0;
1126 }
1127 
1128 /*
1129  * Add a route
1130  */
1131 int
1132 rte_lpm_add_v20(struct rte_lpm_v20 *lpm, uint32_t ip, uint8_t depth,
1133 		uint8_t next_hop)
1134 {
1135 	int32_t rule_index, status = 0;
1136 	uint32_t ip_masked;
1137 
1138 	/* Check user arguments. */
1139 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM_MAX_DEPTH))
1140 		return -EINVAL;
1141 
1142 	ip_masked = ip & depth_to_mask(depth);
1143 
1144 	/* Add the rule to the rule table. */
1145 	rule_index = rule_add_v20(lpm, ip_masked, depth, next_hop);
1146 
1147 	/* If the is no space available for new rule return error. */
1148 	if (rule_index < 0) {
1149 		return rule_index;
1150 	}
1151 
1152 	if (depth <= MAX_DEPTH_TBL24) {
1153 		status = add_depth_small_v20(lpm, ip_masked, depth, next_hop);
1154 	} else { /* If depth > RTE_LPM_MAX_DEPTH_TBL24 */
1155 		status = add_depth_big_v20(lpm, ip_masked, depth, next_hop);
1156 
1157 		/*
1158 		 * If add fails due to exhaustion of tbl8 extensions delete
1159 		 * rule that was added to rule table.
1160 		 */
1161 		if (status < 0) {
1162 			rule_delete_v20(lpm, rule_index, depth);
1163 
1164 			return status;
1165 		}
1166 	}
1167 
1168 	return 0;
1169 }
1170 VERSION_SYMBOL(rte_lpm_add, _v20, 2.0);
1171 
1172 int
1173 rte_lpm_add_v1604(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
1174 		uint32_t next_hop)
1175 {
1176 	int32_t rule_index, status = 0;
1177 	uint32_t ip_masked;
1178 
1179 	/* Check user arguments. */
1180 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM_MAX_DEPTH))
1181 		return -EINVAL;
1182 
1183 	ip_masked = ip & depth_to_mask(depth);
1184 
1185 	/* Add the rule to the rule table. */
1186 	rule_index = rule_add_v1604(lpm, ip_masked, depth, next_hop);
1187 
1188 	/* If the is no space available for new rule return error. */
1189 	if (rule_index < 0) {
1190 		return rule_index;
1191 	}
1192 
1193 	if (depth <= MAX_DEPTH_TBL24) {
1194 		status = add_depth_small_v1604(lpm, ip_masked, depth, next_hop);
1195 	} else { /* If depth > RTE_LPM_MAX_DEPTH_TBL24 */
1196 		status = add_depth_big_v1604(lpm, ip_masked, depth, next_hop);
1197 
1198 		/*
1199 		 * If add fails due to exhaustion of tbl8 extensions delete
1200 		 * rule that was added to rule table.
1201 		 */
1202 		if (status < 0) {
1203 			rule_delete_v1604(lpm, rule_index, depth);
1204 
1205 			return status;
1206 		}
1207 	}
1208 
1209 	return 0;
1210 }
1211 BIND_DEFAULT_SYMBOL(rte_lpm_add, _v1604, 16.04);
1212 MAP_STATIC_SYMBOL(int rte_lpm_add(struct rte_lpm *lpm, uint32_t ip,
1213 		uint8_t depth, uint32_t next_hop), rte_lpm_add_v1604);
1214 
1215 /*
1216  * Look for a rule in the high-level rules table
1217  */
1218 int
1219 rte_lpm_is_rule_present_v20(struct rte_lpm_v20 *lpm, uint32_t ip, uint8_t depth,
1220 uint8_t *next_hop)
1221 {
1222 	uint32_t ip_masked;
1223 	int32_t rule_index;
1224 
1225 	/* Check user arguments. */
1226 	if ((lpm == NULL) ||
1227 		(next_hop == NULL) ||
1228 		(depth < 1) || (depth > RTE_LPM_MAX_DEPTH))
1229 		return -EINVAL;
1230 
1231 	/* Look for the rule using rule_find. */
1232 	ip_masked = ip & depth_to_mask(depth);
1233 	rule_index = rule_find_v20(lpm, ip_masked, depth);
1234 
1235 	if (rule_index >= 0) {
1236 		*next_hop = lpm->rules_tbl[rule_index].next_hop;
1237 		return 1;
1238 	}
1239 
1240 	/* If rule is not found return 0. */
1241 	return 0;
1242 }
1243 VERSION_SYMBOL(rte_lpm_is_rule_present, _v20, 2.0);
1244 
1245 int
1246 rte_lpm_is_rule_present_v1604(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
1247 uint32_t *next_hop)
1248 {
1249 	uint32_t ip_masked;
1250 	int32_t rule_index;
1251 
1252 	/* Check user arguments. */
1253 	if ((lpm == NULL) ||
1254 		(next_hop == NULL) ||
1255 		(depth < 1) || (depth > RTE_LPM_MAX_DEPTH))
1256 		return -EINVAL;
1257 
1258 	/* Look for the rule using rule_find. */
1259 	ip_masked = ip & depth_to_mask(depth);
1260 	rule_index = rule_find_v1604(lpm, ip_masked, depth);
1261 
1262 	if (rule_index >= 0) {
1263 		*next_hop = lpm->rules_tbl[rule_index].next_hop;
1264 		return 1;
1265 	}
1266 
1267 	/* If rule is not found return 0. */
1268 	return 0;
1269 }
1270 BIND_DEFAULT_SYMBOL(rte_lpm_is_rule_present, _v1604, 16.04);
1271 MAP_STATIC_SYMBOL(int rte_lpm_is_rule_present(struct rte_lpm *lpm, uint32_t ip,
1272 		uint8_t depth, uint32_t *next_hop), rte_lpm_is_rule_present_v1604);
1273 
1274 static inline int32_t
1275 find_previous_rule_v20(struct rte_lpm_v20 *lpm, uint32_t ip, uint8_t depth,
1276 		uint8_t *sub_rule_depth)
1277 {
1278 	int32_t rule_index;
1279 	uint32_t ip_masked;
1280 	uint8_t prev_depth;
1281 
1282 	for (prev_depth = (uint8_t)(depth - 1); prev_depth > 0; prev_depth--) {
1283 		ip_masked = ip & depth_to_mask(prev_depth);
1284 
1285 		rule_index = rule_find_v20(lpm, ip_masked, prev_depth);
1286 
1287 		if (rule_index >= 0) {
1288 			*sub_rule_depth = prev_depth;
1289 			return rule_index;
1290 		}
1291 	}
1292 
1293 	return -1;
1294 }
1295 
1296 static inline int32_t
1297 find_previous_rule_v1604(struct rte_lpm *lpm, uint32_t ip, uint8_t depth,
1298 		uint8_t *sub_rule_depth)
1299 {
1300 	int32_t rule_index;
1301 	uint32_t ip_masked;
1302 	uint8_t prev_depth;
1303 
1304 	for (prev_depth = (uint8_t)(depth - 1); prev_depth > 0; prev_depth--) {
1305 		ip_masked = ip & depth_to_mask(prev_depth);
1306 
1307 		rule_index = rule_find_v1604(lpm, ip_masked, prev_depth);
1308 
1309 		if (rule_index >= 0) {
1310 			*sub_rule_depth = prev_depth;
1311 			return rule_index;
1312 		}
1313 	}
1314 
1315 	return -1;
1316 }
1317 
1318 static inline int32_t
1319 delete_depth_small_v20(struct rte_lpm_v20 *lpm, uint32_t ip_masked,
1320 	uint8_t depth, int32_t sub_rule_index, uint8_t sub_rule_depth)
1321 {
1322 	uint32_t tbl24_range, tbl24_index, tbl8_group_index, tbl8_index, i, j;
1323 
1324 	/* Calculate the range and index into Table24. */
1325 	tbl24_range = depth_to_range(depth);
1326 	tbl24_index = (ip_masked >> 8);
1327 
1328 	/*
1329 	 * Firstly check the sub_rule_index. A -1 indicates no replacement rule
1330 	 * and a positive number indicates a sub_rule_index.
1331 	 */
1332 	if (sub_rule_index < 0) {
1333 		/*
1334 		 * If no replacement rule exists then invalidate entries
1335 		 * associated with this rule.
1336 		 */
1337 		for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
1338 
1339 			if (lpm->tbl24[i].valid_group == 0 &&
1340 					lpm->tbl24[i].depth <= depth) {
1341 				lpm->tbl24[i].valid = INVALID;
1342 			} else if (lpm->tbl24[i].valid_group == 1) {
1343 				/*
1344 				 * If TBL24 entry is extended, then there has
1345 				 * to be a rule with depth >= 25 in the
1346 				 * associated TBL8 group.
1347 				 */
1348 
1349 				tbl8_group_index = lpm->tbl24[i].group_idx;
1350 				tbl8_index = tbl8_group_index *
1351 						RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1352 
1353 				for (j = tbl8_index; j < (tbl8_index +
1354 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES); j++) {
1355 
1356 					if (lpm->tbl8[j].depth <= depth)
1357 						lpm->tbl8[j].valid = INVALID;
1358 				}
1359 			}
1360 		}
1361 	} else {
1362 		/*
1363 		 * If a replacement rule exists then modify entries
1364 		 * associated with this rule.
1365 		 */
1366 
1367 		struct rte_lpm_tbl_entry_v20 new_tbl24_entry = {
1368 			.next_hop = lpm->rules_tbl[sub_rule_index].next_hop,
1369 			.valid = VALID,
1370 			.valid_group = 0,
1371 			.depth = sub_rule_depth,
1372 		};
1373 
1374 		struct rte_lpm_tbl_entry_v20 new_tbl8_entry = {
1375 			.valid = VALID,
1376 			.valid_group = VALID,
1377 			.depth = sub_rule_depth,
1378 		};
1379 		new_tbl8_entry.next_hop =
1380 				lpm->rules_tbl[sub_rule_index].next_hop;
1381 
1382 		for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
1383 
1384 			if (lpm->tbl24[i].valid_group == 0 &&
1385 					lpm->tbl24[i].depth <= depth) {
1386 				lpm->tbl24[i] = new_tbl24_entry;
1387 			} else  if (lpm->tbl24[i].valid_group == 1) {
1388 				/*
1389 				 * If TBL24 entry is extended, then there has
1390 				 * to be a rule with depth >= 25 in the
1391 				 * associated TBL8 group.
1392 				 */
1393 
1394 				tbl8_group_index = lpm->tbl24[i].group_idx;
1395 				tbl8_index = tbl8_group_index *
1396 						RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1397 
1398 				for (j = tbl8_index; j < (tbl8_index +
1399 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES); j++) {
1400 
1401 					if (lpm->tbl8[j].depth <= depth)
1402 						lpm->tbl8[j] = new_tbl8_entry;
1403 				}
1404 			}
1405 		}
1406 	}
1407 
1408 	return 0;
1409 }
1410 
1411 static inline int32_t
1412 delete_depth_small_v1604(struct rte_lpm *lpm, uint32_t ip_masked,
1413 	uint8_t depth, int32_t sub_rule_index, uint8_t sub_rule_depth)
1414 {
1415 #define group_idx next_hop
1416 	uint32_t tbl24_range, tbl24_index, tbl8_group_index, tbl8_index, i, j;
1417 
1418 	/* Calculate the range and index into Table24. */
1419 	tbl24_range = depth_to_range(depth);
1420 	tbl24_index = (ip_masked >> 8);
1421 
1422 	/*
1423 	 * Firstly check the sub_rule_index. A -1 indicates no replacement rule
1424 	 * and a positive number indicates a sub_rule_index.
1425 	 */
1426 	if (sub_rule_index < 0) {
1427 		/*
1428 		 * If no replacement rule exists then invalidate entries
1429 		 * associated with this rule.
1430 		 */
1431 		for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
1432 
1433 			if (lpm->tbl24[i].valid_group == 0 &&
1434 					lpm->tbl24[i].depth <= depth) {
1435 				lpm->tbl24[i].valid = INVALID;
1436 			} else if (lpm->tbl24[i].valid_group == 1) {
1437 				/*
1438 				 * If TBL24 entry is extended, then there has
1439 				 * to be a rule with depth >= 25 in the
1440 				 * associated TBL8 group.
1441 				 */
1442 
1443 				tbl8_group_index = lpm->tbl24[i].group_idx;
1444 				tbl8_index = tbl8_group_index *
1445 						RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1446 
1447 				for (j = tbl8_index; j < (tbl8_index +
1448 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES); j++) {
1449 
1450 					if (lpm->tbl8[j].depth <= depth)
1451 						lpm->tbl8[j].valid = INVALID;
1452 				}
1453 			}
1454 		}
1455 	} else {
1456 		/*
1457 		 * If a replacement rule exists then modify entries
1458 		 * associated with this rule.
1459 		 */
1460 
1461 		struct rte_lpm_tbl_entry new_tbl24_entry = {
1462 			.next_hop = lpm->rules_tbl[sub_rule_index].next_hop,
1463 			.valid = VALID,
1464 			.valid_group = 0,
1465 			.depth = sub_rule_depth,
1466 		};
1467 
1468 		struct rte_lpm_tbl_entry new_tbl8_entry = {
1469 			.valid = VALID,
1470 			.valid_group = VALID,
1471 			.depth = sub_rule_depth,
1472 			.next_hop = lpm->rules_tbl
1473 			[sub_rule_index].next_hop,
1474 		};
1475 
1476 		for (i = tbl24_index; i < (tbl24_index + tbl24_range); i++) {
1477 
1478 			if (lpm->tbl24[i].valid_group == 0 &&
1479 					lpm->tbl24[i].depth <= depth) {
1480 				lpm->tbl24[i] = new_tbl24_entry;
1481 			} else  if (lpm->tbl24[i].valid_group == 1) {
1482 				/*
1483 				 * If TBL24 entry is extended, then there has
1484 				 * to be a rule with depth >= 25 in the
1485 				 * associated TBL8 group.
1486 				 */
1487 
1488 				tbl8_group_index = lpm->tbl24[i].group_idx;
1489 				tbl8_index = tbl8_group_index *
1490 						RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1491 
1492 				for (j = tbl8_index; j < (tbl8_index +
1493 					RTE_LPM_TBL8_GROUP_NUM_ENTRIES); j++) {
1494 
1495 					if (lpm->tbl8[j].depth <= depth)
1496 						lpm->tbl8[j] = new_tbl8_entry;
1497 				}
1498 			}
1499 		}
1500 	}
1501 #undef group_idx
1502 	return 0;
1503 }
1504 
1505 /*
1506  * Checks if table 8 group can be recycled.
1507  *
1508  * Return of -EEXIST means tbl8 is in use and thus can not be recycled.
1509  * Return of -EINVAL means tbl8 is empty and thus can be recycled
1510  * Return of value > -1 means tbl8 is in use but has all the same values and
1511  * thus can be recycled
1512  */
1513 static inline int32_t
1514 tbl8_recycle_check_v20(struct rte_lpm_tbl_entry_v20 *tbl8,
1515 		uint32_t tbl8_group_start)
1516 {
1517 	uint32_t tbl8_group_end, i;
1518 	tbl8_group_end = tbl8_group_start + RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1519 
1520 	/*
1521 	 * Check the first entry of the given tbl8. If it is invalid we know
1522 	 * this tbl8 does not contain any rule with a depth < RTE_LPM_MAX_DEPTH
1523 	 *  (As they would affect all entries in a tbl8) and thus this table
1524 	 *  can not be recycled.
1525 	 */
1526 	if (tbl8[tbl8_group_start].valid) {
1527 		/*
1528 		 * If first entry is valid check if the depth is less than 24
1529 		 * and if so check the rest of the entries to verify that they
1530 		 * are all of this depth.
1531 		 */
1532 		if (tbl8[tbl8_group_start].depth <= MAX_DEPTH_TBL24) {
1533 			for (i = (tbl8_group_start + 1); i < tbl8_group_end;
1534 					i++) {
1535 
1536 				if (tbl8[i].depth !=
1537 						tbl8[tbl8_group_start].depth) {
1538 
1539 					return -EEXIST;
1540 				}
1541 			}
1542 			/* If all entries are the same return the tb8 index */
1543 			return tbl8_group_start;
1544 		}
1545 
1546 		return -EEXIST;
1547 	}
1548 	/*
1549 	 * If the first entry is invalid check if the rest of the entries in
1550 	 * the tbl8 are invalid.
1551 	 */
1552 	for (i = (tbl8_group_start + 1); i < tbl8_group_end; i++) {
1553 		if (tbl8[i].valid)
1554 			return -EEXIST;
1555 	}
1556 	/* If no valid entries are found then return -EINVAL. */
1557 	return -EINVAL;
1558 }
1559 
1560 static inline int32_t
1561 tbl8_recycle_check_v1604(struct rte_lpm_tbl_entry *tbl8,
1562 		uint32_t tbl8_group_start)
1563 {
1564 	uint32_t tbl8_group_end, i;
1565 	tbl8_group_end = tbl8_group_start + RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1566 
1567 	/*
1568 	 * Check the first entry of the given tbl8. If it is invalid we know
1569 	 * this tbl8 does not contain any rule with a depth < RTE_LPM_MAX_DEPTH
1570 	 *  (As they would affect all entries in a tbl8) and thus this table
1571 	 *  can not be recycled.
1572 	 */
1573 	if (tbl8[tbl8_group_start].valid) {
1574 		/*
1575 		 * If first entry is valid check if the depth is less than 24
1576 		 * and if so check the rest of the entries to verify that they
1577 		 * are all of this depth.
1578 		 */
1579 		if (tbl8[tbl8_group_start].depth <= MAX_DEPTH_TBL24) {
1580 			for (i = (tbl8_group_start + 1); i < tbl8_group_end;
1581 					i++) {
1582 
1583 				if (tbl8[i].depth !=
1584 						tbl8[tbl8_group_start].depth) {
1585 
1586 					return -EEXIST;
1587 				}
1588 			}
1589 			/* If all entries are the same return the tb8 index */
1590 			return tbl8_group_start;
1591 		}
1592 
1593 		return -EEXIST;
1594 	}
1595 	/*
1596 	 * If the first entry is invalid check if the rest of the entries in
1597 	 * the tbl8 are invalid.
1598 	 */
1599 	for (i = (tbl8_group_start + 1); i < tbl8_group_end; i++) {
1600 		if (tbl8[i].valid)
1601 			return -EEXIST;
1602 	}
1603 	/* If no valid entries are found then return -EINVAL. */
1604 	return -EINVAL;
1605 }
1606 
1607 static inline int32_t
1608 delete_depth_big_v20(struct rte_lpm_v20 *lpm, uint32_t ip_masked,
1609 	uint8_t depth, int32_t sub_rule_index, uint8_t sub_rule_depth)
1610 {
1611 	uint32_t tbl24_index, tbl8_group_index, tbl8_group_start, tbl8_index,
1612 			tbl8_range, i;
1613 	int32_t tbl8_recycle_index;
1614 
1615 	/*
1616 	 * Calculate the index into tbl24 and range. Note: All depths larger
1617 	 * than MAX_DEPTH_TBL24 are associated with only one tbl24 entry.
1618 	 */
1619 	tbl24_index = ip_masked >> 8;
1620 
1621 	/* Calculate the index into tbl8 and range. */
1622 	tbl8_group_index = lpm->tbl24[tbl24_index].group_idx;
1623 	tbl8_group_start = tbl8_group_index * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1624 	tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
1625 	tbl8_range = depth_to_range(depth);
1626 
1627 	if (sub_rule_index < 0) {
1628 		/*
1629 		 * Loop through the range of entries on tbl8 for which the
1630 		 * rule_to_delete must be removed or modified.
1631 		 */
1632 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1633 			if (lpm->tbl8[i].depth <= depth)
1634 				lpm->tbl8[i].valid = INVALID;
1635 		}
1636 	} else {
1637 		/* Set new tbl8 entry. */
1638 		struct rte_lpm_tbl_entry_v20 new_tbl8_entry = {
1639 			.valid = VALID,
1640 			.depth = sub_rule_depth,
1641 			.valid_group = lpm->tbl8[tbl8_group_start].valid_group,
1642 		};
1643 
1644 		new_tbl8_entry.next_hop =
1645 				lpm->rules_tbl[sub_rule_index].next_hop;
1646 		/*
1647 		 * Loop through the range of entries on tbl8 for which the
1648 		 * rule_to_delete must be modified.
1649 		 */
1650 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1651 			if (lpm->tbl8[i].depth <= depth)
1652 				lpm->tbl8[i] = new_tbl8_entry;
1653 		}
1654 	}
1655 
1656 	/*
1657 	 * Check if there are any valid entries in this tbl8 group. If all
1658 	 * tbl8 entries are invalid we can free the tbl8 and invalidate the
1659 	 * associated tbl24 entry.
1660 	 */
1661 
1662 	tbl8_recycle_index = tbl8_recycle_check_v20(lpm->tbl8, tbl8_group_start);
1663 
1664 	if (tbl8_recycle_index == -EINVAL) {
1665 		/* Set tbl24 before freeing tbl8 to avoid race condition. */
1666 		lpm->tbl24[tbl24_index].valid = 0;
1667 		tbl8_free_v20(lpm->tbl8, tbl8_group_start);
1668 	} else if (tbl8_recycle_index > -1) {
1669 		/* Update tbl24 entry. */
1670 		struct rte_lpm_tbl_entry_v20 new_tbl24_entry = {
1671 			.next_hop = lpm->tbl8[tbl8_recycle_index].next_hop,
1672 			.valid = VALID,
1673 			.valid_group = 0,
1674 			.depth = lpm->tbl8[tbl8_recycle_index].depth,
1675 		};
1676 
1677 		/* Set tbl24 before freeing tbl8 to avoid race condition. */
1678 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
1679 		tbl8_free_v20(lpm->tbl8, tbl8_group_start);
1680 	}
1681 
1682 	return 0;
1683 }
1684 
1685 static inline int32_t
1686 delete_depth_big_v1604(struct rte_lpm *lpm, uint32_t ip_masked,
1687 	uint8_t depth, int32_t sub_rule_index, uint8_t sub_rule_depth)
1688 {
1689 #define group_idx next_hop
1690 	uint32_t tbl24_index, tbl8_group_index, tbl8_group_start, tbl8_index,
1691 			tbl8_range, i;
1692 	int32_t tbl8_recycle_index;
1693 
1694 	/*
1695 	 * Calculate the index into tbl24 and range. Note: All depths larger
1696 	 * than MAX_DEPTH_TBL24 are associated with only one tbl24 entry.
1697 	 */
1698 	tbl24_index = ip_masked >> 8;
1699 
1700 	/* Calculate the index into tbl8 and range. */
1701 	tbl8_group_index = lpm->tbl24[tbl24_index].group_idx;
1702 	tbl8_group_start = tbl8_group_index * RTE_LPM_TBL8_GROUP_NUM_ENTRIES;
1703 	tbl8_index = tbl8_group_start + (ip_masked & 0xFF);
1704 	tbl8_range = depth_to_range(depth);
1705 
1706 	if (sub_rule_index < 0) {
1707 		/*
1708 		 * Loop through the range of entries on tbl8 for which the
1709 		 * rule_to_delete must be removed or modified.
1710 		 */
1711 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1712 			if (lpm->tbl8[i].depth <= depth)
1713 				lpm->tbl8[i].valid = INVALID;
1714 		}
1715 	} else {
1716 		/* Set new tbl8 entry. */
1717 		struct rte_lpm_tbl_entry new_tbl8_entry = {
1718 			.valid = VALID,
1719 			.depth = sub_rule_depth,
1720 			.valid_group = lpm->tbl8[tbl8_group_start].valid_group,
1721 			.next_hop = lpm->rules_tbl[sub_rule_index].next_hop,
1722 		};
1723 
1724 		/*
1725 		 * Loop through the range of entries on tbl8 for which the
1726 		 * rule_to_delete must be modified.
1727 		 */
1728 		for (i = tbl8_index; i < (tbl8_index + tbl8_range); i++) {
1729 			if (lpm->tbl8[i].depth <= depth)
1730 				lpm->tbl8[i] = new_tbl8_entry;
1731 		}
1732 	}
1733 
1734 	/*
1735 	 * Check if there are any valid entries in this tbl8 group. If all
1736 	 * tbl8 entries are invalid we can free the tbl8 and invalidate the
1737 	 * associated tbl24 entry.
1738 	 */
1739 
1740 	tbl8_recycle_index = tbl8_recycle_check_v1604(lpm->tbl8, tbl8_group_start);
1741 
1742 	if (tbl8_recycle_index == -EINVAL) {
1743 		/* Set tbl24 before freeing tbl8 to avoid race condition. */
1744 		lpm->tbl24[tbl24_index].valid = 0;
1745 		tbl8_free_v1604(lpm->tbl8, tbl8_group_start);
1746 	} else if (tbl8_recycle_index > -1) {
1747 		/* Update tbl24 entry. */
1748 		struct rte_lpm_tbl_entry new_tbl24_entry = {
1749 			.next_hop = lpm->tbl8[tbl8_recycle_index].next_hop,
1750 			.valid = VALID,
1751 			.valid_group = 0,
1752 			.depth = lpm->tbl8[tbl8_recycle_index].depth,
1753 		};
1754 
1755 		/* Set tbl24 before freeing tbl8 to avoid race condition. */
1756 		lpm->tbl24[tbl24_index] = new_tbl24_entry;
1757 		tbl8_free_v1604(lpm->tbl8, tbl8_group_start);
1758 	}
1759 #undef group_idx
1760 	return 0;
1761 }
1762 
1763 /*
1764  * Deletes a rule
1765  */
1766 int
1767 rte_lpm_delete_v20(struct rte_lpm_v20 *lpm, uint32_t ip, uint8_t depth)
1768 {
1769 	int32_t rule_to_delete_index, sub_rule_index;
1770 	uint32_t ip_masked;
1771 	uint8_t sub_rule_depth;
1772 	/*
1773 	 * Check input arguments. Note: IP must be a positive integer of 32
1774 	 * bits in length therefore it need not be checked.
1775 	 */
1776 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM_MAX_DEPTH)) {
1777 		return -EINVAL;
1778 	}
1779 
1780 	ip_masked = ip & depth_to_mask(depth);
1781 
1782 	/*
1783 	 * Find the index of the input rule, that needs to be deleted, in the
1784 	 * rule table.
1785 	 */
1786 	rule_to_delete_index = rule_find_v20(lpm, ip_masked, depth);
1787 
1788 	/*
1789 	 * Check if rule_to_delete_index was found. If no rule was found the
1790 	 * function rule_find returns -EINVAL.
1791 	 */
1792 	if (rule_to_delete_index < 0)
1793 		return -EINVAL;
1794 
1795 	/* Delete the rule from the rule table. */
1796 	rule_delete_v20(lpm, rule_to_delete_index, depth);
1797 
1798 	/*
1799 	 * Find rule to replace the rule_to_delete. If there is no rule to
1800 	 * replace the rule_to_delete we return -1 and invalidate the table
1801 	 * entries associated with this rule.
1802 	 */
1803 	sub_rule_depth = 0;
1804 	sub_rule_index = find_previous_rule_v20(lpm, ip, depth, &sub_rule_depth);
1805 
1806 	/*
1807 	 * If the input depth value is less than 25 use function
1808 	 * delete_depth_small otherwise use delete_depth_big.
1809 	 */
1810 	if (depth <= MAX_DEPTH_TBL24) {
1811 		return delete_depth_small_v20(lpm, ip_masked, depth,
1812 				sub_rule_index, sub_rule_depth);
1813 	} else { /* If depth > MAX_DEPTH_TBL24 */
1814 		return delete_depth_big_v20(lpm, ip_masked, depth, sub_rule_index,
1815 				sub_rule_depth);
1816 	}
1817 }
1818 VERSION_SYMBOL(rte_lpm_delete, _v20, 2.0);
1819 
1820 int
1821 rte_lpm_delete_v1604(struct rte_lpm *lpm, uint32_t ip, uint8_t depth)
1822 {
1823 	int32_t rule_to_delete_index, sub_rule_index;
1824 	uint32_t ip_masked;
1825 	uint8_t sub_rule_depth;
1826 	/*
1827 	 * Check input arguments. Note: IP must be a positive integer of 32
1828 	 * bits in length therefore it need not be checked.
1829 	 */
1830 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM_MAX_DEPTH)) {
1831 		return -EINVAL;
1832 	}
1833 
1834 	ip_masked = ip & depth_to_mask(depth);
1835 
1836 	/*
1837 	 * Find the index of the input rule, that needs to be deleted, in the
1838 	 * rule table.
1839 	 */
1840 	rule_to_delete_index = rule_find_v1604(lpm, ip_masked, depth);
1841 
1842 	/*
1843 	 * Check if rule_to_delete_index was found. If no rule was found the
1844 	 * function rule_find returns -EINVAL.
1845 	 */
1846 	if (rule_to_delete_index < 0)
1847 		return -EINVAL;
1848 
1849 	/* Delete the rule from the rule table. */
1850 	rule_delete_v1604(lpm, rule_to_delete_index, depth);
1851 
1852 	/*
1853 	 * Find rule to replace the rule_to_delete. If there is no rule to
1854 	 * replace the rule_to_delete we return -1 and invalidate the table
1855 	 * entries associated with this rule.
1856 	 */
1857 	sub_rule_depth = 0;
1858 	sub_rule_index = find_previous_rule_v1604(lpm, ip, depth, &sub_rule_depth);
1859 
1860 	/*
1861 	 * If the input depth value is less than 25 use function
1862 	 * delete_depth_small otherwise use delete_depth_big.
1863 	 */
1864 	if (depth <= MAX_DEPTH_TBL24) {
1865 		return delete_depth_small_v1604(lpm, ip_masked, depth,
1866 				sub_rule_index, sub_rule_depth);
1867 	} else { /* If depth > MAX_DEPTH_TBL24 */
1868 		return delete_depth_big_v1604(lpm, ip_masked, depth, sub_rule_index,
1869 				sub_rule_depth);
1870 	}
1871 }
1872 BIND_DEFAULT_SYMBOL(rte_lpm_delete, _v1604, 16.04);
1873 MAP_STATIC_SYMBOL(int rte_lpm_delete(struct rte_lpm *lpm, uint32_t ip,
1874 		uint8_t depth), rte_lpm_delete_v1604);
1875 
1876 /*
1877  * Delete all rules from the LPM table.
1878  */
1879 void
1880 rte_lpm_delete_all_v20(struct rte_lpm_v20 *lpm)
1881 {
1882 	/* Zero rule information. */
1883 	memset(lpm->rule_info, 0, sizeof(lpm->rule_info));
1884 
1885 	/* Zero tbl24. */
1886 	memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
1887 
1888 	/* Zero tbl8. */
1889 	memset(lpm->tbl8, 0, sizeof(lpm->tbl8));
1890 
1891 	/* Delete all rules form the rules table. */
1892 	memset(lpm->rules_tbl, 0, sizeof(lpm->rules_tbl[0]) * lpm->max_rules);
1893 }
1894 VERSION_SYMBOL(rte_lpm_delete_all, _v20, 2.0);
1895 
1896 void
1897 rte_lpm_delete_all_v1604(struct rte_lpm *lpm)
1898 {
1899 	/* Zero rule information. */
1900 	memset(lpm->rule_info, 0, sizeof(lpm->rule_info));
1901 
1902 	/* Zero tbl24. */
1903 	memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
1904 
1905 	/* Zero tbl8. */
1906 	memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0])
1907 			* RTE_LPM_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
1908 
1909 	/* Delete all rules form the rules table. */
1910 	memset(lpm->rules_tbl, 0, sizeof(lpm->rules_tbl[0]) * lpm->max_rules);
1911 }
1912 BIND_DEFAULT_SYMBOL(rte_lpm_delete_all, _v1604, 16.04);
1913 MAP_STATIC_SYMBOL(void rte_lpm_delete_all(struct rte_lpm *lpm),
1914 		rte_lpm_delete_all_v1604);
1915