Linux驱动之虚拟网卡

简介:

写网卡驱动之前我总结一下个人的一些观点:其实写驱动并不是大家想想的那么难,这里我客观评价一下内核层和应用层的区别:

底层:

工作在内核层的朋友应该有这种感觉,才开始学的时候真的很难,也就是说上手难,我就拿Linux驱动来说吧,写一个完整的驱动,你得装一个虚拟机跑Linux吧,用来编译驱动程序,虚拟机里面需要安装一些库和工具,驱动程序必须跑在一个完整的系统上,所以首先你得搭建好整个系统,你还得了解硬件时序等,这些东西对新手来说真的是够头痛了,但是你会发现你真正的成为一个驱动开发人员后你就有一种豁然开朗的感觉,原来写驱动程序这么简单,框架是不变的。所以说工作在底层的软件开发朋友们也不要觉得自己是多厉害,只是起点稍微高了一点。

应用层:

应用层相对来说上手就简单一点了,主要有以下几个方面的体现:

第一、用到的工具很少,写应用程序基本都是集成开发环境下,就那么一个工具,编译成功基本就可以使用。

第二、调试代码的时候是最方便的,加一些打印语句,然后运行就能够找到逻辑结构的错误。非常节省时间

第三、出现错误了,网上一贴,基本上问题就解决了。

难点:写一个应用程序逻辑结构思维是非常强的,你的代码量也相对的多每天接触的东西有可能不一样,需要不断的去更新自己的知识。

以上只是个人的观点,如有不同见解的可以留言。


写这个代码时遇到了一个问题,至今没有得到解决,问题叙述如下:我ping其他ip地址都是能够ping通的,就是不能够ping通自己,我目前也不知道原因,有知道原因的朋友,希望能够分享一下。



虚拟网卡驱动总结如下:

/*
 * 参考 drivers\net\cs89x0.c
 */
static struct net_device *vnet_dev;


static void 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_buff
netif_rx(rx_skb);
}

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里的数据通过网卡发送出去 */
netif_stop_queue(dev); /* 停止该网卡的队列 */
    /* ...... */           /* 把skb的数据写入网卡 */


/* 构造一个假的sk_buff,上报 */
emulator_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;
}

static int virt_net_init(void)
{
/* 1. 分配一个net_device结构体 */
vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);;  /* alloc_etherdev */

/* 2. 设置 */
vnet_dev->hard_start_xmit = virt_net_send_packet;

/* 设置MAC地址 */
    vnet_dev->dev_addr[0] = 0x08;
    vnet_dev->dev_addr[1] = 0x89;
    vnet_dev->dev_addr[2] = 0x89;
    vnet_dev->dev_addr[3] = 0x89;
    vnet_dev->dev_addr[4] = 0x89;
    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;
}


static void virt_net_exit(void)
{
unregister_netdev(vnet_dev);
free_netdev(vnet_dev);
}



目录
相关文章
|
4月前
|
监控 网络协议 Linux
在Linux中,如何查看某个网卡是否连接着交换机?
在Linux中,如何查看某个网卡是否连接着交换机?
|
4月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
47 6
|
3月前
|
Linux Python
linux之部署python环境&创建虚拟环境
linux之部署python环境&创建虚拟环境
|
4月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
52 5
|
4月前
|
Ubuntu NoSQL Linux
Linux内核和驱动
Linux内核和驱动
31 2
|
4月前
|
数据采集 Linux
Linux源码阅读笔记20-PCI设备驱动详解
Linux源码阅读笔记20-PCI设备驱动详解
|
3月前
|
Linux API
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
|
4月前
|
网络协议 Ubuntu Linux
在Linux中,如何将本地80端口的请求转发到8080端口,当前主机IP为192.168.16.1,其中本地网卡eth0。
在Linux中,如何将本地80端口的请求转发到8080端口,当前主机IP为192.168.16.1,其中本地网卡eth0。
|
4月前
|
Ubuntu Linux 网络安全
在Linux中,能否给⼀个网卡配置多个IP? 如果能,怎么配置?
在Linux中,能否给⼀个网卡配置多个IP? 如果能,怎么配置?
|
4月前
|
Ubuntu Linux
在Linux中,想修改ip,需要编辑哪个配置⽂件?修改完配置⽂件后,如何重启网卡?使配置生效?
在Linux中,想修改ip,需要编辑哪个配置⽂件?修改完配置⽂件后,如何重启网卡?使配置生效?