1b77f6600SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause 2b77f6600SCristian Dumitrescu * Copyright(c) 2020 Intel Corporation 3b77f6600SCristian Dumitrescu */ 4b77f6600SCristian Dumitrescu 5b77f6600SCristian Dumitrescu #include <stdlib.h> 6b77f6600SCristian Dumitrescu #include <string.h> 7e2b8dc52SVenkata Suresh Kumar P #include <netinet/in.h> 8e2b8dc52SVenkata Suresh Kumar P #ifdef RTE_EXEC_ENV_LINUX 9e2b8dc52SVenkata Suresh Kumar P #include <linux/if.h> 10e2b8dc52SVenkata Suresh Kumar P #include <linux/if_tun.h> 11e2b8dc52SVenkata Suresh Kumar P #endif 12e2b8dc52SVenkata Suresh Kumar P #include <sys/ioctl.h> 13e2b8dc52SVenkata Suresh Kumar P #include <fcntl.h> 14e2b8dc52SVenkata Suresh Kumar P #include <unistd.h> 15b77f6600SCristian Dumitrescu 16b77f6600SCristian Dumitrescu #include <rte_mbuf.h> 17b77f6600SCristian Dumitrescu #include <rte_ethdev.h> 18b77f6600SCristian Dumitrescu #include <rte_swx_ctl.h> 19b77f6600SCristian Dumitrescu 20b77f6600SCristian Dumitrescu #include "obj.h" 21b77f6600SCristian Dumitrescu 22b77f6600SCristian Dumitrescu /* 23b77f6600SCristian Dumitrescu * link 24b77f6600SCristian Dumitrescu */ 25b77f6600SCristian Dumitrescu TAILQ_HEAD(link_list, link); 26b77f6600SCristian Dumitrescu 27b77f6600SCristian Dumitrescu /* 2877a41301SCristian Dumitrescu * ring 2977a41301SCristian Dumitrescu */ 3077a41301SCristian Dumitrescu TAILQ_HEAD(ring_list, ring); 3177a41301SCristian Dumitrescu 3277a41301SCristian Dumitrescu /* 33b77f6600SCristian Dumitrescu * obj 34b77f6600SCristian Dumitrescu */ 35b77f6600SCristian Dumitrescu struct obj { 36b77f6600SCristian Dumitrescu struct link_list link_list; 3777a41301SCristian Dumitrescu struct ring_list ring_list; 38b77f6600SCristian Dumitrescu }; 39b77f6600SCristian Dumitrescu 40b77f6600SCristian Dumitrescu /* 41b77f6600SCristian Dumitrescu * link 42b77f6600SCristian Dumitrescu */ 43b77f6600SCristian Dumitrescu static struct rte_eth_conf port_conf_default = { 44b77f6600SCristian Dumitrescu .link_speeds = 0, 45b77f6600SCristian Dumitrescu .rxmode = { 46295968d1SFerruh Yigit .mq_mode = RTE_ETH_MQ_RX_NONE, 471bb4a528SFerruh Yigit .mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */ 48b77f6600SCristian Dumitrescu }, 49b77f6600SCristian Dumitrescu .rx_adv_conf = { 50b77f6600SCristian Dumitrescu .rss_conf = { 51b77f6600SCristian Dumitrescu .rss_key = NULL, 52b77f6600SCristian Dumitrescu .rss_key_len = 40, 53b77f6600SCristian Dumitrescu .rss_hf = 0, 54b77f6600SCristian Dumitrescu }, 55b77f6600SCristian Dumitrescu }, 56b77f6600SCristian Dumitrescu .txmode = { 57295968d1SFerruh Yigit .mq_mode = RTE_ETH_MQ_TX_NONE, 58b77f6600SCristian Dumitrescu }, 59b77f6600SCristian Dumitrescu .lpbk_mode = 0, 60b77f6600SCristian Dumitrescu }; 61b77f6600SCristian Dumitrescu 62295968d1SFerruh Yigit #define RETA_CONF_SIZE (RTE_ETH_RSS_RETA_SIZE_512 / RTE_ETH_RETA_GROUP_SIZE) 63b77f6600SCristian Dumitrescu 64b77f6600SCristian Dumitrescu static int 65b77f6600SCristian Dumitrescu rss_setup(uint16_t port_id, 66b77f6600SCristian Dumitrescu uint16_t reta_size, 67b77f6600SCristian Dumitrescu struct link_params_rss *rss) 68b77f6600SCristian Dumitrescu { 69b77f6600SCristian Dumitrescu struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE]; 70b77f6600SCristian Dumitrescu uint32_t i; 71b77f6600SCristian Dumitrescu int status; 72b77f6600SCristian Dumitrescu 73b77f6600SCristian Dumitrescu /* RETA setting */ 74b77f6600SCristian Dumitrescu memset(reta_conf, 0, sizeof(reta_conf)); 75b77f6600SCristian Dumitrescu 76b77f6600SCristian Dumitrescu for (i = 0; i < reta_size; i++) 77295968d1SFerruh Yigit reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX; 78b77f6600SCristian Dumitrescu 79b77f6600SCristian Dumitrescu for (i = 0; i < reta_size; i++) { 80295968d1SFerruh Yigit uint32_t reta_id = i / RTE_ETH_RETA_GROUP_SIZE; 81295968d1SFerruh Yigit uint32_t reta_pos = i % RTE_ETH_RETA_GROUP_SIZE; 82b77f6600SCristian Dumitrescu uint32_t rss_qs_pos = i % rss->n_queues; 83b77f6600SCristian Dumitrescu 84b77f6600SCristian Dumitrescu reta_conf[reta_id].reta[reta_pos] = 85b77f6600SCristian Dumitrescu (uint16_t) rss->queue_id[rss_qs_pos]; 86b77f6600SCristian Dumitrescu } 87b77f6600SCristian Dumitrescu 88b77f6600SCristian Dumitrescu /* RETA update */ 89b77f6600SCristian Dumitrescu status = rte_eth_dev_rss_reta_update(port_id, 90b77f6600SCristian Dumitrescu reta_conf, 91b77f6600SCristian Dumitrescu reta_size); 92b77f6600SCristian Dumitrescu 93b77f6600SCristian Dumitrescu return status; 94b77f6600SCristian Dumitrescu } 95b77f6600SCristian Dumitrescu 96b77f6600SCristian Dumitrescu struct link * 97b77f6600SCristian Dumitrescu link_create(struct obj *obj, const char *name, struct link_params *params) 98b77f6600SCristian Dumitrescu { 99b77f6600SCristian Dumitrescu struct rte_eth_dev_info port_info; 100b77f6600SCristian Dumitrescu struct rte_eth_conf port_conf; 101b77f6600SCristian Dumitrescu struct link *link; 102b77f6600SCristian Dumitrescu struct link_params_rss *rss; 103*02d36ef6SCristian Dumitrescu struct rte_mempool *mempool; 104b77f6600SCristian Dumitrescu uint32_t cpu_id, i; 105b77f6600SCristian Dumitrescu int status; 106f31c80f8SCristian Dumitrescu uint16_t port_id = 0; 107b77f6600SCristian Dumitrescu 108b77f6600SCristian Dumitrescu /* Check input params */ 109b77f6600SCristian Dumitrescu if ((name == NULL) || 110b77f6600SCristian Dumitrescu link_find(obj, name) || 111b77f6600SCristian Dumitrescu (params == NULL) || 112b77f6600SCristian Dumitrescu (params->rx.n_queues == 0) || 113b77f6600SCristian Dumitrescu (params->rx.queue_size == 0) || 114b77f6600SCristian Dumitrescu (params->tx.n_queues == 0) || 115b77f6600SCristian Dumitrescu (params->tx.queue_size == 0)) 116b77f6600SCristian Dumitrescu return NULL; 117b77f6600SCristian Dumitrescu 118f31c80f8SCristian Dumitrescu status = rte_eth_dev_get_port_by_name(name, &port_id); 119b77f6600SCristian Dumitrescu if (status) 120b77f6600SCristian Dumitrescu return NULL; 121b77f6600SCristian Dumitrescu 122b77f6600SCristian Dumitrescu if (rte_eth_dev_info_get(port_id, &port_info) != 0) 123b77f6600SCristian Dumitrescu return NULL; 124b77f6600SCristian Dumitrescu 125*02d36ef6SCristian Dumitrescu mempool = rte_mempool_lookup(params->rx.mempool_name); 126*02d36ef6SCristian Dumitrescu if (!mempool) 127b77f6600SCristian Dumitrescu return NULL; 128b77f6600SCristian Dumitrescu 129b77f6600SCristian Dumitrescu rss = params->rx.rss; 130b77f6600SCristian Dumitrescu if (rss) { 131b77f6600SCristian Dumitrescu if ((port_info.reta_size == 0) || 132295968d1SFerruh Yigit (port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512)) 133b77f6600SCristian Dumitrescu return NULL; 134b77f6600SCristian Dumitrescu 135b77f6600SCristian Dumitrescu if ((rss->n_queues == 0) || 136b77f6600SCristian Dumitrescu (rss->n_queues >= LINK_RXQ_RSS_MAX)) 137b77f6600SCristian Dumitrescu return NULL; 138b77f6600SCristian Dumitrescu 139b77f6600SCristian Dumitrescu for (i = 0; i < rss->n_queues; i++) 140b77f6600SCristian Dumitrescu if (rss->queue_id[i] >= port_info.max_rx_queues) 141b77f6600SCristian Dumitrescu return NULL; 142b77f6600SCristian Dumitrescu } 143b77f6600SCristian Dumitrescu 144b77f6600SCristian Dumitrescu /** 145b77f6600SCristian Dumitrescu * Resource create 146b77f6600SCristian Dumitrescu */ 147b77f6600SCristian Dumitrescu /* Port */ 148b77f6600SCristian Dumitrescu memcpy(&port_conf, &port_conf_default, sizeof(port_conf)); 149b77f6600SCristian Dumitrescu if (rss) { 150295968d1SFerruh Yigit port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS; 151b77f6600SCristian Dumitrescu port_conf.rx_adv_conf.rss_conf.rss_hf = 152295968d1SFerruh Yigit (RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) & 153b77f6600SCristian Dumitrescu port_info.flow_type_rss_offloads; 154b77f6600SCristian Dumitrescu } 155b77f6600SCristian Dumitrescu 156b77f6600SCristian Dumitrescu cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id); 157b77f6600SCristian Dumitrescu if (cpu_id == (uint32_t) SOCKET_ID_ANY) 158b77f6600SCristian Dumitrescu cpu_id = 0; 159b77f6600SCristian Dumitrescu 160b77f6600SCristian Dumitrescu status = rte_eth_dev_configure( 161b77f6600SCristian Dumitrescu port_id, 162b77f6600SCristian Dumitrescu params->rx.n_queues, 163b77f6600SCristian Dumitrescu params->tx.n_queues, 164b77f6600SCristian Dumitrescu &port_conf); 165b77f6600SCristian Dumitrescu 166b77f6600SCristian Dumitrescu if (status < 0) 167b77f6600SCristian Dumitrescu return NULL; 168b77f6600SCristian Dumitrescu 169b77f6600SCristian Dumitrescu if (params->promiscuous) { 170b77f6600SCristian Dumitrescu status = rte_eth_promiscuous_enable(port_id); 171b77f6600SCristian Dumitrescu if (status != 0) 172b77f6600SCristian Dumitrescu return NULL; 173b77f6600SCristian Dumitrescu } 174b77f6600SCristian Dumitrescu 175b77f6600SCristian Dumitrescu /* Port RX */ 176b77f6600SCristian Dumitrescu for (i = 0; i < params->rx.n_queues; i++) { 177b77f6600SCristian Dumitrescu status = rte_eth_rx_queue_setup( 178b77f6600SCristian Dumitrescu port_id, 179b77f6600SCristian Dumitrescu i, 180b77f6600SCristian Dumitrescu params->rx.queue_size, 181b77f6600SCristian Dumitrescu cpu_id, 182b77f6600SCristian Dumitrescu NULL, 183*02d36ef6SCristian Dumitrescu mempool); 184b77f6600SCristian Dumitrescu 185b77f6600SCristian Dumitrescu if (status < 0) 186b77f6600SCristian Dumitrescu return NULL; 187b77f6600SCristian Dumitrescu } 188b77f6600SCristian Dumitrescu 189b77f6600SCristian Dumitrescu /* Port TX */ 190b77f6600SCristian Dumitrescu for (i = 0; i < params->tx.n_queues; i++) { 191b77f6600SCristian Dumitrescu status = rte_eth_tx_queue_setup( 192b77f6600SCristian Dumitrescu port_id, 193b77f6600SCristian Dumitrescu i, 194b77f6600SCristian Dumitrescu params->tx.queue_size, 195b77f6600SCristian Dumitrescu cpu_id, 196b77f6600SCristian Dumitrescu NULL); 197b77f6600SCristian Dumitrescu 198b77f6600SCristian Dumitrescu if (status < 0) 199b77f6600SCristian Dumitrescu return NULL; 200b77f6600SCristian Dumitrescu } 201b77f6600SCristian Dumitrescu 202b77f6600SCristian Dumitrescu /* Port start */ 203b77f6600SCristian Dumitrescu status = rte_eth_dev_start(port_id); 204b77f6600SCristian Dumitrescu if (status < 0) 205b77f6600SCristian Dumitrescu return NULL; 206b77f6600SCristian Dumitrescu 207b77f6600SCristian Dumitrescu if (rss) { 208b77f6600SCristian Dumitrescu status = rss_setup(port_id, port_info.reta_size, rss); 209b77f6600SCristian Dumitrescu 210b77f6600SCristian Dumitrescu if (status) { 211b77f6600SCristian Dumitrescu rte_eth_dev_stop(port_id); 212b77f6600SCristian Dumitrescu return NULL; 213b77f6600SCristian Dumitrescu } 214b77f6600SCristian Dumitrescu } 215b77f6600SCristian Dumitrescu 216b77f6600SCristian Dumitrescu /* Port link up */ 217b77f6600SCristian Dumitrescu status = rte_eth_dev_set_link_up(port_id); 218b77f6600SCristian Dumitrescu if ((status < 0) && (status != -ENOTSUP)) { 219b77f6600SCristian Dumitrescu rte_eth_dev_stop(port_id); 220b77f6600SCristian Dumitrescu return NULL; 221b77f6600SCristian Dumitrescu } 222b77f6600SCristian Dumitrescu 223b77f6600SCristian Dumitrescu /* Node allocation */ 224b77f6600SCristian Dumitrescu link = calloc(1, sizeof(struct link)); 225b77f6600SCristian Dumitrescu if (link == NULL) { 226b77f6600SCristian Dumitrescu rte_eth_dev_stop(port_id); 227b77f6600SCristian Dumitrescu return NULL; 228b77f6600SCristian Dumitrescu } 229b77f6600SCristian Dumitrescu 230b77f6600SCristian Dumitrescu /* Node fill in */ 231b77f6600SCristian Dumitrescu strlcpy(link->name, name, sizeof(link->name)); 232b77f6600SCristian Dumitrescu link->port_id = port_id; 233b77f6600SCristian Dumitrescu link->n_rxq = params->rx.n_queues; 234b77f6600SCristian Dumitrescu link->n_txq = params->tx.n_queues; 235b77f6600SCristian Dumitrescu 236b77f6600SCristian Dumitrescu /* Node add to list */ 237b77f6600SCristian Dumitrescu TAILQ_INSERT_TAIL(&obj->link_list, link, node); 238b77f6600SCristian Dumitrescu 239b77f6600SCristian Dumitrescu return link; 240b77f6600SCristian Dumitrescu } 241b77f6600SCristian Dumitrescu 242b77f6600SCristian Dumitrescu int 243b77f6600SCristian Dumitrescu link_is_up(struct obj *obj, const char *name) 244b77f6600SCristian Dumitrescu { 245b77f6600SCristian Dumitrescu struct rte_eth_link link_params; 246b77f6600SCristian Dumitrescu struct link *link; 247b77f6600SCristian Dumitrescu 248b77f6600SCristian Dumitrescu /* Check input params */ 249b77f6600SCristian Dumitrescu if (!obj || !name) 250b77f6600SCristian Dumitrescu return 0; 251b77f6600SCristian Dumitrescu 252b77f6600SCristian Dumitrescu link = link_find(obj, name); 253b77f6600SCristian Dumitrescu if (link == NULL) 254b77f6600SCristian Dumitrescu return 0; 255b77f6600SCristian Dumitrescu 256b77f6600SCristian Dumitrescu /* Resource */ 257b77f6600SCristian Dumitrescu if (rte_eth_link_get(link->port_id, &link_params) < 0) 258b77f6600SCristian Dumitrescu return 0; 259b77f6600SCristian Dumitrescu 260295968d1SFerruh Yigit return (link_params.link_status == RTE_ETH_LINK_DOWN) ? 0 : 1; 261b77f6600SCristian Dumitrescu } 262b77f6600SCristian Dumitrescu 263b77f6600SCristian Dumitrescu struct link * 264b77f6600SCristian Dumitrescu link_find(struct obj *obj, const char *name) 265b77f6600SCristian Dumitrescu { 266b77f6600SCristian Dumitrescu struct link *link; 267b77f6600SCristian Dumitrescu 268b77f6600SCristian Dumitrescu if (!obj || !name) 269b77f6600SCristian Dumitrescu return NULL; 270b77f6600SCristian Dumitrescu 271b77f6600SCristian Dumitrescu TAILQ_FOREACH(link, &obj->link_list, node) 272b77f6600SCristian Dumitrescu if (strcmp(link->name, name) == 0) 273b77f6600SCristian Dumitrescu return link; 274b77f6600SCristian Dumitrescu 275b77f6600SCristian Dumitrescu return NULL; 276b77f6600SCristian Dumitrescu } 277b77f6600SCristian Dumitrescu 278b77f6600SCristian Dumitrescu struct link * 279b77f6600SCristian Dumitrescu link_next(struct obj *obj, struct link *link) 280b77f6600SCristian Dumitrescu { 281b77f6600SCristian Dumitrescu return (link == NULL) ? 282b77f6600SCristian Dumitrescu TAILQ_FIRST(&obj->link_list) : TAILQ_NEXT(link, node); 283b77f6600SCristian Dumitrescu } 284b77f6600SCristian Dumitrescu 285b77f6600SCristian Dumitrescu /* 28677a41301SCristian Dumitrescu * ring 28777a41301SCristian Dumitrescu */ 28877a41301SCristian Dumitrescu struct ring * 28977a41301SCristian Dumitrescu ring_create(struct obj *obj, const char *name, struct ring_params *params) 29077a41301SCristian Dumitrescu { 29177a41301SCristian Dumitrescu struct ring *ring; 29277a41301SCristian Dumitrescu struct rte_ring *r; 29377a41301SCristian Dumitrescu unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ; 29477a41301SCristian Dumitrescu 29577a41301SCristian Dumitrescu /* Check input params */ 29677a41301SCristian Dumitrescu if (!name || ring_find(obj, name) || !params || !params->size) 29777a41301SCristian Dumitrescu return NULL; 29877a41301SCristian Dumitrescu 29977a41301SCristian Dumitrescu /** 30077a41301SCristian Dumitrescu * Resource create 30177a41301SCristian Dumitrescu */ 30277a41301SCristian Dumitrescu r = rte_ring_create( 30377a41301SCristian Dumitrescu name, 30477a41301SCristian Dumitrescu params->size, 30577a41301SCristian Dumitrescu params->numa_node, 30677a41301SCristian Dumitrescu flags); 30777a41301SCristian Dumitrescu if (!r) 30877a41301SCristian Dumitrescu return NULL; 30977a41301SCristian Dumitrescu 31077a41301SCristian Dumitrescu /* Node allocation */ 31177a41301SCristian Dumitrescu ring = calloc(1, sizeof(struct ring)); 31277a41301SCristian Dumitrescu if (!ring) { 31377a41301SCristian Dumitrescu rte_ring_free(r); 31477a41301SCristian Dumitrescu return NULL; 31577a41301SCristian Dumitrescu } 31677a41301SCristian Dumitrescu 31777a41301SCristian Dumitrescu /* Node fill in */ 31877a41301SCristian Dumitrescu strlcpy(ring->name, name, sizeof(ring->name)); 31977a41301SCristian Dumitrescu 32077a41301SCristian Dumitrescu /* Node add to list */ 32177a41301SCristian Dumitrescu TAILQ_INSERT_TAIL(&obj->ring_list, ring, node); 32277a41301SCristian Dumitrescu 32377a41301SCristian Dumitrescu return ring; 32477a41301SCristian Dumitrescu } 32577a41301SCristian Dumitrescu 32677a41301SCristian Dumitrescu struct ring * 32777a41301SCristian Dumitrescu ring_find(struct obj *obj, const char *name) 32877a41301SCristian Dumitrescu { 32977a41301SCristian Dumitrescu struct ring *ring; 33077a41301SCristian Dumitrescu 33177a41301SCristian Dumitrescu if (!obj || !name) 33277a41301SCristian Dumitrescu return NULL; 33377a41301SCristian Dumitrescu 33477a41301SCristian Dumitrescu TAILQ_FOREACH(ring, &obj->ring_list, node) 33577a41301SCristian Dumitrescu if (strcmp(ring->name, name) == 0) 33677a41301SCristian Dumitrescu return ring; 33777a41301SCristian Dumitrescu 33877a41301SCristian Dumitrescu return NULL; 33977a41301SCristian Dumitrescu } 34077a41301SCristian Dumitrescu 34177a41301SCristian Dumitrescu /* 342b77f6600SCristian Dumitrescu * obj 343b77f6600SCristian Dumitrescu */ 344b77f6600SCristian Dumitrescu struct obj * 345b77f6600SCristian Dumitrescu obj_init(void) 346b77f6600SCristian Dumitrescu { 347b77f6600SCristian Dumitrescu struct obj *obj; 348b77f6600SCristian Dumitrescu 349b77f6600SCristian Dumitrescu obj = calloc(1, sizeof(struct obj)); 350b77f6600SCristian Dumitrescu if (!obj) 351b77f6600SCristian Dumitrescu return NULL; 352b77f6600SCristian Dumitrescu 353b77f6600SCristian Dumitrescu TAILQ_INIT(&obj->link_list); 35477a41301SCristian Dumitrescu TAILQ_INIT(&obj->ring_list); 355b77f6600SCristian Dumitrescu 356b77f6600SCristian Dumitrescu return obj; 357b77f6600SCristian Dumitrescu } 358