mirror of
https://github.com/systemd/systemd
synced 2026-03-17 18:44:46 +01:00
Compare commits
58 Commits
1319c7e044
...
f75420a43a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75420a43a | ||
|
|
16e09d51a7 | ||
|
|
9f40351f77 | ||
|
|
50b9fa01ed | ||
|
|
a7f07cbe34 | ||
|
|
29836c166d | ||
|
|
1187fc3375 | ||
|
|
112a0972a2 | ||
|
|
0e397560cc | ||
|
|
440d40dcc0 | ||
|
|
1362bd6c64 | ||
|
|
5a1860f761 | ||
|
|
79c6e11456 | ||
|
|
0d411b7f8f | ||
|
|
852a391605 | ||
|
|
b156a95d4a | ||
|
|
4b9a8c2b51 | ||
|
|
0c9ee5d5e8 | ||
|
|
813572853e | ||
|
|
8252fb4439 | ||
|
|
bfd7fb09cf | ||
|
|
5106ad00e6 | ||
|
|
5546870e7b | ||
|
|
1a0e5ca2f3 | ||
|
|
9670e45a6e | ||
|
|
5062b8593a | ||
|
|
7d5b232f40 | ||
|
|
71a754f70f | ||
|
|
d24bf1b514 | ||
|
|
8e00e24cc9 | ||
|
|
cc4c8fb136 | ||
|
|
a8e5e27c9f | ||
|
|
93fabc10fa | ||
|
|
0fa8ee6c77 | ||
|
|
fa28381202 | ||
|
|
793117b3fd | ||
|
|
b9bf3f22a8 | ||
|
|
f0269653e9 | ||
|
|
8566df791e | ||
|
|
9710895378 | ||
|
|
40b12fa20d | ||
|
|
5f33159190 | ||
|
|
fdeba3f5cc | ||
|
|
d8350b60e0 | ||
|
|
14d9ab9d32 | ||
|
|
354bc760cd | ||
|
|
4c0c8d1e72 | ||
|
|
2551b422e1 | ||
|
|
c3e960883f | ||
|
|
9a038aaced | ||
|
|
ff9e07838d | ||
|
|
9373f5a812 | ||
|
|
4e0006cc4b | ||
|
|
165d7c5c42 | ||
|
|
fb3aec45a0 | ||
|
|
ab486ef4eb | ||
|
|
b27e5d53f3 | ||
|
|
1d28a3cf6c |
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
29
meson.build
29
meson.build
@ -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')
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -180,6 +180,7 @@ if have_gnu_efi
|
||||
possible_common_cc_flags + [
|
||||
'-ffreestanding',
|
||||
'-fno-stack-protector',
|
||||
'-fno-strict-aliasing',
|
||||
'-fpic',
|
||||
'-fshort-wchar',
|
||||
'-Wall',
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 },
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
862
src/network/networkd-setlink.c
Normal file
862
src/network/networkd-setlink.c
Normal 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;
|
||||
}
|
||||
41
src/network/networkd-setlink.h
Normal file
41
src/network/networkd-setlink.h
Normal 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);
|
||||
@ -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",
|
||||
|
||||
@ -366,6 +366,7 @@ RelayTarget=
|
||||
RelayAgentCircuitId=
|
||||
RelayAgentRemoteId=
|
||||
ServerAddress=
|
||||
UplinkInterface=
|
||||
[DHCPServerStaticLease]
|
||||
MACAddress=
|
||||
Address=
|
||||
|
||||
@ -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
|
||||
|
||||
8
test/test-network/conf/dhcp-server-uplink.network
Normal file
8
test/test-network/conf/dhcp-server-uplink.network
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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'])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user