深入理解Linux网络技术内幕 第4章 通知链
2020-06-07 06:12
232 查看
通知链
概述
内核多个子系统之间具有相互依赖性,因此一个子系统需要侦测或产生其他子系统感兴趣的事件。
在网络协议栈中,比如路由子系统对网卡设备的UP、DOWN就非常感兴趣,路由子系统根据网卡产生的事件执行相应的动作。
通知链就是一个函数链表,当给定的事情发生时,就调用链表中的所有的函数。通知链有两个角色:
- 被通知者(notified),注册回调函数给通知者。
- 通知者(notifier),产生事件并调用回调函数。
定义通知链
内核使用struct notifier_block描述一个通知链元素。
notifier_call成员是回调函数。
struct notifier_block { notifier_fn_t notifier_call; struct notifier_block __rcu *next; int priority; };
注册通知链
notifier_chain_register函数用于实现将通知链元素放入链表中。
static int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n) { while ((*nl) != NULL) { if (n->priority > (*nl)->priority) break; nl = &((*nl)->next); } n->next = *nl; rcu_assign_pointer(*nl, n); return 0; }
通知链事件通知
notifier_call_chain函数依次调用链表中的回调函数。回调函数的返回值会影响到后面回调函数是否被调用。
#define NOTIFY_DONE 0x0000 /* Don't care */ #define NOTIFY_OK 0x0001 /* Suits me */ #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ #define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ /* * Clean way to return from the notifier and stop further calls. */ #define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) static int notifier_call_chain(struct notifier_block **nl, unsigned long val, void *v, int nr_to_call, int *nr_calls) { int ret = NOTIFY_DONE; struct notifier_block *nb, *next_nb; nb = rcu_dereference_raw(*nl); while (nb && nr_to_call) { next_nb = rcu_dereference_raw(nb->next); #ifdef CONFIG_DEBUG_NOTIFIERS if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { WARN(1, "Invalid notifier called!"); nb = next_nb; continue; } #endif ret = nb->notifier_call(nb, val, v); if (nr_calls) (*nr_calls)++; if (ret & NOTIFY_STOP_MASK) break; nb = next_nb; nr_to_call--; } return ret; }
网络子系统的通知链
网络设备通知链
/** * register_netdevice_notifier - register a network notifier block * @nb: notifier * * Register a notifier to be called when network device events occur. * The notifier passed is linked into the kernel structures and must * not be reused until it has been unregistered. A negative errno code * is returned on a failure. * * When registered all registration and up events are replayed * to the new notifier to allow device to have a race free * view of the network device list. */ int register_netdevice_notifier(struct notifier_block *nb) { struct net_device *dev; struct net_device *last; struct net *net; int err; /* Close race with setup_net() and cleanup_net() */ down_write(&pernet_ops_rwsem); rtnl_lock(); err = raw_notifier_chain_register(&netdev_chain, nb); if (err) goto unlock; if (dev_boot_phase) goto unlock; for_each_net(net) { for_each_netdev(net, dev) { err = call_netdevice_notifier(nb, NETDEV_REGISTER, dev); err = notifier_to_errno(err); if (err) goto rollback; if (!(dev->flags & IFF_UP)) continue; call_netdevice_notifier(nb, NETDEV_UP, dev); } } unlock: rtnl_unlock(); up_write(&pernet_ops_rwsem); return err; rollback: last = dev; for_each_net(net) { for_each_netdev(net, dev) { if (dev == last) goto outroll; if (dev->flags & IFF_UP) { call_netdevice_notifier(nb, NETDEV_GOING_DOWN, dev); call_netdevice_notifier(nb, NETDEV_DOWN, dev); } call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev); } } outroll: raw_notifier_chain_unregister(&netdev_chain, nb); goto unlock; }
IPV4相关的通知链
int register_inetaddr_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&inetaddr_chain, nb); } int register_inetaddr_validator_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&inetaddr_validator_chain, nb); }
IPV6相关的通知链
int inet6addr_notifier_call_chain(unsigned long val, void *v) { return atomic_notifier_call_chain(&inet6addr_chain, val, v); } int register_inet6addr_validator_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&inet6addr_validator_chain, nb); }
相关文章推荐
- 深入理解Linux网络技术内幕——IPv4 概念
- 深入理解Linux网络技术内幕——PCI层和网络接口卡
- 深入理解Linux网络技术内幕——协议处理函数
- 深入理解Linux网络技术内幕——L4层协议与Raw IP的处理
- 深入理解Linux网络技术内幕——内核基础架构和组件初始化
- 深入理解Linux网络技术内幕——中断与网络驱动程序
- 深入理解Linux网络技术内幕-设备注册和初始化(四)
- 深入理解Linux网络技术内幕——IPv4 分段与重组
- 深入理解linux网络技术内幕--通知链
- 深入理解Linux网络技术内幕——设备的注册与初始化(一)
- 深入理解Linux网络技术内幕——设备的注册与初始化(一)
- 深入理解Linux网络技术内幕——网络设备初始化
- 深入理解Linux网络技术内幕——IPv4选项的处理
- 深入理解Linux网络技术内幕——Notification内核通知表链
- 深入理解Linux网络技术内幕——网络设备初始化
- 深入理解Linux网络技术内幕——IPv4 报文的传输发送
- 深入理解Linux网络技术内幕——设备的注册与初始化(二)
- 深入理解Linux网络技术内幕——Notification内核通知表链
- 深入理解Linux网络技术内幕——设备的注册与初始化(二)
- 深入理解linux网络技术内幕:用户空间与内核的接口