回环网卡驱动
1.回环网卡和普通网卡的区别是他是虚拟的不是实际的物理网卡,它相当于把普通网卡的发送端和接收端短接在一起。

2.在内核源代码里的回环网卡程序(drivers/net/loopback.c)不是以一个模块的形式给出,但是他的初始化(loopback_net_init)和退出函数(loopback_dev_free)会被内核的其他部分调用到。

3.参照网卡初始化的流程图进行设计驱动程序,其中分配net_device结构不能用alloc_etherdev函数,因为该函数是分配以太网卡的结构体的,要用alloc_netdev函数来给回环网卡分配结构体。参考内核源代码别人如何用使用这个函数alloc_netdev(0, "lo", loopback_setup);第一个0表示net_device这个结构体的私有成员的大小,一般选择0,第二个表示网卡名字,ifconfig显示的名称,第三个就是具体的网卡结构体的初始化函数指针。
struct net_device *dev;
dev = alloc_netdev(0, "lo", loopback_setup);
最终会调用到loopback_setup函数。(至于在将函数指针作为参数的时候如何传递形参,就要复习C语言了)
4.回环网卡不需要初始化硬件。所以直接注册回环网卡的结构体到内核(第三步)。最后指定回环网卡注册到网络子系统。
net->loopback_dev = dev;这一步很关键。

5.具体的初始化(loopback_setup)(第二步)
(1)基地址,MAC地址以及中断号都用不着,主要是netdev_ops这个结构体,他包含了这个网卡支持的操作。

(2)表示回环网卡支持的最大的接收数据的包的大小,除了正式数据,还有相关网络协议的头部分。
dev->mtu          = (16 * 1024) + 20 + 20 + 12;有效数据一般定义为16KB。

(3)加上表示回环网卡专有的标志。
dev->flags          = IFF_LOOPBACK;

(4)加上构造报头的结构体指针,这个结构体指针指向的结构体成员是众多构造以太网报头的函数指针。
dev->header_ops          = &eth_header_ops;
理想查找可看到
extern const struct header_ops eth_header_ops;

struct header_ops {
     int     (*create) (struct sk_buff *skb, struct net_device *dev,
                  unsigned short type, const void *daddr,
                  const void *saddr, unsigned len);
     int     (*parse)(const struct sk_buff *skb, unsigned char *haddr);
     int     (*rebuild)(struct sk_buff *skb);
#define HAVE_HEADER_CACHE
     int     (*cache)(const struct neighbour *neigh, struct hh_cache *hh);
     void     (*cache_update)(struct hh_cache *hh,
                    const struct net_device *dev,
                    const unsigned char *haddr);
};
6.数据发送

static int loopback_net_xmit(struct sk_buff *skb,struct net_device *dev)
{
skb->protocol = eth_type_trans(skb,dev);

packets++;
bytes += skb->len;

netif_rx(skb);

return 0;
}

}
(1)第一个参数是协议栈传送给回环网卡的包数据,第二个参数是回环网卡的结构体。

(2)停止发送队列
通知上层暂停送数据,好让txd发送已送达的数据,但是不涉及硬件,所以在回环网卡可忽略。相应的,将数据写入寄存器和唤醒再次发送以及释放队列就可忽略。

(3)信息统计,表明上层送下来的包的协议
skb->protocol = eth_type_trans(skb, dev);

(4)统计发送过来的数据大小以及包的个数。

bytes += skb->len;

netif_rx(skb);

7.由于从协议栈来的数据包(skb)存放到txd,而且txd不需要往外发送,txd和rxd“连”在一起,所以直接在发送部分调用普通网卡的接收部分的netif_rx(skb)函数,所以发送的同时就完成了接收。同时我们更清楚地看到在发送的时候不能释放skb,否则没有可接收的数据。

8.实现获取网卡状态的函数

static struct net_device_stats *loopback_get_stats(struct net_device *dev)
{
struct net_device_stats *stats = &dev->stats;

stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;

return stats;
}

