diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 4fba788950..6a217d9cae 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -440,6 +440,16 @@
+
+ FDBMaxLearned=
+
+ Specifies the maximum number of learned Ethernet addresses for the bridge. When the limit is
+ reached, no more addresses are learned. When unset, the kernel's default will be used. 0 disables the limit.
+
+
+
+
+
diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
index e39a75cfe4..4cd54a3df5 100644
--- a/src/libsystemd/sd-netlink/netlink-types-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
@@ -173,6 +173,7 @@ static const NLAPolicy rtnl_link_info_data_bridge_policies[] = {
[IFLA_BR_MCAST_MLD_VERSION] = BUILD_POLICY(U8),
[IFLA_BR_VLAN_STATS_PER_PORT] = BUILD_POLICY(U8),
[IFLA_BR_MULTI_BOOLOPT] = BUILD_POLICY_WITH_SIZE(BINARY, sizeof(struct br_boolopt_multi)),
+ [IFLA_BR_FDB_MAX_LEARNED] = BUILD_POLICY(U32),
};
static const NLAPolicy rtnl_link_info_data_can_policies[] = {
diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c
index d426c0c501..27f3916476 100644
--- a/src/network/netdev/bridge.c
+++ b/src/network/netdev/bridge.c
@@ -137,6 +137,12 @@ static int netdev_bridge_post_create_message(NetDev *netdev, sd_netlink_message
return r;
}
+ if (b->fdb_max_learned_set) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_FDB_MAX_LEARNED, b->fdb_max_learned);
+ if (r < 0)
+ return r;
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return r;
@@ -230,6 +236,40 @@ int config_parse_bridge_port_priority(
prio);
}
+int config_parse_bridge_fdb_max_learned(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Bridge *b = ASSERT_PTR(userdata);
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ b->fdb_max_learned_set = false;
+ return 0;
+ }
+
+ r = config_parse_uint32_bounded(unit, filename, line, section, section_line, lvalue, rvalue,
+ 0, UINT32_MAX, true, &b->fdb_max_learned);
+ if (r <= 0)
+ return r;
+
+ b->fdb_max_learned_set = true;
+ return 1;
+}
+
static void bridge_init(NetDev *netdev) {
Bridge *b = BRIDGE(netdev);
diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h
index 72dd3e4205..7be00e1063 100644
--- a/src/network/netdev/bridge.h
+++ b/src/network/netdev/bridge.h
@@ -19,6 +19,8 @@ typedef struct Bridge {
uint16_t group_fwd_mask;
uint16_t default_pvid;
uint8_t igmp_version;
+ uint32_t fdb_max_learned;
+ bool fdb_max_learned_set;
usec_t forward_delay;
usec_t hello_time;
@@ -44,3 +46,4 @@ MulticastRouter multicast_router_from_string(const char *s) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_multicast_router);
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_igmp_version);
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
+CONFIG_PARSER_PROTOTYPE(config_parse_bridge_fdb_max_learned);
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 4883a2652d..8325c8779d 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -234,6 +234,7 @@ Bridge.VLANFiltering, config_parse_tristate,
Bridge.VLANProtocol, config_parse_vlanprotocol, 0, offsetof(Bridge, vlan_protocol)
Bridge.STP, config_parse_tristate, 0, offsetof(Bridge, stp)
Bridge.MulticastIGMPVersion, config_parse_uint8, 0, offsetof(Bridge, igmp_version)
+Bridge.FDBMaxLearned, config_parse_bridge_fdb_max_learned, 0, offsetof(Bridge, fdb_max_learned)
VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table) /* deprecated */
VRF.Table, config_parse_uint32, 0, offsetof(Vrf, table)
BareUDP.DestinationPort, config_parse_ip_port, 0, offsetof(BareUDP, dest_port)