10_虚拟网卡驱动

10_虚拟网卡驱动


回顾字符设备驱动编写框架:

image-20210203153658147

回顾块设备驱动编写框架:

image-20210203153723877

1、网卡驱动框架

image-20210203153743093

app: socket

--------------------------------------------------

​ ---------------

​ --------------- 若干层网络协议–纯软件

​ ---------------

​ ---------------

hard_start_xmit || /\ (上报)

(发包) / || netif_rx 传输的是包,放在sk_buff里

​ ---------------

​ 硬件相关的驱动程序(要提供hard_start_xmit, 有数据时要用netif_rx上报)

--------------------------------------------------

​ 硬件

怎么写网卡驱动程序?

\1. 分配一个net_device结构体

\2. 设置:

2.1 发包函数: hard_start_xmit

2.2 收到数据时(在中断处理函数里)用netif_rx上报数据

2.3 其他设置

\3. 注册: register_netdevice

2、编写代码

static struct net_device *vnet_dev;

2.1、在模拟收包函数emulator_rx_packet中


static int emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)

{/* 参考LDD3 */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;

​    

​    //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) *///((u8 *)daddr)[2] ^= 1;

​    type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);//printk("tx package type = %02x\n", *type);// 修改类型, 原来0x8表示ping*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

​    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;// 提交sk_buffnetif_rx(rx_skb);}

2.2、在发包函数virt_net_send_packet中

static int virt_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里的数据通过网卡发送出去

​     \* 1真实网卡会停止该网卡的队列,

​     \* netif_stop_queue(dev); 

​     \* 2将skb的数据写入网卡数据全部发送出去后,

​     \* * ...... *

​     \* 3数据发送完之后产生中断,释放skb

​     \* dev_kfree_skb (skb);

​     \* 4在中断里唤醒网卡的队列

​     \* netif_wake_queue(dev);

​     */

 

  /* 停止该网卡的队列 */netif_stop_queue(dev);

  /* ...... */      /* 把skb的数据写入网卡 *//* 构造一个假的sk_buff,上报 */emulator_rx_packet(skb, dev);

 

  /* 释放skb */

​    dev_kfree_skb (skb);

 

  /* 数据全部发送出去后,唤醒网卡的队列 */netif_wake_queue(dev);/* 更新统计信息 */

​    dev->stats.tx_packets++;

​    dev->stats.tx_bytes += skb->len;

​    

​    return 0;

}

2.3、在入口函数virt_net_init中

static int virt_net_init(void)

{/* 1. 分配一个net_device *//* 不适用alloc_etherdev 

​     \* 来分配结构体,因为会分配一个eth*名称的

​     \* 参数1:私有数据

​     \* 参数2:名称

​     */

​    vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);/* 2. 设置 */

​    vnet_dev->hard_start_xmit = virt_net_send_packet;/* 设置MAC地址 */

  vnet_dev->dev_addr[0] = 0x08;

	。。。

  vnet_dev->dev_addr[5] = 0x11;/* 设置下面两项才能ping通 */

​    vnet_dev->flags       |= IFF_NOARP;

​    vnet_dev->features |= NETIF_F_NO_CSUM;/* 3. 注册 *///register_netdevice(vnet_dev);register_netdev(vnet_dev);return 0;

}

2.4、在出口函数virt_net_exit中

static void virt_net_exit(void)

{unregister_netdev(vnet_dev);free_netdev(vnet_dev);

}

3、测试

1th

\1. insmod virt_net.ko
Ifconfig

\2. ifconfig vnet0 3.3.3.3

ifconfig // 查看

image-20210203154144683

\3. ping 3.3.3.3 // ping自己成功,这是纯软件概念,与网卡硬件层无关

ping 3.3.3.4 // ping别人死机,需要经过硬件层,使用收发包函数来传输,但还没设置,必然死机

image-20210203154202231

能够ping的通自己,说明传输时没有经过硬件相关层,即没有使用收发包函数就直接返回数据了。

image-20210203154214703

2th

\1. insmod virt_net.ko

Ifconfig

image-20210203154233972

\2. ifconfig vnet0 3.3.3.3

ifconfig // 查看

image-20210203154248644

\3. ping 3.3.3.3 // ping自己成功,这是纯软件概念,与网卡硬件层无关

ping 3.3.3.4 // ping别人成功,经过硬件层设置

image-20210203154308036

问题1:虽然成功ping通别的IP,发送了6个包,但是缺少统计信息不能显示出来;

问题2:并且HWaddr 00:00:00:00:00:00。

image-20210203154320502

3th

\1. insmod virt_net.ko

ifconfig

\2. ifconfig vnet0 3.3.3.3

ifconfig // 查看

\3. ping 3.3.3.3 // ping自己成功,这是纯软件概念,与网卡硬件层无关

ping 3.3.3.4 // ping成功

改1:更新统计信息

​ dev->stats.tx_packets++;

​ dev->stats.tx_bytes += skb->len;

改2:设置MAC地址之后;HWaddr 08:89:89:89:89:11

image-20210203154339144

问题3:但是不能收到别人的包,只能发包

4th

\1. insmod virt_net.ko

ifconfig

\2. ifconfig vnet0 3.3.3.3

ifconfig // 查看

\3. ping 3.3.3.3 // ping自己成功,这是纯软件概念,与网卡硬件层无关

ping 3.3.3.4 // ping成功

改3:虚构一个包,再使用函数 netif_rx(rx_skb)来提交sk_buff

image-20210203154414341

这样就可以实现收发功能了

= skb->len;

改2:设置MAC地址之后;HWaddr 08:89:89:89:89:11

[外链图片转存中…(img-FujWXWca-1612338393611)]

问题3:但是不能收到别人的包,只能发包

4th

\1. insmod virt_net.ko

ifconfig

\2. ifconfig vnet0 3.3.3.3

ifconfig // 查看

\3. ping 3.3.3.3 // ping自己成功,这是纯软件概念,与网卡硬件层无关

ping 3.3.3.4 // ping成功

改3:虚构一个包,再使用函数 netif_rx(rx_skb)来提交sk_buff

[外链图片转存中…(img-W2OVAeio-1612338393612)]

这样就可以实现收发功能了

image-20210203154430370

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值