Alternative fix for the crash on conntrack unload. Simply flush all fragment queues when unloading conntrack_standalone so that there are no partially assembled fragments left with skb->dst == NULL. Index: v2.6.8/include/net/ip.h =================================================================== --- v2.6.8.orig/include/net/ip.h +++ v2.6.8/include/net/ip.h @@ -255,6 +255,7 @@ extern int ip_call_ra_chain(struct sk_bu */ struct sk_buff *ip_defrag(struct sk_buff *skb); +extern void ipfrag_flush(void); extern int ip_frag_nqueues; extern atomic_t ip_frag_mem; Index: v2.6.8/net/ipv4/ip_fragment.c =================================================================== --- v2.6.8.orig/net/ipv4/ip_fragment.c +++ v2.6.8/net/ipv4/ip_fragment.c @@ -239,13 +239,13 @@ static void ipq_kill(struct ipq *ipq) /* Memory limiting on fragments. Evictor trashes the oldest * fragment queue until we are back under the low threshold. */ -static void ip_evictor(void) +static void __ip_evictor(int threshold) { struct ipq *qp; struct list_head *tmp; for(;;) { - if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh) + if (atomic_read(&ip_frag_mem) <= threshold) return; read_lock(&ipfrag_lock); if (list_empty(&ipq_lru_list)) { @@ -267,6 +267,11 @@ static void ip_evictor(void) } } +static inline void ip_evictor(void) +{ + __ip_evictor(sysctl_ipfrag_low_thresh); +} + /* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -677,4 +682,10 @@ void ipfrag_init(void) add_timer(&ipfrag_secret_timer); } +void ipfrag_flush(void) +{ + __ip_evictor(0); +} + EXPORT_SYMBOL(ip_defrag); +EXPORT_SYMBOL(ipfrag_flush); Index: v2.6.8/net/ipv4/netfilter/ip_conntrack_standalone.c =================================================================== --- v2.6.8.orig/net/ipv4/netfilter/ip_conntrack_standalone.c +++ v2.6.8/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -562,6 +562,8 @@ static int init_or_cleanup(int init) nf_unregister_hook(&ip_conntrack_defrag_local_out_ops); cleanup_defragops: nf_unregister_hook(&ip_conntrack_defrag_ops); + /* Frag queues may hold fragments with skb->dst == NULL */ + ipfrag_flush(); cleanup_proc: proc_net_remove("ip_conntrack"); cleanup_init: