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