diff --git a/include/net/tcp.h b/include/net/tcp.h index 0239e815edf71e7cfbfc60bede22069d3cf2dd32..e9d387fffe22f84bc5d2a7d87e8483bf82633001 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -258,6 +258,7 @@ DECLARE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); 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 598c1b114d2c2256fa06735b823b38cef70a8a34..919f0f8691186205e6cee6c03d854e44bd8093a7 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -1011,7 +1011,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct inet_bind_bucket *tb; bool tb_created = false; u32 remaining, offset; - int ret, i, low, high; + int ret, i, low, high, span_size; int l3mdev; u32 index; @@ -1021,6 +1021,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); @@ -1043,7 +1048,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)) @@ -1084,7 +1089,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 6ac890b4073f4583b0f98ee3294babb91bbcf482..b17eb28a969011878ae414c50d5178f1e764d8f5 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -39,6 +39,7 @@ static unsigned long ip_ping_group_range_min[] = { 0, 0 }; static unsigned long ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; static u32 u32_max_div_HZ = UINT_MAX / HZ; static int one_day_secs = 24 * 3600; +int sysctl_local_port_allocation; static u32 fib_multipath_hash_fields_all_mask __maybe_unused = FIB_MULTIPATH_HASH_FIELD_ALL_MASK; static unsigned int tcp_child_ehash_entries_max = 16 * 1024 * 1024; @@ -579,6 +580,13 @@ static struct ctl_table ipv4_table[] = { .extra1 = &sysctl_fib_sync_mem_min, .extra2 = &sysctl_fib_sync_mem_max, }, + { + .procname = "local_port_allocation", + .data = &sysctl_local_port_allocation, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { } };