Linux lookback驱动分析

来源:互联网 发布:孙俪的淘宝店铺叫什么 编辑:程序博客网 时间:2024/03/29 03:32

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, 它有下列原型:

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_setupstatic void loopback_setup(struct net_device *dev){//最大传输单元dev->mtu= (16 * 1024) + 20 + 20 + 12;        //硬件头部长度,被发送报文在 IP 头之前的字节数。对于以太网接口值为14dev->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 ), 用于发现一个合适值来赋给 protocolskb->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++;} elselb_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);}






0 0
原创粉丝点击