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 22 TAILQ_HEAD(rte_fib6_list, rte_tailq_entry); 23 static struct rte_tailq_elem rte_fib6_tailq = { 24 .name = "RTE_FIB6", 25 }; 26 EAL_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 40 struct 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 50 static void 51 dummy_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 67 static int 68 dummy_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 93 static int 94 init_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 119 int 120 rte_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 129 int 130 rte_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 139 int 140 rte_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 150 struct rte_fib6 * 151 rte_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 233 free_fib: 234 rte_free(fib); 235 free_te: 236 rte_free(te); 237 exit: 238 rte_mcfg_tailq_write_unlock(); 239 rte_rib6_free(rib); 240 241 return NULL; 242 } 243 244 struct rte_fib6 * 245 rte_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 269 static void 270 free_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 282 void 283 rte_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 311 void * 312 rte_fib6_get_dp(struct rte_fib6 *fib) 313 { 314 return (fib == NULL) ? NULL : fib->dp; 315 } 316 317 struct rte_rib6 * 318 rte_fib6_get_rib(struct rte_fib6 *fib) 319 { 320 return (fib == NULL) ? NULL : fib->rib; 321 } 322 323 int 324 rte_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