Skip to content

Commit

Permalink
bridge: Add a sysctl to limit new brides FDB entries
Browse files Browse the repository at this point in the history
This is a convenience setting, which allows the administrator to limit
the default limit of FDB entries for all created bridges, instead of
having to set it for each created bridge using the netlink property.

The setting is network namespace local, and defaults to 0, which means
unlimited, for backwards compatibility reasons.

Signed-off-by: Johannes Nixdorf <jnixdorf-oss@avm.de>
  • Loading branch information
Johannes Nixdorf authored and intel-lab-lkp committed May 15, 2023
1 parent f04aa74 commit fd0a1c1
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
83 changes: 83 additions & 0 deletions net/bridge/br.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/llc.h>
#include <net/llc.h>
#include <net/netns/generic.h>
#include <net/stp.h>
#include <net/switchdev.h>

Expand Down Expand Up @@ -348,6 +349,82 @@ void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
clear_bit(opt, &br->options);
}

#ifdef CONFIG_SYSCTL
static unsigned int br_net_id __read_mostly;

struct br_net {
struct ctl_table_header *ctl_hdr;

unsigned int fdb_max_entries_default;
};

static int br_proc_rtnl_uintvec(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
int ret;

rtnl_lock();
ret = proc_douintvec(table, write, buffer, lenp, ppos);
rtnl_unlock();

return ret;
}

static struct ctl_table br_sysctl_table[] = {
{
.procname = "bridge-fdb-max-entries-default",
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = br_proc_rtnl_uintvec,
},
{ }
};

static int __net_init br_net_init(struct net *net)
{
struct ctl_table *table = br_sysctl_table;
struct br_net *brnet;

if (!net_eq(net, &init_net)) {
table = kmemdup(table, sizeof(br_sysctl_table), GFP_KERNEL);
if (!table)
return -ENOMEM;
}

brnet = net_generic(net, br_net_id);

brnet->fdb_max_entries_default = 0;

table[0].data = &brnet->fdb_max_entries_default;
brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
if (!brnet->ctl_hdr) {
if (!net_eq(net, &init_net))
kfree(table);

return -ENOMEM;
}

return 0;
}

static void __net_exit br_net_exit(struct net *net)
{
struct br_net *brnet = net_generic(net, br_net_id);
struct ctl_table *table = brnet->ctl_hdr->ctl_table_arg;

unregister_net_sysctl_table(brnet->ctl_hdr);
if (!net_eq(net, &init_net))
kfree(table);
}

unsigned int br_fdb_max_entries_default(struct net *net)
{
struct br_net *brnet = net_generic(net, br_net_id);

return brnet->fdb_max_entries_default;
}
#endif

static void __net_exit br_net_exit_batch(struct list_head *net_list)
{
struct net_device *dev;
Expand All @@ -367,6 +444,12 @@ static void __net_exit br_net_exit_batch(struct list_head *net_list)
}

static struct pernet_operations br_net_ops = {
#ifdef CONFIG_SYSCTL
.init = br_net_init,
.exit = br_net_exit,
.id = &br_net_id,
.size = sizeof(struct br_net),
#endif
.exit_batch = br_net_exit_batch,
};

Expand Down
4 changes: 3 additions & 1 deletion net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ static void br_set_lockdep_class(struct net_device *dev)
static int br_dev_init(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
struct net *net = dev_net(dev);
int err;

br->fdb_max_entries = br_fdb_max_entries_default(net);

dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!dev->tstats)
return -ENOMEM;
Expand Down Expand Up @@ -529,7 +532,6 @@ void br_dev_setup(struct net_device *dev)
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
br->fdb_n_entries = 0;
br->fdb_max_entries = 0;
dev->max_mtu = ETH_MAX_MTU;

br_netfilter_rtable_init(br);
Expand Down
9 changes: 9 additions & 0 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -2223,4 +2223,13 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
u16 vid, struct net_bridge_port *p, struct nd_msg *msg);
struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m);
bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid);

#ifdef CONFIG_SYSFS
unsigned int br_fdb_max_entries_default(struct net *net);
#else
static inline unsigned int br_fdb_max_entries_default(struct net *net)
{
return 0;
}
#endif
#endif

0 comments on commit fd0a1c1

Please sign in to comment.