#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct flow_cache_entry { struct flow_cache_entry *next; u16 family; u8 dir; struct flowi key; u32 genid; void *object; atomic_t *object_ref; }; static void flow_cache_shrink(int cpu) { int shrink_to = flow_lwm / flow_hash_size; __flow_cache_shrink(cpu, shrink_to); } static void flow_new_hash_rnd(int cpu) { get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32)); flow_hash_rnd_recalc(cpu) = 0; __flow_cache_shrink(cpu, 0); } static u32 flow_hash_code(struct flowi *key, int cpu) { u32 *k = (u32 *) key; return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) & (flow_hash_size - 1)); } #if (BITS_PER_LONG == 64) typedef u64 flow_compare_t; #else typedef u32 flow_compare_t; #endif extern void flowi_is_missized(void); /* I hear what you're saying, use memcmp. But memcmp cannot make * important assumptions that we can here, such as alignment and * constant size. */ static void __devinit flow_cache_cpu_prepare(int cpu) { struct tasklet_struct *tasklet; unsigned long order; for (order = 0; (PAGE_SIZE << order) < (sizeof(struct flow_cache_entry *)*flow_hash_size); order++) /* NOTHING */; flow_table(cpu) = (struct flow_cache_entry **) __get_free_pages(GFP_KERNEL, order); if (!flow_table(cpu)) panic("NET: failed to allocate flow cache order %lu\n", order); memset(flow_table(cpu), 0, PAGE_SIZE << order); flow_hash_rnd_recalc(cpu) = 1; flow_count(cpu) = 0; tasklet = flow_flush_tasklet(cpu); tasklet_init(tasklet, flow_cache_flush_tasklet, 0); } static int __init flow_cache_init(void) { int i; flow_cachep = kmem_cache_create("flow_cache", sizeof(struct flow_cache_entry), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!flow_cachep) panic("NET: failed to allocate flow cache slab\n"); flow_hash_shift = 10; flow_lwm = 2 * flow_hash_size; flow_hwm = 4 * flow_hash_size; init_timer(&flow_hash_rnd_timer); flow_hash_rnd_timer.function = flow_cache_new_hashrnd; flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; add_timer(&flow_hash_rnd_timer); for_each_cpu(i) flow_cache_cpu_prepare(i); hotcpu_notifier(flow_cache_cpu, 0); return 0; }