1
0
mirror of https://github.com/systemd/systemd synced 2026-03-16 18:14:46 +01:00

Compare commits

..

10 Commits

Author SHA1 Message Date
asavah
670427a4d4 man: prevent race condition when generating systemd.directives.xml 2021-05-20 20:49:50 +01:00
Lennart Poettering
9d54c9a3d9
Merge pull request #19551 from cgzones/fix_reload
selinux: reload label db on policy load with libselinux 3.2
2021-05-20 21:37:59 +02:00
Lennart Poettering
f9e60ff9ad
Merge pull request #19605 from yuwata/network-fdb-outgoing-interface
network: bridge-fdb: add support to specify outgoing interface
2021-05-20 21:33:14 +02:00
Yu Watanabe
e6655fbe40 man: mention that drop-in files are merged in alphanumeric order
This addresses the request in https://github.com/systemd/systemd/issues/19467#issuecomment-829332877.
2021-05-20 21:20:51 +02:00
Yu Watanabe
db5486b450 test-network: add a testcase for OutgoingInterface= in [BridgeFDB] 2021-05-20 18:23:15 +09:00
Susant Sahani
af99cdf4d4 network: bridge-fdb: add support to specify outgoing interface 2021-05-20 18:23:15 +09:00
Yu Watanabe
e5b35bf6c2 network: use queue to configure bridge FDB 2021-05-20 18:23:15 +09:00
Yu Watanabe
9671ae9d51 network: bridgeFDB: rename FdbEntry -> BridgeFDB 2021-05-20 18:23:15 +09:00
Christian Göttsche
57e70396df selinux: invoke selinux_set_callback(3) more type-safe 2021-05-14 16:53:04 +02:00
Christian Göttsche
c46c768811 selinux: reload label db on policy load with libselinux 3.2
Currently the label database is not reloaded with libselinux 3.2 on a
policy reload.

Since libselinux 3.2 avc_open(3) uses the SELinux status page instead of
a netlink socket to check for policy reloads.
The status page is also queried in mac_selinux_maybe_reload().
Thus calls to selinux_check_access(3) might consume an update, queried
by selinux_status_updated(3), leaving mac_selinux_maybe_reload() unable
to detect a policy reload.

Do not use selinux_status_updated(3), use selinux_status_policyload(3)
unconditionally.

Relevant libselinux commit: 05bdc03130

Debian Bullseye is going to ship libselinux 3.1, so stay compatible for
backports.
2021-05-14 14:12:39 +02:00
21 changed files with 295 additions and 147 deletions

View File

@ -113,6 +113,7 @@ systemd_directives_xml = custom_target(
'systemd.directives.xml', 'systemd.directives.xml',
input : ['directives-template.xml', source_xml_files], input : ['directives-template.xml', source_xml_files],
output : 'systemd.directives.xml', output : 'systemd.directives.xml',
depends : custom_entities_ent,
command : [make_directive_index_py, '@OUTPUT@', '@INPUT@']) command : [make_directive_index_py, '@OUTPUT@', '@INPUT@'])
nonindex_xml_files = source_xml_files + [systemd_directives_xml] nonindex_xml_files = source_xml_files + [systemd_directives_xml]

View File

@ -47,9 +47,9 @@
<para>Along with the link file <filename>foo.link</filename>, a "drop-in" directory <para>Along with the link file <filename>foo.link</filename>, a "drop-in" directory
<filename>foo.link.d/</filename> may exist. All files with the suffix <literal>.conf</literal> <filename>foo.link.d/</filename> may exist. All files with the suffix <literal>.conf</literal>
from this directory will be parsed after the file itself is parsed. This is useful to alter or add from this directory will be merged in the alphanumeric order and parsed after the main file itself
configuration settings, without having to modify the main configuration file. Each drop-in file has been parsed. This is useful to alter or add configuration settings, without having to modify
must have appropriate section headers.</para> the main configuration file. Each drop-in file must have appropriate section headers.</para>
<para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal> <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
directories can be placed in <filename>/usr/lib/systemd/network</filename> or directories can be placed in <filename>/usr/lib/systemd/network</filename> or

View File

@ -52,9 +52,9 @@
<para>Along with the netdev file <filename>foo.netdev</filename>, a "drop-in" directory <para>Along with the netdev file <filename>foo.netdev</filename>, a "drop-in" directory
<filename>foo.netdev.d/</filename> may exist. All files with the suffix <literal>.conf</literal> <filename>foo.netdev.d/</filename> may exist. All files with the suffix <literal>.conf</literal>
from this directory will be parsed after the file itself is parsed. This is useful to alter or from this directory will be merged in the alphanumeric order and parsed after the main file itself
add configuration settings, without having to modify the main configuration file. Each drop-in has been parsed. This is useful to alter or add configuration settings, without having to modify
file must have appropriate section headers.</para> the main configuration file. Each drop-in file must have appropriate section headers.</para>
<para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal> <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
directories can be placed in <filename>/usr/lib/systemd/network</filename> or directories can be placed in <filename>/usr/lib/systemd/network</filename> or

