4c44cd754192bb7764ae1a61d54df67572bc0b6c
[dpdk.git] / lib / librte_lpm / rte_lpm6.c
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 #include <string.h>
34 #include <stdint.h>
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <errno.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>
45 #include <rte_malloc.h>
46 #include <rte_memzone.h>
47 #include <rte_memcpy.h>
48 #include <rte_eal.h>
49 #include <rte_eal_memconfig.h>
50 #include <rte_per_lcore.h>
51 #include <rte_string_fns.h>
52 #include <rte_errno.h>
53 #include <rte_rwlock.h>
54 #include <rte_spinlock.h>
55
56 #include "rte_lpm6.h"
57
58 #define RTE_LPM6_TBL24_NUM_ENTRIES        (1 << 24)
59 #define RTE_LPM6_TBL8_GROUP_NUM_ENTRIES         256
60 #define RTE_LPM6_TBL8_MAX_NUM_GROUPS      (1 << 21)
61
62 #define RTE_LPM6_VALID_EXT_ENTRY_BITMASK 0xA0000000
63 #define RTE_LPM6_LOOKUP_SUCCESS          0x20000000
64 #define RTE_LPM6_TBL8_BITMASK            0x001FFFFF
65
66 #define ADD_FIRST_BYTE                            3
67 #define LOOKUP_FIRST_BYTE                         4
68 #define BYTE_SIZE                                 8
69 #define BYTES2_SIZE                              16
70
71 #define lpm6_tbl8_gindex next_hop
72
73 /** Flags for setting an entry as valid/invalid. */
74 enum valid_flag {
75         INVALID = 0,
76         VALID
77 };
78
79 TAILQ_HEAD(rte_lpm6_list, rte_tailq_entry);
80
81 static struct rte_tailq_elem rte_lpm6_tailq = {
82         .name = "RTE_LPM6",
83 };
84 EAL_REGISTER_TAILQ(rte_lpm6_tailq)
85
86 /** Tbl entry structure. It is the same for both tbl24 and tbl8 */
87 struct rte_lpm6_tbl_entry {
88         uint32_t next_hop:      21;  /**< Next hop / next table to be checked. */
89         uint32_t depth  :8;      /**< Rule depth. */
90
91         /* Flags. */
92         uint32_t valid     :1;   /**< Validation flag. */
93         uint32_t valid_group :1; /**< Group validation flag. */
94         uint32_t ext_entry :1;   /**< External entry. */
95 };
96
97 /** Rules tbl entry structure. */
98 struct rte_lpm6_rule {
99         uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE]; /**< Rule IP address. */
100         uint8_t next_hop; /**< Rule next hop. */
101         uint8_t depth; /**< Rule depth. */
102 };
103
104 /** LPM6 structure. */
105 struct rte_lpm6 {
106         /* LPM metadata. */
107         char name[RTE_LPM6_NAMESIZE];    /**< Name of the lpm. */
108         uint32_t max_rules;              /**< Max number of rules. */
109         uint32_t used_rules;             /**< Used rules so far. */
110         uint32_t number_tbl8s;           /**< Number of tbl8s to allocate. */
111         uint32_t next_tbl8;              /**< Next tbl8 to be used. */
112
113         /* LPM Tables. */
114         struct rte_lpm6_rule *rules_tbl; /**< LPM rules. */
115         struct rte_lpm6_tbl_entry tbl24[RTE_LPM6_TBL24_NUM_ENTRIES]
116                         __rte_cache_aligned; /**< LPM tbl24 table. */
117         struct rte_lpm6_tbl_entry tbl8[0]
118                         __rte_cache_aligned; /**< LPM tbl8 table. */
119 };
120
121 /*
122  * Takes an array of uint8_t (IPv6 address) and masks it using the depth.
123  * It leaves untouched one bit per unit in the depth variable
124  * and set the rest to 0.
125  */
126 static inline void
127 mask_ip(uint8_t *ip, uint8_t depth)
128 {
129         int16_t part_depth, mask;
130         int i;
131
132                 part_depth = depth;
133
134                 for (i = 0; i < RTE_LPM6_IPV6_ADDR_SIZE; i++) {
135                         if (part_depth < BYTE_SIZE && part_depth >= 0) {
136                                 mask = (uint16_t)(~(UINT8_MAX >> part_depth));
137                                 ip[i] = (uint8_t)(ip[i] & mask);
138                         } else if (part_depth < 0) {
139                                 ip[i] = 0;
140                         }
141                         part_depth -= BYTE_SIZE;
142                 }
143 }
144
145 /*
146  * Allocates memory for LPM object
147  */
148 struct rte_lpm6 *
149 rte_lpm6_create(const char *name, int socket_id,
150                 const struct rte_lpm6_config *config)
151 {
152         char mem_name[RTE_LPM6_NAMESIZE];
153         struct rte_lpm6 *lpm = NULL;
154         struct rte_tailq_entry *te;
155         uint64_t mem_size, rules_size;
156         struct rte_lpm6_list *lpm_list;
157
158         lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
159
160         RTE_BUILD_BUG_ON(sizeof(struct rte_lpm6_tbl_entry) != sizeof(uint32_t));
161
162         /* Check user arguments. */
163         if ((name == NULL) || (socket_id < -1) || (config == NULL) ||
164                         (config->max_rules == 0) ||
165                         config->number_tbl8s > RTE_LPM6_TBL8_MAX_NUM_GROUPS) {
166                 rte_errno = EINVAL;
167                 return NULL;
168         }
169
170         snprintf(mem_name, sizeof(mem_name), "LPM_%s", name);
171
172         /* Determine the amount of memory to allocate. */
173         mem_size = sizeof(*lpm) + (sizeof(lpm->tbl8[0]) *
174                         RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * config->number_tbl8s);
175         rules_size = sizeof(struct rte_lpm6_rule) * config->max_rules;
176
177         rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
178
179         /* Guarantee there's no existing */
180         TAILQ_FOREACH(te, lpm_list, next) {
181                 lpm = (struct rte_lpm6 *) te->data;
182                 if (strncmp(name, lpm->name, RTE_LPM6_NAMESIZE) == 0)
183                         break;
184         }
185         if (te != NULL)
186                 goto exit;
187
188         /* allocate tailq entry */
189         te = rte_zmalloc("LPM6_TAILQ_ENTRY", sizeof(*te), 0);
190         if (te == NULL) {
191                 RTE_LOG(ERR, LPM, "Failed to allocate tailq entry!\n");
192                 goto exit;
193         }
194
195         /* Allocate memory to store the LPM data structures. */
196         lpm = (struct rte_lpm6 *)rte_zmalloc_socket(mem_name, (size_t)mem_size,
197                         RTE_CACHE_LINE_SIZE, socket_id);
198
199         if (lpm == NULL) {
200                 RTE_LOG(ERR, LPM, "LPM memory allocation failed\n");
201                 rte_free(te);
202                 goto exit;
203         }
204
205         lpm->rules_tbl = (struct rte_lpm6_rule *)rte_zmalloc_socket(NULL,
206                         (size_t)rules_size, RTE_CACHE_LINE_SIZE, socket_id);
207
208         if (lpm->rules_tbl == NULL) {
209                 RTE_LOG(ERR, LPM, "LPM rules_tbl allocation failed\n");
210                 rte_free(lpm);
211                 lpm = NULL;
212                 rte_free(te);
213                 goto exit;
214         }
215
216         /* Save user arguments. */
217         lpm->max_rules = config->max_rules;
218         lpm->number_tbl8s = config->number_tbl8s;
219         snprintf(lpm->name, sizeof(lpm->name), "%s", name);
220
221         te->data = (void *) lpm;
222
223         TAILQ_INSERT_TAIL(lpm_list, te, next);
224
225 exit:
226         rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
227
228         return lpm;
229 }
230
231 /*
232  * Find an existing lpm table and return a pointer to it.
233  */
234 struct rte_lpm6 *
235 rte_lpm6_find_existing(const char *name)
236 {
237         struct rte_lpm6 *l = NULL;
238         struct rte_tailq_entry *te;
239         struct rte_lpm6_list *lpm_list;
240
241         lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
242
243         rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
244         TAILQ_FOREACH(te, lpm_list, next) {
245                 l = (struct rte_lpm6 *) te->data;
246                 if (strncmp(name, l->name, RTE_LPM6_NAMESIZE) == 0)
247                         break;
248         }
249         rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
250
251         if (te == NULL) {
252                 rte_errno = ENOENT;
253                 return NULL;
254         }
255
256         return l;
257 }
258
259 /*
260  * Deallocates memory for given LPM table.
261  */
262 void
263 rte_lpm6_free(struct rte_lpm6 *lpm)
264 {
265         struct rte_lpm6_list *lpm_list;
266         struct rte_tailq_entry *te;
267
268         /* Check user arguments. */
269         if (lpm == NULL)
270                 return;
271
272         lpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);
273
274         rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
275
276         /* find our tailq entry */
277         TAILQ_FOREACH(te, lpm_list, next) {
278                 if (te->data == (void *) lpm)
279                         break;
280         }
281
282         if (te != NULL)
283                 TAILQ_REMOVE(lpm_list, te, next);
284
285         rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
286
287         rte_free(lpm->rules_tbl);
288         rte_free(lpm);
289         rte_free(te);
290 }
291
292 /*
293  * Checks if a rule already exists in the rules table and updates
294  * the nexthop if so. Otherwise it adds a new rule if enough space is available.
295  */
296 static inline int32_t
297 rule_add(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t next_hop, uint8_t depth)
298 {
299         uint32_t rule_index;
300
301         /* Scan through rule list to see if rule already exists. */
302         for (rule_index = 0; rule_index < lpm->used_rules; rule_index++) {
303
304                 /* If rule already exists update its next_hop and return. */
305                 if ((memcmp (lpm->rules_tbl[rule_index].ip, ip,
306                                 RTE_LPM6_IPV6_ADDR_SIZE) == 0) &&
307                                 lpm->rules_tbl[rule_index].depth == depth) {
308                         lpm->rules_tbl[rule_index].next_hop = next_hop;
309
310                         return rule_index;
311                 }
312         }
313
314         /*
315          * If rule does not exist check if there is space to add a new rule to
316          * this rule group. If there is no space return error.
317          */
318         if (lpm->used_rules == lpm->max_rules) {
319                 return -ENOSPC;
320         }
321
322         /* If there is space for the new rule add it. */
323         rte_memcpy(lpm->rules_tbl[rule_index].ip, ip, RTE_LPM6_IPV6_ADDR_SIZE);
324         lpm->rules_tbl[rule_index].next_hop = next_hop;
325         lpm->rules_tbl[rule_index].depth = depth;
326
327         /* Increment the used rules counter for this rule group. */
328         lpm->used_rules++;
329
330         return rule_index;
331 }
332
333 /*
334  * Function that expands a rule across the data structure when a less-generic
335  * one has been added before. It assures that every possible combination of bits
336  * in the IP address returns a match.
337  */
338 static void
339 expand_rule(struct rte_lpm6 *lpm, uint32_t tbl8_gindex, uint8_t depth,
340                 uint8_t next_hop)
341 {
342         uint32_t tbl8_group_end, tbl8_gindex_next, j;
343
344         tbl8_group_end = tbl8_gindex + RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
345
346         struct rte_lpm6_tbl_entry new_tbl8_entry = {
347                 .valid = VALID,
348                 .valid_group = VALID,
349                 .depth = depth,
350                 .next_hop = next_hop,
351                 .ext_entry = 0,
352         };
353
354         for (j = tbl8_gindex; j < tbl8_group_end; j++) {
355                 if (!lpm->tbl8[j].valid || (lpm->tbl8[j].ext_entry == 0
356                                 && lpm->tbl8[j].depth <= depth)) {
357
358                         lpm->tbl8[j] = new_tbl8_entry;
359
360                 } else if (lpm->tbl8[j].ext_entry == 1) {
361
362                         tbl8_gindex_next = lpm->tbl8[j].lpm6_tbl8_gindex
363                                         * RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
364                         expand_rule(lpm, tbl8_gindex_next, depth, next_hop);
365                 }
366         }
367 }
368
369 /*
370  * Partially adds a new route to the data structure (tbl24+tbl8s).
371  * It returns 0 on success, a negative number on failure, or 1 if
372  * the process needs to be continued by calling the function again.
373  */
374 static inline int
375 add_step(struct rte_lpm6 *lpm, struct rte_lpm6_tbl_entry *tbl,
376                 struct rte_lpm6_tbl_entry **tbl_next, uint8_t *ip, uint8_t bytes,
377                 uint8_t first_byte, uint8_t depth, uint8_t next_hop)
378 {
379         uint32_t tbl_index, tbl_range, tbl8_group_start, tbl8_group_end, i;
380         int32_t tbl8_gindex;
381         int8_t bitshift;
382         uint8_t bits_covered;
383
384         /*
385          * Calculate index to the table based on the number and position
386          * of the bytes being inspected in this step.
387          */
388         tbl_index = 0;
389         for (i = first_byte; i < (uint32_t)(first_byte + bytes); i++) {
390                 bitshift = (int8_t)((bytes - i)*BYTE_SIZE);
391
392                 if (bitshift < 0) bitshift = 0;
393                 tbl_index = tbl_index | ip[i-1] << bitshift;
394         }
395
396         /* Number of bits covered in this step */
397         bits_covered = (uint8_t)((bytes+first_byte-1)*BYTE_SIZE);
398
399         /*
400          * If depth if smaller than this number (ie this is the last step)
401          * expand the rule across the relevant positions in the table.
402          */
403         if (depth <= bits_covered) {
404                 tbl_range = 1 << (bits_covered - depth);
405
406                 for (i = tbl_index; i < (tbl_index + tbl_range); i++) {
407                         if (!tbl[i].valid || (tbl[i].ext_entry == 0 &&
408                                         tbl[i].depth <= depth)) {
409
410                                 struct rte_lpm6_tbl_entry new_tbl_entry = {
411                                         .next_hop = next_hop,
412                                         .depth = depth,
413                                         .valid = VALID,
414                                         .valid_group = VALID,
415                                         .ext_entry = 0,
416                                 };
417
418                                 tbl[i] = new_tbl_entry;
419
420                         } else if (tbl[i].ext_entry == 1) {
421
422                                 /*
423                                  * If tbl entry is valid and extended calculate the index
424                                  * into next tbl8 and expand the rule across the data structure.
425                                  */
426                                 tbl8_gindex = tbl[i].lpm6_tbl8_gindex *
427                                                 RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
428                                 expand_rule(lpm, tbl8_gindex, depth, next_hop);
429                         }
430                 }
431
432                 return 0;
433         }
434         /*
435          * If this is not the last step just fill one position
436          * and calculate the index to the next table.
437          */
438         else {
439                 /* If it's invalid a new tbl8 is needed */
440                 if (!tbl[tbl_index].valid) {
441                         if (lpm->next_tbl8 < lpm->number_tbl8s)
442                                 tbl8_gindex = (lpm->next_tbl8)++;
443                         else
444                                 return -ENOSPC;
445
446                         struct rte_lpm6_tbl_entry new_tbl_entry = {
447                                 .lpm6_tbl8_gindex = tbl8_gindex,
448                                 .depth = 0,
449                                 .valid = VALID,
450                                 .valid_group = VALID,
451                                 .ext_entry = 1,
452                         };
453
454                         tbl[tbl_index] = new_tbl_entry;
455                 }
456                 /*
457                  * If it's valid but not extended the rule that was stored *
458                  * here needs to be moved to the next table.
459                  */
460                 else if (tbl[tbl_index].ext_entry == 0) {
461                         /* Search for free tbl8 group. */
462                         if (lpm->next_tbl8 < lpm->number_tbl8s)
463                                 tbl8_gindex = (lpm->next_tbl8)++;
464                         else
465                                 return -ENOSPC;
466
467                         tbl8_group_start = tbl8_gindex *
468                                         RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
469                         tbl8_group_end = tbl8_group_start +
470                                         RTE_LPM6_TBL8_GROUP_NUM_ENTRIES;
471
472                         /* Populate new tbl8 with tbl value. */
473                         for (i = tbl8_group_start; i < tbl8_group_end; i++) {
474                                 lpm->tbl8[i].valid = VALID;
475                                 lpm->tbl8[i].depth = tbl[tbl_index].depth;
476                                 lpm->tbl8[i].next_hop = tbl[tbl_index].next_hop;
477                                 lpm->tbl8[i].ext_entry = 0;
478                         }
479
480                         /*
481                          * Update tbl entry to point to new tbl8 entry. Note: The
482                          * ext_flag and tbl8_index need to be updated simultaneously,
483                          * so assign whole structure in one go.
484                          */
485                         struct rte_lpm6_tbl_entry new_tbl_entry = {
486                                 .lpm6_tbl8_gindex = tbl8_gindex,
487                                 .depth = 0,
488                                 .valid = VALID,
489                                 .valid_group = VALID,
490                                 .ext_entry = 1,
491                         };
492
493                         tbl[tbl_index] = new_tbl_entry;
494                 }
495
496                 *tbl_next = &(lpm->tbl8[tbl[tbl_index].lpm6_tbl8_gindex *
497                                 RTE_LPM6_TBL8_GROUP_NUM_ENTRIES]);
498         }
499
500         return 1;
501 }
502
503 /*
504  * Add a route
505  */
506 int
507 rte_lpm6_add(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,
508                 uint8_t next_hop)
509 {
510         struct rte_lpm6_tbl_entry *tbl;
511         struct rte_lpm6_tbl_entry *tbl_next;
512         int32_t rule_index;
513         int status;
514         uint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];
515         int i;
516
517         /* Check user arguments. */
518         if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM6_MAX_DEPTH))
519                 return -EINVAL;
520
521         /* Copy the IP and mask it to avoid modifying user's input data. */
522         memcpy(masked_ip, ip, RTE_LPM6_IPV6_ADDR_SIZE);
523         mask_ip(masked_ip, depth);
524
525         /* Add the rule to the rule table. */
526         rule_index = rule_add(lpm, masked_ip, next_hop, depth);
527
528         /* If there is no space available for new rule return error. */
529         if (rule_index < 0) {
530                 return rule_index;
531         }
532
533         /* Inspect the first three bytes through tbl24 on the first step. */
534         tbl = lpm->tbl24;
535         status = add_step (lpm, tbl, &tbl_next, masked_ip, ADD_FIRST_BYTE, 1,
536                         depth, next_hop);
537         if (status < 0) {
538                 rte_lpm6_delete(lpm, masked_ip, depth);
539
540                 return status;
541         }
542
543         /*
544          * Inspect one by one the rest of the bytes until
545          * the process is completed.
546          */
547         for (i = ADD_FIRST_BYTE; i < RTE_LPM6_IPV6_ADDR_SIZE && status == 1; i++) {
548                 tbl = tbl_next;
549                 status = add_step (lpm, tbl, &tbl_next, masked_ip, 1, (uint8_t)(i+1),
550                                 depth, next_hop);
551                 if (status < 0) {
552                         rte_lpm6_delete(lpm, masked_ip, depth);
553
554                         return status;
555                 }
556         }
557
558         return status;
559 }
560
561 /*
562  * Takes a pointer to a table entry and inspect one level.
563  * The function returns 0 on lookup success, ENOENT if no match was found
564  * or 1 if the process needs to be continued by calling the function again.
565  */
566 static inline int
567 lookup_step(const struct rte_lpm6 *lpm, const struct rte_lpm6_tbl_entry *tbl,
568                 const struct rte_lpm6_tbl_entry **tbl_next, uint8_t *ip,
569                 uint8_t first_byte, uint8_t *next_hop)
570 {
571         uint32_t tbl8_index, tbl_entry;
572
573         /* Take the integer value from the pointer. */
574         tbl_entry = *(const uint32_t *)tbl;
575
576         /* If it is valid and extended we calculate the new pointer to return. */
577         if ((tbl_entry & RTE_LPM6_VALID_EXT_ENTRY_BITMASK) ==
578                         RTE_LPM6_VALID_EXT_ENTRY_BITMASK) {
579
580                 tbl8_index = ip[first_byte-1] +
581                                 ((tbl_entry & RTE_LPM6_TBL8_BITMASK) *
582                                 RTE_LPM6_TBL8_GROUP_NUM_ENTRIES);
583
584                 *tbl_next = &lpm->tbl8[tbl8_index];
585
586                 return 1;
587         } else {
588                 /* If not extended then we can have a match. */
589                 *next_hop = (uint8_t)tbl_entry;
590                 return (tbl_entry & RTE_LPM6_LOOKUP_SUCCESS) ? 0 : -ENOENT;
591         }
592 }
593
594 /*
595  * Looks up an IP
596  */
597 int
598 rte_lpm6_lookup(const struct rte_lpm6 *lpm, uint8_t *ip, uint8_t *next_hop)
599 {
600         const struct rte_lpm6_tbl_entry *tbl;
601         const struct rte_lpm6_tbl_entry *tbl_next;
602         int status;
603         uint8_t first_byte;
604         uint32_t tbl24_index;
605
606         /* DEBUG: Check user input arguments. */
607         if ((lpm == NULL) || (ip == NULL) || (next_hop == NULL)) {
608                 return -EINVAL;
609         }
610
611         first_byte = LOOKUP_FIRST_BYTE;
612         tbl24_index = (ip[0] << BYTES2_SIZE) | (ip[1] << BYTE_SIZE) | ip[2];
613
614         /* Calculate pointer to the first entry to be inspected */
615         tbl = &lpm->tbl24[tbl24_index];
616
617         do {
618                 /* Continue inspecting following levels until success or failure */
619                 status = lookup_step(lpm, tbl, &tbl_next, ip, first_byte++, next_hop);
620                 tbl = tbl_next;
621         } while (status == 1);
622
623         return status;
624 }
625
626 /*
627  * Looks up a group of IP addresses
628  */
629 int
630 rte_lpm6_lookup_bulk_func(const struct rte_lpm6 *lpm,
631                 uint8_t ips[][RTE_LPM6_IPV6_ADDR_SIZE],
632                 int16_t * next_hops, unsigned n)
633 {
634         unsigned i;
635         const struct rte_lpm6_tbl_entry *tbl;
636         const struct rte_lpm6_tbl_entry *tbl_next;
637         uint32_t tbl24_index;
638         uint8_t first_byte, next_hop;
639         int status;
640
641         /* DEBUG: Check user input arguments. */
642         if ((lpm == NULL) || (ips == NULL) || (next_hops == NULL)) {
643                 return -EINVAL;
644         }
645
646         for (i = 0; i < n; i++) {
647                 first_byte = LOOKUP_FIRST_BYTE;
648                 tbl24_index = (ips[i][0] << BYTES2_SIZE) |
649                                 (ips[i][1] << BYTE_SIZE) | ips[i][2];
650
651                 /* Calculate pointer to the first entry to be inspected */
652                 tbl = &lpm->tbl24[tbl24_index];
653
654                 do {
655                         /* Continue inspecting following levels until success or failure */
656                         status = lookup_step(lpm, tbl, &tbl_next, ips[i], first_byte++,
657                                         &next_hop);
658                         tbl = tbl_next;
659                 } while (status == 1);
660
661                 if (status < 0)
662                         next_hops[i] = -1;
663                 else
664                         next_hops[i] = next_hop;
665         }
666
667         return 0;
668 }
669
670 /*
671  * Finds a rule in rule table.
672  * NOTE: Valid range for depth parameter is 1 .. 128 inclusive.
673  */
674 static inline int32_t
675 rule_find(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)
676 {
677         uint32_t rule_index;
678
679         /* Scan used rules at given depth to find rule. */
680         for (rule_index = 0; rule_index < lpm->used_rules; rule_index++) {
681                 /* If rule is found return the rule index. */
682                 if ((memcmp (lpm->rules_tbl[rule_index].ip, ip,
683                                 RTE_LPM6_IPV6_ADDR_SIZE) == 0) &&
684                                 lpm->rules_tbl[rule_index].depth == depth) {
685
686                         return rule_index;
687                 }
688         }
689
690         /* If rule is not found return -ENOENT. */
691         return -ENOENT;
692 }
693
694 /*
695  * Look for a rule in the high-level rules table
696  */
697 int
698 rte_lpm6_is_rule_present(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,
699 uint8_t *next_hop)
700 {
701         uint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];
702         int32_t rule_index;
703
704         /* Check user arguments. */
705         if ((lpm == NULL) || next_hop == NULL || ip == NULL ||
706                         (depth < 1) || (depth > RTE_LPM6_MAX_DEPTH))
707                 return -EINVAL;
708
709         /* Copy the IP and mask it to avoid modifying user's input data. */
710         memcpy(ip_masked, ip, RTE_LPM6_IPV6_ADDR_SIZE);
711         mask_ip(ip_masked, depth);
712
713         /* Look for the rule using rule_find. */
714         rule_index = rule_find(lpm, ip_masked, depth);
715
716         if (rule_index >= 0) {
717                 *next_hop = lpm->rules_tbl[rule_index].next_hop;
718                 return 1;
719         }
720
721         /* If rule is not found return 0. */
722         return 0;
723 }
724
725 /*
726  * Delete a rule from the rule table.
727  * NOTE: Valid range for depth parameter is 1 .. 128 inclusive.
728  */
729 static inline void
730 rule_delete(struct rte_lpm6 *lpm, int32_t rule_index)
731 {
732         /*
733          * Overwrite redundant rule with last rule in group and decrement rule
734          * counter.
735          */
736         lpm->rules_tbl[rule_index] = lpm->rules_tbl[lpm->used_rules-1];
737         lpm->used_rules--;
738 }
739
740 /*
741  * Deletes a rule
742  */
743 int
744 rte_lpm6_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)
745 {
746         int32_t rule_to_delete_index;
747         uint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];
748         unsigned i;
749
750         /*
751          * Check input arguments.
752          */
753         if ((lpm == NULL) || (depth < 1) || (depth > RTE_LPM6_MAX_DEPTH)) {
754                 return -EINVAL;
755         }
756
757         /* Copy the IP and mask it to avoid modifying user's input data. */
758         memcpy(ip_masked, ip, RTE_LPM6_IPV6_ADDR_SIZE);
759         mask_ip(ip_masked, depth);
760
761         /*
762          * Find the index of the input rule, that needs to be deleted, in the
763          * rule table.
764          */
765         rule_to_delete_index = rule_find(lpm, ip_masked, depth);
766
767         /*
768          * Check if rule_to_delete_index was found. If no rule was found the
769          * function rule_find returns -ENOENT.
770          */
771         if (rule_to_delete_index < 0)
772                 return rule_to_delete_index;
773
774         /* Delete the rule from the rule table. */
775         rule_delete(lpm, rule_to_delete_index);
776
777         /*
778          * Set all the table entries to 0 (ie delete every rule
779          * from the data structure.
780          */
781         lpm->next_tbl8 = 0;
782         memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
783         memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0])
784                         * RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
785
786         /*
787          * Add every rule again (except for the one that was removed from
788          * the rules table).
789          */
790         for (i = 0; i < lpm->used_rules; i++) {
791                 rte_lpm6_add(lpm, lpm->rules_tbl[i].ip, lpm->rules_tbl[i].depth,
792                                 lpm->rules_tbl[i].next_hop);
793         }
794
795         return 0;
796 }
797
798 /*
799  * Deletes a group of rules
800  */
801 int
802 rte_lpm6_delete_bulk_func(struct rte_lpm6 *lpm,
803                 uint8_t ips[][RTE_LPM6_IPV6_ADDR_SIZE], uint8_t *depths, unsigned n)
804 {
805         int32_t rule_to_delete_index;
806         uint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];
807         unsigned i;
808
809         /*
810          * Check input arguments.
811          */
812         if ((lpm == NULL) || (ips == NULL) || (depths == NULL)) {
813                 return -EINVAL;
814         }
815
816         for (i = 0; i < n; i++) {
817                 /* Copy the IP and mask it to avoid modifying user's input data. */
818                 memcpy(ip_masked, ips[i], RTE_LPM6_IPV6_ADDR_SIZE);
819                 mask_ip(ip_masked, depths[i]);
820
821                 /*
822                  * Find the index of the input rule, that needs to be deleted, in the
823                  * rule table.
824                  */
825                 rule_to_delete_index = rule_find(lpm, ip_masked, depths[i]);
826
827                 /*
828                  * Check if rule_to_delete_index was found. If no rule was found the
829                  * function rule_find returns -ENOENT.
830                  */
831                 if (rule_to_delete_index < 0)
832                         continue;
833
834                 /* Delete the rule from the rule table. */
835                 rule_delete(lpm, rule_to_delete_index);
836         }
837
838         /*
839          * Set all the table entries to 0 (ie delete every rule
840          * from the data structure.
841          */
842         lpm->next_tbl8 = 0;
843         memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
844         memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0])
845                         * RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
846
847         /*
848          * Add every rule again (except for the ones that were removed from
849          * the rules table).
850          */
851         for (i = 0; i < lpm->used_rules; i++) {
852                 rte_lpm6_add(lpm, lpm->rules_tbl[i].ip, lpm->rules_tbl[i].depth,
853                                 lpm->rules_tbl[i].next_hop);
854         }
855
856         return 0;
857 }
858
859 /*
860  * Delete all rules from the LPM table.
861  */
862 void
863 rte_lpm6_delete_all(struct rte_lpm6 *lpm)
864 {
865         /* Zero used rules counter. */
866         lpm->used_rules = 0;
867
868         /* Zero next tbl8 index. */
869         lpm->next_tbl8 = 0;
870
871         /* Zero tbl24. */
872         memset(lpm->tbl24, 0, sizeof(lpm->tbl24));
873
874         /* Zero tbl8. */
875         memset(lpm->tbl8, 0, sizeof(lpm->tbl8[0]) *
876                         RTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);
877
878         /* Delete all rules form the rules table. */
879         memset(lpm->rules_tbl, 0, sizeof(struct rte_lpm6_rule) * lpm->max_rules);
880 }