Skip to content

Commit 8582661

Browse files
wkzdavem330
authored andcommitted
net: bridge: switchdev: recycle unused hwdoms
Since hwdoms have only been used thus far for equality comparisons, the bridge has used the simplest possible assignment policy; using a counter to keep track of the last value handed out. With the upcoming transmit offloading, we need to perform set operations efficiently based on hwdoms, e.g. we want to answer questions like "has this skb been forwarded to any port within this hwdom?" Move to a bitmap-based allocation scheme that recycles hwdoms once all members leaves the bridge. This means that we can use a single unsigned long to keep track of the hwdoms that have received an skb. v1->v2: convert the typedef DECLARE_BITMAP(br_hwdom_map_t, BR_HWDOM_MAX) into a plain unsigned long. v2->v6: none Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f7cf972 commit 8582661

File tree

3 files changed

+86
-39
lines changed

3 files changed

+86
-39
lines changed

net/bridge/br_if.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ static void del_nbp(struct net_bridge_port *p)
349349
nbp_backup_clear(p);
350350

351351
nbp_update_port_count(br);
352+
nbp_switchdev_del(p);
352353

353354
netdev_upper_dev_unlink(dev, br->dev);
354355

@@ -643,7 +644,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
643644
if (err)
644645
goto err5;
645646

646-
err = nbp_switchdev_hwdom_set(p);
647+
err = nbp_switchdev_add(p);
647648
if (err)
648649
goto err6;
649650

@@ -719,6 +720,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
719720
list_del_rcu(&p->list);
720721
br_fdb_delete_by_port(br, p, 0, 1);
721722
nbp_update_port_count(br);
723+
nbp_switchdev_del(p);
722724
err6:
723725
netdev_upper_dev_unlink(dev, br->dev);
724726
err5:

net/bridge/br_private.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#define BR_MULTICAST_DEFAULT_HASH_MAX 4096
3131

32+
#define BR_HWDOM_MAX BITS_PER_LONG
33+
3234
#define BR_VERSION "2.3"
3335

3436
/* Control of forwarding link local multicast */
@@ -517,6 +519,8 @@ struct net_bridge {
517519
* identifiers in case a bridge spans multiple switchdev instances.
518520
*/
519521
int last_hwdom;
522+
/* Bit mask of hardware domain numbers in use */
523+
unsigned long busy_hwdoms;
520524
#endif
521525
struct hlist_head fdb_list;
522526

@@ -1840,7 +1844,6 @@ static inline void br_sysfs_delbr(struct net_device *dev) { return; }
18401844

18411845
/* br_switchdev.c */
18421846
#ifdef CONFIG_NET_SWITCHDEV
1843-
int nbp_switchdev_hwdom_set(struct net_bridge_port *p);
18441847
void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
18451848
struct sk_buff *skb);
18461849
bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
@@ -1854,17 +1857,15 @@ void br_switchdev_fdb_notify(struct net_bridge *br,
18541857
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
18551858
struct netlink_ext_ack *extack);
18561859
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
1860+
int nbp_switchdev_add(struct net_bridge_port *p);
1861+
void nbp_switchdev_del(struct net_bridge_port *p);
1862+
void br_switchdev_init(struct net_bridge *br);
18571863