View File

@ -51,9 +51,10 @@
<para>Along with the network file <filename>foo.network</filename>, a "drop-in" directory <para>Along with the network file <filename>foo.network</filename>, a "drop-in" directory
<filename>foo.network.d/</filename> may exist. All files with the suffix <filename>foo.network.d/</filename> may exist. All files with the suffix
<literal>.conf</literal> from this directory will be parsed after the file itself is <literal>.conf</literal> from this directory will be merged in the alphanumeric order and parsed
parsed. This is useful to alter or add configuration settings, without having to modify the main after the main file itself has been parsed. This is useful to alter or add configuration settings,
configuration file. Each drop-in file must have appropriate section headers.</para> without having to modify the main configuration file. Each drop-in file must have appropriate
section headers.</para>
<para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal> <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
directories can be placed in <filename>/usr/lib/systemd/network</filename> or directories can be placed in <filename>/usr/lib/systemd/network</filename> or
@ -2856,6 +2857,13 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
device is a VXLAN type device and has route shortcircuit enabled. Defaults to <literal>self</literal>.</para> device is a VXLAN type device and has route shortcircuit enabled. Defaults to <literal>self</literal>.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>OutgoingInterface=</varname></term>
<listitem>
<para>Specifies the name or index of the outgoing interface for the VXLAN device driver to
reach the remote VXLAN tunnel endpoint. Defaults to unset.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -184,14 +184,16 @@
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory <para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory
<filename>foo.service.d/</filename> may exist. All files with the suffix <literal>.conf</literal> from this <filename>foo.service.d/</filename> may exist. All files with the suffix
directory will be parsed after the unit file itself is parsed. This is useful to alter or add configuration <literal>.conf</literal> from this directory will be merged in the alphanumeric order and parsed
settings for a unit, without having to modify unit files. Drop-in files must contain appropriate section after the main unit file itself has been parsed. This is useful to alter or add configuration
headers. For instantiated units, this logic will first look for the instance <literal>.d/</literal> subdirectory settings for a unit, without having to modify unit files. Each drop-in file must contain appropriate
(e.g. <literal>foo@bar.service.d/</literal>) and read its <literal>.conf</literal> files, followed by the template section headers. For instantiated units, this logic will first look for the instance
<literal>.d/</literal> subdirectory (e.g. <literal>foo@.service.d/</literal>) and the <literal>.conf</literal> <literal>.d/</literal> subdirectory (e.g. <literal>foo@bar.service.d/</literal>) and read its
files there. Moreover for unit names containing dashes (<literal>-</literal>), the set of directories generated by <literal>.conf</literal> files, followed by the template <literal>.d/</literal> subdirectory (e.g.
repeatedly truncating the unit name after all dashes is searched too. Specifically, for a unit name <literal>foo@.service.d/</literal>) and the <literal>.conf</literal> files there. Moreover for unit
names containing dashes (<literal>-</literal>), the set of directories generated by repeatedly
truncating the unit name after all dashes is searched too. Specifically, for a unit name
<filename>foo-bar-baz.service</filename> not only the regular drop-in directory <filename>foo-bar-baz.service</filename> not only the regular drop-in directory
<filename>foo-bar-baz.service.d/</filename> is searched but also both <filename>foo-bar-.service.d/</filename> and <filename>foo-bar-baz.service.d/</filename> is searched but also both <filename>foo-bar-.service.d/</filename> and
<filename>foo-.service.d/</filename>. This is useful for defining common drop-ins for a set of related units, whose <filename>foo-.service.d/</filename>. This is useful for defining common drop-ins for a set of related units, whose

View File

@ -182,29 +182,28 @@ int mac_selinux_init(void) {
void mac_selinux_maybe_reload(void) { void mac_selinux_maybe_reload(void) {
#if HAVE_SELINUX #if HAVE_SELINUX
int r; int policyload;
if (!initialized) if (!initialized)
return; return;
r = selinux_status_updated(); /* Do not use selinux_status_updated(3), cause since libselinux 3.2 selinux_check_access(3),
if (r < 0) * called in core and user instances, does also use it under the hood.
log_debug_errno(errno, "Failed to update SELinux from status page: %m"); * That can cause changes to be consumed by selinux_check_access(3) and not being visible here.
if (r > 0) { * Also do not use selinux callbacks, selinux_set_callback(3), cause they are only automatically
int policyload; * invoked since libselinux 3.2 by selinux_status_updated(3).
* Relevant libselinux commit: https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503
log_debug("SELinux status page update"); * Debian Bullseye is going to ship libselinux 3.1, so stay compatible for backports. */
/* from libselinux > 3.1 callbacks gets automatically called, see
https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503 */
/* only reload on policy changes, not enforcing status changes */
policyload = selinux_status_policyload(); policyload = selinux_status_policyload();
if (policyload < 0) {
log_debug_errno(errno, "Failed to get SELinux policyload from status page: %m");
return;
}
if (policyload != last_policyload) { if (policyload != last_policyload) {
mac_selinux_reload(policyload); mac_selinux_reload(policyload);
last_policyload = policyload; last_policyload = policyload;
} }
}
#endif #endif
} }

