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