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