Notification chain in bridge

这也是Bridge的副产品,真是好就没有没弄内核了,忘光了,还好Notification chain是个轻量级的东西。仍是联系Bridge来看,Brdige运用网络子体系的netdev_chain的有关操作也同时学习了。写这篇博客消耗2个小时。

Notification chain,翻译成告诉链,用于内核不一样的子体系之间彼此告诉一些事情,并主动触发告诉链上的函数对其进行处置。内核中注册了数以十计的告诉链。例如,激活网卡的事情,会使得sysfs在/sys下的显现发作改动,那么sysfs就会调用有关的notification chain上的函数去完结这个操作。而这些处置函数,就叫做Notifier。这个当地就有一个谁主谁次的联系,假如sysfs想在网卡em1接受到28326412个packets的时分,让网络子体系告诉它,进行一些列的操作,是不是可行?答案是不是定的,由于要从头编译内核,无法动态注册。

内核在文件kernel/notifier.c中界说了notification chain的有关操作,这些操作包含声明一个“告诉链”,向告诉链中注册“告诉块”,将“告诉块”从“告诉链”中刊出,调用告诉链中的告诉块等等。本篇博客将呈现如下词汇或相似说法,基本上即是字面意思,与内核中的布局或函数相对应:

  • 告诉链
  • 告诉块
  • 告诉函数
  • 注册告诉块
  • 刊出告诉块
  • 调用告诉函数

先看下数据布局:

1、Notification chain的首要布局


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

typedefint(*notifier_fn_t)(structnotifier_block *nb,

unsignedlongaction,void*data);

structnotifier_block {

notifier_fn_t notifier_call;

structnotifier_block __rcu *next;

intpriority;

};

structatomic_notifier_head {

spinlock_t lock;

structnotifier_block __rcu *head;

};

structblocking_notifier_head {

structrw_semaphore rwsem;

structnotifier_block __rcu *head;

};

structraw_notifier_head {

structnotifier_block __rcu *head;

};

structsrcu_notifier_head {

structmutex mutex;

structsrcu_struct srcu;

structnotifier_block __rcu *head;

};

“告诉链”以单向链表的办法保护,内核供给了几种类型的链表头,他们之间的差异在于同步机制,即在向链表中添加、删去元素时运用的同步办法,有atomic_notifier_head、blocking_notifier_head、srcu_notifier_head,当然,假如你自个有同步办法,也能够运用raw_notifier_head(NETLINK)。内核供给了几种声明并初始化“告诉链头”的宏界说,如ATOMIC_NOTIFIER_HEAD(name)、BLOCKING_NOTIFIER_HEAD(name)、RAW_NOTIFIER_HEAD(name)。

“告诉链”上的每个元素,即“告诉块”,即是布局体notifier_block,其首要效果的成员时“告诉函数”notifier_call,priority为“告诉链”上的告诉块的优先级,优先级高的“告诉函数”先履行:

nc

关于其他操作,如向告诉链中注册“告诉块”,将“告诉块”从“告诉链”中刊出,调用告诉链中的告诉块等,内核有相似如下的界说(以atomic系列为例,blocking,raw,srcu相似):


1

2

3

4

5

6

intatomic_notifier_chain_register(structatomic_notifier_head *nh,

structnotifier_block *nb);

intatomic_notifier_chain_unregister(structatomic_notifier_head *nh,

structnotifier_block *nb);

intatomic_notifier_call_chain(structatomic_notifier_head *nh,

unsignedlongval,void*v);

“告诉链”一般依照“声明告诉链头”,“注册告诉块”,“调用告诉链”的进程运用,调用xxx_notifier_call_chain()时,会依照告诉链上的告诉块的优先级由高到低的次第进行调用。

2、网络子体系的netdev_chain

网络子体系实际上不止一个“告诉链”,而netdev_chain是用来进行设备音讯告诉的,比方网卡激活、网卡地址修正等,netdev_chain声明在net/core/dev.c:


1

staticRAW_NOTIFIER_HEAD(netdev_chain);

netdev_chain撑持的事情有(include/linux/netdevice.h):


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

#define NETDEV_UP 0x0001

#define NETDEV_DOWN 0x0002

#define NETDEV_REBOOT 0x0003

#define NETDEV_CHANGE 0x0004

#define NETDEV_REGISTER 0x0005

#define NETDEV_UNREGISTER 0x0006

