+#ifdef RTE_PORT_PCAP
+
+static int
+pcap_source_load(struct rte_port_source *port,
+ const char *file_name,
+ uint32_t n_bytes_per_pkt,
+ int socket_id)
+{
+ uint32_t n_pkts = 0;
+ uint32_t i;
+ uint32_t *pkt_len_aligns = NULL;
+ size_t total_buff_len = 0;
+ pcap_t *pcap_handle;
+ char pcap_errbuf[PCAP_ERRBUF_SIZE];
+ uint32_t max_len;
+ struct pcap_pkthdr pcap_hdr;
+ const uint8_t *pkt;
+ uint8_t *buff = NULL;
+ uint32_t pktmbuf_maxlen = (uint32_t)
+ (rte_pktmbuf_data_room_size(port->mempool) -
+ RTE_PKTMBUF_HEADROOM);
+
+ if (n_bytes_per_pkt == 0)
+ max_len = pktmbuf_maxlen;
+ else
+ max_len = RTE_MIN(n_bytes_per_pkt, pktmbuf_maxlen);
+
+ /* first time open, get packet number */
+ pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
+ if (pcap_handle == NULL) {
+ RTE_LOG(ERR, PORT, "Failed to open pcap file "
+ "'%s' for reading\n", file_name);
+ goto error_exit;
+ }
+
+ while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL)
+ n_pkts++;
+
+ pcap_close(pcap_handle);
+
+ port->pkt_len = rte_zmalloc_socket("PCAP",
+ (sizeof(*port->pkt_len) * n_pkts), 0, socket_id);
+ if (port->pkt_len == NULL) {
+ RTE_LOG(ERR, PORT, "No enough memory\n");
+ goto error_exit;
+ }
+
+ pkt_len_aligns = rte_malloc("PCAP",
+ (sizeof(*pkt_len_aligns) * n_pkts), 0);
+ if (pkt_len_aligns == NULL) {
+ RTE_LOG(ERR, PORT, "No enough memory\n");
+ goto error_exit;
+ }
+
+ port->pkts = rte_zmalloc_socket("PCAP",
+ (sizeof(*port->pkts) * n_pkts), 0, socket_id);
+ if (port->pkts == NULL) {
+ RTE_LOG(ERR, PORT, "No enough memory\n");
+ goto error_exit;
+ }
+
+ /* open 2nd time, get pkt_len */
+ pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
+ if (pcap_handle == NULL) {
+ RTE_LOG(ERR, PORT, "Failed to open pcap file "
+ "'%s' for reading\n", file_name);
+ goto error_exit;
+ }
+
+ for (i = 0; i < n_pkts; i++) {
+ pkt = pcap_next(pcap_handle, &pcap_hdr);
+ port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len);
+ pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP(
+ port->pkt_len[i]);
+ total_buff_len += pkt_len_aligns[i];
+ }
+
+ pcap_close(pcap_handle);
+
+ /* allocate a big trunk of data for pcap file load */
+ buff = rte_zmalloc_socket("PCAP",
+ total_buff_len, 0, socket_id);
+ if (buff == NULL) {
+ RTE_LOG(ERR, PORT, "No enough memory\n");
+ goto error_exit;
+ }
+
+ port->pkt_buff = buff;
+
+ /* open file one last time to copy the pkt content */
+ pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
+ if (pcap_handle == NULL) {
+ RTE_LOG(ERR, PORT, "Failed to open pcap file "
+ "'%s' for reading\n", file_name);
+ goto error_exit;
+ }
+
+ for (i = 0; i < n_pkts; i++) {
+ pkt = pcap_next(pcap_handle, &pcap_hdr);
+ rte_memcpy(buff, pkt, port->pkt_len[i]);
+ port->pkts[i] = buff;
+ buff += pkt_len_aligns[i];
+ }
+
+ pcap_close(pcap_handle);
+
+ port->n_pkts = n_pkts;
+
+ rte_free(pkt_len_aligns);
+
+ RTE_LOG(INFO, PORT, "Successfully load pcap file "
+ "'%s' with %u pkts\n",
+ file_name, port->n_pkts);
+
+ return 0;
+
+error_exit:
+ if (pkt_len_aligns)
+ rte_free(pkt_len_aligns);
+ if (port->pkt_len)
+ rte_free(port->pkt_len);
+ if (port->pkts)
+ rte_free(port->pkts);
+ if (port->pkt_buff)
+ rte_free(port->pkt_buff);
+
+ return -1;
+}
+
+#define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \
+ pcap_source_load(port, file_name, n_bytes, socket_id)
+
+#else /* RTE_PORT_PCAP */
+
+#define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \
+({ \
+ int _ret = 0; \
+ \
+ if (file_name) { \
+ RTE_LOG(ERR, PORT, "Source port field " \
+ "\"file_name\" is not NULL.\n"); \
+ _ret = -1; \
+ } \
+ \
+ _ret; \
+})
+
+#endif /* RTE_PORT_PCAP */
+