Linux lookback驱动分析
2015-10-12 19:19
549 查看
Linux的网络驱动中,lookback 驱动算是最为简单的。本次分析的程序来自 Linux-2.6.32.68 源码,其中 lookback.c 驱动程序位于 /drives/net/ 目录下。
普通的网卡驱动都是以模块化注册到系统的,但是 lookback 驱动是和 kernel 一体的,Linux在启动的时候会调用 lookback 驱动。
1、设备注册
lookback网络驱动接口在一个全局的网络设备列表里插入一个数据结构.每个接口由一个结构 net_device 项来描述, 它在 <linux/netdevice.h> 里定义.
net_device 结构, 如同许多其他内核结构, 包含一个 kobject,以及因此它可被引用计数并通过 sysfs 输出. 如同别的这样的结构, 它必须动态分配. 进行这种分配的内核函数是 alloc_netdev, 它有下列原型:
sizeof_priv 是驱动的的"私有数据"区的大小;name 是这个接口的名字;setup是一个初始化函数的指针, 被调用来设置 net_device结构的剩余部分。
net_device 结构完成初始化之后,接着传递这个结构给 register_netdev 完成设备的注册。
ethtool 是一个实用工具, 提供大量控制网络接口的操作。对 ethtool 支持的相关声明可在 <linux/ethtool.h> 中找到. 它的核心是一个 ethtool_ops类型的结构, 里面包含一个全部 24 个不同方法来支持 ethtool.
执行destructor 的时候, loopback_dev_free释放了 net_device 结构,一旦已调用了free_netdev, 将再不能对个设备或者私有数据做任何引用。
网络驱动中,还声明了一些能够操作它的函数:
其中loopback_dev_init 用于设备初始化
loopback_xmit用于发送报文
loopback_get_stats用于获取接口的统计信息
普通的网卡驱动都是以模块化注册到系统的,但是 lookback 驱动是和 kernel 一体的,Linux在启动的时候会调用 lookback 驱动。
1、设备注册
lookback网络驱动接口在一个全局的网络设备列表里插入一个数据结构.每个接口由一个结构 net_device 项来描述, 它在 <linux/netdevice.h> 里定义.
net_device 结构, 如同许多其他内核结构, 包含一个 kobject,以及因此它可被引用计数并通过 sysfs 输出. 如同别的这样的结构, 它必须动态分配. 进行这种分配的内核函数是 alloc_netdev, 它有下列原型:
struct net_device *alloc_netdev( int sizeof_priv, const char *name, void (*setup)(struct net_device*));
sizeof_priv 是驱动的的"私有数据"区的大小;name 是这个接口的名字;setup是一个初始化函数的指针, 被调用来设置 net_device结构的剩余部分。
net_device 结构完成初始化之后,接着传递这个结构给 register_netdev 完成设备的注册。
/* Setup and register the loopback device. */ static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; err = -ENOMEM; //初始化net_device 结构 dev = alloc_netdev(0, "lo", loopback_setup); if (!dev) goto out; //设置网络命名空间 dev_net_set(dev, net); //注册网络设备 err = register_netdev(dev); if (err) goto out_free_netdev; net->loopback_dev = dev; return 0; out_free_netdev: free_netdev(dev); out: if (net == &init_net) panic("loopback: Failed to register netdevice: %d\n", err); return err; } Lookback驱动中初始化net_device 结构语句: dev = alloc_netdev(0, "lo", loopback_setup) 初始化函数为loopback_setup static void loopback_setup(struct net_device *dev) { //最大传输单元 dev->mtu = (16 * 1024) + 20 + 20 + 12; //硬件头部长度,被发送报文在 IP 头之前的字节数。对于以太网接口值为14 dev->hard_header_len = ETH_HLEN; /* 14 */ //硬件 (MAC) 地址长度。以太网地址长度是 6 个字节 dev->addr_len = ETH_ALEN; /* 6 */ //设备发送队列中可以排队的最大帧数 dev->tx_queue_len = 0; //接口的硬件类型,类型定义于 <linux/if_arp.h> dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ //接口标志。IFF_LOOPBACK这个标志只在环回接口中设置. 内核检查 IFF_LOOPBACK , 以代替硬连线 lo dev->flags = IFF_LOOPBACK; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL; // 声明对 ethtool 支持 dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; dev->destructor = loopback_dev_free; }
ethtool 是一个实用工具, 提供大量控制网络接口的操作。对 ethtool 支持的相关声明可在 <linux/ethtool.h> 中找到. 它的核心是一个 ethtool_ops类型的结构, 里面包含一个全部 24 个不同方法来支持 ethtool.
static const struct ethtool_ops loopback_ethtool_ops = { .get_link = always_on, .set_tso = ethtool_op_set_tso, .get_tx_csum = always_on, .get_sg = always_on, .get_rx_csum = always_on, };
执行destructor 的时候, loopback_dev_free释放了 net_device 结构,一旦已调用了free_netdev, 将再不能对个设备或者私有数据做任何引用。
static void loopback_dev_free(struct net_device *dev) { struct pcpu_lstats *lstats = dev->ml_priv; free_percpu(lstats); free_netdev(dev);
网络驱动中,还声明了一些能够操作它的函数:
static const struct net_device_ops loopback_ops = { .ndo_init = loopback_dev_init, .ndo_start_xmit= loopback_xmit, .ndo_get_stats = loopback_get_stats, };
其中loopback_dev_init 用于设备初始化
static int loopback_dev_init(struct net_device *dev) { struct pcpu_lstats *lstats; lstats = alloc_percpu(struct pcpu_lstats); if (!lstats) return -ENOMEM; dev->ml_priv = lstats; return 0; }
loopback_xmit用于发送报文
static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; int len; skb_orphan(skb); //帮助函数( eth_type_trans ), 用于发现一个合适值来赋给 protocol skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); len = skb->len; if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { lb_stats->bytes += len; lb_stats->packets++; } else lb_stats->drops++; return NETDEV_TX_OK; }
loopback_get_stats用于获取接口的统计信息
static struct net_device_stats *loopback_get_stats(struct net_device *dev) { const struct pcpu_lstats *pcpu_lstats; struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; unsigned long drops = 0; int i; pcpu_lstats = dev->ml_priv; for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; lb_stats = per_cpu_ptr(pcpu_lstats, i); bytes += lb_stats->bytes; packets += lb_stats->packets; drops += lb_stats->drops; } stats->rx_packets = packets; stats->tx_packets = packets; stats->rx_dropped = drops; stats->rx_errors = drops; stats->rx_bytes = bytes; stats->tx_bytes = bytes; return stats; }
2、设备注销
调用了unregister_netdev函数,注销一个网络设备。static __net_exit void loopback_net_exit(struct net *net) { struct net_device *dev = net->loopback_dev; unregister_netdev(dev); }
相关文章推荐
- linux命令概论
- CentOS 6.5 部署 Horizon
- centos 笔记
- linux内核之trap.c文件分析
- linux虚拟机共享文件查找,手动升级vmware tools
- linux-shell 脚本转换 十六进制 十进制 八进制 二进制
- Linux进程间通信(二) - 消息队列
- the usage of linux command "expect"
- Centos7升级内核到3.18.22
- 找到linux下当前进程启动的目录
- linux下/proc/sysrq-trigger文件的功能
- centos6.6离线安装ftp服务
- 学习日志---linux打卡7
- LINUX常用的日志分析命令
- 内存管理器(一)简单分配器
- Linux下SSH免密码登录
- [国嵌笔记][005][Linux命令详解]
- 在linux上使用yum安装JDK
- Linux内核源码(asm/bitops/atomic.h)学习
- Linux软连接和硬链接