]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: bridge: add support for NO_LL_LEARN
authorJonas Gorski <jonas.gorski@bisdn.de>
Tue, 10 Dec 2024 15:45:20 +0000 (16:45 +0100)
committerJonas Gorski <jonas.gorski@bisdn.de>
Tue, 28 Jan 2025 09:38:01 +0000 (10:38 +0100)
When using locked ports on a bridge link-local learning needs to be
disabled to prevent the kernel from learning and automatically unlocking
hosts based on link-local traffic.

So add support for enabling NO_LL_LEARN for bridges.

man/systemd.netdev.xml
src/network/netdev/bridge.c
src/network/netdev/bridge.h
src/network/netdev/netdev-gperf.gperf
test/test-network/conf/25-bridge.netdev
test/test-network/systemd-networkd-tests.py

index d072501a458ac4b6d427fb2da4463b7df682e511..b809bd220e0ac10863266b57d14aa1d2d92d4af0 100644 (file)
           <xi:include href="version-info.xml" xpointer="v257"/>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>LinkLocalLearning=</varname></term>
+        <listitem>
+          <para>Takes a boolean. This enables learning source addresses from link local frames. When unset, the
+          kernel's default will be used.
+          </para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index d3ba4989d942f12f516fc8edce762bb3975d9e75..06f9840d1c6fe3ba8c2d8c461f426e473f734a57 100644 (file)
@@ -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) {
index 7be00e1063715c4eda66505075d1079fccd026e9..a1d682bf8f3a7595c13593276b155d4a2a1588ae 100644 (file)
@@ -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;
index be61e208a0113e0ab2b9b304aefba813c1f15ab6..dcd786d87f1f25a2112fa5ca9691dae57c8abbd9 100644 (file)
@@ -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)
index 9e7fa545b24ec7f86c3850d1ab5416cb0ca97e3a..398637b64353a48dfe5d8f17febd653fd1bc82d4 100644 (file)
@@ -18,3 +18,4 @@ VLANProtocol=802.1ad
 STP=true
 MulticastIGMPVersion=3
 FDBMaxLearned=4
+LinkLocalLearning=no
index a151e00a2f106ae5bb549a1d285da2e511a96484..533945ed0d714f8243308f34ecf07729d9cffd22 100755 (executable)
@@ -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)