/* Ajith - Syntax Higlighter - End ----------------------------------------------- */

2.12.2012

Notification Chains in Linux Kernel - Part 03

Continuation after PART-2.


Notifying Events on a Chain 
Notifications are generated with notifier_call_chain. This function simply invokes, in order of priority, all the callback routines registered against the chain. Note that callback routines are executed in the context of the process that calls notifier_call_chain. A callback routine could, however, be implemented so that it queues the notification somewhere and wakes up a process that will look at it.

NOTE: Similar to register and unregister functions we don't directly call notifier_call_chain function as we have wrapper functions for respective chains.
 <kernel/notifier.c>

 58 static int __kprobes notifier_call_chain(struct notifier_block **nl,
 59                     unsigned long val, void *v,
 60                     int nr_to_call, int *nr_calls)
 61 {
 62     int ret = NOTIFY_DONE;
 63     struct notifier_block *nb, *next_nb;
 64 
 65     nb = rcu_dereference(*nl);
 66 
 67     while (nb && nr_to_call) {
 68         next_nb = rcu_dereference(nb->next);
 69         ret = nb->notifier_call(nb, val, v);
 .
 76         nb = next_nb;
 77         nr_to_call--;
 78     }
 79     return ret;
 80 }
  • nl
    Notification chain. 

  • val
    Event type. The chain itself identifies a class of events; val unequivocally identifies an event type (i.e., NETDEV_REGISTER). 

  • v
    Input parameter that can be used by the handlers registered by the various clients. This can be used in different ways under different circumstances. For instance, when a new network device is registered with the kernel, the associated notification uses v to identify the net_device data structure.

  • nr_to_call
    Number of notifier functions to be called. Don't care value of this parameter is -1. 

  • nr_calls
    Records the number of notifications sent. Don't care value of this field is NULL.

Example of notifier chains in Network Subsystem 
Let us see an example of using the notifier chains in bridge subsystem.
<net/bridge/br_notify.c>

 24 struct notifier_block br_device_notifier = {
 25     .notifier_call = br_device_event
 26 };

<net/bridge/br.c>

 30 static int __init br_init(void)
 31 {
 .
 48     err = register_netdevice_notifier(&br_device_notifier);
 .
 72 }
Once we fill the br_device_notifier we are registering to netdevice chain by calling the function register_netdevice_notifier(). netdev_chain is the head of the netdevice chain.
<net/core/dev.c>

245 static RAW_NOTIFIER_HEAD(netdev_chain);
.
1129 int register_netdevice_notifier(struct notifier_block *nb)
1130 {
.
1136     rtnl_lock();
1137     err = raw_notifier_chain_register(&netdev_chain, nb);
1138     if (err)
1139         goto unlock;
.
1177 }
When any events occur we invoke all the registered functions via notifier_call_chain function.
<net/core/dev.c>

1208 int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
1209 {
1210     return raw_notifier_call_chain(&netdev_chain, val, dev);
1211 }     
Below is the list of event types supported by netdevice:
<include/linux/notifier.h>

181 /* netdevice notifier chain */
182 #define NETDEV_UP   0x0001  /* For now you can't veto a device up/down */
183 #define NETDEV_DOWN 0x0002
184 #define NETDEV_REBOOT   0x0003  
.
188 #define NETDEV_CHANGE   0x0004  /* Notify device state change */
189 #define NETDEV_REGISTER 0x0005
190 #define NETDEV_UNREGISTER   0x0006
191 #define NETDEV_CHANGEMTU    0x0007
192 #define NETDEV_CHANGEADDR   0x0008
193 #define NETDEV_GOING_DOWN   0x0009
194 #define NETDEV_CHANGENAME   0x000A
195 #define NETDEV_FEAT_CHANGE  0x000B
Now it is upto to the notified to write a switch case to invoke the appropriate internal function in their subsystem for processing the respective event.
 <net/bridge/br_notify.c>

 34 static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
 35 {
 .
 43     /* not a port of a bridge */
 44     if (p == NULL)
 45         return NOTIFY_DONE;
 .
 49     switch (event) {
 50     case NETDEV_CHANGEMTU:
 51         dev_set_mtu(br->dev, br_min_mtu(br));
 52         break;
 53 
 54     case NETDEV_CHANGEADDR:
 55         spin_lock_bh(&br->lock);
 56         br_fdb_changeaddr(p, dev->dev_addr);
 57         br_stp_recalculate_bridge_id(br);
 58         spin_unlock_bh(&br->lock);
 59         break;
 60 
 61     case NETDEV_CHANGE:
 62         br_port_carrier_check(p);
 63         break;
 .
 72     case NETDEV_DOWN:
 73         spin_lock_bh(&br->lock);
 74         if (br->dev->flags & IFF_UP)
 75             br_stp_disable_port(p);
 76         spin_unlock_bh(&br->lock);
 77         break;
 78 
 79     case NETDEV_UP:
 80         if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) {
 81             spin_lock_bh(&br->lock);
 82             br_stp_enable_port(p);
 83             spin_unlock_bh(&br->lock);
 .
 98 }
We can say the whole notification mechanism is much more like call-back functions used to trigger appropriate functions when certain operation or an even happens.

No comments :

Post a Comment

Your comments are moderated