capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / capt-mmap-v3.c
blob41ec28a70408fa381fe157d0432a041dc3969f7f
1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 #include "iptraf-ng-compat.h"
6 #include "packet.h"
7 #include "capt.h"
9 struct capt_data_mmap_v3 {
10 void *mmap;
11 size_t mmap_size;
12 int hdrlen;
13 struct tpacket_block_desc **pbds;
14 struct tpacket_block_desc *pbd;
15 struct tpacket3_hdr *ppd;
16 unsigned int curblock;
17 unsigned int lastblock;
19 uint32_t num_pkts; /* only for debug */
20 uint32_t cur_pkt; /* only for debug */
23 #define BLOCKS 256 /* 256 blocks / 512 frames in each block:
24 * this gets room for 128k packets, which
25 * "should be enough for everybody" ;-) */
27 #define FRAMES_PER_BLOCK 512 /* keep it as power-of-two (dramaticly lowers
28 * CPU utilization) */
30 #define FRAMES (BLOCKS * FRAMES_PER_BLOCK) /* frames over all blocks */
32 #define FRAME_SIZE TPACKET_ALIGN(MAX_PACKET_SIZE + TPACKET_HDRLEN)
34 static struct tpacket_block_desc *capt_mmap_find_filled_block(struct capt_data_mmap_v3 *data)
36 for (unsigned int i = data->lastblock; i < data->lastblock + BLOCKS; i++) {
37 unsigned int block = i >= BLOCKS ? i - BLOCKS : i;
39 if (data->pbds[block]->hdr.bh1.block_status & TP_STATUS_USER) {
40 data->curblock = block;
41 return data->pbds[block];
44 return NULL;
47 static unsigned int capt_have_packet_mmap_v3(struct capt *capt)
49 struct capt_data_mmap_v3 *data = capt->priv;
51 if (data->pbd != NULL)
52 return true;
54 data->pbd = capt_mmap_find_filled_block(data);
55 if (data->pbd != NULL)
56 return true;
57 else
58 return false;
61 static int capt_get_packet_mmap_v3(struct capt *capt, struct pkt_hdr *pkt)
63 struct capt_data_mmap_v3 *data = capt->priv;
65 if (data->pbd == NULL)
66 data->pbd = capt_mmap_find_filled_block(data);
68 if (data->pbd == NULL)
69 return 0; /* no packet ready */
71 if (data->ppd == NULL) {
72 data->ppd = (struct tpacket3_hdr *) ((uint8_t *)data->pbd + data->pbd->hdr.bh1.offset_to_first_pkt);
73 data->num_pkts = data->pbd->hdr.bh1.num_pkts;
76 /* here should be at least one packet ready */
77 pkt->pkt_buf = (char *)data->ppd + data->ppd->tp_mac;
78 pkt->pkt_payload = NULL;
79 pkt->pkt_len = data->ppd->tp_len;
80 pkt->from = (struct sockaddr_ll *)((uint8_t *)data->ppd + data->hdrlen);
81 pkt->pkt_protocol = ntohs(pkt->from->sll_protocol);
83 return pkt->pkt_len;
86 static int capt_put_packet_mmap_v3(struct capt *capt, struct pkt_hdr *pkt __unused)
88 struct capt_data_mmap_v3 *data = capt->priv;
90 if (data->ppd->tp_next_offset != 0) {
91 data->ppd = (struct tpacket3_hdr *)((uint8_t *)data->ppd + data->ppd->tp_next_offset);
92 data->cur_pkt++;
93 } else {
94 data->ppd = NULL;
95 data->num_pkts = 0;
96 data->cur_pkt = 0;
97 data->pbd->hdr.bh1.block_status = TP_STATUS_KERNEL;
98 data->pbd = NULL;
99 data->lastblock = data->curblock;
102 return 0;
105 static void capt_cleanup_mmap_v3(struct capt *capt)
107 struct capt_data_mmap_v3 *data = capt->priv;
109 free(data->pbds);
111 munlock(data->mmap, data->mmap_size);
112 munmap(data->mmap, data->mmap_size);
114 memset(data, 0, sizeof(*data));
116 free(capt->priv);
117 capt->priv = NULL;
120 int capt_setup_mmap_v3(struct capt *capt)
122 int version = TPACKET_V3;
123 if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0)
124 return -1;
126 int hdrlen = version;
127 socklen_t socklen = sizeof(hdrlen);
128 if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0)
129 return -1;
131 struct tpacket_req3 req;
133 req.tp_block_nr = BLOCKS;
134 req.tp_frame_nr = FRAMES;
135 req.tp_frame_size = FRAME_SIZE;
136 req.tp_block_size = FRAMES_PER_BLOCK * req.tp_frame_size;
138 req.tp_retire_blk_tov = 20; /* block retire timeout in msec */
139 req.tp_sizeof_priv = 0;
140 // req.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
142 if(setsockopt(capt->fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
143 return -1;
145 size_t size = req.tp_block_size * req.tp_block_nr;
146 void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, capt->fd, 0);
147 if (map == MAP_FAILED)
148 return -1;
150 if (mlock(map, size) != 0) {
151 munmap(map, size);
152 return -1;
155 struct capt_data_mmap_v3 *data = xmallocz(sizeof(struct capt_data_mmap_v3));
157 data->hdrlen = hdrlen;
158 data->mmap = map;
159 data->mmap_size = size;
161 data->pbds = xmallocz(BLOCKS * sizeof(*data->pbd));
162 for (int i = 0; i < BLOCKS; i++) {
163 data->pbds[i] = map + i * req.tp_block_size;
166 capt->priv = data;
167 capt->have_packet = capt_have_packet_mmap_v3;
168 capt->get_packet = capt_get_packet_mmap_v3;
169 capt->put_packet = capt_put_packet_mmap_v3;
170 capt->cleanup = capt_cleanup_mmap_v3;
172 return 0; /* All O.K. */