View File

@ -162,8 +162,8 @@ static int access_init(sd_bus_error *error) {
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror_safe(saved_errno)); return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror_safe(saved_errno));
} }
selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) { .func_audit = audit_callback });
selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = log_callback });
initialized = true; initialized = true;
return 1; return 1;

View File

@ -30,16 +30,12 @@ int mac_selinux_setup(bool *loaded_policy) {
usec_t before_load, after_load; usec_t before_load, after_load;
char *con; char *con;
int r; int r;
static const union selinux_callback cb = {
.func_log = null_log,
};
bool initialized = false; bool initialized = false;
assert(loaded_policy); assert(loaded_policy);
/* Turn off all of SELinux' own logging, we want to do that */ /* Turn off all of SELinux' own logging, we want to do that */
selinux_set_callback(SELINUX_CB_LOG, cb); selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = null_log });
/* Don't load policy in the initrd if we don't appear to have /* Don't load policy in the initrd if we don't appear to have
* it. For the real root, we check below if we've already * it. For the real root, we check below if we've already

View File

@ -57,6 +57,8 @@ sources = files('''
networkd-address-pool.h networkd-address-pool.h
networkd-address.c networkd-address.c
networkd-address.h networkd-address.h
networkd-bridge-fdb.c
networkd-bridge-fdb.h
networkd-brvlan.c networkd-brvlan.c
networkd-brvlan.h networkd-brvlan.h
networkd-can.c networkd-can.c
@ -73,8 +75,6 @@ sources = files('''
networkd-dhcp4.h networkd-dhcp4.h
networkd-dhcp6.c networkd-dhcp6.c
networkd-dhcp6.h networkd-dhcp6.h
networkd-fdb.c
networkd-fdb.h
networkd-ipv4ll.c networkd-ipv4ll.c
networkd-ipv4ll.h networkd-ipv4ll.h
networkd-ipv6-proxy-ndp.c networkd-ipv6-proxy-ndp.c

View File

@ -9,42 +9,46 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "bridge.h" #include "bridge.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-fdb.h" #include "networkd-bridge-fdb.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "string-table.h" #include "string-table.h"
#include "vlan-util.h" #include "vlan-util.h"
#include "vxlan.h" #include "vxlan.h"
#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U #define STATIC_BRIDGE_FDB_ENTRIES_PER_NETWORK_MAX 1024U
/* remove and FDB entry. */ /* remove and FDB entry. */
FdbEntry *fdb_entry_free(FdbEntry *fdb_entry) { BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
if (!fdb_entry) if (!fdb)
return NULL; return NULL;
if (fdb_entry->network) { if (fdb->network) {
assert(fdb_entry->section); assert(fdb->section);
hashmap_remove(fdb_entry->network->fdb_entries_by_section, fdb_entry->section); hashmap_remove(fdb->network->bridge_fdb_entries_by_section, fdb->section);
} }
network_config_section_free(fdb_entry->section); network_config_section_free(fdb->section);
return mfree(fdb_entry);
free(fdb->outgoing_ifname);
return mfree(fdb);
} }
DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free); DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeFDB, bridge_fdb_free);
/* create a new FDB entry or get an existing one. */ /* create a new FDB entry or get an existing one. */
static int fdb_entry_new_static( static int bridge_fdb_new_static(
Network *network, Network *network,
const char *filename, const char *filename,
unsigned section_line, unsigned section_line,
FdbEntry **ret) { BridgeFDB **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(fdb_entry_freep) FdbEntry *fdb_entry = NULL; _cleanup_(bridge_fdb_freep) BridgeFDB *fdb = NULL;
int r; int r;
assert(network); assert(network);
@ -57,72 +61,82 @@ static int fdb_entry_new_static(
return r; return r;
/* search entry in hashmap first. */ /* search entry in hashmap first. */
fdb_entry = hashmap_get(network->fdb_entries_by_section, n); fdb = hashmap_get(network->bridge_fdb_entries_by_section, n);
if (fdb_entry) { if (fdb) {
*ret = TAKE_PTR(fdb_entry); *ret = TAKE_PTR(fdb);
return 0; return 0;
} }
if (hashmap_size(network->fdb_entries_by_section) >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX) if (hashmap_size(network->bridge_fdb_entries_by_section) >= STATIC_BRIDGE_FDB_ENTRIES_PER_NETWORK_MAX)
return -E2BIG; return -E2BIG;
/* allocate space for and FDB entry. */ /* allocate space for and FDB entry. */
fdb_entry = new(FdbEntry, 1); fdb = new(BridgeFDB, 1);
if (!fdb_entry) if (!fdb)
return -ENOMEM; return -ENOMEM;
/* init FDB structure. */ /* init FDB structure. */
*fdb_entry = (FdbEntry) { *fdb = (BridgeFDB) {
.network = network, .network = network,
.section = TAKE_PTR(n), .section = TAKE_PTR(n),
.vni = VXLAN_VID_MAX + 1, .vni = VXLAN_VID_MAX + 1,
.fdb_ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF, .ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
}; };
r = hashmap_ensure_put(&network->fdb_entries_by_section, &network_config_hash_ops, fdb_entry->section, fdb_entry); r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &network_config_hash_ops, fdb->section, fdb);
if (r < 0) if (r < 0)
return r; return r;
/* return allocated FDB structure. */ /* return allocated FDB structure. */
*ret = TAKE_PTR(fdb_entry); *ret = TAKE_PTR(fdb);
return 0; return 0;
} }
static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int bridge_fdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
assert(link); assert(link);
assert(link->static_bridge_fdb_messages > 0);
link->static_bridge_fdb_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1; return 0;
r = sd_netlink_message_get_errno(m); r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) { if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not add FDB entry"); log_link_message_warning_errno(link, m, r, "Could not add bridge FDB entry");
link_enter_failed(link); link_enter_failed(link);
return 1; return 0;
} }
return 1; if (link->static_bridge_fdb_messages == 0) {
log_link_debug(link, "Bridge FDB entries set");
link->static_bridge_fdb_configured = true;
link_check_ready(link);
}
return 0;
} }
/* send a request to the kernel to add a FDB entry in its static MAC table. */ /* send a request to the kernel to add a FDB entry in its static MAC table. */
static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) { static int bridge_fdb_configure(const BridgeFDB *fdb, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r; int r;
assert(fdb);
assert(link); assert(link);
assert(link->network);
assert(link->manager); assert(link->manager);
assert(fdb_entry); assert(link->manager->rtnl);
assert(callback);
/* create new RTM message */ /* create new RTM message */
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_BRIDGE); r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_BRIDGE);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m"); return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_flags(req, fdb_entry->fdb_ntf_flags); r = sd_rtnl_message_neigh_set_flags(req, fdb->ntf_flags);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set neighbor flags: %m"); return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
@ -131,31 +145,37 @@ static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set neighbor state: %m"); return log_link_error_errno(link, r, "Could not set neighbor state: %m");
r = sd_netlink_message_append_data(req, NDA_LLADDR, &fdb_entry->mac_addr, sizeof(fdb_entry->mac_addr)); r = sd_netlink_message_append_data(req, NDA_LLADDR, &fdb->mac_addr, sizeof(fdb->mac_addr));
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m"); return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m");
/* VLAN Id is optional. We'll add VLAN Id only if it's specified. */ /* VLAN Id is optional. We'll add VLAN Id only if it's specified. */
if (fdb_entry->vlan_id > 0) { if (fdb->vlan_id > 0) {
r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id); r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb->vlan_id);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_VLAN attribute: %m"); return log_link_error_errno(link, r, "Could not append NDA_VLAN attribute: %m");
} }
if (in_addr_is_set(fdb_entry->family, &fdb_entry->destination_addr)) { if (fdb->outgoing_ifindex > 0) {
r = netlink_message_append_in_addr_union(req, NDA_DST, fdb_entry->family, &fdb_entry->destination_addr); r = sd_netlink_message_append_u32(req, NDA_IFINDEX, fdb->outgoing_ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_IFINDEX attribute: %m");
}
if (in_addr_is_set(fdb->family, &fdb->destination_addr)) {
r = netlink_message_append_in_addr_union(req, NDA_DST, fdb->family, &fdb->destination_addr);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m"); return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
} }
if (fdb_entry->vni <= VXLAN_VID_MAX) { if (fdb->vni <= VXLAN_VID_MAX) {
r = sd_netlink_message_append_u32(req, NDA_VNI, fdb_entry->vni); r = sd_netlink_message_append_u32(req, NDA_VNI, fdb->vni);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_VNI attribute: %m"); return log_link_error_errno(link, r, "Could not append NDA_VNI attribute: %m");
} }
/* send message to the kernel to update its internal static MAC table. */ /* send message to the kernel to update its internal static MAC table. */
r = netlink_call_async(link->manager->rtnl, NULL, req, set_fdb_handler, r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link); link_netlink_destroy_callback, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@ -165,30 +185,78 @@ static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
return 1; return 1;
} }
int link_set_bridge_fdb(Link *link) { int link_request_static_bridge_fdb(Link *link) {
FdbEntry *fdb_entry; BridgeFDB *fdb;
int r; int r;
assert(link); assert(link);
assert(link->network); assert(link->network);
HASHMAP_FOREACH(fdb_entry, link->network->fdb_entries_by_section) { link->static_bridge_fdb_configured = false;
r = fdb_entry_configure(link, fdb_entry);
HASHMAP_FOREACH(fdb, link->network->bridge_fdb_entries_by_section) {
r = link_queue_request(link, REQUEST_TYPE_BRIDGE_FDB, fdb, false,
&link->static_bridge_fdb_messages, bridge_fdb_configure_handler, NULL);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); return log_link_error_errno(link, r, "Failed to request static bridge FDB entry: %m");
}
if (link->static_bridge_fdb_messages == 0) {
link->static_bridge_fdb_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting bridge FDB entries");
link_set_state(link, LINK_STATE_CONFIGURING);
} }
return 0; return 0;
} }
void network_drop_invalid_fdb_entries(Network *network) { static bool bridge_fdb_is_ready_to_configure(BridgeFDB *fdb, Link *link) {
FdbEntry *fdb_entry; Link *out = NULL;
assert(fdb);
assert(link);
assert(link->manager);
if (!link_is_ready_to_configure(link, false))
return false;
if (fdb->outgoing_ifname) {
if (link_get_by_name(link->manager, fdb->outgoing_ifname, &out) < 0)
return false;
fdb->outgoing_ifindex = out->ifindex;
} else if (fdb->outgoing_ifindex > 0) {
if (link_get(link->manager, fdb->outgoing_ifindex, &out) < 0)
return false;
}
if (out && !link_is_ready_to_configure(out, false))
return false;
return true;
}
int request_process_bridge_fdb(Request *req) {
assert(req);
assert(req->link);
assert(req->fdb);
assert(req->type == REQUEST_TYPE_BRIDGE_FDB);
if (!bridge_fdb_is_ready_to_configure(req->fdb, req->link))
return 0;
return bridge_fdb_configure(req->fdb, req->link, req->netlink_handler);
}
void network_drop_invalid_bridge_fdb_entries(Network *network) {
BridgeFDB *fdb;
assert(network); assert(network);
HASHMAP_FOREACH(fdb_entry, network->fdb_entries_by_section) HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
if (section_is_invalid(fdb_entry->section)) if (section_is_invalid(fdb->section))
fdb_entry_free(fdb_entry); bridge_fdb_free(fdb);
} }
/* parse the HW address from config files. */ /* parse the HW address from config files. */
@ -204,8 +272,8 @@ int config_parse_fdb_hwaddr(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata; Network *network = userdata;
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
int r; int r;
assert(filename); assert(filename);
@ -214,18 +282,17 @@ int config_parse_fdb_hwaddr(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = fdb_entry_new_static(network, filename, section_line, &fdb_entry); r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
r = ether_addr_from_string(rvalue, &fdb_entry->mac_addr); r = ether_addr_from_string(rvalue, &fdb->mac_addr);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0; return 0;
} }
fdb_entry = NULL; TAKE_PTR(fdb);
return 0; return 0;
} }
@ -242,8 +309,8 @@ int config_parse_fdb_vlan_id(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata; Network *network = userdata;
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
int r; int r;
assert(filename); assert(filename);
@ -252,18 +319,17 @@ int config_parse_fdb_vlan_id(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = fdb_entry_new_static(network, filename, section_line, &fdb_entry); r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
r = config_parse_vlanid(unit, filename, line, section, r = config_parse_vlanid(unit, filename, line, section,
section_line, lvalue, ltype, section_line, lvalue, ltype,
rvalue, &fdb_entry->vlan_id, userdata); rvalue, &fdb->vlan_id, userdata);
if (r < 0) if (r < 0)
return r; return r;
fdb_entry = NULL; TAKE_PTR(fdb);
return 0; return 0;
} }
@ -279,7 +345,7 @@ int config_parse_fdb_destination(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL; _cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata; Network *network = userdata;
int r; int r;
@ -289,11 +355,11 @@ int config_parse_fdb_destination(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = fdb_entry_new_static(network, filename, section_line, &fdb_entry); r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
r = in_addr_from_string_auto(rvalue, &fdb_entry->family, &fdb_entry->destination_addr); r = in_addr_from_string_auto(rvalue, &fdb->family, &fdb->destination_addr);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"FDB destination IP address is invalid, ignoring assignment: %s", "FDB destination IP address is invalid, ignoring assignment: %s",
@ -301,8 +367,7 @@ int config_parse_fdb_destination(
return 0; return 0;
} }
fdb_entry = NULL; TAKE_PTR(fdb);
return 0; return 0;
} }
@ -318,7 +383,7 @@ int config_parse_fdb_vxlan_vni(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL; _cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata; Network *network = userdata;
uint32_t vni; uint32_t vni;
int r; int r;
@ -329,7 +394,7 @@ int config_parse_fdb_vxlan_vni(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = fdb_entry_new_static(network, filename, section_line, &fdb_entry); r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
@ -348,20 +413,20 @@ int config_parse_fdb_vxlan_vni(
return 0; return 0;
} }
fdb_entry->vni = vni; fdb->vni = vni;
fdb_entry = NULL;
TAKE_PTR(fdb);
return 0; return 0;
} }
static const char* const fdb_ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = { static const char* const ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = {
[NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use", [NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use",
[NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self", [NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self",
[NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master", [NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master",
[NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router", [NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router",
}; };
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fdb_ntf_flags, NeighborCacheEntryFlags); DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(ntf_flags, NeighborCacheEntryFlags);
int config_parse_fdb_ntf_flags( int config_parse_fdb_ntf_flags(
const char *unit, const char *unit,
@ -375,7 +440,48 @@ int config_parse_fdb_ntf_flags(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL; _cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata;
NeighborCacheEntryFlags f;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0)
return log_oom();
f = ntf_flags_from_string(rvalue);
if (f < 0) {
log_syntax(unit, LOG_WARNING, filename, line, f,
"FDB failed to parse AssociatedWith=, ignoring assignment: %s",
rvalue);
return 0;
}
fdb->ntf_flags = f;
TAKE_PTR(fdb);
return 0;
}
int config_parse_fdb_interface(
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) {
_cleanup_(bridge_fdb_free_or_set_invalidp) BridgeFDB *fdb = NULL;
Network *network = userdata; Network *network = userdata;
int r; int r;
@ -385,20 +491,36 @@ int config_parse_fdb_ntf_flags(
assert(rvalue); assert(rvalue);
assert(data); assert(data);
r = fdb_entry_new_static(network, filename, section_line, &fdb_entry); r = bridge_fdb_new_static(network, filename, section_line, &fdb);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
NeighborCacheEntryFlags f = fdb_ntf_flags_from_string(rvalue); if (isempty(rvalue)) {
if (f < 0) { fdb->outgoing_ifname = mfree(fdb->outgoing_ifname);
log_syntax(unit, LOG_WARNING, filename, line, f, fdb->outgoing_ifindex = 0;
"FDB failed to parse AssociatedWith=, ignoring assignment: %s", TAKE_PTR(fdb);
rvalue);
return 0; return 0;
} }
fdb_entry->fdb_ntf_flags = f; r = parse_ifindex(rvalue);
fdb_entry = NULL; if (r > 0) {
fdb->outgoing_ifname = mfree(fdb->outgoing_ifname);
fdb->outgoing_ifindex = r;
TAKE_PTR(fdb);
return 0;
}
if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
r = free_and_strdup(&fdb->outgoing_ifname, rvalue);
if (r < 0)
return log_oom();
fdb->outgoing_ifindex = 0;
TAKE_PTR(fdb);
return 0; return 0;
} }

View File

@ -11,10 +11,10 @@
#include "conf-parser.h" #include "conf-parser.h"
#include "ether-addr-util.h" #include "ether-addr-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link; typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef enum NeighborCacheEntryFlags { typedef enum NeighborCacheEntryFlags {
NEIGHBOR_CACHE_ENTRY_FLAGS_USE = NTF_USE, NEIGHBOR_CACHE_ENTRY_FLAGS_USE = NTF_USE,
@ -25,7 +25,7 @@ typedef enum NeighborCacheEntryFlags {
_NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -EINVAL, _NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -EINVAL,
} NeighborCacheEntryFlags; } NeighborCacheEntryFlags;
typedef struct FdbEntry { typedef struct BridgeFDB {
Network *network; Network *network;
NetworkConfigSection *section; NetworkConfigSection *section;
@ -36,17 +36,22 @@ typedef struct FdbEntry {
struct ether_addr mac_addr; struct ether_addr mac_addr;
union in_addr_union destination_addr; union in_addr_union destination_addr;
NeighborCacheEntryFlags fdb_ntf_flags; NeighborCacheEntryFlags ntf_flags;
} FdbEntry; char *outgoing_ifname;
int outgoing_ifindex;
} BridgeFDB;
FdbEntry *fdb_entry_free(FdbEntry *fdb_entry); BridgeFDB *bridge_fdb_free(BridgeFDB *fdb);
void network_drop_invalid_fdb_entries(Network *network); void network_drop_invalid_bridge_fdb_entries(Network *network);
int link_set_bridge_fdb(Link *link); int link_request_static_bridge_fdb(Link *link);
int request_process_bridge_fdb(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_destination); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_destination);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vxlan_vni); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vxlan_vni);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_ntf_flags); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_ntf_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_interface);

