Only run test once in verbose mode.
[dabba.git] / libdabba / packet_mmap.c
blob690fb35a2003af29160baf7ca812fd92843b36df
1 /**
2 * \file packet_mmap.c
3 * \author written by Emmanuel Roullit emmanuel.roullit@gmail.com (c) 2011
4 * \date 2011
5 */
7 /* __LICENSE_HEADER_BEGIN__ */
9 /*
10 * Copyright (C) 2011 Emmanuel Roullit <emmanuel.roullit@gmail.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
28 /* __LICENSE_HEADER_END__ */
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <assert.h>
36 #include <sys/mman.h>
37 #include <sys/socket.h>
39 #include <arpa/inet.h>
40 #include <linux/if_ether.h>
42 #include <libdabba/macros.h>
43 #include <libdabba/packet_mmap.h>
44 #include <libdabba/nic.h>
46 /**
47 * \internal
48 * \brief Register a packet mmap to the kernel
49 * \param[in] pkt_mmap packet mmap to register
50 * \return 0 on success, error code of \c setsockopt(2) on failure
53 static int packet_mmap_register(const struct packet_mmap *const pkt_mmap)
55 assert(pkt_mmap);
57 if (setsockopt
58 (pkt_mmap->pf_sock, SOL_PACKET, pkt_mmap->type,
59 (void *)(&pkt_mmap->layout), sizeof(pkt_mmap->layout)) < 0) {
60 return (errno);
63 return (0);
66 /**
67 * \internal
68 * \brief Unregister a packet mmap from the kernel
69 * \param[in] pkt_mmap packet mmap to unregister
70 * \return 0 on success, error code of \c setsockopt(2) on failure
73 static void packet_mmap_unregister(struct packet_mmap *pkt_mmap)
75 assert(pkt_mmap);
77 memset(&pkt_mmap->layout, 0, sizeof(pkt_mmap->layout));
79 setsockopt(pkt_mmap->pf_sock, SOL_PACKET, pkt_mmap->type,
80 (void *)(&pkt_mmap->layout), sizeof(pkt_mmap->layout));
83 /**
84 * \internal
85 * \brief Map a packet mmap memory from the kernel to the userspace
86 * \param[in,out] pkt_mmap packet mmap to map to userspace
87 * \return 0 on success, EINVAL on failure
90 static int packet_mmap_mmap(struct packet_mmap *pkt_mmap)
92 assert(pkt_mmap);
94 pkt_mmap->buf =
95 mmap(0,
96 pkt_mmap->layout.tp_block_size *
97 pkt_mmap->layout.tp_block_nr, PROT_READ | PROT_WRITE,
98 MAP_SHARED | MAP_LOCKED, pkt_mmap->pf_sock, 0);
100 if (pkt_mmap->buf == MAP_FAILED)
101 return (EINVAL);
103 return (0);
107 * \internal
108 * \brief Unmap a packet mmap memory from the kernel to the userspace
109 * \param[in,out] pkt_mmap packet mmap to unmap to userspace
112 static void packet_mmap_munmap(struct packet_mmap *pkt_mmap)
114 assert(pkt_mmap);
116 if (pkt_mmap->buf) {
117 munmap(pkt_mmap->buf,
118 pkt_mmap->layout.tp_block_size *
119 pkt_mmap->layout.tp_block_nr);
121 pkt_mmap->buf = NULL;
126 * \internal
127 * \brief Bind a packet mmap socket to the interface
128 * \param[in] pkt_mmap packet mmap to bind to the interface
129 * \return 0 on success, error code from \c bind(2) on failure
132 static int packet_mmap_bind(const struct packet_mmap *const pkt_mmap)
134 struct sockaddr_ll sll;
136 assert(pkt_mmap);
138 memset(&sll, 0, sizeof(sll));
139 sll.sll_family = AF_PACKET;
140 sll.sll_protocol = htons(ETH_P_ALL);
141 sll.sll_ifindex = pkt_mmap->ifindex;
143 if (bind(pkt_mmap->pf_sock, (struct sockaddr *)&sll, sizeof(sll)) < 0)
144 return (errno);
146 /* Check error and if dev is ready */
148 return (0);
152 * \internal
153 * \brief Allocate and initialize a packet mmap I/O vector buffer
154 * \param[in,out] pkt_mmap packet mmap to create
155 * \return 0 on success, ENOMEM on failure
158 static int packet_mmap_vector_create(struct packet_mmap *pkt_mmap)
160 size_t a;
162 assert(pkt_mmap);
163 assert(pkt_mmap->buf);
165 pkt_mmap->vec =
166 calloc(pkt_mmap->layout.tp_frame_nr, sizeof(*pkt_mmap->vec));
168 if (!pkt_mmap->vec)
169 return (ENOMEM);
171 for (a = 0; a < pkt_mmap->layout.tp_frame_nr; a++) {
172 pkt_mmap->vec[a].iov_base =
173 &pkt_mmap->buf[a * pkt_mmap->layout.tp_frame_size];
175 pkt_mmap->vec[a].iov_len = pkt_mmap->layout.tp_frame_size;
178 return (0);
182 * \internal
183 * \brief Free packet mmap I/O vector buffer
184 * \param[in,out] pkt_mmap packet mmap to free
187 static void packet_mmap_vector_destroy(struct packet_mmap *pkt_mmap)
189 assert(pkt_mmap);
191 free(pkt_mmap->vec);
195 * \brief Destroy a packet mmap
196 * \param[in,out] pkt_mmap packet mmap to destroy
199 void packet_mmap_destroy(struct packet_mmap *pkt_mmap)
201 assert(pkt_mmap);
203 packet_mmap_vector_destroy(pkt_mmap);
204 packet_mmap_munmap(pkt_mmap);
205 packet_mmap_unregister(pkt_mmap);
207 memset(pkt_mmap, 0, sizeof(*pkt_mmap));
211 * \brief Create a packet mmap
212 * \param[in,out] pkt_mmap packet mmap to create
213 * \param[in] dev Device name
214 * \param[in] pf_sock Open PF_PACKET socket
215 * \param[in] type Packet mmap type to create
216 * \param[in] frame_size Maximum packet mmap frame size
217 * \param[in] page_order Page order to use to create a block
218 * \param[in] frame_nr Total amount of frame in the packet mmap
219 * \return 0 on success, else on failure
221 * To create a packet mmap, the input frame_size and the size must be a power of
222 * two. Also the frame and block number must be bigger than zero.
225 int packet_mmap_create(struct packet_mmap *pkt_mmap,
226 const char *const dev, const int pf_sock,
227 const enum packet_mmap_type type,
228 const enum packet_mmap_frame_size frame_size,
229 const size_t frame_nr)
231 int rc = 0;
233 assert(pkt_mmap);
234 assert(dev);
236 if (!is_power_of_2(frame_size) || !is_power_of_2(frame_nr))
237 return EINVAL;
239 memset(pkt_mmap, 0, sizeof(*pkt_mmap));
241 rc = devname_to_ifindex(dev, &pkt_mmap->ifindex);
243 if (rc != 0)
244 goto out;
246 pkt_mmap->type = type;
247 pkt_mmap->pf_sock = pf_sock;
249 pkt_mmap->layout.tp_frame_size = frame_size;
250 pkt_mmap->layout.tp_block_nr = frame_nr / 8;
251 pkt_mmap->layout.tp_block_size = 8 * frame_size;
252 pkt_mmap->layout.tp_frame_nr = frame_nr;
254 if (pkt_mmap->layout.tp_frame_nr == 0
255 || pkt_mmap->layout.tp_block_nr == 0) {
256 rc = EINVAL;
257 goto out;
260 rc = packet_mmap_register(pkt_mmap);
262 if (rc != 0)
263 goto out;
265 rc = packet_mmap_mmap(pkt_mmap);
267 if (rc != 0)
268 goto out;
270 rc = packet_mmap_vector_create(pkt_mmap);
272 if (rc != 0)
273 goto out;
275 rc = packet_mmap_bind(pkt_mmap);
277 if (rc != 0)
278 goto out;
280 return (0);
281 out:
282 packet_mmap_destroy(pkt_mmap);
283 return (rc);