199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com> 399a2dd95SBruce Richardson * Copyright(c) 2019 Intel Corporation 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <stdint.h> 799a2dd95SBruce Richardson #include <string.h> 8233b41c2SStephen Hemminger #include <sys/queue.h> 999a2dd95SBruce Richardson 1099a2dd95SBruce Richardson #include <rte_eal_memconfig.h> 1199a2dd95SBruce Richardson #include <rte_tailq.h> 1299a2dd95SBruce Richardson #include <rte_errno.h> 13fdb83ffbSStephen Hemminger #include <rte_log.h> 1499a2dd95SBruce Richardson #include <rte_malloc.h> 1599a2dd95SBruce Richardson #include <rte_string_fns.h> 1699a2dd95SBruce Richardson 176cb10a9bSRobin Jarry #include <rte_ip6.h> 1899a2dd95SBruce Richardson #include <rte_rib6.h> 1999a2dd95SBruce Richardson #include <rte_fib6.h> 2099a2dd95SBruce Richardson 2199a2dd95SBruce Richardson #include "trie.h" 22fdb83ffbSStephen Hemminger #include "fib_log.h" 2399a2dd95SBruce Richardson 2499a2dd95SBruce Richardson TAILQ_HEAD(rte_fib6_list, rte_tailq_entry); 2599a2dd95SBruce Richardson static struct rte_tailq_elem rte_fib6_tailq = { 2699a2dd95SBruce Richardson .name = "RTE_FIB6", 2799a2dd95SBruce Richardson }; 2899a2dd95SBruce Richardson EAL_REGISTER_TAILQ(rte_fib6_tailq) 2999a2dd95SBruce Richardson 3099a2dd95SBruce Richardson /* Maximum length of a FIB name. */ 3199a2dd95SBruce Richardson #define FIB6_NAMESIZE 64 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson #if defined(RTE_LIBRTE_FIB_DEBUG) 3499a2dd95SBruce Richardson #define FIB6_RETURN_IF_TRUE(cond, retval) do { \ 3599a2dd95SBruce Richardson if (cond) \ 3699a2dd95SBruce Richardson return retval; \ 3799a2dd95SBruce Richardson } while (0) 3899a2dd95SBruce Richardson #else 3999a2dd95SBruce Richardson #define FIB6_RETURN_IF_TRUE(cond, retval) 4099a2dd95SBruce Richardson #endif 4199a2dd95SBruce Richardson 4299a2dd95SBruce Richardson struct rte_fib6 { 4399a2dd95SBruce Richardson char name[FIB6_NAMESIZE]; 4499a2dd95SBruce Richardson enum rte_fib6_type type; /**< Type of FIB struct */ 457be78d02SJosh Soref struct rte_rib6 *rib; /**< RIB helper datastructure */ 4699a2dd95SBruce Richardson void *dp; /**< pointer to the dataplane struct*/ 477be78d02SJosh Soref rte_fib6_lookup_fn_t lookup; /**< FIB lookup function */ 487be78d02SJosh Soref rte_fib6_modify_fn_t modify; /**< modify FIB datastructure */ 4999a2dd95SBruce Richardson uint64_t def_nh; 5099a2dd95SBruce Richardson }; 5199a2dd95SBruce Richardson 5299a2dd95SBruce Richardson static void 536cb10a9bSRobin Jarry dummy_lookup(void *fib_p, const struct rte_ipv6_addr *ips, 5499a2dd95SBruce Richardson uint64_t *next_hops, const unsigned int n) 5599a2dd95SBruce Richardson { 5699a2dd95SBruce Richardson unsigned int i; 5799a2dd95SBruce Richardson struct rte_fib6 *fib = fib_p; 5899a2dd95SBruce Richardson struct rte_rib6_node *node; 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson for (i = 0; i < n; i++) { 61*59b99315SRobin Jarry node = rte_rib6_lookup(fib->rib, &ips[i]); 6299a2dd95SBruce Richardson if (node != NULL) 6399a2dd95SBruce Richardson rte_rib6_get_nh(node, &next_hops[i]); 6499a2dd95SBruce Richardson else 6599a2dd95SBruce Richardson next_hops[i] = fib->def_nh; 6699a2dd95SBruce Richardson } 6799a2dd95SBruce Richardson } 6899a2dd95SBruce Richardson 6999a2dd95SBruce Richardson static int 706cb10a9bSRobin Jarry dummy_modify(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, 7199a2dd95SBruce Richardson uint8_t depth, uint64_t next_hop, int op) 7299a2dd95SBruce Richardson { 7399a2dd95SBruce Richardson struct rte_rib6_node *node; 746cb10a9bSRobin Jarry if ((fib == NULL) || (depth > RTE_IPV6_MAX_DEPTH)) 7599a2dd95SBruce Richardson return -EINVAL; 7699a2dd95SBruce Richardson 77*59b99315SRobin Jarry node = rte_rib6_lookup_exact(fib->rib, ip, depth); 7899a2dd95SBruce Richardson 7999a2dd95SBruce Richardson switch (op) { 8099a2dd95SBruce Richardson case RTE_FIB6_ADD: 8199a2dd95SBruce Richardson if (node == NULL) 82*59b99315SRobin Jarry node = rte_rib6_insert(fib->rib, ip, depth); 8399a2dd95SBruce Richardson if (node == NULL) 8499a2dd95SBruce Richardson return -rte_errno; 8599a2dd95SBruce Richardson return rte_rib6_set_nh(node, next_hop); 8699a2dd95SBruce Richardson case RTE_FIB6_DEL: 8799a2dd95SBruce Richardson if (node == NULL) 8899a2dd95SBruce Richardson return -ENOENT; 89*59b99315SRobin Jarry rte_rib6_remove(fib->rib, ip, depth); 9099a2dd95SBruce Richardson return 0; 9199a2dd95SBruce Richardson } 9299a2dd95SBruce Richardson return -EINVAL; 9399a2dd95SBruce Richardson } 9499a2dd95SBruce Richardson 9599a2dd95SBruce Richardson static int 9699a2dd95SBruce Richardson init_dataplane(struct rte_fib6 *fib, __rte_unused int socket_id, 9799a2dd95SBruce Richardson struct rte_fib6_conf *conf) 9899a2dd95SBruce Richardson { 9999a2dd95SBruce Richardson char dp_name[sizeof(void *)]; 10099a2dd95SBruce Richardson 10199a2dd95SBruce Richardson snprintf(dp_name, sizeof(dp_name), "%p", fib); 10299a2dd95SBruce Richardson switch (conf->type) { 10399a2dd95SBruce Richardson case RTE_FIB6_DUMMY: 10499a2dd95SBruce Richardson fib->dp = fib; 10599a2dd95SBruce Richardson fib->lookup = dummy_lookup; 10699a2dd95SBruce Richardson fib->modify = dummy_modify; 10799a2dd95SBruce Richardson return 0; 10899a2dd95SBruce Richardson case RTE_FIB6_TRIE: 10999a2dd95SBruce Richardson fib->dp = trie_create(dp_name, socket_id, conf); 11099a2dd95SBruce Richardson if (fib->dp == NULL) 11199a2dd95SBruce Richardson return -rte_errno; 11299a2dd95SBruce Richardson fib->lookup = trie_get_lookup_fn(fib->dp, RTE_FIB6_LOOKUP_DEFAULT); 11399a2dd95SBruce Richardson fib->modify = trie_modify; 11499a2dd95SBruce Richardson return 0; 11599a2dd95SBruce Richardson default: 11699a2dd95SBruce Richardson return -EINVAL; 11799a2dd95SBruce Richardson } 11899a2dd95SBruce Richardson return 0; 11999a2dd95SBruce Richardson } 12099a2dd95SBruce Richardson 12199a2dd95SBruce Richardson int 1226cb10a9bSRobin Jarry rte_fib6_add(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, 12399a2dd95SBruce Richardson uint8_t depth, uint64_t next_hop) 12499a2dd95SBruce Richardson { 12599a2dd95SBruce Richardson if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) || 1266cb10a9bSRobin Jarry (depth > RTE_IPV6_MAX_DEPTH)) 12799a2dd95SBruce Richardson return -EINVAL; 12899a2dd95SBruce Richardson return fib->modify(fib, ip, depth, next_hop, RTE_FIB6_ADD); 12999a2dd95SBruce Richardson } 13099a2dd95SBruce Richardson 13199a2dd95SBruce Richardson int 1326cb10a9bSRobin Jarry rte_fib6_delete(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, 13399a2dd95SBruce Richardson uint8_t depth) 13499a2dd95SBruce Richardson { 13599a2dd95SBruce Richardson if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) || 1366cb10a9bSRobin Jarry (depth > RTE_IPV6_MAX_DEPTH)) 13799a2dd95SBruce Richardson return -EINVAL; 13899a2dd95SBruce Richardson return fib->modify(fib, ip, depth, 0, RTE_FIB6_DEL); 13999a2dd95SBruce Richardson } 14099a2dd95SBruce Richardson 14199a2dd95SBruce Richardson int 14299a2dd95SBruce Richardson rte_fib6_lookup_bulk(struct rte_fib6 *fib, 1436cb10a9bSRobin Jarry const struct rte_ipv6_addr *ips, 14499a2dd95SBruce Richardson uint64_t *next_hops, int n) 14599a2dd95SBruce Richardson { 14699a2dd95SBruce Richardson FIB6_RETURN_IF_TRUE((fib == NULL) || (ips == NULL) || 14799a2dd95SBruce Richardson (next_hops == NULL) || (fib->lookup == NULL), -EINVAL); 14899a2dd95SBruce Richardson fib->lookup(fib->dp, ips, next_hops, n); 14999a2dd95SBruce Richardson return 0; 15099a2dd95SBruce Richardson } 15199a2dd95SBruce Richardson 15299a2dd95SBruce Richardson struct rte_fib6 * 15399a2dd95SBruce Richardson rte_fib6_create(const char *name, int socket_id, struct rte_fib6_conf *conf) 15499a2dd95SBruce Richardson { 15599a2dd95SBruce Richardson char mem_name[FIB6_NAMESIZE]; 15699a2dd95SBruce Richardson int ret; 15799a2dd95SBruce Richardson struct rte_fib6 *fib = NULL; 15899a2dd95SBruce Richardson struct rte_rib6 *rib = NULL; 15999a2dd95SBruce Richardson struct rte_tailq_entry *te; 16099a2dd95SBruce Richardson struct rte_fib6_list *fib_list; 16199a2dd95SBruce Richardson struct rte_rib6_conf rib_conf; 16299a2dd95SBruce Richardson 16399a2dd95SBruce Richardson /* Check user arguments. */ 16499a2dd95SBruce Richardson if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) || 16599a2dd95SBruce Richardson (conf->type > RTE_FIB6_TRIE)) { 16699a2dd95SBruce Richardson rte_errno = EINVAL; 16799a2dd95SBruce Richardson return NULL; 16899a2dd95SBruce Richardson } 16999a2dd95SBruce Richardson 17011c5b9b5SVladimir Medvedkin rib_conf.ext_sz = conf->rib_ext_sz; 17199a2dd95SBruce Richardson rib_conf.max_nodes = conf->max_routes * 2; 17299a2dd95SBruce Richardson 17399a2dd95SBruce Richardson rib = rte_rib6_create(name, socket_id, &rib_conf); 17499a2dd95SBruce Richardson if (rib == NULL) { 175ae67895bSDavid Marchand FIB_LOG(ERR, 176ae67895bSDavid Marchand "Can not allocate RIB %s", name); 17799a2dd95SBruce Richardson return NULL; 17899a2dd95SBruce Richardson } 17999a2dd95SBruce Richardson 18099a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "FIB6_%s", name); 18199a2dd95SBruce Richardson fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list); 18299a2dd95SBruce Richardson 18399a2dd95SBruce Richardson rte_mcfg_tailq_write_lock(); 18499a2dd95SBruce Richardson 18599a2dd95SBruce Richardson /* guarantee there's no existing */ 18699a2dd95SBruce Richardson TAILQ_FOREACH(te, fib_list, next) { 18799a2dd95SBruce Richardson fib = (struct rte_fib6 *)te->data; 18899a2dd95SBruce Richardson if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0) 18999a2dd95SBruce Richardson break; 19099a2dd95SBruce Richardson } 19199a2dd95SBruce Richardson fib = NULL; 19299a2dd95SBruce Richardson if (te != NULL) { 19399a2dd95SBruce Richardson rte_errno = EEXIST; 19499a2dd95SBruce Richardson goto exit; 19599a2dd95SBruce Richardson } 19699a2dd95SBruce Richardson 19799a2dd95SBruce Richardson /* allocate tailq entry */ 19899a2dd95SBruce Richardson te = rte_zmalloc("FIB_TAILQ_ENTRY", sizeof(*te), 0); 19999a2dd95SBruce Richardson if (te == NULL) { 200ae67895bSDavid Marchand FIB_LOG(ERR, 201ae67895bSDavid Marchand "Can not allocate tailq entry for FIB %s", name); 20299a2dd95SBruce Richardson rte_errno = ENOMEM; 20399a2dd95SBruce Richardson goto exit; 20499a2dd95SBruce Richardson } 20599a2dd95SBruce Richardson 20699a2dd95SBruce Richardson /* Allocate memory to store the FIB data structures. */ 20799a2dd95SBruce Richardson fib = rte_zmalloc_socket(mem_name, 20899a2dd95SBruce Richardson sizeof(struct rte_fib6), RTE_CACHE_LINE_SIZE, socket_id); 20999a2dd95SBruce Richardson if (fib == NULL) { 210ae67895bSDavid Marchand FIB_LOG(ERR, "FIB %s memory allocation failed", name); 21199a2dd95SBruce Richardson rte_errno = ENOMEM; 21299a2dd95SBruce Richardson goto free_te; 21399a2dd95SBruce Richardson } 21499a2dd95SBruce Richardson 21599a2dd95SBruce Richardson rte_strlcpy(fib->name, name, sizeof(fib->name)); 21699a2dd95SBruce Richardson fib->rib = rib; 21799a2dd95SBruce Richardson fib->type = conf->type; 21899a2dd95SBruce Richardson fib->def_nh = conf->default_nh; 21999a2dd95SBruce Richardson ret = init_dataplane(fib, socket_id, conf); 22099a2dd95SBruce Richardson if (ret < 0) { 221ae67895bSDavid Marchand FIB_LOG(ERR, 222ae67895bSDavid Marchand "FIB dataplane struct %s memory allocation failed", 22399a2dd95SBruce Richardson name); 22499a2dd95SBruce Richardson rte_errno = -ret; 22599a2dd95SBruce Richardson goto free_fib; 22699a2dd95SBruce Richardson } 22799a2dd95SBruce Richardson 22899a2dd95SBruce Richardson te->data = (void *)fib; 22999a2dd95SBruce Richardson TAILQ_INSERT_TAIL(fib_list, te, next); 23099a2dd95SBruce Richardson 23199a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 23299a2dd95SBruce Richardson 23399a2dd95SBruce Richardson return fib; 23499a2dd95SBruce Richardson 23599a2dd95SBruce Richardson free_fib: 23699a2dd95SBruce Richardson rte_free(fib); 23799a2dd95SBruce Richardson free_te: 23899a2dd95SBruce Richardson rte_free(te); 23999a2dd95SBruce Richardson exit: 24099a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 24199a2dd95SBruce Richardson rte_rib6_free(rib); 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson return NULL; 24499a2dd95SBruce Richardson } 24599a2dd95SBruce Richardson 24699a2dd95SBruce Richardson struct rte_fib6 * 24799a2dd95SBruce Richardson rte_fib6_find_existing(const char *name) 24899a2dd95SBruce Richardson { 24999a2dd95SBruce Richardson struct rte_fib6 *fib = NULL; 25099a2dd95SBruce Richardson struct rte_tailq_entry *te; 25199a2dd95SBruce Richardson struct rte_fib6_list *fib_list; 25299a2dd95SBruce Richardson 25399a2dd95SBruce Richardson fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list); 25499a2dd95SBruce Richardson 25599a2dd95SBruce Richardson rte_mcfg_tailq_read_lock(); 25699a2dd95SBruce Richardson TAILQ_FOREACH(te, fib_list, next) { 25799a2dd95SBruce Richardson fib = (struct rte_fib6 *) te->data; 25899a2dd95SBruce Richardson if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0) 25999a2dd95SBruce Richardson break; 26099a2dd95SBruce Richardson } 26199a2dd95SBruce Richardson rte_mcfg_tailq_read_unlock(); 26299a2dd95SBruce Richardson 26399a2dd95SBruce Richardson if (te == NULL) { 26499a2dd95SBruce Richardson rte_errno = ENOENT; 26599a2dd95SBruce Richardson return NULL; 26699a2dd95SBruce Richardson } 26799a2dd95SBruce Richardson 26899a2dd95SBruce Richardson return fib; 26999a2dd95SBruce Richardson } 27099a2dd95SBruce Richardson 27199a2dd95SBruce Richardson static void 27299a2dd95SBruce Richardson free_dataplane(struct rte_fib6 *fib) 27399a2dd95SBruce Richardson { 27499a2dd95SBruce Richardson switch (fib->type) { 27599a2dd95SBruce Richardson case RTE_FIB6_DUMMY: 27699a2dd95SBruce Richardson return; 27799a2dd95SBruce Richardson case RTE_FIB6_TRIE: 27899a2dd95SBruce Richardson trie_free(fib->dp); 27999a2dd95SBruce Richardson default: 28099a2dd95SBruce Richardson return; 28199a2dd95SBruce Richardson } 28299a2dd95SBruce Richardson } 28399a2dd95SBruce Richardson 28499a2dd95SBruce Richardson void 28599a2dd95SBruce Richardson rte_fib6_free(struct rte_fib6 *fib) 28699a2dd95SBruce Richardson { 28799a2dd95SBruce Richardson struct rte_tailq_entry *te; 28899a2dd95SBruce Richardson struct rte_fib6_list *fib_list; 28999a2dd95SBruce Richardson 29099a2dd95SBruce Richardson if (fib == NULL) 29199a2dd95SBruce Richardson return; 29299a2dd95SBruce Richardson 29399a2dd95SBruce Richardson fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list); 29499a2dd95SBruce Richardson 29599a2dd95SBruce Richardson rte_mcfg_tailq_write_lock(); 29699a2dd95SBruce Richardson 29799a2dd95SBruce Richardson /* find our tailq entry */ 29899a2dd95SBruce Richardson TAILQ_FOREACH(te, fib_list, next) { 29999a2dd95SBruce Richardson if (te->data == (void *)fib) 30099a2dd95SBruce Richardson break; 30199a2dd95SBruce Richardson } 30299a2dd95SBruce Richardson if (te != NULL) 30399a2dd95SBruce Richardson TAILQ_REMOVE(fib_list, te, next); 30499a2dd95SBruce Richardson 30599a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock(); 30699a2dd95SBruce Richardson 30799a2dd95SBruce Richardson free_dataplane(fib); 30899a2dd95SBruce Richardson rte_rib6_free(fib->rib); 30999a2dd95SBruce Richardson rte_free(fib); 31099a2dd95SBruce Richardson rte_free(te); 31199a2dd95SBruce Richardson } 31299a2dd95SBruce Richardson 31399a2dd95SBruce Richardson void * 31499a2dd95SBruce Richardson rte_fib6_get_dp(struct rte_fib6 *fib) 31599a2dd95SBruce Richardson { 31699a2dd95SBruce Richardson return (fib == NULL) ? NULL : fib->dp; 31799a2dd95SBruce Richardson } 31899a2dd95SBruce Richardson 31999a2dd95SBruce Richardson struct rte_rib6 * 32099a2dd95SBruce Richardson rte_fib6_get_rib(struct rte_fib6 *fib) 32199a2dd95SBruce Richardson { 32299a2dd95SBruce Richardson return (fib == NULL) ? NULL : fib->rib; 32399a2dd95SBruce Richardson } 32499a2dd95SBruce Richardson 32599a2dd95SBruce Richardson int 32699a2dd95SBruce Richardson rte_fib6_select_lookup(struct rte_fib6 *fib, 32799a2dd95SBruce Richardson enum rte_fib6_lookup_type type) 32899a2dd95SBruce Richardson { 32999a2dd95SBruce Richardson rte_fib6_lookup_fn_t fn; 33099a2dd95SBruce Richardson 33199a2dd95SBruce Richardson switch (fib->type) { 33299a2dd95SBruce Richardson case RTE_FIB6_TRIE: 33399a2dd95SBruce Richardson fn = trie_get_lookup_fn(fib->dp, type); 33499a2dd95SBruce Richardson if (fn == NULL) 33599a2dd95SBruce Richardson return -EINVAL; 33699a2dd95SBruce Richardson fib->lookup = fn; 33799a2dd95SBruce Richardson return 0; 33899a2dd95SBruce Richardson default: 33999a2dd95SBruce Richardson return -EINVAL; 34099a2dd95SBruce Richardson } 34199a2dd95SBruce Richardson } 342