dpdk/lib/fib/rte_fib6.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>
   3 * Copyright(c) 2019 Intel Corporation
   4 */
   5
   6#include <stdint.h>
   7#include <string.h>
   8
   9#include <rte_eal.h>
  10#include <rte_eal_memconfig.h>
  11#include <rte_tailq.h>
  12#include <rte_errno.h>
  13#include <rte_rwlock.h>
  14#include <rte_malloc.h>
  15#include <rte_string_fns.h>
  16
  17#include <rte_rib6.h>
  18#include <rte_fib6.h>
  19
  20#include "trie.h"
  21
  22TAILQ_HEAD(rte_fib6_list, rte_tailq_entry);
  23static struct rte_tailq_elem rte_fib6_tailq = {
  24        .name = "RTE_FIB6",
  25};
  26EAL_REGISTER_TAILQ(rte_fib6_tailq)
  27
  28/* Maximum length of a FIB name. */
  29#define FIB6_NAMESIZE   64
  30
  31#if defined(RTE_LIBRTE_FIB_DEBUG)
  32#define FIB6_RETURN_IF_TRUE(cond, retval) do {          \
  33        if (cond)                                       \
  34                return retval;                          \
  35} while (0)
  36#else
  37#define FIB6_RETURN_IF_TRUE(cond, retval)
  38#endif
  39
  40struct rte_fib6 {
  41        char                    name[FIB6_NAMESIZE];
  42        enum rte_fib6_type      type;   /**< Type of FIB struct */
  43        struct rte_rib6         *rib;   /**< RIB helper datastruct */
  44        void                    *dp;    /**< pointer to the dataplane struct*/
  45        rte_fib6_lookup_fn_t    lookup; /**< fib lookup function */
  46        rte_fib6_modify_fn_t    modify; /**< modify fib datastruct */
  47        uint64_t                def_nh;
  48};
  49
  50static void
  51dummy_lookup(void *fib_p, uint8_t ips[][RTE_FIB6_IPV6_ADDR_SIZE],
  52        uint64_t *next_hops, const unsigned int n)
  53{
  54        unsigned int i;
  55        struct rte_fib6 *fib = fib_p;
  56        struct rte_rib6_node *node;
  57
  58        for (i = 0; i < n; i++) {
  59                node = rte_rib6_lookup(fib->rib, ips[i]);
  60                if (node != NULL)
  61                        rte_rib6_get_nh(node, &next_hops[i]);
  62                else
  63                        next_hops[i] = fib->def_nh;
  64        }
  65}
  66
  67static int
  68dummy_modify(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
  69        uint8_t depth, uint64_t next_hop, int op)
  70{
  71        struct rte_rib6_node *node;
  72        if ((fib == NULL) || (depth > RTE_FIB6_MAXDEPTH))
  73                return -EINVAL;
  74
  75        node = rte_rib6_lookup_exact(fib->rib, ip, depth);
  76
  77        switch (op) {
  78        case RTE_FIB6_ADD:
  79                if (node == NULL)
  80                        node = rte_rib6_insert(fib->rib, ip, depth);
  81                if (node == NULL)
  82                        return -rte_errno;
  83                return rte_rib6_set_nh(node, next_hop);
  84        case RTE_FIB6_DEL:
  85                if (node == NULL)
  86                        return -ENOENT;
  87                rte_rib6_remove(fib->rib, ip, depth);
  88                return 0;
  89        }
  90        return -EINVAL;
  91}
  92
  93static int
  94init_dataplane(struct rte_fib6 *fib, __rte_unused int socket_id,
  95        struct rte_fib6_conf *conf)
  96{
  97        char dp_name[sizeof(void *)];
  98
  99        snprintf(dp_name, sizeof(dp_name), "%p", fib);
 100        switch (conf->type) {
 101        case RTE_FIB6_DUMMY:
 102                fib->dp = fib;
 103                fib->lookup = dummy_lookup;
 104                fib->modify = dummy_modify;
 105                return 0;
 106        case RTE_FIB6_TRIE:
 107                fib->dp = trie_create(dp_name, socket_id, conf);
 108                if (fib->dp == NULL)
 109                        return -rte_errno;
 110                fib->lookup = trie_get_lookup_fn(fib->dp, RTE_FIB6_LOOKUP_DEFAULT);
 111                fib->modify = trie_modify;
 112                return 0;
 113        default:
 114                return -EINVAL;
 115        }
 116        return 0;
 117}
 118
 119int
 120rte_fib6_add(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
 121        uint8_t depth, uint64_t next_hop)
 122{
 123        if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) ||
 124                        (depth > RTE_FIB6_MAXDEPTH))
 125                return -EINVAL;
 126        return fib->modify(fib, ip, depth, next_hop, RTE_FIB6_ADD);
 127}
 128
 129int
 130rte_fib6_delete(struct rte_fib6 *fib, const uint8_t ip[RTE_FIB6_IPV6_ADDR_SIZE],
 131        uint8_t depth)
 132{
 133        if ((fib == NULL) || (ip == NULL) || (fib->modify == NULL) ||
 134                        (depth > RTE_FIB6_MAXDEPTH))
 135                return -EINVAL;
 136        return fib->modify(fib, ip, depth, 0, RTE_FIB6_DEL);
 137}
 138
 139int
 140rte_fib6_lookup_bulk(struct rte_fib6 *fib,
 141        uint8_t ips[][RTE_FIB6_IPV6_ADDR_SIZE],
 142        uint64_t *next_hops, int n)
 143{
 144        FIB6_RETURN_IF_TRUE((fib == NULL) || (ips == NULL) ||
 145                (next_hops == NULL) || (fib->lookup == NULL), -EINVAL);
 146        fib->lookup(fib->dp, ips, next_hops, n);
 147        return 0;
 148}
 149
 150struct rte_fib6 *
 151rte_fib6_create(const char *name, int socket_id, struct rte_fib6_conf *conf)
 152{
 153        char mem_name[FIB6_NAMESIZE];
 154        int ret;
 155        struct rte_fib6 *fib = NULL;
 156        struct rte_rib6 *rib = NULL;
 157        struct rte_tailq_entry *te;
 158        struct rte_fib6_list *fib_list;
 159        struct rte_rib6_conf rib_conf;
 160
 161        /* Check user arguments. */
 162        if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) ||
 163                        (conf->type > RTE_FIB6_TRIE)) {
 164                rte_errno = EINVAL;
 165                return NULL;
 166        }
 167
 168        rib_conf.ext_sz = 0;
 169        rib_conf.max_nodes = conf->max_routes * 2;
 170
 171        rib = rte_rib6_create(name, socket_id, &rib_conf);
 172        if (rib == NULL) {
 173                RTE_LOG(ERR, LPM,
 174                        "Can not allocate RIB %s\n", name);
 175                return NULL;
 176        }
 177
 178        snprintf(mem_name, sizeof(mem_name), "FIB6_%s", name);
 179        fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
 180
 181        rte_mcfg_tailq_write_lock();
 182
 183        /* guarantee there's no existing */
 184        TAILQ_FOREACH(te, fib_list, next) {
 185                fib = (struct rte_fib6 *)te->data;
 186                if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0)
 187                        break;
 188        }
 189        fib = NULL;
 190        if (te != NULL) {
 191                rte_errno = EEXIST;
 192                goto exit;
 193        }
 194
 195        /* allocate tailq entry */
 196        te = rte_zmalloc("FIB_TAILQ_ENTRY", sizeof(*te), 0);
 197        if (te == NULL) {
 198                RTE_LOG(ERR, LPM,
 199                        "Can not allocate tailq entry for FIB %s\n", name);
 200                rte_errno = ENOMEM;
 201                goto exit;
 202        }
 203
 204        /* Allocate memory to store the FIB data structures. */
 205        fib = rte_zmalloc_socket(mem_name,
 206                sizeof(struct rte_fib6), RTE_CACHE_LINE_SIZE, socket_id);
 207        if (fib == NULL) {
 208                RTE_LOG(ERR, LPM, "FIB %s memory allocation failed\n", name);
 209                rte_errno = ENOMEM;
 210                goto free_te;
 211        }
 212
 213        rte_strlcpy(fib->name, name, sizeof(fib->name));
 214        fib->rib = rib;
 215        fib->type = conf->type;
 216        fib->def_nh = conf->default_nh;
 217        ret = init_dataplane(fib, socket_id, conf);
 218        if (ret < 0) {
 219                RTE_LOG(ERR, LPM,
 220                        "FIB dataplane struct %s memory allocation failed\n",
 221                        name);
 222                rte_errno = -ret;
 223                goto free_fib;
 224        }
 225
 226        te->data = (void *)fib;
 227        TAILQ_INSERT_TAIL(fib_list, te, next);
 228
 229        rte_mcfg_tailq_write_unlock();
 230
 231        return fib;
 232
 233free_fib:
 234        rte_free(fib);
 235free_te:
 236        rte_free(te);
 237exit:
 238        rte_mcfg_tailq_write_unlock();
 239        rte_rib6_free(rib);
 240
 241        return NULL;
 242}
 243
 244struct rte_fib6 *
 245rte_fib6_find_existing(const char *name)
 246{
 247        struct rte_fib6 *fib = NULL;
 248        struct rte_tailq_entry *te;
 249        struct rte_fib6_list *fib_list;
 250
 251        fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
 252
 253        rte_mcfg_tailq_read_lock();
 254        TAILQ_FOREACH(te, fib_list, next) {
 255                fib = (struct rte_fib6 *) te->data;
 256                if (strncmp(name, fib->name, FIB6_NAMESIZE) == 0)
 257                        break;
 258        }
 259        rte_mcfg_tailq_read_unlock();
 260
 261        if (te == NULL) {
 262                rte_errno = ENOENT;
 263                return NULL;
 264        }
 265
 266        return fib;
 267}
 268
 269static void
 270free_dataplane(struct rte_fib6 *fib)
 271{
 272        switch (fib->type) {
 273        case RTE_FIB6_DUMMY:
 274                return;
 275        case RTE_FIB6_TRIE:
 276                trie_free(fib->dp);
 277        default:
 278                return;
 279        }
 280}
 281
 282void
 283rte_fib6_free(struct rte_fib6 *fib)
 284{
 285        struct rte_tailq_entry *te;
 286        struct rte_fib6_list *fib_list;
 287
 288        if (fib == NULL)
 289                return;
 290
 291        fib_list = RTE_TAILQ_CAST(rte_fib6_tailq.head, rte_fib6_list);
 292
 293        rte_mcfg_tailq_write_lock();
 294
 295        /* find our tailq entry */
 296        TAILQ_FOREACH(te, fib_list, next) {
 297                if (te->data == (void *)fib)
 298                        break;
 299        }
 300        if (te != NULL)
 301                TAILQ_REMOVE(fib_list, te, next);
 302
 303        rte_mcfg_tailq_write_unlock();
 304
 305        free_dataplane(fib);
 306        rte_rib6_free(fib->rib);
 307        rte_free(fib);
 308        rte_free(te);
 309}
 310
 311void *
 312rte_fib6_get_dp(struct rte_fib6 *fib)
 313{
 314        return (fib == NULL) ? NULL : fib->dp;
 315}
 316
 317struct rte_rib6 *
 318rte_fib6_get_rib(struct rte_fib6 *fib)
 319{
 320        return (fib == NULL) ? NULL : fib->rib;
 321}
 322
 323int
 324rte_fib6_select_lookup(struct rte_fib6 *fib,
 325        enum rte_fib6_lookup_type type)
 326{
 327        rte_fib6_lookup_fn_t fn;
 328
 329        switch (fib->type) {
 330        case RTE_FIB6_TRIE:
 331                fn = trie_get_lookup_fn(fib->dp, type);
 332                if (fn == NULL)
 333                        return -EINVAL;
 334                fib->lookup = fn;
 335                return 0;
 336        default:
 337                return -EINVAL;
 338        }
 339}
 340