3 * \author written by Emmanuel Roullit emmanuel.roullit@gmail.com (c) 2011
7 /* __LICENSE_HEADER_BEGIN__ */
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
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__ */
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>
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
)
58 (pkt_mmap
->pf_sock
, SOL_PACKET
, pkt_mmap
->type
,
59 (void *)(&pkt_mmap
->layout
), sizeof(pkt_mmap
->layout
)) < 0) {
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
)
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
));
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
)
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
)
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
)
117 munmap(pkt_mmap
->buf
,
118 pkt_mmap
->layout
.tp_block_size
*
119 pkt_mmap
->layout
.tp_block_nr
);
121 pkt_mmap
->buf
= NULL
;
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
;
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)
146 /* Check error and if dev is ready */
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
)
163 assert(pkt_mmap
->buf
);
166 calloc(pkt_mmap
->layout
.tp_frame_nr
, sizeof(*pkt_mmap
->vec
));
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
;
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
)
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
)
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
)
236 if (!is_power_of_2(frame_size
) || !is_power_of_2(frame_nr
))
239 memset(pkt_mmap
, 0, sizeof(*pkt_mmap
));
241 rc
= devname_to_ifindex(dev
, &pkt_mmap
->ifindex
);
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) {
260 rc
= packet_mmap_register(pkt_mmap
);
265 rc
= packet_mmap_mmap(pkt_mmap
);
270 rc
= packet_mmap_vector_create(pkt_mmap
);
275 rc
= packet_mmap_bind(pkt_mmap
);
282 packet_mmap_destroy(pkt_mmap
);