Support packets in flight
[samplevnf.git] / VNFs / DPPD-PROX / handle_dump.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <rte_cycles.h>
18 #include <pcap.h>
19
20 #include "prox_malloc.h"
21 #include "clock.h"
22 #include "log.h"
23 #include "lconf.h"
24 #include "task_init.h"
25 #include "task_base.h"
26 #include "stats.h"
27 #include "prox_compat.h"
28
29 struct task_dump {
30         struct task_base base;
31         uint32_t n_mbufs;
32         struct rte_mbuf **mbufs;
33         uint32_t n_pkts;
34         char pcap_file[256];
35 };
36
37 static uint16_t buffer_packets(struct task_dump *task, struct rte_mbuf **mbufs, uint16_t n_pkts)
38 {
39         uint16_t j = 0;
40
41         if (task->n_mbufs == task->n_pkts)
42                 return 0;
43
44         for (j = 0; j < n_pkts && task->n_mbufs < task->n_pkts; ++j) {
45 #if RTE_VERSION >= RTE_VERSION_NUM(20,11,0,0)
46                 uint64_t rdtsc = rte_rdtsc();
47                 memcpy(&mbufs[j]->dynfield1[0], &rdtsc, sizeof(rdtsc));
48 #else
49                 mbufs[j]->udata64 = rte_rdtsc();
50 #endif
51                 task->mbufs[task->n_mbufs++] = mbufs[j];
52         }
53
54         return j;
55 }
56
57 static int handle_dump_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
58 {
59         struct task_dump *task = (struct task_dump *)tbase;
60         const uint16_t ofs = buffer_packets(task, mbufs, n_pkts);
61
62         for (uint16_t j = ofs; j < n_pkts; ++j)
63                 rte_pktmbuf_free(mbufs[j]);
64         TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, n_pkts - ofs);
65         return n_pkts;
66 }
67
68 static void init_task_dump(struct task_base *tbase, __attribute__((unused)) struct task_args *targ)
69 {
70         struct task_dump *task = (struct task_dump *)tbase;
71         const int socket_id = rte_lcore_to_socket_id(targ->lconf->id);
72
73         if (targ->n_pkts == 0)
74                 targ->n_pkts = 64 * 1024;
75         task->mbufs = prox_zmalloc(sizeof(*task->mbufs) * targ->n_pkts, socket_id);
76         task->n_pkts = targ->n_pkts;
77         if (!strcmp(targ->pcap_file, "")) {
78                 strcpy(targ->pcap_file, "out.pcap");
79         }
80         prox_strncpy(task->pcap_file, targ->pcap_file, sizeof(task->pcap_file));
81 }
82
83 static void stop(struct task_base *tbase)
84 {
85         struct task_dump *task = (struct task_dump *)tbase;
86         static pcap_dumper_t *pcap_dump_handle;
87         pcap_t *handle;
88         uint32_t n_pkts = 65536;
89         struct pcap_pkthdr header = {{0}, 0, 0};
90         static int once = 0;
91         char err_str[PCAP_ERRBUF_SIZE];
92         const uint64_t hz = rte_get_tsc_hz();
93         struct timeval tv = {0};
94         uint64_t tsc, beg = 0;
95
96         plogx_info("Dumping %d packets to '%s'\n", task->n_mbufs, task->pcap_file);
97         handle = pcap_open_dead(DLT_EN10MB, n_pkts);
98         pcap_dump_handle = pcap_dump_open(handle, task->pcap_file);
99
100         if (task->n_mbufs) {
101 #if RTE_VERSION >= RTE_VERSION_NUM(20,11,0,0)
102                 memcpy(&beg, &task->mbufs[0]->dynfield1[0], sizeof(beg));
103 #else
104                 beg = task->mbufs[0]->udata64;
105 #endif
106         }
107         for (uint32_t j = 0; j < task->n_mbufs; ++j) {
108 #if RTE_VERSION >= RTE_VERSION_NUM(20,11,0,0)
109                 uint64_t mbufs_beg;
110                 memcpy(&mbufs_beg, &task->mbufs[j]->dynfield1[0], sizeof(mbufs_beg));
111                 tsc = mbufs_beg - beg;
112 #else
113                 tsc = task->mbufs[j]->udata64 - beg;
114 #endif
115                 header.len = rte_pktmbuf_pkt_len(task->mbufs[j]);
116                 header.caplen = header.len;
117                 tsc_to_tv(&header.ts, tsc);
118                 pcap_dump((unsigned char *)pcap_dump_handle, &header, rte_pktmbuf_mtod(task->mbufs[j], void *));
119         }
120
121         pcap_dump_close(pcap_dump_handle);
122         pcap_close(handle);
123         plogx_info("Dump complete, releasing mbufs\n");
124
125         uint32_t j = 0;
126
127         while (j + 64 < task->n_mbufs) {
128                 tbase->tx_pkt(tbase, &task->mbufs[j], 64, NULL);
129                 j += 64;
130         }
131         if (j < task->n_mbufs) {
132                 tbase->tx_pkt(tbase, &task->mbufs[j], task->n_mbufs - j, NULL);
133         }
134         task->n_mbufs = 0;
135 }
136
137 static struct task_init task_init_dump = {
138         .mode_str = "dump",
139         .init = init_task_dump,
140         .handle = handle_dump_bulk,
141         .stop = stop,
142         .flag_features = TASK_FEATURE_ZERO_RX,
143         .size = sizeof(struct task_dump)
144 };
145
146 __attribute__((constructor)) static void reg_task_dump(void)
147 {
148         reg_task(&task_init_dump);
149 }