內核版本:2.6.34
接上篇《添加網絡協議》。
為了用戶方便查看brcm設備的工作狀態(tài),使用proc文件系統(tǒng)是很好的方式。一個網絡協議模塊可以注冊到網絡空間中
register_pernet_subsys(),這個函數會為子空間分配一個id號,通過id可以在網絡空間中找到分配給該子空間的內
存:init_net->gen->ptr[id - 1]。而我們正是利用這塊內存去存儲proc中的相關信息:struct
brcm_net,它記錄了brcm設備在proc文件系統(tǒng)中的位置。
- struct brcm_net {
-
- struct proc_dir_entry *proc_brcm_dir;
-
- struct proc_dir_entry *proc_brcm_conf;
- };
在加載brcm模塊時會注冊子空間,brcm_init_net創(chuàng)建在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設備是可以動態(tài)創(chuàng)建的,因此這部分代碼應該發(fā)生在添加和刪除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文件系統(tǒng);其次,對于發(fā)往brcm下層設備的事件,要考慮這些事件造
成的連帶影響(比如eth1被down掉,則其上的brcm設備也應該被down掉),一般是下層設備的事件對其上的所有brcm設備都進行相應操作。
所以在brcm_device_event有兩類進入的設備dev會進行操作,一類是brcm設備,它僅僅是操作proc文件系統(tǒng)。判斷是否為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:
-
- 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:
-
- 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:
-
- 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:
-
- 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:
-
- grp->killall = 1;
-
- for (i = 0; i < BRCM_GROUP_ARRAY_LEN; i++) {
- brcmdev = brcm_group_get_device(grp, i);
- if (!brcmdev)
- continue;
-
-
-
- if (grp->nr_ports == 1)
- i = BRCM_GROUP_ARRAY_LEN;
-
- unregister_brcm_dev(brcmdev, &list);
- }
- unregister_netdevice_many(&list);
- break;
- }
到這里,協議的添加就大致完成了,當然還包括一些頭文件的修改,宏變量的添加等就不一一詳述,具體可見最后的附件。
為了編譯進內核,還需要修改以下文件:
$(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設備后的狀態(tài):

可以使用原生套接字自己打上brcm頭后發(fā)送報文讓協議棧接收,或者用wireshark等捕獲協議棧發(fā)出的報文,下圖即是捕獲到的報文:

這是主機發(fā)出的arp報文,可以看到,在源mac后接的不是vlan報頭,而是我們添加的brcm報文,協議號是8744。
查看proc中信息:

附:patch補丁 && 重要的源文件 && bconfig工具源碼
http://download.csdn.net/source/3548117
|