Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 12: Networks


Theokfnspecified isip_forward_finish. Control is passed directly to this function if the above test
establishes that no netfilter hooks are registered for the combination ofPF_INETandNF_IP_FORWARD.
Otherwise, the relevant netfilter code is executed and control is then transferred toip_forward_finish
(assuming the packet is not discarded or removed from kernel control). If no hooks are installed, code
flow is the same as ifip_forwardandip_forward_finishwere implemented as a single, uninterrupted
procedure.

The kernel makes use of the optimization options of the C compiler to prevent speed loss if netfilter is
disabled. Kernel versions before 2.6.24 required that theokfnwas defined as aninlinefunction:

net/ipv4/ip_forward.c
static inline int ip_forward_finish(struct sk_buff *skb) {
...
}

This means that it is shown as a normal function, but the compiler does not invoke it by means of a classic
function call (pass parameters, set instruction pointers to function code, read arguments, etc.). Instead,
the entire C code is copied to the point at which the function is invoked. Although this results in a longer
executable (particularly for larger functions), it is compensated by speed gains. The GNU C compiler
guarantees thatinlinefunctions are as fast as macros if this approach is adopted.

However, starting with kernel 2.6.24, the inline definition could be removed in nearly all cases!

net/ipv4/ip_forward.c
static int ip_forward_finish(struct sk_buff *skb) {
...
}

This is possible because the GNU C compiler has become able to perform an additional optimization
technique: procedure tail calls. They originate fromfunctional languages and are, for instance, mandatory
for implementations of the Scheme language. When a function is called as the last statement of another
function, it is not necessary that the callee returns to the caller after it has finished its work — there is
nothing left to do in the caller. This allows for performing some simplifications of the call mechanism
that lead to an execution that is as fast as with the old inline mechanism, without the need to duplicate
code by inlining, and thus without increasing the size of the kernel. However, this optimization is not
performed by gcc for all hook functions, and a small number of them still remain inlined.

If the netfilter configuration is enabled, scanning of thenf_hooksarray makes no sense, and theNF_HOOK
macro is then defined differently:

include/net/netfilter.h
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)

Invocation of the hook function is simply replaced with a call to the function defined inokfn(theinline
keyword instructs the compiler to do this by copying the code). The original two functions have now
merged into one, and there is no need for an intervening function call.

Scanningthe Hook Table


nf_hook_slowis called if at least one hook function is registered and needs to be invoked. All hooks are
stored in thenf_hookstwo-dimensional array:

net/netfilter/core.c
struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS] __read_mostly;
Free download pdf