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