1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include <stdlib.h> 6 #include <string.h> 7 #include <netinet/in.h> 8 #ifdef RTE_EXEC_ENV_LINUX 9 #include <linux/if.h> 10 #include <linux/if_tun.h> 11 #endif 12 #include <sys/ioctl.h> 13 #include <fcntl.h> 14 #include <unistd.h> 15 16 #include <rte_mempool.h> 17 #include <rte_mbuf.h> 18 #include <rte_ethdev.h> 19 #include <rte_swx_ctl.h> 20 21 #include "obj.h" 22 23 /* 24 * mempool 25 */ 26 TAILQ_HEAD(mempool_list, mempool); 27 28 /* 29 * link 30 */ 31 TAILQ_HEAD(link_list, link); 32 33 /* 34 * ring 35 */ 36 TAILQ_HEAD(ring_list, ring); 37 38 /* 39 * obj 40 */ 41 struct obj { 42 struct mempool_list mempool_list; 43 struct link_list link_list; 44 struct ring_list ring_list; 45 }; 46 47 /* 48 * mempool 49 */ 50 #define BUFFER_SIZE_MIN (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 51 52 struct mempool * 53 mempool_create(struct obj *obj, const char *name, struct mempool_params *params) 54 { 55 struct mempool *mempool; 56 struct rte_mempool *m; 57 58 /* Check input params */ 59 if ((name == NULL) || 60 mempool_find(obj, name) || 61 (params == NULL) || 62 (params->buffer_size < BUFFER_SIZE_MIN) || 63 (params->pool_size == 0)) 64 return NULL; 65 66 /* Resource create */ 67 m = rte_pktmbuf_pool_create( 68 name, 69 params->pool_size, 70 params->cache_size, 71 0, 72 params->buffer_size - sizeof(struct rte_mbuf), 73 params->cpu_id); 74 75 if (m == NULL) 76 return NULL; 77 78 /* Node allocation */ 79 mempool = calloc(1, sizeof(struct mempool)); 80 if (mempool == NULL) { 81 rte_mempool_free(m); 82 return NULL; 83 } 84 85 /* Node fill in */ 86 strlcpy(mempool->name, name, sizeof(mempool->name)); 87 mempool->m = m; 88 mempool->buffer_size = params->buffer_size; 89 90 /* Node add to list */ 91 TAILQ_INSERT_TAIL(&obj->mempool_list, mempool, node); 92 93 return mempool; 94 } 95 96 struct mempool * 97 mempool_find(struct obj *obj, const char *name) 98 { 99 struct mempool *mempool; 100 101 if (!obj || !name) 102 return NULL; 103 104 TAILQ_FOREACH(mempool, &obj->mempool_list, node) 105 if (strcmp(mempool->name, name) == 0) 106 return mempool; 107 108 return NULL; 109 } 110 111 /* 112 * link 113 */ 114 static struct rte_eth_conf port_conf_default = { 115 .link_speeds = 0, 116 .rxmode = { 117 .mq_mode = RTE_ETH_MQ_RX_NONE, 118 .mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */ 119 .split_hdr_size = 0, /* Header split buffer size */ 120 }, 121 .rx_adv_conf = { 122 .rss_conf = { 123 .rss_key = NULL, 124 .rss_key_len = 40, 125 .rss_hf = 0, 126 }, 127 }, 128 .txmode = { 129 .mq_mode = RTE_ETH_MQ_TX_NONE, 130 }, 131 .lpbk_mode = 0, 132 }; 133 134 #define RETA_CONF_SIZE (RTE_ETH_RSS_RETA_SIZE_512 / RTE_ETH_RETA_GROUP_SIZE) 135 136 static int 137 rss_setup(uint16_t port_id, 138 uint16_t reta_size, 139 struct link_params_rss *rss) 140 { 141 struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE]; 142 uint32_t i; 143 int status; 144 145 /* RETA setting */ 146 memset(reta_conf, 0, sizeof(reta_conf)); 147 148 for (i = 0; i < reta_size; i++) 149 reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX; 150 151 for (i = 0; i < reta_size; i++) { 152 uint32_t reta_id = i / RTE_ETH_RETA_GROUP_SIZE; 153 uint32_t reta_pos = i % RTE_ETH_RETA_GROUP_SIZE; 154 uint32_t rss_qs_pos = i % rss->n_queues; 155 156 reta_conf[reta_id].reta[reta_pos] = 157 (uint16_t) rss->queue_id[rss_qs_pos]; 158 } 159 160 /* RETA update */ 161 status = rte_eth_dev_rss_reta_update(port_id, 162 reta_conf, 163 reta_size); 164 165 return status; 166 } 167 168 struct link * 169 link_create(struct obj *obj, const char *name, struct link_params *params) 170 { 171 struct rte_eth_dev_info port_info; 172 struct rte_eth_conf port_conf; 173 struct link *link; 174 struct link_params_rss *rss; 175 struct mempool *mempool; 176 uint32_t cpu_id, i; 177 int status; 178 uint16_t port_id = 0; 179 180 /* Check input params */ 181 if ((name == NULL) || 182 link_find(obj, name) || 183 (params == NULL) || 184 (params->rx.n_queues == 0) || 185 (params->rx.queue_size == 0) || 186 (params->tx.n_queues == 0) || 187 (params->tx.queue_size == 0)) 188 return NULL; 189 190 status = rte_eth_dev_get_port_by_name(name, &port_id); 191 if (status) 192 return NULL; 193 194 if (rte_eth_dev_info_get(port_id, &port_info) != 0) 195 return NULL; 196 197 mempool = mempool_find(obj, params->rx.mempool_name); 198 if (mempool == NULL) 199 return NULL; 200 201 rss = params->rx.rss; 202 if (rss) { 203 if ((port_info.reta_size == 0) || 204 (port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512)) 205 return NULL; 206 207 if ((rss->n_queues == 0) || 208 (rss->n_queues >= LINK_RXQ_RSS_MAX)) 209 return NULL; 210 211 for (i = 0; i < rss->n_queues; i++) 212 if (rss->queue_id[i] >= port_info.max_rx_queues) 213 return NULL; 214 } 215 216 /** 217 * Resource create 218 */ 219 /* Port */ 220 memcpy(&port_conf, &port_conf_default, sizeof(port_conf)); 221 if (rss) { 222 port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS; 223 port_conf.rx_adv_conf.rss_conf.rss_hf = 224 (RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) & 225 port_info.flow_type_rss_offloads; 226 } 227 228 cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id); 229 if (cpu_id == (uint32_t) SOCKET_ID_ANY) 230 cpu_id = 0; 231 232 status = rte_eth_dev_configure( 233 port_id, 234 params->rx.n_queues, 235 params->tx.n_queues, 236 &port_conf); 237 238 if (status < 0) 239 return NULL; 240 241 if (params->promiscuous) { 242 status = rte_eth_promiscuous_enable(port_id); 243 if (status != 0) 244 return NULL; 245 } 246 247 /* Port RX */ 248 for (i = 0; i < params->rx.n_queues; i++) { 249 status = rte_eth_rx_queue_setup( 250 port_id, 251 i, 252 params->rx.queue_size, 253 cpu_id, 254 NULL, 255 mempool->m); 256 257 if (status < 0) 258 return NULL; 259 } 260 261 /* Port TX */ 262 for (i = 0; i < params->tx.n_queues; i++) { 263 status = rte_eth_tx_queue_setup( 264 port_id, 265 i, 266 params->tx.queue_size, 267 cpu_id, 268 NULL); 269 270 if (status < 0) 271 return NULL; 272 } 273 274 /* Port start */ 275 status = rte_eth_dev_start(port_id); 276 if (status < 0) 277 return NULL; 278 279 if (rss) { 280 status = rss_setup(port_id, port_info.reta_size, rss); 281 282 if (status) { 283 rte_eth_dev_stop(port_id); 284 return NULL; 285 } 286 } 287 288 /* Port link up */ 289 status = rte_eth_dev_set_link_up(port_id); 290 if ((status < 0) && (status != -ENOTSUP)) { 291 rte_eth_dev_stop(port_id); 292 return NULL; 293 } 294 295 /* Node allocation */ 296 link = calloc(1, sizeof(struct link)); 297 if (link == NULL) { 298 rte_eth_dev_stop(port_id); 299 return NULL; 300 } 301 302 /* Node fill in */ 303 strlcpy(link->name, name, sizeof(link->name)); 304 link->port_id = port_id; 305 link->n_rxq = params->rx.n_queues; 306 link->n_txq = params->tx.n_queues; 307 308 /* Node add to list */ 309 TAILQ_INSERT_TAIL(&obj->link_list, link, node); 310 311 return link; 312 } 313 314 int 315 link_is_up(struct obj *obj, const char *name) 316 { 317 struct rte_eth_link link_params; 318 struct link *link; 319 320 /* Check input params */ 321 if (!obj || !name) 322 return 0; 323 324 link = link_find(obj, name); 325 if (link == NULL) 326 return 0; 327 328 /* Resource */ 329 if (rte_eth_link_get(link->port_id, &link_params) < 0) 330 return 0; 331 332 return (link_params.link_status == RTE_ETH_LINK_DOWN) ? 0 : 1; 333 } 334 335 struct link * 336 link_find(struct obj *obj, const char *name) 337 { 338 struct link *link; 339 340 if (!obj || !name) 341 return NULL; 342 343 TAILQ_FOREACH(link, &obj->link_list, node) 344 if (strcmp(link->name, name) == 0) 345 return link; 346 347 return NULL; 348 } 349 350 struct link * 351 link_next(struct obj *obj, struct link *link) 352 { 353 return (link == NULL) ? 354 TAILQ_FIRST(&obj->link_list) : TAILQ_NEXT(link, node); 355 } 356 357 /* 358 * ring 359 */ 360 struct ring * 361 ring_create(struct obj *obj, const char *name, struct ring_params *params) 362 { 363 struct ring *ring; 364 struct rte_ring *r; 365 unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ; 366 367 /* Check input params */ 368 if (!name || ring_find(obj, name) || !params || !params->size) 369 return NULL; 370 371 /** 372 * Resource create 373 */ 374 r = rte_ring_create( 375 name, 376 params->size, 377 params->numa_node, 378 flags); 379 if (!r) 380 return NULL; 381 382 /* Node allocation */ 383 ring = calloc(1, sizeof(struct ring)); 384 if (!ring) { 385 rte_ring_free(r); 386 return NULL; 387 } 388 389 /* Node fill in */ 390 strlcpy(ring->name, name, sizeof(ring->name)); 391 392 /* Node add to list */ 393 TAILQ_INSERT_TAIL(&obj->ring_list, ring, node); 394 395 return ring; 396 } 397 398 struct ring * 399 ring_find(struct obj *obj, const char *name) 400 { 401 struct ring *ring; 402 403 if (!obj || !name) 404 return NULL; 405 406 TAILQ_FOREACH(ring, &obj->ring_list, node) 407 if (strcmp(ring->name, name) == 0) 408 return ring; 409 410 return NULL; 411 } 412 413 /* 414 * obj 415 */ 416 struct obj * 417 obj_init(void) 418 { 419 struct obj *obj; 420 421 obj = calloc(1, sizeof(struct obj)); 422 if (!obj) 423 return NULL; 424 425 TAILQ_INIT(&obj->mempool_list); 426 TAILQ_INIT(&obj->link_list); 427 TAILQ_INIT(&obj->ring_list); 428 429 return obj; 430 } 431