diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index d072501a45..b809bd220e 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -456,6 +456,16 @@
+
+ LinkLocalLearning=
+
+ Takes a boolean. This enables learning source addresses from link local frames. When unset, the
+ kernel's default will be used.
+
+
+
+
+
diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c
index d3ba4989d9..06f9840d1c 100644
--- a/src/network/netdev/bridge.c
+++ b/src/network/netdev/bridge.c
@@ -47,6 +47,7 @@ static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Ne
static int netdev_bridge_post_create_message(NetDev *netdev, sd_netlink_message *req) {
Bridge *b = BRIDGE(netdev);
+ struct br_boolopt_multi bm = {};
int r;
r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
@@ -142,6 +143,17 @@ static int netdev_bridge_post_create_message(NetDev *netdev, sd_netlink_message
return r;
}
+ if (b->linklocal_learn >= 0) {
+ bm.optmask |= 1 << BR_BOOLOPT_NO_LL_LEARN;
+ SET_FLAG(bm.optval, 1 << BR_BOOLOPT_NO_LL_LEARN, !b->linklocal_learn);
+ }
+
+ if (bm.optmask != 0) {
+ r = sd_netlink_message_append_data(req, IFLA_BR_MULTI_BOOLOPT, &bm, sizeof(bm));
+ if (r < 0)
+ return r;
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return r;
@@ -279,6 +291,7 @@ static void bridge_init(NetDev *netdev) {
b->default_pvid = VLANID_INVALID;
b->forward_delay = USEC_INFINITY;
b->ageing_time = USEC_INFINITY;
+ b->linklocal_learn = -1;
}
static bool bridge_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h
index 7be00e1063..a1d682bf8f 100644
--- a/src/network/netdev/bridge.h
+++ b/src/network/netdev/bridge.h
@@ -21,6 +21,7 @@ typedef struct Bridge {
uint8_t igmp_version;
uint32_t fdb_max_learned;
bool fdb_max_learned_set;
+ int linklocal_learn;
usec_t forward_delay;
usec_t hello_time;
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index be61e208a0..dcd786d87f 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -236,6 +236,7 @@ Bridge.VLANProtocol, config_parse_vlanprotocol,
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)
+Bridge.LinkLocalLearning, config_parse_tristate, 0, offsetof(Bridge, linklocal_learn)
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)
diff --git a/test/test-network/conf/25-bridge.netdev b/test/test-network/conf/25-bridge.netdev
index 9e7fa545b2..398637b643 100644
--- a/test/test-network/conf/25-bridge.netdev
+++ b/test/test-network/conf/25-bridge.netdev
@@ -18,3 +18,4 @@ VLANProtocol=802.1ad
STP=true
MulticastIGMPVersion=3
FDBMaxLearned=4
+LinkLocalLearning=no
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index a151e00a2f..533945ed0d 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -1682,6 +1682,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
self.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
+ self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'no_linklocal_learn')))
output = networkctl_status('bridge99')
print(output)