从这个结构体可以获取网卡状态信息
/* The main device statistics structure */
struct rtnl_link_stats64 {
     __u64     rx_packets;          /* total packets received     */
     __u64     tx_packets;          /* total packets transmitted     */
     __u64     rx_bytes;          /* total bytes received      */
     __u64     tx_bytes;          /* total bytes transmitted     */
     __u64     rx_errors;          /* bad packets received          */
     __u64     tx_errors;          /* packet transmit problems     */
     __u64     rx_dropped;          /* no space in linux buffers     */
     __u64     tx_dropped;          /* no space available in linux     */
     __u64     multicast;          /* multicast packets received     */
     __u64     collisions;

/* detailed rx_errors: */
     __u64     rx_length_errors;
     __u64     rx_over_errors;          /* receiver ring buff overflow     */
     __u64     rx_crc_errors;          /* recved pkt with crc error     */
     __u64     rx_frame_errors;     /* recv'd frame alignment error */
     __u64     rx_fifo_errors;          /* recv'r fifo overrun          */
     __u64     rx_missed_errors;     /* receiver missed packet     */

/* detailed tx_errors */
     __u64     tx_aborted_errors;
     __u64     tx_carrier_errors;
     __u64     tx_fifo_errors;
     __u64     tx_heartbeat_errors;
     __u64     tx_window_errors;

/* for cslip etc */
     __u64     rx_compressed;
     __u64     tx_compressed;
};
主要是这四个成员
  stats->rx_packets = packets;
     stats->tx_packets = packets;
     stats->rx_bytes   = bytes;
     stats->tx_bytes   = bytes;
。实际上自己可以重写这个获取状态的函数,因为struct net_device *dev有一个成员就是struct net_device_stats     stats;所以可以在重写的时候定义一个struct net_device_stats     stats指向形参传递进来的回环网卡结构体的stats成员,同样只需要注意stats成员的上述四个成员即可。

9.在退出该驱动的时候就是取消注册结构体。达到注销网卡的目的。

static __net_exit void loopback_net_exit(struct net *net)
{
struct net_device *dev = net->loopback_dev;

unregister_netdev(dev);
}

