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_mbuf.h> 17 #include <rte_ethdev.h> 18 #include <rte_swx_ctl.h> 19 20 #include "obj.h" 21 22 /* 23 * link 24 */ 25 TAILQ_HEAD(link_list, link); 26 27 /* 28 * obj 29 */ 30 struct obj { 31 struct link_list link_list; 32 }; 33 34 /* 35 * link 36 */ 37 static struct rte_eth_conf port_conf_default = { 38 .link_speeds = 0, 39 .rxmode = { 40 .mq_mode = RTE_ETH_MQ_RX_NONE, 41 .mtu = 9000 - (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN), /* Jumbo frame MTU */ 42 }, 43 .rx_adv_conf = { 44 .rss_conf = { 45 .rss_key = NULL, 46 .rss_key_len = 40, 47 .rss_hf = 0, 48 }, 49 }, 50 .txmode = { 51 .mq_mode = RTE_ETH_MQ_TX_NONE, 52 }, 53 .lpbk_mode = 0, 54 }; 55 56 #define RETA_CONF_SIZE (RTE_ETH_RSS_RETA_SIZE_512 / RTE_ETH_RETA_GROUP_SIZE) 57 58 static int 59 rss_setup(uint16_t port_id, 60 uint16_t reta_size, 61 struct link_params_rss *rss) 62 { 63 struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE]; 64 uint32_t i; 65 int status; 66 67 /* RETA setting */ 68 memset(reta_conf, 0, sizeof(reta_conf)); 69 70 for (i = 0; i < reta_size; i++) 71 reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX; 72 73 for (i = 0; i < reta_size; i++) { 74 uint32_t reta_id = i / RTE_ETH_RETA_GROUP_SIZE; 75 uint32_t reta_pos = i % RTE_ETH_RETA_GROUP_SIZE; 76 uint32_t rss_qs_pos = i % rss->n_queues; 77 78 reta_conf[reta_id].reta[reta_pos] = 79 (uint16_t) rss->queue_id[rss_qs_pos]; 80 } 81 82 /* RETA update */ 83 status = rte_eth_dev_rss_reta_update(port_id, 84 reta_conf, 85 reta_size); 86 87 return status; 88 } 89 90 struct link * 91 link_create(struct obj *obj, const char *name, struct link_params *params) 92 { 93 struct rte_eth_dev_info port_info; 94 struct rte_eth_conf port_conf; 95 struct link *link; 96 struct link_params_rss *rss; 97 struct rte_mempool *mempool; 98 uint32_t cpu_id, i; 99 int status; 100 uint16_t port_id = 0; 101 102 /* Check input params */ 103 if ((name == NULL) || 104 link_find(obj, name) || 105 (params == NULL) || 106 (params->rx.n_queues == 0) || 107 (params->rx.queue_size == 0) || 108 (params->tx.n_queues == 0) || 109 (params->tx.queue_size == 0)) 110 return NULL; 111 112 status = rte_eth_dev_get_port_by_name(name, &port_id); 113 if (status) 114 return NULL; 115 116 if (rte_eth_dev_info_get(port_id, &port_info) != 0) 117 return NULL; 118 119 mempool = rte_mempool_lookup(params->rx.mempool_name); 120 if (!mempool) 121 return NULL; 122 123 rss = params->rx.rss; 124 if (rss) { 125 if ((port_info.reta_size == 0) || 126 (port_info.reta_size > RTE_ETH_RSS_RETA_SIZE_512)) 127 return NULL; 128 129 if ((rss->n_queues == 0) || 130 (rss->n_queues >= LINK_RXQ_RSS_MAX)) 131 return NULL; 132 133 for (i = 0; i < rss->n_queues; i++) 134 if (rss->queue_id[i] >= port_info.max_rx_queues) 135 return NULL; 136 } 137 138 /** 139 * Resource create 140 */ 141 /* Port */ 142 memcpy(&port_conf, &port_conf_default, sizeof(port_conf)); 143 if (rss) { 144 port_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS; 145 port_conf.rx_adv_conf.rss_conf.rss_hf = 146 (RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) & 147 port_info.flow_type_rss_offloads; 148 } 149 150 cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id); 151 if (cpu_id == (uint32_t) SOCKET_ID_ANY) 152 cpu_id = 0; 153 154 status = rte_eth_dev_configure( 155 port_id, 156 params->rx.n_queues, 157 params->tx.n_queues, 158 &port_conf); 159 160 if (status < 0) 161 return NULL; 162 163 if (params->promiscuous) { 164 status = rte_eth_promiscuous_enable(port_id); 165 if (status != 0) 166 return NULL; 167 } 168 169 /* Port RX */ 170 for (i = 0; i < params->rx.n_queues; i++) { 171 status = rte_eth_rx_queue_setup( 172 port_id, 173 i, 174 params->rx.queue_size, 175 cpu_id, 176 NULL, 177 mempool); 178 179 if (status < 0) 180 return NULL; 181 } 182 183 /* Port TX */ 184 for (i = 0; i < params->tx.n_queues; i++) { 185 status = rte_eth_tx_queue_setup( 186 port_id, 187 i, 188 params->tx.queue_size, 189 cpu_id, 190 NULL); 191 192 if (status < 0) 193 return NULL; 194 } 195 196 /* Port start */ 197 status = rte_eth_dev_start(port_id); 198 if (status < 0) 199 return NULL; 200 201 if (rss) { 202 status = rss_setup(port_id, port_info.reta_size, rss); 203 204 if (status) { 205 rte_eth_dev_stop(port_id); 206 return NULL; 207 } 208 } 209 210 /* Port link up */ 211 status = rte_eth_dev_set_link_up(port_id); 212 if ((status < 0) && (status != -ENOTSUP)) { 213 rte_eth_dev_stop(port_id); 214 return NULL; 215 } 216 217 /* Node allocation */ 218 link = calloc(1, sizeof(struct link)); 219 if (link == NULL) { 220 rte_eth_dev_stop(port_id); 221 return NULL; 222 } 223 224 /* Node fill in */ 225 strlcpy(link->name, name, sizeof(link->name)); 226 link->port_id = port_id; 227 link->n_rxq = params->rx.n_queues; 228 link->n_txq = params->tx.n_queues; 229 230 /* Node add to list */ 231 TAILQ_INSERT_TAIL(&obj->link_list, link, node); 232 233 return link; 234 } 235 236 int 237 link_is_up(struct obj *obj, const char *name) 238 { 239 struct rte_eth_link link_params; 240 struct link *link; 241 242 /* Check input params */ 243 if (!obj || !name) 244 return 0; 245 246 link = link_find(obj, name); 247 if (link == NULL) 248 return 0; 249 250 /* Resource */ 251 if (rte_eth_link_get(link->port_id, &link_params) < 0) 252 return 0; 253 254 return (link_params.link_status == RTE_ETH_LINK_DOWN) ? 0 : 1; 255 } 256 257 struct link * 258 link_find(struct obj *obj, const char *name) 259 { 260 struct link *link; 261 262 if (!obj || !name) 263 return NULL; 264 265 TAILQ_FOREACH(link, &obj->link_list, node) 266 if (strcmp(link->name, name) == 0) 267 return link; 268 269 return NULL; 270 } 271 272 struct link * 273 link_next(struct obj *obj, struct link *link) 274 { 275 return (link == NULL) ? 276 TAILQ_FIRST(&obj->link_list) : TAILQ_NEXT(link, node); 277 } 278 279 /* 280 * obj 281 */ 282 struct obj * 283 obj_init(void) 284 { 285 struct obj *obj; 286 287 obj = calloc(1, sizeof(struct obj)); 288 if (!obj) 289 return NULL; 290 291 TAILQ_INIT(&obj->link_list); 292 293 return obj; 294 } 295