dma-buf 获取网卡数据的例程
时间: 2023-10-13 14:26:37 浏览: 192
下面是一个基于 DMA-BUF 的例程,用于从网卡获取数据:
```c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dma-buf.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#define MAX_SKB_SIZE 65536
static struct dma_buf *skb_to_dma_buf(struct sk_buff *skb)
{
struct dma_buf *buf;
void *addr;
size_t len;
addr = skb->data;
len = skb->len;
buf = dma_buf_export(addr, len, NULL, NULL);
if (IS_ERR(buf)) {
pr_err("Failed to export DMA buffer from skb\n");
return NULL;
}
return buf;
}
static void dma_buf_to_skb(struct dma_buf *buf, struct sk_buff *skb)
{
void *addr;
size_t len;
addr = dma_buf_vmap(buf);
if (!addr) {
pr_err("Failed to map DMA buffer\n");
return;
}
len = dma_buf_get_length(buf);
skb_put_data(skb, addr, len);
dma_buf_vunmap(buf, addr);
}
static int my_netdev_rx_handler(struct sk_buff *skb)
{
struct dma_buf *buf;
struct sk_buff *new_skb;
if (skb->len > MAX_SKB_SIZE) {
pr_err("Received packet is too large\n");
return NET_RX_DROP;
}
buf = skb_to_dma_buf(skb);
if (!buf) {
return NET_RX_DROP;
}
new_skb = netdev_alloc_skb(NULL, skb->len, GFP_ATOMIC);
if (!new_skb) {
pr_err("Failed to allocate new skb\n");
dma_buf_put(buf);
return NET_RX_DROP;
}
dma_buf_to_skb(buf, new_skb);
/* Process new_skb here */
dma_buf_put(buf);
kfree_skb(skb);
return NET_RX_SUCCESS;
}
static struct net_device *my_netdev;
static int __init my_module_init(void)
{
int err;
my_netdev = alloc_netdev(0, "my_netdev", NET_NAME_UNKNOWN, ether_setup);
if (!my_netdev) {
pr_err("Failed to allocate net device\n");
return -ENOMEM;
}
err = register_netdev(my_netdev);
if (err) {
pr_err("Failed to register net device\n");
free_netdev(my_netdev);
return err;
}
netdev_rx_handler_register(my_netdev, my_netdev_rx_handler, NULL);
return 0;
}
static void __exit my_module_exit(void)
{
netdev_rx_handler_unregister(my_netdev);
unregister_netdev(my_netdev);
free_netdev(my_netdev);
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
```
这个例程假设你已经有了一个网卡设备 `my_netdev`,并且已经调用了 `register_netdev` 将其注册到内核中。
当有新的数据包到达网卡时,内核会调用 `my_netdev_rx_handler` 函数。这个函数首先将接收到的数据包转换成 DMA-BUF,然后将其数据复制到一个新的 `sk_buff` 中,最后交由上层应用程序处理。注意,这里的数据传输是通过 DMA 实现的,因此可以获得更好的性能和可靠性。
阅读全文