summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/handle_dump.c
blob: 29a46fef8e5e51cb4f2e9127dc62729a7dc95fae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
// Copyright (c) 2010-2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include <rte_cycles.h>
#include <pcap.h>

#include "prox_malloc.h"
#include "clock.h"
#include "log.h"
#include "lconf.h"
#include "task_init.h"
#include "task_base.h"
#include "stats.h"
#include "prox_compat.h"

struct task_dump {
	struct task_base base;
	uint32_t n_mbufs;
        struct rte_mbuf **mbufs;
	uint32_t n_pkts;
	char pcap_file[256];
};

static uint16_t buffer_packets(struct task_dump *task, struct rte_mbuf **mbufs, uint16_t n_pkts)
{
	uint16_t j = 0;

	if (task->n_mbufs == task->n_pkts)
		return 0;

	for (j = 0; j < n_pkts && task->n_mbufs < task->n_pkts; ++j) {
		mbufs[j]->udata64 = rte_rdtsc();
		task->mbufs[task->n_mbufs++] = mbufs[j];
	}

	return j;
}

static int handle_dump_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
{
	struct task_dump *task = (struct task_dump *)tbase;
	const uint16_t ofs = buffer_packets(task, mbufs, n_pkts);

	for (uint16_t j = ofs; j < n_pkts; ++j)
		rte_pktmbuf_free(mbufs[j]);
	TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, n_pkts - ofs);
	return n_pkts;
}

static void init_task_dump(struct task_base *tbase, __attribute__((unused)) struct task_args *targ)
{
	struct task_dump *task = (struct task_dump *)tbase;
	const int socket_id = rte_lcore_to_socket_id(targ->lconf->id);

	if (targ->n_pkts == 0)
		targ->n_pkts = 64 * 1024;
	task->mbufs = prox_zmalloc(sizeof(*task->mbufs) * targ->n_pkts, socket_id);
	task->n_pkts = targ->n_pkts;
	if (!strcmp(targ->pcap_file, "")) {
		strcpy(targ->pcap_file, "out.pcap");
	}
	prox_strncpy(task->pcap_file, targ->pcap_file, sizeof(task->pcap_file));
}

static void stop(struct task_base *tbase)
{
	struct task_dump *task = (struct task_dump *)tbase;
	static pcap_dumper_t *pcap_dump_handle;
	pcap_t *handle;
	uint32_t n_pkts = 65536;
	struct pcap_pkthdr header = {{0}, 0, 0};
	static int once = 0;
	char err_str[PCAP_ERRBUF_SIZE];
	const uint64_t hz = rte_get_tsc_hz();
	struct timeval tv = {0};
	uint64_t tsc, beg = 0;

	plogx_info("Dumping %d packets to '%s'\n", task->n_mbufs, task->pcap_file);
	handle = pcap_open_dead(DLT_EN10MB, n_pkts);
	pcap_dump_handle = pcap_dump_open(handle, task->pcap_file);

	if (task->n_mbufs) {
		beg = task->mbufs[0]->udata64;
	}
	for (uint32_t j = 0; j < task->n_mbufs; ++j) {
		tsc = task->mbufs[j]->udata64 - beg;
		header.len = rte_pktmbuf_pkt_len(task->mbufs[j]);
		header.caplen = header.len;
		tsc_to_tv(&header.ts, tsc);
		pcap_dump((unsigned char *)pcap_dump_handle, &header, rte_pktmbuf_mtod(task->mbufs[j], void *));
	}

	pcap_dump_close(pcap_dump_handle);
	pcap_close(handle);
	plogx_info("Dump complete, releasing mbufs\n");

	uint32_t j = 0;

	while (j + 64 < task->n_mbufs) {
		tbase->tx_pkt(tbase, &task->mbufs[j], 64, NULL);
		j += 64;
	}
	if (j < task->n_mbufs) {
		tbase->tx_pkt(tbase, &task->mbufs[j], task->n_mbufs - j, NULL);
	}
	task->n_mbufs = 0;
}

static struct task_init task_init_dump = {
	.mode_str = "dump",
	.init = init_task_dump,
	.handle = handle_dump_bulk,
	.stop = stop,
	.flag_features = TASK_FEATURE_ZERO_RX,
	.size = sizeof(struct task_dump)
};

__attribute__((constructor)) static void reg_task_dump(void)
{
	reg_task(&task_init_dump);
}