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