18581864
static inline void br_switchdev_frame_unmark(struct sk_buff *skb)
18591865
{
18601866
skb->offload_fwd_mark = 0;
18611867
}
18621868
#else
1863-
static inline int nbp_switchdev_hwdom_set(struct net_bridge_port *p)
1864-
{
1865-
return 0;
1866-
}
1867-
18681869
static inline void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
18691870
struct sk_buff *skb)
18701871
{
@@ -1905,6 +1906,20 @@ br_switchdev_fdb_notify(struct net_bridge *br,
19051906
static inline void br_switchdev_frame_unmark(struct sk_buff *skb)
19061907
{
19071908
}
1909+
1910+
static inline int nbp_switchdev_add(struct net_bridge_port *p)
1911+
{
1912+
return 0;
1913+
}
1914+
1915+
static inline void nbp_switchdev_del(struct net_bridge_port *p)
1916+
{
1917+
}
1918+
1919+
static inline void br_switchdev_init(struct net_bridge *br)
1920+
{
1921+
}
1922+
19081923
#endif /* CONFIG_NET_SWITCHDEV */
19091924

19101925
/* br_arp_nd_proxy.c */

net/bridge/br_switchdev.c

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,6 @@
88

99
#include "br_private.h"
1010

11-
static int br_switchdev_hwdom_get(struct net_bridge *br, struct net_device *dev)
12-
{
13-
struct net_bridge_port *p;
14-
15-
/* dev is yet to be added to the port list. */
16-
list_for_each_entry(p, &br->port_list, list) {
17-
if (netdev_port_same_parent_id(dev, p->dev))
18-
return p->hwdom;
19-
}
20-
21-
return ++br->last_hwdom;
22-
}
23-
24-
int nbp_switchdev_hwdom_set(struct net_bridge_port *p)
25-
{
26-
struct netdev_phys_item_id ppid = { };
27-
int err;
28-
29-
ASSERT_RTNL();
30-
31-
err = dev_get_port_parent_id(p->dev, &ppid, true);
32-
if (err) {
33-
if (err == -EOPNOTSUPP)
34-
return 0;
35-
return err;
36-
}
37-
38-
p->hwdom = br_switchdev_hwdom_get(p->br, p->dev);
39-
40-
return 0;
41-
}
42-
4311
void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
4412
struct sk_buff *skb)
4513
{
@@ -156,3 +124,65 @@ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
156124

157125
return switchdev_port_obj_del(dev, &v.obj);
158126
}
127+
128+
static int nbp_switchdev_hwdom_set(struct net_bridge_port *joining)
129+
{
130+
struct net_bridge *br = joining->br;
131+
struct net_bridge_port *p;
132+
int hwdom;
133+
134+
/* joining is yet to be added to the port list. */
135+
list_for_each_entry(p, &br->port_list, list) {
136+
if (netdev_port_same_parent_id(joining->dev, p->dev)) {
137+
joining->hwdom = p->hwdom;
138+
return 0;
139+
}
140+
}
141+
142+
hwdom = find_next_zero_bit(&br->busy_hwdoms, BR_HWDOM_MAX, 1);
143+
if (hwdom >= BR_HWDOM_MAX)
144+
return -EBUSY;
145+
146+
set_bit(hwdom, &br->busy_hwdoms);
147+
joining->hwdom = hwdom;
148+
return 0;
149+
}
150+
151+
static void nbp_switchdev_hwdom_put(struct net_bridge_port *leaving)
152+
{
153+
struct net_bridge *br = leaving->br;
154+
struct net_bridge_port *p;
155+
156+
/* leaving is no longer in the port list. */
157+
list_for_each_entry(p, &br->port_list, list) {
158+
if (p->hwdom == leaving->hwdom)
159+
return;
160+
}
161+
162+
clear_bit(leaving->hwdom, &br->busy_hwdoms);
163+
}
164+
165+
int nbp_switchdev_add(struct net_bridge_port *p)
166+
{
167+
struct netdev_phys_item_id ppid = { };
168+
int err;
169+
170+
ASSERT_RTNL();
171+
172+
err = dev_get_port_parent_id(p->dev, &ppid, true);
173+
if (err) {
174+
if (err == -EOPNOTSUPP)
175+
return 0;
176+
return err;
177+
}
178+
179+
return nbp_switchdev_hwdom_set(p);
180+
}
181+
182+
void nbp_switchdev_del(struct net_bridge_port *p)
183+
{
184+
ASSERT_RTNL();
185+
186+
if (p->hwdom)
187+
nbp_switchdev_hwdom_put(p);
188+
}

0 commit comments

Comments
 (0)