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

Compare commits

...

58 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
f75420a43a man: explain ConditionNeedsUpdate a bit more
We were effectively doing all post-upgrade scripts twice in Fedora. We got this
wrong, so it's likely other people will get it wrong too. So let's explain
what is actually needed to make this work, but also when it's not useful.
2021-06-08 10:47:11 +02:00
Yu Watanabe
16e09d51a7 meson: do not share compiler flags except for emitting warnings
Follow-up for 65267363978dbb298eb4ba9b628d028c969fa616.

Prompted by https://github.com/systemd/systemd/issues/19191#issuecomment-856312107.
2021-06-08 10:44:34 +02:00
alexlzhu
9f40351f77
man: update docs on systemd-system.conf logging (LogTime=) (#19846)
Updating documentation for systemd to reflect that logging is done in the console.
2021-06-08 15:54:07 +09:00
Yu Watanabe
50b9fa01ed
Merge pull request #19639 from yuwata/network-next
network: bunch of fixes and new features
2021-06-08 10:29:54 +09:00
Yu Watanabe
a7f07cbe34 network: wait for all set-link requests are processed 2021-06-08 06:39:48 +09:00
Yu Watanabe
29836c166d network: drop trivial aliases of link_set_state() 2021-06-08 06:39:48 +09:00
Yu Watanabe
1187fc3375 network: use link_request_to_set_master() or friends 2021-06-08 06:39:48 +09:00
Yu Watanabe
112a0972a2 network: introduce link_request_to_activate()
The request will be processed after all setlink requests are processed.
The function will be used in later commits.
2021-06-08 06:39:48 +09:00
Yu Watanabe
0e397560cc network: it is not necessary to call RTM_GETLINK when carrier is gained 2021-06-08 06:39:48 +09:00
Yu Watanabe
440d40dcc0 network: set bridge or bond properties after master ifindex is set 2021-06-08 06:39:48 +09:00
Yu Watanabe
1362bd6c64 network: sync link information after set-link request is processed
Some properties do not notify their changes. See do_setlink() in
net/core/rtnetlink.c of kernel.
2021-06-08 06:39:48 +09:00
Yu Watanabe
5a1860f761 network: use link_call_getlink() where applicable 2021-06-08 06:39:48 +09:00
Yu Watanabe
79c6e11456 network: introduce link_call_getlink() 2021-06-08 06:39:48 +09:00
Yu Watanabe
0d411b7f8f network: split link_update() into small pieces 2021-06-08 06:39:26 +09:00
Yu Watanabe
852a391605 network: shorten code a bit, and reduce indentation 2021-06-08 06:35:49 +09:00
Yu Watanabe
b156a95d4a network: update operational state or friends on reconfigure 2021-06-08 06:35:49 +09:00
Yu Watanabe
4b9a8c2b51 network: make link enter failed state when link_initialized() is failed 2021-06-08 06:35:49 +09:00
Yu Watanabe
0c9ee5d5e8 network: move functions
This changes no behavior. Preparation for later commits.
2021-06-08 06:35:49 +09:00
Yu Watanabe
813572853e network: introduce link_get_master() and use it where applicable 2021-06-08 06:35:49 +09:00
Yu Watanabe
8252fb4439 network: introduce link_request_to_set_bridge_vlan()
This will be used in later commits.
2021-06-08 06:35:45 +09:00
Yu Watanabe
bfd7fb09cf sd-netlink: add IFLA_BRIDGE_FLAGS and IFLA_BRIDGE_VLAN_INFO attributes 2021-06-08 06:34:41 +09:00
Yu Watanabe
5106ad00e6 network: expose bridge_vlan_append_info() 2021-06-08 06:34:38 +09:00
Yu Watanabe
5546870e7b network: introduce network_adjust_bridge_vlan() 2021-06-08 06:33:27 +09:00
Yu Watanabe
1a0e5ca2f3 network: rebreak arguments 2021-06-08 06:33:27 +09:00
Yu Watanabe
9670e45a6e network: rename networkd-brvlan.[ch] -> networkd-bridge-vlan.[ch] 2021-06-08 06:33:27 +09:00
Yu Watanabe
5062b8593a network: introduce link_request_to_set_bond()
This will be used in later commits.
2021-06-08 06:33:27 +09:00
Yu Watanabe
7d5b232f40 network: introduce link_request_to_set_bridge()
This will be used in later commits.
2021-06-08 06:33:27 +09:00
Yu Watanabe
71a754f70f network: introduce link_request_to_create_stacked_netdev()
This will be used in later commits.
2021-06-08 06:33:27 +09:00
Yu Watanabe
d24bf1b514 network: introduce link_request_to_set_master()
The function will be used later.
2021-06-08 06:33:27 +09:00
Yu Watanabe
8e00e24cc9 network: use request queue to set IPv6LL address generation mode 2021-06-08 06:33:27 +09:00
Yu Watanabe
cc4c8fb136 network: use request queue to set interface group 2021-06-08 06:33:27 +09:00
Yu Watanabe
a8e5e27c9f network: use request queue to set MAC address 2021-06-08 06:33:27 +09:00
Yu Watanabe
93fabc10fa network: use request queue to set link flags 2021-06-08 06:33:27 +09:00
Yu Watanabe
0fa8ee6c77 network: use request queue to set MTU 2021-06-08 06:33:27 +09:00
Yu Watanabe
fa28381202 network: merge link_configure() and link_configure_continue() again
It is not necessary to stop whole configuration process until MTU and
IPv6LL address generation mode are set. But it is enough just setting
IPv6 MTU again after MTU is set, and dropping IPv6LL address after
setting the address generation mode.
2021-06-08 06:33:27 +09:00
Yu Watanabe
793117b3fd network: drop meaningless condition about setting MTU
The condition does not fix infinite loop of interface reset, as the
interface is reset after netlink reply is received, thus setting_mtu is
false.

See also #18738.
2021-06-08 06:33:27 +09:00
Yu Watanabe
b9bf3f22a8 network: introduces link_drop_ipv6ll_addresses()
It is not necessary to parse whole message and store the address in
Link::addresses_foreign, as the address will be removed soon later.
2021-06-08 06:33:27 +09:00
Yu Watanabe
f0269653e9 network: make link enter failed state on failure in link_update() and link_reset_carrier()
Previously, several failures in link_carrier_gained() make link enter
failed state, and other errors are ignored. Now, all failures in
link_carrier_gained(), moreover, link_update() are critical.
2021-06-08 06:33:27 +09:00
Yu Watanabe
8566df791e network: rename link_acquire_conf() -> link_acquire_dynamic_conf()
To clarify it starts dynamic configuration engines e.g. DHCP clients.
2021-06-08 06:33:27 +09:00
Yu Watanabe
9710895378 network: request to configure static settings earlier
Now, all static configs should be ordered after the link gains its carrier.
So, it is not necessary to wait for that before queuing requests.
2021-06-08 06:33:27 +09:00
Yu Watanabe
40b12fa20d network: introduce request_hash_ops to dedup requests
If KeepConfiguration= or ConfigureWithoutCarrier= is set, then the same
requests may be queued.
2021-06-08 06:33:27 +09:00
Yu Watanabe
5f33159190 network: expose hash and compare functions 2021-06-08 06:33:27 +09:00
Yu Watanabe
fdeba3f5cc network: use request queue to configure IPv6 proxy NDP addresses 2021-06-08 06:33:27 +09:00
Yu Watanabe
d8350b60e0 network: move logic for setting proxy_ndp sysctl to networkd-sysctl.c 2021-06-08 06:33:27 +09:00
Yu Watanabe
14d9ab9d32 network: introduce network_adjust_ipv6_proxy_ndp() 2021-06-08 06:33:27 +09:00
Yu Watanabe
354bc760cd network: address label: use request queue to configure address labels 2021-06-08 06:33:27 +09:00
Yu Watanabe
4c0c8d1e72 network: address label: use struct in6_addr instead
Address label is for IPv6.
2021-06-08 06:33:27 +09:00
Yu Watanabe
2551b422e1 network: address label: refuse IPv4 mapped address with large prefix length
See ip6addrlbl_alloc() in net/ipv6/addrlabel.c of kernel.
2021-06-08 06:33:27 +09:00
Yu Watanabe
c3e960883f in-addr-util: introduce in6_addr_is_ipv4_mapped_address() 2021-06-08 06:33:27 +09:00
Yu Watanabe
9a038aaced network: use request queue to configure bridge MDB 2021-06-08 06:33:27 +09:00
Yu Watanabe
ff9e07838d network: rename MdbEntry -> BridgeMDB 2021-06-08 06:33:27 +09:00
Yu Watanabe
9373f5a812 test-network: fix setting name
This fixes an issue introduced by 72ffb9133d686bef6d9d79e9d2899571651d5c1b.
2021-06-08 06:33:27 +09:00
Yu Watanabe
4e0006cc4b test-network: add a testcase for UplinkInterface= for DHCP server 2021-06-08 06:33:27 +09:00
Yu Watanabe
165d7c5c42 network: introduce UplinkInterface= setting for DHCP server 2021-06-08 06:33:27 +09:00
Yu Watanabe
fb3aec45a0 network: make manager_find_uplink() uses stored route information
networkd already has all information about routes. It is not necessary
to re-read them by using local_gateways().

This also makes manager_find_uplink() take family.
2021-06-08 06:33:27 +09:00
Yu Watanabe
ab486ef4eb network: restart DHCP server on carrier gain 2021-06-08 06:33:27 +09:00
Yu Watanabe
b27e5d53f3 sd-dhcp-server: make sd_dhcp_server_start() no-op if it is already running 2021-06-08 06:33:27 +09:00
Yu Watanabe
1d28a3cf6c network: use request queue to configure DHCP server 2021-06-08 06:33:27 +09:00
60 changed files with 2970 additions and 2517 deletions

View File

@ -35,7 +35,7 @@
<varlistentry id='log-time'>
<term><varname>$SYSTEMD_LOG_TIME</varname></term>
<listitem><para id='log-time-body'>A boolean. If true, log messages will be prefixed with a
<listitem><para id='log-time-body'>A boolean. If true, console log messages will be prefixed with a
timestamp.</para>
<para>This setting is only useful when messages are written directly to the terminal or a file, because

View File

@ -2405,6 +2405,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
network traffic.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>UplinkInterface=</varname></term>
<listitem><para>Specifies name or index of uplink interface, or one of the special values
<literal>:none</literal> and <literal>:auto</literal>. When emitting DNS, NTP, or SIP servers
are enabled but no servers are specified, the servers configured in the uplink interface will
be emitted. When <literal>:auto</literal>, the link which has default gateway with higher
priority will be automatically selected. When <literal>:none</literal>, no uplink interface
will be selected. Defaults to <literal>:auto</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>EmitDNS=</varname></term>
<term><varname>DNS=</varname></term>

View File

@ -1374,11 +1374,23 @@
<para>If the <varname>systemd.condition-needs-update=</varname> option is specified on the kernel
command line (taking a boolean), it will override the result of this condition check, taking
precedence over any file modification time checks. If it is used
precedence over any file modification time checks. If the kernel command line option is used,
<filename>systemd-update-done.service</filename> will not have immediate effect on any following
<varname>ConditionNeedsUpdate=</varname> checks, until the system is rebooted where the kernel
command line option is not specified anymore.</para>
</listitem>
<para>Note that to make this scheme effective, the timestamp of <filename>/usr/</filename> should
be explicitly updated after its contents are modified. The kernel will automatically update
modification timestamp on a directory only when immediate children of a directory are modified; an
modification of nested files will not automatically result in mtime of <filename>/usr/</filename>
being updated.</para>
<para>Also note that if the update method includes a call to execute appropriate post-update steps
itself, it should not touch the timestamp of <filename>/usr/</filename>. In a typical distribution
packaging scheme, packages will do any required update steps as part of the installation or
upgrade, to make package contents immediately usable. <varname>ConditionNeedsUpdate=</varname>
should be used with other update mechanisms where such an immediate update does not
happen.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -1184,7 +1184,7 @@
<varlistentry>
<term><option>--log-time=</option></term>
<listitem><para>Prefix messages with timestamp. See <varname>systemd.log_time</varname> above.
<listitem><para>Prefix console messages with timestamp. See <varname>systemd.log_time</varname> above.
</para></listitem>
</varlistentry>

View File

@ -355,13 +355,6 @@ possible_common_cc_flags = [
# negative arguments are correctly detected starting with meson 0.46.
'-Wno-error=#warnings', # clang
'-Wno-string-plus-int', # clang
'-ffast-math',
'-fno-common',
'-fdiagnostics-show-option',
'-fno-strict-aliasing',
'-fvisibility=hidden',
'--param=ssp-buffer-size=4',
]
# Disable -Wmaybe-unitialized when compiling with -Os/-O1/-O3/etc. There are
@ -388,8 +381,21 @@ if cc.get_id() == 'clang'
]
endif
possible_cc_flags = possible_common_cc_flags + [
'-Werror=missing-declarations',
'-Werror=missing-prototypes',
'-fdiagnostics-show-option',
'-ffast-math',
'-fno-common',
'-fno-strict-aliasing',
'-fstack-protector',
'-fstack-protector-strong',
'-fvisibility=hidden',
'--param=ssp-buffer-size=4',
]
if get_option('buildtype') != 'debug'
possible_common_cc_flags += [
possible_cc_flags += [
'-ffunction-sections',
'-fdata-sections',
]
@ -397,13 +403,6 @@ if get_option('buildtype') != 'debug'
possible_link_flags += '-Wl,--gc-sections'
endif
possible_cc_flags = possible_common_cc_flags + [
'-Werror=missing-declarations',
'-Werror=missing-prototypes',
'-fstack-protector',
'-fstack-protector-strong',
]
add_project_arguments(cc.get_supported_arguments(basic_disabled_warnings), language : 'c')
add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language : 'c')

View File

@ -121,6 +121,12 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
return -EAFNOSUPPORT;
}
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
return a->s6_addr32[0] == 0 &&
a->s6_addr32[1] == 0 &&
a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
}
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
assert(a);
assert(b);

