1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 #include <string.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <stdint.h> 8 9 #include <rte_mbuf.h> 10 #include <rte_ethdev.h> 11 #include <rte_hexdump.h> 12 13 #include "rte_swx_port_ethdev.h" 14 15 #define CHECK(condition) \ 16 do { \ 17 if (!(condition)) \ 18 return NULL; \ 19 } while (0) 20 21 #ifndef TRACE_LEVEL 22 #define TRACE_LEVEL 0 23 #endif 24 25 #if TRACE_LEVEL 26 #define TRACE(...) printf(__VA_ARGS__) 27 #else 28 #define TRACE(...) 29 #endif 30 31 /* 32 * Port ETHDEV Reader 33 */ 34 struct reader { 35 struct { 36 uint16_t port_id; 37 uint16_t queue_id; 38 uint32_t burst_size; 39 } params; 40 struct rte_swx_port_in_stats stats; 41 struct rte_mbuf **pkts; 42 int n_pkts; 43 int pos; 44 }; 45 46 static void * 47 reader_create(void *args) 48 { 49 struct rte_eth_dev_info info; 50 struct rte_swx_port_ethdev_reader_params *params = args; 51 struct reader *p; 52 int status; 53 uint16_t port_id; 54 55 /* Check input parameters. */ 56 CHECK(params); 57 58 CHECK(params->dev_name); 59 status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id); 60 CHECK(!status); 61 62 status = rte_eth_dev_info_get(port_id, &info); 63 CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_rx_queues)); 64 65 CHECK(params->burst_size); 66 67 /* Memory allocation. */ 68 p = calloc(1, sizeof(struct reader)); 69 CHECK(p); 70 71 p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *)); 72 if (!p->pkts) { 73 free(p); 74 CHECK(0); 75 } 76 77 /* Initialization. */ 78 p->params.port_id = port_id; 79 p->params.queue_id = params->queue_id; 80 p->params.burst_size = params->burst_size; 81 82 return p; 83 } 84 85 static int 86 reader_pkt_rx(void *port, struct rte_swx_pkt *pkt) 87 { 88 struct reader *p = port; 89 struct rte_mbuf *m; 90 91 if (p->pos == p->n_pkts) { 92 int n_pkts; 93 94 n_pkts = rte_eth_rx_burst(p->params.port_id, 95 p->params.queue_id, 96 p->pkts, 97 p->params.burst_size); 98 if (!n_pkts) { 99 p->stats.n_empty++; 100 return 0; 101 } 102 103 TRACE("[Ethdev RX port %u queue %u] %d packets in\n", 104 (uint32_t)p->params.port_id, 105 (uint32_t)p->params.queue_id, 106 n_pkts); 107 108 p->n_pkts = n_pkts; 109 p->pos = 0; 110 } 111 112 m = p->pkts[p->pos++]; 113 pkt->handle = m; 114 pkt->pkt = m->buf_addr; 115 pkt->offset = m->data_off; 116 pkt->length = m->pkt_len; 117 118 TRACE("[Ethdev RX port %u queue %u] Pkt %d (%u bytes at offset %u)\n", 119 (uint32_t)p->params.port_id, 120 (uint32_t)p->params.queue_id, 121 p->pos - 1, 122 pkt->length, 123 pkt->offset); 124 if (TRACE_LEVEL) 125 rte_hexdump(stdout, 126 NULL, 127 &((uint8_t *)m->buf_addr)[m->data_off], 128 m->data_len); 129 130 p->stats.n_pkts++; 131 p->stats.n_bytes += pkt->length; 132 133 return 1; 134 } 135 136 static void 137 reader_free(void *port) 138 { 139 struct reader *p = port; 140 int i; 141 142 if (!p) 143 return; 144 145 for (i = 0; i < p->n_pkts; i++) { 146 struct rte_mbuf *pkt = p->pkts[i]; 147 148 rte_pktmbuf_free(pkt); 149 } 150 151 free(p->pkts); 152 free(p); 153 } 154 155 static void 156 reader_stats_read(void *port, struct rte_swx_port_in_stats *stats) 157 { 158 struct reader *p = port; 159 160 memcpy(stats, &p->stats, sizeof(p->stats)); 161 } 162 163 /* 164 * Port ETHDEV Writer 165 */ 166 struct writer { 167 struct { 168 uint16_t port_id; 169 uint16_t queue_id; 170 uint32_t burst_size; 171 } params; 172 struct rte_swx_port_out_stats stats; 173 174 struct rte_mbuf **pkts; 175 int n_pkts; 176 }; 177 178 static void * 179 writer_create(void *args) 180 { 181 struct rte_eth_dev_info info; 182 struct rte_swx_port_ethdev_writer_params *params = args; 183 struct writer *p; 184 int status; 185 uint16_t port_id; 186 187 /* Check input parameters. */ 188 CHECK(params); 189 190 CHECK(params->dev_name); 191 status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id); 192 CHECK(!status); 193 194 status = rte_eth_dev_info_get(port_id, &info); 195 CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_tx_queues)); 196 197 CHECK(params->burst_size); 198 199 /* Memory allocation. */ 200 p = calloc(1, sizeof(struct writer)); 201 CHECK(p); 202 203 p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *)); 204 if (!p->pkts) { 205 free(p); 206 CHECK(0); 207 } 208 209 /* Initialization. */ 210 p->params.port_id = port_id; 211 p->params.queue_id = params->queue_id; 212 p->params.burst_size = params->burst_size; 213 214 return p; 215 } 216 217 static void 218 __writer_flush(struct writer *p) 219 { 220 int n_pkts; 221 222 for (n_pkts = 0; ; ) { 223 n_pkts += rte_eth_tx_burst(p->params.port_id, 224 p->params.queue_id, 225 p->pkts + n_pkts, 226 p->n_pkts - n_pkts); 227 228 TRACE("[Ethdev TX port %u queue %u] %d packets out\n", 229 (uint32_t)p->params.port_id, 230 (uint32_t)p->params.queue_id, 231 n_pkts); 232 233 if (n_pkts == p->n_pkts) 234 break; 235 } 236 237 p->n_pkts = 0; 238 } 239 240 static void 241 writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) 242 { 243 struct writer *p = port; 244 struct rte_mbuf *m = pkt->handle; 245 246 TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u)\n", 247 (uint32_t)p->params.port_id, 248 (uint32_t)p->params.queue_id, 249 p->n_pkts - 1, 250 pkt->length, 251 pkt->offset); 252 if (TRACE_LEVEL) 253 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 254 255 m->pkt_len = pkt->length; 256 m->data_len = (uint16_t)pkt->length; 257 m->data_off = (uint16_t)pkt->offset; 258 259 p->stats.n_pkts++; 260 p->stats.n_bytes += pkt->length; 261 262 p->pkts[p->n_pkts++] = m; 263 if (p->n_pkts == (int)p->params.burst_size) 264 __writer_flush(p); 265 } 266 267 static void 268 writer_flush(void *port) 269 { 270 struct writer *p = port; 271 272 if (p->n_pkts) 273 __writer_flush(p); 274 } 275 276 static void 277 writer_free(void *port) 278 { 279 struct writer *p = port; 280 281 if (!p) 282 return; 283 284 writer_flush(p); 285 free(p->pkts); 286 free(port); 287 } 288 289 static void 290 writer_stats_read(void *port, struct rte_swx_port_out_stats *stats) 291 { 292 struct writer *p = port; 293 294 memcpy(stats, &p->stats, sizeof(p->stats)); 295 } 296 297 /* 298 * Summary of port operations 299 */ 300 struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops = { 301 .create = reader_create, 302 .free = reader_free, 303 .pkt_rx = reader_pkt_rx, 304 .stats_read = reader_stats_read, 305 }; 306 307 struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = { 308 .create = writer_create, 309 .free = writer_free, 310 .pkt_tx = writer_pkt_tx, 311 .flush = writer_flush, 312 .stats_read = writer_stats_read, 313 }; 314