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);
}



目录
相关文章
|
1月前
|
安全 Linux 网络虚拟化
Linux网络名称空间和Veth虚拟设备的关系
在讨论Linux网络名称空间和veth(虚拟以太网对)之间的关系时,我们必须从Linux网络虚拟化的核心概念开始。Linux网络名称空间和veth是Linux网络虚拟化和容器化技术的重要组成部分,它们之间的关系密不可分,对于构建隔离、高效的网络环境至关重要。😊
|
2月前
|
Linux API 调度
Linux系统驱动跟裸机驱动的区别
Linux系统驱动跟裸机驱动的区别
33 0
|
2月前
|
网络协议 Ubuntu Linux
Linux 动态/静态配置ip网卡信息
Linux 动态/静态配置ip网卡信息
49 0
|
2月前
|
运维 Linux Apache
Linux Apache服务详解——Apache虚拟目录与禁止显示目录列表实战
Linux Apache服务详解——Apache虚拟目录与禁止显示目录列表实战
24 2
|
2月前
|
域名解析 Linux Apache
Linux Apache服务详解——虚拟网站主机功能实战
Linux Apache服务详解——虚拟网站主机功能实战
44 5
|
2月前
|
Linux C语言 SoC
嵌入式linux总线设备驱动模型分析
嵌入式linux总线设备驱动模型分析
33 1
|
2月前
|
存储 缓存 Linux
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
39 0
|
1月前
|
Cloud Native Linux 网络虚拟化
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
在Linux网络虚拟化领域,虚拟以太网设备(veth)扮演着至关重要的角色🌐。veth是一种特殊类型的网络设备,它在Linux内核中以成对的形式存在,允许两个网络命名空间之间的通信🔗。这篇文章将从多个维度深入分析veth的概念、作用、重要性,以及在容器和云原生环境中的应用📚。
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
|
5天前
|
Linux
linux驱动层输出dev_dbg打印信息
linux驱动层输出dev_dbg打印信息
11 0
|
14天前
|
存储 监控 Linux
【专栏】在 Linux 中,了解已安装驱动器是系统管理的关键
【4月更文挑战第28天】在 Linux 中,了解已安装驱动器是系统管理的关键。本文介绍了三种方法:1) 使用 `lsblk` 命令显示设备名、大小和类型;2) `fdisk -l` 命令提供详细分区信息;3) `gnome-disks` 等系统管理工具展示驱动器信息。此外,还讨论了驱动器类型识别、挂载点概念及其应用。通过这些方法,用户能有效地监控和管理 Linux 系统中的驱动器。