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