It’s important to distinguish between two kinds of registration. First, when a device is discovered, it is registered with the kernel as a generic device. Second, an NIC device is registered with the network stack as a network device. For example, a PCI Ethernet card is registered both as a generic PCI device with the PCI layer, and as an Ethernet card (where the device gets a name such as eth0) with the network stack.
The kernel’s many subsystems are heavily interdependent, so an event detected or generated by one of them could be of interest to others. To fulfill the need for interaction, Linux uses so-called notification chains.
Note that notification chains are used only between kernel subsystems.
A notification chain is simply a list of functions to execute when a given event occurs. Each function lets one other subsystem know about an event that occurred within, or was detected by, the subsystem calling the function.
Thus, for each notification chain there is a passive side (the notified) and an active side (the notifier), as in the so-called publish-and-subscribe model:
- The notified are the subsystems that ask to be notified about the event and that provide a callback function to invoke
- The notifier is the subsystem that experiences an event and calls the callback function.
each subsystem maintainer should know:
- The kinds of events from other subsystems he is interested in
- The kinds of events he knows about and that other subsystems may be interested in
The elements of the notification chain’s list are of type notifier_block, whose definition is the following:
struct notifier_block
{
int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
struct notifier_block *next;
int priority;
};
subsystems usually register their notifier_call functions only at boot time or at module load time, and from that moment on access the lists in a read-only manner (that is, shared).
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.
int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb = *n;
while (nb)
{
ret = nb->notifier_call(nb, val, v);
if (ret & NOTIFY_STOP_MASK)
{
return ret;
}
nb = nb->next;
}
return ret;
}
n
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.
The callback routines called by notifier_call_chain can return any of the NOTIFY_XXX values defined in include/linux/notifier.h:
NOTIFY_OK
Notification was processed correctly.
NOTIFY_DONE
Not interested in the notification.*
NOTIFY_BAD
Something went wrong. Stop calling the callback routines for this event.
NOTIFY_STOP
Routine invoked correctly. However, no further callbacks need to be called for this event.
NOTIFY_STOP_MASK
This flag is checked by notifier_call_chain to see whether to stop invoking the callback routines, or keep going. Both NOTIFY_BAD and NOTIFY_STOP include this flag in their definitions
Notification Chains for the Networking Subsystems
The kernel defines at least 10 different notification chains.
inetaddr_chain
Sends notifications about the insertion, removal, and change of an Internet Protocol Version 4 (IPv4) address on a local interface.
netdev_chain
Sends notifications about the registration status of network devices
Registrations to notification chains usually take place when the interested kernel component is initialized.