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_errno.h> 12 #include <rte_malloc.h> 13 #include <rte_rwlock.h> 14 #include <rte_string_fns.h> 15 #include <rte_tailq.h> 16 17 #include <rte_rib.h> 18 #include <rte_fib.h> 19 20 #include "dir24_8.h" 21 22 TAILQ_HEAD(rte_fib_list, rte_tailq_entry); 23 static struct rte_tailq_elem rte_fib_tailq = { 24 .name = "RTE_FIB", 25 }; 26 EAL_REGISTER_TAILQ(rte_fib_tailq) 27 28 /* Maximum length of a FIB name. */ 29 #define RTE_FIB_NAMESIZE 64 30 31 #if defined(RTE_LIBRTE_FIB_DEBUG) 32 #define FIB_RETURN_IF_TRUE(cond, retval) do { \ 33 if (cond) \ 34 return retval; \ 35 } while (0) 36 #else 37 #define FIB_RETURN_IF_TRUE(cond, retval) 38 #endif 39 40 struct rte_fib { 41 char name[RTE_FIB_NAMESIZE]; 42 enum rte_fib_type type; /**< Type of FIB struct */ 43 struct rte_rib *rib; /**< RIB helper datastruct */ 44 void *dp; /**< pointer to the dataplane struct*/ 45 rte_fib_lookup_fn_t lookup; /**< fib lookup function */ 46 rte_fib_modify_fn_t modify; /**< modify fib datastruct */ 47 uint64_t def_nh; 48 }; 49 50 static void 51 dummy_lookup(void *fib_p, const uint32_t *ips, uint64_t *next_hops, 52 const unsigned int n) 53 { 54 unsigned int i; 55 struct rte_fib *fib = fib_p; 56 struct rte_rib_node *node; 57 58 for (i = 0; i < n; i++) { 59 node = rte_rib_lookup(fib->rib, ips[i]); 60 if (node != NULL) 61 rte_rib_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_fib *fib, uint32_t ip, uint8_t depth, 69 uint64_t next_hop, int op) 70 { 71 struct rte_rib_node *node; 72 if ((fib == NULL) || (depth > RTE_FIB_MAXDEPTH)) 73 return -EINVAL; 74 75 node = rte_rib_lookup_exact(fib->rib, ip, depth); 76 77 switch (op) { 78 case RTE_FIB_ADD: 79 if (node == NULL) 80 node = rte_rib_insert(fib->rib, ip, depth); 81 if (node == NULL) 82 return -rte_errno; 83 return rte_rib_set_nh(node, next_hop); 84 case RTE_FIB_DEL: 85 if (node == NULL) 86 return -ENOENT; 87 rte_rib_remove(fib->rib, ip, depth); 88 return 0; 89 } 90 return -EINVAL; 91 } 92 93 static int 94 init_dataplane(struct rte_fib *fib, __rte_unused int socket_id, 95 struct rte_fib_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_FIB_DUMMY: 102 fib->dp = fib; 103 fib->lookup = dummy_lookup; 104 fib->modify = dummy_modify; 105 return 0; 106 case RTE_FIB_DIR24_8: 107 fib->dp = dir24_8_create(dp_name, socket_id, conf); 108 if (fib->dp == NULL) 109 return -rte_errno; 110 fib->lookup = dir24_8_get_lookup_fn(fib->dp, 111 RTE_FIB_LOOKUP_DEFAULT); 112 fib->modify = dir24_8_modify; 113 return 0; 114 default: 115 return -EINVAL; 116 } 117 return 0; 118 } 119 120 int 121 rte_fib_add(struct rte_fib *fib, uint32_t ip, uint8_t depth, uint64_t next_hop) 122 { 123 if ((fib == NULL) || (fib->modify == NULL) || 124 (depth > RTE_FIB_MAXDEPTH)) 125 return -EINVAL; 126 return fib->modify(fib, ip, depth, next_hop, RTE_FIB_ADD); 127 } 128 129 int 130 rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t depth) 131 { 132 if ((fib == NULL) || (fib->modify == NULL) || 133 (depth > RTE_FIB_MAXDEPTH)) 134 return -EINVAL; 135 return fib->modify(fib, ip, depth, 0, RTE_FIB_DEL); 136 } 137 138 int 139 rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips, 140 uint64_t *next_hops, int n) 141 { 142 FIB_RETURN_IF_TRUE(((fib == NULL) || (ips == NULL) || 143 (next_hops == NULL) || (fib->lookup == NULL)), -EINVAL); 144 145 fib->lookup(fib->dp, ips, next_hops, n); 146 return 0; 147 } 148 149 struct rte_fib * 150 rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf) 151 { 152 char mem_name[RTE_FIB_NAMESIZE]; 153 int ret; 154 struct rte_fib *fib = NULL; 155 struct rte_rib *rib = NULL; 156 struct rte_tailq_entry *te; 157 struct rte_fib_list *fib_list; 158 struct rte_rib_conf rib_conf; 159 160 /* Check user arguments. */ 161 if ((name == NULL) || (conf == NULL) || (conf->max_routes < 0) || 162 (conf->type > RTE_FIB_DIR24_8)) { 163 rte_errno = EINVAL; 164 return NULL; 165 } 166 167 rib_conf.ext_sz = 0; 168 rib_conf.max_nodes = conf->max_routes * 2; 169 170 rib = rte_rib_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), "FIB_%s", name); 178 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_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_fib *)te->data; 185 if (strncmp(name, fib->name, RTE_FIB_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_fib), 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 " 220 "with err %d\n", name, ret); 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_rib_free(rib); 239 240 return NULL; 241 } 242 243 struct rte_fib * 244 rte_fib_find_existing(const char *name) 245 { 246 struct rte_fib *fib = NULL; 247 struct rte_tailq_entry *te; 248 struct rte_fib_list *fib_list; 249 250 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_list); 251 252 rte_mcfg_tailq_read_lock(); 253 TAILQ_FOREACH(te, fib_list, next) { 254 fib = (struct rte_fib *) te->data; 255 if (strncmp(name, fib->name, RTE_FIB_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_fib *fib) 270 { 271 switch (fib->type) { 272 case RTE_FIB_DUMMY: 273 return; 274 case RTE_FIB_DIR24_8: 275 dir24_8_free(fib->dp); 276 default: 277 return; 278 } 279 } 280 281 void 282 rte_fib_free(struct rte_fib *fib) 283 { 284 struct rte_tailq_entry *te; 285 struct rte_fib_list *fib_list; 286 287 if (fib == NULL) 288 return; 289 290 fib_list = RTE_TAILQ_CAST(rte_fib_tailq.head, rte_fib_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_rib_free(fib->rib); 306 rte_free(fib); 307 rte_free(te); 308 } 309 310 void * 311 rte_fib_get_dp(struct rte_fib *fib) 312 { 313 return (fib == NULL) ? NULL : fib->dp; 314 } 315 316 struct rte_rib * 317 rte_fib_get_rib(struct rte_fib *fib) 318 { 319 return (fib == NULL) ? NULL : fib->rib; 320 } 321 322 int 323 rte_fib_select_lookup(struct rte_fib *fib, 324 enum rte_fib_lookup_type type) 325 { 326 rte_fib_lookup_fn_t fn; 327 328 switch (fib->type) { 329 case RTE_FIB_DIR24_8: 330 fn = dir24_8_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