xref: /dpdk/lib/lpm/rte_lpm6.c (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 #include <string.h>
5 #include <stdint.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <sys/queue.h>
9 
10 #include <rte_log.h>
11 #include <rte_common.h>
12 #include <rte_malloc.h>
13 #include <rte_memcpy.h>
14 #include <rte_eal_memconfig.h>
15 #include <rte_string_fns.h>
16 #include <rte_errno.h>
17 #include <rte_hash.h>
18 #include <assert.h>
19 #include <rte_jhash.h>
20 #include <rte_tailq.h>
21 
22 #include "rte_lpm6.h"
23 #include "lpm_log.h"
24 
25 #define RTE_LPM6_TBL24_NUM_ENTRIES        (1 << 24)
26 #define RTE_LPM6_TBL8_GROUP_NUM_ENTRIES         256
27 #define RTE_LPM6_TBL8_MAX_NUM_GROUPS      (1 << 21)
28 
29 #define RTE_LPM6_VALID_EXT_ENTRY_BITMASK 0xA0000000
30 #define RTE_LPM6_LOOKUP_SUCCESS          0x20000000
31 #define RTE_LPM6_TBL8_BITMASK            0x001FFFFF
32 
33 #define ADD_FIRST_BYTE                            3
34 #define LOOKUP_FIRST_BYTE                         4
35 #define BYTE_SIZE                                 8
36 #define BYTES2_SIZE                              16
37 
38 #define RULE_HASH_TABLE_EXTRA_SPACE              64
39 #define TBL24_IND                        UINT32_MAX
40 
41 #define lpm6_tbl8_gindex next_hop
42 
43 /** Flags for setting an entry as valid/invalid. */
44 enum valid_flag {
45 	INVALID = 0,
46 	VALID
47 };
48 
49 TAILQ_HEAD(rte_lpm6_list, rte_tailq_entry);
50 
51 static struct rte_tailq_elem rte_lpm6_tailq = {
52 	.name = "RTE_LPM6",
53 };
54 EAL_REGISTER_TAILQ(rte_lpm6_tailq)
55 
56 /** Tbl entry structure. It is the same for both tbl24 and tbl8 */
57 struct rte_lpm6_tbl_entry {
58 	uint32_t next_hop:	21;  /**< Next hop / next table to be checked. */
59 	uint32_t depth	:8;      /**< Rule depth. */
60 
61 	/* Flags. */
62 	uint32_t valid     :1;   /**< Validation flag. */
63 	uint32_t valid_group :1; /**< Group validation flag. */
64 	uint32_t ext_entry :1;   /**< External entry. */
65 };
66 
67 /** Rules tbl entry structure. */
68 struct rte_lpm6_rule {
69 	uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE]; /**< Rule IP address. */
70 	uint32_t next_hop; /**< Rule next hop. */
71 	uint8_t depth; /**< Rule depth. */
72 };
73 
74 /** Rules tbl entry key. */
75 struct rte_lpm6_rule_key {
76 	uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE]; /**< Rule IP address. */
77 	uint32_t depth; /**< Rule depth. */
78 };
79 
80 /* Header of tbl8 */
81 struct rte_lpm_tbl8_hdr {
82 	uint32_t owner_tbl_ind; /**< owner table: TBL24_IND if owner is tbl24,
83 				  *  otherwise index of tbl8
84 				  */
85 	uint32_t owner_entry_ind; /**< index of the owner table entry where
86 				    *  pointer to the tbl8 is stored
87 				    */
88 	uint32_t ref_cnt; /**< table reference counter */
89 };
90 
91 /** LPM6 structure. */
92 struct rte_lpm6 {
93 	/* LPM metadata. */
94 	char name[RTE_LPM6_NAMESIZE];    /**< Name of the lpm. */
95 	uint32_t max_rules;              /**< Max number of rules. */
96 	uint32_t used_rules;             /**< Used rules so far. */
97 	uint32_t number_tbl8s;           /**< Number of tbl8s to allocate. */
98 
99 	/* LPM Tables. */
100 	struct rte_hash *rules_tbl; /**< LPM rules. */
101 	struct rte_lpm6_tbl_entry tbl24[RTE_LPM6_TBL24_NUM_ENTRIES]
102 			__rte_cache_aligned; /**< LPM tbl24 table. */
103 
104 	uint32_t *tbl8_pool; /**< pool of indexes of free tbl8s */
105 	uint32_t tbl8_pool_pos; /**< current position in the tbl8 pool */
106 
107 	struct rte_lpm_tbl8_hdr *tbl8_hdrs; /* array of tbl8 headers */
108 
109 	struct rte_lpm6_tbl_entry tbl8[0]
110 			__rte_cache_aligned; /**< LPM tbl8 table. */
111 };
112 
113 /*
114  * Takes an array of uint8_t (IPv6 address) and masks it using the depth.
115  * It leaves untouched one bit per unit in the depth variable
116  * and set the rest to 0.
117  */
118 static inline void
119 ip6_mask_addr(uint8_t *ip, uint8_t depth)
120 {
121 	int16_t part_depth, mask;
122 	int i;
123 
124 	part_depth = depth;
125 
126 	for (i = 0; i < RTE_LPM6_IPV6_ADDR_SIZE; i++) {
127 		if (part_depth < BYTE_SIZE && part_depth >= 0) {
128 			mask = (uint16_t)(~(UINT8_MAX >> part_depth));
129 			ip[i] = (uint8_t)(ip[i] & mask);
130 		} else if (part_depth < 0)
131 			ip[i] = 0;
132 
133 		part_depth -= BYTE_SIZE;
134 	}
135 }
136 
137 /* copy ipv6 address */
138 static inline void
139 ip6_copy_addr(uint8_t *dst, const uint8_t *src)
140 {
141 	rte_memcpy(dst, src, RTE_LPM6_IPV6_ADDR_SIZE);
142 }
143 
144 /*
145  * LPM6 rule hash function
146  *
147  * It's used as a hash function for the rte_hash
148  *	containing rules
149  */
150 static inline uint32_t
151 rule_hash(const void *data, __rte_unused uint32_t data_len,
152 		  uint32_t init_val)
153 {
154 	return rte_jhash(data, sizeof(struct rte_lpm6_rule_key), init_val);
155 }
156 
157 /*
158  * Init pool of free tbl8 indexes
159  */
160 static void
161 tbl8_pool_init(struct rte_lpm6 *lpm)
162 {
163 	uint32_t i;
164 
165 	/* put entire range of indexes to the tbl8 pool */
166 	for (i = 0; i < lpm->number_tbl8s; i++)
167 		lpm->tbl8_pool[i] = i;
168 
169 	lpm->tbl8_pool_pos = 0;
170 }
171 
172 /*
173  * Get an index of a free tbl8 from the pool
174  */
175 static inline uint32_t
176 tbl8_get(struct rte_lpm6 *lpm, uint32_t *tbl8_ind)
177 {
178 	if (lpm->tbl8_pool_pos == lpm->number_tbl8s)
179 		/* no more free tbl8 */
180 		return -ENOSPC;
181 
182 	/* next index */
183 	*tbl8_ind = lpm->tbl8_pool[lpm->tbl8_pool_pos++];
184 	return 0;
185 }
186 
187 /*
188  * Put an index of a free tbl8 back to the pool
189  */
190 static inline uint32_t
191 tbl8_put(struct rte_lpm6 *lpm, uint32_t tbl8_ind)
192 {
193 	if (lpm->tbl8_pool_pos == 0)
194 		/* pool is full */
195 		return -ENOSPC;
196 
197 	lpm->tbl8_pool[--lpm->tbl8_pool_pos] = tbl8_ind;
198 	return 0;
199 }
200 
201 /*
202  * Returns number of tbl8s available in the pool
203  */
204 static inline uint32_t
205 tbl8_available(struct rte_lpm6 *lpm)
206 {
207 	return lpm->number_tbl8s - lpm->tbl8_pool_pos;
208 }
209 
210 /*
211  * Init a rule key.
212  *	  note that ip must be already masked
213  */
214 static inline void
215 rule_key_init(struct rte_lpm6_rule_key *key, uint8_t *ip, uint8_t depth)
216 {
217 	ip6_copy_addr(key->ip, ip);
218 	key->depth = depth;
219 }
220 
221 /*
222  * Rebuild the entire LPM tree by reinserting all rules
223  */
224 static void
225 rebuild_lpm(struct rte_lpm6 *lpm)
226 {
227 	uint64_t next_hop;
228 	struct rte_lpm6_rule_key *rule_key;
229 	uint32_t iter = 0;
230 
231 	while (rte_hash_iterate(lpm->rules_tbl, (void *) &rule_key,
232 			(void **) &next_hop, &iter) >= 0)
233 		rte_lpm6_add(lpm, rule_key->ip, rule_key->depth,
234 			(uint32_t) next_hop);
235 }
236 
237 /*
238  * Allocates memory for LPM object
239  */
240 struct rte_lpm6 *
241 rte_lpm6_create(const char *name, int socket_id,
242 		const struct rte_lpm6_config *config)
243 {
244 	char mem_name[RTE_LPM6_NAMESIZE];
245 	struct rte_lpm6 *lpm = NULL;
246 	struct rte_tailq_entry *te;
247 	uint64_t mem_size;
248 	struct rte_lpm6_list *lpm_list;
249 	struct rte_hash *rules_tbl = NULL;
250 	uint32_t *tbl8_pool = NULL;
251 	struct rte_lpm_tbl8_hdr *tbl8_hdrs = NULL;
252 
253 	lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
254 
255 	RTE_BUILD_BUG_ON(sizeof(struct rte_lpm6_tbl_entry) != sizeof(uint32_t));
256 	RTE_BUILD_BUG_ON(sizeof(struct rte_lpm6_rule_key) %
257 		sizeof(uint32_t) != 0);
258 
259 	/* Check user arguments. */
260 	if ((name == NULL) || (socket_id < -1) || (config == NULL) ||
261 			(config->max_rules == 0) ||
262 			config->number_tbl8s > RTE_LPM6_TBL8_MAX_NUM_GROUPS) {
263 		rte_errno = EINVAL;
264 		return NULL;
265 	}
266 
267 	/* create rules hash table */
268 	snprintf(mem_name, sizeof(mem_name), "LRH_%s", name);
269 	struct rte_hash_parameters rule_hash_tbl_params = {
270 		.entries = config->max_rules * 1.2 +
271 			RULE_HASH_TABLE_EXTRA_SPACE,
272 		.key_len = sizeof(struct rte_lpm6_rule_key),
273 		.hash_func = rule_hash,
274 		.hash_func_init_val = 0,
275 		.name = mem_name,
276 		.reserved = 0,
277 		.socket_id = socket_id,
278 		.extra_flag = 0
279 	};
280 
281 	rules_tbl = rte_hash_create(&rule_hash_tbl_params);
282 	if (rules_tbl == NULL) {
283 		LPM_LOG(ERR, "LPM rules hash table allocation failed: %s (%d)",
284 				  rte_strerror(rte_errno), rte_errno);
285 		goto fail_wo_unlock;
286 	}
287 
288 	/* allocate tbl8 indexes pool */
289 	tbl8_pool = rte_malloc(NULL,
290 			sizeof(uint32_t) * config->number_tbl8s,
291 			RTE_CACHE_LINE_SIZE);
292 	if (tbl8_pool == NULL) {
293 		LPM_LOG(ERR, "LPM tbl8 pool allocation failed: %s (%d)",
294 				  rte_strerror(rte_errno), rte_errno);
295 		rte_errno = ENOMEM;
296 		goto fail_wo_unlock;
297 	}
298 
299 	/* allocate tbl8 headers */
300 	tbl8_hdrs = rte_malloc(NULL,
301 			sizeof(struct rte_lpm_tbl8_hdr) * config->number_tbl8s,
302 			RTE_CACHE_LINE_SIZE);
303 	if (tbl8_hdrs == NULL) {
304 		LPM_LOG(ERR, "LPM tbl8 headers allocation failed: %s (%d)",
305 				  rte_strerror(rte_errno), rte_errno);
306 		rte_errno = ENOMEM;
307 		goto fail_wo_unlock;
308 	}
309 
310 	snprintf(mem_name, sizeof(mem_name), "LPM_%s", name);
311 
312 	/* Determine the amount of memory to allocate. */
313 	mem_size = sizeof(*lpm) + (sizeof(lpm->tbl8[0]) *
314 			RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * config->number_tbl8s);
315 
316 	rte_mcfg_tailq_write_lock();
317 
318 	/* Guarantee there's no existing */
319 	TAILQ_FOREACH(te, lpm_list, next) {
320 		lpm = (struct rte_lpm6 *) te->data;
321 		if (strncmp(name, lpm->name, RTE_LPM6_NAMESIZE) == 0)
322 			break;
323 	}
324 	lpm = NULL;
325 	if (te != NULL) {
326 		rte_errno = EEXIST;
327 		goto fail;
328 	}
329 
330 	/* allocate tailq entry */
331 	te = rte_zmalloc("LPM6_TAILQ_ENTRY", sizeof(*te), 0);
332 	if (te == NULL) {
333 		LPM_LOG(ERR, "Failed to allocate tailq entry!");
334 		rte_errno = ENOMEM;
335 		goto fail;
336 	}
337 
338 	/* Allocate memory to store the LPM data structures. */
339 	lpm = rte_zmalloc_socket(mem_name, (size_t)mem_size,
340 			RTE_CACHE_LINE_SIZE, socket_id);
341 
342 	if (lpm == NULL) {
343 		LPM_LOG(ERR, "LPM memory allocation failed");
344 		rte_free(te);
345 		rte_errno = ENOMEM;
346 		goto fail;
347 	}
348 
349 	/* Save user arguments. */
350 	lpm->max_rules = config->max_rules;
351 	lpm->number_tbl8s = config->number_tbl8s;
352 	strlcpy(lpm->name, name, sizeof(lpm->name));
353 	lpm->rules_tbl = rules_tbl;
354 	lpm->tbl8_pool = tbl8_pool;
355 	lpm->tbl8_hdrs = tbl8_hdrs;
356 
357 	/* init the stack */
358 	tbl8_pool_init(lpm);
359 
360 	te->data = (void *) lpm;
361 
362 	TAILQ_INSERT_TAIL(lpm_list, te, next);
363 	rte_mcfg_tailq_write_unlock();
364 	return lpm;
365 
366 fail:
367 	rte_mcfg_tailq_write_unlock();
368 
369 fail_wo_unlock:
370 	rte_free(tbl8_hdrs);
371 	rte_free(tbl8_pool);
372 	rte_hash_free(rules_tbl);
373 
374 	return NULL;
375 }
376 
377 /*
378  * Find an existing lpm table and return a pointer to it.
379  */
380 struct rte_lpm6 *
381 rte_lpm6_find_existing(const char *name)
382 {
383 	struct rte_lpm6 *l = NULL;
384 	struct rte_tailq_entry *te;
385 	struct rte_lpm6_list *lpm_list;
386 
387 	lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
388 
389 	rte_mcfg_tailq_read_lock();
390 	TAILQ_FOREACH(te, lpm_list, next) {
391 		l = (struct rte_lpm6 *) te->data;
392 		if (strncmp(name, l->name, RTE_LPM6_NAMESIZE) == 0)
393 			break;
394 	}
395 	rte_mcfg_tailq_read_unlock();
396 
397 	if (te == NULL) {
398 		rte_errno = ENOENT;
399 		return NULL;
400 	}
401 
402 	return l;
403 }
404 
405 /*
406  * Deallocates memory for given LPM table.
407  */
408 void
409 rte_lpm6_free(struct rte_lpm6 *lpm)
410 {
411 	struct rte_lpm6_list *lpm_list;
412 	struct rte_tailq_entry *te;
413 
414 	/* Check user arguments. */
415 	if (lpm == NULL)
416 		return;
417 
418 	lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
419 
420 	rte_mcfg_tailq_write_lock();
421 
422 	/* find our tailq entry */
423 	TAILQ_FOREACH(te, lpm_list, next) {
424 		if (te->data == (void *) lpm)
425 			break;
426 	}
427 
428 	if (te != NULL)
429 		TAILQ_REMOVE(lpm_list, te, next);
430 
431 	rte_mcfg_tailq_write_unlock();
432 
433 	rte_free(lpm->tbl8_hdrs);
434 	rte_free(lpm->tbl8_pool);
435 	rte_hash_free(lpm->rules_tbl);
436 	rte_free(lpm);
437 	rte_free(te);
438 }
439 
440 /* Find a rule */
441 static inline int
442 rule_find_with_key(struct rte_lpm6 *lpm,
443 		  const struct rte_lpm6_rule_key *rule_key,
444 		  uint32_t *next_hop)
445 {
446 	uint64_t hash_val;
447 	int ret;
448 
449 	/* lookup for a rule */
450 	ret = rte_hash_lookup_data(lpm->rules_tbl, (const void *) rule_key,
451 		(void **) &hash_val);
452 	if (ret >= 0) {
453 		*next_hop = (uint32_t) hash_val;
454 		return 1;
455 	}
456 
457 	return 0;
458 }
459 
460 /* Find a rule */
461 static int
462 rule_find(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,
463 		  uint32_t *next_hop)
464 {
465 	struct rte_lpm6_rule_key rule_key;
466 
467 	/* init a rule key */
468 	rule_key_init(&rule_key, ip, depth);
469 
470 	return rule_find_with_key(lpm, &rule_key, next_hop);
471 }
472 
473 /*
474  * Checks if a rule already exists in the rules table and updates
475  * the nexthop if so. Otherwise it adds a new rule if enough space is available.
476  *
477  * Returns:
478  *    0 - next hop of existed rule is updated
479  *    1 - new rule successfully added
480  *   <0 - error
481  */
482 static inline int
483 rule_add(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth, uint32_t next_hop)
484 {
485 	int ret, rule_exist;
486 	struct rte_lpm6_rule_key rule_key;
487 	uint32_t unused;
488 
489 	/* init a rule key */
490 	rule_key_init(&rule_key, ip, depth);
491 
492 	/* Scan through rule list to see if rule already exists. */
493 	rule_exist = rule_find_with_key(lpm, &rule_key, &unused);
494 
495 	/*
496 	 * If rule does not exist check if there is space to add a new rule to
497 	 * this rule group. If there is no space return error.
498 	 */
499 	if (!rule_exist && lpm->used_rules == lpm->max_rules)
500 		return -ENOSPC;
501 
502 	/* add the rule or update rules next hop */
503 	ret = rte_hash_add_key_data(lpm->rules_tbl, &rule_key,
504 		(void *)(uintptr_t) next_hop);
505 	if (ret < 0)
506 		return ret;
507 
508 	/* Increment the used rules counter for this rule group. */
509 	if (!rule_exist) {
510 		lpm->used_rules++;
511 		return 1;
512 	}
513 
514 	return 0;
515 }
516 
517 /*
518  * Function that expands a rule across the data structure when a less-generic
519  * one has been added before. It assures that every possible combination of bits
520  * in the IP address returns a match.
521  */
522 static void
523 expand_rule(struct rte_lpm6 *lpm, uint32_t tbl8_gindex, uint8_t old_depth,
524 		uint8_t new_depth, uint32_t next_hop, uint8_t valid)
525 {
526 	uint32_t tbl8_group_end, tbl8_gindex_next, j;
527 
528 	tbl8_group_end = tbl8_gindex + RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
529 
530 	struct rte_lpm6_tbl_entry new_tbl8_entry = {
531 		.valid = valid,
532 		.valid_group = valid,
533 		.depth = new_depth,
534 		.next_hop = next_hop,
535 		.ext_entry = 0,
536 	};
537 
538 	for (j = tbl8_gindex; j < tbl8_group_end; j++) {
539 		if (!lpm->tbl8[j].valid || (lpm->tbl8[j].ext_entry == 0
540 				&& lpm->tbl8[j].depth <= old_depth)) {
541 
542 			lpm->tbl8[j] = new_tbl8_entry;
543 
544 		} else if (lpm->tbl8[j].ext_entry == 1) {
545 
546 			tbl8_gindex_next = lpm->tbl8[j].lpm6_tbl8_gindex
547 					* RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
548 			expand_rule(lpm, tbl8_gindex_next, old_depth, new_depth,
549 					next_hop, valid);
550 		}
551 	}
552 }
553 
554 /*
555  * Init a tbl8 header
556  */
557 static inline void
558 init_tbl8_header(struct rte_lpm6 *lpm, uint32_t tbl_ind,
559 		uint32_t owner_tbl_ind, uint32_t owner_entry_ind)
560 {
561 	struct rte_lpm_tbl8_hdr *tbl_hdr = &lpm->tbl8_hdrs[tbl_ind];
562 	tbl_hdr->owner_tbl_ind = owner_tbl_ind;
563 	tbl_hdr->owner_entry_ind = owner_entry_ind;
564 	tbl_hdr->ref_cnt = 0;
565 }
566 
567 /*
568  * Calculate index to the table based on the number and position
569  * of the bytes being inspected in this step.
570  */
571 static uint32_t
572 get_bitshift(const uint8_t *ip, uint8_t first_byte, uint8_t bytes)
573 {
574 	uint32_t entry_ind, i;
575 	int8_t bitshift;
576 
577 	entry_ind = 0;
578 	for (i = first_byte; i < (uint32_t)(first_byte + bytes); i++) {
579 		bitshift = (int8_t)((bytes - i)*BYTE_SIZE);
580 
581 		if (bitshift < 0)
582 			bitshift = 0;
583 		entry_ind = entry_ind | ip[i-1] << bitshift;
584 	}
585 
586 	return entry_ind;
587 }
588 
589 /*
590  * Simulate adding a new route to the LPM counting number
591  * of new tables that will be needed
592  *
593  * It returns 0 on success, or 1 if
594  * the process needs to be continued by calling the function again.
595  */
596 static inline int
597 simulate_add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,
598 		struct rte_lpm6_tbl_entry **next_tbl, const uint8_t *ip,
599 		uint8_t bytes, uint8_t first_byte, uint8_t depth,
600 		uint32_t *need_tbl_nb)
601 {
602 	uint32_t entry_ind;
603 	uint8_t bits_covered;
604 	uint32_t next_tbl_ind;
605 
606 	/*
607 	 * Calculate index to the table based on the number and position
608 	 * of the bytes being inspected in this step.
609 	 */
610 	entry_ind = get_bitshift(ip, first_byte, bytes);
611 
612 	/* Number of bits covered in this step */
613 	bits_covered = (uint8_t)((bytes+first_byte-1)*BYTE_SIZE);
614 
615 	if (depth <= bits_covered) {
616 		*need_tbl_nb = 0;
617 		return 0;
618 	}
619 
620 	if (tbl[entry_ind].valid == 0 || tbl[entry_ind].ext_entry == 0) {
621 		/* from this point on a new table is needed on each level
622 		 * that is not covered yet
623 		 */
624 		depth -= bits_covered;
625 		uint32_t cnt = depth >> 3; /* depth / BYTE_SIZE */
626 		if (depth & 7) /* 0b00000111 */
627 			/* if depth % 8 > 0 then one more table is needed
628 			 * for those last bits
629 			 */
630 			cnt++;
631 
632 		*need_tbl_nb = cnt;
633 		return 0;
634 	}
635 
636 	next_tbl_ind = tbl[entry_ind].lpm6_tbl8_gindex;
637 	*next_tbl = &(lpm->tbl8[next_tbl_ind *
638 		RTE_LPM6_TBL8_GROUP_NUM_ENTRIES]);
639 	*need_tbl_nb = 0;
640 	return 1;
641 }
642 
643 /*
644  * Partially adds a new route to the data structure (tbl24+tbl8s).
645  * It returns 0 on success, a negative number on failure, or 1 if
646  * the process needs to be continued by calling the function again.
647  */
648 static inline int
649 add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,
650 		uint32_t tbl_ind, struct rte_lpm6_tbl_entry **next_tbl,
651 		uint32_t *next_tbl_ind, uint8_t *ip, uint8_t bytes,
652 		uint8_t first_byte, uint8_t depth, uint32_t next_hop,
653 		uint8_t is_new_rule)
654 {
655 	uint32_t entry_ind, tbl_range, tbl8_group_start, tbl8_group_end, i;
656 	uint32_t tbl8_gindex;
657 	uint8_t bits_covered;
658 	int ret;
659 
660 	/*
661 	 * Calculate index to the table based on the number and position
662 	 * of the bytes being inspected in this step.
663 	 */
664 	entry_ind = get_bitshift(ip, first_byte, bytes);
665 
666 	/* Number of bits covered in this step */
667 	bits_covered = (uint8_t)((bytes+first_byte-1)*BYTE_SIZE);
668 
669 	/*
670 	 * If depth if smaller than this number (ie this is the last step)
671 	 * expand the rule across the relevant positions in the table.
672 	 */
673 	if (depth <= bits_covered) {
674 		tbl_range = 1 << (bits_covered - depth);
675 
676 		for (i = entry_ind; i < (entry_ind + tbl_range); i++) {
677 			if (!tbl[i].valid || (tbl[i].ext_entry == 0 &&
678 					tbl[i].depth <= depth)) {
679 
680 				struct rte_lpm6_tbl_entry new_tbl_entry = {
681 					.next_hop = next_hop,
682 					.depth = depth,
683 					.valid = VALID,
684 					.valid_group = VALID,
685 					.ext_entry = 0,
686 				};
687 
688 				tbl[i] = new_tbl_entry;
689 
690 			} else if (tbl[i].ext_entry == 1) {
691 
692 				/*
693 				 * If tbl entry is valid and extended calculate the index
694 				 * into next tbl8 and expand the rule across the data structure.
695 				 */
696 				tbl8_gindex = tbl[i].lpm6_tbl8_gindex *
697 						RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
698 				expand_rule(lpm, tbl8_gindex, depth, depth,
699 						next_hop, VALID);
700 			}
701 		}
702 
703 		/* update tbl8 rule reference counter */
704 		if (tbl_ind != TBL24_IND && is_new_rule)
705 			lpm->tbl8_hdrs[tbl_ind].ref_cnt++;
706 
707 		return 0;
708 	}
709 	/*
710 	 * If this is not the last step just fill one position
711 	 * and calculate the index to the next table.
712 	 */
713 	else {
714 		/* If it's invalid a new tbl8 is needed */
715 		if (!tbl[entry_ind].valid) {
716 			/* get a new table */
717 			ret = tbl8_get(lpm, &tbl8_gindex);
718 			if (ret != 0)
719 				return -ENOSPC;
720 
721 			/* invalidate all new tbl8 entries */
722 			tbl8_group_start = tbl8_gindex *
723 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
724 			memset(&lpm->tbl8[tbl8_group_start], 0,
725 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES *
726 					sizeof(struct rte_lpm6_tbl_entry));
727 
728 			/* init the new table's header:
729 			 *   save the reference to the owner table
730 			 */
731 			init_tbl8_header(lpm, tbl8_gindex, tbl_ind, entry_ind);
732 
733 			/* reference to a new tbl8 */
734 			struct rte_lpm6_tbl_entry new_tbl_entry = {
735 				.lpm6_tbl8_gindex = tbl8_gindex,
736 				.depth = 0,
737 				.valid = VALID,
738 				.valid_group = VALID,
739 				.ext_entry = 1,
740 			};
741 
742 			tbl[entry_ind] = new_tbl_entry;
743 
744 			/* update the current table's reference counter */
745 			if (tbl_ind != TBL24_IND)
746 				lpm->tbl8_hdrs[tbl_ind].ref_cnt++;
747 		}
748 		/*
749 		 * If it's valid but not extended the rule that was stored
750 		 * here needs to be moved to the next table.
751 		 */
752 		else if (tbl[entry_ind].ext_entry == 0) {
753 			/* get a new tbl8 index */
754 			ret = tbl8_get(lpm, &tbl8_gindex);
755 			if (ret != 0)
756 				return -ENOSPC;
757 
758 			tbl8_group_start = tbl8_gindex *
759 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
760 			tbl8_group_end = tbl8_group_start +
761 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
762 
763 			struct rte_lpm6_tbl_entry tbl_entry = {
764 				.next_hop = tbl[entry_ind].next_hop,
765 				.depth = tbl[entry_ind].depth,
766 				.valid = VALID,
767 				.valid_group = VALID,
768 				.ext_entry = 0
769 			};
770 
771 			/* Populate new tbl8 with tbl value. */
772 			for (i = tbl8_group_start; i < tbl8_group_end; i++)
773 				lpm->tbl8[i] = tbl_entry;
774 
775 			/* init the new table's header:
776 			 *   save the reference to the owner table
777 			 */
778 			init_tbl8_header(lpm, tbl8_gindex, tbl_ind, entry_ind);
779 
780 			/*
781 			 * Update tbl entry to point to new tbl8 entry. Note: The
782 			 * ext_flag and tbl8_index need to be updated simultaneously,
783 			 * so assign whole structure in one go.
784 			 */
785 			struct rte_lpm6_tbl_entry new_tbl_entry = {
786 				.lpm6_tbl8_gindex = tbl8_gindex,
787 				.depth = 0,
788 				.valid = VALID,
789 				.valid_group = VALID,
790 				.ext_entry = 1,
791 			};
792 
793 			tbl[entry_ind] = new_tbl_entry;
794 
795 			/* update the current table's reference counter */
796 			if (tbl_ind != TBL24_IND)
797 				lpm->tbl8_hdrs[tbl_ind].ref_cnt++;
798 		}
799 
800 		*next_tbl_ind = tbl[entry_ind].lpm6_tbl8_gindex;
801 		*next_tbl = &(lpm->tbl8[*next_tbl_ind *
802 				  RTE_LPM6_TBL8_GROUP_NUM_ENTRIES]);
803 	}
804 
805 	return 1;
806 }
807 
808 /*
809  * Simulate adding a route to LPM
810  *
811  *	Returns:
812  *    0 on success
813  *    -ENOSPC not enough tbl8 left
814  */
815 static int
816 simulate_add(struct rte_lpm6 *lpm, const uint8_t *masked_ip, uint8_t depth)
817 {
818 	struct rte_lpm6_tbl_entry *tbl;
819 	struct rte_lpm6_tbl_entry *tbl_next = NULL;
820 	int ret, i;
821 
822 	/* number of new tables needed for a step */
823 	uint32_t need_tbl_nb;
824 	/* total number of new tables needed */
825 	uint32_t total_need_tbl_nb;
826 
827 	/* Inspect the first three bytes through tbl24 on the first step. */
828 	ret = simulate_add_step(lpm, lpm->tbl24, &tbl_next, masked_ip,
829 		ADD_FIRST_BYTE, 1, depth, &need_tbl_nb);
830 	total_need_tbl_nb = need_tbl_nb;
831 	/*
832 	 * Inspect one by one the rest of the bytes until
833 	 * the process is completed.
834 	 */
835 	for (i = ADD_FIRST_BYTE; i < RTE_LPM6_IPV6_ADDR_SIZE && ret == 1; i++) {
836 		tbl = tbl_next;
837 		ret = simulate_add_step(lpm, tbl, &tbl_next, masked_ip, 1,
838 			(uint8_t)(i + 1), depth, &need_tbl_nb);
839 		total_need_tbl_nb += need_tbl_nb;
840 	}
841 
842 	if (tbl8_available(lpm) < total_need_tbl_nb)
843 		/* not enough tbl8 to add a rule */
844 		return -ENOSPC;
845 
846 	return 0;
847 }
848 
849 /*
850  * Add a route
851  */
852 int
853 rte_lpm6_add(struct rte_lpm6 *lpm, const uint8_t *ip, uint8_t depth,
854 	     uint32_t next_hop)
855 {
856 	struct rte_lpm6_tbl_entry *tbl;
857 	struct rte_lpm6_tbl_entry *tbl_next = NULL;
858 	/* init to avoid compiler warning */
859 	uint32_t tbl_next_num = 123456;
860 	int status;
861 	uint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];
862 	int i;
863 
864 	/* Check user arguments. */
865 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM6_MAX_DEPTH))
866 		return -EINVAL;
867 
868 	/* Copy the IP and mask it to avoid modifying user's input data. */
869 	ip6_copy_addr(masked_ip, ip);
870 	ip6_mask_addr(masked_ip, depth);
871 
872 	/* Simulate adding a new route */
873 	int ret = simulate_add(lpm, masked_ip, depth);
874 	if (ret < 0)
875 		return ret;
876 
877 	/* Add the rule to the rule table. */
878 	int is_new_rule = rule_add(lpm, masked_ip, depth, next_hop);
879 	/* If there is no space available for new rule return error. */
880 	if (is_new_rule < 0)
881 		return is_new_rule;
882 
883 	/* Inspect the first three bytes through tbl24 on the first step. */
884 	tbl = lpm->tbl24;
885 	status = add_step(lpm, tbl, TBL24_IND, &tbl_next, &tbl_next_num,
886 		masked_ip, ADD_FIRST_BYTE, 1, depth, next_hop,
887 		is_new_rule);
888 	assert(status >= 0);
889 
890 	/*
891 	 * Inspect one by one the rest of the bytes until
892 	 * the process is completed.
893 	 */
894 	for (i = ADD_FIRST_BYTE; i < RTE_LPM6_IPV6_ADDR_SIZE && status == 1; i++) {
895 		tbl = tbl_next;
896 		status = add_step(lpm, tbl, tbl_next_num, &tbl_next,
897 			&tbl_next_num, masked_ip, 1, (uint8_t)(i + 1),
898 			depth, next_hop, is_new_rule);
899 		assert(status >= 0);
900 	}
901 
902 	return status;
903 }
904 
905 /*
906  * Takes a pointer to a table entry and inspect one level.
907  * The function returns 0 on lookup success, ENOENT if no match was found
908  * or 1 if the process needs to be continued by calling the function again.
909  */
910 static inline int
911 lookup_step(const struct rte_lpm6 *lpm, const struct rte_lpm6_tbl_entry *tbl,
912 		const struct rte_lpm6_tbl_entry **tbl_next, const uint8_t *ip,
913 		uint8_t first_byte, uint32_t *next_hop)
914 {
915 	uint32_t tbl8_index, tbl_entry;
916 
917 	/* Take the integer value from the pointer. */
918 	tbl_entry = *(const uint32_t *)tbl;
919 
920 	/* If it is valid and extended we calculate the new pointer to return. */
921 	if ((tbl_entry & RTE_LPM6_VALID_EXT_ENTRY_BITMASK) ==
922 			RTE_LPM6_VALID_EXT_ENTRY_BITMASK) {
923 
924 		tbl8_index = ip[first_byte-1] +
925 				((tbl_entry & RTE_LPM6_TBL8_BITMASK) *
926 				RTE_LPM6_TBL8_GROUP_NUM_ENTRIES);
927 
928 		*tbl_next = &lpm->tbl8[tbl8_index];
929 
930 		return 1;
931 	} else {
932 		/* If not extended then we can have a match. */
933 		*next_hop = ((uint32_t)tbl_entry & RTE_LPM6_TBL8_BITMASK);
934 		return (tbl_entry & RTE_LPM6_LOOKUP_SUCCESS) ? 0 : -ENOENT;
935 	}
936 }
937 
938 /*
939  * Looks up an IP
940  */
941 int
942 rte_lpm6_lookup(const struct rte_lpm6 *lpm, const uint8_t *ip,
943 		uint32_t *next_hop)
944 {
945 	const struct rte_lpm6_tbl_entry *tbl;
946 	const struct rte_lpm6_tbl_entry *tbl_next = NULL;
947 	int status;
948 	uint8_t first_byte;
949 	uint32_t tbl24_index;
950 
951 	/* DEBUG: Check user input arguments. */
952 	if ((lpm == NULL) || (ip == NULL) || (next_hop == NULL))
953 		return -EINVAL;
954 
955 	first_byte = LOOKUP_FIRST_BYTE;
956 	tbl24_index = (ip[0] << BYTES2_SIZE) | (ip[1] << BYTE_SIZE) | ip[2];
957 
958 	/* Calculate pointer to the first entry to be inspected */
959 	tbl = &lpm->tbl24[tbl24_index];
960 
961 	do {
962 		/* Continue inspecting following levels until success or failure */
963 		status = lookup_step(lpm, tbl, &tbl_next, ip, first_byte++, next_hop);
964 		tbl = tbl_next;
965 	} while (status == 1);
966 
967 	return status;
968 }
969 
970 /*
971  * Looks up a group of IP addresses
972  */
973 int
974 rte_lpm6_lookup_bulk_func(const struct rte_lpm6 *lpm,
975 		uint8_t ips[][RTE_LPM6_IPV6_ADDR_SIZE],
976 		int32_t *next_hops, unsigned int n)
977 {
978 	unsigned int i;
979 	const struct rte_lpm6_tbl_entry *tbl;
980 	const struct rte_lpm6_tbl_entry *tbl_next = NULL;
981 	uint32_t tbl24_index, next_hop;
982 	uint8_t first_byte;
983 	int status;
984 
985 	/* DEBUG: Check user input arguments. */
986 	if ((lpm == NULL) || (ips == NULL) || (next_hops == NULL))
987 		return -EINVAL;
988 
989 	for (i = 0; i < n; i++) {
990 		first_byte = LOOKUP_FIRST_BYTE;
991 		tbl24_index = (ips[i][0] << BYTES2_SIZE) |
992 				(ips[i][1] << BYTE_SIZE) | ips[i][2];
993 
994 		/* Calculate pointer to the first entry to be inspected */
995 		tbl = &lpm->tbl24[tbl24_index];
996 
997 		do {
998 			/* Continue inspecting following levels
999 			 * until success or failure
1000 			 */
1001 			status = lookup_step(lpm, tbl, &tbl_next, ips[i],
1002 					first_byte++, &next_hop);
1003 			tbl = tbl_next;
1004 		} while (status == 1);
1005 
1006 		if (status < 0)
1007 			next_hops[i] = -1;
1008 		else
1009 			next_hops[i] = (int32_t)next_hop;
1010 	}
1011 
1012 	return 0;
1013 }
1014 
1015 /*
1016  * Look for a rule in the high-level rules table
1017  */
1018 int
1019 rte_lpm6_is_rule_present(struct rte_lpm6 *lpm, const uint8_t *ip, uint8_t depth,
1020 			 uint32_t *next_hop)
1021 {
1022 	uint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];
1023 
1024 	/* Check user arguments. */
1025 	if ((lpm == NULL) || next_hop == NULL || ip == NULL ||
1026 			(depth < 1) || (depth > RTE_LPM6_MAX_DEPTH))
1027 		return -EINVAL;
1028 
1029 	/* Copy the IP and mask it to avoid modifying user's input data. */
1030 	ip6_copy_addr(masked_ip, ip);
1031 	ip6_mask_addr(masked_ip, depth);
1032 
1033 	return rule_find(lpm, masked_ip, depth, next_hop);
1034 }
1035 
1036 /*
1037  * Delete a rule from the rule table.
1038  * NOTE: Valid range for depth parameter is 1 .. 128 inclusive.
1039  * return
1040  *	  0 on success
1041  *   <0 on failure
1042  */
1043 static inline int
1044 rule_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)
1045 {
1046 	int ret;
1047 	struct rte_lpm6_rule_key rule_key;
1048 
1049 	/* init rule key */
1050 	rule_key_init(&rule_key, ip, depth);
1051 
1052 	/* delete the rule */
1053 	ret = rte_hash_del_key(lpm->rules_tbl, (void *) &rule_key);
1054 	if (ret >= 0)
1055 		lpm->used_rules--;
1056 
1057 	return ret;
1058 }
1059 
1060 /*
1061  * Deletes a group of rules
1062  *
1063  * Note that the function rebuilds the lpm table,
1064  * rather than doing incremental updates like
1065  * the regular delete function
1066  */
1067 int
1068 rte_lpm6_delete_bulk_func(struct rte_lpm6 *lpm,
1069 		uint8_t ips[][RTE_LPM6_IPV6_ADDR_SIZE], uint8_t *depths,
1070 		unsigned n)
1071 {
1072 	uint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];
1073 	unsigned i;
1074 
1075 	/* Check input arguments. */
1076 	if ((lpm == NULL) || (ips == NULL) || (depths == NULL))
1077 		return -EINVAL;
1078 
1079 	for (i = 0; i < n; i++) {
1080 		ip6_copy_addr(masked_ip, ips[i]);
1081 		ip6_mask_addr(masked_ip, depths[i]);
1082 		rule_delete(lpm, masked_ip, depths[i]);
1083 	}
1084 
1085 	/*
1086 	 * Set all the table entries to 0 (ie delete every rule
1087 	 * from the data structure.
1088 	 */
1089 	memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
1090 	memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0])
1091 			* RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
1092 	tbl8_pool_init(lpm);
1093 
1094 	/*
1095 	 * Add every rule again (except for the ones that were removed from
1096 	 * the rules table).
1097 	 */
1098 	rebuild_lpm(lpm);
1099 
1100 	return 0;
1101 }
1102 
1103 /*
1104  * Delete all rules from the LPM table.
1105  */
1106 void
1107 rte_lpm6_delete_all(struct rte_lpm6 *lpm)
1108 {
1109 	/* Zero used rules counter. */
1110 	lpm->used_rules = 0;
1111 
1112 	/* Zero tbl24. */
1113 	memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
1114 
1115 	/* Zero tbl8. */
1116 	memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0]) *
1117 			RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
1118 
1119 	/* init pool of free tbl8 indexes */
1120 	tbl8_pool_init(lpm);
1121 
1122 	/* Delete all rules form the rules table. */
1123 	rte_hash_reset(lpm->rules_tbl);
1124 }
1125 
1126 /*
1127  * Convert a depth to a one byte long mask
1128  *   Example: 4 will be converted to 0xF0
1129  */
1130 static uint8_t __attribute__((pure))
1131 depth_to_mask_1b(uint8_t depth)
1132 {
1133 	/* To calculate a mask start with a 1 on the left hand side and right
1134 	 * shift while populating the left hand side with 1's
1135 	 */
1136 	return (signed char)0x80 >> (depth - 1);
1137 }
1138 
1139 /*
1140  * Find a less specific rule
1141  */
1142 static int
1143 rule_find_less_specific(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,
1144 	struct rte_lpm6_rule *rule)
1145 {
1146 	int ret;
1147 	uint32_t next_hop;
1148 	uint8_t mask;
1149 	struct rte_lpm6_rule_key rule_key;
1150 
1151 	if (depth == 1)
1152 		return 0;
1153 
1154 	rule_key_init(&rule_key, ip, depth);
1155 
1156 	while (depth > 1) {
1157 		depth--;
1158 
1159 		/* each iteration zero one more bit of the key */
1160 		mask = depth & 7; /* depth % BYTE_SIZE */
1161 		if (mask > 0)
1162 			mask = depth_to_mask_1b(mask);
1163 
1164 		rule_key.depth = depth;
1165 		rule_key.ip[depth >> 3] &= mask;
1166 
1167 		ret = rule_find_with_key(lpm, &rule_key, &next_hop);
1168 		if (ret) {
1169 			rule->depth = depth;
1170 			ip6_copy_addr(rule->ip, rule_key.ip);
1171 			rule->next_hop = next_hop;
1172 			return 1;
1173 		}
1174 	}
1175 
1176 	return 0;
1177 }
1178 
1179 /*
1180  * Find range of tbl8 cells occupied by a rule
1181  */
1182 static void
1183 rule_find_range(struct rte_lpm6 *lpm, const uint8_t *ip, uint8_t depth,
1184 		  struct rte_lpm6_tbl_entry **from,
1185 		  struct rte_lpm6_tbl_entry **to,
1186 		  uint32_t *out_tbl_ind)
1187 {
1188 	uint32_t ind;
1189 	uint32_t first_3bytes = (uint32_t)ip[0] << 16 | ip[1] << 8 | ip[2];
1190 
1191 	if (depth <= 24) {
1192 		/* rule is within the top level */
1193 		ind = first_3bytes;
1194 		*from = &lpm->tbl24[ind];
1195 		ind += (1 << (24 - depth)) - 1;
1196 		*to = &lpm->tbl24[ind];
1197 		*out_tbl_ind = TBL24_IND;
1198 	} else {
1199 		/* top level entry */
1200 		struct rte_lpm6_tbl_entry *tbl = &lpm->tbl24[first_3bytes];
1201 		assert(tbl->ext_entry == 1);
1202 		/* first tbl8 */
1203 		uint32_t tbl_ind = tbl->lpm6_tbl8_gindex;
1204 		tbl = &lpm->tbl8[tbl_ind *
1205 				RTE_LPM6_TBL8_GROUP_NUM_ENTRIES];
1206 		/* current ip byte, the top level is already behind */
1207 		uint8_t byte = 3;
1208 		/* minus top level */
1209 		depth -= 24;
1210 
1211 		/* iterate through levels (tbl8s)
1212 		 * until we reach the last one
1213 		 */
1214 		while (depth > 8) {
1215 			tbl += ip[byte];
1216 			assert(tbl->ext_entry == 1);
1217 			/* go to the next level/tbl8 */
1218 			tbl_ind = tbl->lpm6_tbl8_gindex;
1219 			tbl = &lpm->tbl8[tbl_ind *
1220 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES];
1221 			byte += 1;
1222 			depth -= 8;
1223 		}
1224 
1225 		/* last level/tbl8 */
1226 		ind = ip[byte] & depth_to_mask_1b(depth);
1227 		*from = &tbl[ind];
1228 		ind += (1 << (8 - depth)) - 1;
1229 		*to = &tbl[ind];
1230 		*out_tbl_ind = tbl_ind;
1231 	}
1232 }
1233 
1234 /*
1235  * Remove a table from the LPM tree
1236  */
1237 static void
1238 remove_tbl(struct rte_lpm6 *lpm, struct rte_lpm_tbl8_hdr *tbl_hdr,
1239 		  uint32_t tbl_ind, struct rte_lpm6_rule *lsp_rule)
1240 {
1241 	struct rte_lpm6_tbl_entry *owner_entry;
1242 
1243 	if (tbl_hdr->owner_tbl_ind == TBL24_IND)
1244 		owner_entry = &lpm->tbl24[tbl_hdr->owner_entry_ind];
1245 	else {
1246 		uint32_t owner_tbl_ind = tbl_hdr->owner_tbl_ind;
1247 		owner_entry = &lpm->tbl8[
1248 			owner_tbl_ind * RTE_LPM6_TBL8_GROUP_NUM_ENTRIES +
1249 			tbl_hdr->owner_entry_ind];
1250 
1251 		struct rte_lpm_tbl8_hdr *owner_tbl_hdr =
1252 			&lpm->tbl8_hdrs[owner_tbl_ind];
1253 		if (--owner_tbl_hdr->ref_cnt == 0)
1254 			remove_tbl(lpm, owner_tbl_hdr, owner_tbl_ind, lsp_rule);
1255 	}
1256 
1257 	assert(owner_entry->ext_entry == 1);
1258 
1259 	/* unlink the table */
1260 	if (lsp_rule != NULL) {
1261 		struct rte_lpm6_tbl_entry new_tbl_entry = {
1262 			.next_hop = lsp_rule->next_hop,
1263 			.depth = lsp_rule->depth,
1264 			.valid = VALID,
1265 			.valid_group = VALID,
1266 			.ext_entry = 0
1267 		};
1268 
1269 		*owner_entry = new_tbl_entry;
1270 	} else {
1271 		struct rte_lpm6_tbl_entry new_tbl_entry = {
1272 			.next_hop = 0,
1273 			.depth = 0,
1274 			.valid = INVALID,
1275 			.valid_group = INVALID,
1276 			.ext_entry = 0
1277 		};
1278 
1279 		*owner_entry = new_tbl_entry;
1280 	}
1281 
1282 	/* return the table to the pool */
1283 	tbl8_put(lpm, tbl_ind);
1284 }
1285 
1286 /*
1287  * Deletes a rule
1288  */
1289 int
1290 rte_lpm6_delete(struct rte_lpm6 *lpm, const uint8_t *ip, uint8_t depth)
1291 {
1292 	uint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];
1293 	struct rte_lpm6_rule lsp_rule_obj;
1294 	struct rte_lpm6_rule *lsp_rule;
1295 	int ret;
1296 	uint32_t tbl_ind;
1297 	struct rte_lpm6_tbl_entry *from, *to;
1298 
1299 	/* Check input arguments. */
1300 	if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM6_MAX_DEPTH))
1301 		return -EINVAL;
1302 
1303 	/* Copy the IP and mask it to avoid modifying user's input data. */
1304 	ip6_copy_addr(masked_ip, ip);
1305 	ip6_mask_addr(masked_ip, depth);
1306 
1307 	/* Delete the rule from the rule table. */
1308 	ret = rule_delete(lpm, masked_ip, depth);
1309 	if (ret < 0)
1310 		return -ENOENT;
1311 
1312 	/* find rule cells */
1313 	rule_find_range(lpm, masked_ip, depth, &from, &to, &tbl_ind);
1314 
1315 	/* find a less specific rule (a rule with smaller depth)
1316 	 * note: masked_ip will be modified, don't use it anymore
1317 	 */
1318 	ret = rule_find_less_specific(lpm, masked_ip, depth,
1319 			&lsp_rule_obj);
1320 	lsp_rule = ret ? &lsp_rule_obj : NULL;
1321 
1322 	/* decrement the table rule counter,
1323 	 * note that tbl24 doesn't have a header
1324 	 */
1325 	if (tbl_ind != TBL24_IND) {
1326 		struct rte_lpm_tbl8_hdr *tbl_hdr = &lpm->tbl8_hdrs[tbl_ind];
1327 		if (--tbl_hdr->ref_cnt == 0) {
1328 			/* remove the table */
1329 			remove_tbl(lpm, tbl_hdr, tbl_ind, lsp_rule);
1330 			return 0;
1331 		}
1332 	}
1333 
1334 	/* iterate rule cells */
1335 	for (; from <= to; from++)
1336 		if (from->ext_entry == 1) {
1337 			/* reference to a more specific space
1338 			 * of the prefix/rule. Entries in a more
1339 			 * specific space that are not used by
1340 			 * a more specific prefix must be occupied
1341 			 * by the prefix
1342 			 */
1343 			if (lsp_rule != NULL)
1344 				expand_rule(lpm,
1345 					from->lpm6_tbl8_gindex *
1346 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES,
1347 					depth, lsp_rule->depth,
1348 					lsp_rule->next_hop, VALID);
1349 			else
1350 				/* since the prefix has no less specific prefix,
1351 				 * its more specific space must be invalidated
1352 				 */
1353 				expand_rule(lpm,
1354 					from->lpm6_tbl8_gindex *
1355 					RTE_LPM6_TBL8_GROUP_NUM_ENTRIES,
1356 					depth, 0, 0, INVALID);
1357 		} else if (from->depth == depth) {
1358 			/* entry is not a reference and belongs to the prefix */
1359 			if (lsp_rule != NULL) {
1360 				struct rte_lpm6_tbl_entry new_tbl_entry = {
1361 					.next_hop = lsp_rule->next_hop,
1362 					.depth = lsp_rule->depth,
1363 					.valid = VALID,
1364 					.valid_group = VALID,
1365 					.ext_entry = 0
1366 				};
1367 
1368 				*from = new_tbl_entry;
1369 			} else {
1370 				struct rte_lpm6_tbl_entry new_tbl_entry = {
1371 					.next_hop = 0,
1372 					.depth = 0,
1373 					.valid = INVALID,
1374 					.valid_group = INVALID,
1375 					.ext_entry = 0
1376 				};
1377 
1378 				*from = new_tbl_entry;
1379 			}
1380 		}
1381 
1382 	return 0;
1383 }
1384