23.2. Selecting the IP Header's ID FieldThe main function for the initialization of the IP packet ID is _ _ip_select_ident. This function can be called both directly and indirectly via ip_select_ident or ip_select_ident_more. Both of these wrapper functions differentiate between packets that can and cannot be fragmented (based on the MF flag). Two cases are defined:
ip_select_ident_more, which is used by TCP (see ip_queue_xmit), receives one more input parameter (more) that is used in those cases where the device supports TCP offloading. Let's go back to _ _ip_select_ident: void _ _ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) { struct rtable *rt = (struct rtable *) dst; if (rt) { if (rt->peer == NULL) rt_bind_peer(rt, 1); if (rt->peer) { iph->id = htons(inet_getid(rt->peer, more)); return; } } else printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", _ _builtin_return_address(0)); ip_select_fb_ident(iph); } We saw in the section "Long-Living IP Peer Information" that for each IP peer there is an inet_peer data structure that keeps, among other things, a counter that can be used to set the IP packet ID (iph->id). _ _ip_select_ident uses this ID when it is available, and falls back to ip_select_fb_ident otherwise. If the inet_peer structure is not already initialized in the routing cache entry rt, rt_bind_peer first looks for the inet_peer structure associated with the peer, and if it does not exist, the function tries to create it (because the last input parameter to rt_bind_peer is set to 1). Such creation attempts can fail on a loaded system that runs out of memory and thus cannot afford the allocation of a new inet_peer structure. In this case, _ _ip_select_ident generates an ID with ip_select_fb_ident, which represents the last recourse. The way ip_select_fb_ident (where fb stands for fallback) works is simple: it keeps a static variable, ip_fallback_id, combines it with the destination IP address of the peer, and passes it to the secure_ip_id function we already saw in the section "Lookups." The only drawback of this solution is that because this function can potentially be used for several peers, there is no longer a guarantee that the IDs assigned to consecutive IP packets sent to any given peer within a reasonable amount of time will be different. It is important that different IP packets addressed to the same destination have different IDs because the IP ID is one of the fields used to take care of defragmentation. Thus, if different IP packets with the same ID get fragmented and the fragments get mixed, there is no way for the receiver to distinguish the fragments belonging to the different IP packets (see the section "Associating fragments with their IP packets" in Chapter 18). ![]() |