#define NETDEV_CHANGEMTU 0x0007

#define NETDEV_CHANGEADDR 0x0008

#define NETDEV_GOING_DOWN 0x0009

#define NETDEV_CHANGENAME 0x000A

#define NETDEV_FEAT_CHANGE 0x000B

#define NETDEV_BONDING_FAILOVER 0x000C

#define NETDEV_PRE_UP 0x000D

#define NETDEV_PRE_TYPE_CHANGE 0x000E

#define NETDEV_POST_TYPE_CHANGE 0x000F

#define NETDEV_POST_INIT 0x0010

#define NETDEV_UNREGISTER_FINAL 0x0011

#define NETDEV_RELEASE 0x0012

#define NETDEV_NOTIFY_PEERS 0x0013

#define NETDEV_JOIN 0x0014

#define NETDEV_CHANGEUPPER 0x0015

#define NETDEV_RESEND_IGMP 0x0016

为了便利netdev_chain愈加贴近于net_device操作,网络子体系在“告诉链”的基础上封装了几个netdev_chain的操作接口,基本上函数名即是字面意思,联系网桥的notifier的完成详细去剖析:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

externintregister_netdevice_notifier(structnotifier_block *nb);

externintunregister_netdevice_notifier(structnotifier_block *nb);

structnetdev_notifier_info {

structnet_device *dev;

};

structnetdev_notifier_change_info {

structnetdev_notifier_info info;/* must be first */

unsignedintflags_changed;

};

staticinlinevoidnetdev_notifier_info_init(structnetdev_notifier_info *info,

structnet_device *dev)

{

info->dev = dev;

}

staticinlinestructnet_device *

netdev_notifier_info_to_dev(conststructnetdev_notifier_info *info)

{

returninfo->dev;

}

externintcall_netdevice_notifiers_info(unsignedlongval,structnet_device *dev,

structnetdev_notifier_info *info);

externintcall_netdevice_notifiers(unsignedlongval,structnet_device *dev);

call_netdevice_notifiers的第二个参数相当于

3、Bridge里的notifier

bridge在模块初始化的时分就经过register_netdevice_notifier向netdev_chain注册了自个“告诉块”,姓名是br_device_notifier,告诉处置函数是br_device_event。br_device_notifier完成了netdev_chain撑持的一切的事情。bridge注册br_device_notifier的意图在于,假如体系内任何网络设备的装备、状况等信息发作了改动,将能够影响到网桥本身的装备、状况的改动,因而需求搜集与网桥有关的设备的装备、状况改动事情,并做有关的处置。

register_netdevice_notifier接口对比有意思(其实register_netdevice_notifier并没有调用atomic_notifier_call_chain()之类的函数,而是直接调用了告诉块的notifier_call函数),假如某模块经过register_netdevice_notifier注册自个的告诉块,则register_netdevice_notifier将网络子体系保护的一切网络的一切net_device,均运用新注册的告诉块的告诉函数+NETDEV_REGISTER参数,处置一遍。假如设备是IFF_UP状况,则再运用NETDEV_UP参数处置一遍。

应该是这样了解,netdev_chain用于保护一切网络的一切net_device的告诉事情,关于netdev_chain新注册的告诉块,对告诉块本身而言,刚刚获悉其他设备的存在,或许以为其刚刚注册,假如其他设备处于激活状况,那么新注册的告诉块以为刚刚激活,则调用一遍告诉处置函数。

不过这样以来,将发作一个风趣的表象,假如用户经过ioctl()为网桥添加一个NIC,由于网桥添加NIC的进程将致使bridge的ID和MTU从头核算,而bridge从头核算自个的ID和MTU后,假如发现ID改动了,将会发作一个告诉NETDEV_CHANGEADDR事件,netdev_chain将播送该告诉,这样bridge又会收到由于自个装备、状况发作改动而触发的自个的notifier;假如MTU的值发作了改动,相同由dev_set_mtu()接口自生就会触发一个NETDEV_CHANGEMTU事情,bridge又收到一个自个触发的事情,而notifier原则上是要接纳其他子体系的告诉。

为了防止这种循环欠套,br_device_notifier()在处置时,一方面只处置网桥设备和网桥的port设备,另一方面关于改动ID、MTU等接口,需求添加逻辑判别,假如真改动,则触发notifier,假如仅仅需求改动得与旧值共同,则不触发notifier。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值