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 } params; 43 struct rte_swx_port_in_stats stats; 44 struct rte_mbuf **pkts; 45 uint32_t n_pkts; 46 uint32_t pos; 47 }; 48 49 static void 50 source_free(void *port) 51 { 52 struct source *p = port; 53 uint32_t i; 54 55 if (!p) 56 return; 57 58 for (i = 0; i < p->n_pkts; i++) 59 rte_pktmbuf_free(p->pkts[i]); 60 61 free(p->pkts); 62 63 free(p); 64 } 65 66 static void * 67 source_create(void *args) 68 { 69 char pcap_errbuf[PCAP_ERRBUF_SIZE]; 70 struct rte_swx_port_source_params *params = args; 71 struct source *p = NULL; 72 pcap_t *f = NULL; 73 uint32_t n_pkts_max, i; 74 75 /* Check input arguments. */ 76 CHECK(params); 77 CHECK(params->pool); 78 CHECK(params->file_name && params->file_name[0]); 79 n_pkts_max = params->n_pkts_max ? 80 params->n_pkts_max : 81 RTE_SWX_PORT_SOURCE_PKTS_MAX; 82 83 /* Resource allocation. */ 84 f = pcap_open_offline(params->file_name, pcap_errbuf); 85 if (!f) 86 goto error; 87 88 p = calloc(1, sizeof(struct source)); 89 if (!p) 90 goto error; 91 92 p->pkts = calloc(n_pkts_max, sizeof(struct rte_mbuf *)); 93 if (!p->pkts) 94 goto error; 95 96 /* Initialization. */ 97 p->params.pool = params->pool; 98 99 /* PCAP file. */ 100 for (i = 0; i < n_pkts_max; i++) { 101 struct pcap_pkthdr pcap_pkthdr; 102 const uint8_t *pcap_pktdata; 103 struct rte_mbuf *m; 104 uint8_t *m_data; 105 106 /* Read new packet from PCAP file. */ 107 pcap_pktdata = pcap_next(f, &pcap_pkthdr); 108 if (!pcap_pktdata) 109 break; 110 111 /* Allocate new buffer from pool. */ 112 m = rte_pktmbuf_alloc(params->pool); 113 if (!m) 114 goto error; 115 m_data = rte_pktmbuf_mtod(m, uint8_t *); 116 117 rte_memcpy(m_data, pcap_pktdata, pcap_pkthdr.caplen); 118 m->data_len = pcap_pkthdr.caplen; 119 m->pkt_len = pcap_pkthdr.caplen; 120 121 p->pkts[p->n_pkts] = m; 122 p->n_pkts++; 123 } 124 125 if (!p->n_pkts) 126 goto error; 127 128 pcap_close(f); 129 return p; 130 131 error: 132 source_free(p); 133 if (f) 134 pcap_close(f); 135 return NULL; 136 } 137 138 static int 139 source_pkt_rx(void *port, struct rte_swx_pkt *pkt) 140 { 141 struct source *p = port; 142 struct rte_mbuf *m_dst, *m_src; 143 uint8_t *m_dst_data, *m_src_data; 144 145 /* m_src identification. */ 146 m_src = p->pkts[p->pos]; 147 m_src_data = rte_pktmbuf_mtod(m_src, uint8_t *); 148 149 /* m_dst allocation from pool. */ 150 m_dst = rte_pktmbuf_alloc(p->params.pool); 151 if (!m_dst) 152 return 0; 153 154 /* m_dst initialization. */ 155 m_dst->data_len = m_src->data_len; 156 m_dst->pkt_len = m_src->pkt_len; 157 m_dst->data_off = m_src->data_off; 158 159 m_dst_data = rte_pktmbuf_mtod(m_dst, uint8_t *); 160 rte_memcpy(m_dst_data, m_src_data, m_src->data_len); 161 162 /* pkt initialization. */ 163 pkt->handle = m_dst; 164 pkt->pkt = m_dst->buf_addr; 165 pkt->offset = m_dst->data_off; 166 pkt->length = m_dst->pkt_len; 167 168 TRACE("[Source port] Pkt RX (%u bytes at offset %u)\n", 169 pkt->length, 170 pkt->offset); 171 if (TRACE_LEVEL) 172 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 173 174 /* port stats update. */ 175 p->stats.n_pkts++; 176 p->stats.n_bytes += pkt->length; 177 178 /* m_src next. */ 179 p->pos++; 180 if (p->pos == p->n_pkts) 181 p->pos = 0; 182 183 return 1; 184 } 185 186 static void 187 source_stats_read(void *port, struct rte_swx_port_in_stats *stats) 188 { 189 struct source *p = port; 190 191 if (!p || !stats) 192 return; 193 194 memcpy(stats, &p->stats, sizeof(p->stats)); 195 } 196 197 struct rte_swx_port_in_ops rte_swx_port_source_ops = { 198 .create = source_create, 199 .free = source_free, 200 .pkt_rx = source_pkt_rx, 201 .stats_read = source_stats_read, 202 }; 203 204 #else 205 206 struct rte_swx_port_in_ops rte_swx_port_source_ops = { 207 .create = NULL, 208 .free = NULL, 209 .pkt_rx = NULL, 210 .stats_read = NULL, 211 }; 212 213 #endif 214 215 /* 216 * Port SINK 217 */ 218 struct sink { 219 struct rte_swx_port_out_stats stats; 220 221 #ifdef RTE_PORT_PCAP 222 pcap_t *f_pcap; 223 pcap_dumper_t *f_dump; 224 #endif 225 }; 226 227 static void 228 sink_free(void *port) 229 { 230 struct sink *p = port; 231 232 if (!p) 233 return; 234 235 #ifdef RTE_PORT_PCAP 236 if (p->f_dump) 237 pcap_dump_close(p->f_dump); 238 if (p->f_pcap) 239 pcap_close(p->f_pcap); 240 #endif 241 242 free(p); 243 } 244 245 static void * 246 sink_create(void *args __rte_unused) 247 { 248 struct sink *p; 249 250 /* Memory allocation. */ 251 p = calloc(1, sizeof(struct sink)); 252 if (!p) 253 goto error; 254 255 #ifdef RTE_PORT_PCAP 256 if (args) { 257 struct rte_swx_port_sink_params *params = args; 258 259 if (params->file_name && params->file_name[0]) { 260 p->f_pcap = pcap_open_dead(DLT_EN10MB, 65535); 261 if (!p->f_pcap) 262 goto error; 263 264 p->f_dump = pcap_dump_open(p->f_pcap, 265 params->file_name); 266 if (!p->f_dump) 267 goto error; 268 } 269 } 270 #endif 271 272 return p; 273 274 error: 275 sink_free(p); 276 return NULL; 277 } 278 279 static void 280 sink_pkt_tx(void *port, struct rte_swx_pkt *pkt) 281 { 282 struct sink *p = port; 283 struct rte_mbuf *m = pkt->handle; 284 285 TRACE("[Sink port] Pkt TX (%u bytes at offset %u)\n", 286 pkt->length, 287 pkt->offset); 288 if (TRACE_LEVEL) 289 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); 290 291 m->pkt_len = pkt->length; 292 m->data_len = (uint16_t)pkt->length; 293 m->data_off = (uint16_t)pkt->offset; 294 295 p->stats.n_pkts++; 296 p->stats.n_bytes += pkt->length; 297 298 #ifdef RTE_PORT_PCAP 299 if (p->f_dump) { 300 struct pcap_pkthdr pcap_pkthdr; 301 uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *); 302 303 pcap_pkthdr.len = m->pkt_len; 304 pcap_pkthdr.caplen = m->data_len; 305 gettimeofday(&pcap_pkthdr.ts, NULL); 306 307 pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data); 308 pcap_dump_flush(p->f_dump); 309 } 310 #endif 311 312 rte_pktmbuf_free(m); 313 } 314 315 static void 316 sink_stats_read(void *port, struct rte_swx_port_out_stats *stats) 317 { 318 struct sink *p = port; 319 320 if (!p || !stats) 321 return; 322 323 memcpy(stats, &p->stats, sizeof(p->stats)); 324 } 325 326 /* 327 * Summary of port operations 328 */ 329 struct rte_swx_port_out_ops rte_swx_port_sink_ops = { 330 .create = sink_create, 331 .free = sink_free, 332 .pkt_tx = sink_pkt_tx, 333 .flush = NULL, 334 .stats_read = sink_stats_read, 335 }; 336