• Kuniyuki Iwashima's avatar
    udp: Introduce optional per-netns hash table. · 9804985b
    Kuniyuki Iwashima authored
    The maximum hash table size is 64K due to the nature of the protocol. [0]
    It's smaller than TCP, and fewer sockets can cause a performance drop.
    
    On an EC2 c5.24xlarge instance (192 GiB memory), after running iperf3 in
    different netns, creating 32Mi sockets without data transfer in the root
    netns causes regression for the iperf3's connection.
    
      uhash_entries		sockets		length		Gbps
    	    64K		      1		     1		5.69
    			    1Mi		    16		5.27
    			    2Mi		    32		4.90
    			    4Mi		    64		4.09
    			    8Mi		   128		2.96
    			   16Mi		   256		2.06
    			   32Mi		   512		1.12
    
    The per-netns hash table breaks the lengthy lists into shorter ones.  It is
    useful on a multi-tenant system with thousands of netns.  With smaller hash
    tables, we can look up sockets faster, isolate noisy neighbours, and reduce
    lock contention.
    
    The max size of the per-netns table is 64K as well.  This is because the
    possible hash range by udp_hashfn() always fits in 64K within the same
    netns and we cannot make full use of the whole buckets larger than 64K.
    
      /* 0 < num < 64K  ->  X < hash < X + 64K */
      (num + net_hash_mix(net)) & mask;
    
    Also, the min size is 128.  We use a bitmap to search for an available
    port in udp_lib_get_port().  To keep the bitmap on the stack and not
    fire the CONFIG_FRAME_WARN error at build time, we round up the table
    size to 128.
    
    The sysctl usage is the same with TCP:
    
      $ dmesg | cut -d ' ' -f 6- | grep "UDP hash"
      UDP hash table entries: 65536 (order: 9, 2097152 bytes, vmalloc)
    
      # sysctl net.ipv4.udp_hash_entries
      net.ipv4.udp_hash_entries = 65536  # can be changed by uhash_entries
    
      # sysctl net.ipv4.udp_child_hash_entries
      net.ipv4.udp_child_hash_entries = 0  # disabled by default
    
      # ip netns add test1
      # ip netns exec test1 sysctl net.ipv4.udp_hash_entries
      net.ipv4.udp_hash_entries = -65536  # share the global table
    
      # sysctl -w net.ipv4.udp_child_hash_entries=100
      net.ipv4.udp_child_hash_entries = 100
    
      # ip netns add test2
      # ip netns exec test2 sysctl net.ipv4.udp_hash_entries
      net.ipv4.udp_hash_entries = 128  # own a per-netns table with 2^n buckets
    
    We could optimise the hash table lookup/iteration further by removing
    the netns comparison for the per-netns one in the future.  Also, we
    could optimise the sparse udp_hslot layout by putting it in udp_table.
    
    [0]: https://lore.kernel.org/netdev/4ACC2815.7010101@gmail.com/Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    9804985b
udp.c 87.6 KB