之前的snull只能自娱自乐,我们来实现一个可以和外部通讯的虚拟网卡。
这个虚拟网卡参考了vlan协议实现。
重点我们说四个东西,引用真实的网卡、自定义协议号注册、发送和接受。
Linux-3.0.8
引用真实的网卡:
单从程序上看就这一句:
real_netdev = dev_get_by_name(&init_net, "eth0");
dev_get_by_name()和init_net
init_net是struct net结构,这个结构中有两个成员
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
你可以想象到应该还有个函数时dev_get_by_index()。每个struct net_device有一个ifindex成员,在此会用到。
dev_get_by_name就是获取通过name去查找hash表。找到对应的网卡结构体地址。
从这点我们也可以看出内核用一个hash表去管理网卡设备。
我们再看在那把网卡放入此hash表。首先说一下init_net,它是一个全局变量,如果要使用它,需要包含头文件net/net_namespace.h。
写网卡驱动时,会调用register_netdevice(dev)注册设备
在里面会调用
static int list_netdevice(structnet_device *dev)
{
struct net *net = dev_net(dev);// #defineread_pnet(pnet) (&init_net)
//…
list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net,dev->name));
hlist_add_head_rcu(&dev->index_hlist,
dev_index_hash(net,dev->ifindex));
//…
可以看出除了两个hash表以外,还有一个链表结构。
随便提一下rcu,可以看下面的博客
http://blog.csdn.net/ustc_dylan/article/details/4049647
获取完了以后,就可以通过调用netdev_ops去操作硬件了。
自定义协议号注册:
我们这个网卡就只接受自己定义的一个协议,所以我们向内核添加一个:
static struct packet_typevnic_pack_type __read_mostly =
{
.type =cpu_to_be16(ETH_P_VNIC),
.func = vnic_rcv,//接收函数
};
dev_add_pack(&vnic_pack_type);
ETH_IP_VNIC是我自定义的。当然你也可以添加上内核已提供的ARP、IP等,就可以接收ARP或IP了。
这里说一下dev_add_pack()
这个函数会被次结构体链接到
if (pt->type == htons(ETH_P_ALL))
return &ptype_all;
else
return&ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
我的当然是下面这个
static struct list_headptype_base[PTYPE_HASH_SIZE] __read_mostly;
也是一个hash表去管理。
下期说发送和接收。