Networking Namespaces

Recall from Chapter 1 that many parts of the kernel are contained in namespaces. These allow for building multiple virtual viewpoints of the system that are separated and segregated from each other. Every instance looks like a single machine running Linux, but, in fact, many such instances can operate simultaneously on a single physical machine. During the development of 2.6.24, the kernel started to adopt namespaces also for the networking subsystem. This adds some extra complexity to the networking layer because all properties of the subsystem that used to be ''global'' in former versions — for instance, the available network cards — need to be managed on a per-namespace basis now. If a particular networking device is visible in one namespace, it need not be available in another one.

As usual, a central structure is used to keep track of all available namespaces. The definition is as follows:

include/net/net_namespace.h struct net {

atomic_t count; /* To decided when the network * namespace should be freed.

struct struct struct struct struct struct struct struct

Work has only begun to make the networking subsystem fully aware of namespaces. What you see now — the situation in kernel 2.6.24 — still represents a comparatively early stage of development. Therefore, struct net will grow in size in the future as more and more networking components are transferred from a global management to a namespace-aware implementation. For now, the basic infrastructure is in place. Network devices are kept track of under consideration of namespaces, and support for the most important protocols is available. Since I have not yet discussed any specific points of the networking implementation, the structures referenced in struct net are naturally still unknown (however, I promise that this will certainly change in the course of this chapter). For now, it suffices to present a broad overview about what is handled in a namespace-aware fashion:

□ count is a standard usage counter, and the auxiliary functions get_net and put_net are provided to obtain and release permission to use a specific net instance. When count drops to zero, the namespace is deallocated and removed from the system.

□ All available namespaces are kept on a doubly linked list that is headed by net_namespace_list. list is used as the list element. The function copy_net_ns adds a new namespace to the list. It is automatically called when a set of new namespaces is created with create_new_namespace.

list_head list; /* list of network namespaces */

proc_dir_entry *proc_net; proc_dir_entry *proc_net_stat; proc_dir_entry *proc_net_root;

net_device *loopback_dev; /* The loopback */

list_head dev_base_head; hlist_head *dev_name_head; hlist_head *dev_index_head;

□ Since each namespace can contain different network devices, this must also be reflected in the contents of Procfs (see Chapter 10.1). Three entries require a per-namespace handling: /proc/net is represented by proc_net, while /proc/net/stats is represented by proc_net_stats. proc_net_root points to the root element of the Procfs instance for the current namespace, that is, /proc.

□ Each namespace may have a different loopback device, and loopback_dev points to the (virtual) network device that fulfills this role.

□ Network devices are represented by struct net_device. All devices associated with a specific namespace are kept on a doubly linked list headed by dev_base_head. The devices are kept on two additional hash tables: One uses the device name as hash key (dev_name_head), and one uses the interface index (dev_index_head).

Note that there is a slight difference in terminology between devices and interfaces. While devices represent hardware devices that provide physical transmission capabilities, interfaces can be purely virtual entities, possibly implemented on top of real devices. For example, a network card could provide two interfaces.

Since the distinction between these terms is not relevant for our purposes, I use both terms interchangeably in the following.

Many components still require substantial rework to make them handle namespaces correctly, and there is still a considerable way to go until a fully namespace-aware networking subsystem will be available. For instance, kernel 2.6.25 (which was still under development when this chapter was written) will introduce initial preparations to make specific protocols aware of namespaces:

include/net/net_namespace.h struct net {

struct netns_packet packet; struct netns_unix unx; struct netns_ipv4 ipv4; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct netns_ipv6 ipv6;

#endif

The new members like ipv4 will store (formerly global) protocol parameters, and protocol-specific structures are introduced for this purpose. The approach proceeds step-by-step: First, the basic framework is set in place. Subsequent steps will then move global properties into the per-namespace representation; the structures are initially empty. More work along these lines is expected to be accepted into future kernel versions.

Each network namespace consists of several components, for example, the representation in Procfs. Whenever a new networking namespace is created, these components must be initialized. Likewise, some cleanups are necessary when a namespace is deleted. The kernel employs the following structure to keep track of all required initialization/cleanup tuples:

include/net/net_namespace.h struct pernet_operations {

struct list_head list;

int (*init)(struct net *net); void (*exit)(struct net *net);

The structure does not present any surprises: init stores an initialization function, while clean-up work is handled by exit. All available pernet_operation instances are kept on a list headed by pernet_list; list is used as the list element. The auxiliary functions register_pernet_subsys and unregister_pernet_subsys add and remove elements to and from the list, respectively. Whenever a new networking namespace is created, the kernel iterates over the list of pernet_operations and calls the initialization function with the net instance that represents the new namespace as parameter. Cleaning up when a networking namespace is deleted is handled similarly.

Most computers will typically require only a single networking namespace. The global variable init_net (and in this case, the variable is really global and not contained in another namespace!) contains the net instance for this namespace. In the following, I mostly neglect namespaces to simplify matters. It suffices to keep in mind that all global functions of the network layer require a network namespace as parameter, and that any global properties of the networking subsystem may only be referenced by a detour through the namespace under consideration.

When network packets are analyzed in the kernel, the data of lower-level protocols are passed to higherlevel layers. The reverse sequence applies when data are sent. The data (header and payload) generated by the various protocols are successively passed to lower layers until they are finally transmitted. As the speed of these operations is crucial to network layer performance, the kernel makes use of a special structure known as a socket buffer, which is defined as follows:

struct sk_buff {

Was this article helpful?

+3 0

Post a comment