dummy网卡驱动解析

 
dummy是linux下虚拟网卡驱动,注意这里是泛指 网卡而不是 以太网卡!!
为什么强调这一点呢?对于以太网卡,内核有更高级的接口可用。
linux-2.6.22/drivers/net/dummy.c
 
dummy网卡描述:
     dummy网卡是内核虚拟出来的网卡,没有任何实际用途,仅仅作为开发网卡驱动的参考。
本驱动只提供一个网卡接口,可以修改numdummies的值增加网卡接口个数。
本驱动只实现了发送代码,没有接收部分。
网卡发送只是简单的计数而已。
通过对本文的学习,能够对网卡驱动有个大致认识。
 
=============================================
/* dummy.c: a dummy net driver

 The purpose of this driver is to provide a device to point a
 route through, but not to actually transmit packets.

 Why?  If you have a machine whose only connection is an occasional
 PPP/SLIP/PLIP link, you can only connect to your own hostname
 when the link is up.  Otherwise you have to use localhost.
 This isn't very consistent.

 One solution is to set up a dummy link using PPP/SLIP/PLIP,
 but this seems (to me) too much overhead for too little gain.
 This driver provides a small alternative. Thus you can do

 [when not running slip]
  ifconfig dummy slip.addr.ess.here up
 [to go to slip]
  ifconfig dummy down
  dip whatever

 This was written by looking at Donald Becker's skeleton driver
 and the loopback driver.  I then threw away anything that didn't
 apply! Thanks to Alan Cox for the key clue on what to do with
 misguided packets.

   Nick Holloway, 27th May 1994
 [I tweaked this explanation a little but that's all]
   Alan Cox, 30th May 1994
*/

#i nclude <linux/module.h>
#i nclude <linux/kernel.h>
#i nclude <linux/netdevice.h>
#i nclude <linux/etherdevice.h>
#i nclude <linux/init.h>
#i nclude <linux/moduleparam.h>

static int numdummies = 1;  dummy网卡的个数,默认1

static int dummy_xmit(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *dummy_get_stats(struct net_device *dev);

提供设定MAC地址接口,供上层调用。至于在用户程序如何配置网卡MAC地址,自己查看ifconfig帮助吧:)
static int dummy_set_address(struct net_device *dev, void *p)
{
 struct sockaddr *sa = p;

 if (!is_valid_ether_addr(sa->sa_data))
  return -EADDRNOTAVAIL;

 memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
 return 0;
}

/* fake multicast ability */
static void set_multicast_list(struct net_device *dev)
{
}

static void __init dummy_setup(struct net_device *dev)
{
 /* Initialize the device structure. */
类似fops的东西初始化  这部分也是网卡驱动的关键所在。
 dev->get_stats = dummy_get_stats;
 dev->hard_start_xmit = dummy_xmit;
 dev->set_multicast_list = set_multicast_list;
 dev->set_mac_address = dummy_set_address;
 /* Fill in device structure with ethernet-generic values. */
既然dummy不是以太网卡,这里怎么用ether_setup初始化呢?
思考题,呵呵。
  ether_setup(dev);
 dev->tx_queue_len = 0;
 dev->change_mtu = NULL;
 dev->flags |= IFF_NOARP;  没有ARP支持。
 dev->flags &= ~IFF_MULTICAST;
 SET_MODULE_OWNER(dev);
给当前dummy网卡指定个随机的MAC地址,务必是唯一的
 random_ether_addr(dev->dev_addr);
}
static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{
 struct net_device_stats *stats = netdev_priv(dev);
 
简单的修改发送包个数,和包长度!
 stats->tx_packets++;
 stats->tx_bytes+=skb->len;
 
默认发送成功,释放对应内存
 dev_kfree_skb(skb);
 return 0;
}
static struct net_device_stats *dummy_get_stats(struct net_device *dev)
{
返回网卡状态信息,上层去解析
 return netdev_priv(dev);
}

static struct net_device **dummies;

/* Number of dummy devices to be set up by this module. */
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");

static int __init dummy_init_one(int index)
{
 struct net_device *dev_dummy;  dummy网卡接口对于的数据结构net_device,描述该网卡所有信息。
 int err;

调用alloc_netdev 分配网卡(不是以太网)资源,通过参数dummy%d指定内核将来配置“ifconfig dummy0”。
若是以太网卡,则调用alloc_etherdev(),内核将来配置“ifconfig ethX”
alloc_netdev(int sizeof_priv,,..)的第一个参数很重要
sizeof_priv指需要保存的额外信息所需空间大小。
dummy驱动要求提供net_device_stats空间作为私有数据区。
 
dev_dummy = alloc_netdev( sizeof(struct net_device_stats), 
     "dummy%d", dummy_setup);    立即 调用dummy_setup,初始化一些参数

 if (!dev_dummy)
  return -ENOMEM;

注册dummy网卡到内核中 
if ((err = register_netdev(dev_dummy))) {
  free_netdev(dev_dummy);
  dev_dummy = NULL;
 } else {
  dummyies[]是内核中维护dummy网卡接口的全局变量。
  dummy网卡接口的个数可以通过dummies看出。
  显然,若是以太网卡,内核里面肯定也有个数组eth[]与之对应,维护内核中所有以太网卡接口
  dummies[index] = dev_dummy;
 }

 return err;
}

static void dummy_free_one(int index)
{
 unregister_netdev(dummies[index]);  unregister_netdev()卸载网卡接口函数
 free_netdev(dummies[index]);              释放dummy网卡资源
}

static int __init dummy_init_module(void)
{
 int i, err = 0;
 dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
 if (!dummies)
  return -ENOMEM;
 for (i = 0; i < numdummies && !err; i++)
  err = dummy_init_one(i);     注册多个dummy网卡
 if (err) {
  i--;
  while (--i >= 0)
   dummy_free_one(i);
 }
 return err;
}

static void __exit dummy_cleanup_module(void)
{
 int i;
 for (i = 0; i < numdummies; i++)
  dummy_free_one(i);  释放注册的多个dummy网卡
 kfree(dummies);
}

module_init(dummy_init_module);
module_exit(dummy_cleanup_module);
MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值