View File

@ -58,6 +58,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u);
bool in4_addr_is_local_multicast(const struct in_addr *a);
bool in4_addr_is_non_local(const struct in_addr *a);
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a);
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);

View File

@ -180,6 +180,7 @@ if have_gnu_efi
possible_common_cc_flags + [
'-ffreestanding',
'-fno-stack-protector',
'-fno-strict-aliasing',
'-fpic',
'-fshort-wchar',
'-Wall',

View File

@ -1202,6 +1202,10 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
assert_return(server, -EINVAL);
assert_return(server->event, -EINVAL);
if (sd_dhcp_server_is_running(server))
return 0;
assert_return(!server->receive_message, -EBUSY);
assert_return(server->fd_raw < 0, -EBUSY);
assert_return(server->fd < 0, -EBUSY);

View File

@ -61,7 +61,7 @@ static int test_basic(sd_event *event, bool bind_to_interface) {
return log_info_errno(r, "sd_dhcp_server_start failed: %m");
assert_se(r >= 0);
assert_se(sd_dhcp_server_start(server) == -EBUSY);
assert_se(sd_dhcp_server_start(server) >= 0);
assert_se(sd_dhcp_server_stop(server) >= 0);
assert_se(sd_dhcp_server_stop(server) >= 0);
assert_se(sd_dhcp_server_start(server) >= 0);

View File

@ -374,6 +374,7 @@ static const NLType rtnl_link_info_data_bareudp_types[] = {
[IFLA_BAREUDP_SRCPORT_MIN] = { .type = NETLINK_TYPE_U16 },
[IFLA_BAREUDP_MULTIPROTO_MODE] = { .type = NETLINK_TYPE_FLAG },
};
/* these strings must match the .kind entries in the kernel */
static const char* const nl_union_link_info_data_table[] = {
[NL_UNION_LINK_INFO_DATA_BOND] = "bond",
@ -559,13 +560,26 @@ static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
.types = rtnl_af_spec_inet6_types,
};
static const NLType rtnl_af_spec_types[] = {
static const NLType rtnl_af_spec_unspec_types[] = {
[AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
};
static const NLTypeSystem rtnl_af_spec_type_system = {
.count = ELEMENTSOF(rtnl_af_spec_types),
.types = rtnl_af_spec_types,
static const NLType rtnl_af_spec_bridge_types[] = {
[IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRIDGE_VLAN_INFO] = { .size = sizeof(struct bridge_vlan_info) },
};
static const NLTypeSystem rtnl_af_spec_type_systems[] = {
[AF_UNSPEC] = { .count = ELEMENTSOF(rtnl_af_spec_unspec_types),
.types = rtnl_af_spec_unspec_types },
[AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_af_spec_bridge_types),
.types = rtnl_af_spec_bridge_types },
};
static const NLTypeSystemUnion rtnl_af_spec_type_system_union = {
.num = AF_MAX,
.type_systems = rtnl_af_spec_type_systems,
.match_type = NL_MATCH_PROTOCOL,
};
static const NLType rtnl_prop_list_types[] = {
@ -648,11 +662,10 @@ static const NLType rtnl_link_types[] = {
[IFLA_VF_PORTS] = { .type = NETLINK_TYPE_NESTED },
[IFLA_PORT_SELF] = { .type = NETLINK_TYPE_NESTED },
*/
[IFLA_AF_SPEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_type_system },
[IFLA_AF_SPEC] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_af_spec_type_system_union },
/*
[IFLA_VF_PORTS],
[IFLA_PORT_SELF],
[IFLA_AF_SPEC],
*/
[IFLA_GROUP] = { .type = NETLINK_TYPE_U32 },
[IFLA_NET_NS_FD] = { .type = NETLINK_TYPE_U32 },

View File

@ -59,8 +59,10 @@ sources = files('''
networkd-address.h
networkd-bridge-fdb.c
networkd-bridge-fdb.h
networkd-brvlan.c
networkd-brvlan.h
networkd-bridge-mdb.c
networkd-bridge-mdb.h
networkd-bridge-vlan.c
networkd-bridge-vlan.h
networkd-can.c
networkd-can.h
networkd-conf.c
@ -95,8 +97,6 @@ sources = files('''
networkd-manager-bus.h
networkd-manager.c
networkd-manager.h
networkd-mdb.c
networkd-mdb.h
networkd-ndisc.c
networkd-ndisc.h
networkd-neighbor.c
@ -115,6 +115,8 @@ sources = files('''
networkd-route.h
networkd-routing-policy-rule.c
networkd-routing-policy-rule.h
networkd-setlink.c
networkd-setlink.h
networkd-speed-meter.c
networkd-speed-meter.h
networkd-sriov.c

View File

@ -222,78 +222,6 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
return 0;
}
static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->ifname);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set bonding interface: %m");
return 1;
}
return 1;
}
int link_set_bond(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->network);
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->network->bond->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
if (r < 0)
return log_link_error_errno(link, r, "Could not set netlink flags: %m");
r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond");
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
if (link->network->active_slave) {
r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BOND_ACTIVE_SLAVE attribute: %m");
}
if (link->network->primary_slave) {
r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BOND_PRIMARY attribute: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return r;
}
int config_parse_arp_ip_target_address(
const char *unit,
const char *filename,

View File

@ -46,8 +46,6 @@ typedef struct Bond {
DEFINE_NETDEV_CAST(BOND, Bond);
extern const NetDevVTable bond_vtable;
int link_set_bond(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_xmit_hash_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_lacp_rate);

View File

@ -161,142 +161,6 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return r;
}
static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->ifname);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set bridge interface: %m");
return 1;
}
return 1;
}
int link_set_bridge(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->network);
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
if (r < 0)
return log_link_error_errno(link, r, "Could not set message family: %m");
r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
if (link->network->use_bpdu >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
}
if (link->network->hairpin >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
}
if (link->network->fast_leave >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
}
if (link->network->allow_port_to_be_root >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
}
if (link->network->unicast_flood >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
}
if (link->network->multicast_flood >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m");
}
if (link->network->multicast_to_unicast >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
}
if (link->network->neighbor_suppression >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m");
}
if (link->network->learning >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m");
}
if (link->network->bridge_proxy_arp >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP, link->network->bridge_proxy_arp);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP attribute: %m");
}
if (link->network->bridge_proxy_arp_wifi >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP_WIFI, link->network->bridge_proxy_arp_wifi);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP_WIFI attribute: %m");
}
if (link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
}
if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PRIORITY attribute: %m");
}
if (link->network->multicast_router != _MULTICAST_ROUTER_INVALID) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MULTICAST_ROUTER, link->network->multicast_router);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MULTICAST_ROUTER attribute: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bridge_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return r;
}
int config_parse_bridge_igmp_version(
const char *unit,
const char *filename,

View File

@ -41,8 +41,6 @@ typedef enum MulticastRouter {
DEFINE_NETDEV_CAST(BRIDGE, Bridge);
extern const NetDevVTable bridge_vtable;
int link_set_bridge(Link *link);
const char* multicast_router_to_string(MulticastRouter i) _const_;
MulticastRouter multicast_router_from_string(const char *s) _pure_;

View File

@ -25,6 +25,7 @@
#include "netdevsim.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "nlmon.h"
#include "path-lookup.h"
#include "siphash24.h"
@ -158,19 +159,6 @@ int config_parse_netdev_kind(
return 0;
}
static void netdev_callbacks_clear(NetDev *netdev) {
netdev_join_callback *callback;
if (!netdev)
return;
while ((callback = netdev->callbacks)) {
LIST_REMOVE(callbacks, netdev->callbacks, callback);
link_unref(callback->link);
free(callback);
}
}
bool netdev_is_managed(NetDev *netdev) {
if (!netdev || !netdev->manager || !netdev->ifname)
return false;
@ -186,8 +174,6 @@ static void netdev_detach_from_manager(NetDev *netdev) {
static NetDev *netdev_free(NetDev *netdev) {
assert(netdev);
netdev_callbacks_clear(netdev);
netdev_detach_from_manager(netdev);
free(netdev->filename);
@ -222,12 +208,8 @@ void netdev_drop(NetDev *netdev) {
log_netdev_debug(netdev, "netdev removed");
netdev_callbacks_clear(netdev);
netdev_detach_from_manager(netdev);
netdev_unref(netdev);
return;
}
@ -251,55 +233,10 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret) {
static int netdev_enter_failed(NetDev *netdev) {
netdev->state = NETDEV_STATE_FAILED;
netdev_callbacks_clear(netdev);
return 0;
}
static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(netdev);
assert(netdev->state == NETDEV_STATE_READY);
assert(netdev->manager);
assert(netdev->manager->rtnl);
assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF, NETDEV_KIND_BATADV));
assert(link);
assert(callback);
if (link->flags & IFF_UP && netdev->kind == NETDEV_KIND_BOND) {
log_netdev_debug(netdev, "Link '%s' was up when attempting to enslave it. Bringing link down.", link->ifname);
r = link_down(link, NULL);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not bring link down: %m");
}
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
r = netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
link_ref(link);
log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
return 0;
}
static int netdev_enter_ready(NetDev *netdev) {
netdev_join_callback *callback, *callback_next;
int r;
assert(netdev);
assert(netdev->ifname);
@ -310,18 +247,6 @@ static int netdev_enter_ready(NetDev *netdev) {
log_netdev_info(netdev, "netdev ready");
LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
/* enslave the links that were attempted to be enslaved before the
* link was ready */
r = netdev_enslave_ready(netdev, callback->link, callback->callback);
if (r < 0)
return r;
LIST_REMOVE(callbacks, netdev->callbacks, callback);
link_unref(callback->link);
free(callback);
}
if (NETDEV_VTABLE(netdev)->post_create)
NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
@ -350,45 +275,6 @@ static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev
return 1;
}
static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
int r;
assert(netdev);
assert(netdev->manager);
assert(netdev->manager->rtnl);
assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF, NETDEV_KIND_BATADV));
if (netdev->state == NETDEV_STATE_READY) {
r = netdev_enslave_ready(netdev, link, callback);
if (r < 0)
return r;
} else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
if (r >= 0)
callback(netdev->manager->rtnl, m, link);
} else {
/* the netdev is not yet ready, save this request for when it is */
netdev_join_callback *cb;
cb = new(netdev_join_callback, 1);
if (!cb)
return log_oom();
*cb = (netdev_join_callback) {
.callback = callback,
.link = link_ref(link),
};
LIST_PREPEND(callbacks, netdev->callbacks, cb);
log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
}
return 0;
}
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
uint16_t type;
const char *kind;
@ -621,7 +507,6 @@ static int netdev_create_after_configured(NetDev *netdev, Link *link) {
return NETDEV_VTABLE(netdev)->create_after_configured(netdev, link);
}
/* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
int r;
@ -630,12 +515,6 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
assert(netdev->manager->rtnl);
switch (netdev_get_create_type(netdev)) {
case NETDEV_CREATE_MASTER:
r = netdev_enslave(netdev, link, callback);
if (r < 0)
return r;
break;
case NETDEV_CREATE_STACKED:
r = netdev_create(netdev, link, callback);
if (r < 0)
@ -654,6 +533,140 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
return 0;
}
static bool netdev_is_ready_to_create(NetDev *netdev, Link *link) {
Request req;
assert(netdev);
assert(link);
if (netdev->state != NETDEV_STATE_LOADING)
return false;
if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
link->state != LINK_STATE_CONFIGURED)
return false;
req = (Request) {
.link = link,
.type = REQUEST_TYPE_SET_LINK,
.set_link_operation = SET_LINK_MTU,
};
if (ordered_set_contains(link->manager->request_queue, &req))
return false;
return true;
}
int request_process_create_stacked_netdev(Request *req) {
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_CREATE_STACKED_NETDEV);
assert(req->netdev);
assert(req->netlink_handler);
if (!netdev_is_ready_to_create(req->netdev, req->link))
return 0;
r = netdev_join(req->netdev, req->link, req->netlink_handler);
if (r < 0)
return log_link_error_errno(req->link, r, "Failed to create stacked netdev '%s': %m", req->netdev->ifname);
return 1;
}
static int link_create_stacked_netdev_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not create stacked netdev");
link_enter_failed(link);
return 0;
}
return 1;
}
static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
assert(link);
assert(link->create_stacked_netdev_messages > 0);
link->create_stacked_netdev_messages--;
if (link_create_stacked_netdev_handler_internal(rtnl, m, link) <= 0)
return 0;
if (link->create_stacked_netdev_messages == 0) {
link->stacked_netdevs_created = true;
log_link_debug(link, "Stacked netdevs created.");
}
return 0;
}
static int link_create_stacked_netdev_after_configured_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
assert(link);
assert(link->create_stacked_netdev_after_configured_messages > 0);
link->create_stacked_netdev_after_configured_messages--;
if (link_create_stacked_netdev_handler_internal(rtnl, m, link) <= 0)
return 0;
if (link->create_stacked_netdev_after_configured_messages == 0) {
link->stacked_netdevs_after_configured_created = true;
log_link_debug(link, "Stacked netdevs created.");
}
return 0;
}
int link_request_to_crate_stacked_netdev(Link *link, NetDev *netdev) {
NetDevCreateType create_type;
int r;
assert(link);
assert(netdev);
create_type = netdev_get_create_type(netdev);
if (!IN_SET(create_type, NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED))
return -EINVAL;
if (netdev->state != NETDEV_STATE_LOADING || netdev->ifindex > 0)
/* Already created (or removed?) */
return 0;
if (create_type == NETDEV_CREATE_STACKED) {
link->stacked_netdevs_created = false;
r = link_queue_request(link, REQUEST_TYPE_CREATE_STACKED_NETDEV, netdev, false,
&link->create_stacked_netdev_messages,
link_create_stacked_netdev_handler,
NULL);
} else {
link->stacked_netdevs_after_configured_created = false;
r = link_queue_request(link, REQUEST_TYPE_CREATE_STACKED_NETDEV, netdev, false,
&link->create_stacked_netdev_after_configured_messages,
link_create_stacked_netdev_after_configured_handler,
NULL);
}
if (r < 0)
return log_link_error_errno(link, r, "Failed to request to create stacked netdev '%s': %m",
netdev->ifname);
log_link_debug(link, "Requested to create stacked netdev '%s'", netdev->ifname);
return 0;
}
int netdev_load_one(Manager *manager, const char *filename) {
_cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
const char *dropin_dirname;
@ -770,8 +783,6 @@ int netdev_load_one(Manager *manager, const char *filename) {
if (r < 0)
return r;
LIST_HEAD_INIT(netdev->callbacks);
log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {

View File

@ -40,15 +40,6 @@
"-WireGuardPeer\0" \
"-Xfrm\0"
typedef struct netdev_join_callback netdev_join_callback;
struct netdev_join_callback {
link_netlink_message_handler_t callback;
Link *link;
LIST_FIELDS(netdev_join_callback, callbacks);
};
typedef enum NetDevKind {
NETDEV_KIND_BRIDGE,
NETDEV_KIND_BOND,
@ -112,6 +103,7 @@ typedef enum NetDevCreateType {
typedef struct Manager Manager;
typedef struct Condition Condition;
typedef struct Request Request;
typedef struct NetDev {
Manager *manager;
@ -129,8 +121,6 @@ typedef struct NetDev {
struct ether_addr *mac;
uint32_t mtu;
int ifindex;
LIST_HEAD(netdev_join_callback, callbacks);
} NetDev;
typedef struct NetDevVTable {
@ -205,7 +195,9 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret);
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
int netdev_get_mac(const char *ifname, struct ether_addr **ret);
int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
int netdev_join_after_configured(NetDev *netdev, Link *link, link_netlink_message_handler_t callback);
int request_process_create_stacked_netdev(Request *req);
int link_request_to_crate_stacked_netdev(Link *link, NetDev *netdev);
const char *netdev_kind_to_string(NetDevKind d) _const_;
NetDevKind netdev_kind_from_string(const char *d) _pure_;

View File

@ -9,6 +9,7 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "parse-util.h"
AddressLabel *address_label_free(AddressLabel *label) {
@ -63,16 +64,16 @@ static int address_label_new_static(Network *network, const char *filename, unsi
return 0;
}
static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int address_label_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->address_label_messages > 0);
assert(link->static_address_label_messages > 0);
link->address_label_messages--;
link->static_address_label_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@ -84,13 +85,16 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
if (link->address_label_messages == 0)
if (link->static_address_label_messages == 0) {
log_link_debug(link, "Addresses label set");
link->static_address_labels_configured = true;
link_check_ready(link);
}
return 1;
}
static int address_label_configure(AddressLabel *label, Link *link) {
static int address_label_configure(AddressLabel *label, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -99,6 +103,7 @@ static int address_label_configure(AddressLabel *label, Link *link) {
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
assert(callback);
r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
link->ifindex, AF_INET6);
@ -113,39 +118,59 @@ static int address_label_configure(AddressLabel *label, Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFAL_LABEL attribute: %m");
r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6);
r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req,
address_label_handler,
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
return 1;
}
int link_set_address_labels(Link *link) {
int link_request_static_address_labels(Link *link) {
AddressLabel *label;
int r;
assert(link);
assert(link->network);
HASHMAP_FOREACH(label, link->network->address_labels_by_section) {
r = address_label_configure(label, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set address label: %m");
link->static_address_labels_configured = false;
link->address_label_messages++;
HASHMAP_FOREACH(label, link->network->address_labels_by_section) {
r = link_queue_request(link, REQUEST_TYPE_ADDRESS_LABEL, label, false,
&link->static_address_label_messages, address_label_configure_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request address label: %m");
}
if (link->static_address_label_messages == 0) {
link->static_address_labels_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting address labels.");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
int request_process_address_label(Request *req) {
assert(req);
assert(req->link);
assert(req->label);
assert(req->type == REQUEST_TYPE_ADDRESS_LABEL);
if (!link_is_ready_to_configure(req->link, false))
return 0;
return address_label_configure(req->label, req->link, req->netlink_handler);
}
void network_drop_invalid_address_labels(Network *network) {
AddressLabel *label;
@ -156,19 +181,22 @@ void network_drop_invalid_address_labels(Network *network) {
address_label_free(label);
}
int config_parse_address_label_prefix(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) {
int config_parse_address_label_prefix(
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_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
Network *network = userdata;
unsigned char prefixlen;
union in_addr_union a;
int r;
assert(filename);
@ -181,11 +209,22 @@ int config_parse_address_label_prefix(const char *unit,
if (r < 0)
return log_oom();
r = in_addr_prefix_from_string(rvalue, AF_INET6, &n->in_addr, &n->prefixlen);
r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Address label is invalid, ignoring assignment: %s", rvalue);
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid prefix for address label, ignoring assignment: %s", rvalue);
return 0;
}
if (in6_addr_is_ipv4_mapped_address(&a.in6) && prefixlen > 96) {
/* See ip6addrlbl_alloc() in net/ipv6/addrlabel.c of kernel. */
log_syntax(unit, LOG_WARNING, filename, line, 0,
"The prefix length of IPv4 mapped address for address label must be equal to or smaller than 96, "
"ignoring assignment: %s", rvalue);
return 0;
}
n->in_addr = a.in6;
n->prefixlen = prefixlen;
TAKE_PTR(n);
return 0;

View File

@ -7,8 +7,9 @@
#include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef struct AddressLabel {
Network *network;
@ -16,14 +17,15 @@ typedef struct AddressLabel {
unsigned char prefixlen;
uint32_t label;
union in_addr_union in_addr;
struct in6_addr in_addr;
} AddressLabel;
AddressLabel *address_label_free(AddressLabel *label);
void network_drop_invalid_address_labels(Network *network);
int link_set_address_labels(Link *link);
int link_request_static_address_labels(Link *link);
int request_process_address_label(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_address_label);
CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix);

View File

@ -784,7 +784,7 @@ bool link_address_is_dynamic(const Link *link, const Address *address) {
return false;
}
static int link_enumerate_ipv6_tentative_addresses(Link *link) {
int link_drop_ipv6ll_addresses(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
int r;
@ -792,6 +792,12 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) {
assert(link->manager);
assert(link->manager->rtnl);
/* IPv6LL address may be in the tentative state, and in that case networkd has not received it.
* So, we need to dump all IPv6 addresses. */
if (link_ipv6ll_enabled(link))
return 0;
r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, link->ifindex, AF_INET6);
if (r < 0)
return r;
@ -805,27 +811,57 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) {
return r;
for (sd_netlink_message *addr = reply; addr; addr = sd_netlink_message_next(addr)) {
unsigned char flags;
_cleanup_(address_freep) Address *a = NULL;
unsigned char flags, prefixlen;
struct in6_addr address;
int ifindex;
/* NETLINK_GET_STRICT_CHK socket option is supported since kernel 4.20. To support
* older kernels, we need to check ifindex here. */
r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address message without valid ifindex, ignoring: %m");
log_link_debug_errno(link, r, "rtnl: received address message without valid ifindex, ignoring: %m");
continue;
} else if (link->ifindex != ifindex)
continue;
r = sd_rtnl_message_addr_get_flags(addr, &flags);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received address message without valid flags, ignoring: %m");
log_link_debug_errno(link, r, "rtnl: received address message without valid flags, ignoring: %m");
continue;
} else if (!(flags & IFA_F_TENTATIVE))
}
r = sd_rtnl_message_addr_get_prefixlen(addr, &prefixlen);
if (r < 0) {
log_link_debug_errno(link, r, "rtnl: received address message without prefixlen, ignoring: %m");
continue;
}
if (sd_netlink_message_read_in6_addr(addr, IFA_LOCAL, NULL) >= 0)
/* address with peer, ignoring. */
continue;
log_link_debug(link, "Found tentative ipv6 link-local address");
(void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager);
r = sd_netlink_message_read_in6_addr(addr, IFA_ADDRESS, &address);
if (r < 0) {
log_link_debug_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
continue;
}
if (!in6_addr_is_link_local(&address))
continue;
r = address_new(&a);
if (r < 0)
return -ENOMEM;
a->family = AF_INET6;
a->in_addr.in6 = address;
a->prefixlen = prefixlen;
a->flags = flags;
r = address_remove(a, link);
if (r < 0)
return r;
}
return 0;
@ -837,17 +873,9 @@ int link_drop_foreign_addresses(Link *link) {
assert(link);
/* The kernel doesn't notify us about tentative addresses;
* so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */
if (!link_ipv6ll_enabled(link)) {
r = link_enumerate_ipv6_tentative_addresses(link);
if (r < 0)
return r;
}
SET_FOREACH(address, link->addresses_foreign) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1 && link_ipv6ll_enabled(link))
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1)
continue;
if (link_address_is_dynamic(link, address)) {
@ -1091,10 +1119,6 @@ static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
log_link_debug(link, "Addresses set");
link->static_addresses_configured = true;
link_check_ready(link);
r = dhcp4_server_configure(link);
if (r < 0)
link_enter_failed(link);
}
return 1;
@ -1152,6 +1176,8 @@ int link_request_static_addresses(Link *link) {
static_address_handler, &req);
if (r < 0)
return r;
if (r == 0)
continue;
req->after_configure = static_address_after_configure;
}
@ -1182,6 +1208,8 @@ int link_request_static_addresses(Link *link) {
static_address_handler, &req);
if (r < 0)
return r;
if (r == 0)
continue;
req->after_configure = static_address_after_configure;
}
@ -1207,8 +1235,8 @@ int link_request_static_addresses(Link *link) {
static_address_handler, &req);
if (r < 0)
return r;
req->after_configure = static_address_after_configure;
if (r > 0)
req->after_configure = static_address_after_configure;
}
}

View File

@ -64,6 +64,7 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
int link_drop_ipv6ll_addresses(Link *link);
bool link_address_is_dynamic(const Link *link, const Address *address);
int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret);
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);

View File

@ -3,41 +3,42 @@
#include <net/if.h>
#include "netlink-util.h"
#include "networkd-bridge-mdb.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-mdb.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "string-util.h"
#include "vlan-util.h"
#define STATIC_MDB_ENTRIES_PER_NETWORK_MAX 1024U
#define STATIC_BRIDGE_MDB_ENTRIES_PER_NETWORK_MAX 1024U
/* remove MDB entry. */
MdbEntry *mdb_entry_free(MdbEntry *mdb_entry) {
if (!mdb_entry)
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
if (!mdb)
return NULL;
if (mdb_entry->network) {
assert(mdb_entry->section);
hashmap_remove(mdb_entry->network->mdb_entries_by_section, mdb_entry->section);
if (mdb->network) {
assert(mdb->section);
hashmap_remove(mdb->network->bridge_mdb_entries_by_section, mdb->section);
}
network_config_section_free(mdb_entry->section);
network_config_section_free(mdb->section);
return mfree(mdb_entry);
return mfree(mdb);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeMDB, bridge_mdb_free);
/* create a new MDB entry or get an existing one. */
static int mdb_entry_new_static(
static int bridge_mdb_new_static(
Network *network,
const char *filename,
unsigned section_line,
MdbEntry **ret) {
BridgeMDB **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(mdb_entry_freep) MdbEntry *mdb_entry = NULL;
_cleanup_(bridge_mdb_freep) BridgeMDB *mdb = NULL;
int r;
assert(network);
@ -50,42 +51,42 @@ static int mdb_entry_new_static(
return r;
/* search entry in hashmap first. */
mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
if (mdb_entry) {
*ret = TAKE_PTR(mdb_entry);
mdb = hashmap_get(network->bridge_mdb_entries_by_section, n);
if (mdb) {
*ret = TAKE_PTR(mdb);
return 0;
}
if (hashmap_size(network->mdb_entries_by_section) >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
if (hashmap_size(network->bridge_mdb_entries_by_section) >= STATIC_BRIDGE_MDB_ENTRIES_PER_NETWORK_MAX)
return -E2BIG;
/* allocate space for an MDB entry. */
mdb_entry = new(MdbEntry, 1);
if (!mdb_entry)
mdb = new(BridgeMDB, 1);
if (!mdb)
return -ENOMEM;
/* init MDB structure. */
*mdb_entry = (MdbEntry) {
*mdb = (BridgeMDB) {
.network = network,
.section = TAKE_PTR(n),
};
r = hashmap_ensure_put(&network->mdb_entries_by_section, &network_config_hash_ops, mdb_entry->section, mdb_entry);
r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &network_config_hash_ops, mdb->section, mdb);
if (r < 0)
return r;
/* return allocated MDB structure. */
*ret = TAKE_PTR(mdb_entry);
*ret = TAKE_PTR(mdb);
return 0;
}
static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->bridge_mdb_messages > 0);
assert(link->static_bridge_mdb_messages > 0);
link->bridge_mdb_messages--;
link->static_bridge_mdb_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@ -94,7 +95,7 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
if (r == -EINVAL && streq_ptr(link->kind, "bridge") && (!link->network || !link->network->bridge)) {
/* To configure bridge MDB entries on bridge master, 1bc844ee0faa1b92e3ede00bdd948021c78d7088 (v5.4) is required. */
if (!link->manager->bridge_mdb_on_master_not_supported) {
log_link_warning_errno(link, r, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring: %m");
log_link_warning_errno(link, r, "Kernel seems not to support bridge MDB entries on bridge master, ignoring: %m");
link->manager->bridge_mdb_on_master_not_supported = true;
}
} else if (r < 0 && r != -EEXIST) {
@ -103,8 +104,8 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
return 1;
}
if (link->bridge_mdb_messages == 0) {
link->bridge_mdb_configured = true;
if (link->static_bridge_mdb_messages == 0) {
link->static_bridge_mdb_configured = true;
link_check_ready(link);
}
@ -124,22 +125,23 @@ static int link_get_bridge_master_ifindex(Link *link) {
}
/* send a request to the kernel to add an MDB entry */
static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
struct br_mdb_entry entry;
int master, r;
assert(mdb);
assert(link);
assert(link->network);
assert(link->manager);
assert(mdb_entry);
assert(callback);
if (DEBUG_LOGGING) {
_cleanup_free_ char *a = NULL;
(void) in_addr_to_string(mdb_entry->family, &mdb_entry->group_addr, &a);
(void) in_addr_to_string(mdb->family, &mdb->group_addr, &a);
log_link_debug(link, "Configuring bridge MDB entry: MulticastGroupAddress=%s, VLANId=%u",
strna(a), mdb_entry->vlan_id);
strna(a), mdb->vlan_id);
}
master = link_get_bridge_master_ifindex(link);
@ -151,22 +153,17 @@ static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
* See br_mdb_add_group() in net/bridge/br_mdb.c of kernel. */
.state = master == link->ifindex ? MDB_TEMPORARY : MDB_PERMANENT,
.ifindex = link->ifindex,
.vid = mdb_entry->vlan_id,
.vid = mdb->vlan_id,
};
/* create new RTM message */
r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
switch (mdb_entry->family) {
switch (mdb->family) {
case AF_INET:
entry.addr.u.ip4 = mdb_entry->group_addr.in.s_addr;
entry.addr.u.ip4 = mdb->group_addr.in.s_addr;
entry.addr.proto = htobe16(ETH_P_IP);
break;
case AF_INET6:
entry.addr.u.ip6 = mdb_entry->group_addr.in6;
entry.addr.u.ip6 = mdb->group_addr.in6;
entry.addr.proto = htobe16(ETH_P_IPV6);
break;
@ -174,11 +171,16 @@ static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
assert_not_reached("Invalid address family");
}
/* create new RTM message */
r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
r = sd_netlink_message_append_data(req, MDBA_SET_ENTRY, &entry, sizeof(entry));
if (r < 0)
return log_link_error_errno(link, r, "Could not append MDBA_SET_ENTRY attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, set_mdb_handler,
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@ -188,109 +190,133 @@ static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
return 1;
}
int link_set_bridge_mdb(Link *link) {
MdbEntry *mdb_entry;
int link_request_static_bridge_mdb(Link *link) {
BridgeMDB *mdb;
int r;
assert(link);
assert(link->manager);
if (link->bridge_mdb_messages != 0) {
log_link_debug(link, "MDB entries are configuring.");
return 0;
}
link->bridge_mdb_configured = false;
link->static_bridge_mdb_configured = false;
if (!link->network)
return 0;
if (hashmap_isempty(link->network->mdb_entries_by_section))
if (hashmap_isempty(link->network->bridge_mdb_entries_by_section))
goto finish;
if (!link_has_carrier(link)) {
log_link_debug(link, "Link does not have carrier yet, setting MDB entries later.");
return 0;
}
if (link->network->bridge) {
Link *master;
r = link_get(link->manager, link->network->bridge->ifindex, &master);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get Link object for Bridge=%s", link->network->bridge->ifname);
if (!link_has_carrier(master)) {
log_link_debug(link, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link->network->bridge->ifname);
return 0;
if (!link->network->bridge) {
if (!streq_ptr(link->kind, "bridge")) {
log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
goto finish;
} else if (link->manager->bridge_mdb_on_master_not_supported) {
log_link_debug(link, "Kernel seems not to support bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
goto finish;
}
} else if (!streq_ptr(link->kind, "bridge")) {
log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
goto finish;
} else if (link->manager->bridge_mdb_on_master_not_supported) {
log_link_debug(link, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
goto finish;
}
HASHMAP_FOREACH(mdb_entry, link->network->mdb_entries_by_section) {
r = mdb_entry_configure(link, mdb_entry);
HASHMAP_FOREACH(mdb, link->network->bridge_mdb_entries_by_section) {
r = link_queue_request(link, REQUEST_TYPE_BRIDGE_MDB, mdb, false,
&link->static_bridge_mdb_messages, bridge_mdb_configure_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
link->bridge_mdb_messages++;
return log_link_error_errno(link, r, "Failed to request MDB entry to multicast group database: %m");
}
finish:
if (link->bridge_mdb_messages == 0) {
link->bridge_mdb_configured = true;
if (link->static_bridge_mdb_messages == 0) {
link->static_bridge_mdb_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting bridge MDB entries.");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
static int mdb_entry_verify(MdbEntry *mdb_entry) {
if (section_is_invalid(mdb_entry->section))
static bool bridge_mdb_is_ready_to_configure(Link *link) {
Link *master;
if (!link_is_ready_to_configure(link, false))
return false;
if (!link->network->bridge)
return true; /* The interface is bridge master. */
if (link->master_ifindex <= 0)
return false;
if (link->master_ifindex != link->network->bridge->ifindex)
return false;
if (link_get(link->manager, link->master_ifindex, &master) < 0)
return false;
if (!streq_ptr(master->kind, "bridge"))
return false;
if (!IN_SET(master->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (!link_has_carrier(master))
return false;
return true;
}
int request_process_bridge_mdb(Request *req) {
assert(req);
assert(req->link);
assert(req->mdb);
assert(req->type == REQUEST_TYPE_BRIDGE_MDB);
if (!bridge_mdb_is_ready_to_configure(req->link))
return 0;
return bridge_mdb_configure(req->mdb, req->link, req->netlink_handler);
}
static int bridge_mdb_verify(BridgeMDB *mdb) {
if (section_is_invalid(mdb->section))
return -EINVAL;
if (mdb_entry->family == AF_UNSPEC)
if (mdb->family == AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
"Ignoring [BridgeMDB] section from line %u.",
mdb_entry->section->filename, mdb_entry->section->line);
mdb->section->filename, mdb->section->line);
if (!in_addr_is_multicast(mdb_entry->family, &mdb_entry->group_addr))
if (!in_addr_is_multicast(mdb->family, &mdb->group_addr))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: MulticastGroupAddress= is not a multicast address. "
"Ignoring [BridgeMDB] section from line %u.",
mdb_entry->section->filename, mdb_entry->section->line);
mdb->section->filename, mdb->section->line);
if (mdb_entry->family == AF_INET) {
if (in4_addr_is_local_multicast(&mdb_entry->group_addr.in))
if (mdb->family == AF_INET) {
if (in4_addr_is_local_multicast(&mdb->group_addr.in))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: MulticastGroupAddress= is a local multicast address. "
"Ignoring [BridgeMDB] section from line %u.",
mdb_entry->section->filename, mdb_entry->section->line);
mdb->section->filename, mdb->section->line);
} else {
if (in6_addr_is_link_local_all_nodes(&mdb_entry->group_addr.in6))
if (in6_addr_is_link_local_all_nodes(&mdb->group_addr.in6))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: MulticastGroupAddress= is the multicast all nodes address. "
"Ignoring [BridgeMDB] section from line %u.",
mdb_entry->section->filename, mdb_entry->section->line);
mdb->section->filename, mdb->section->line);
}
return 0;
}
void network_drop_invalid_mdb_entries(Network *network) {
MdbEntry *mdb_entry;
void network_drop_invalid_bridge_mdb_entries(Network *network) {
BridgeMDB *mdb;
assert(network);
HASHMAP_FOREACH(mdb_entry, network->mdb_entries_by_section)
if (mdb_entry_verify(mdb_entry) < 0)
mdb_entry_free(mdb_entry);
HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
if (bridge_mdb_verify(mdb) < 0)
bridge_mdb_free(mdb);
}
/* parse the VLAN Id from config files. */
@ -306,7 +332,7 @@ int config_parse_mdb_vlan_id(
void *data,
void *userdata) {
_cleanup_(mdb_entry_free_or_set_invalidp) MdbEntry *mdb_entry = NULL;
_cleanup_(bridge_mdb_free_or_set_invalidp) BridgeMDB *mdb = NULL;
Network *network = userdata;
int r;
@ -316,17 +342,17 @@ int config_parse_mdb_vlan_id(
assert(rvalue);
assert(data);
r = mdb_entry_new_static(network, filename, section_line, &mdb_entry);
r = bridge_mdb_new_static(network, filename, section_line, &mdb);
if (r < 0)
return log_oom();
r = config_parse_vlanid(unit, filename, line, section,
section_line, lvalue, ltype,
rvalue, &mdb_entry->vlan_id, userdata);
rvalue, &mdb->vlan_id, userdata);
if (r < 0)
return r;
TAKE_PTR(mdb_entry);
TAKE_PTR(mdb);
return 0;
}
@ -343,7 +369,7 @@ int config_parse_mdb_group_address(
void *data,
void *userdata) {
_cleanup_(mdb_entry_free_or_set_invalidp) MdbEntry *mdb_entry = NULL;
_cleanup_(bridge_mdb_free_or_set_invalidp) BridgeMDB *mdb = NULL;
Network *network = userdata;
int r;
@ -353,16 +379,16 @@ int config_parse_mdb_group_address(
assert(rvalue);
assert(data);
r = mdb_entry_new_static(network, filename, section_line, &mdb_entry);
r = bridge_mdb_new_static(network, filename, section_line, &mdb);
if (r < 0)
return log_oom();
r = in_addr_from_string_auto(rvalue, &mdb_entry->family, &mdb_entry->group_addr);
r = in_addr_from_string_auto(rvalue, &mdb->family, &mdb->group_addr);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Cannot parse multicast group address: %m");
return 0;
}
TAKE_PTR(mdb_entry);
TAKE_PTR(mdb);
return 0;
}

View File

@ -7,23 +7,25 @@
#include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef struct MdbEntry {
typedef struct BridgeMDB {
Network *network;
NetworkConfigSection *section;
int family;
union in_addr_union group_addr;
uint16_t vlan_id;
} MdbEntry;
} BridgeMDB;
MdbEntry *mdb_entry_free(MdbEntry *mdb_entry);
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb);
void network_drop_invalid_mdb_entries(Network *network);
void network_drop_invalid_bridge_mdb_entries(Network *network);
int link_set_bridge_mdb(Link *link);
int link_request_static_bridge_mdb(Link *link);
int request_process_bridge_mdb(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id);

View File

@ -10,7 +10,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
#include "netlink-util.h"
#include "networkd-brvlan.h"
#include "networkd-bridge-vlan.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
@ -42,7 +42,13 @@ static int find_next_bit(int i, uint32_t x) {
return j ? j + i : 0;
}
static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) {
int bridge_vlan_append_info(
const Link *link,
sd_netlink_message *req,
uint16_t pvid,
const uint32_t *br_vid_bitmap,
const uint32_t *br_untagged_bitmap) {
struct bridge_vlan_info br_vlan;
bool done, untagged = false;
uint16_t begin, end;
@ -135,82 +141,29 @@ static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint
return cnt;
}
static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
void network_adjust_bridge_vlan(Network *network) {
assert(network);
assert(link);
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
log_link_message_warning_errno(link, m, r, "Could not add VLAN to bridge port");
return 1;
}
int link_set_bridge_vlan(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(link->network);
if (!link->network->use_br_vlan)
return 0;
if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
return 0;
if (!network->use_br_vlan)
return;
/* pvid might not be in br_vid_bitmap yet */
if (link->network->pvid)
set_bit(link->network->pvid, link->network->br_vid_bitmap);
/* create new RTM message */
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
if (r < 0)
return log_link_error_errno(link, r, "Could not set message family: %m");
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
/* master needs flag self */
if (!link->network->bridge) {
uint16_t flags = BRIDGE_FLAGS_SELF;
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(flags));
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_BRIDGE_FLAGS: %m");
}
/* add vlan info */
r = append_vlan_info_data(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
if (r < 0)
return log_link_error_errno(link, r, "Could not append VLANs: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
/* send message to the kernel */
r = netlink_call_async(link->manager->rtnl, NULL, req, set_brvlan_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
if (network->pvid)
set_bit(network->pvid, network->br_vid_bitmap);
}
int config_parse_brvlan_pvid(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) {
int config_parse_brvlan_pvid(
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) {
Network *network = userdata;
uint16_t pvid;
int r;
@ -225,11 +178,18 @@ int config_parse_brvlan_pvid(const char *unit, const char *filename,
return 0;
}
int config_parse_brvlan_vlan(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) {
int config_parse_brvlan_vlan(
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) {
Network *network = userdata;
uint16_t vid, vid_end;
int r;
@ -253,14 +213,21 @@ int config_parse_brvlan_vlan(const char *unit, const char *filename,
return 0;
}
int config_parse_brvlan_untagged(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) {
int config_parse_brvlan_untagged(
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) {
Network *network = userdata;
int r;
uint16_t vid, vid_end;
int r;
assert(filename);
assert(section);

View File

@ -5,14 +5,26 @@
Copyright © 2016 BISDN GmbH. All rights reserved.
***/
#include <inttypes.h>
#include "sd-netlink.h"
#include "conf-parser.h"
#define BRIDGE_VLAN_BITMAP_MAX 4096
#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)
typedef struct Link Link;
typedef struct Network Network;
int link_set_bridge_vlan(Link *link);
void network_adjust_bridge_vlan(Network *network);
int bridge_vlan_append_info(
const Link * link,
sd_netlink_message *req,
uint16_t pvid,
const uint32_t *br_vid_bitmap,
const uint32_t *br_untagged_bitmap);
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_pvid);
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_vlan);

View File

@ -7,6 +7,7 @@
#include "networkd-can.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-setlink.h"
#include "parse-util.h"
#include "string-util.h"
@ -69,7 +70,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
log_link_debug(link, "Link set");
r = link_activate(link);
r = link_request_to_activate(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@ -229,28 +230,6 @@ static int link_set_can(Link *link) {
return 0;
}
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
log_link_message_warning_errno(link, m, r, "Could not bring down interface");
link_enter_failed(link);
return 1;
}
r = link_set_can(link);
if (r < 0)
link_enter_failed(link);
return 1;
}
int link_configure_can(Link *link) {
int r;
@ -258,16 +237,16 @@ int link_configure_can(Link *link) {
if (streq_ptr(link->kind, "can")) {
/* The CAN interface must be down to configure bitrate, etc... */
if ((link->flags & IFF_UP))
r = link_down(link, link_down_handler);
else
r = link_set_can(link);
if (r < 0)
link_enter_failed(link);
return r;
if (link->flags & IFF_UP) {
r = link_down(link);
if (r < 0)
return r;
}
return link_set_can(link);
}
r = link_activate(link);
r = link_request_to_activate(link);
if (r < 0)
return r;

View File

@ -15,6 +15,7 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "parse-util.h"
#include "socket-netlink.h"
#include "string-table.h"
@ -96,6 +97,26 @@ static int link_find_dhcp_server_address(Link *link, Address **ret) {
return -ENOENT;
}
static int dhcp_server_find_uplink(Link *link, Link **ret) {
assert(link);
if (link->network->dhcp_server_uplink_name)
return link_get_by_name(link->manager, link->network->dhcp_server_uplink_name, ret);
if (link->network->dhcp_server_uplink_index > 0)
return link_get(link->manager, link->network->dhcp_server_uplink_index, ret);
if (link->network->dhcp_server_uplink_index == 0) {
/* It is not necessary to propagate error in automatic selection. */
if (manager_find_uplink(link->manager, AF_INET, link, ret) < 0)
*ret = NULL;
return 0;
}
*ret = NULL;
return 0;
}
static int link_push_uplink_to_dhcp_server(
Link *link,
sd_dhcp_lease_server_type_t what,
@ -289,7 +310,7 @@ static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
}
int dhcp4_server_configure(Link *link) {
static int dhcp4_server_configure(Link *link) {
bool acquired_uplink = false;
sd_dhcp_option *p;
DHCPStaticLease *static_lease;
@ -300,21 +321,18 @@ int dhcp4_server_configure(Link *link) {
assert(link);
if (!link_dhcp4_server_enabled(link))
return 0;
log_link_debug(link, "Configuring DHCP Server.");
if (!(link->flags & IFF_UP))
return 0;
if (link->dhcp_server)
return -EBUSY;
if (!link->dhcp_server) {
r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
if (r < 0)
return r;
r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
if (r < 0)
return r;
r = sd_dhcp_server_attach_event(link->dhcp_server, link->manager->event, 0);
if (r < 0)
return r;
}
r = sd_dhcp_server_attach_event(link->dhcp_server, link->manager->event, 0);
if (r < 0)
return r;
r = sd_dhcp_server_set_callback(link->dhcp_server, dhcp_server_callback, link);
if (r < 0)
@ -365,7 +383,7 @@ int dhcp4_server_configure(Link *link) {
else {
/* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */
if (!acquired_uplink) {
uplink = manager_find_uplink(link->manager, link);
(void) dhcp_server_find_uplink(link, &uplink);
acquired_uplink = true;
}
@ -447,15 +465,73 @@ int dhcp4_server_configure(Link *link) {
return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m");
}
if (!sd_dhcp_server_is_running(link->dhcp_server)) {
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0)
return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0)
return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
log_link_debug(link, "Offering DHCPv4 leases");
}
log_link_debug(link, "Offering DHCPv4 leases");
return 0;
return 1;
}
int link_request_dhcp_server(Link *link) {
assert(link);
if (!link_dhcp4_server_enabled(link))
return 0;
if (link->dhcp_server)
return 0;
log_link_debug(link, "Requesting DHCP server.");
return link_queue_request(link, REQUEST_TYPE_DHCP_SERVER, NULL, false, NULL, NULL, NULL);
}
static bool dhcp_server_is_ready_to_configure(Link *link) {
Link *uplink = NULL;
Address *a;
assert(link);
if (!link->network)
return false;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (!link_has_carrier(link))
return false;
if (link->address_remove_messages > 0)
return false;
if (!link->static_addresses_configured)
return false;
if (link_find_dhcp_server_address(link, &a) < 0)
return false;
if (!address_is_ready(a))
return false;
if (dhcp_server_find_uplink(link, &uplink) < 0)
return false;
if (uplink && !uplink->network)
return false;
return true;
}
int request_process_dhcp_server(Request *req) {
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_DHCP_SERVER);
if (!dhcp_server_is_ready_to_configure(req->link))
return 0;
return dhcp4_server_configure(req->link);
}
int config_parse_dhcp_server_relay_agent_suboption(
@ -584,3 +660,55 @@ int config_parse_dhcp_server_address(
network->dhcp_server_address_prefixlen = prefixlen;
return 0;
}
int config_parse_dhcp_server_uplink(
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) {
Network *network = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue) || streq(rvalue, ":auto")) {
network->dhcp_server_uplink_index = 0; /* uplink will be selected automatically */
network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
return 0;
}
if (streq(rvalue, ":none")) {
network->dhcp_server_uplink_index = -1; /* uplink will not be selected automatically */
network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
return 0;
}
r = parse_ifindex(rvalue);
if (r > 0) {
network->dhcp_server_uplink_index = r;
network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
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_warn(&network->dhcp_server_uplink_name, rvalue);
if (r < 0)
return r;
network->dhcp_server_uplink_index = 0;
return 0;
}

View File

@ -5,11 +5,14 @@
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
void network_adjust_dhcp_server(Network *network);
int dhcp4_server_configure(Link *link);
int link_request_dhcp_server(Link *link);
int request_process_dhcp_server(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_uplink);

View File

@ -20,6 +20,7 @@
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-setlink.h"
#include "networkd-state-file.h"
#include "string-table.h"
#include "strv.h"
@ -208,7 +209,7 @@ static int dhcp4_request_route(Route *in, Link *link) {
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
dhcp4_route_handler, &req);
if (r < 0)
if (r <= 0)
return r;
req->after_configure = dhcp4_after_route_configure;
@ -685,7 +686,7 @@ static int dhcp_reset_mtu(Link *link) {
if (link->original_mtu == mtu)
return 0;
r = link_set_mtu(link, link->original_mtu);
r = link_request_to_set_mtu(link, link->original_mtu);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
@ -1064,6 +1065,8 @@ static int dhcp4_request_address(Link *link, bool announce) {
dhcp4_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
if (r == 0)
return 0;
req->after_configure = dhcp4_after_address_configure;
@ -1127,7 +1130,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_mtu(lease, &mtu);
if (r >= 0) {
r = link_set_mtu(link, mtu);
r = link_request_to_set_mtu(link, mtu);
if (r < 0)
log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
}

View File

@ -312,6 +312,8 @@ static int dhcp6_pd_request_route(Link *link, const struct in6_addr *prefix, con
dhcp6_pd_route_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 prefix route: %m");
if (r == 0)
return 0;
req->after_configure = dhcp6_pd_after_route_configure;
@ -470,6 +472,8 @@ static int dhcp6_pd_request_address(
dhcp6_pd_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 delegated prefix address: %m");
if (r == 0)
return 0;
req->after_configure = dhcp6_pd_after_address_configure;
@ -897,6 +901,8 @@ static int dhcp6_request_unreachable_route(Link *link, const struct in6_addr *ad
if (r < 0)
return log_link_error_errno(link, r, "Failed to request unreachable route for DHCPv6 delegated subnet %s: %m",
strna(buf));
if (r == 0)
return 0;
req->after_configure = dhcp6_after_route_configure;
@ -1173,6 +1179,8 @@ static int dhcp6_request_address(
dhcp6_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv6 address %s: %m", strna(buffer));
if (r == 0)
return 0;
req->after_configure = dhcp6_after_address_configure;

View File

@ -8,30 +8,59 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "socket-util.h"
#include "string-util.h"
#include "sysctl-util.h"
static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
void network_adjust_ipv6_proxy_ndp(Network *network) {
assert(network);
if (set_isempty(network->ipv6_proxy_ndp_addresses))
return;
if (!socket_ipv6_is_supported()) {
log_once(LOG_WARNING,
"%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, "
"Ignoring IPv6 proxy NDP addresses.", network->filename);
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
}
}
static int ipv6_proxy_ndp_address_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->static_ipv6_proxy_ndp_messages > 0);
link->static_ipv6_proxy_ndp_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0)
log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring");
if (link->static_ipv6_proxy_ndp_messages == 0) {
log_link_debug(link, "IPv6 proxy NDP addresses set.");
link->static_ipv6_proxy_ndp_configured = true;
link_check_ready(link);
}
return 1;
}
/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
static int ipv6_proxy_ndp_address_configure(Link *link, const struct in6_addr *address) {
static int ipv6_proxy_ndp_address_configure(
const struct in6_addr *address,
Link *link,
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(address);
assert(link);
assert(link->manager);
assert(address);
assert(link->manager->rtnl);
assert(callback);
/* create new netlink message */
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
@ -46,71 +75,56 @@ static int ipv6_proxy_ndp_address_configure(Link *link, const struct in6_addr *a
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler,
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
return 1;
}
static bool ipv6_proxy_ndp_is_needed(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
if (link->network->ipv6_proxy_ndp >= 0)
return link->network->ipv6_proxy_ndp;
return !set_isempty(link->network->ipv6_proxy_ndp_addresses);
}
static int ipv6_proxy_ndp_set(Link *link) {
bool v;
int r;
assert(link);
if (!socket_ipv6_is_supported())
return 0;
v = ipv6_proxy_ndp_is_needed(link);
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
if (r < 0)
return log_link_warning_errno(link, r, "Cannot configure proxy NDP for the interface, ignoring: %m");
return v;
}
/* configure all ipv6 proxy ndp addresses */
int link_set_ipv6_proxy_ndp_addresses(Link *link) {
int link_request_static_ipv6_proxy_ndp_addresses(Link *link) {
struct in6_addr *address;
int r;
assert(link);
assert(link->network);
/* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
r = ipv6_proxy_ndp_set(link);
if (r <= 0)
return 0;
link->static_ipv6_proxy_ndp_configured = false;
SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) {
r = ipv6_proxy_ndp_address_configure(link, address);
r = link_queue_request(link, REQUEST_TYPE_IPV6_PROXY_NDP, address, false,
&link->static_ipv6_proxy_ndp_messages,
ipv6_proxy_ndp_address_configure_handler, NULL);
if (r < 0)
return r;
return log_link_warning_errno(link, r, "Failed to request IPv6 proxy NDP address: %m");
}
if (link->static_ipv6_proxy_ndp_messages == 0) {
link->static_ipv6_proxy_ndp_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting IPv6 proxy NDP addresses.");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
int request_process_ipv6_proxy_ndp_address(Request *req) {
assert(req);
assert(req->link);
assert(req->ipv6_proxy_ndp);
assert(req->type == REQUEST_TYPE_IPV6_PROXY_NDP);
if (!link_is_ready_to_configure(req->link, false))
return 0;
return ipv6_proxy_ndp_address_configure(req->ipv6_proxy_ndp, req->link, req->netlink_handler);
}
int config_parse_ipv6_proxy_ndp_address(
const char *unit,
const char *filename,

View File

@ -4,7 +4,12 @@
#include "conf-parser.h"
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
int link_set_ipv6_proxy_ndp_addresses(Link *link);
void network_adjust_ipv6_proxy_ndp(Network *network);
int link_request_static_ipv6_proxy_ndp_addresses(Link *link);
int request_process_ipv6_proxy_ndp_address(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address);

File diff suppressed because it is too large Load Diff

View File

@ -79,9 +79,11 @@ typedef struct Link {
LinkAddressState ipv6_address_state;
LinkOnlineState online_state;
unsigned address_label_messages;
unsigned static_address_messages;
unsigned static_address_label_messages;
unsigned static_bridge_fdb_messages;
unsigned static_bridge_mdb_messages;
unsigned static_ipv6_proxy_ndp_messages;
unsigned static_neighbor_messages;
unsigned static_nexthop_messages;
unsigned static_route_messages;
@ -92,8 +94,9 @@ typedef struct Link {
unsigned route_remove_messages;
unsigned tc_messages;
unsigned sr_iov_messages;
unsigned enslaving;
unsigned bridge_mdb_messages;
unsigned set_link_messages;
unsigned create_stacked_netdev_messages;
unsigned create_stacked_netdev_after_configured_messages;
Set *addresses;
Set *addresses_foreign;
@ -123,19 +126,21 @@ typedef struct Link {
bool ipv4ll_address_configured:1;
bool static_addresses_configured:1;
bool static_address_labels_configured:1;
bool static_bridge_fdb_configured:1;
bool static_bridge_mdb_configured:1;
bool static_ipv6_proxy_ndp_configured:1;
bool static_neighbors_configured:1;
bool static_nexthops_configured:1;
bool static_routes_configured:1;
bool static_routing_policy_rules_configured:1;
bool tc_configured:1;
bool sr_iov_configured:1;
bool setting_mtu:1;
bool setting_genmode:1;
bool ipv6_mtu_set:1;
bool bridge_mdb_configured:1;
bool can_configured:1;
bool activated:1;
bool master_set:1;
bool stacked_netdevs_created:1;
bool stacked_netdevs_after_configured_created:1;
sd_dhcp_server *dhcp_server;
@ -213,13 +218,13 @@ DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
int link_get(Manager *m, int ifindex, Link **ret);
int link_get_by_name(Manager *m, const char *ifname, Link **ret);
int link_get_master(Link *link, Link **ret);
int link_up(Link *link);
int link_down(Link *link, link_netlink_message_handler_t callback);
int link_activate(Link *link);
int link_getlink_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int link_call_getlink(Link *link, link_netlink_message_handler_t callback);
int link_handle_bound_to_list(Link *link);
void link_enter_failed(Link *link);
void link_set_state(Link *link, LinkState state);
void link_check_ready(Link *link);
@ -232,8 +237,6 @@ bool link_ipv6_enabled(Link *link);
bool link_ipv6ll_enabled(Link *link);
int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
int link_set_mtu(Link *link, uint32_t mtu);
bool link_ipv4ll_enabled(Link *link);
int link_stop_engines(Link *link, bool may_keep_dhcp);

View File

@ -60,8 +60,10 @@ static int manager_reset_all(Manager *m) {
HASHMAP_FOREACH(link, m->links) {
r = link_carrier_reset(link);
if (r < 0)
if (r < 0) {
log_link_warning_errno(link, r, "Could not reset carrier: %m");
link_enter_failed(link);
}
}
return 0;
@ -452,7 +454,7 @@ Manager* manager_free(Manager *m) {
HASHMAP_FOREACH(link, m->links)
(void) link_stop_engines(link, true);
m->request_queue = ordered_set_free_with_destructor(m->request_queue, request_free);
m->request_queue = ordered_set_free(m->request_queue);
m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
@ -719,43 +721,6 @@ int manager_enumerate(Manager *m) {
return 0;
}
Link* manager_find_uplink(Manager *m, Link *exclude) {
_cleanup_free_ struct local_address *gateways = NULL;
int n;
assert(m);
/* Looks for a suitable "uplink", via black magic: an
* interface that is up and where the default route with the
* highest priority points to. */
n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways);
if (n < 0) {
log_warning_errno(n, "Failed to determine list of default gateways: %m");
return NULL;
}
for (int i = 0; i < n; i++) {
Link *link;
link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex));
if (!link) {
log_debug("Weird, found a gateway for a link we don't know. Ignoring.");
continue;
}
if (link == exclude)
continue;
if (link->operstate < LINK_OPERSTATE_ROUTABLE)
continue;
return link;
}
return NULL;
}
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
const sd_bus_error *e;
int r;

View File

@ -111,8 +111,6 @@ bool manager_should_reload(Manager *m);
int manager_enumerate(Manager *m);
Link* manager_find_uplink(Manager *m, Link *exclude);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone);

View File

@ -395,7 +395,7 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_routes_messages,
ndisc_route_handler, &req);
if (r < 0)
if (r <= 0)
return r;
req->userdata = sd_ndisc_router_ref(rt);
@ -507,7 +507,7 @@ static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_addresses_messages,
ndisc_address_handler, &req);
if (r < 0)
if (r <= 0)
return r;
req->userdata = sd_ndisc_router_ref(rt);

View File

@ -69,7 +69,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
return 0;
}
static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
assert(neighbor);
siphash24_compress(&neighbor->family, sizeof(neighbor->family), state);
@ -89,7 +89,7 @@ static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state)
siphash24_compress(&neighbor->lladdr, neighbor->lladdr_size, state);
}
static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
int r;
r = CMP(a->family, b->family);

View File

@ -33,6 +33,9 @@ typedef struct Neighbor {
Neighbor *neighbor_free(Neighbor *neighbor);
void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state);
int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
void network_drop_invalid_neighbors(Network *network);
int link_drop_neighbors(Link *link);

View File

@ -10,6 +10,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h"
#include "networkd-can.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-server-static-lease.h"
@ -18,7 +19,6 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "networkd-dhcp6.h"
#include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-mdb.h"
#include "networkd-ndisc.h"
#include "networkd-network.h"
#include "networkd-neighbor.h"
@ -264,6 +264,7 @@ IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter,
IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix)
IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix)
DHCPServer.ServerAddress, config_parse_dhcp_server_address, 0, 0
DHCPServer.UplinkInterface, config_parse_dhcp_server_uplink, 0, 0
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_relay_target)
DHCPServer.RelayAgentCircuitId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_circuit_id)
DHCPServer.RelayAgentRemoteId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_remote_id)

View File

@ -16,11 +16,12 @@
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-server-static-lease.h"
#include "networkd-dhcp-server.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-manager.h"
#include "networkd-mdb.h"
#include "networkd-ndisc.h"
#include "networkd-neighbor.h"
#include "networkd-network.h"
@ -177,9 +178,11 @@ int network_verify(Network *network) {
/* IPMasquerade implies IPForward */
network->ip_forward |= network->ip_masquerade;
network_adjust_ipv6_proxy_ndp(network);
network_adjust_ipv6_accept_ra(network);
network_adjust_dhcp(network);
network_adjust_radv(network);
network_adjust_bridge_vlan(network);
if (network->mtu > 0 && network->dhcp_use_mtu) {
log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
@ -234,7 +237,7 @@ int network_verify(Network *network) {
network_drop_invalid_routes(network);
network_drop_invalid_nexthops(network);
network_drop_invalid_bridge_fdb_entries(network);
network_drop_invalid_mdb_entries(network);
network_drop_invalid_bridge_mdb_entries(network);
network_drop_invalid_neighbors(network);
network_drop_invalid_address_labels(network);
network_drop_invalid_prefixes(network);
@ -604,7 +607,7 @@ static Network *network_free(Network *network) {
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->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->bridge_mdb_entries_by_section, bridge_mdb_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->prefixes_by_section, prefix_free);
@ -617,6 +620,7 @@ static Network *network_free(Network *network) {
free(network->name);
free(network->dhcp_server_timezone);
free(network->dhcp_server_uplink_name);
for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
free(network->dhcp_server_emit[t].addresses);
@ -658,7 +662,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
Address *address;
Route *route;
BridgeFDB *fdb;
MdbEntry *mdb;
BridgeMDB *mdb;
Neighbor *neighbor;
assert(network);
@ -675,7 +679,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
if (fdb->family == AF_INET6)
return true;
HASHMAP_FOREACH(mdb, network->mdb_entries_by_section)
HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
if (mdb->family == AF_INET6)
return true;

View File

@ -12,11 +12,10 @@
#include "hashmap.h"
#include "net-condition.h"
#include "netdev.h"
#include "networkd-brvlan.h"
#include "networkd-bridge-vlan.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
#include "networkd-dhcp-server.h"
#include "networkd-lldp-rx.h"
#include "networkd-lldp-tx.h"
#include "networkd-ndisc.h"
@ -192,6 +191,8 @@ struct Network {
bool dhcp_server_bind_to_interface;
unsigned char dhcp_server_address_prefixlen;
struct in_addr dhcp_server_address;
int dhcp_server_uplink_index;
char *dhcp_server_uplink_name;
struct in_addr dhcp_server_relay_target;
char *dhcp_server_relay_agent_circuit_id;
char *dhcp_server_relay_agent_remote_id;
@ -309,7 +310,7 @@ struct Network {
Hashmap *routes_by_section;
Hashmap *nexthops_by_section;
Hashmap *bridge_fdb_entries_by_section;
Hashmap *mdb_entries_by_section;
Hashmap *bridge_mdb_entries_by_section;
Hashmap *neighbors_by_section;
Hashmap *address_labels_by_section;
Hashmap *prefixes_by_section;

View File

@ -104,7 +104,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
return 0;
}
static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
assert(nexthop);
siphash24_compress(&nexthop->protocol, sizeof(nexthop->protocol), state);
@ -124,7 +124,7 @@ static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
}
}
static int nexthop_compare_func(const NextHop *a, const NextHop *b) {
int nexthop_compare_func(const NextHop *a, const NextHop *b) {
int r;
r = CMP(a->protocol, b->protocol);

View File

@ -37,6 +37,9 @@ typedef struct NextHop {
NextHop *nexthop_free(NextHop *nexthop);
void nexthop_hash_func(const NextHop *nexthop, struct siphash *state);
int nexthop_compare_func(const NextHop *a, const NextHop *b);
void network_drop_invalid_nexthops(Network *network);
int link_drop_nexthops(Link *link);

View File

@ -1,7 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "networkd-address.h"
#include "networkd-address-label.h"
#include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h"
#include "networkd-dhcp-server.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-manager.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
@ -11,12 +15,27 @@
static void request_free_object(RequestType type, void *object) {
switch(type) {
case REQUEST_TYPE_ACTIVATE_LINK:
break;
case REQUEST_TYPE_ADDRESS:
address_free(object);
break;
case REQUEST_TYPE_ADDRESS_LABEL:
address_label_free(object);
break;
case REQUEST_TYPE_BRIDGE_FDB:
bridge_fdb_free(object);
break;
case REQUEST_TYPE_BRIDGE_MDB:
bridge_mdb_free(object);
break;
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
break;
case REQUEST_TYPE_DHCP_SERVER:
break;
case REQUEST_TYPE_IPV6_PROXY_NDP:
free(object);
break;
case REQUEST_TYPE_NEIGHBOR:
neighbor_free(object);
break;
@ -29,21 +48,26 @@ static void request_free_object(RequestType type, void *object) {
case REQUEST_TYPE_ROUTING_POLICY_RULE:
routing_policy_rule_free(object);
break;
case REQUEST_TYPE_SET_LINK:
break;
default:
assert_not_reached("invalid request type.");
}
}
Request *request_free(Request *req) {
static Request *request_free(Request *req) {
if (!req)
return NULL;
if (req->link && req->link->manager)
/* To prevent from triggering assertions in hash functions, remove this request before
* freeing object below. */
ordered_set_remove(req->link->manager->request_queue, req);
if (req->on_free)
/* on_free() may use object. So, let's call this earlier. */
req->on_free(req);
if (req->consume_object)
request_free_object(req->type, req->object);
if (req->link && req->link->manager)
ordered_set_remove(req->link->manager->request_queue, req);
link_unref(req->link);
return mfree(req);
@ -58,6 +82,106 @@ void request_drop(Request *req) {
request_free(req);
}
static void request_hash_func(const Request *req, struct siphash *state) {
assert(req);
assert(req->link);
assert(state);
siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
siphash24_compress(&req->type, sizeof(req->type), state);
switch(req->type) {
case REQUEST_TYPE_ACTIVATE_LINK:
break;
case REQUEST_TYPE_ADDRESS:
address_hash_func(req->address, state);
break;
case REQUEST_TYPE_ADDRESS_LABEL:
case REQUEST_TYPE_BRIDGE_FDB:
case REQUEST_TYPE_BRIDGE_MDB:
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
/* TODO: Currently, these types do not have any specific hash and compare functions.
* Fortunately, all these objects are 'static', thus we can use the trivial functions. */
trivial_hash_func(req->object, state);
break;
case REQUEST_TYPE_DHCP_SERVER:
/* This type does not have object. */
break;
case REQUEST_TYPE_IPV6_PROXY_NDP:
in6_addr_hash_func(req->ipv6_proxy_ndp, state);
break;
case REQUEST_TYPE_NEIGHBOR:
neighbor_hash_func(req->neighbor, state);
break;
case REQUEST_TYPE_NEXTHOP:
nexthop_hash_func(req->nexthop, state);
break;
case REQUEST_TYPE_ROUTE:
route_hash_func(req->route, state);
break;
case REQUEST_TYPE_ROUTING_POLICY_RULE:
routing_policy_rule_hash_func(req->rule, state);
break;
case REQUEST_TYPE_SET_LINK:
siphash24_compress(&req->set_link_operation, sizeof(req->set_link_operation), state);
break;
default:
assert_not_reached("invalid request type.");
}
}
static int request_compare_func(const struct Request *a, const struct Request *b) {
int r;
assert(a);
assert(b);
assert(a->link);
assert(b->link);
r = CMP(a->link->ifindex, b->link->ifindex);
if (r != 0)
return r;
r = CMP(a->type, b->type);
if (r != 0)
return r;
switch (a->type) {
case REQUEST_TYPE_ACTIVATE_LINK:
return 0;
case REQUEST_TYPE_ADDRESS:
return address_compare_func(a->address, b->address);
case REQUEST_TYPE_ADDRESS_LABEL:
case REQUEST_TYPE_BRIDGE_FDB:
case REQUEST_TYPE_BRIDGE_MDB:
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
return trivial_compare_func(a->object, b->object);
case REQUEST_TYPE_DHCP_SERVER:
return 0;
case REQUEST_TYPE_IPV6_PROXY_NDP:
return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
case REQUEST_TYPE_NEIGHBOR:
return neighbor_compare_func(a->neighbor, b->neighbor);
case REQUEST_TYPE_NEXTHOP:
return nexthop_compare_func(a->nexthop, b->nexthop);
case REQUEST_TYPE_ROUTE:
return route_compare_func(a->route, b->route);
case REQUEST_TYPE_ROUTING_POLICY_RULE:
return routing_policy_rule_compare_func(a->rule, b->rule);
case REQUEST_TYPE_SET_LINK:
return CMP(a->set_link_operation, b->set_link_operation);
default:
assert_not_reached("invalid request type.");
}
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
request_hash_ops,
Request,
request_hash_func,
request_compare_func,
request_free);
int link_queue_request(
Link *link,
RequestType type,
@ -68,13 +192,18 @@ int link_queue_request(
Request **ret) {
_cleanup_(request_freep) Request *req = NULL;
Request *existing;
int r;
assert(link);
assert(link->manager);
assert(type >= 0 && type < _REQUEST_TYPE_MAX);
assert(object);
assert(netlink_handler);
assert(IN_SET(type,
REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_SET_LINK) ||
object);
assert(type == REQUEST_TYPE_DHCP_SERVER || netlink_handler);
req = new(Request, 1);
if (!req) {
@ -84,7 +213,7 @@ int link_queue_request(
}
*req = (Request) {
.link = link,
.link = link_ref(link),
.type = type,
.object = object,
.consume_object = consume_object,
@ -92,9 +221,17 @@ int link_queue_request(
.netlink_handler = netlink_handler,
};
link_ref(link);
existing = ordered_set_get(link->manager->request_queue, req);
if (existing) {
/* To prevent from removing the existing request. */
req->link = link_unref(req->link);
r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req);
if (ret)
*ret = existing;
return 0;
}
r = ordered_set_ensure_put(&link->manager->request_queue, &request_hash_ops, req);
if (r < 0)
return r;
@ -105,7 +242,7 @@ int link_queue_request(
*ret = req;
TAKE_PTR(req);
return 0;
return 1;
}
int manager_process_requests(sd_event_source *s, void *userdata) {
@ -120,12 +257,30 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
ORDERED_SET_FOREACH(req, manager->request_queue) {
switch(req->type) {
case REQUEST_TYPE_ACTIVATE_LINK:
r = request_process_activation(req);
break;
case REQUEST_TYPE_ADDRESS:
r = request_process_address(req);
break;
case REQUEST_TYPE_ADDRESS_LABEL:
r = request_process_address_label(req);
break;
case REQUEST_TYPE_BRIDGE_FDB:
r = request_process_bridge_fdb(req);
break;
case REQUEST_TYPE_BRIDGE_MDB:
r = request_process_bridge_mdb(req);
break;
case REQUEST_TYPE_CREATE_STACKED_NETDEV:
r = request_process_create_stacked_netdev(req);
break;
case REQUEST_TYPE_DHCP_SERVER:
r = request_process_dhcp_server(req);
break;
case REQUEST_TYPE_IPV6_PROXY_NDP:
r = request_process_ipv6_proxy_ndp_address(req);
break;
case REQUEST_TYPE_NEIGHBOR:
r = request_process_neighbor(req);
break;
@ -138,6 +293,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
case REQUEST_TYPE_ROUTING_POLICY_RULE:
r = request_process_routing_policy_rule(req);
break;
case REQUEST_TYPE_SET_LINK:
r = request_process_set_link(req);
break;
default:
return -EINVAL;
}

View File

@ -4,10 +4,14 @@
#include "sd-event.h"
#include "networkd-link.h"
#include "networkd-setlink.h"
typedef struct Address Address;
typedef struct AddressLabel AddressLabel;
typedef struct BridgeFDB BridgeFDB;
typedef struct BridgeMDB BridgeMDB;
typedef struct Neighbor Neighbor;
typedef struct NetDev NetDev;
typedef struct NextHop NextHop;
typedef struct Route Route;
typedef struct RoutingPolicyRule RoutingPolicyRule;
@ -18,27 +22,41 @@ typedef int (*request_after_configure_handler_t)(Request*, void*);
typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType {
REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_ADDRESS,
REQUEST_TYPE_ADDRESS_LABEL,
REQUEST_TYPE_BRIDGE_FDB,
REQUEST_TYPE_BRIDGE_MDB,
REQUEST_TYPE_CREATE_STACKED_NETDEV,
REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_IPV6_PROXY_NDP,
REQUEST_TYPE_NEIGHBOR,
REQUEST_TYPE_NEXTHOP,
REQUEST_TYPE_ROUTE,
REQUEST_TYPE_ROUTING_POLICY_RULE,
REQUEST_TYPE_SET_LINK,
_REQUEST_TYPE_MAX,
_REQUEST_TYPE_INVALID = -EINVAL,
} RequestType;
assert_cc(sizeof(SetLinkOperation) <= sizeof(void*));
typedef struct Request {
Link *link;
RequestType type;
bool consume_object;
union {
Address *address;
AddressLabel *label;
BridgeFDB *fdb;
BridgeMDB *mdb;
struct in6_addr *ipv6_proxy_ndp;
Neighbor *neighbor;
NextHop *nexthop;
Route *route;
RoutingPolicyRule *rule;
SetLinkOperation set_link_operation;
NetDev *netdev;
void *object;
};
void *userdata;
@ -48,7 +66,6 @@ typedef struct Request {
request_on_free_handler_t on_free;
} Request;
Request *request_free(Request *req);
void request_drop(Request *req);
int link_queue_request(

View File

@ -646,10 +646,10 @@ static int radv_set_domains(Link *link, Link *uplink) {
}
int radv_emit_dns(Link *link) {
Link *uplink;
Link *uplink = NULL;
int r;
uplink = manager_find_uplink(link->manager, link);
(void) manager_find_uplink(link->manager, AF_INET6, link, &uplink);
r = radv_set_dns(link, uplink);
if (r < 0)

View File

@ -771,6 +771,65 @@ bool manager_address_is_reachable(Manager *manager, int family, const union in_a
return false;
}
static Route *routes_get_default_gateway(Set *routes, int family, Route *gw) {
Route *route;
SET_FOREACH(route, routes) {
if (family != AF_UNSPEC && route->family != family)
continue;
if (route->dst_prefixlen != 0)
continue;
if (route->src_prefixlen != 0)
continue;
if (route->table != RT_TABLE_MAIN)
continue;
if (route->type != RTN_UNICAST)
continue;
if (route->scope != RT_SCOPE_UNIVERSE)
continue;
if (!in_addr_is_set(route->gw_family, &route->gw))
continue;
if (gw) {
if (route->gw_weight > gw->gw_weight)
continue;
if (route->priority >= gw->priority)
continue;
}
gw = route;
}
return gw;
}
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret) {
Route *gw = NULL;
Link *link;
assert(m);
assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
/* Looks for a suitable "uplink", via black magic: an interface that is up and where the
* default route with the highest priority points to. */
HASHMAP_FOREACH(link, m->links) {
if (link == exclude)
continue;
if (link->state != LINK_STATE_CONFIGURED)
continue;
gw = routes_get_default_gateway(link->routes, family, gw);
gw = routes_get_default_gateway(link->routes_foreign, family, gw);
}
if (!gw)
return -ENOENT;
assert(gw->link);
*ret = gw->link;
return 0;
}
static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
_cleanup_free_ char *dst = NULL, *src = NULL, *gw_alloc = NULL, *prefsrc = NULL,
*table = NULL, *scope = NULL, *proto = NULL;

View File

@ -78,6 +78,7 @@ int route_remove(const Route *route, Manager *manager, Link *link);
int link_has_route(Link *link, const Route *route);
bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);

View File

@ -143,7 +143,7 @@ static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRu
return 0;
}
static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
assert(rule);
siphash24_compress(&rule->family, sizeof(rule->family), state);
@ -183,7 +183,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
}
}
static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
int r;
r = CMP(a->family, b->family);

View File

@ -52,6 +52,9 @@ typedef struct RoutingPolicyRule {
RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule);
void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state);
int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b);
void network_drop_invalid_routing_policy_rules(Network *network);
int link_request_static_routing_policy_rules(Link *link);

View File

@ -0,0 +1,862 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <linux/if.h>
#include "missing_network.h"
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "string-table.h"
#include "sysctl-util.h"
static const char *const set_link_operation_table[_SET_LINK_OPERATION_MAX] = {
[SET_LINK_ADDRESS_GENERATION_MODE] = "IPv6LL address generation mode",
[SET_LINK_BOND] = "bond configurations",
[SET_LINK_BRIDGE] = "bridge configurations",
[SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations",
[SET_LINK_FLAGS] = "link flags",
[SET_LINK_GROUP] = "interface group",
[SET_LINK_MAC] = "MAC address",
[SET_LINK_MASTER] = "master interface",
[SET_LINK_MTU] = "MTU",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(set_link_operation, SetLinkOperation);
static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_getlink_handler_internal(rtnl, m, link, "Failed to sync link information");
}
static int get_link_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
if (get_link_default_handler(rtnl, m, link) > 0)
link->master_set = true;
return 0;
}
static int set_link_handler_internal(
sd_netlink *rtnl,
sd_netlink_message *m,
Link *link,
SetLinkOperation op,
bool ignore,
link_netlink_message_handler_t get_link_handler) {
int r;
assert(m);
assert(link);
assert(link->set_link_messages > 0);
assert(op >= 0 && op < _SET_LINK_OPERATION_MAX);
link->set_link_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0) {
const char *error_msg;
error_msg = strjoina("Failed to set ", set_link_operation_to_string(op), ignore ? ", ignoring" : "");
log_link_message_warning_errno(link, m, r, error_msg);
if (!ignore)
link_enter_failed(link);
return 0;
}
log_link_debug(link, "%s set.", set_link_operation_to_string(op));
if (get_link_handler) {
r = link_call_getlink(link, get_link_handler);
if (r < 0) {
link_enter_failed(link);
return 0;
}
}
if (link->set_link_messages == 0)
link_check_ready(link);
return 1;
}
static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
r = set_link_handler_internal(rtnl, m, link, SET_LINK_ADDRESS_GENERATION_MODE, true, NULL);
if (r <= 0)
return r;
r = link_drop_ipv6ll_addresses(link);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to drop IPv6LL addresses: %m");
link_enter_failed(link);
}
return 0;
}
static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_BOND, true, NULL);
}
static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE, true, NULL);
}
static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE_VLAN, true, NULL);
}
static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_FLAGS, true, get_link_default_handler);
}
static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_GROUP, true, NULL);
}
static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_MAC, true, get_link_default_handler);
}
static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_MASTER, true, get_link_master_handler);
}
static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
r = set_link_handler_internal(rtnl, m, link, SET_LINK_MTU, true, get_link_default_handler);
if (r <= 0)
return r;
/* The kernel resets ipv6 mtu after changing device mtu;
* we must set this here, after we've set device mtu */
r = link_set_ipv6_mtu(link);
if (r < 0)
log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m");
return 0;
}
static int link_configure(
Link *link,
SetLinkOperation op,
void *userdata,
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(link->manager->rtnl);
assert(link->network);
assert(op >= 0 && op < _SET_LINK_OPERATION_MAX);
assert(callback);
log_link_debug(link, "Setting %s", set_link_operation_to_string(op));
if (op == SET_LINK_BOND) {
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->master_ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not allocate RTM_NEWLINK message: %m");
} else {
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
}
switch (op) {
case SET_LINK_ADDRESS_GENERATION_MODE:
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
r = sd_netlink_message_open_container(req, AF_INET6);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open AF_INET6 container: %m");
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, PTR_TO_UINT8(userdata));
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE attribute: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close AF_INET6 container: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
break;
case SET_LINK_BOND:
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set netlink message flags: %m");
r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_LINKINFO container: %m");
r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond");
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_INFO_DATA container: %m");
if (link->network->active_slave) {
r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BOND_ACTIVE_SLAVE attribute: %m");
}
if (link->network->primary_slave) {
r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BOND_PRIMARY attribute: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_INFO_DATA container: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_LINKINFO container: %m");
break;
case SET_LINK_BRIDGE:
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set message family: %m");
r = sd_netlink_message_open_container(req, IFLA_PROTINFO);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_PROTINFO container: %m");
if (link->network->use_bpdu >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m");
}
if (link->network->hairpin >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m");
}
if (link->network->fast_leave >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m");
}
if (link->network->allow_port_to_be_root >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m");
}
if (link->network->unicast_flood >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
}
if (link->network->multicast_flood >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m");
}
if (link->network->multicast_to_unicast >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
}
if (link->network->neighbor_suppression >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m");
}
if (link->network->learning >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m");
}
if (link->network->bridge_proxy_arp >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP, link->network->bridge_proxy_arp);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP attribute: %m");
}
if (link->network->bridge_proxy_arp_wifi >= 0) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP_WIFI, link->network->bridge_proxy_arp_wifi);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP_WIFI attribute: %m");
}
if (link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
}
if (link->network->priority != LINK_BRIDGE_PORT_PRIORITY_INVALID) {
r = sd_netlink_message_append_u16(req, IFLA_BRPORT_PRIORITY, link->network->priority);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_PRIORITY attribute: %m");
}
if (link->network->multicast_router != _MULTICAST_ROUTER_INVALID) {
r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MULTICAST_ROUTER, link->network->multicast_router);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRPORT_MULTICAST_ROUTER attribute: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_PROTINFO container: %m");
break;
case SET_LINK_BRIDGE_VLAN:
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set message family: %m");
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return log_link_debug_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
if (!link->network->bridge) {
/* master needs BRIDGE_FLAGS_SELF flag*/
r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_BRIDGE_FLAGS attribute: %m");
}
r = bridge_vlan_append_info(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append VLANs: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_debug_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
break;
case SET_LINK_FLAGS: {
unsigned ifi_change = 0, ifi_flags = 0;
if (link->network->arp >= 0) {
ifi_change |= IFF_NOARP;
SET_FLAG(ifi_flags, IFF_NOARP, link->network->arp == 0);
}
if (link->network->multicast >= 0) {
ifi_change |= IFF_MULTICAST;
SET_FLAG(ifi_flags, IFF_MULTICAST, link->network->multicast);
}
if (link->network->allmulticast >= 0) {
ifi_change |= IFF_ALLMULTI;
SET_FLAG(ifi_flags, IFF_ALLMULTI, link->network->allmulticast);
}
if (link->network->promiscuous >= 0) {
ifi_change |= IFF_PROMISC;
SET_FLAG(ifi_flags, IFF_PROMISC, link->network->promiscuous);
}
r = sd_rtnl_message_link_set_flags(req, ifi_flags, ifi_change);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set link flags: %m");
break;
}
case SET_LINK_GROUP:
r = sd_netlink_message_append_u32(req, IFLA_GROUP, link->network->group);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_GROUP attribute: %m");
break;
case SET_LINK_MAC:
r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_ADDRESS attribute: %m");
break;
case SET_LINK_MASTER:
r = sd_netlink_message_append_u32(req, IFLA_MASTER, PTR_TO_UINT32(userdata));
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_MASTER attribute: %m");
break;
case SET_LINK_MTU:
r = sd_netlink_message_append_u32(req, IFLA_MTU, PTR_TO_UINT32(userdata));
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_MTU attribute: %m");
break;
default:
assert_not_reached("Invalid set link operation");
}
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_debug_errno(link, r, "Could not send RTM_SETLINK message: %m");
link_ref(link);
return 0;
}
static bool netdev_is_ready(NetDev *netdev) {
assert(netdev);
if (netdev->state != NETDEV_STATE_READY)
return false;
if (netdev->ifindex == 0)
return false;
return true;
}
static bool link_is_ready_to_call_set_link(Request *req) {
SetLinkOperation op;
Link *link;
int r;
assert(req);
link = req->link;
op = req->set_link_operation;
if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
switch (op) {
case SET_LINK_BOND:
case SET_LINK_BRIDGE:
case SET_LINK_BRIDGE_VLAN:
if (!link->master_set)
return false;
break;
case SET_LINK_MASTER: {
uint32_t m = 0;
assert(link->network);
if (link->network->batadv) {
if (!netdev_is_ready(link->network->batadv))
return false;
m = link->network->batadv->ifindex;
} else if (link->network->bond) {
if (!netdev_is_ready(link->network->bond))
return false;
m = link->network->bond->ifindex;
if (FLAGS_SET(link->flags, IFF_UP)) {
/* link must be down when joining to bond master. */
r = link_down(link);
if (r < 0) {
link_enter_failed(link);
return false;
}
}
} else if (link->network->bridge) {
if (!netdev_is_ready(link->network->bridge))
return false;
m = link->network->bridge->ifindex;
} else if (link->network->vrf) {
if (!netdev_is_ready(link->network->vrf))
return false;
m = link->network->vrf->ifindex;
}
req->userdata = UINT32_TO_PTR(m);
break;
}
default:
break;
}
return true;
}
int request_process_set_link(Request *req) {
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_SET_LINK);
assert(req->set_link_operation >= 0 && req->set_link_operation < _SET_LINK_OPERATION_MAX);
assert(req->netlink_handler);
if (!link_is_ready_to_call_set_link(req))
return 0;
r = link_configure(req->link, req->set_link_operation, req->userdata, req->netlink_handler);
if (r < 0)
return log_link_error_errno(req->link, r, "Failed to set %s: %m",
set_link_operation_to_string(req->set_link_operation));
return 1;
}
static int link_request_set_link(
Link *link,
SetLinkOperation op,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
Request *req;
int r;
assert(link);
assert(op >= 0 && op < _SET_LINK_OPERATION_MAX);
assert(netlink_handler);
r = link_queue_request(link, REQUEST_TYPE_SET_LINK, INT_TO_PTR(op), false,
&link->set_link_messages, netlink_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request to set %s: %m",
set_link_operation_to_string(op));
log_link_debug(link, "Requested to set %s", set_link_operation_to_string(op));
if (ret)
*ret = req;
return 0;
}
int link_request_to_set_addrgen_mode(Link *link) {
Request *req;
uint8_t mode;
int r;
assert(link);
assert(link->network);
if (!socket_ipv6_is_supported())
return 0;
if (!link_ipv6ll_enabled(link))
mode = IN6_ADDR_GEN_MODE_NONE;
else if (link->network->ipv6ll_address_gen_mode >= 0)
mode = link->network->ipv6ll_address_gen_mode;
else {
r = sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL);
if (r < 0) {
/* The file may not exist. And even if it exists, when stable_secret is unset,
* reading the file fails with ENOMEM when read_full_virtual_file(), which uses
* read() as the backend, and EIO when read_one_line_file() which uses fgetc(). */
log_link_debug_errno(link, r, "Failed to read sysctl property stable_secret, ignoring: %m");
mode = IN6_ADDR_GEN_MODE_EUI64;
} else
mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
}
r = link_request_set_link(link, SET_LINK_ADDRESS_GENERATION_MODE, link_set_addrgen_mode_handler, &req);
if (r < 0)
return r;
req->userdata = UINT8_TO_PTR(mode);
return 0;
}
int link_request_to_set_bond(Link *link) {
assert(link);
assert(link->network);
if (!link->network->bond)
return 0;
return link_request_set_link(link, SET_LINK_BOND, link_set_bond_handler, NULL);
}
int link_request_to_set_bridge(Link *link) {
assert(link);
assert(link->network);
if (!link->network->bridge)
return 0;
return link_request_set_link(link, SET_LINK_BRIDGE, link_set_bridge_handler, NULL);
}
int link_request_to_set_bridge_vlan(Link *link) {
assert(link);
assert(link->network);
if (!link->network->use_br_vlan)
return 0;
if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
return 0;
return link_request_set_link(link, SET_LINK_BRIDGE_VLAN, link_set_bridge_vlan_handler, NULL);
}
int link_request_to_set_flags(Link *link) {
assert(link);
assert(link->network);
if (link->network->arp < 0 &&
link->network->multicast < 0 &&
link->network->allmulticast < 0 &&
link->network->promiscuous < 0)
return 0;
return link_request_set_link(link, SET_LINK_FLAGS, link_set_flags_handler, NULL);
}
int link_request_to_set_group(Link *link) {
assert(link);
assert(link->network);
if (!link->network->group_set)
return 0;
return link_request_set_link(link, SET_LINK_GROUP, link_set_group_handler, NULL);
}
int link_request_to_set_mac(Link *link) {
assert(link);
assert(link->network);
if (!link->network->mac)
return 0;
return link_request_set_link(link, SET_LINK_MAC, link_set_mac_handler, NULL);
}
int link_request_to_set_master(Link *link) {
assert(link);
link->master_set = false;
return link_request_set_link(link, SET_LINK_MASTER, link_set_master_handler, NULL);
}
int link_request_to_set_mtu(Link *link, uint32_t mtu) {
Request *req = NULL; /* avoid false maybe-uninitialized warning */
int r;
assert(link);
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
* MTU bytes to IPV6_MTU_MIN. */
if (mtu < IPV6_MIN_MTU && link_ipv6_enabled(link)) {
log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as IPv6 is enabled "
"and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes");
mtu = IPV6_MIN_MTU;
}
if (link->mtu == mtu)
return 0;
r = link_request_set_link(link, SET_LINK_MTU, link_set_mtu_handler, &req);
if (r < 0)
return r;
req->userdata = UINT32_TO_PTR(mtu);
return 0;
}
static bool link_reduces_vlan_mtu(Link *link) {
/* See netif_reduces_vlan_mtu() in kernel. */
return streq_ptr(link->kind, "macsec");
}
static uint32_t link_get_requested_mtu_by_stacked_netdevs(Link *link) {
uint32_t mtu = 0;
NetDev *dev;
HASHMAP_FOREACH(dev, link->network->stacked_netdevs)
if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
/* See vlan_dev_change_mtu() in kernel. */
mtu = MAX(mtu, link_reduces_vlan_mtu(link) ? dev->mtu + 4 : dev->mtu);
else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
/* See macvlan_change_mtu() in kernel. */
mtu = dev->mtu;
return mtu;
}
int link_configure_mtu(Link *link) {
uint32_t mtu;
assert(link);
assert(link->network);
if (link->network->mtu > 0)
return link_request_to_set_mtu(link, link->network->mtu);
mtu = link_get_requested_mtu_by_stacked_netdevs(link);
if (link->mtu >= mtu)
return 0;
log_link_notice(link, "Bumping MTU bytes from %"PRIu32" to %"PRIu32" because of stacked device. "
"If it is not desired, then please explicitly specify MTUBytes= setting.",
link->mtu, mtu);
return link_request_to_set_mtu(link, mtu);
}
static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool check_ready) {
int r;
assert(m);
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
r = sd_netlink_message_get_errno(m);
if (r < 0)
log_link_message_warning_errno(link, m, r, up ?
"Could not bring up interface, ignoring" :
"Could not bring down interface, ignoring");
if (check_ready) {
link->activated = true;
link_check_ready(link);
}
return 0;
}
static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_up_or_down_handler_internal(rtnl, m, link, true, true);
}
static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_up_or_down_handler_internal(rtnl, m, link, false, true);
}
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_up_or_down_handler_internal(rtnl, m, link, true, false);
}
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_up_or_down_handler_internal(rtnl, m, link, false, false);
}
static int link_up_or_down(Link *link, bool up, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(link->manager->rtnl);
assert(callback);
log_link_debug(link, "Bringing link %s", up ? "up" : "down");
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_flags(req, up ? IFF_UP : 0, IFF_UP);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set link flags: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_debug_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
}
int link_up(Link *link) {
return link_up_or_down(link, true, link_up_handler);
}
int link_down(Link *link) {
return link_up_or_down(link, false, link_down_handler);
}
static bool link_is_ready_to_activate(Link *link) {
assert(link);
if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (link->set_link_messages > 0)
return false;
return true;
}
int request_process_activation(Request *req) {
Link *link;
bool up;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ACTIVATE_LINK);
assert(req->netlink_handler);
link = req->link;
up = PTR_TO_INT(req->userdata);
if (!link_is_ready_to_activate(link))
return 0;
r = link_up_or_down(link, up, req->netlink_handler);
if (r < 0)
return log_link_error_errno(link, r, "Failed to bring %s: %m", up ? "up" : "down");
return 1;
}
int link_request_to_activate(Link *link) {
Request *req;
bool up;
int r;
assert(link);
assert(link->network);
switch (link->network->activation_policy) {
case ACTIVATION_POLICY_BOUND:
/* FIXME: also use request queue to handle the list. */
r = link_handle_bound_to_list(link);
if (r < 0)
return r;
_fallthrough_;
case ACTIVATION_POLICY_MANUAL:
link->activated = true;
link_check_ready(link);
return 0;
case ACTIVATION_POLICY_UP:
case ACTIVATION_POLICY_ALWAYS_UP:
up = true;
break;
case ACTIVATION_POLICY_DOWN:
case ACTIVATION_POLICY_ALWAYS_DOWN:
up = false;
break;
default:
assert_not_reached("invalid activation policy");
}
link->activated = false;
r = link_queue_request(link, REQUEST_TYPE_ACTIVATE_LINK, NULL, false, NULL,
up ? link_activate_up_handler : link_activate_down_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request to activate link: %m");
req->userdata = INT_TO_PTR(up);
log_link_debug(link, "Requested to activate link");
return 0;
}

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
typedef struct Link Link;
typedef struct Request Request;
typedef enum SetLinkOperation {
SET_LINK_ADDRESS_GENERATION_MODE, /* Setting IPv6LL address generation mode. */
SET_LINK_BOND, /* Setting bond configs. */
SET_LINK_BRIDGE, /* Setting bridge configs. */
SET_LINK_BRIDGE_VLAN, /* Setting bridge vlan configs. */
SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */
SET_LINK_GROUP, /* Setting interface group. */
SET_LINK_MAC, /* Setting MAC address. */
SET_LINK_MASTER, /* Setting IFLA_MASTER. */
SET_LINK_MTU, /* Setting MTU. */
_SET_LINK_OPERATION_MAX,
_SET_LINK_OPERATION_INVALID = -EINVAL,
} SetLinkOperation;
int link_request_to_set_addrgen_mode(Link *link);
int link_request_to_set_bond(Link *link);
int link_request_to_set_bridge(Link *link);
int link_request_to_set_bridge_vlan(Link *link);
int link_request_to_set_flags(Link *link);
int link_request_to_set_group(Link *link);
int link_request_to_set_mac(Link *link);
int link_request_to_set_master(Link *link);
int link_request_to_set_mtu(Link *link, uint32_t mtu);
int link_configure_mtu(Link *link);
int request_process_set_link(Request *req);
int link_up(Link *link);
int link_down(Link *link);
int request_process_activation(Request *req);
int link_request_to_activate(Link *link);

View File

@ -161,6 +161,47 @@ static int link_set_ipv6_hop_limit(Link *link) {
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
}
static int link_set_ipv6_proxy_ndp(Link *link) {
bool v;
assert(link);
if (!socket_ipv6_is_supported())
return 0;
if (link->flags & IFF_LOOPBACK)
return 0;
if (!link->network)
return 0;
if (link->network->ipv6_proxy_ndp >= 0)
v = link->network->ipv6_proxy_ndp;
else
v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
}
int link_set_ipv6_mtu(Link *link) {
assert(link);
/* Make this a NOP if IPv6 is not available */
if (!socket_ipv6_is_supported())
return 0;
if (link->flags & IFF_LOOPBACK)
return 0;
if (!link->network)
return 0;
if (link->network->ipv6_mtu == 0)
return 0;
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
}
static int link_set_ipv4_accept_local(Link *link) {
assert(link);
@ -224,6 +265,14 @@ int link_set_sysctl(Link *link) {
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
r = link_set_ipv6_proxy_ndp(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
r = link_set_ipv6_mtu(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
r = link_set_ipv4_accept_local(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
@ -244,30 +293,6 @@ int link_set_sysctl(Link *link) {
return 0;
}
int link_set_ipv6_mtu(Link *link) {
int r;
assert(link);
/* Make this a NOP if IPv6 is not available */
if (!socket_ipv6_is_supported())
return 0;
if (link->flags & IFF_LOOPBACK)
return 0;
if (link->network->ipv6_mtu == 0)
return 0;
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
if (r < 0)
return r;
link->ipv6_mtu_set = true;
return 0;
}
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
[IPV6_PRIVACY_EXTENSIONS_NO] = "no",
[IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",

View File

@ -366,6 +366,7 @@ RelayTarget=
RelayAgentCircuitId=
RelayAgentRemoteId=
ServerAddress=
UplinkInterface=
[DHCPServerStaticLease]
MACAddress=
Address=

View File

@ -8,7 +8,7 @@ Address=192.168.5.2/24
DHCPServer=yes
[DHCPServer]
Address=192.168.5.1/24
ServerAddress=192.168.5.1/24
PoolOffset=10
PoolSize=50
EmitRouter=yes

View File

@ -0,0 +1,8 @@
[Match]
Name=dummy98
[Network]
IPv6AcceptRA=no
Address=192.168.5.2/24
DNS=192.168.5.1
NTP=192.168.5.1

View File

@ -9,5 +9,4 @@ DHCPServer=yes
ServerAddress=192.168.5.1/24
PoolOffset=10
PoolSize=50
DNS=192.168.5.1
NTP=192.168.5.1
UplinkInterface=dummy98

View File

@ -3668,16 +3668,22 @@ class NetworkdRATests(unittest.TestCase, Utilities):
self.assertRegex(output, '2002:da8:2:0')
class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
links = ['veth99']
links = [
'dummy98',
'veth99',
]
units = [
'12-dummy.netdev',
'25-veth.netdev',
'dhcp-client.network',
'dhcp-client-static-lease.network',
'dhcp-client-timezone-router.network',
'dhcp-server.network',
'dhcp-server-static-lease.network',
'dhcp-server-timezone-router.network']
'dhcp-server-timezone-router.network',
'dhcp-server-uplink.network',
]
def setUp(self):
remove_links(self.links)
@ -3689,7 +3695,8 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
stop_networkd(show_logs=True)
def test_dhcp_server(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network',
'12-dummy.netdev', 'dhcp-server-uplink.network')
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:routable'])