linux 适配电脑内核,Linux内核实践 如何添加网络协议[三]:实现 -电脑资料

内核版本:2.6.34

接上篇《添加网络协议》,

为了用户方便查看brcm设备的工作状态,使用proc文件系统是很好的方 式。一个网络协议模块可以注册到网络空间中register_pernet_subsys(),这个函数会为子空间分配一个id号,通过id可以在网 络空间中找到分配给该子空间的内存:init_net->gen->ptr[id - 1]。而我们正是利用这块内存去存储proc中的相关信息 :struct brcm_net,它记录了brcm设备在proc文件系统中的位置。

struct brcm_net {

/* /proc/net/brcm */

struct proc_dir_entry *proc_brcm_dir;

/* /proc/net/brcm/config */

struct proc_dir_entry *proc_brcm_conf;

};

在加载brcm模块时会注册子空间,brcm_init_net创建在proc中的相关项,并记录路径在brcm_net中; brcm_exit_net删除在proc中的相关项;brcm_net_id记录分配给子空间的id,这样通过init_net->gen->ptr[brcm_net_id - 1]就可以操作brcm_net了。

err = register_pernet_subsys(&brcm_net_ops);

static struct pernet_operations brcm_net_ops = {

.init = brcm_init_net,

.exit = brcm_exit_net,

.id = &brcm_net_id,

.size = sizeof(struct brcm_net),

};

注意到在brcm_init_net和brcm_exit_net中添加和删除的仅仅是/proc/net/brcm目录和config文件,而在使用中 brcm设备是可以动态创建的,因此这部分代码应该发生在添加和删除brcm设备时,而不是在brcm模块注册和删除时。最简单的是 直接添加在register方法或unregister方法中,但内核提供了更好的机制:事件,将对proc的操作分离出来,因为proc的操作实 际上属于附加的操作而不是必须的操作。下面就来看event机制。

前面几篇已经有描述过event机制,这里的事件都是关于设 备的事件,使用的是register_netdevice_notifier()来,注册notifier到netdev_chain链表上。在加载brcm模块时注册 notifier,brcm_notifier_block包含了brcm设备对所关心的事件作出的反应。

err = register_netdevice_notifier

(&brcm_notifier_block);

static struct notifier_block brcm_notifier_block __read_mostly = {

.notifier_call = brcm_device_event,

};

设备对哪些事件会感兴趣,首先,brcm设备对注册和注销是感兴趣的,要操作proc文件系统;其次,对于发往brcm 下层设备的事件,要考虑这些事件造成的连带影响(比如eth1被down掉,则其上的brcm设备也应该被down掉),一般是下层设备的 事件对其上的所有brcm设备都进行相应操作。

所以在brcm_device_event有两类进入的设备dev会进行操作,一类是brcm设备 ,它仅仅是操作proc文件系统。判断是否为brcm设备,是的话则由__brcm_device_event() 处理。

if (is_brcm_dev(dev))

__brcm_device_event(dev, event);

static void __brcm_device_event(struct net_device *dev, unsigned long event)

{

switch (event) {

case NETDEV_CHANGENAME:

brcm_proc_rem_dev(dev);

if (brcm_proc_add_dev(dev) < 0)

pr_warning("BRCM: failed to change proc name for %s\n",

dev->name);

break;

case NETDEV_REGISTER:

if (brcm_proc_add_dev(dev) < 0)

pr_warning("BRCM: failed to add proc entry for %s\n",

dev->name);

break;

case NETDEV_UNREGISTER:

brcm_proc_rem_dev(dev);

break;

}

}

如何是brcm的下层设备,如根据brcm_group_hash中的映射关系,对下层设备相关的所有brcm设备进行操作:

switch (event) {

case NETDEV_CHANGE:

/* Propagate real device state to vlan devices */

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

netif_stacked_transfer_operstate(dev, brcmdev);

}

break;

case NETDEV_CHANGEADDR:

/* Adjust unicast filters on underlying device */

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

flgs = brcmdev->flags;

if (!(flgs & IFF_UP))

continue;

brcm_sync_address(dev, brcmdev);

}

break;

case NETDEV_CHANGEMTU:

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

if (brcmdev->mtu <= dev->mtu)

continue;

dev_set_mtu(brcmdev, dev->mtu);

}

break;

case NETDEV_DOWN:

/* Put all VLANs for this dev in the down state too. */

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

flgs = brcmdev->flags;

if (!(flgs & IFF_UP))

continue;

brcm = brcm_dev_info(brcmdev);

dev_change_flags(brcmdev, flgs & ~IFF_UP);

netif_stacked_transfer_operstate(dev, brcmdev);

}

break;

case NETDEV_UP:

/* Put all VLANs for this dev in the up state too. */

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

flgs = brcmdev->flags;

if (flgs & IFF_UP)

continue;

brcm = brcm_dev_info(brcmdev);

dev_change_flags(brcmdev, flgs | IFF_UP);

netif_stacked_transfer_operstate(dev, brcmdev);

}

break;

case NETDEV_UNREGISTER:

/* Delete all BRCMs for this dev. */

grp->killall = 1;

for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {

brcmdev = brcm_group_get_device(grp, i);

if (!brcmdev)

continue;

/* unregistration of last brcm destroys group, abort

* afterwards */

if (grp->nr_ports == 1)

i = BRCM_GROUP_ARRAY_LEN;

unregister_brcm_dev(brcmdev, &list);

}

unregister_netdevice_many(&list);

break;

}

到这里,协议的添加就大致完成了,当然还包括一些头文件的修改,宏变量的添加等就不一一详述,具体可见最后的附件,Linux内核实践 如何添加网络协议[三]:实现》(https://www.unjs.com)。

为了编译进内核,还需要修改以下文件:

$(linux)/net/Kconfig  $(linux)/net/Makefile

最后,在make menuconfig选择添加brcm协议

Networking Support -> Networking options

同时,需要一个简单 的用户空间工具来配置我们的brcm设备,就像vconfig用来配置vlan设备一样;编写的简单的bconfig工具,命令格式:

"Usage: add [interface-name] [brcm_port]\n"

"       rem [dev-name]";

内核编译完成后就该进行测试了,如果开启了内核调 试信息,启动内核就看到以下信息:

然后启用网卡,可以查看到添加了brcm设备后的状态:

可以使用原生套接字自己打上brcm头后发送报文让协议栈接收,或者用wireshark等捕获协议栈发出的报文,下图即是捕获到 的报文:

这是主机发出的arp报文,可以看到,在源mac后接的不是vlan报头,而是我们添加的brcm报文,协议号是8744。

查看proc 中信息:

附:patch补丁 && 重要的源文件 && bconfig工具源码

http://download.csdn.net/source/3548117

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值