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