[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20221111040034.29736-6-kuniyu@amazon.com>
Date: Thu, 10 Nov 2022 20:00:33 -0800
From: Kuniyuki Iwashima <kuniyu@...zon.com>
To: "David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>
CC: Kuniyuki Iwashima <kuniyu@...zon.com>,
Kuniyuki Iwashima <kuni1840@...il.com>,
<netdev@...r.kernel.org>
Subject: [PATCH v2 net-next 5/6] udp: Add bitmap in udp_table.
We use a bitmap in udp_lib_get_port() to search for an available
port. Currently, the bitmap size is fixed and has enough room for
UDP_HTABLE_SIZE_MIN.
The following patch adds the per-netns hash table for UDP, whose size
can be smaller than UDP_HTABLE_SIZE_MIN. If we define a bitmap with
enough size on the stack, it will be over CONFIG_FRAME_WARN. To avoid
that, we allocate bitmaps for each udp_table->hash[slot] in advance.
Signed-off-by: Kuniyuki Iwashima <kuniyu@...zon.com>
---
include/linux/udp.h | 1 +
include/net/udp.h | 20 ++++++++++++++++++++
net/ipv4/udp.c | 12 +++++++++---
3 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/include/linux/udp.h b/include/linux/udp.h
index dea57aa37df6..779a7c065a32 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -23,6 +23,7 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
return (struct udphdr *)skb_transport_header(skb);
}
+#define UDP_MAX_PORT_LOG 16
#define UDP_HTABLE_SIZE_MIN (CONFIG_BASE_SMALL ? 128 : 256)
static inline u32 udp_hashfn(const struct net *net, u32 num, u32 mask)
diff --git a/include/net/udp.h b/include/net/udp.h
index de4b528522bb..314dd51a2cc6 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -72,11 +72,31 @@ struct udp_hslot {
struct udp_table {
struct udp_hslot *hash;
struct udp_hslot *hash2;
+ unsigned long *bitmap;
unsigned int mask;
unsigned int log;
};
extern struct udp_table udp_table;
void udp_table_init(struct udp_table *, const char *);
+
+static inline unsigned int udp_bitmap_size(struct udp_table *table)
+{
+ return 1 << (UDP_MAX_PORT_LOG - table->log);
+}
+
+static inline unsigned long *udp_hashbitmap(struct udp_table *table,
+ struct net *net, unsigned int num)
+{
+ unsigned long *bitmap;
+ unsigned int size;
+
+ size = udp_bitmap_size(table);
+ bitmap = &table->bitmap[udp_hashfn(net, num, table->mask) * BITS_TO_LONGS(size)];
+ bitmap_zero(bitmap, size);
+
+ return bitmap;
+}
+
static inline struct udp_hslot *udp_hashslot(struct udp_table *table,
struct net *net, unsigned int num)
{
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 37e79158d145..42d7b84a5f16 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -129,7 +129,6 @@ DEFINE_PER_CPU(int, udp_memory_per_cpu_fw_alloc);
EXPORT_PER_CPU_SYMBOL_GPL(udp_memory_per_cpu_fw_alloc);
#define MAX_UDP_PORTS 65536
-#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
static struct udp_table *udp_get_table_prot(struct sock *sk)
{
@@ -243,9 +242,9 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
int error = 1;
if (!snum) {
- DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN);
unsigned short first, last;
int low, high, remaining;
+ unsigned long *bitmap;
unsigned int rand;
inet_get_local_port_range(net, &low, &high);
@@ -260,8 +259,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
last = first + udptable->mask + 1;
do {
hslot = udp_hashslot(udptable, net, first);
- bitmap_zero(bitmap, PORTS_PER_CHAIN);
spin_lock_bh(&hslot->lock);
+ bitmap = udp_hashbitmap(udptable, net, first);
udp_lib_lport_inuse(net, snum, hslot, bitmap, sk,
udptable->log);
@@ -3290,6 +3289,13 @@ void __init udp_table_init(struct udp_table *table, const char *name)
table->hash2[i].count = 0;
spin_lock_init(&table->hash2[i].lock);
}
+
+ table->bitmap = kmalloc_array(table->mask + 1,
+ BITS_TO_LONGS(udp_bitmap_size(table)) *
+ sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!table->bitmap)
+ panic("UDP: failed to alloc bitmap\n");
}
u32 udp_flow_hashrnd(void)
--
2.30.2
Powered by blists - more mailing lists