下面为范例代码

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h> /* For the statistics structure. */ unsigned long bytes = ;
unsigned long packets = ; static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{ skb->protocol = eth_type_trans(skb,dev); //标明数据包的协议---以太网协议 bytes += skb->len; //发送包的长度
packets++; //包的数目 netif_rx(skb); return ;
} static struct net_device_stats *loopback_get_stats(struct net_device *dev)
{
struct net_device_stats *stats = &dev->stats; stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
} static const struct net_device_ops loopback_ops = {
.ndo_start_xmit= loopback_xmit,
.ndo_get_stats = loopback_get_stats, //获取网卡状态信息
}; /*
* The loopback device is special. There is only one instance
* per network namespace.
*/
static void loopback_setup(struct net_device *dev)
{
dev->mtu = ( * ) + + + ; //网卡能接收的最大数据包的大小 tcp头 20 以太网头 20 ip头 12
dev->flags = IFF_LOOPBACK; //回环网卡标志位
dev->header_ops = &eth_header_ops; //数据头的构造函数(以太网头构造函数) 直接使用内核自带的函数 内核自动调用该函数
dev->netdev_ops = &loopback_ops; //网卡操作函数集 } /* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net)
{
struct net_device *dev;
int err;
err = -ENOMEM;
dev = alloc_netdev(, "lo", loopback_setup); //分配net_device结构-alloc_etherdev(以太网) setup初始化netdev
if (!dev)
goto out; err = register_netdev(dev);
if (err)
goto out_free_netdev; net->loopback_dev = dev; //将分配好的dev告诉网络(回环网卡特有)
return ; out_free_netdev:
free_netdev(dev);
out:
if (net == &init_net)
panic("loopback: Failed to register netdevice: %d\n", err);
return err;
} static __net_exit void loopback_net_exit(struct net *net)
{
struct net_device *dev = net->loopback_dev; unregister_netdev(dev);
} /* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
.init = loopback_net_init,
.exit = loopback_net_exit,
};

linux回环网卡驱动设计的更多相关文章

  1. windows 7中添加新硬件的两种方法(本地回环网卡)

    最近在windows7上使用VMwareWorkstation7玩一些实验,遇到需要配置不同网络的问题. 因为在windows2003server上习惯使用要本地回环网卡了,那就想着在Windows7 ...

  2. Linux下查看网卡驱动和版本信息

    Linux下查看网卡驱动和版本信息 查看网卡生产厂商和信号 查看基本信息:lspci 查看详细信息:lspci -vvv # 3个小写的v 查看网卡信息:lspci | grep Ethernet 查 ...

  3. 新装Linux系统没有网卡驱动的解决办法和步骤

    Linux下查看网卡驱动和版本信息 - CSDN博客 https://blog.csdn.net/guyan1101/article/details/72770424/ 检查网卡是否加载 - Linu ...

  4. 怎样在linux下安装网卡驱动

    由于我电脑的各种奇葩问题的存在,导致我装上Ubuntu13.10之后网卡居然无法使用,坚持了挺久使用无线网,终于坚持不住了,百度了各种解决方式,终于成功解决.这里也记录一下我的解决过程,供大家参考.大 ...

  5. Linux回环接口(loop-back/loopback)

    回环接口(loop-back/loopback) Moakap整理 Loopback接口是一个虚拟网络接口,在不同的领域,其含义也大不一样. 1. TCP/IP协议栈中的loopback接口 在TCP ...

  6. Linux回环接口-----(loop-back/loopback)

    回环接口(loop-back/loopback) Moakap整理 Loopback接口是一个虚拟网络接口,在不同的领域,其含义也大不一样. 1. TCP/IP协议栈中的loopback接口 在TCP ...

  7. Linux系统安装-MacBook网卡驱动问题解决

    先附上MacBook的linux安装教程 需要注意的是第7步中可能无法识别出OS X的系统,也没关系,只要格式化磁盘的时候注意选择对应磁盘即可,格式化成EXT4分区. 安装好后发现无法连接无线网络,应 ...

  8. 安装Loopback网卡/回环网卡

    $CurrentPath = $MyInvocation.MyCommand.Path.substring(0,$MyInvocation.MyCommand.Path.LastIndexOf('\' ...

  9. Linux网卡驱动

    <网络知识> a:网络模型               OSI模型               TCP模型 虽然OSI模型看着挺完美的,但是过于复杂,这样就会导致不实用,在Linux系统中 ...

随机推荐

  1. sqlserver添加用户的时候出现 错误18456

    1.用本机默认的window身份验证登录 2.登录成功后,在数据库->安全性->登录名->右键属性->如图选择“新建登录名” 3.在如图所示的登录名中,输入将要新建的登录用户, ...

  2. python编写接口

  3. com学习前提必看

    1) COM组件实际上是一个C++类,而接口都是纯虚类.组件从接口派生而来.我们可以简单的用纯粹的C++的语法形式来描述COM是个什么东西: class IObject { public: virtu ...

  4. Swift 学习一函数&函数属性&懒加载

    函数 函数相当于OC中的方法 格式: func 函数名(参数列表) -> 返回值类型 {    代码块    return 返回值} func 函数名(参数列表){  // 返回值为Void 可 ...

  5. django中时区设置

    通过django中的models更新数据库的DateTimeField字段,发现有错误,于是更改了: TIME_ZONE = 'Asia/Shanghai' 结果,还是不正确,于是把: USE_TZ ...

  6. 在集群环境中使用 EhCache 缓存系统|RMI 集群模式

    RMI 是 Java 的一种远程方法调用技术,是一种点对点的基于 Java 对象的通讯方式.EhCache 从 1.2 版本开始就支持 RMI 方式的缓存集群.在集群环境中 EhCache 所有缓存对 ...

  7. [前端 4] 使用Js实现图片上传预览

    导读:今天做图片上传预览,刚开始的做法是,先将图片上传到Nginx,然后重新加载页面才能看到这个图片.在这个过程中,用户一直都看不到自己上传的文件是什么样子.Ps:我发现我真的有强迫症了,都告诉我说不 ...

  8. ionic pull to refresh 下拉更新頁面

    有些項目都用到了下拉更新頁面的效果: 1. 在index.html 中添加ion-refresher 指令 且在我們需要更新內容的外面 添加 如 <ion-refresher pulling-t ...

  9. nagios架构及windows,linux客户端配置

    Linux下Nagios的安装与配置 一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等. ...

  10. 【MySQL】binlog_format以及binlog事务记录分析

    MySQL官方对于binlog_format参数的说明: http://dev.mysql.com/doc/refman/5.5/en/binary-log-setting.html binlog_f ...