Skip to content

Commit 2a80d89

Browse files
committed
Merge branch 'net-improve-multicast-group-join-performance'
Jonas Rebmann says: ==================== improve multicast join group performance This series seeks to improve performance on updating igmp group memberships such as with IP_ADD_MEMBERSHIP or MCAST_JOIN_SOURCE_GROUP. Our use case was to add 2000 multicast memberships on a TQMLS1046A which took about 3.6 seconds for the membership additions alone. Our userspace reproducer tool was instrumented to log runtimes of the individual setsockopt invocations which clearly indicated quadratic complexity of setting up the membership with regard to the total number of multicast groups to be joined. We used perf to locate the hotspots and subsequently optimized the most costly sections of code. This series includes a patch to Linux igmp handling as well as a patch to the DPAA/Freescale driver. With both patches applied, our memberships can be set up in only about 87 miliseconds, which corresponds to a speedup of around 40. While we have acheived practically linear run-time complexity on the kernel side, a small quadratic factor remains in parts of the freescale driver code which we haven't yet optimized. We have by now payed little attention to the optimization potential in dropping group memberships, yet the dpaa patch applies to joining and leaving groups alike. Overall, this patch series brings great improvements in use cases involving large numbers of multicast groups, particularly when using the fsl_dpa driver, without noteworthy drawbacks in other scenarios. ==================== Signed-off-by: Jonas Rebmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents 2050327 + 298f70b commit 2a80d89

File tree

7 files changed

+39
-54
lines changed

7 files changed

+39
-54
lines changed

drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,22 @@ static int dpaa_set_mac_address(struct net_device *net_dev, void *addr)
463463
return 0;
464464
}
465465

466+
static int dpaa_addr_sync(struct net_device *net_dev, const u8 *addr)
467+
{
468+
const struct dpaa_priv *priv = netdev_priv(net_dev);
469+
470+
return priv->mac_dev->add_hash_mac_addr(priv->mac_dev->fman_mac,
471+
(enet_addr_t *)addr);
472+
}
473+
474+
static int dpaa_addr_unsync(struct net_device *net_dev, const u8 *addr)
475+
{
476+
const struct dpaa_priv *priv = netdev_priv(net_dev);
477+
478+
return priv->mac_dev->remove_hash_mac_addr(priv->mac_dev->fman_mac,
479+
(enet_addr_t *)addr);
480+
}
481+
466482
static void dpaa_set_rx_mode(struct net_device *net_dev)
467483
{
468484
const struct dpaa_priv *priv;
@@ -490,9 +506,9 @@ static void dpaa_set_rx_mode(struct net_device *net_dev)
490506
err);
491507
}
492508

493-
err = priv->mac_dev->set_multi(net_dev, priv->mac_dev);
509+
err = __dev_mc_sync(net_dev, dpaa_addr_sync, dpaa_addr_unsync);
494510
if (err < 0)
495-
netif_err(priv, drv, net_dev, "mac_dev->set_multi() = %d\n",
511+
netif_err(priv, drv, net_dev, "dpaa_addr_sync() = %d\n",
496512
err);
497513
}
498514

drivers/net/ethernet/freescale/fman/fman_dtsec.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,6 @@ int dtsec_initialization(struct mac_device *mac_dev,
14151415
mac_dev->set_exception = dtsec_set_exception;
14161416
mac_dev->set_allmulti = dtsec_set_allmulti;
14171417
mac_dev->set_tstamp = dtsec_set_tstamp;
1418-
mac_dev->set_multi = fman_set_multi;
14191418
mac_dev->enable = dtsec_enable;
14201419
mac_dev->disable = dtsec_disable;
14211420

drivers/net/ethernet/freescale/fman/fman_memac.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,6 @@ int memac_initialization(struct mac_device *mac_dev,
10871087
mac_dev->set_exception = memac_set_exception;
10881088
mac_dev->set_allmulti = memac_set_allmulti;
10891089
mac_dev->set_tstamp = memac_set_tstamp;
1090-
mac_dev->set_multi = fman_set_multi;
10911090
mac_dev->enable = memac_enable;
10921091
mac_dev->disable = memac_disable;
10931092

drivers/net/ethernet/freescale/fman/fman_tgec.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,6 @@ int tgec_initialization(struct mac_device *mac_dev,
771771
mac_dev->set_exception = tgec_set_exception;
772772
mac_dev->set_allmulti = tgec_set_allmulti;
773773
mac_dev->set_tstamp = tgec_set_tstamp;
774-
mac_dev->set_multi = fman_set_multi;
775774
mac_dev->enable = tgec_enable;
776775
mac_dev->disable = tgec_disable;
777776

drivers/net/ethernet/freescale/fman/mac.c

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ MODULE_DESCRIPTION("FSL FMan MAC API based driver");
3232
struct mac_priv_s {
3333
u8 cell_index;
3434
struct fman *fman;
35-
/* List of multicast addresses */
36-
struct list_head mc_addr_list;
3735
struct platform_device *eth_dev;
3836
u16 speed;
3937
};
@@ -57,44 +55,6 @@ static void mac_exception(struct mac_device *mac_dev,
5755
__func__, ex);
5856
}
5957

60-
int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev)
61-
{
62-
struct mac_priv_s *priv;
63-
struct mac_address *old_addr, *tmp;
64-
struct netdev_hw_addr *ha;
65-
int err;
66-
enet_addr_t *addr;
67-
68-
priv = mac_dev->priv;
69-
70-
/* Clear previous address list */
71-
list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) {
72-
addr = (enet_addr_t *)old_addr->addr;
73-
err = mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr);
74-
if (err < 0)
75-
return err;
76-
77-
list_del(&old_addr->list);
78-
kfree(old_addr);
79-
}
80-
81-
/* Add all the addresses from the new list */
82-
netdev_for_each_mc_addr(ha, net_dev) {
83-
addr = (enet_addr_t *)ha->addr;
84-
err = mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr);
85-
if (err < 0)
86-
return err;
87-
88-
tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
89-
if (!tmp)
90-
return -ENOMEM;
91-
92-
ether_addr_copy(tmp->addr, ha->addr);
93-
list_add(&tmp->list, &priv->mc_addr_list);
94-
}
95-
return 0;
96-
}
97-
9858
static DEFINE_MUTEX(eth_lock);
9959

10060
static struct platform_device *dpaa_eth_add_device(int fman_id,
@@ -181,8 +141,6 @@ static int mac_probe(struct platform_device *_of_dev)
181141
mac_dev->priv = priv;
182142
mac_dev->dev = dev;
183143

184-
INIT_LIST_HEAD(&priv->mc_addr_list);
185-
186144
/* Get the FM node */
187145
dev_node = of_get_parent(mac_node);
188146
if (!dev_node) {

drivers/net/ethernet/freescale/fman/mac.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ struct mac_device {
3939
int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr);
4040
int (*set_allmulti)(struct fman_mac *mac_dev, bool enable);
4141
int (*set_tstamp)(struct fman_mac *mac_dev, bool enable);
42-
int (*set_multi)(struct net_device *net_dev,
43-
struct mac_device *mac_dev);
4442
int (*set_exception)(struct fman_mac *mac_dev,
4543
enum fman_mac_exceptions exception, bool enable);
4644
int (*add_hash_mac_addr)(struct fman_mac *mac_dev,

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)