虚拟网卡驱动学习记录

简介: 虚拟网卡驱动学习记录

字符设备
读写的效率比较低,主要关注数据流转和实时性。
驱动程序,会注册file_operation函数,有相应的read write函数
块设备
是以固定大小的块(一般为512字节或4KB)进行读写的设备,例如硬盘、SSD等。它们通常需要进行缓存和寻址,能够支持随机访问,并且提供了更高层次的抽象,如文件系统。侧重于缓存管理、数据组织与文件系统交互等。

怎么写虚拟网卡驱动程序?

1. 分配一个net_device结构体

    static struct net_device *vnet_dev;
    vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);

2. 设置:

2.1 发包函数: hard_start_xmit

    vnet_dev->hard_start_xmit = virtual_net_send_packet;

2.2 收到数据时(在中断处理函数里)用netif_rx上报数据
2.3 其他设置,设置MAC地址等

    vnet_dev->dev_addr[0] = 0x00;
    vnet_dev->dev_addr[1] = 0xFF;
    vnet_dev->dev_addr[2] = 0x52;
    vnet_dev->dev_addr[3] = 0xDC;
    vnet_dev->dev_addr[4] = 0xAB;
    vnet_dev->dev_addr[5] = 0xD6;
    vnet_dev->flags           |= IFF_NOARP;
    vnet_dev->features        |= NETIF_F_NO_CSUM;

3. 注册

register_netdev(vnet_dev);

部分源码

static void virtual_rx_packet(struct sk_buff *skb, struct net_device *dev)
{
       
    unsigned char *type;
    struct iphdr *ih;
    __be32 *saddr, *daddr, tmp;
    unsigned char    tmp_dev_addr[ETH_ALEN];
    struct ethhdr *ethhdr;

    struct sk_buff *rx_skb;

    // 从硬件读出/保存数据
    /* 对调"源/目的"的mac地址 */
    ethhdr = (struct ethhdr *)skb->data;
    memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);
    memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);
    memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

    /* 对调"源/目的"的ip地址 */    
    ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
    saddr = &ih->saddr;
    daddr = &ih->daddr;

    tmp = *saddr;
    *saddr = *daddr;
    *daddr = tmp;    
    type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);    
    *type = 0; /* 0表示reply */

    ih->check = 0;           /* and rebuild the checksum (ip needs it) */
    ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);

    // 构造一个sk_buff, 目的是把收到的数据同时又发出去,用来测试ping命令,因为ping自己网卡的IP,不涉及到发包,其它的IP会就会涉及到发包。
    rx_skb = dev_alloc_skb(skb->len + 2);
    skb_reserve(rx_skb, 2); /* align IP on 16B boundary */    
    memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

    /* Write metadata, and then pass to the receive level */
    rx_skb->dev = dev;
    rx_skb->protocol = eth_type_trans(rx_skb, dev);
    rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
    dev->stats.rx_packets++;
    dev->stats.rx_bytes += skb->len;
    netif_rx(rx_skb);
}

static int virtual_net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
   
    static int cnt = 0;
    printk("virt_net_send_packet cnt = %d\n", ++cnt);

    /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */
    netif_stop_queue(dev); /* 停止该网卡的队列 */
    /* ...... */           /* 把skb的数据写入网卡 */

    /* 构造一个虚拟的sk_buff,上报 */
    virtual_rx_packet(skb, dev);

    dev_kfree_skb (skb);   /* 释放skb */
    netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */

    /* 更新统计信息 */
    dev->stats.tx_packets++;
    dev->stats.tx_bytes += skb->len;

    return 0;
}

缺陷

发送skbuf部分,如果真实网卡,会相应的一系列寄存器的操作,才能把数据发出去。

相关文章
|
5天前
|
负载均衡 安全 Linux
02.Linux网卡:连接虚拟与现实的桥梁🌉
在介绍Linux网卡之前,让我们先迈入时光机🕰️,回到1980年代末期,互联网正在逐步从一个科研网络向公众网络转变,Linux——一个自由和开源的操作系统诞生了🐧。Linux的出现,对于计算机科学领域来说,就像是一场革命🔥,它不仅促进了开源文化的发展🌱,也让更多的人能够自由地使用和修改操作系统💻。
02.Linux网卡:连接虚拟与现实的桥梁🌉
|
8月前
|
Ubuntu 网络协议 Linux
嵌入式Linux系列第8篇:操作网口
嵌入式Linux系列第8篇:操作网口
|
6天前
|
编译器 Linux 开发工具
openwrt软路由基础探索
openwrt软路由基础探索
76 0
|
11月前
|
运维 Linux
【Linux运维】安装——虚拟硬件环境
【Linux运维】安装——虚拟硬件环境
|
域名解析 缓存 负载均衡
linux【网络】DNS 解析时快时慢,我该怎么办?
linux【网络】DNS 解析时快时慢,我该怎么办?
linux【网络】DNS 解析时快时慢,我该怎么办?
|
Ubuntu Linux Perl
linux实用技巧:使用脚本获取活动网卡的mac地址
linux实用技巧:使用脚本获取活动网卡的mac地址
linux实用技巧:使用脚本获取活动网卡的mac地址
|
虚拟化 数据安全/隐私保护 网络架构
在ESXi上搭建自己的OpenWRT软路由系统
在ESXi上搭建自己的OpenWRT软路由系统
在ESXi上搭建自己的OpenWRT软路由系统
|
应用服务中间件 nginx
如何在服务器上添加虚拟IP?看完原来如此简单!!
最近,有位小伙伴为了实现Nginx的高可用,在自己的服务器上搭建了一套Nginx集群,Nginx节点的服务器总共有3台。那么问题来了:如何对外只使用一个IP地址,通过某种策略来访问三个服务器节点上的Nginx?答案就是:可以使用虚拟IP来实现!那么,如何在服务器上添加虚拟IP?今天,我们就一起实操在服务器上添加虚拟IP。
1506 0
如何在服务器上添加虚拟IP?看完原来如此简单!!
|
Linux
你知道如何在Linux操作系统上添加虚拟IP吗?这篇文章帮你搞定
在高并发和高可用的场景中,往往会搭建服务器集群,那么如何将多台服务器的IP映射成一个IP地址呢?本文就帮你搞定这个问题。
227 0
你知道如何在Linux操作系统上添加虚拟IP吗?这篇文章帮你搞定