1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 #include <stdint.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #ifdef RTE_PORT_PCAP 8 #include <pcap.h> 9 #endif 10 #include <sys/time.h> 11 12 #include <rte_common.h> 13 #include <rte_mbuf.h> 14 #include <rte_hexdump.h> 15 16 #include "rte_swx_port_source_sink.h" 17 18 #define CHECK(condition) \ 19 do { \ 20 if (!(condition)) \ 21 return NULL; \ 22 } while (0) 23 24 #ifndef TRACE_LEVEL 25 #define TRACE_LEVEL 0 26 #endif 27 28 #if TRACE_LEVEL 29 #define TRACE(...) printf(__VA_ARGS__) 30 #else 31 #define TRACE(...) 32 #endif 33 34 /* 35 * Port SOURCE 36 */ 37 #ifdef RTE_PORT_PCAP 38 39 struct source { 40 struct { 41 struct rte_mempool *pool; 42 uint64_t n_loops; 43 } params; 44 struct rte_swx_port_in_stats stats; 45 struct rte_mbuf **pkts; 46 uint32_t n_pkts; 47 uint32_t pos; 48 }; 49 50 static void 51 source_free(void *port) 52 { 53 struct source *p = port; 54 uint32_t i; 55 56 if (!p) 57 return; 58 59 for (i = 0; i < p->n_pkts; i++) 60 rte_pktmbuf_free(p->pkts[i]); 61 62 free(p->pkts); 63 64 free(p); 65 } 66 67 static void * 68 source_create(void *args) 69 { 70 char pcap_errbuf[PCAP_ERRBUF_SIZE]; 71 struct rte_swx_port_source_params *params = args; 72 struct source *p = NULL; 73 pcap_t *f = NULL; 74 uint32_t n_pkts_max, i; 75 76 /* Check input arguments. */ 77 CHECK(params); 78 CHECK(params->pool); 79 CHECK(params->file_name && params->file_name[0]); 80 n_pkts_max = params->n_pkts_max ? 81 params->n_pkts_max : 82 RTE_SWX_PORT_SOURCE_PKTS_MAX; 83 84 /* Resource allocation. */ 85 f = pcap_open_offline(params->file_name, pcap_errbuf); 86 if (!f) 87 goto error; 88 89 p = calloc(1, sizeof(struct source)); 90 if (!p) 91 goto error; 92 93 p->pkts = calloc(n_pkts_max, sizeof(struct rte_mbuf *)); 94 if (!p->pkts) 95 goto error; 96 97 /* Initialization. */ 98 p->params.pool = params->pool; 99 100 p->params.n_loops = params->n_loops ? params->n_loops : UINT64_MAX; 101 102 /* PCAP file. */ 103 for (i = 0; i < n_pkts_max; i++) { 104 struct pcap_pkthdr pcap_pkthdr; 105 const uint8_t *pcap_pktdata; 106 struct rte_mbuf *m; 107 uint8_t *m_data; 108 109 /* Read new packet from PCAP file. */ 110 pcap_pktdata = pcap_next(f, &pcap_pkthdr); 111 if (!pcap_pktdata) 112 break; 113 114 /* Allocate new buffer from pool. */ 115 m = rte_pktmbuf_alloc(params->pool); 116 if (!m) 117 goto error; 118 m_data = rte_pktmbuf_mtod(m, uint8_t *); 119 120 rte_memcpy(m_data, pcap_pktdata, pcap_pkthdr.caplen); 121 m->data_len = pcap_pkthdr.caplen; 122 m->pkt_len = pcap_pkthdr.caplen; 123 124 p->pkts[p->n_pkts] = m; 125 p->n_pkts++; 126 } 127 128 if (!p->n_pkts) 129 goto error; 130 131 pcap_close(f); 132 return p; 133 134 error: 135 source_free(p); 136 if (f) 137 pcap_close(f); 138 return NULL; 139 } 140 141 static int 142 source_pkt_rx(void *port, struct rte_swx_pkt *pkt) 143 { 144 struct source *p = port; 145 struct rte_mbuf *m_dst, *m_src; 146 uint8_t *m_dst_data, *m_src_data; 147 148 if (!p->params.n_loops) 149 return 0; 150 /* m_src identification. */ 151 m_src = p->pkts[p->pos]; 152 m_src_data = rte_pktmbuf_mtod(m_src, uint8_t *); 153 154 /* m_dst allocation from pool. */ 155 m_dst = rte_pktmbuf_alloc(p->params.pool); 156 if (!m_dst) 157 return 0; 158 159 /* m_dst initialization. */ 160 m_dst->data_len = m_src->data_len; 161 m_dst->pkt_len = m_src->pkt_len; 162 m_dst->data_off = m_src->data_off; 163 164 m_dst_data = rte_pktmbuf_mtod(m_dst, uint8_t *); 165 rte_memcpy(m_dst_data, m_src_data, m_src->data_len); 166 167 /* pkt initialization. */ 168 pkt->handle = m_dst; 169 pkt->pkt = m_dst->buf_addr; 170 pkt->offset = m_dst->data_off; 171 pkt->length = m_dst->pkt_len; 172 173 TRACE("[Source port] Pkt RX (%u bytes at offset %u)\n", 174 pkt->length, 175 pkt->offset); 176 if (TRACE_LEVEL) 177 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 178 179 /* port stats update. */ 180 p->stats.n_pkts++; 181 p->stats.n_bytes += pkt->length; 182 183 /* m_src next. */ 184 p->pos++; 185 if (p->pos == p->n_pkts) { 186 p->pos = 0; 187 p->params.n_loops--; 188 } 189 190 return 1; 191 } 192 193 static void 194 source_stats_read(void *port, struct rte_swx_port_in_stats *stats) 195 { 196 struct source *p = port; 197 198 if (!p || !stats) 199 return; 200 201 memcpy(stats, &p->stats, sizeof(p->stats)); 202 } 203 204 struct rte_swx_port_in_ops rte_swx_port_source_ops = { 205 .create = source_create, 206 .free = source_free, 207 .pkt_rx = source_pkt_rx, 208 .stats_read = source_stats_read, 209 }; 210 211 #else 212 213 struct rte_swx_port_in_ops rte_swx_port_source_ops = { 214 .create = NULL, 215 .free = NULL, 216 .pkt_rx = NULL, 217 .stats_read = NULL, 218 }; 219 220 #endif 221 222 /* 223 * Port SINK 224 */ 225 struct sink { 226 struct rte_swx_port_out_stats stats; 227 228 #ifdef RTE_PORT_PCAP 229 pcap_t *f_pcap; 230 pcap_dumper_t *f_dump; 231 #endif 232 }; 233 234 static void 235 sink_free(void *port) 236 { 237 struct sink *p = port; 238 239 if (!p) 240 return; 241 242 #ifdef RTE_PORT_PCAP 243 if (p->f_dump) 244 pcap_dump_close(p->f_dump); 245 if (p->f_pcap) 246 pcap_close(p->f_pcap); 247 #endif 248 249 free(p); 250 } 251 252 static void * 253 sink_create(void *args __rte_unused) 254 { 255 struct sink *p; 256 257 /* Memory allocation. */ 258 p = calloc(1, sizeof(struct sink)); 259 if (!p) 260 goto error; 261 262 #ifdef RTE_PORT_PCAP 263 if (args) { 264 struct rte_swx_port_sink_params *params = args; 265 266 if (params->file_name && params->file_name[0]) { 267 p->f_pcap = pcap_open_dead(DLT_EN10MB, 65535); 268 if (!p->f_pcap) 269 goto error; 270 271 p->f_dump = pcap_dump_open(p->f_pcap, 272 params->file_name); 273 if (!p->f_dump) 274 goto error; 275 } 276 } 277 #endif 278 279 return p; 280 281 error: 282 sink_free(p); 283 return NULL; 284 } 285 286 static void 287 sink_pkt_tx(void *port, struct rte_swx_pkt *pkt) 288 { 289 struct sink *p = port; 290 struct rte_mbuf *m = pkt->handle; 291 292 TRACE("[Sink port] Pkt TX (%u bytes at offset %u)\n", 293 pkt->length, 294 pkt->offset); 295 if (TRACE_LEVEL) 296 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 297 298 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); 299 m->pkt_len = pkt->length; 300 m->data_off = (uint16_t)pkt->offset; 301 302 p->stats.n_pkts++; 303 p->stats.n_bytes += pkt->length; 304 305 #ifdef RTE_PORT_PCAP 306 if (p->f_dump) { 307 struct pcap_pkthdr pcap_pkthdr; 308 uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *); 309 310 pcap_pkthdr.len = m->pkt_len; 311 pcap_pkthdr.caplen = m->data_len; 312 gettimeofday(&pcap_pkthdr.ts, NULL); 313 314 pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data); 315 pcap_dump_flush(p->f_dump); 316 } 317 #endif 318 319 rte_pktmbuf_free(m); 320 } 321 322 static void 323 __sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length __rte_unused) 324 { 325 struct sink *p = port; 326 struct rte_mbuf *m = pkt->handle; 327 328 TRACE("[Sink port] Pkt TX (%u bytes at offset %u) (clone)\n", 329 pkt->length, 330 pkt->offset); 331 if (TRACE_LEVEL) 332 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 333 334 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); 335 m->pkt_len = pkt->length; 336 m->data_off = (uint16_t)pkt->offset; 337 338 p->stats.n_pkts++; 339 p->stats.n_bytes += pkt->length; 340 p->stats.n_pkts_clone++; 341 342 #ifdef RTE_PORT_PCAP 343 if (p->f_dump) { 344 struct pcap_pkthdr pcap_pkthdr; 345 uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *); 346 347 pcap_pkthdr.len = m->pkt_len; 348 pcap_pkthdr.caplen = RTE_MIN(m->data_len, truncation_length); 349 gettimeofday(&pcap_pkthdr.ts, NULL); 350 351 pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data); 352 pcap_dump_flush(p->f_dump); 353 } 354 #endif 355 } 356 357 static void 358 sink_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt) 359 { 360 __sink_pkt_clone_tx(port, pkt, UINT32_MAX); 361 } 362 363 static void 364 sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length) 365 { 366 __sink_pkt_clone_tx(port, pkt, truncation_length); 367 } 368 369 static void 370 sink_stats_read(void *port, struct rte_swx_port_out_stats *stats) 371 { 372 struct sink *p = port; 373 374 if (!p || !stats) 375 return; 376 377 memcpy(stats, &p->stats, sizeof(p->stats)); 378 } 379 380 /* 381 * Summary of port operations 382 */ 383 struct rte_swx_port_out_ops rte_swx_port_sink_ops = { 384 .create = sink_create, 385 .free = sink_free, 386 .pkt_tx = sink_pkt_tx, 387 .pkt_fast_clone_tx = sink_pkt_fast_clone_tx, 388 .pkt_clone_tx = sink_pkt_clone_tx, 389 .flush = NULL, 390 .stats_read = sink_stats_read, 391 }; 392