View File

@ -27,11 +27,11 @@
#include "network-internal.h" #include "network-internal.h"
#include "networkd-address-label.h" #include "networkd-address-label.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-can.h" #include "networkd-can.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"
#include "networkd-fdb.h"
#include "networkd-ipv4ll.h" #include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h" #include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link-bus.h" #include "networkd-link-bus.h"
@ -744,6 +744,9 @@ void link_check_ready(Link *link) {
return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str)); return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str));
} }
if (!link->static_bridge_fdb_configured)
return (void) log_link_debug(link, "%s(): static bridge MDB entries are not configured.", __func__);
if (!link->static_neighbors_configured) if (!link->static_neighbors_configured)
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__); return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
@ -817,10 +820,6 @@ static int link_set_static_configs(Link *link) {
assert(link->network); assert(link->network);
assert(link->state != _LINK_STATE_INVALID); assert(link->state != _LINK_STATE_INVALID);
r = link_set_bridge_fdb(link);
if (r < 0)
return r;
r = link_set_bridge_mdb(link); r = link_set_bridge_mdb(link);
if (r < 0) if (r < 0)
return r; return r;
@ -837,6 +836,10 @@ static int link_set_static_configs(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
r = link_request_static_bridge_fdb(link);
if (r < 0)
return r;
r = link_request_static_neighbors(link); r = link_request_static_neighbors(link);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -81,6 +81,7 @@ typedef struct Link {
unsigned address_label_messages; unsigned address_label_messages;
unsigned static_address_messages; unsigned static_address_messages;
unsigned static_bridge_fdb_messages;
unsigned static_neighbor_messages; unsigned static_neighbor_messages;
unsigned static_nexthop_messages; unsigned static_nexthop_messages;
unsigned static_route_messages; unsigned static_route_messages;
@ -122,6 +123,7 @@ typedef struct Link {
bool ipv4ll_address_configured:1; bool ipv4ll_address_configured:1;
bool static_addresses_configured:1; bool static_addresses_configured:1;
bool static_bridge_fdb_configured:1;
bool static_neighbors_configured:1; bool static_neighbors_configured:1;
bool static_nexthops_configured:1; bool static_nexthops_configured:1;
bool static_routes_configured:1; bool static_routes_configured:1;

View File

@ -9,12 +9,12 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "net-condition.h" #include "net-condition.h"
#include "networkd-address-label.h" #include "networkd-address-label.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-can.h" #include "networkd-can.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"
#include "networkd-fdb.h"
#include "networkd-ipv4ll.h" #include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h" #include "networkd-ipv6-proxy-ndp.h"
#include "networkd-mdb.h" #include "networkd-mdb.h"
@ -306,6 +306,7 @@ BridgeFDB.VLANId, config_parse_fdb_vlan_id,
BridgeFDB.Destination, config_parse_fdb_destination, 0, 0 BridgeFDB.Destination, config_parse_fdb_destination, 0, 0
BridgeFDB.VNI, config_parse_fdb_vxlan_vni, 0, 0 BridgeFDB.VNI, config_parse_fdb_vxlan_vni, 0, 0
BridgeFDB.AssociatedWith, config_parse_fdb_ntf_flags, 0, 0 BridgeFDB.AssociatedWith, config_parse_fdb_ntf_flags, 0, 0
BridgeFDB.OutgoingInterface, config_parse_fdb_interface, 0, 0
BridgeMDB.MulticastGroupAddress, config_parse_mdb_group_address, 0, 0 BridgeMDB.MulticastGroupAddress, config_parse_mdb_group_address, 0, 0
BridgeMDB.VLANId, config_parse_mdb_vlan_id, 0, 0 BridgeMDB.VLANId, config_parse_mdb_vlan_id, 0, 0
BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0 BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0

View File

@ -15,9 +15,9 @@
#include "net-condition.h" #include "net-condition.h"
#include "networkd-address-label.h" #include "networkd-address-label.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-fdb.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-mdb.h" #include "networkd-mdb.h"
#include "networkd-ndisc.h" #include "networkd-ndisc.h"
@ -230,7 +230,7 @@ int network_verify(Network *network) {
network_drop_invalid_addresses(network); network_drop_invalid_addresses(network);
network_drop_invalid_routes(network); network_drop_invalid_routes(network);
network_drop_invalid_nexthops(network); network_drop_invalid_nexthops(network);
network_drop_invalid_fdb_entries(network); network_drop_invalid_bridge_fdb_entries(network);
network_drop_invalid_mdb_entries(network); network_drop_invalid_mdb_entries(network);
network_drop_invalid_neighbors(network); network_drop_invalid_neighbors(network);
network_drop_invalid_address_labels(network); network_drop_invalid_address_labels(network);
@ -598,7 +598,7 @@ static Network *network_free(Network *network) {
ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free); ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
hashmap_free_with_destructor(network->routes_by_section, route_free); hashmap_free_with_destructor(network->routes_by_section, route_free);
hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free); hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free); hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free); hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free); hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
hashmap_free_with_destructor(network->address_labels_by_section, address_label_free); hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
@ -651,7 +651,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
bool network_has_static_ipv6_configurations(Network *network) { bool network_has_static_ipv6_configurations(Network *network) {
Address *address; Address *address;
Route *route; Route *route;
FdbEntry *fdb; BridgeFDB *fdb;
MdbEntry *mdb; MdbEntry *mdb;
Neighbor *neighbor; Neighbor *neighbor;
@ -665,7 +665,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
if (route->family == AF_INET6) if (route->family == AF_INET6)
return true; return true;
HASHMAP_FOREACH(fdb, network->fdb_entries_by_section) HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
if (fdb->family == AF_INET6) if (fdb->family == AF_INET6)
return true; return true;

View File

@ -307,7 +307,7 @@ struct Network {
OrderedHashmap *addresses_by_section; OrderedHashmap *addresses_by_section;
Hashmap *routes_by_section; Hashmap *routes_by_section;
Hashmap *nexthops_by_section; Hashmap *nexthops_by_section;
Hashmap *fdb_entries_by_section; Hashmap *bridge_fdb_entries_by_section;
Hashmap *mdb_entries_by_section; Hashmap *mdb_entries_by_section;
Hashmap *neighbors_by_section; Hashmap *neighbors_by_section;
Hashmap *address_labels_by_section; Hashmap *address_labels_by_section;

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-neighbor.h" #include "networkd-neighbor.h"
#include "networkd-nexthop.h" #include "networkd-nexthop.h"
@ -13,6 +14,9 @@ static void request_free_object(RequestType type, void *object) {
case REQUEST_TYPE_ADDRESS: case REQUEST_TYPE_ADDRESS:
address_free(object); address_free(object);
break; break;
case REQUEST_TYPE_BRIDGE_FDB:
bridge_fdb_free(object);
break;
case REQUEST_TYPE_NEIGHBOR: case REQUEST_TYPE_NEIGHBOR:
neighbor_free(object); neighbor_free(object);
break; break;
@ -119,6 +123,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
case REQUEST_TYPE_ADDRESS: case REQUEST_TYPE_ADDRESS:
r = request_process_address(req); r = request_process_address(req);
break; break;
case REQUEST_TYPE_BRIDGE_FDB:
r = request_process_bridge_fdb(req);
break;
case REQUEST_TYPE_NEIGHBOR: case REQUEST_TYPE_NEIGHBOR:
r = request_process_neighbor(req); r = request_process_neighbor(req);
break; break;

View File

@ -6,6 +6,7 @@
#include "networkd-link.h" #include "networkd-link.h"
typedef struct Address Address; typedef struct Address Address;
typedef struct BridgeFDB BridgeFDB;
typedef struct Neighbor Neighbor; typedef struct Neighbor Neighbor;
typedef struct NextHop NextHop; typedef struct NextHop NextHop;
typedef struct Route Route; typedef struct Route Route;
@ -18,6 +19,7 @@ typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType { typedef enum RequestType {
REQUEST_TYPE_ADDRESS, REQUEST_TYPE_ADDRESS,
REQUEST_TYPE_BRIDGE_FDB,
REQUEST_TYPE_NEIGHBOR, REQUEST_TYPE_NEIGHBOR,
REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_NEXTHOP,
REQUEST_TYPE_ROUTE, REQUEST_TYPE_ROUTE,
@ -32,6 +34,7 @@ typedef struct Request {
bool consume_object; bool consume_object;
union { union {
Address *address; Address *address;
BridgeFDB *fdb;
Neighbor *neighbor; Neighbor *neighbor;
NextHop *nexthop; NextHop *nexthop;
Route *route; Route *route;

View File

@ -58,6 +58,7 @@ MACAddress=
Destination= Destination=
VNI= VNI=
AssociatedWith= AssociatedWith=
OutgoingInterface=
[BridgeMDB] [BridgeMDB]
MulticastGroupAddress= MulticastGroupAddress=
VLANId= VLANId=

View File

@ -16,3 +16,4 @@ Destination=10.0.0.6
[BridgeFDB] [BridgeFDB]
MACAddress=00:11:22:33:44:77 MACAddress=00:11:22:33:44:77
Destination=10.0.0.7 Destination=10.0.0.7
OutgoingInterface=test1

View File

@ -1645,7 +1645,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent') self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent') self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent') self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent')
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env) output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env)
print(output) print(output)
@ -1653,9 +1653,6 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'Destination Port: 5555') self.assertRegex(output, 'Destination Port: 5555')
self.assertRegex(output, 'Underlying Device: test1') self.assertRegex(output, 'Underlying Device: test1')
output = check_output('ip -d link show vxlan98')
print(output)
def test_macsec(self): def test_macsec(self):
copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key', copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
'macsec.network', '12-dummy.netdev') 'macsec.network', '12-dummy.netdev')