网卡驱动2-做一个与外界交互的虚拟网卡1(引用真实的网卡、自定义协议号注册)

之前的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表去管理。

下期说发送和接收。

你可能感兴趣的:(linux,内核,linux内核)