Crude walkthrough of the Linux IPv6 kernel implementation (Linux 2.4.0-test6)

Softnet: a rewrite of the Linux networking stack, primarily by Alexey Kuznetsov It centres around the use of soft IRQ's to provide fine timing control, fine enough for use by the network stack for traffic shaping etc. It also provides the required re-entrancy abilities for multiple processors to be executing network stack code simultaneoulsy - essential for making Linux's networking peformance scalable.

net/core/dev.c:netif_rx takes incoming skbuff from device, and queues the skb for handling later via softnet. Softnet will later call net_rx_action and deliver the packet to the protocol handlers via the preassinged callback in the devices packet handler chain. Packet handlers get associated with the device via dev_add_pack(packet_type), and the packet_type structure holds the protocol handler callback. In the case of IPv6, the packet hanlder is installed by the function ipv6_sockglue:ipv6_packet_init, in turn run by the af_inet6 intialisation program, which is compiled as init_module or inet6_proto_init, depending on whether IPv6 support is compiled in, or modularised.

Ultimately though, the handler installed is ipv6_rcv, defined by

struct packet_type ipv6_packet_type =
{
	__constant_htons(ETH_P_IPV6), 
	NULL,					/* All devices */
	ipv6_rcv,
	(void*)1,
	NULL
};
Which finally brings us to
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
Initial sanity checks are performed, and information about the device the packet arrived on is captured while it is still possible. As long as the IPv6 data payload is greater than zero, or if zero that the first IPv6 header is not the hop-by-hop header, the packet is trimmed to the length it proclaims to be. If however the first IPv6 header is the hop-by-hop header, then that the hop-by-hop header is first sent to ipv6_parse_hopopts.

At this stage, the packet is ready for sending to netfilters 'pre-routing input' hook. Netfilter is informed to resume processing at ip6_rcv_finish, that merely runs ip6_route_input on the skbuff, and then passes it off to the resulting skb->dst that was determined.

ip6_route_input is defined in net/ipv6/route.c. This is where the complexity starts. .... routing process ... the call to skb->dst->input results in a call to ip6_input. This merely calls the netfilter 'post-routing input' hook, which is told to pass control onto ip6_input_finish. ip6_input_finish does the real work of handling incoming IPv6 packets. After moving over the already dealt with (if present) hop-by-hop options headers, checks are first made whether the subsequent headers are either TCP or UDP. If not, then ipv6_parse_exthdrs is called to deal with the out-of-the-ordinary headers.

Otherwise, len is fixed up. (Following dev_put code is believed to decrement the 'in_use' count of the incoming device, so that after all packets delivered to higher level, the device can be taken down if desired).

If the protocol type of the packet is registered with a raw IPv6 socket, then it is dispatched appropriately. Otherwise registered IPv6 protocol handlers hash bucket is looked up, and all matching handlers called on the the skbuff (or a clone of the skbuff, depending on whether handlers can play together or not - ipprot->copy flag).

(work out the semantics of ipv6_raw_deliver and ipv6_raw_rcv etc.)