Skip to content

Commit 69a3272

Browse files
jonrebmdavem330
authored andcommitted
net: ipv4: igmp: optimize ____ip_mc_inc_group() using mc_hash
The runtime cost of joining a single multicast group in the current implementation of ____ip_mc_inc_group grows linearly with the number of existing memberships. This is caused by the linear search for an existing group record in the multicast address list. This linear complexity results in quadratic complexity when successively adding memberships, which becomes a performance bottleneck when setting up large numbers of multicast memberships. If available, use the existing multicast hash map mc_hash to quickly search for an existing group membership record. This leads to near-constant complexity on the addition of a new multicast record, significantly improving performance for workloads involving many multicast memberships. On profiling with a loopback device, this patch presented a speedup of around 6 when successively setting up 2000 multicast groups using setsockopt without measurable drawbacks on smaller numbers of multicast groups. Signed-off-by: Jonas Rebmann <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2050327 commit 69a3272

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

net/ipv4/igmp.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,16 +1437,32 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
14371437
static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
14381438
unsigned int mode, gfp_t gfp)
14391439
{
1440+
struct ip_mc_list __rcu **mc_hash;
14401441
struct ip_mc_list *im;
14411442

14421443
ASSERT_RTNL();
14431444

1444-
for_each_pmc_rtnl(in_dev, im) {
1445-
if (im->multiaddr == addr) {
1446-
im->users++;
1447-
ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0);
1448-
goto out;
1445+
mc_hash = rtnl_dereference(in_dev->mc_hash);
1446+
if (mc_hash) {
1447+
u32 hash = hash_32((__force u32)addr, MC_HASH_SZ_LOG);
1448+
1449+
for (im = rtnl_dereference(mc_hash[hash]);
1450+
im;
1451+
im = rtnl_dereference(im->next_hash)) {
1452+
if (im->multiaddr == addr)
1453+
break;
14491454
}
1455+
} else {
1456+
for_each_pmc_rtnl(in_dev, im) {
1457+
if (im->multiaddr == addr)
1458+
break;
1459+
}
1460+
}
1461+
1462+
if (im) {
1463+
im->users++;
1464+
ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0);
1465+
goto out;
14501466
}
14511467

14521468
im = kzalloc(sizeof(*im), gfp);

0 commit comments

Comments
 (0)