diff --git a/include/net/tcp.h b/include/net/tcp.h index 9c86ff1e3ed1538f6f3dc59c5de7962c44117679..1b832683ccf8f0144b5ca8e72b526e748873aff5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -258,6 +258,7 @@ extern long sysctl_tcp_mem[3]; extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; extern unsigned long tcp_memory_pressure; +extern int sysctl_local_port_allocation; /* optimized version of sk_under_memory_pressure() for TCP sockets */ static inline bool tcp_under_memory_pressure(const struct sock *sk) diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ed8324ee4b1b69baa1ae79ea1a97e7363573e922..396a58d9708cfda0063000616bdf72e477b59c9b 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -742,7 +742,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct net *net = sock_net(sk); struct inet_bind_bucket *tb; u32 remaining, offset; - int ret, i, low, high; + int ret, i, low, high, span_size; int l3mdev; u32 index; @@ -762,6 +762,11 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, local_bh_enable(); return ret; } + /* local_port_allocation 0 means even and odd port allocation strategy + * will be applied, so span size is 2; otherwise sequential allocation + * will be used and span size is 1. Default value is 0. + */ + span_size = sysctl_local_port_allocation ? 1 : 2; l3mdev = inet_sk_bound_l3mdev(sk); @@ -783,7 +788,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, offset &= ~1U; other_parity_scan: port = low + offset; - for (i = 0; i < remaining; i += 2, port += 2) { + for (i = 0; i < remaining; i += span_size, port += span_size) { if (unlikely(port >= high)) port -= remaining; if (inet_is_local_reserved_port(net, port)) @@ -824,7 +829,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, } offset++; - if ((offset & 1) && remaining > 1) + if ((offset & 1) && remaining > 1 && span_size == 2) goto other_parity_scan; return -EADDRNOTAVAIL; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index dee47ef056556940d8c9e55f0f4ee47b66f6f7aa..d82c0eceec913a7e452fc2b370846c5cdcf8e708 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -51,6 +51,7 @@ static int comp_sack_nr_max = 255; static u32 u32_max_div_HZ = UINT_MAX / HZ; static int one_day_secs = 24 * 3600; +int sysctl_local_port_allocation; /* obsolete */ static int sysctl_tcp_low_latency __read_mostly; @@ -575,6 +576,13 @@ static struct ctl_table ipv4_table[] = { .extra2 = SYSCTL_ONE, }, #endif + { + .procname = "local_port_allocation", + .data = &sysctl_local_port_allocation, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { } };