]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2014 John W. Linville <linville@tuxdriver.com> | |
3 | * Originally based upon librte_pmd_pcap code: | |
4 | * Copyright(c) 2010-2015 Intel Corporation. | |
5 | * Copyright(c) 2014 6WIND S.A. | |
6 | * All rights reserved. | |
7c673cae FG |
7 | */ |
8 | ||
9 | #include <rte_mbuf.h> | |
11fdf7f2 TL |
10 | #include <rte_ethdev_driver.h> |
11 | #include <rte_ethdev_vdev.h> | |
7c673cae FG |
12 | #include <rte_malloc.h> |
13 | #include <rte_kvargs.h> | |
11fdf7f2 | 14 | #include <rte_bus_vdev.h> |
7c673cae FG |
15 | |
16 | #include <linux/if_ether.h> | |
17 | #include <linux/if_packet.h> | |
18 | #include <arpa/inet.h> | |
19 | #include <net/if.h> | |
20 | #include <sys/types.h> | |
21 | #include <sys/socket.h> | |
22 | #include <sys/ioctl.h> | |
23 | #include <sys/mman.h> | |
24 | #include <unistd.h> | |
25 | #include <poll.h> | |
26 | ||
27 | #define ETH_AF_PACKET_IFACE_ARG "iface" | |
28 | #define ETH_AF_PACKET_NUM_Q_ARG "qpairs" | |
29 | #define ETH_AF_PACKET_BLOCKSIZE_ARG "blocksz" | |
30 | #define ETH_AF_PACKET_FRAMESIZE_ARG "framesz" | |
31 | #define ETH_AF_PACKET_FRAMECOUNT_ARG "framecnt" | |
11fdf7f2 | 32 | #define ETH_AF_PACKET_QDISC_BYPASS_ARG "qdisc_bypass" |
7c673cae FG |
33 | |
34 | #define DFLT_BLOCK_SIZE (1 << 12) | |
35 | #define DFLT_FRAME_SIZE (1 << 11) | |
36 | #define DFLT_FRAME_COUNT (1 << 9) | |
37 | ||
38 | #define RTE_PMD_AF_PACKET_MAX_RINGS 16 | |
39 | ||
40 | struct pkt_rx_queue { | |
41 | int sockfd; | |
42 | ||
43 | struct iovec *rd; | |
44 | uint8_t *map; | |
45 | unsigned int framecount; | |
46 | unsigned int framenum; | |
47 | ||
48 | struct rte_mempool *mb_pool; | |
11fdf7f2 | 49 | uint16_t in_port; |
7c673cae FG |
50 | |
51 | volatile unsigned long rx_pkts; | |
52 | volatile unsigned long err_pkts; | |
53 | volatile unsigned long rx_bytes; | |
54 | }; | |
55 | ||
56 | struct pkt_tx_queue { | |
57 | int sockfd; | |
11fdf7f2 | 58 | unsigned int frame_data_size; |
7c673cae FG |
59 | |
60 | struct iovec *rd; | |
61 | uint8_t *map; | |
62 | unsigned int framecount; | |
63 | unsigned int framenum; | |
64 | ||
65 | volatile unsigned long tx_pkts; | |
66 | volatile unsigned long err_pkts; | |
67 | volatile unsigned long tx_bytes; | |
68 | }; | |
69 | ||
70 | struct pmd_internals { | |
71 | unsigned nb_queues; | |
72 | ||
73 | int if_index; | |
11fdf7f2 | 74 | char *if_name; |
7c673cae FG |
75 | struct ether_addr eth_addr; |
76 | ||
77 | struct tpacket_req req; | |
78 | ||
79 | struct pkt_rx_queue rx_queue[RTE_PMD_AF_PACKET_MAX_RINGS]; | |
80 | struct pkt_tx_queue tx_queue[RTE_PMD_AF_PACKET_MAX_RINGS]; | |
81 | }; | |
82 | ||
83 | static const char *valid_arguments[] = { | |
84 | ETH_AF_PACKET_IFACE_ARG, | |
85 | ETH_AF_PACKET_NUM_Q_ARG, | |
86 | ETH_AF_PACKET_BLOCKSIZE_ARG, | |
87 | ETH_AF_PACKET_FRAMESIZE_ARG, | |
88 | ETH_AF_PACKET_FRAMECOUNT_ARG, | |
11fdf7f2 | 89 | ETH_AF_PACKET_QDISC_BYPASS_ARG, |
7c673cae FG |
90 | NULL |
91 | }; | |
92 | ||
7c673cae FG |
93 | static struct rte_eth_link pmd_link = { |
94 | .link_speed = ETH_SPEED_NUM_10G, | |
95 | .link_duplex = ETH_LINK_FULL_DUPLEX, | |
96 | .link_status = ETH_LINK_DOWN, | |
11fdf7f2 | 97 | .link_autoneg = ETH_LINK_FIXED, |
7c673cae FG |
98 | }; |
99 | ||
11fdf7f2 TL |
100 | static int af_packet_logtype; |
101 | ||
102 | #define PMD_LOG(level, fmt, args...) \ | |
103 | rte_log(RTE_LOG_ ## level, af_packet_logtype, \ | |
104 | "%s(): " fmt "\n", __func__, ##args) | |
105 | ||
7c673cae FG |
106 | static uint16_t |
107 | eth_af_packet_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) | |
108 | { | |
109 | unsigned i; | |
110 | struct tpacket2_hdr *ppd; | |
111 | struct rte_mbuf *mbuf; | |
112 | uint8_t *pbuf; | |
113 | struct pkt_rx_queue *pkt_q = queue; | |
114 | uint16_t num_rx = 0; | |
115 | unsigned long num_rx_bytes = 0; | |
116 | unsigned int framecount, framenum; | |
117 | ||
118 | if (unlikely(nb_pkts == 0)) | |
119 | return 0; | |
120 | ||
121 | /* | |
122 | * Reads the given number of packets from the AF_PACKET socket one by | |
123 | * one and copies the packet data into a newly allocated mbuf. | |
124 | */ | |
125 | framecount = pkt_q->framecount; | |
126 | framenum = pkt_q->framenum; | |
127 | for (i = 0; i < nb_pkts; i++) { | |
128 | /* point at the next incoming frame */ | |
129 | ppd = (struct tpacket2_hdr *) pkt_q->rd[framenum].iov_base; | |
130 | if ((ppd->tp_status & TP_STATUS_USER) == 0) | |
131 | break; | |
132 | ||
133 | /* allocate the next mbuf */ | |
134 | mbuf = rte_pktmbuf_alloc(pkt_q->mb_pool); | |
135 | if (unlikely(mbuf == NULL)) | |
136 | break; | |
137 | ||
138 | /* packet will fit in the mbuf, go ahead and receive it */ | |
139 | rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf) = ppd->tp_snaplen; | |
140 | pbuf = (uint8_t *) ppd + ppd->tp_mac; | |
141 | memcpy(rte_pktmbuf_mtod(mbuf, void *), pbuf, rte_pktmbuf_data_len(mbuf)); | |
142 | ||
11fdf7f2 TL |
143 | /* check for vlan info */ |
144 | if (ppd->tp_status & TP_STATUS_VLAN_VALID) { | |
145 | mbuf->vlan_tci = ppd->tp_vlan_tci; | |
146 | mbuf->ol_flags |= (PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED); | |
147 | } | |
148 | ||
7c673cae FG |
149 | /* release incoming frame and advance ring buffer */ |
150 | ppd->tp_status = TP_STATUS_KERNEL; | |
151 | if (++framenum >= framecount) | |
152 | framenum = 0; | |
153 | mbuf->port = pkt_q->in_port; | |
154 | ||
155 | /* account for the receive frame */ | |
156 | bufs[i] = mbuf; | |
157 | num_rx++; | |
158 | num_rx_bytes += mbuf->pkt_len; | |
159 | } | |
160 | pkt_q->framenum = framenum; | |
161 | pkt_q->rx_pkts += num_rx; | |
162 | pkt_q->rx_bytes += num_rx_bytes; | |
163 | return num_rx; | |
164 | } | |
165 | ||
166 | /* | |
167 | * Callback to handle sending packets through a real NIC. | |
168 | */ | |
169 | static uint16_t | |
170 | eth_af_packet_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) | |
171 | { | |
172 | struct tpacket2_hdr *ppd; | |
173 | struct rte_mbuf *mbuf; | |
174 | uint8_t *pbuf; | |
175 | unsigned int framecount, framenum; | |
176 | struct pollfd pfd; | |
177 | struct pkt_tx_queue *pkt_q = queue; | |
178 | uint16_t num_tx = 0; | |
179 | unsigned long num_tx_bytes = 0; | |
180 | int i; | |
181 | ||
182 | if (unlikely(nb_pkts == 0)) | |
183 | return 0; | |
184 | ||
185 | memset(&pfd, 0, sizeof(pfd)); | |
186 | pfd.fd = pkt_q->sockfd; | |
187 | pfd.events = POLLOUT; | |
188 | pfd.revents = 0; | |
189 | ||
190 | framecount = pkt_q->framecount; | |
191 | framenum = pkt_q->framenum; | |
192 | ppd = (struct tpacket2_hdr *) pkt_q->rd[framenum].iov_base; | |
193 | for (i = 0; i < nb_pkts; i++) { | |
11fdf7f2 TL |
194 | mbuf = *bufs++; |
195 | ||
196 | /* drop oversized packets */ | |
197 | if (mbuf->pkt_len > pkt_q->frame_data_size) { | |
198 | rte_pktmbuf_free(mbuf); | |
199 | continue; | |
200 | } | |
201 | ||
202 | /* insert vlan info if necessary */ | |
203 | if (mbuf->ol_flags & PKT_TX_VLAN_PKT) { | |
204 | if (rte_vlan_insert(&mbuf)) { | |
205 | rte_pktmbuf_free(mbuf); | |
206 | continue; | |
207 | } | |
208 | } | |
209 | ||
7c673cae FG |
210 | /* point at the next incoming frame */ |
211 | if ((ppd->tp_status != TP_STATUS_AVAILABLE) && | |
212 | (poll(&pfd, 1, -1) < 0)) | |
11fdf7f2 | 213 | break; |
7c673cae FG |
214 | |
215 | /* copy the tx frame data */ | |
7c673cae FG |
216 | pbuf = (uint8_t *) ppd + TPACKET2_HDRLEN - |
217 | sizeof(struct sockaddr_ll); | |
11fdf7f2 TL |
218 | |
219 | struct rte_mbuf *tmp_mbuf = mbuf; | |
220 | while (tmp_mbuf) { | |
221 | uint16_t data_len = rte_pktmbuf_data_len(tmp_mbuf); | |
222 | memcpy(pbuf, rte_pktmbuf_mtod(tmp_mbuf, void*), data_len); | |
223 | pbuf += data_len; | |
224 | tmp_mbuf = tmp_mbuf->next; | |
225 | } | |
226 | ||
227 | ppd->tp_len = mbuf->pkt_len; | |
228 | ppd->tp_snaplen = mbuf->pkt_len; | |
7c673cae FG |
229 | |
230 | /* release incoming frame and advance ring buffer */ | |
231 | ppd->tp_status = TP_STATUS_SEND_REQUEST; | |
232 | if (++framenum >= framecount) | |
233 | framenum = 0; | |
234 | ppd = (struct tpacket2_hdr *) pkt_q->rd[framenum].iov_base; | |
235 | ||
236 | num_tx++; | |
237 | num_tx_bytes += mbuf->pkt_len; | |
238 | rte_pktmbuf_free(mbuf); | |
239 | } | |
240 | ||
241 | /* kick-off transmits */ | |
11fdf7f2 TL |
242 | if (sendto(pkt_q->sockfd, NULL, 0, MSG_DONTWAIT, NULL, 0) == -1) { |
243 | /* error sending -- no packets transmitted */ | |
244 | num_tx = 0; | |
245 | num_tx_bytes = 0; | |
246 | } | |
7c673cae FG |
247 | |
248 | pkt_q->framenum = framenum; | |
249 | pkt_q->tx_pkts += num_tx; | |
11fdf7f2 | 250 | pkt_q->err_pkts += i - num_tx; |
7c673cae | 251 | pkt_q->tx_bytes += num_tx_bytes; |
11fdf7f2 | 252 | return i; |
7c673cae FG |
253 | } |
254 | ||
255 | static int | |
256 | eth_dev_start(struct rte_eth_dev *dev) | |
257 | { | |
258 | dev->data->dev_link.link_status = ETH_LINK_UP; | |
259 | return 0; | |
260 | } | |
261 | ||
262 | /* | |
263 | * This function gets called when the current port gets stopped. | |
264 | */ | |
265 | static void | |
266 | eth_dev_stop(struct rte_eth_dev *dev) | |
267 | { | |
268 | unsigned i; | |
269 | int sockfd; | |
270 | struct pmd_internals *internals = dev->data->dev_private; | |
271 | ||
272 | for (i = 0; i < internals->nb_queues; i++) { | |
273 | sockfd = internals->rx_queue[i].sockfd; | |
274 | if (sockfd != -1) | |
275 | close(sockfd); | |
11fdf7f2 TL |
276 | |
277 | /* Prevent use after free in case tx fd == rx fd */ | |
278 | if (sockfd != internals->tx_queue[i].sockfd) { | |
279 | sockfd = internals->tx_queue[i].sockfd; | |
280 | if (sockfd != -1) | |
281 | close(sockfd); | |
282 | } | |
283 | ||
284 | internals->rx_queue[i].sockfd = -1; | |
285 | internals->tx_queue[i].sockfd = -1; | |
7c673cae FG |
286 | } |
287 | ||
288 | dev->data->dev_link.link_status = ETH_LINK_DOWN; | |
289 | } | |
290 | ||
291 | static int | |
292 | eth_dev_configure(struct rte_eth_dev *dev __rte_unused) | |
293 | { | |
294 | return 0; | |
295 | } | |
296 | ||
297 | static void | |
298 | eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) | |
299 | { | |
300 | struct pmd_internals *internals = dev->data->dev_private; | |
301 | ||
7c673cae FG |
302 | dev_info->if_index = internals->if_index; |
303 | dev_info->max_mac_addrs = 1; | |
304 | dev_info->max_rx_pktlen = (uint32_t)ETH_FRAME_LEN; | |
305 | dev_info->max_rx_queues = (uint16_t)internals->nb_queues; | |
306 | dev_info->max_tx_queues = (uint16_t)internals->nb_queues; | |
307 | dev_info->min_rx_bufsize = 0; | |
11fdf7f2 | 308 | dev_info->rx_offload_capa = DEV_RX_OFFLOAD_CRC_STRIP; |
7c673cae FG |
309 | } |
310 | ||
11fdf7f2 | 311 | static int |
7c673cae FG |
312 | eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats) |
313 | { | |
314 | unsigned i, imax; | |
315 | unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0; | |
316 | unsigned long rx_bytes_total = 0, tx_bytes_total = 0; | |
317 | const struct pmd_internals *internal = dev->data->dev_private; | |
318 | ||
319 | imax = (internal->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS ? | |
320 | internal->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS); | |
321 | for (i = 0; i < imax; i++) { | |
322 | igb_stats->q_ipackets[i] = internal->rx_queue[i].rx_pkts; | |
323 | igb_stats->q_ibytes[i] = internal->rx_queue[i].rx_bytes; | |
324 | rx_total += igb_stats->q_ipackets[i]; | |
325 | rx_bytes_total += igb_stats->q_ibytes[i]; | |
326 | } | |
327 | ||
328 | imax = (internal->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS ? | |
329 | internal->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS); | |
330 | for (i = 0; i < imax; i++) { | |
331 | igb_stats->q_opackets[i] = internal->tx_queue[i].tx_pkts; | |
332 | igb_stats->q_errors[i] = internal->tx_queue[i].err_pkts; | |
333 | igb_stats->q_obytes[i] = internal->tx_queue[i].tx_bytes; | |
334 | tx_total += igb_stats->q_opackets[i]; | |
335 | tx_err_total += igb_stats->q_errors[i]; | |
336 | tx_bytes_total += igb_stats->q_obytes[i]; | |
337 | } | |
338 | ||
339 | igb_stats->ipackets = rx_total; | |
340 | igb_stats->ibytes = rx_bytes_total; | |
341 | igb_stats->opackets = tx_total; | |
342 | igb_stats->oerrors = tx_err_total; | |
343 | igb_stats->obytes = tx_bytes_total; | |
11fdf7f2 | 344 | return 0; |
7c673cae FG |
345 | } |
346 | ||
347 | static void | |
348 | eth_stats_reset(struct rte_eth_dev *dev) | |
349 | { | |
350 | unsigned i; | |
351 | struct pmd_internals *internal = dev->data->dev_private; | |
352 | ||
353 | for (i = 0; i < internal->nb_queues; i++) { | |
354 | internal->rx_queue[i].rx_pkts = 0; | |
355 | internal->rx_queue[i].rx_bytes = 0; | |
356 | } | |
357 | ||
358 | for (i = 0; i < internal->nb_queues; i++) { | |
359 | internal->tx_queue[i].tx_pkts = 0; | |
360 | internal->tx_queue[i].err_pkts = 0; | |
361 | internal->tx_queue[i].tx_bytes = 0; | |
362 | } | |
363 | } | |
364 | ||
365 | static void | |
366 | eth_dev_close(struct rte_eth_dev *dev __rte_unused) | |
367 | { | |
368 | } | |
369 | ||
370 | static void | |
371 | eth_queue_release(void *q __rte_unused) | |
372 | { | |
373 | } | |
374 | ||
375 | static int | |
376 | eth_link_update(struct rte_eth_dev *dev __rte_unused, | |
377 | int wait_to_complete __rte_unused) | |
378 | { | |
379 | return 0; | |
380 | } | |
381 | ||
382 | static int | |
383 | eth_rx_queue_setup(struct rte_eth_dev *dev, | |
384 | uint16_t rx_queue_id, | |
385 | uint16_t nb_rx_desc __rte_unused, | |
386 | unsigned int socket_id __rte_unused, | |
387 | const struct rte_eth_rxconf *rx_conf __rte_unused, | |
388 | struct rte_mempool *mb_pool) | |
389 | { | |
390 | struct pmd_internals *internals = dev->data->dev_private; | |
391 | struct pkt_rx_queue *pkt_q = &internals->rx_queue[rx_queue_id]; | |
11fdf7f2 | 392 | unsigned int buf_size, data_size; |
7c673cae FG |
393 | |
394 | pkt_q->mb_pool = mb_pool; | |
395 | ||
396 | /* Now get the space available for data in the mbuf */ | |
11fdf7f2 TL |
397 | buf_size = rte_pktmbuf_data_room_size(pkt_q->mb_pool) - |
398 | RTE_PKTMBUF_HEADROOM; | |
399 | data_size = internals->req.tp_frame_size; | |
400 | data_size -= TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); | |
401 | ||
402 | if (data_size > buf_size) { | |
403 | PMD_LOG(ERR, | |
404 | "%s: %d bytes will not fit in mbuf (%d bytes)", | |
405 | dev->device->name, data_size, buf_size); | |
7c673cae FG |
406 | return -ENOMEM; |
407 | } | |
408 | ||
409 | dev->data->rx_queues[rx_queue_id] = pkt_q; | |
410 | pkt_q->in_port = dev->data->port_id; | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
415 | static int | |
416 | eth_tx_queue_setup(struct rte_eth_dev *dev, | |
417 | uint16_t tx_queue_id, | |
418 | uint16_t nb_tx_desc __rte_unused, | |
419 | unsigned int socket_id __rte_unused, | |
420 | const struct rte_eth_txconf *tx_conf __rte_unused) | |
421 | { | |
422 | ||
423 | struct pmd_internals *internals = dev->data->dev_private; | |
424 | ||
425 | dev->data->tx_queues[tx_queue_id] = &internals->tx_queue[tx_queue_id]; | |
426 | return 0; | |
427 | } | |
428 | ||
11fdf7f2 TL |
429 | static int |
430 | eth_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) | |
431 | { | |
432 | struct pmd_internals *internals = dev->data->dev_private; | |
433 | struct ifreq ifr = { .ifr_mtu = mtu }; | |
434 | int ret; | |
435 | int s; | |
436 | unsigned int data_size = internals->req.tp_frame_size - | |
437 | TPACKET2_HDRLEN - | |
438 | sizeof(struct sockaddr_ll); | |
439 | ||
440 | if (mtu > data_size) | |
441 | return -EINVAL; | |
442 | ||
443 | s = socket(PF_INET, SOCK_DGRAM, 0); | |
444 | if (s < 0) | |
445 | return -EINVAL; | |
446 | ||
447 | snprintf(ifr.ifr_name, IFNAMSIZ, "%s", internals->if_name); | |
448 | ret = ioctl(s, SIOCSIFMTU, &ifr); | |
449 | close(s); | |
450 | ||
451 | if (ret < 0) | |
452 | return -EINVAL; | |
453 | ||
454 | return 0; | |
455 | } | |
456 | ||
457 | static void | |
458 | eth_dev_change_flags(char *if_name, uint32_t flags, uint32_t mask) | |
459 | { | |
460 | struct ifreq ifr; | |
461 | int s; | |
462 | ||
463 | s = socket(PF_INET, SOCK_DGRAM, 0); | |
464 | if (s < 0) | |
465 | return; | |
466 | ||
467 | snprintf(ifr.ifr_name, IFNAMSIZ, "%s", if_name); | |
468 | if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) | |
469 | goto out; | |
470 | ifr.ifr_flags &= mask; | |
471 | ifr.ifr_flags |= flags; | |
472 | if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) | |
473 | goto out; | |
474 | out: | |
475 | close(s); | |
476 | } | |
477 | ||
478 | static void | |
479 | eth_dev_promiscuous_enable(struct rte_eth_dev *dev) | |
480 | { | |
481 | struct pmd_internals *internals = dev->data->dev_private; | |
482 | ||
483 | eth_dev_change_flags(internals->if_name, IFF_PROMISC, ~0); | |
484 | } | |
485 | ||
486 | static void | |
487 | eth_dev_promiscuous_disable(struct rte_eth_dev *dev) | |
488 | { | |
489 | struct pmd_internals *internals = dev->data->dev_private; | |
490 | ||
491 | eth_dev_change_flags(internals->if_name, 0, ~IFF_PROMISC); | |
492 | } | |
493 | ||
7c673cae FG |
494 | static const struct eth_dev_ops ops = { |
495 | .dev_start = eth_dev_start, | |
496 | .dev_stop = eth_dev_stop, | |
497 | .dev_close = eth_dev_close, | |
498 | .dev_configure = eth_dev_configure, | |
499 | .dev_infos_get = eth_dev_info, | |
11fdf7f2 TL |
500 | .mtu_set = eth_dev_mtu_set, |
501 | .promiscuous_enable = eth_dev_promiscuous_enable, | |
502 | .promiscuous_disable = eth_dev_promiscuous_disable, | |
7c673cae FG |
503 | .rx_queue_setup = eth_rx_queue_setup, |
504 | .tx_queue_setup = eth_tx_queue_setup, | |
505 | .rx_queue_release = eth_queue_release, | |
506 | .tx_queue_release = eth_queue_release, | |
507 | .link_update = eth_link_update, | |
508 | .stats_get = eth_stats_get, | |
509 | .stats_reset = eth_stats_reset, | |
510 | }; | |
511 | ||
512 | /* | |
513 | * Opens an AF_PACKET socket | |
514 | */ | |
515 | static int | |
516 | open_packet_iface(const char *key __rte_unused, | |
517 | const char *value __rte_unused, | |
518 | void *extra_args) | |
519 | { | |
520 | int *sockfd = extra_args; | |
521 | ||
522 | /* Open an AF_PACKET socket... */ | |
523 | *sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | |
524 | if (*sockfd == -1) { | |
11fdf7f2 | 525 | PMD_LOG(ERR, "Could not open AF_PACKET socket"); |
7c673cae FG |
526 | return -1; |
527 | } | |
528 | ||
529 | return 0; | |
530 | } | |
531 | ||
11fdf7f2 TL |
532 | static struct rte_vdev_driver pmd_af_packet_drv; |
533 | ||
7c673cae | 534 | static int |
11fdf7f2 | 535 | rte_pmd_init_internals(struct rte_vdev_device *dev, |
7c673cae FG |
536 | const int sockfd, |
537 | const unsigned nb_queues, | |
538 | unsigned int blocksize, | |
539 | unsigned int blockcnt, | |
540 | unsigned int framesize, | |
541 | unsigned int framecnt, | |
11fdf7f2 | 542 | unsigned int qdisc_bypass, |
7c673cae FG |
543 | struct pmd_internals **internals, |
544 | struct rte_eth_dev **eth_dev, | |
545 | struct rte_kvargs *kvlist) | |
546 | { | |
11fdf7f2 TL |
547 | const char *name = rte_vdev_device_name(dev); |
548 | const unsigned int numa_node = dev->device.numa_node; | |
7c673cae FG |
549 | struct rte_eth_dev_data *data = NULL; |
550 | struct rte_kvargs_pair *pair = NULL; | |
551 | struct ifreq ifr; | |
552 | size_t ifnamelen; | |
553 | unsigned k_idx; | |
554 | struct sockaddr_ll sockaddr; | |
555 | struct tpacket_req *req; | |
556 | struct pkt_rx_queue *rx_queue; | |
557 | struct pkt_tx_queue *tx_queue; | |
558 | int rc, tpver, discard; | |
559 | int qsockfd = -1; | |
560 | unsigned int i, q, rdsize; | |
11fdf7f2 TL |
561 | #if defined(PACKET_FANOUT) |
562 | int fanout_arg; | |
563 | #endif | |
7c673cae FG |
564 | |
565 | for (k_idx = 0; k_idx < kvlist->count; k_idx++) { | |
566 | pair = &kvlist->pairs[k_idx]; | |
567 | if (strstr(pair->key, ETH_AF_PACKET_IFACE_ARG) != NULL) | |
568 | break; | |
569 | } | |
570 | if (pair == NULL) { | |
11fdf7f2 TL |
571 | PMD_LOG(ERR, |
572 | "%s: no interface specified for AF_PACKET ethdev", | |
7c673cae | 573 | name); |
11fdf7f2 | 574 | return -1; |
7c673cae FG |
575 | } |
576 | ||
11fdf7f2 TL |
577 | PMD_LOG(INFO, |
578 | "%s: creating AF_PACKET-backed ethdev on numa socket %u", | |
7c673cae FG |
579 | name, numa_node); |
580 | ||
7c673cae FG |
581 | *internals = rte_zmalloc_socket(name, sizeof(**internals), |
582 | 0, numa_node); | |
583 | if (*internals == NULL) | |
11fdf7f2 | 584 | return -1; |
7c673cae FG |
585 | |
586 | for (q = 0; q < nb_queues; q++) { | |
587 | (*internals)->rx_queue[q].map = MAP_FAILED; | |
588 | (*internals)->tx_queue[q].map = MAP_FAILED; | |
589 | } | |
590 | ||
591 | req = &((*internals)->req); | |
592 | ||
593 | req->tp_block_size = blocksize; | |
594 | req->tp_block_nr = blockcnt; | |
595 | req->tp_frame_size = framesize; | |
596 | req->tp_frame_nr = framecnt; | |
597 | ||
598 | ifnamelen = strlen(pair->value); | |
599 | if (ifnamelen < sizeof(ifr.ifr_name)) { | |
600 | memcpy(ifr.ifr_name, pair->value, ifnamelen); | |
601 | ifr.ifr_name[ifnamelen] = '\0'; | |
602 | } else { | |
11fdf7f2 TL |
603 | PMD_LOG(ERR, |
604 | "%s: I/F name too long (%s)", | |
7c673cae | 605 | name, pair->value); |
11fdf7f2 | 606 | return -1; |
7c673cae FG |
607 | } |
608 | if (ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1) { | |
11fdf7f2 TL |
609 | PMD_LOG(ERR, |
610 | "%s: ioctl failed (SIOCGIFINDEX)", | |
7c673cae | 611 | name); |
11fdf7f2 | 612 | return -1; |
7c673cae | 613 | } |
11fdf7f2 TL |
614 | (*internals)->if_name = strdup(pair->value); |
615 | if ((*internals)->if_name == NULL) | |
616 | return -1; | |
7c673cae FG |
617 | (*internals)->if_index = ifr.ifr_ifindex; |
618 | ||
619 | if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1) { | |
11fdf7f2 TL |
620 | PMD_LOG(ERR, |
621 | "%s: ioctl failed (SIOCGIFHWADDR)", | |
7c673cae | 622 | name); |
11fdf7f2 | 623 | return -1; |
7c673cae FG |
624 | } |
625 | memcpy(&(*internals)->eth_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); | |
626 | ||
627 | memset(&sockaddr, 0, sizeof(sockaddr)); | |
628 | sockaddr.sll_family = AF_PACKET; | |
629 | sockaddr.sll_protocol = htons(ETH_P_ALL); | |
630 | sockaddr.sll_ifindex = (*internals)->if_index; | |
631 | ||
632 | #if defined(PACKET_FANOUT) | |
633 | fanout_arg = (getpid() ^ (*internals)->if_index) & 0xffff; | |
634 | fanout_arg |= (PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG) << 16; | |
635 | #if defined(PACKET_FANOUT_FLAG_ROLLOVER) | |
636 | fanout_arg |= PACKET_FANOUT_FLAG_ROLLOVER << 16; | |
637 | #endif | |
638 | #endif | |
639 | ||
640 | for (q = 0; q < nb_queues; q++) { | |
641 | /* Open an AF_PACKET socket for this queue... */ | |
642 | qsockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | |
643 | if (qsockfd == -1) { | |
11fdf7f2 TL |
644 | PMD_LOG(ERR, |
645 | "%s: could not open AF_PACKET socket", | |
7c673cae FG |
646 | name); |
647 | return -1; | |
648 | } | |
649 | ||
650 | tpver = TPACKET_V2; | |
651 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_VERSION, | |
652 | &tpver, sizeof(tpver)); | |
653 | if (rc == -1) { | |
11fdf7f2 TL |
654 | PMD_LOG(ERR, |
655 | "%s: could not set PACKET_VERSION on AF_PACKET socket for %s", | |
656 | name, pair->value); | |
7c673cae FG |
657 | goto error; |
658 | } | |
659 | ||
660 | discard = 1; | |
661 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_LOSS, | |
662 | &discard, sizeof(discard)); | |
663 | if (rc == -1) { | |
11fdf7f2 TL |
664 | PMD_LOG(ERR, |
665 | "%s: could not set PACKET_LOSS on AF_PACKET socket for %s", | |
666 | name, pair->value); | |
7c673cae FG |
667 | goto error; |
668 | } | |
669 | ||
670 | #if defined(PACKET_QDISC_BYPASS) | |
7c673cae | 671 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_QDISC_BYPASS, |
11fdf7f2 | 672 | &qdisc_bypass, sizeof(qdisc_bypass)); |
7c673cae | 673 | if (rc == -1) { |
11fdf7f2 TL |
674 | PMD_LOG(ERR, |
675 | "%s: could not set PACKET_QDISC_BYPASS on AF_PACKET socket for %s", | |
676 | name, pair->value); | |
7c673cae FG |
677 | goto error; |
678 | } | |
11fdf7f2 TL |
679 | #else |
680 | RTE_SET_USED(qdisc_bypass); | |
7c673cae FG |
681 | #endif |
682 | ||
683 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_RX_RING, req, sizeof(*req)); | |
684 | if (rc == -1) { | |
11fdf7f2 TL |
685 | PMD_LOG(ERR, |
686 | "%s: could not set PACKET_RX_RING on AF_PACKET socket for %s", | |
687 | name, pair->value); | |
7c673cae FG |
688 | goto error; |
689 | } | |
690 | ||
691 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_TX_RING, req, sizeof(*req)); | |
692 | if (rc == -1) { | |
11fdf7f2 | 693 | PMD_LOG(ERR, |
7c673cae | 694 | "%s: could not set PACKET_TX_RING on AF_PACKET " |
11fdf7f2 | 695 | "socket for %s", name, pair->value); |
7c673cae FG |
696 | goto error; |
697 | } | |
698 | ||
699 | rx_queue = &((*internals)->rx_queue[q]); | |
700 | rx_queue->framecount = req->tp_frame_nr; | |
701 | ||
702 | rx_queue->map = mmap(NULL, 2 * req->tp_block_size * req->tp_block_nr, | |
703 | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, | |
704 | qsockfd, 0); | |
705 | if (rx_queue->map == MAP_FAILED) { | |
11fdf7f2 TL |
706 | PMD_LOG(ERR, |
707 | "%s: call to mmap failed on AF_PACKET socket for %s", | |
7c673cae FG |
708 | name, pair->value); |
709 | goto error; | |
710 | } | |
711 | ||
712 | /* rdsize is same for both Tx and Rx */ | |
713 | rdsize = req->tp_frame_nr * sizeof(*(rx_queue->rd)); | |
714 | ||
715 | rx_queue->rd = rte_zmalloc_socket(name, rdsize, 0, numa_node); | |
716 | if (rx_queue->rd == NULL) | |
717 | goto error; | |
718 | for (i = 0; i < req->tp_frame_nr; ++i) { | |
719 | rx_queue->rd[i].iov_base = rx_queue->map + (i * framesize); | |
720 | rx_queue->rd[i].iov_len = req->tp_frame_size; | |
721 | } | |
722 | rx_queue->sockfd = qsockfd; | |
723 | ||
724 | tx_queue = &((*internals)->tx_queue[q]); | |
725 | tx_queue->framecount = req->tp_frame_nr; | |
11fdf7f2 TL |
726 | tx_queue->frame_data_size = req->tp_frame_size; |
727 | tx_queue->frame_data_size -= TPACKET2_HDRLEN - | |
728 | sizeof(struct sockaddr_ll); | |
7c673cae FG |
729 | |
730 | tx_queue->map = rx_queue->map + req->tp_block_size * req->tp_block_nr; | |
731 | ||
732 | tx_queue->rd = rte_zmalloc_socket(name, rdsize, 0, numa_node); | |
733 | if (tx_queue->rd == NULL) | |
734 | goto error; | |
735 | for (i = 0; i < req->tp_frame_nr; ++i) { | |
736 | tx_queue->rd[i].iov_base = tx_queue->map + (i * framesize); | |
737 | tx_queue->rd[i].iov_len = req->tp_frame_size; | |
738 | } | |
739 | tx_queue->sockfd = qsockfd; | |
740 | ||
741 | rc = bind(qsockfd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)); | |
742 | if (rc == -1) { | |
11fdf7f2 TL |
743 | PMD_LOG(ERR, |
744 | "%s: could not bind AF_PACKET socket to %s", | |
7c673cae FG |
745 | name, pair->value); |
746 | goto error; | |
747 | } | |
748 | ||
749 | #if defined(PACKET_FANOUT) | |
750 | rc = setsockopt(qsockfd, SOL_PACKET, PACKET_FANOUT, | |
751 | &fanout_arg, sizeof(fanout_arg)); | |
752 | if (rc == -1) { | |
11fdf7f2 | 753 | PMD_LOG(ERR, |
7c673cae | 754 | "%s: could not set PACKET_FANOUT on AF_PACKET socket " |
11fdf7f2 | 755 | "for %s", name, pair->value); |
7c673cae FG |
756 | goto error; |
757 | } | |
758 | #endif | |
759 | } | |
760 | ||
761 | /* reserve an ethdev entry */ | |
11fdf7f2 | 762 | *eth_dev = rte_eth_vdev_allocate(dev, 0); |
7c673cae FG |
763 | if (*eth_dev == NULL) |
764 | goto error; | |
765 | ||
766 | /* | |
767 | * now put it all together | |
768 | * - store queue data in internals, | |
769 | * - store numa_node in eth_dev | |
770 | * - point eth_dev_data to internals | |
771 | * - and point eth_dev structure to new eth_dev_data structure | |
772 | */ | |
773 | ||
774 | (*internals)->nb_queues = nb_queues; | |
775 | ||
11fdf7f2 | 776 | data = (*eth_dev)->data; |
7c673cae | 777 | data->dev_private = *internals; |
7c673cae FG |
778 | data->nb_rx_queues = (uint16_t)nb_queues; |
779 | data->nb_tx_queues = (uint16_t)nb_queues; | |
780 | data->dev_link = pmd_link; | |
781 | data->mac_addrs = &(*internals)->eth_addr; | |
7c673cae | 782 | |
7c673cae | 783 | (*eth_dev)->dev_ops = &ops; |
7c673cae FG |
784 | |
785 | return 0; | |
786 | ||
787 | error: | |
788 | if (qsockfd != -1) | |
789 | close(qsockfd); | |
790 | for (q = 0; q < nb_queues; q++) { | |
791 | munmap((*internals)->rx_queue[q].map, | |
792 | 2 * req->tp_block_size * req->tp_block_nr); | |
793 | ||
794 | rte_free((*internals)->rx_queue[q].rd); | |
795 | rte_free((*internals)->tx_queue[q].rd); | |
796 | if (((*internals)->rx_queue[q].sockfd != 0) && | |
797 | ((*internals)->rx_queue[q].sockfd != qsockfd)) | |
798 | close((*internals)->rx_queue[q].sockfd); | |
799 | } | |
11fdf7f2 | 800 | free((*internals)->if_name); |
7c673cae | 801 | rte_free(*internals); |
7c673cae FG |
802 | return -1; |
803 | } | |
804 | ||
805 | static int | |
11fdf7f2 | 806 | rte_eth_from_packet(struct rte_vdev_device *dev, |
7c673cae | 807 | int const *sockfd, |
7c673cae FG |
808 | struct rte_kvargs *kvlist) |
809 | { | |
11fdf7f2 | 810 | const char *name = rte_vdev_device_name(dev); |
7c673cae FG |
811 | struct pmd_internals *internals = NULL; |
812 | struct rte_eth_dev *eth_dev = NULL; | |
813 | struct rte_kvargs_pair *pair = NULL; | |
814 | unsigned k_idx; | |
815 | unsigned int blockcount; | |
816 | unsigned int blocksize = DFLT_BLOCK_SIZE; | |
817 | unsigned int framesize = DFLT_FRAME_SIZE; | |
818 | unsigned int framecount = DFLT_FRAME_COUNT; | |
819 | unsigned int qpairs = 1; | |
11fdf7f2 | 820 | unsigned int qdisc_bypass = 1; |
7c673cae FG |
821 | |
822 | /* do some parameter checking */ | |
823 | if (*sockfd < 0) | |
824 | return -1; | |
825 | ||
826 | /* | |
827 | * Walk arguments for configurable settings | |
828 | */ | |
829 | for (k_idx = 0; k_idx < kvlist->count; k_idx++) { | |
830 | pair = &kvlist->pairs[k_idx]; | |
831 | if (strstr(pair->key, ETH_AF_PACKET_NUM_Q_ARG) != NULL) { | |
832 | qpairs = atoi(pair->value); | |
833 | if (qpairs < 1 || | |
834 | qpairs > RTE_PMD_AF_PACKET_MAX_RINGS) { | |
11fdf7f2 TL |
835 | PMD_LOG(ERR, |
836 | "%s: invalid qpairs value", | |
7c673cae FG |
837 | name); |
838 | return -1; | |
839 | } | |
840 | continue; | |
841 | } | |
842 | if (strstr(pair->key, ETH_AF_PACKET_BLOCKSIZE_ARG) != NULL) { | |
843 | blocksize = atoi(pair->value); | |
844 | if (!blocksize) { | |
11fdf7f2 TL |
845 | PMD_LOG(ERR, |
846 | "%s: invalid blocksize value", | |
7c673cae FG |
847 | name); |
848 | return -1; | |
849 | } | |
850 | continue; | |
851 | } | |
852 | if (strstr(pair->key, ETH_AF_PACKET_FRAMESIZE_ARG) != NULL) { | |
853 | framesize = atoi(pair->value); | |
854 | if (!framesize) { | |
11fdf7f2 TL |
855 | PMD_LOG(ERR, |
856 | "%s: invalid framesize value", | |
7c673cae FG |
857 | name); |
858 | return -1; | |
859 | } | |
860 | continue; | |
861 | } | |
862 | if (strstr(pair->key, ETH_AF_PACKET_FRAMECOUNT_ARG) != NULL) { | |
863 | framecount = atoi(pair->value); | |
864 | if (!framecount) { | |
11fdf7f2 TL |
865 | PMD_LOG(ERR, |
866 | "%s: invalid framecount value", | |
7c673cae FG |
867 | name); |
868 | return -1; | |
869 | } | |
870 | continue; | |
871 | } | |
11fdf7f2 TL |
872 | if (strstr(pair->key, ETH_AF_PACKET_QDISC_BYPASS_ARG) != NULL) { |
873 | qdisc_bypass = atoi(pair->value); | |
874 | if (qdisc_bypass > 1) { | |
875 | PMD_LOG(ERR, | |
876 | "%s: invalid bypass value", | |
877 | name); | |
878 | return -1; | |
879 | } | |
880 | continue; | |
881 | } | |
7c673cae FG |
882 | } |
883 | ||
884 | if (framesize > blocksize) { | |
11fdf7f2 TL |
885 | PMD_LOG(ERR, |
886 | "%s: AF_PACKET MMAP frame size exceeds block size!", | |
7c673cae FG |
887 | name); |
888 | return -1; | |
889 | } | |
890 | ||
891 | blockcount = framecount / (blocksize / framesize); | |
892 | if (!blockcount) { | |
11fdf7f2 TL |
893 | PMD_LOG(ERR, |
894 | "%s: invalid AF_PACKET MMAP parameters", name); | |
7c673cae FG |
895 | return -1; |
896 | } | |
897 | ||
11fdf7f2 TL |
898 | PMD_LOG(INFO, "%s: AF_PACKET MMAP parameters:", name); |
899 | PMD_LOG(INFO, "%s:\tblock size %d", name, blocksize); | |
900 | PMD_LOG(INFO, "%s:\tblock count %d", name, blockcount); | |
901 | PMD_LOG(INFO, "%s:\tframe size %d", name, framesize); | |
902 | PMD_LOG(INFO, "%s:\tframe count %d", name, framecount); | |
903 | ||
904 | if (rte_pmd_init_internals(dev, *sockfd, qpairs, | |
905 | blocksize, blockcount, | |
906 | framesize, framecount, | |
907 | qdisc_bypass, | |
908 | &internals, ð_dev, | |
909 | kvlist) < 0) | |
7c673cae FG |
910 | return -1; |
911 | ||
912 | eth_dev->rx_pkt_burst = eth_af_packet_rx; | |
913 | eth_dev->tx_pkt_burst = eth_af_packet_tx; | |
914 | ||
11fdf7f2 | 915 | rte_eth_dev_probing_finish(eth_dev); |
7c673cae FG |
916 | return 0; |
917 | } | |
918 | ||
919 | static int | |
11fdf7f2 | 920 | rte_pmd_af_packet_probe(struct rte_vdev_device *dev) |
7c673cae | 921 | { |
7c673cae FG |
922 | int ret = 0; |
923 | struct rte_kvargs *kvlist; | |
924 | int sockfd = -1; | |
11fdf7f2 TL |
925 | struct rte_eth_dev *eth_dev; |
926 | const char *name = rte_vdev_device_name(dev); | |
7c673cae | 927 | |
11fdf7f2 | 928 | PMD_LOG(INFO, "Initializing pmd_af_packet for %s", name); |
7c673cae | 929 | |
11fdf7f2 TL |
930 | if (rte_eal_process_type() == RTE_PROC_SECONDARY && |
931 | strlen(rte_vdev_device_args(dev)) == 0) { | |
932 | eth_dev = rte_eth_dev_attach_secondary(name); | |
933 | if (!eth_dev) { | |
934 | PMD_LOG(ERR, "Failed to probe %s", name); | |
935 | return -1; | |
936 | } | |
937 | /* TODO: request info from primary to set up Rx and Tx */ | |
938 | eth_dev->dev_ops = &ops; | |
939 | eth_dev->device = &dev->device; | |
940 | rte_eth_dev_probing_finish(eth_dev); | |
941 | return 0; | |
942 | } | |
7c673cae | 943 | |
11fdf7f2 | 944 | kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments); |
7c673cae FG |
945 | if (kvlist == NULL) { |
946 | ret = -1; | |
947 | goto exit; | |
948 | } | |
949 | ||
950 | /* | |
951 | * If iface argument is passed we open the NICs and use them for | |
952 | * reading / writing | |
953 | */ | |
954 | if (rte_kvargs_count(kvlist, ETH_AF_PACKET_IFACE_ARG) == 1) { | |
955 | ||
956 | ret = rte_kvargs_process(kvlist, ETH_AF_PACKET_IFACE_ARG, | |
957 | &open_packet_iface, &sockfd); | |
958 | if (ret < 0) | |
959 | goto exit; | |
960 | } | |
961 | ||
11fdf7f2 TL |
962 | if (dev->device.numa_node == SOCKET_ID_ANY) |
963 | dev->device.numa_node = rte_socket_id(); | |
964 | ||
965 | ret = rte_eth_from_packet(dev, &sockfd, kvlist); | |
7c673cae FG |
966 | close(sockfd); /* no longer needed */ |
967 | ||
968 | exit: | |
969 | rte_kvargs_free(kvlist); | |
970 | return ret; | |
971 | } | |
972 | ||
973 | static int | |
11fdf7f2 | 974 | rte_pmd_af_packet_remove(struct rte_vdev_device *dev) |
7c673cae FG |
975 | { |
976 | struct rte_eth_dev *eth_dev = NULL; | |
977 | struct pmd_internals *internals; | |
978 | unsigned q; | |
979 | ||
11fdf7f2 TL |
980 | PMD_LOG(INFO, "Closing AF_PACKET ethdev on numa socket %u", |
981 | rte_socket_id()); | |
7c673cae | 982 | |
11fdf7f2 | 983 | if (dev == NULL) |
7c673cae FG |
984 | return -1; |
985 | ||
986 | /* find the ethdev entry */ | |
11fdf7f2 | 987 | eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev)); |
7c673cae FG |
988 | if (eth_dev == NULL) |
989 | return -1; | |
990 | ||
991 | internals = eth_dev->data->dev_private; | |
992 | for (q = 0; q < internals->nb_queues; q++) { | |
993 | rte_free(internals->rx_queue[q].rd); | |
994 | rte_free(internals->tx_queue[q].rd); | |
995 | } | |
11fdf7f2 | 996 | free(internals->if_name); |
7c673cae FG |
997 | |
998 | rte_free(eth_dev->data->dev_private); | |
7c673cae FG |
999 | |
1000 | rte_eth_dev_release_port(eth_dev); | |
1001 | ||
1002 | return 0; | |
1003 | } | |
1004 | ||
1005 | static struct rte_vdev_driver pmd_af_packet_drv = { | |
1006 | .probe = rte_pmd_af_packet_probe, | |
1007 | .remove = rte_pmd_af_packet_remove, | |
1008 | }; | |
1009 | ||
1010 | RTE_PMD_REGISTER_VDEV(net_af_packet, pmd_af_packet_drv); | |
1011 | RTE_PMD_REGISTER_ALIAS(net_af_packet, eth_af_packet); | |
1012 | RTE_PMD_REGISTER_PARAM_STRING(net_af_packet, | |
1013 | "iface=<string> " | |
1014 | "qpairs=<int> " | |
1015 | "blocksz=<int> " | |
1016 | "framesz=<int> " | |
11fdf7f2 TL |
1017 | "framecnt=<int> " |
1018 | "qdisc_bypass=<0|1>"); | |
1019 | ||
1020 | RTE_INIT(af_packet_init_log) | |
1021 | { | |
1022 | af_packet_logtype = rte_log_register("pmd.net.packet"); | |
1023 | if (af_packet_logtype >= 0) | |
1024 | rte_log_set_level(af_packet_logtype, RTE_LOG_NOTICE); | |
1025 | } |