1
0
mirror of https://github.com/systemd/systemd synced 2025-12-26 10:54:45 +01:00

Compare commits

...

140 Commits

Author SHA1 Message Date
Yu Watanabe
ab582fda48
Merge pull request #17240 from yuwata/network-cleanup
network: several cleanups and fix IPv4DAD and IP Masqurade
2020-10-07 07:42:40 +09:00
Marco Wang
ee85122987 boot/efi: Explicitly specify void in parameter list
Functions that accept no arguments should be
explicitly declared a void parameter in their parameter list.

Signed-off-by: Marco Wang <m.aesophor@gmail.com>
2020-10-06 22:29:57 +02:00
Yu Watanabe
66493453b3 test-network: also remove IPv6 rules 2020-10-07 03:23:27 +09:00
Yu Watanabe
713bfdaa6c test-network: add a missing netdev in the list 2020-10-07 03:23:27 +09:00
Yu Watanabe
47f8411249 test-network: disable RA in test_sriov
We usually disable IPv6AcceptRA= if the test does not require any
dynamic address configuration, as it makes slightly slow down the test.

C.f. 491b79aeac323909e8cef60ba6e91e27fd731679.
2020-10-07 03:23:27 +09:00
Yu Watanabe
5cf52d90a9 test-network: add missing file in the list 2020-10-07 03:23:27 +09:00
Yu Watanabe
6dcc637574 test-network: drop duplicated address 2020-10-07 03:23:27 +09:00
Yu Watanabe
13ffa39f8e network: rename network_verify_xxx() -> network_drop_invalid_xxx()
As 'verify' implies a boolean result.
2020-10-07 03:22:03 +09:00
Yu Watanabe
494b6b43cb network: fix masquerade setting logic
Previously, address_establish() took Address object stored in Network
object. And address_release() took Address object stored in Link
object. Thus, address_release() always did nothing.
2020-10-07 03:13:26 +09:00
Yu Watanabe
cd1caf30c0 network: always use RT_SCOPE_HOST for IPv4 loopback addresses
For IPv6 case, use RT_SCOPE_HOST only when scope is not explicitly specified.
2020-10-07 03:13:18 +09:00
Yu Watanabe
d93d655c40 network: update MAC address in IPv4 ACD clients
When the MAC address of a link is updated, an address on the link may
be under checking address duplication. Or, (currently such code is not
implemented yet, but) address duplication check may be restarted later.
For that case, the IPv4 ACD clients must use the new updated MAC address.
2020-10-07 02:59:34 +09:00
Yu Watanabe
490ccbd5e5 network: configure IPv4 DAD per link address
Previously, IPv4 DAD is configured in each Address object stored in
Network object. If a .network file matches multipe links, then it causes
an assertion. To prevent it, now IPv4 DAD is configured in each Address
object belogs to Link object.
2020-10-07 02:57:58 +09:00
Yu Watanabe
693ec5ca83 network: constify one argument 2020-10-07 02:57:54 +09:00
Yu Watanabe
cde1f0e8fc network: introduce address_copy() 2020-10-07 02:54:01 +09:00
Yu Watanabe
eaff204f09 network: do not update Address::flags in address_configure() 2020-10-07 02:50:51 +09:00
Yu Watanabe
f5ee7d74af network: fix indentation 2020-10-07 02:50:51 +09:00
Yu Watanabe
4cf8500067 network: use sd_event stored in Manager 2020-10-07 02:50:51 +09:00
Yu Watanabe
2ffd6d73f9 network: check feature is enabled in xxx_configure() 2020-10-07 02:50:51 +09:00
Yu Watanabe
51f5dfd8ba network: move link_enumerate_ipv6_tentative_addresses() 2020-10-07 02:50:51 +09:00
Yu Watanabe
acc9fc2f51 network: drop unused function 2020-10-07 02:50:51 +09:00
Yu Watanabe
5e0534f1c1 network: move sysctl related functions to networkd-sysctl.c 2020-10-07 02:50:51 +09:00
Yu Watanabe
be9363ccab network: introduce radv_update_mac() 2020-10-07 02:50:51 +09:00
Yu Watanabe
eebba6dc24 network: introduce dhcp6_update_mac() 2020-10-07 02:50:51 +09:00
Yu Watanabe
d947f7f977 network: introduce dhcp4_update_mac() 2020-10-07 02:50:50 +09:00
Yu Watanabe
a3adb4a6a2 network: introduce ipv4ll_update_mac() 2020-10-07 02:50:50 +09:00
Yu Watanabe
5460bde5c5 network: introduce link_serialize_dhcp6_client() 2020-10-07 02:50:50 +09:00
Yu Watanabe
ca21a19a2e network: introduce link_serialize_ipv4ll() 2020-10-07 02:50:50 +09:00
Yu Watanabe
daad60d19e network: introduce link_deserialize_ipv4ll() 2020-10-07 02:50:50 +09:00
Yu Watanabe
571eeba909 network: introduce link_deserialize_dhcp4() 2020-10-07 02:50:50 +09:00
Yu Watanabe
bbe694f91f network: introduce network_verify_sr_iov() 2020-10-07 02:50:50 +09:00
Yu Watanabe
f3a3ff2762 network: move link_configure_sr_iov() 2020-10-07 02:50:50 +09:00
Yu Watanabe
209af9a67a network: introduce network_verify_traffic_control() 2020-10-07 02:50:50 +09:00
Yu Watanabe
200543791a network: move link_configure_traffic_control() 2020-10-07 02:50:50 +09:00
Yu Watanabe
34d7f2c99e network: merge link_set_bridge_vlan() and br_vlan_configure() 2020-10-07 02:50:50 +09:00
Yu Watanabe
256c75fd1f network: move DUID related functions 2020-10-07 02:50:50 +09:00
Yu Watanabe
086b8853d1 network: move link_radv_enabled() 2020-10-07 02:50:50 +09:00
Yu Watanabe
5ae0fb7fb7 network: move link_dhcp4_server_enabled() 2020-10-07 02:50:50 +09:00
Yu Watanabe
062c020fb6 network: move link_ipv6_accept_ra_enabled() 2020-10-07 02:50:50 +09:00
Yu Watanabe
6f7a17ff0c network: unify link_ipv{4,6}_forward_enabled() 2020-10-07 02:50:50 +09:00
Yu Watanabe
67c311abd3 network: unify link_dhcp{4,6}_enabled() 2020-10-07 02:50:50 +09:00
Yu Watanabe
ac49887e8c network: move link_get_xxx_route_table() 2020-10-07 02:50:50 +09:00
Yu Watanabe
bfbf150ee6 network: manage address pools by OrderedSet 2020-10-07 02:50:50 +09:00
Yu Watanabe
3fe721c674 network: drop unused argument 2020-10-07 02:50:50 +09:00
Yu Watanabe
ed76f58521 network: move functions related to address pool 2020-10-07 02:50:50 +09:00
Yu Watanabe
093e35334d network: header cleanup 2020-10-07 02:50:50 +09:00
Yu Watanabe
67a58eb378 network: make several functions static 2020-10-07 02:50:50 +09:00
Yu Watanabe
aa651e88de network: manage addresses from pool by Set 2020-10-07 02:50:50 +09:00
Yu Watanabe
9cd9fc8f44 network: drop list of static addresses
[Address] sections are managed by both LIST and Hashmap. Let's drop the
list and manage them by OrderedHashmap.
2020-10-07 02:50:50 +09:00
Yu Watanabe
7818f8589a network: make address_free() return NULL 2020-10-07 02:50:50 +09:00
Yu Watanabe
2488e4d934 network: introduce link_stop_ipv4_dad() 2020-10-07 02:50:50 +09:00
Yu Watanabe
b87d6a8284 network: move link_configure_ipv4_dad() 2020-10-07 02:50:50 +09:00
Yu Watanabe
da4d3a612d network: introduce link_deserialize_addresses() 2020-10-07 02:50:50 +09:00
Yu Watanabe
3b31e2b718 network: introduce link_serialize_addresses() 2020-10-07 02:50:50 +09:00
Yu Watanabe
32400c2ff0 network: introduce network_verify_addresses() 2020-10-07 02:50:50 +09:00
Yu Watanabe
9a0ad16b26 network: update log messages
And drop unnecessary log for in_addr_to_string(), as its result is used
only for the consequent logs.
2020-10-07 02:49:17 +09:00
Yu Watanabe
e1fc2c4371 network: move manager_rtnl_process_address() 2020-10-07 02:44:43 +09:00
Yu Watanabe
d7fbb9f50c network: introduce link_drop_addresses() 2020-10-07 02:44:43 +09:00
Yu Watanabe
f8f2f880d4 network: introduce link_drop_foreign_addresses() 2020-10-07 02:44:43 +09:00
Yu Watanabe
682c65b04c network: introduce link_set_addresses() 2020-10-07 02:44:43 +09:00
Yu Watanabe
e2263711ba network: cleanup networkd-route.h 2020-10-07 02:44:43 +09:00
Yu Watanabe
2a54a0446b network: drop list of static routes
[Route] sections are managed by both LIST and Hashmap. Let's drop the
list.
2020-10-07 02:44:43 +09:00
Yu Watanabe
833f3663a0 network: introduce hashmap_find_free_section_line() 2020-10-07 02:44:43 +09:00
Yu Watanabe
74154c2e28 network: make several functions static 2020-10-07 02:44:43 +09:00
Yu Watanabe
d9940a3f8a network: introduce network_verify_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
565194127a network: introduce link_serialize_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
731ff05b32 network: introduce link_deserialize_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
62f0ea5fae network: introduce link_drop_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
779804dd60 network: introduce link_drop_foreign_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
169948e9d2 network: make route_free() return NULL 2020-10-07 02:44:42 +09:00
Yu Watanabe
4468f01b67 network: move manager_rtnl_process_route() 2020-10-07 02:44:42 +09:00
Yu Watanabe
141318f777 network: move link_request_set_routes() 2020-10-07 02:44:42 +09:00
Yu Watanabe
be023c670b network: make network_get_ipv6_dns() always set return value on success 2020-10-07 02:44:42 +09:00
Yu Watanabe
a8d4a21091 network: fix indentation 2020-10-07 02:44:42 +09:00
Yu Watanabe
b5ce40472c network: cleanup networkd-radv.h 2020-10-07 02:44:42 +09:00
Yu Watanabe
1a7deb2fcf network: introduce network_verify_prefix() and network_verify_route_prefix() 2020-10-07 02:44:42 +09:00
Yu Watanabe
d30081c24e network: also check route prefixes are configured 2020-10-07 02:44:42 +09:00
Yu Watanabe
ecb0e85ea9 network: drop redundant list of prefixes and route prefixes 2020-10-07 02:44:42 +09:00
Yu Watanabe
064dfb05f0 network: make prefix_free() and route_prefix_free() return NULL 2020-10-07 02:44:42 +09:00
Yu Watanabe
87851e0feb network: warn if IPv6ProxyNDPAddress= is set and IPv6ProxyNDP= is disabled 2020-10-07 02:44:42 +09:00
Yu Watanabe
fd773a11d8 network: propagate errors in ipv6_proxy_ndp_set()
And ignore IPv6ProxyNDPAddress= settings if proxy_ndp is zero.
2020-10-07 02:44:42 +09:00
Yu Watanabe
5823a48993 network: drop networkd-ipv6-proxy-ndp.h from networkd-network.h 2020-10-07 02:44:42 +09:00
Yu Watanabe
c16b58217a network: rename ipv6_proxy_ndp_addresses_configure() -> link_set_ipv6_proxy_ndp_addresses() 2020-10-07 02:44:42 +09:00
Yu Watanabe
d349f5026e network: drop struct IPv6ProxyNDPAddress
Its only important value is in6_addr. So, let's just use struct in6_addr
and drop IPv6ProxyNDPAddress.
2020-10-07 02:44:42 +09:00
Yu Watanabe
a8c82f90e7 network: move functions 2020-10-07 02:44:42 +09:00
Yu Watanabe
dbf6319691 network: cleanup networkd-mdb.h 2020-10-07 02:44:42 +09:00
Yu Watanabe
ee4522ce86 network: introduce network_verify_mdb_entries() 2020-10-07 02:44:42 +09:00
Yu Watanabe
03c9738e1d network: drop list of bridge MDB entries
[BridgeMDB] sections are managed by LIST and Hashmap, and they contins
the completely same information. Let's drop the list.
2020-10-07 02:44:42 +09:00
Yu Watanabe
8c06da1cd1 network: move mdb_entry_free() and friends 2020-10-07 02:44:42 +09:00
Yu Watanabe
ee446d57b8 network: cleanup networkd-fdb.h 2020-10-07 02:44:42 +09:00
Yu Watanabe
75ffb011b0 network: drop unused fdb_ntf_flags_to_string() 2020-10-07 02:44:42 +09:00
Yu Watanabe
e6ad630d77 network: introduce network_verify_fdb_entries() 2020-10-07 02:44:42 +09:00
Yu Watanabe
5bb4542b0c network: move link_set_bridge_fdb() 2020-10-07 02:44:42 +09:00
Yu Watanabe
62ed9442bf network: drop list of bridge FDB entries
[BridgeFDB] sections are managed by both LIST and Hashmap, and they
contains the completely same information. Let's drop the list.
2020-10-07 02:44:42 +09:00
Yu Watanabe
df3a18f87f network: make fdb_entry_free() return NULL 2020-10-07 02:44:42 +09:00
Yu Watanabe
fb486c9082 network: cleanup networkd-address-label.h 2020-10-07 02:44:42 +09:00
Yu Watanabe
fe2bc17ca7 network: introduce link_set_address_labels() 2020-10-07 02:44:42 +09:00
Yu Watanabe
ab316813ea network: introduce network_verify_address_labels() 2020-10-07 02:44:42 +09:00
Yu Watanabe
cae418a306 network: make address_label_free() return NULL 2020-10-07 02:44:42 +09:00
Yu Watanabe
d6a2a0f9a7 network: drop list of static address labels
[IPv6AddressLabel] sections are managed by both LIST and Hashmap.
Let's drop list, as they store the completely same information.
2020-10-07 02:44:42 +09:00
Yu Watanabe
64753f354d network: make neighbor_free() return NULL 2020-10-07 02:44:42 +09:00
Yu Watanabe
78ada14f25 network: introduce network_verify_neighbors() 2020-10-07 02:44:42 +09:00
Yu Watanabe
5904833659 network: introduce neighbor_drop_{,foreign_}neighbors() 2020-10-07 02:44:42 +09:00
Yu Watanabe
1939ebeb89 network: cleanup headers in networkd-neighbor.[ch] 2020-10-07 02:44:42 +09:00
Yu Watanabe
9be0b3abc2 network: drop unused arguments 2020-10-07 02:44:42 +09:00
Yu Watanabe
0d6e933eac network: make several functions static 2020-10-07 02:44:42 +09:00
Yu Watanabe
19f8cffce1 network: make neighbor_{add,get}() takes Neighbor object 2020-10-07 02:44:42 +09:00
Yu Watanabe
b0ba6938df network: drop list of static neighbors
[Neighbor] sections are managed by both LIST and Hashmap.
Let's drop list, as they store the completely same information.
2020-10-07 02:44:42 +09:00
Yu Watanabe
eab052d2b3 network: move manager_rtnl_process_neighbor() to networkd-neighbor.c 2020-10-07 02:44:42 +09:00
Yu Watanabe
58f1fe9af9 network: move link_request_set_neighbors() to networkd-neighbor.c 2020-10-07 02:44:42 +09:00
Yu Watanabe
fceee7cc7e network: move functions 2020-10-07 02:44:42 +09:00
Yu Watanabe
0992f9fb0e network: introduce network_verify_nexthops() 2020-10-07 02:44:42 +09:00
Yu Watanabe
f96f4ebc85 network: use netlink_message_read_in_addr_union() 2020-10-07 02:44:42 +09:00
Yu Watanabe
f29b6b371e sd-netlink: introduce netlink_message_read_in_addr_union() 2020-10-07 02:44:36 +09:00
Yu Watanabe
47a277f18b network: use log_link_xxx() at more places 2020-10-07 02:39:51 +09:00
Yu Watanabe
8c11221879 network: drop NextHop::oif and always use link ifindex 2020-10-07 02:39:51 +09:00
Yu Watanabe
cf5a228f7b network: slightly shorten nexthop_compare_func() 2020-10-07 02:39:51 +09:00
Yu Watanabe
75156ccbdc network: cleanup headers included in networkd-nexthop.h 2020-10-07 02:39:51 +09:00
Yu Watanabe
b82663ddee network: drop list of static nexthops
[NextHop] sections are managed by both LIST and Hashmap.
Let's drop list, as they store the completely same information.
2020-10-07 02:39:51 +09:00
Yu Watanabe
8d7b137a82 network: drop unused nexthop_remove() and nexthop_equal() 2020-10-07 02:39:51 +09:00
Yu Watanabe
4736035aaa network: make several functions static 2020-10-07 02:39:51 +09:00
Yu Watanabe
454c87b5d5 network: move manager_rtnl_process_nexthop() to networkd-nexthop.c 2020-10-07 02:39:51 +09:00
Yu Watanabe
c133770a6b network: move link_request_set_nexthop() to networkd-nexthop.c 2020-10-07 02:39:51 +09:00
Yu Watanabe
446aaaf35f network: introduce helper function to enumerate information using netlink 2020-10-07 02:39:13 +09:00
Yu Watanabe
d08ed5a1fd network: specify all known attributes when removing routing policy rules
Otherwise, routing_policy_rule_remove() may removes unintended rule.
2020-10-07 02:36:29 +09:00
Yu Watanabe
5a82104bf3 network: add missing "else" 2020-10-07 02:36:29 +09:00
Yu Watanabe
6f3337277f network: drop unused element 2020-10-07 02:36:29 +09:00
Yu Watanabe
50a3682f1e network: introduce network_verify_routing_policy_rules() 2020-10-07 02:36:29 +09:00
Yu Watanabe
f1828a222a network: make routing_policy_rule_new() static 2020-10-07 02:36:29 +09:00
Yu Watanabe
51a0dc4a15 network: move manager_rtnl_process_rule() to networkd-routing-policy-rule.[ch] 2020-10-07 02:36:29 +09:00
Yu Watanabe
8dfed23d92 network: use typesafe macro netlink_add_match() 2020-10-07 02:36:29 +09:00
Yu Watanabe
3d65f7c863 sd-netlink: fix typo and make netlink_add_match() take description 2020-10-07 02:36:29 +09:00
Yu Watanabe
0d7d377b80 network: move log_message_warning_errno() to networkd-util.h 2020-10-07 02:36:29 +09:00
Yu Watanabe
ca183bf8fd network: drop list of static routing policy rules
[RoutingPolicyRule] sections are managed by both LIST and Hashmap.
Let's drop list.
2020-10-07 02:36:29 +09:00
Yu Watanabe
02e9f4e536 network: do not duplicate rule if Family=both 2020-10-07 02:36:29 +09:00
Yu Watanabe
b0815fa499 network: make routing_policy_rule_free() returns NULL 2020-10-07 02:36:29 +09:00
Yu Watanabe
816ef8d1da network: add more logs on loading routing policy rules failure
And reduce scope of variables.
2020-10-07 02:36:24 +09:00
Yu Watanabe
eb3445ce93 network: reduce scope of variables 2020-10-06 00:51:01 +09:00
Yu Watanabe
ddc9df3183 network: drop routing_policy_rule_make_local()
Its error handling was bogus...
2020-10-06 00:51:01 +09:00
Yu Watanabe
7532b88808 network: make several functions static 2020-10-06 00:51:01 +09:00
Yu Watanabe
c0ec474675 network: move link_request_set_routing_policy() 2020-10-06 00:51:01 +09:00
67 changed files with 4841 additions and 5072 deletions

View File

@ -266,7 +266,7 @@ static EFI_TCG * tcg1_interface_check(void) {
return tcg;
}
static EFI_TCG2 * tcg2_interface_check() {
static EFI_TCG2 * tcg2_interface_check(void) {
EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
EFI_STATUS status;
EFI_TCG2 *tcg;

View File

@ -862,11 +862,12 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ
return 0;
}
int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
int r;
int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data) {
void *attr_data;
int r;
assert_return(m, -EINVAL);
assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
if (r < 0)
@ -875,35 +876,35 @@ int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type,
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
else if ((size_t) r < sizeof(struct in_addr))
else if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
return -EIO;
if (data)
memcpy(data, attr_data, sizeof(struct in_addr));
memcpy(data, attr_data, FAMILY_ADDRESS_SIZE(family));
return 0;
}
int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
union in_addr_union u;
int r;
void *attr_data;
assert_return(m, -EINVAL);
r = netlink_message_read_in_addr_union(m, type, AF_INET, &u);
if (r >= 0 && data)
*data = u.in;
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
if (r < 0)
return r;
return r;
}
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
else if ((size_t) r < sizeof(struct in6_addr))
return -EIO;
int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
union in_addr_union u;
int r;
if (data)
memcpy(data, attr_data, sizeof(struct in6_addr));
r = netlink_message_read_in_addr_union(m, type, AF_INET6, &u);
if (r >= 0 && data)
*data = u.in6;
return 0;
return r;
}
int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret) {

View File

@ -77,18 +77,20 @@ int rtnl_log_create_error(int r);
userdata, 0, __func__); \
})
#define netlink_add_match(nl, ret_slot, metch, callback, destroy_callback, userdata) \
#define netlink_add_match(nl, ret_slot, match, callback, destroy_callback, userdata, description) \
({ \
int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \
void (*_destroy_)(typeof(userdata)) = destroy_callback; \
sd_netlink_add_match(nl, ret_slot, match, \
(sd_netlink_message_handler_t) _callback_, \
(sd_netlink_destroy_t) _destroy_, \
userdata, __func__); \
userdata, description); \
})
int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data);
int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);
int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data);
void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);
int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);

View File

@ -111,6 +111,8 @@ sources = files('''
networkd-speed-meter.h
networkd-sriov.c
networkd-sriov.h
networkd-sysctl.c
networkd-sysctl.h
networkd-util.c
networkd-util.h
networkd-wifi.c

View File

@ -13,7 +13,6 @@
#include "memory-util.h"
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-manager.h"
#include "path-util.h"
#include "socket-util.h"

View File

@ -4,6 +4,7 @@
#include <netinet/in.h>
#include <linux/if_macsec.h>
#include "ether-addr-util.h"
#include "in-addr-util.h"
#include "netdev.h"
#include "networkd-util.h"

View File

@ -4,31 +4,28 @@
#include <linux/if_addrlabel.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "networkd-address-label.h"
#include "netlink-util.h"
#include "networkd-address-label.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
#include "socket-util.h"
void address_label_free(AddressLabel *label) {
AddressLabel *address_label_free(AddressLabel *label) {
if (!label)
return;
return NULL;
if (label->network) {
LIST_REMOVE(labels, label->network->address_labels, label);
assert(label->network->n_address_labels > 0);
label->network->n_address_labels--;
if (label->section) {
hashmap_remove(label->network->address_labels_by_section, label->section);
network_config_section_free(label->section);
}
assert(label->section);
hashmap_remove(label->network->address_labels_by_section, label->section);
}
free(label);
network_config_section_free(label->section);
return mfree(label);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(address_label_freep) AddressLabel *label = NULL;
@ -36,19 +33,17 @@ static int address_label_new_static(Network *network, const char *filename, unsi
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
label = hashmap_get(network->address_labels_by_section, n);
if (label) {
*ret = TAKE_PTR(label);
return 0;
}
label = hashmap_get(network->address_labels_by_section, n);
if (label) {
*ret = TAKE_PTR(label);
return 0;
}
label = new(AddressLabel, 1);
@ -57,25 +52,18 @@ static int address_label_new_static(Network *network, const char *filename, unsi
*label = (AddressLabel) {
.network = network,
.section = TAKE_PTR(n),
};
LIST_APPEND(labels, network->address_labels, label);
network->n_address_labels++;
r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops);
if (r < 0)
return r;
if (filename) {
label->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->address_labels_by_section, label->section, label);
if (r < 0)
return r;
}
r = hashmap_put(network->address_labels_by_section, label->section, label);
if (r < 0)
return r;
*ret = TAKE_PTR(label);
return 0;
}
@ -107,12 +95,7 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
int address_label_configure(
AddressLabel *label,
Link *link,
link_netlink_message_handler_t callback,
bool update) {
static int address_label_configure(AddressLabel *label, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -140,7 +123,7 @@ int address_label_configure(
return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req,
callback ?: address_label_handler,
address_label_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@ -150,6 +133,34 @@ int address_label_configure(
return 0;
}
int link_set_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->address_label_messages++;
}
return 0;
}
void network_drop_invalid_address_labels(Network *network) {
AddressLabel *label;
assert(network);
HASHMAP_FOREACH(label, network->address_labels_by_section)
if (section_is_invalid(label->section))
address_label_free(label);
}
int config_parse_address_label_prefix(const char *unit,
const char *filename,
unsigned line,

View File

@ -2,38 +2,28 @@
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include "conf-parser.h"
#include "in-addr-util.h"
typedef struct AddressLabel AddressLabel;
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
struct AddressLabel {
typedef struct AddressLabel {
Network *network;
NetworkConfigSection *section;
unsigned char prefixlen;
uint32_t label;
union in_addr_union in_addr;
} AddressLabel;
LIST_FIELDS(AddressLabel, labels);
};
AddressLabel *address_label_free(AddressLabel *label);
void address_label_free(AddressLabel *label);
void network_drop_invalid_address_labels(Network *network);
DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
int address_label_configure(AddressLabel *address, Link *link, link_netlink_message_handler_t callback, bool update);
int link_set_address_labels(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_address_label);
CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix);

View File

@ -2,6 +2,7 @@
#include "alloc-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
#include "networkd-manager.h"
#include "set.h"
#include "string-util.h"
@ -10,15 +11,14 @@
static int address_pool_new(
Manager *m,
AddressPool **ret,
int family,
const union in_addr_union *u,
unsigned prefixlen) {
AddressPool *p;
_cleanup_free_ AddressPool *p = NULL;
int r;
assert(m);
assert(ret);
assert(u);
p = new(AddressPool, 1);
@ -32,15 +32,16 @@ static int address_pool_new(
.in_addr = *u,
};
LIST_PREPEND(address_pools, m->address_pools, p);
r = ordered_set_ensure_put(&m->address_pools, NULL, p);
if (r < 0)
return r;
*ret = p;
TAKE_PTR(p);
return 0;
}
int address_pool_new_from_string(
static int address_pool_new_from_string(
Manager *m,
AddressPool **ret,
int family,
const char *p,
unsigned prefixlen) {
@ -49,25 +50,38 @@ int address_pool_new_from_string(
int r;
assert(m);
assert(ret);
assert(p);
r = in_addr_from_string(family, p, &u);
if (r < 0)
return r;
return address_pool_new(m, ret, family, &u, prefixlen);
return address_pool_new(m, family, &u, prefixlen);
}
void address_pool_free(AddressPool *p) {
int address_pool_setup_default(Manager *m) {
int r;
if (!p)
return;
assert(m);
if (p->manager)
LIST_REMOVE(address_pools, p->manager->address_pools, p);
/* Add in the well-known private address ranges. */
r = address_pool_new_from_string(m, AF_INET6, "fd00::", 8);
if (r < 0)
return r;
free(p);
r = address_pool_new_from_string(m, AF_INET, "192.168.0.0", 16);
if (r < 0)
return r;
r = address_pool_new_from_string(m, AF_INET, "172.16.0.0", 12);
if (r < 0)
return r;
r = address_pool_new_from_string(m, AF_INET, "10.0.0.0", 8);
if (r < 0)
return r;
return 0;
}
static bool address_pool_prefix_is_taken(
@ -94,7 +108,7 @@ static bool address_pool_prefix_is_taken(
}
/* Don't clash with addresses already pulled from the pool, but not assigned yet */
LIST_FOREACH(addresses, a, l->pool_addresses) {
SET_FOREACH(a, l->pool_addresses) {
if (a->family != p->family)
continue;
@ -107,7 +121,7 @@ static bool address_pool_prefix_is_taken(
ORDERED_HASHMAP_FOREACH(n, p->manager->networks) {
Address *a;
LIST_FOREACH(addresses, a, n->static_addresses) {
ORDERED_HASHMAP_FOREACH(a, n->addresses_by_section) {
if (a->family != p->family)
continue;
@ -119,7 +133,7 @@ static bool address_pool_prefix_is_taken(
return false;
}
int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixlen, union in_addr_union *found) {
union in_addr_union u;
unsigned i;
int r;
@ -128,6 +142,9 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
assert(prefixlen > 0);
assert(found);
if (p->family != family)
return 0;
if (p->prefixlen >= prefixlen)
return 0;
@ -153,3 +170,21 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
return 0;
}
int address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
AddressPool *p;
int r;
assert(m);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(prefixlen > 0);
assert(found);
ORDERED_SET_FOREACH(p, m->address_pools) {
r = address_pool_acquire_one(p, family, prefixlen, found);
if (r != 0)
return r;
}
return 0;
}

View File

@ -1,25 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
typedef struct AddressPool AddressPool;
#include "in-addr-util.h"
#include "list.h"
typedef struct Manager Manager;
struct AddressPool {
typedef struct AddressPool {
Manager *manager;
int family;
unsigned prefixlen;
union in_addr_union in_addr;
} AddressPool;
LIST_FIELDS(AddressPool, address_pools);
};
int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen);
void address_pool_free(AddressPool *p);
int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found);
int address_pool_setup_default(Manager *m);
int address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,22 @@
#include <inttypes.h>
#include <stdbool.h>
#include "conf-parser.h"
#include "in-addr-util.h"
typedef struct Address Address;
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
#include <stdio.h>
#include "sd-ipv4acd.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "networkd-link.h"
#include "networkd-util.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef int (*address_ready_callback_t)(Address *address);
struct Address {
typedef struct Address {
Network *network;
NetworkConfigSection *section;
@ -42,39 +38,40 @@ struct Address {
bool scope_set:1;
bool ip_masquerade_done:1;
bool manage_temporary_address:1;
bool home_address:1;
bool prefix_route:1;
bool autojoin:1;
AddressFamily duplicate_address_detection;
/* Called when address become ready */
address_ready_callback_t callback;
sd_ipv4acd *acd;
LIST_FIELDS(Address, addresses);
};
} Address;
int address_new(Address **ret);
void address_free(Address *address);
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
Address *address_free(Address *address);
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
int address_drop(Address *address);
int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2);
bool address_is_ready(const Address *a);
int address_section_verify(Address *a);
int configure_ipv4_duplicate_address_detection(Link *link, Address *address);
int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
int link_set_addresses(Link *link);
int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
int link_serialize_addresses(Link *link, FILE *f);
int link_deserialize_addresses(Link *link, const char *addresses);
int ipv4_dad_stop(Link *link);
int ipv4_dad_update_mac(Link *link);
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m);
void network_drop_invalid_addresses(Network *network);
void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops;

View File

@ -146,26 +146,26 @@ static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *lin
return 1;
}
int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
int link_set_bridge_vlan(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
sd_netlink *rtnl;
uint16_t flags;
int r;
assert(link);
assert(link->manager);
assert(br_vid_bitmap);
assert(br_untagged_bitmap);
assert(link->network);
/* pvid might not be in br_vid_bitmap yet */
if (pvid)
set_bit(pvid, br_vid_bitmap);
if (!link->network->use_br_vlan)
return 0;
rtnl = link->manager->rtnl;
if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
return 0;
/* 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(rtnl, &req, RTM_SETLINK, link->ifindex);
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");
@ -179,14 +179,14 @@ int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32
/* master needs flag self */
if (!link->network->bridge) {
flags = BRIDGE_FLAGS_SELF;
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
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, pvid, br_vid_bitmap, br_untagged_bitmap);
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");
@ -195,7 +195,7 @@ int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
/* send message to the kernel */
r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
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");

View File

@ -5,8 +5,6 @@
Copyright © 2016 BISDN GmbH. All rights reserved.
***/
#include <stdint.h>
#include "conf-parser.h"
#define BRIDGE_VLAN_BITMAP_MAX 4096
@ -14,7 +12,7 @@
typedef struct Link Link;
int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap);
int link_set_bridge_vlan(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_pvid);
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_vlan);

View File

@ -1,15 +1,231 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <linux/if_arp.h>
#include "dhcp-internal.h"
#include "dhcp6-internal.h"
#include "escape.h"
#include "in-addr-util.h"
#include "networkd-dhcp-common.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
#include "socket-util.h"
#include "string-table.h"
#include "strv.h"
bool link_dhcp_enabled(Link *link, int family) {
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
if (family == AF_INET6 && !socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
if (link->network->bond)
return false;
if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
}
DUID* link_get_duid(Link *link) {
if (link->network->duid.type != _DUID_TYPE_INVALID)
return &link->network->duid;
else
return &link->manager->duid;
}
static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
assert(duid);
if (duid->raw_data_len > 0)
return 0;
if (duid->type != DUID_TYPE_UUID)
return -EINVAL;
memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
duid->raw_data_len = sizeof(sd_id128_t);
return 1;
}
static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
Manager *manager = userdata;
const sd_bus_error *e;
const void *a;
size_t sz;
DUID *duid;
Link *link;
int r;
assert(m);
assert(manager);
e = sd_bus_message_get_error(m);
if (e) {
log_error_errno(sd_bus_error_get_errno(e),
"Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
e->message);
goto configure;
}
r = sd_bus_message_read_array(m, 'y', &a, &sz);
if (r < 0)
goto configure;
if (sz != sizeof(sd_id128_t)) {
log_error("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
goto configure;
}
memcpy(&manager->product_uuid, a, sz);
while ((duid = set_steal_first(manager->duids_requesting_uuid)))
(void) duid_set_uuid(duid, manager->product_uuid);
manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
configure:
while ((link = set_steal_first(manager->links_requesting_uuid))) {
link_unref(link);
r = link_configure(link);
if (r < 0)
link_enter_failed(link);
}
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
manager->has_product_uuid = true;
return 1;
}
int manager_request_product_uuid(Manager *m, Link *link) {
int r;
assert(m);
if (m->has_product_uuid)
return 0;
log_debug("Requesting product UUID");
if (link) {
DUID *duid;
assert_se(duid = link_get_duid(link));
r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
if (r < 0)
return log_oom();
if (r > 0)
link_ref(link);
r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid);
if (r < 0)
return log_oom();
}
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, requesting product UUID later.");
return 0;
}
r = sd_bus_call_method_async(
m->bus,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
"GetProductUUID",
get_product_uuid_handler,
m,
"b",
false);
if (r < 0)
return log_warning_errno(r, "Failed to get product UUID: %m");
return 0;
}
static bool link_requires_uuid(Link *link) {
const DUID *duid;
assert(link);
assert(link->manager);
assert(link->network);
duid = link_get_duid(link);
if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
return false;
if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
return true;
if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
return true;
return false;
}
int link_configure_duid(Link *link) {
Manager *m;
DUID *duid;
int r;
assert(link);
assert(link->manager);
assert(link->network);
m = link->manager;
duid = link_get_duid(link);
if (!link_requires_uuid(link))
return 1;
if (m->has_product_uuid) {
(void) duid_set_uuid(duid, m->product_uuid);
return 1;
}
if (!m->links_requesting_uuid) {
r = manager_request_product_uuid(m, link);
if (r < 0) {
if (r == -ENOMEM)
return r;
log_link_warning_errno(link, r,
"Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
return 1;
}
} else {
r = set_put(m->links_requesting_uuid, link);
if (r < 0)
return log_oom();
if (r > 0)
link_ref(link);
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
}
return 0;
}
int config_parse_dhcp(
const char* unit,
const char *filename,

View File

@ -7,6 +7,9 @@
#define DHCP_ROUTE_METRIC 1024
typedef struct Link Link;
typedef struct Manager Manager;
typedef enum DHCPUseDomains {
DHCP_USE_DOMAINS_NO,
DHCP_USE_DOMAINS_YES,
@ -35,6 +38,18 @@ typedef struct DUID {
usec_t llt_time;
} DUID;
bool link_dhcp_enabled(Link *link, int family);
static inline bool link_dhcp4_enabled(Link *link) {
return link_dhcp_enabled(link, AF_INET);
}
static inline bool link_dhcp6_enabled(Link *link) {
return link_dhcp_enabled(link, AF_INET6);
}
DUID* link_get_duid(Link *link);
int link_configure_duid(Link *link);
int manager_request_product_uuid(Manager *m, Link *link);
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;

View File

@ -1,9 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <linux/if_arp.h>
#include <linux/if.h>
#include "sd-dhcp-server.h"
#include "fd-util.h"
#include "fileio.h"
#include "networkd-address.h"
#include "networkd-dhcp-server.h"
#include "networkd-link.h"
#include "networkd-manager.h"
@ -14,6 +19,24 @@
#include "string-util.h"
#include "strv.h"
static bool link_dhcp4_server_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
if (link->network->bond)
return false;
if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp_server;
}
static Address* link_find_dhcp_server_address(Link *link) {
Address *address;
@ -21,13 +44,13 @@ static Address* link_find_dhcp_server_address(Link *link) {
assert(link->network);
/* The first statically configured address if there is any */
LIST_FOREACH(addresses, address, link->network->static_addresses)
ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section)
if (address->family == AF_INET &&
!in_addr_is_null(address->family, &address->in_addr))
return address;
/* If that didn't work, find a suitable address we got from the pool */
LIST_FOREACH(addresses, address, link->pool_addresses)
SET_FOREACH(address, link->pool_addresses)
if (address->family == AF_INET)
return address;
@ -230,6 +253,24 @@ int dhcp4_server_configure(Link *link) {
Address *address;
int r;
assert(link);
if (!link_dhcp4_server_enabled(link))
return 0;
if (!(link->flags & IFF_UP))
return 0;
if (!link->dhcp_server) {
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;
}
address = link_find_dhcp_server_address(link);
if (!address)
return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY),
@ -341,6 +382,8 @@ int dhcp4_server_configure(Link *link) {
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");
}
return 0;

View File

@ -11,6 +11,7 @@
#include "hostname-util.h"
#include "parse-util.h"
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
#include "networkd-link.h"
#include "networkd-manager.h"
@ -384,7 +385,7 @@ static int link_set_dhcp_routes(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not set router: %m");
LIST_FOREACH(routes, rt, link->network->static_routes) {
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
if (!rt->gateway_from_dhcp)
continue;
@ -622,7 +623,7 @@ static int configure_dhcpv4_duplicate_address_detection(Link *link) {
if (r < 0)
return r;
r = sd_ipv4acd_attach_event(link->network->dhcp_acd, NULL, 0);
r = sd_ipv4acd_attach_event(link->network->dhcp_acd, link->manager->event, 0);
if (r < 0)
return r;
@ -698,7 +699,7 @@ static int dhcp4_address_ready_callback(Address *address) {
return r;
/* Reconfigure static routes as kernel may remove some routes when lease expires. */
r = link_request_set_routes(link);
r = link_set_routes(link);
if (r < 0)
return r;
@ -755,9 +756,9 @@ static int dhcp4_update_address(Link *link, bool announce) {
link_set_state(link, LINK_STATE_CONFIGURING);
link->dhcp4_configured = false;
/* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they
* are called, the related flags must be cleared. Otherwise, the link becomes configured state
* before routes are configured. */
/* address_handler calls link_set_routes() and link_set_nexthop(). Before they are called, the
* related flags must be cleared. Otherwise, the link becomes configured state before routes
* are configured. */
link->static_routes_configured = false;
link->static_nexthops_configured = false;
@ -814,7 +815,7 @@ static int dhcp4_update_address(Link *link, bool announce) {
addr->cinfo.ifa_valid = lifetime;
addr->prefixlen = prefixlen;
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
addr->prefix_route = link_prefixroute(link);
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
/* allow reusing an existing address and simply update its lifetime
* in case it already exists */
@ -1156,12 +1157,10 @@ static bool promote_secondaries_enabled(const char *ifname) {
* the primary one expires it relies on the kernel to promote the
* secondary IP. See also https://github.com/systemd/systemd/issues/7163
*/
int dhcp4_set_promote_secondaries(Link *link) {
static int dhcp4_set_promote_secondaries(Link *link) {
int r;
assert(link);
assert(link->network);
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
/* check if the kernel has promote_secondaries enabled for our
* interface. If it is not globally enabled or enabled for the
@ -1181,7 +1180,7 @@ int dhcp4_set_promote_secondaries(Link *link) {
return 0;
}
int dhcp4_set_client_identifier(Link *link) {
static int dhcp4_set_client_identifier(Link *link) {
int r;
assert(link);
@ -1240,6 +1239,25 @@ int dhcp4_set_client_identifier(Link *link) {
return 0;
}
static int dhcp4_init(Link *link) {
int r;
assert(link);
if (link->dhcp_client)
return 0;
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0)
return r;
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
if (r < 0)
return r;
return 0;
}
int dhcp4_configure(Link *link) {
sd_dhcp_option *send_option;
void *request_options;
@ -1247,19 +1265,17 @@ int dhcp4_configure(Link *link) {
assert(link);
assert(link->network);
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
if (!link->dhcp_client) {
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to create DHCP4 client: %m");
if (!link_dhcp4_enabled(link))
return 0;
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
if (r < 0)
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to attach event: %m");
}
r = dhcp4_set_promote_secondaries(link);
if (r < 0)
return r;
r = dhcp4_init(link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to initialize DHCP4 client: %m");
r = sd_dhcp_client_set_mac(link->dhcp_client,
(const uint8_t *) &link->mac,
@ -1419,6 +1435,49 @@ int dhcp4_configure(Link *link) {
return dhcp4_set_client_identifier(link);
}
int dhcp4_update_mac(Link *link) {
int r;
assert(link);
if (!link->dhcp_client)
return 0;
r = sd_dhcp_client_set_mac(link->dhcp_client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER);
if (r < 0)
return r;
r = dhcp4_set_client_identifier(link);
if (r < 0)
return r;
return 0;
}
int link_deserialize_dhcp4(Link *link, const char *dhcp4_address) {
union in_addr_union address;
int r;
assert(link);
if (isempty(dhcp4_address))
return 0;
r = in_addr_from_string(AF_INET, dhcp4_address, &address);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to parse DHCPv4 address: %s", dhcp4_address);
r = dhcp4_init(link);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to initialize DHCPv4 client: %m");
r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to set initial DHCPv4 address %s: %m", dhcp4_address);
return 0;
}
int config_parse_dhcp_max_attempts(
const char *unit,
const char *filename,

View File

@ -18,8 +18,9 @@ typedef enum DHCPClientIdentifier {
} DHCPClientIdentifier;
int dhcp4_configure(Link *link);
int dhcp4_set_client_identifier(Link *link);
int dhcp4_set_promote_secondaries(Link *link);
int dhcp4_update_mac(Link *link);
int link_deserialize_dhcp4(Link *link, const char *dhcp4_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);

View File

@ -14,6 +14,7 @@
#include "hostname-util.h"
#include "missing_network.h"
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-dhcp6.h"
#include "networkd-link.h"
#include "networkd-manager.h"
@ -24,6 +25,15 @@
#include "radv-internal.h"
#include "web-util.h"
bool link_dhcp6_pd_is_enabled(Link *link) {
assert(link);
if (!link->network)
return false;
return link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_DHCP6;
}
static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
uint32_t lifetime_preferred, lifetime_valid;
union in_addr_union pd_prefix;
@ -180,6 +190,9 @@ int dhcp6_pd_remove(Link *link) {
assert(link);
assert(link->manager);
if (!link_dhcp6_pd_is_enabled(link))
return 0;
link->dhcp6_pd_address_configured = false;
link->dhcp6_pd_route_configured = false;
@ -342,7 +355,7 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
return 1;
}
r = link_request_set_routes(link);
r = link_set_routes(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@ -425,13 +438,6 @@ static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix,
return 0;
}
bool link_dhcp6_pd_is_enabled(Link *link) {
if (!link->network)
return false;
return link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_DHCP6;
}
static bool link_has_preferred_subnet_id(Link *link) {
if (!link->network)
return false;
@ -607,9 +613,9 @@ static int dhcp6_pd_finalize(Link *link) {
link->dhcp6_pd_address_configured = true;
} else {
log_link_debug(link, "Setting DHCPv6 PD addresses");
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
* Before they are called, the related flags must be cleared. Otherwise, the link
* becomes configured state before routes are configured. */
/* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
* called, the related flags must be cleared. Otherwise, the link becomes configured
* state before routes are configured. */
link->static_routes_configured = false;
link->static_nexthops_configured = false;
}
@ -643,9 +649,6 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) {
if (link == dhcp6_link)
continue;
if (!link_dhcp6_pd_is_enabled(link))
continue;
r = dhcp6_pd_remove(link);
if (r < 0)
link_enter_failed(link);
@ -952,7 +955,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
r = link_request_set_routes(link);
r = link_set_routes(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@ -1075,9 +1078,9 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
link->dhcp6_address_configured = true;
else {
log_link_debug(link, "Setting DHCPv6 addresses");
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
* Before they are called, the related flags must be cleared. Otherwise, the link
* becomes configured state before routes are configured. */
/* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
* called, the related flags must be cleared. Otherwise, the link becomes configured
* state before routes are configured. */
link->static_routes_configured = false;
link->static_nexthops_configured = false;
}
@ -1343,40 +1346,22 @@ static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) {
return false;
}
int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
sd_dhcp6_option *vendor_option;
sd_dhcp6_option *send_option;
void *request_options;
static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
const DUID *duid;
int r;
assert(link);
assert(link->network);
assert(client);
if (link->dhcp6_client)
return 0;
r = sd_dhcp6_client_new(&client);
if (r == -ENOMEM)
return log_oom();
r = sd_dhcp6_client_set_mac(client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
r = sd_dhcp6_client_attach_event(client, NULL, 0);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
r = sd_dhcp6_client_set_mac(client,
(const uint8_t *) &link->mac,
sizeof (link->mac), ARPHRD_ETHER);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MAC address: %m");
return r;
if (link->network->iaid_set) {
r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m");
return r;
}
duid = link_get_duid(link);
@ -1388,7 +1373,40 @@ int dhcp6_configure(Link *link) {
duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
return r;
return 0;
}
int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
sd_dhcp6_option *vendor_option;
sd_dhcp6_option *send_option;
void *request_options;
int r;
assert(link);
assert(link->network);
if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
return 0;
if (link->dhcp6_client)
return 0;
r = sd_dhcp6_client_new(&client);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
r = dhcp6_set_identifier(link, client);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
r = sd_dhcp6_client_add_option(client, send_option);
@ -1471,6 +1489,57 @@ int dhcp6_configure(Link *link) {
return 0;
}
int dhcp6_update_mac(Link *link) {
bool restart;
int r;
assert(link);
if (!link->dhcp6_client)
return 0;
restart = sd_dhcp6_client_is_running(link->dhcp6_client) > 0;
if (restart) {
r = sd_dhcp6_client_stop(link->dhcp6_client);
if (r < 0)
return r;
}
r = dhcp6_set_identifier(link, link->dhcp6_client);
if (r < 0)
return r;
if (restart) {
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0)
return log_link_warning_errno(link, r, "Could not restart DHCPv6 client: %m");
}
return 0;
}
int link_serialize_dhcp6_client(Link *link, FILE *f) {
_cleanup_free_ char *duid = NULL;
uint32_t iaid;
int r;
assert(link);
if (!link->dhcp6_client)
return 0;
r = sd_dhcp6_client_get_iaid(link->dhcp6_client, &iaid);
if (r >= 0)
fprintf(f, "DHCP6_CLIENT_IAID=0x%x\n", iaid);
r = sd_dhcp6_client_duid_as_string(link->dhcp6_client, &duid);
if (r >= 0)
fprintf(f, "DHCP6_CLIENT_DUID=%s\n", duid);
return 0;
}
int config_parse_dhcp6_pd_hint(
const char* unit,
const char *filename,

View File

@ -29,9 +29,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_remove(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_update_mac(Link *link);
int dhcp6_request_address(Link *link, int ir);
int dhcp6_request_prefix_delegation(Link *link);
int link_serialize_dhcp6_client(Link *link, FILE *f);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);

View File

@ -8,27 +8,33 @@
#include "alloc-util.h"
#include "bridge.h"
#include "conf-parser.h"
#include "netlink-util.h"
#include "networkd-fdb.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
#include "string-util.h"
#include "string-table.h"
#include "util.h"
#include "vlan-util.h"
#include "vxlan.h"
#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
static const char* const fdb_ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = {
[NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use",
[NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self",
[NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master",
[NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router",
};
/* remove and FDB entry. */
FdbEntry *fdb_entry_free(FdbEntry *fdb_entry) {
if (!fdb_entry)
return NULL;
DEFINE_STRING_TABLE_LOOKUP(fdb_ntf_flags, NeighborCacheEntryFlags);
if (fdb_entry->network) {
assert(fdb_entry->section);
hashmap_remove(fdb_entry->network->fdb_entries_by_section, fdb_entry->section);
}
network_config_section_free(fdb_entry->section);
return mfree(fdb_entry);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
/* create a new FDB entry or get an existing one. */
static int fdb_entry_new_static(
@ -43,23 +49,21 @@ static int fdb_entry_new_static(
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
/* search entry in hashmap first. */
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
fdb_entry = hashmap_get(network->fdb_entries_by_section, n);
if (fdb_entry) {
*ret = TAKE_PTR(fdb_entry);
return 0;
}
fdb_entry = hashmap_get(network->fdb_entries_by_section, n);
if (fdb_entry) {
*ret = TAKE_PTR(fdb_entry);
return 0;
}
if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
if (hashmap_size(network->fdb_entries_by_section) >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
return -E2BIG;
/* allocate space for and FDB entry. */
@ -70,24 +74,18 @@ static int fdb_entry_new_static(
/* init FDB structure. */
*fdb_entry = (FdbEntry) {
.network = network,
.section = TAKE_PTR(n),
.vni = VXLAN_VID_MAX + 1,
.fdb_ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
};
LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
network->n_static_fdb_entries++;
r = hashmap_ensure_allocated(&network->fdb_entries_by_section, &network_config_hash_ops);
if (r < 0)
return r;
if (filename) {
fdb_entry->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->fdb_entries_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->fdb_entries_by_section, fdb_entry->section, fdb_entry);
if (r < 0)
return r;
}
r = hashmap_put(network->fdb_entries_by_section, fdb_entry->section, fdb_entry);
if (r < 0)
return r;
/* return allocated FDB structure. */
*ret = TAKE_PTR(fdb_entry);
@ -114,7 +112,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
}
/* send a request to the kernel to add a FDB entry in its static MAC table. */
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -171,22 +169,30 @@ int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
return 1;
}
/* remove and FDB entry. */
void fdb_entry_free(FdbEntry *fdb_entry) {
if (!fdb_entry)
return;
int link_set_bridge_fdb(Link *link) {
FdbEntry *fdb_entry;
int r;
if (fdb_entry->network) {
LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry);
assert(fdb_entry->network->n_static_fdb_entries > 0);
fdb_entry->network->n_static_fdb_entries--;
assert(link);
assert(link->network);
if (fdb_entry->section)
hashmap_remove(fdb_entry->network->fdb_entries_by_section, fdb_entry->section);
HASHMAP_FOREACH(fdb_entry, link->network->fdb_entries_by_section) {
r = fdb_entry_configure(link, fdb_entry);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
}
network_config_section_free(fdb_entry->section);
free(fdb_entry);
return 0;
}
void network_drop_invalid_fdb_entries(Network *network) {
FdbEntry *fdb_entry;
assert(network);
HASHMAP_FOREACH(fdb_entry, network->fdb_entries_by_section)
if (section_is_invalid(fdb_entry->section))
fdb_entry_free(fdb_entry);
}
/* parse the HW address from config files. */
@ -352,6 +358,15 @@ int config_parse_fdb_vxlan_vni(
return 0;
}
static const char* const fdb_ntf_flags_table[_NEIGHBOR_CACHE_ENTRY_FLAGS_MAX] = {
[NEIGHBOR_CACHE_ENTRY_FLAGS_USE] = "use",
[NEIGHBOR_CACHE_ENTRY_FLAGS_SELF] = "self",
[NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER] = "master",
[NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER] = "router",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fdb_ntf_flags, NeighborCacheEntryFlags);
int config_parse_fdb_ntf_flags(
const char *unit,
const char *filename,

View File

@ -5,17 +5,16 @@
Copyright © 2014 Intel Corporation. All rights reserved.
***/
#include <inttypes.h>
#include <linux/neighbour.h>
#include "conf-parser.h"
#include "list.h"
#include "macro.h"
#include "ether-addr-util.h"
#include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct FdbEntry FdbEntry;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef enum NeighborCacheEntryFlags {
NEIGHBOR_CACHE_ENTRY_FLAGS_USE = NTF_USE,
@ -26,7 +25,7 @@ typedef enum NeighborCacheEntryFlags {
_NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -1,
} NeighborCacheEntryFlags;
struct FdbEntry {
typedef struct FdbEntry {
Network *network;
NetworkConfigSection *section;
@ -38,17 +37,13 @@ struct FdbEntry {
struct ether_addr mac_addr;
union in_addr_union destination_addr;
NeighborCacheEntryFlags fdb_ntf_flags;
} FdbEntry;
LIST_FIELDS(FdbEntry, static_fdb_entries);
};
FdbEntry *fdb_entry_free(FdbEntry *fdb_entry);
void fdb_entry_free(FdbEntry *fdb_entry);
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
void network_drop_invalid_fdb_entries(Network *network);
DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
const char* fdb_ntf_flags_to_string(NeighborCacheEntryFlags i) _const_;
NeighborCacheEntryFlags fdb_ntf_flags_from_string(const char *s) _pure_;
int link_set_bridge_fdb(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);

View File

@ -142,23 +142,37 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
}
static int ipv4ll_init(Link *link) {
int r;
assert(link);
if (link->ipv4ll)
return 0;
r = sd_ipv4ll_new(&link->ipv4ll);
if (r < 0)
return r;
r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
if (r < 0)
return r;
return 0;
}
int ipv4ll_configure(Link *link) {
uint64_t seed;
int r;
assert(link);
assert(link->network);
assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
if (!link->ipv4ll) {
r = sd_ipv4ll_new(&link->ipv4ll);
if (r < 0)
return r;
if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
return 0;
r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
if (r < 0)
return r;
}
r = ipv4ll_init(link);
if (r < 0)
return r;
if (link->sd_device &&
net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
@ -182,6 +196,82 @@ int ipv4ll_configure(Link *link) {
return 0;
}
int ipv4ll_update_mac(Link *link) {
bool restart;
int r;
assert(link);
if (!link->ipv4ll)
return 0;
restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
if (restart) {
r = sd_ipv4ll_stop(link->ipv4ll);
if (r < 0)
return r;
}
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
if (r < 0)
return r;
if (restart) {
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0)
return r;
}
return 0;
}
int link_serialize_ipv4ll(Link *link, FILE *f) {
struct in_addr address;
int r;
assert(link);
if (!link->ipv4ll)
return 0;
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
fputs("IPV4LL_ADDRESS=", f);
serialize_in_addrs(f, &address, 1, false, NULL);
fputc('\n', f);
return 0;
}
int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address) {
union in_addr_union address;
int r;
assert(link);
if (isempty(ipv4ll_address))
return 0;
r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to parse IPv4LL address: %s", ipv4ll_address);
r = ipv4ll_init(link);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to initialize IPv4LL client: %m");
r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address);
return 0;
}
int config_parse_ipv4ll(
const char* unit,
const char *filename,

View File

@ -8,5 +8,8 @@
typedef struct Link Link;
int ipv4ll_configure(Link *link);
int ipv4ll_update_mac(Link *link);
int link_serialize_ipv4ll(Link *link, FILE *f);
int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);

View File

@ -2,9 +2,7 @@
#include <netinet/in.h>
#include <linux/if.h>
#include <unistd.h>
#include "fileio.h"
#include "netlink-util.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link.h"
@ -14,6 +12,50 @@
#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) {
int r;
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 IPv6 proxy ndp address entry, ignoring");
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) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->manager);
assert(address);
/* create new netlink message */
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
if (r < 0)
return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
r = sd_netlink_message_append_in6_addr(req, NDA_DST, address);
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,
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;
}
static bool ipv6_proxy_ndp_is_needed(Link *link) {
assert(link);
@ -26,10 +68,7 @@ static bool ipv6_proxy_ndp_is_needed(Link *link) {
if (link->network->ipv6_proxy_ndp >= 0)
return link->network->ipv6_proxy_ndp;
if (link->network->n_ipv6_proxy_ndp_addresses == 0)
return false;
return true;
return !set_isempty(link->network->ipv6_proxy_ndp_addresses);
}
static int ipv6_proxy_ndp_set(Link *link) {
@ -45,47 +84,31 @@ static int ipv6_proxy_ndp_set(Link *link) {
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
return log_link_warning_errno(link, r, "Cannot configure proxy NDP for the interface: %m");
return 0;
return v;
}
static int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
_cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
/* configure all ipv6 proxy ndp addresses */
int link_set_ipv6_proxy_ndp_addresses(Link *link) {
struct in6_addr *address;
int r;
assert(network);
assert(ret);
assert(link);
assert(link->network);
/* allocate space for IPv6ProxyNDPAddress entry */
ipv6_proxy_ndp_address = new(IPv6ProxyNDPAddress, 1);
if (!ipv6_proxy_ndp_address)
return -ENOMEM;
/* 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 r;
*ipv6_proxy_ndp_address = (IPv6ProxyNDPAddress) {
.network = network,
};
LIST_PREPEND(ipv6_proxy_ndp_addresses, network->ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address);
network->n_ipv6_proxy_ndp_addresses++;
*ret = TAKE_PTR(ipv6_proxy_ndp_address);
return 0;
}
void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
if (!ipv6_proxy_ndp_address)
return;
if (ipv6_proxy_ndp_address->network) {
LIST_REMOVE(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address->network->ipv6_proxy_ndp_addresses,
ipv6_proxy_ndp_address);
assert(ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses > 0);
ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses--;
SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) {
r = ipv6_proxy_ndp_address_configure(link, address);
if (r < 0)
return r;
}
free(ipv6_proxy_ndp_address);
return 0;
}
int config_parse_ipv6_proxy_ndp_address(
@ -100,26 +123,24 @@ int config_parse_ipv6_proxy_ndp_address(
void *data,
void *userdata) {
_cleanup_free_ struct in6_addr *address = NULL;
Network *network = userdata;
_cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
int r;
union in_addr_union buffer;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
assert(network);
r = ipv6_proxy_ndp_address_new_static(network, &ipv6_proxy_ndp_address);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
return 0;
}
r = in_addr_from_string(AF_INET6, rvalue, &buffer);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse IPv6 proxy NDP address, ignoring: %s",
rvalue);
"Failed to parse IPv6 proxy NDP address, ignoring: %s", rvalue);
return 0;
}
@ -129,76 +150,15 @@ int config_parse_ipv6_proxy_ndp_address(
return 0;
}
ipv6_proxy_ndp_address->in_addr = buffer.in6;
ipv6_proxy_ndp_address = NULL;
address = newdup(struct in6_addr, &buffer.in6, 1);
if (!address)
return log_oom();
r = set_ensure_put(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops, address);
if (r < 0)
return log_oom();
if (r > 0)
TAKE_PTR(address);
return 0;
}
static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
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 IPv6 proxy ndp address entry, ignoring");
return 1;
}
/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
sd_netlink *rtnl;
int r;
assert(link);
assert(link->network);
assert(link->manager);
assert(ipv6_proxy_ndp_address);
rtnl = link->manager->rtnl;
/* create new netlink message */
r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
if (r < 0)
return log_link_error_errno(link, r, "Could not set neighbor flags: %m");
r = sd_netlink_message_append_in6_addr(req, NDA_DST, &ipv6_proxy_ndp_address->in_addr);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = netlink_call_async(rtnl, NULL, req, set_ipv6_proxy_ndp_address_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;
}
/* configure all ipv6 proxy ndp addresses */
int ipv6_proxy_ndp_addresses_configure(Link *link) {
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
int r;
assert(link);
/* 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 r;
LIST_FOREACH(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address, link->network->ipv6_proxy_ndp_addresses) {
r = ipv6_proxy_ndp_address_configure(link, ipv6_proxy_ndp_address);
if (r != 0)
return r;
}
return 0;
}

View File

@ -2,24 +2,9 @@
#pragma once
#include "conf-parser.h"
#include "list.h"
#include "macro.h"
typedef struct Network Network;
typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
typedef struct Link Link;
struct IPv6ProxyNDPAddress {
Network *network;
struct in6_addr in_addr;
LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
};
void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
int ipv6_proxy_ndp_addresses_configure(Link *link);
DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6ProxyNDPAddress*, ipv6_proxy_ndp_address_free);
int link_set_ipv6_proxy_ndp_addresses(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address);

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
#include "sd-radv.h"
#include "sd-netlink.h"
#include "list.h"
#include "log-link.h"
#include "network-util.h"
#include "networkd-util.h"
@ -89,6 +88,7 @@ typedef struct Link {
Set *addresses;
Set *addresses_foreign;
Set *pool_addresses;
Set *static_addresses;
Set *neighbors;
Set *neighbors_foreign;
@ -127,8 +127,6 @@ typedef struct Link {
bool ipv6_mtu_set:1;
bool bridge_mdb_configured:1;
LIST_HEAD(Address, pool_addresses);
sd_dhcp_server *dhcp_server;
sd_ndisc *ndisc;
@ -193,9 +191,6 @@ typedef struct Link {
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
DUID *link_get_duid(Link *link);
int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
void link_ntp_settings_clear(Link *link);
void link_dns_settings_clear(Link *link);
Link *link_unref(Link *link);
@ -226,6 +221,8 @@ int link_save_and_clean(Link *link);
int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link);
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);
@ -237,11 +234,7 @@ int link_stop_clients(Link *link, bool may_keep_dhcp);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
uint32_t link_get_vrf_table(Link *link);
uint32_t link_get_dhcp_route_table(Link *link);
uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
int link_request_set_routes(Link *link);
int link_configure(Link *link);
int link_reconfigure(Link *link, bool force);
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);

View File

@ -9,6 +9,7 @@
#include "networkd-link.h"
#include "networkd-lldp-rx.h"
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "string-table.h"
#include "string-util.h"
@ -25,7 +26,7 @@ static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
bool link_lldp_rx_enabled(Link *link) {
static bool link_lldp_rx_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
@ -68,9 +69,18 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n
int link_lldp_rx_configure(Link *link) {
int r;
r = sd_lldp_new(&link->lldp);
if (r < 0)
return r;
if (!link_lldp_rx_enabled(link))
return 0;
if (!link->lldp) {
r = sd_lldp_new(&link->lldp);
if (r < 0)
return r;
r = sd_lldp_attach_event(link->lldp, link->manager->event, 0);
if (r < 0)
return r;
}
r = sd_lldp_set_ifindex(link->lldp, link->ifindex);
if (r < 0)
@ -87,10 +97,6 @@ int link_lldp_rx_configure(Link *link) {
if (r < 0)
return r;
r = sd_lldp_attach_event(link->lldp, NULL, 0);
if (r < 0)
return r;
r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
if (r < 0)
return r;

View File

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include "conf-parser.h"
typedef struct Link Link;
@ -15,7 +13,6 @@ typedef enum LLDPMode {
_LLDP_MODE_INVALID = -1,
} LLDPMode;
bool link_lldp_rx_enabled(Link *link);
int link_lldp_rx_configure(Link *link);
int link_update_lldp(Link *link);
int link_lldp_save(Link *link);

View File

@ -367,7 +367,7 @@ int link_lldp_emit_start(Link *link) {
assert(link);
if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
if (!link_lldp_emit_enabled(link)) {
link_lldp_emit_stop(link);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -10,12 +10,11 @@
#include "dhcp-identifier.h"
#include "hashmap.h"
#include "list.h"
#include "time-util.h"
#include "networkd-address-pool.h"
#include "networkd-link.h"
#include "networkd-network.h"
#include "ordered-set.h"
#include "set.h"
#include "time-util.h"
struct Manager {
sd_netlink *rtnl;
@ -45,7 +44,7 @@ struct Manager {
OrderedHashmap *networks;
Hashmap *dhcp6_prefixes;
Set *dhcp6_pd_prefixes;
LIST_HEAD(AddressPool, address_pools);
OrderedSet *address_pools;
usec_t network_dirs_ts_usec;
@ -82,27 +81,13 @@ int manager_start(Manager *m);
int manager_load_config(Manager *m);
bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
int manager_rtnl_enumerate_neighbors(Manager *m);
int manager_rtnl_enumerate_routes(Manager *m);
int manager_rtnl_enumerate_rules(Manager *m);
int manager_rtnl_enumerate_nexthop(Manager *m);
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_neighbor(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_rule(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_nexthop(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_enumerate(Manager *m);
void manager_dirty(Manager *m);
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);
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);
int manager_request_product_uuid(Manager *m, Link *link);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);

View File

@ -3,13 +3,32 @@
#include <net/if.h>
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-mdb.h"
#include "networkd-network.h"
#include "string-util.h"
#include "vlan-util.h"
#define STATIC_MDB_ENTRIES_PER_NETWORK_MAX 1024U
/* remove MDB entry. */
MdbEntry *mdb_entry_free(MdbEntry *mdb_entry) {
if (!mdb_entry)
return NULL;
if (mdb_entry->network) {
assert(mdb_entry->section);
hashmap_remove(mdb_entry->network->mdb_entries_by_section, mdb_entry->section);
}
network_config_section_free(mdb_entry->section);
return mfree(mdb_entry);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
/* create a new MDB entry or get an existing one. */
static int mdb_entry_new_static(
Network *network,
@ -23,22 +42,21 @@ static int mdb_entry_new_static(
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
/* search entry in hashmap first. */
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
if (mdb_entry) {
*ret = TAKE_PTR(mdb_entry);
return 0;
}
mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
if (mdb_entry) {
*ret = TAKE_PTR(mdb_entry);
return 0;
}
if (network->n_static_mdb_entries >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
if (hashmap_size(network->mdb_entries_by_section) >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
return -E2BIG;
/* allocate space for an MDB entry. */
@ -49,48 +67,22 @@ static int mdb_entry_new_static(
/* init MDB structure. */
*mdb_entry = (MdbEntry) {
.network = network,
.section = TAKE_PTR(n),
};
LIST_PREPEND(static_mdb_entries, network->static_mdb_entries, mdb_entry);
network->n_static_mdb_entries++;
r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops);
if (r < 0)
return r;
if (filename) {
mdb_entry->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry);
if (r < 0)
return r;
}
r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry);
if (r < 0)
return r;
/* return allocated MDB structure. */
*ret = TAKE_PTR(mdb_entry);
return 0;
}
/* remove and MDB entry. */
MdbEntry *mdb_entry_free(MdbEntry *mdb_entry) {
if (!mdb_entry)
return NULL;
if (mdb_entry->network) {
LIST_REMOVE(static_mdb_entries, mdb_entry->network->static_mdb_entries, mdb_entry);
assert(mdb_entry->network->n_static_mdb_entries > 0);
mdb_entry->network->n_static_mdb_entries--;
if (mdb_entry->section)
hashmap_remove(mdb_entry->network->mdb_entries_by_section, mdb_entry->section);
}
network_config_section_free(mdb_entry->section);
return mfree(mdb_entry);
}
static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@ -212,7 +204,7 @@ int link_set_bridge_mdb(Link *link) {
if (!link->network)
return 0;
if (LIST_IS_EMPTY(link->network->static_mdb_entries))
if (hashmap_isempty(link->network->mdb_entries_by_section))
goto finish;
if (!link_has_carrier(link))
@ -236,7 +228,7 @@ int link_set_bridge_mdb(Link *link) {
goto finish;
}
LIST_FOREACH(static_mdb_entries, mdb_entry, link->network->static_mdb_entries) {
HASHMAP_FOREACH(mdb_entry, link->network->mdb_entries_by_section) {
r = mdb_entry_configure(link, mdb_entry);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
@ -253,6 +245,49 @@ finish:
return 0;
}
static int mdb_entry_verify(MdbEntry *mdb_entry) {
if (section_is_invalid(mdb_entry->section))
return -EINVAL;
if (mdb_entry->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);
if (!in_addr_is_multicast(mdb_entry->family, &mdb_entry->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);
if (mdb_entry->family == AF_INET) {
if (in4_addr_is_local_multicast(&mdb_entry->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);
} else {
if (in6_addr_is_link_local_all_nodes(&mdb_entry->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);
}
return 0;
}
void network_drop_invalid_mdb_entries(Network *network) {
MdbEntry *mdb_entry;
assert(network);
HASHMAP_FOREACH(mdb_entry, network->mdb_entries_by_section)
if (mdb_entry_verify(mdb_entry) < 0)
mdb_entry_free(mdb_entry);
}
/* parse the VLAN Id from config files. */
int config_parse_mdb_vlan_id(
const char *unit,
@ -328,36 +363,3 @@ int config_parse_mdb_group_address(
return 0;
}
int mdb_entry_verify(MdbEntry *mdb_entry) {
if (section_is_invalid(mdb_entry->section))
return -EINVAL;
if (mdb_entry->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);
if (!in_addr_is_multicast(mdb_entry->family, &mdb_entry->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);
if (mdb_entry->family == AF_INET) {
if (in4_addr_is_local_multicast(&mdb_entry->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);
} else {
if (in6_addr_is_link_local_all_nodes(&mdb_entry->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);
}
return 0;
}

View File

@ -1,32 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include "conf-parser.h"
#include "list.h"
#include "macro.h"
#include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Network Network;
typedef struct MdbEntry MdbEntry;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
struct MdbEntry {
typedef struct MdbEntry {
Network *network;
NetworkConfigSection *section;
int family;
union in_addr_union group_addr;
uint16_t vlan_id;
} MdbEntry;
LIST_FIELDS(MdbEntry, static_mdb_entries);
};
int mdb_entry_verify(MdbEntry *mdb_entry);
MdbEntry *mdb_entry_free(MdbEntry *mdb_entry);
int link_set_bridge_mdb(Link *link);
DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
void network_drop_invalid_mdb_entries(Network *network);
int link_set_bridge_mdb(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id);

View File

@ -3,16 +3,18 @@
Copyright © 2014 Intel Corporation. All rights reserved.
***/
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <netinet/icmp6.h>
#include <linux/if.h>
#include "sd-ndisc.h"
#include "missing_network.h"
#include "networkd-address.h"
#include "networkd-dhcp6.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-route.h"
#include "networkd-sysctl.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
@ -35,6 +37,36 @@
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
bool link_ipv6_accept_ra_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
if (!link_ipv6ll_enabled(link))
return false;
/* If unset use system default (enabled if local forwarding is disabled.
* disabled if local forwarding is enabled).
* If set, ignore or enforce RA independent of local forwarding state.
*/
if (link->network->ipv6_accept_ra < 0)
/* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
return !link_ip_forward_enabled(link, AF_INET6);
else if (link->network->ipv6_accept_ra > 0)
/* accept RA even if ip_forward is enabled */
return true;
else
/* ignore RA */
return false;
}
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
static int ndisc_address_callback(Address *address) {
@ -368,7 +400,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
r = link_request_set_routes(link);
r = link_set_routes(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@ -490,7 +522,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, r, "Could not set default route: %m");
Route *route_gw;
LIST_FOREACH(routes, route_gw, link->network->static_routes) {
HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
if (!route_gw->gateway_from_dhcp)
continue;
@ -1133,9 +1165,9 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
else {
log_link_debug(link, "Setting SLAAC addresses.");
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
* Before they are called, the related flags must be cleared. Otherwise, the link
* becomes configured state before routes are configured. */
/* address_handler calls link_set_routes() and link_set_nexthop(). Before they are
* called, the related flags must be cleared. Otherwise, the link becomes configured
* state before routes are configured. */
link->static_routes_configured = false;
link->static_nexthops_configured = false;
}
@ -1194,13 +1226,18 @@ int ndisc_configure(Link *link) {
assert(link);
r = sd_ndisc_new(&link->ndisc);
if (r < 0)
return r;
if (!link_ipv6_accept_ra_enabled(link))
return 0;
r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
if (r < 0)
return r;
if (!link->ndisc) {
r = sd_ndisc_new(&link->ndisc);
if (r < 0)
return r;
r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
if (r < 0)
return r;
}
r = sd_ndisc_set_mac(link->ndisc, &link->mac);
if (r < 0)

View File

@ -69,6 +69,8 @@ static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
}
bool link_ipv6_accept_ra_enabled(Link *link);
int ndisc_configure(Link *link);
void ndisc_vacuum(Link *link);
void ndisc_flush(Link *link);

View File

@ -1,29 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "sd-netlink.h"
#include "alloc-util.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "hashmap.h"
#include "in-addr-util.h"
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-neighbor.h"
#include "networkd-network.h"
#include "set.h"
void neighbor_free(Neighbor *neighbor) {
Neighbor *neighbor_free(Neighbor *neighbor) {
if (!neighbor)
return;
return NULL;
if (neighbor->network) {
LIST_REMOVE(neighbors, neighbor->network->neighbors, neighbor);
assert(neighbor->network->n_neighbors > 0);
neighbor->network->n_neighbors--;
if (neighbor->section)
hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
assert(neighbor->section);
hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
}
network_config_section_free(neighbor->section);
@ -33,9 +25,11 @@ void neighbor_free(Neighbor *neighbor) {
set_remove(neighbor->link->neighbors_foreign, neighbor);
}
free(neighbor);
return mfree(neighbor);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
@ -43,19 +37,17 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
neighbor = hashmap_get(network->neighbors_by_section, n);
if (neighbor) {
*ret = TAKE_PTR(neighbor);
return 0;
}
neighbor = hashmap_get(network->neighbors_by_section, n);
if (neighbor) {
*ret = TAKE_PTR(neighbor);
return 0;
}
neighbor = new(Neighbor, 1);
@ -65,143 +57,18 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
*neighbor = (Neighbor) {
.network = network,
.family = AF_UNSPEC,
.section = TAKE_PTR(n),
};
LIST_APPEND(neighbors, network->neighbors, neighbor);
network->n_neighbors++;
r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
if (r < 0)
return r;
if (filename) {
neighbor->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
if (r < 0)
return r;
}
r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
if (r < 0)
return r;
*ret = TAKE_PTR(neighbor);
return 0;
}
static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->neighbor_messages > 0);
link->neighbor_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
/* Neighbor may not exist yet. So, do not enter failed state here. */
log_link_message_warning_errno(link, m, r, "Could not set neighbor, ignoring");
if (link->neighbor_messages == 0) {
log_link_debug(link, "Neighbors set");
link->neighbors_configured = true;
link_check_ready(link);
}
return 1;
}
int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(neighbor);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
if (r < 0)
return log_link_error_errno(link, r, "Could not set state: %m");
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);
if (r < 0)
return log_link_error_errno(link, r, "Could not set flags: %m");
r = sd_netlink_message_append_data(req, NDA_LLADDR, &neighbor->lladdr, neighbor->lladdr_size);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
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, callback ?: neighbor_configure_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link->neighbor_messages++;
link_ref(link);
r = neighbor_add(link, neighbor->family, &neighbor->in_addr, &neighbor->lladdr, neighbor->lladdr_size, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Could not add neighbor: %m");
return 0;
}
static int neighbor_remove_handler(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 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
/* Neighbor may not exist because it already got deleted, ignore that. */
log_link_message_warning_errno(link, m, r, "Could not remove neighbor");
return 1;
}
int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(neighbor);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_DELNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
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, callback ?: neighbor_remove_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;
}
@ -249,28 +116,20 @@ static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
Neighbor neighbor, *existing;
static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
Neighbor *existing;
assert(link);
assert(addr);
assert(lladdr);
assert(in);
neighbor = (Neighbor) {
.family = family,
.in_addr = *addr,
.lladdr = *lladdr,
.lladdr_size = lladdr_size,
};
existing = set_get(link->neighbors, &neighbor);
existing = set_get(link->neighbors, in);
if (existing) {
if (ret)
*ret = existing;
return 1;
}
existing = set_get(link->neighbors_foreign, &neighbor);
existing = set_get(link->neighbors_foreign, in);
if (existing) {
if (ret)
*ret = existing;
@ -280,24 +139,23 @@ int neighbor_get(Link *link, int family, const union in_addr_union *addr, const
return -ENOENT;
}
static int neighbor_add_internal(Link *link, Set **neighbors, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in, Neighbor **ret) {
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
int r;
assert(link);
assert(neighbors);
assert(addr);
assert(lladdr);
assert(in);
neighbor = new(Neighbor, 1);
if (!neighbor)
return -ENOMEM;
*neighbor = (Neighbor) {
.family = family,
.in_addr = *addr,
.lladdr = *lladdr,
.lladdr_size = lladdr_size,
.family = in->family,
.in_addr = in->in_addr,
.lladdr = in->lladdr,
.lladdr_size = in->lladdr_size,
};
r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor);
@ -310,19 +168,19 @@ static int neighbor_add_internal(Link *link, Set **neighbors, int family, const
if (ret)
*ret = neighbor;
TAKE_PTR(neighbor);
TAKE_PTR(neighbor);
return 0;
}
int neighbor_add(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) {
Neighbor *neighbor;
int r;
r = neighbor_get(link, family, addr, lladdr, lladdr_size, &neighbor);
r = neighbor_get(link, in, &neighbor);
if (r == -ENOENT) {
/* Neighbor doesn't exist, make a new one */
r = neighbor_add_internal(link, &link->neighbors, family, addr, lladdr, lladdr_size, &neighbor);
r = neighbor_add_internal(link, &link->neighbors, in, &neighbor);
if (r < 0)
return r;
} else if (r == 0) {
@ -342,11 +200,11 @@ int neighbor_add(Link *link, int family, const union in_addr_union *addr, const
return 0;
}
int neighbor_add_foreign(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret) {
return neighbor_add_internal(link, &link->neighbors_foreign, family, addr, lladdr, lladdr_size, ret);
static int neighbor_add_foreign(Link *link, const Neighbor *in, Neighbor **ret) {
return neighbor_add_internal(link, &link->neighbors_foreign, in, ret);
}
bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
static bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
if (n1 == n2)
return true;
@ -356,7 +214,365 @@ bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
return neighbor_compare_func(n1, n2) == 0;
}
int neighbor_section_verify(Neighbor *neighbor) {
static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->neighbor_messages > 0);
link->neighbor_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
/* Neighbor may not exist yet. So, do not enter failed state here. */
log_link_message_warning_errno(link, m, r, "Could not set neighbor, ignoring");
if (link->neighbor_messages == 0) {
log_link_debug(link, "Neighbors set");
link->neighbors_configured = true;
link_check_ready(link);
}
return 1;
}
static int neighbor_configure(Neighbor *neighbor, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(neighbor);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_NEWNEIGH message: %m");
r = sd_rtnl_message_neigh_set_state(req, NUD_PERMANENT);
if (r < 0)
return log_link_error_errno(link, r, "Could not set state: %m");
r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);
if (r < 0)
return log_link_error_errno(link, r, "Could not set flags: %m");
r = sd_netlink_message_append_data(req, NDA_LLADDR, &neighbor->lladdr, neighbor->lladdr_size);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_LLADDR attribute: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
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, neighbor_configure_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link->neighbor_messages++;
link_ref(link);
r = neighbor_add(link, neighbor, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Could not add neighbor: %m");
return 0;
}
int link_set_neighbors(Link *link) {
Neighbor *neighbor;
int r;
assert(link);
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
link->neighbors_configured = false;
HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
r = neighbor_configure(neighbor, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set neighbor: %m");
}
if (link->neighbor_messages == 0) {
link->neighbors_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting neighbors");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
static int neighbor_remove_handler(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 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
/* Neighbor may not exist because it already got deleted, ignore that. */
log_link_message_warning_errno(link, m, r, "Could not remove neighbor");
return 1;
}
static int neighbor_remove(Neighbor *neighbor, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(neighbor);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_DELNEIGH,
link->ifindex, neighbor->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
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, neighbor_remove_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;
}
static bool link_is_neighbor_configured(Link *link, Neighbor *neighbor) {
Neighbor *net_neighbor;
assert(link);
assert(neighbor);
if (!link->network)
return false;
HASHMAP_FOREACH(net_neighbor, link->network->neighbors_by_section)
if (neighbor_equal(net_neighbor, neighbor))
return true;
return false;
}
int link_drop_foreign_neighbors(Link *link) {
Neighbor *neighbor;
int r;
assert(link);
SET_FOREACH(neighbor, link->neighbors_foreign)
if (link_is_neighbor_configured(link, neighbor)) {
r = neighbor_add(link, neighbor, NULL);
if (r < 0)
return r;
} else {
r = neighbor_remove(neighbor, link);
if (r < 0)
return r;
}
return 0;
}
int link_drop_neighbors(Link *link) {
Neighbor *neighbor;
int k, r = 0;
assert(link);
SET_FOREACH(neighbor, link->neighbors) {
k = neighbor_remove(neighbor, link);
if (k < 0 && r >= 0)
r = k;
}
return r;
}
static int manager_rtnl_process_neighbor_lladdr(sd_netlink_message *message, union lladdr_union *lladdr, size_t *size, char **str) {
int r;
assert(message);
assert(lladdr);
assert(size);
assert(str);
*str = NULL;
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in6), &lladdr->ip.in6);
if (r >= 0) {
*size = sizeof(lladdr->ip.in6);
if (in_addr_to_string(AF_INET6, &lladdr->ip, str) < 0)
log_warning_errno(r, "Could not print lower address: %m");
return r;
}
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->mac), &lladdr->mac);
if (r >= 0) {
*size = sizeof(lladdr->mac);
*str = new(char, ETHER_ADDR_TO_STRING_MAX);
if (!*str) {
log_oom();
return r;
}
ether_addr_to_string(&lladdr->mac, *str);
return r;
}
r = sd_netlink_message_read(message, NDA_LLADDR, sizeof(lladdr->ip.in), &lladdr->ip.in);
if (r >= 0) {
*size = sizeof(lladdr->ip.in);
if (in_addr_to_string(AF_INET, &lladdr->ip, str) < 0)
log_warning_errno(r, "Could not print lower address: %m");
return r;
}
return r;
}
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(neighbor_freep) Neighbor *tmp = NULL;
_cleanup_free_ char *addr_str = NULL, *lladdr_str = NULL;
Neighbor *neighbor = NULL;
uint16_t type, state;
int ifindex, r;
Link *link;
assert(rtnl);
assert(message);
assert(m);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
return 0;
}
r = sd_netlink_message_get_type(message, &type);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
return 0;
} else if (!IN_SET(type, RTM_NEWNEIGH, RTM_DELNEIGH)) {
log_warning("rtnl: received unexpected message type %u when processing neighbor, ignoring.", type);
return 0;
}
r = sd_rtnl_message_neigh_get_state(message, &state);
if (r < 0) {
log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
return 0;
} else if (!FLAGS_SET(state, NUD_PERMANENT)) {
log_debug("rtnl: received non-static neighbor, ignoring.");
return 0;
}
r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received neighbor message with invalid ifindex %d, ignoring.", ifindex);
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0 || !link) {
/* when enumerating we might be out of sync, but we will get the neighbor again, so just
* ignore it */
if (!m->enumerating)
log_warning("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex);
return 0;
}
tmp = new0(Neighbor, 1);
r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
if (r < 0) {
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
return 0;
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
return 0;
}
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
return 0;
}
if (in_addr_to_string(tmp->family, &tmp->in_addr, &addr_str) < 0)
log_link_warning_errno(link, r, "Could not print address: %m");
r = manager_rtnl_process_neighbor_lladdr(message, &tmp->lladdr, &tmp->lladdr_size, &lladdr_str);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received neighbor message with invalid lladdr, ignoring: %m");
return 0;
}
(void) neighbor_get(link, tmp, &neighbor);
switch (type) {
case RTM_NEWNEIGH:
if (neighbor)
log_link_debug(link, "Received remembered neighbor: %s->%s",
strnull(addr_str), strnull(lladdr_str));
else {
/* A neighbor appeared that we did not request */
r = neighbor_add_foreign(link, tmp, NULL);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember foreign neighbor %s->%s, ignoring: %m",
strnull(addr_str), strnull(lladdr_str));
return 0;
} else
log_link_debug(link, "Remembering foreign neighbor: %s->%s",
strnull(addr_str), strnull(lladdr_str));
}
break;
case RTM_DELNEIGH:
if (neighbor) {
log_link_debug(link, "Forgetting neighbor: %s->%s",
strnull(addr_str), strnull(lladdr_str));
(void) neighbor_free(neighbor);
} else
log_link_debug(link, "Kernel removed a neighbor we don't remember: %s->%s, ignoring.",
strnull(addr_str), strnull(lladdr_str));
break;
default:
assert_not_reached("Received invalid RTNL message type");
}
return 1;
}
static int neighbor_section_verify(Neighbor *neighbor) {
if (section_is_invalid(neighbor->section))
return -EINVAL;
@ -375,6 +591,17 @@ int neighbor_section_verify(Neighbor *neighbor) {
return 0;
}
void network_drop_invalid_neighbors(Network *network) {
Neighbor *neighbor;
assert(network);
HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
if (neighbor_section_verify(neighbor) < 0)
neighbor_free(neighbor);
}
int config_parse_neighbor_address(
const char *unit,
const char *filename,

View File

@ -1,26 +1,25 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include "sd-netlink.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "in-addr-util.h"
#include "list.h"
#include "macro.h"
typedef struct Neighbor Neighbor;
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
typedef Manager Manager;
typedef Network Network;
typedef Link Link;
union lladdr_union {
struct ether_addr mac;
union in_addr_union ip;
};
struct Neighbor {
typedef struct Neighbor {
Network *network;
Link *link;
NetworkConfigSection *section;
@ -29,23 +28,17 @@ struct Neighbor {
union in_addr_union in_addr;
union lladdr_union lladdr;
size_t lladdr_size;
} Neighbor;
LIST_FIELDS(Neighbor, neighbors);
};
Neighbor *neighbor_free(Neighbor *neighbor);
void neighbor_free(Neighbor *neighbor);
void network_drop_invalid_neighbors(Network *network);
DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
int link_set_neighbors(Link *link);
int link_drop_neighbors(Link *link);
int link_drop_foreign_neighbors(Link *link);
int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
int neighbor_remove(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
int neighbor_get(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
int neighbor_add(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
int neighbor_add_foreign(Link *link, int family, const union in_addr_union *addr, const union lladdr_union *lladdr, size_t lladdr_size, Neighbor **ret);
bool neighbor_equal(const Neighbor *n1, const Neighbor *n2);
int neighbor_section_verify(Neighbor *neighbor);
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_hwaddr);

View File

@ -6,15 +6,25 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "conf-parser.h"
#include "netem.h"
#include "network-internal.h"
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-can.h"
#include "networkd-conf.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
#include "networkd-fdb.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"
#include "networkd-nexthop.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sriov.h"
#include "qdisc.h"
#include "tclass.h"
@ -121,11 +131,11 @@ Address.Peer, config_parse_address,
Address.Broadcast, config_parse_broadcast, 0, 0
Address.Label, config_parse_label, 0, 0
Address.PreferredLifetime, config_parse_lifetime, 0, 0
Address.HomeAddress, config_parse_address_flags, 0, 0
Address.ManageTemporaryAddress, config_parse_address_flags, 0, 0
Address.PrefixRoute, config_parse_address_flags, 0, 0 /* deprecated */
Address.AddPrefixRoute, config_parse_address_flags, 0, 0
Address.AutoJoin, config_parse_address_flags, 0, 0
Address.HomeAddress, config_parse_address_flags, IFA_F_HOMEADDRESS, 0
Address.ManageTemporaryAddress, config_parse_address_flags, IFA_F_MANAGETEMPADDR, 0
Address.PrefixRoute, config_parse_address_flags, IFA_F_NOPREFIXROUTE, 0 /* deprecated */
Address.AddPrefixRoute, config_parse_address_flags, IFA_F_NOPREFIXROUTE, 0
Address.AutoJoin, config_parse_address_flags, IFA_F_MCAUTOJOIN, 0
Address.DuplicateAddressDetection, config_parse_duplicate_address_detection, 0, 0
Address.Scope, config_parse_address_scope, 0, 0
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0

View File

@ -14,8 +14,16 @@
#include "in-addr-util.h"
#include "networkd-dhcp-server.h"
#include "network-internal.h"
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-fdb.h"
#include "networkd-manager.h"
#include "networkd-mdb.h"
#include "networkd-neighbor.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-radv.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sriov.h"
#include "parse-util.h"
#include "path-lookup.h"
@ -148,19 +156,6 @@ static int network_resolve_stacked_netdevs(Network *network) {
}
int network_verify(Network *network) {
RoutePrefix *route_prefix, *route_prefix_next;
RoutingPolicyRule *rule, *rule_next;
Neighbor *neighbor, *neighbor_next;
AddressLabel *label, *label_next;
NextHop *nexthop, *nextnop_next;
Address *address, *address_next;
Prefix *prefix, *prefix_next;
Route *route, *route_next;
FdbEntry *fdb, *fdb_next;
MdbEntry *mdb, *mdb_next;
TrafficControl *tc;
SRIOV *sr_iov;
assert(network);
assert(network->filename);
@ -213,18 +208,15 @@ int network_verify(Network *network) {
network->filename);
network->dhcp_server = false;
}
if (network->n_static_addresses > 0) {
if (!ordered_hashmap_isempty(network->addresses_by_section))
log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
network->filename);
while ((address = network->static_addresses))
address_free(address);
}
if (network->n_static_routes > 0) {
if (!hashmap_isempty(network->routes_by_section))
log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
network->filename);
while ((route = network->static_routes))
route_free(route);
}
network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
}
if (network->link_local < 0)
@ -290,54 +282,23 @@ int network_verify(Network *network) {
if (network->keep_configuration < 0)
network->keep_configuration = KEEP_CONFIGURATION_NO;
LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
if (address_section_verify(address) < 0)
address_free(address);
if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
}
LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
if (route_section_verify(route, network) < 0)
route_free(route);
LIST_FOREACH_SAFE(nexthops, nexthop, nextnop_next, network->static_nexthops)
if (nexthop_section_verify(nexthop) < 0)
nexthop_free(nexthop);
LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
if (section_is_invalid(fdb->section))
fdb_entry_free(fdb);
LIST_FOREACH_SAFE(static_mdb_entries, mdb, mdb_next, network->static_mdb_entries)
if (mdb_entry_verify(mdb) < 0)
mdb_entry_free(mdb);
LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
if (neighbor_section_verify(neighbor) < 0)
neighbor_free(neighbor);
LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
if (section_is_invalid(label->section))
address_label_free(label);
LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
if (section_is_invalid(prefix->section))
prefix_free(prefix);
LIST_FOREACH_SAFE(route_prefixes, route_prefix, route_prefix_next, network->static_route_prefixes)
if (section_is_invalid(route_prefix->section))
route_prefix_free(route_prefix);
LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
if (routing_policy_rule_section_verify(rule) < 0)
routing_policy_rule_free(rule);
bool has_root = false, has_clsact = false;
ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section)
if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
traffic_control_free(tc);
ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
if (sr_iov_section_verify(sr_iov) < 0)
sr_iov_free(sr_iov);
network_drop_invalid_addresses(network);
network_drop_invalid_routes(network);
network_drop_invalid_nexthops(network);
network_drop_invalid_fdb_entries(network);
network_drop_invalid_mdb_entries(network);
network_drop_invalid_neighbors(network);
network_drop_invalid_address_labels(network);
network_drop_invalid_prefixes(network);
network_drop_invalid_route_prefixes(network);
network_drop_invalid_routing_policy_rules(network);
network_drop_invalid_traffic_control(network);
network_drop_invalid_sr_iov(network);
return 0;
}
@ -644,18 +605,6 @@ failure:
}
static Network *network_free(Network *network) {
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
RoutePrefix *route_prefix;
RoutingPolicyRule *rule;
AddressLabel *label;
FdbEntry *fdb_entry;
MdbEntry *mdb_entry;
Neighbor *neighbor;
Address *address;
NextHop *nexthop;
Prefix *prefix;
Route *route;
if (!network)
return NULL;
@ -711,49 +660,17 @@ static Network *network_free(Network *network) {
netdev_unref(network->vrf);
hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
while ((route = network->static_routes))
route_free(route);
while ((nexthop = network->static_nexthops))
nexthop_free(nexthop);
while ((address = network->static_addresses))
address_free(address);
while ((fdb_entry = network->static_fdb_entries))
fdb_entry_free(fdb_entry);
while ((mdb_entry = network->static_mdb_entries))
mdb_entry_free(mdb_entry);
while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
while ((neighbor = network->neighbors))
neighbor_free(neighbor);
while ((label = network->address_labels))
address_label_free(label);
while ((prefix = network->static_prefixes))
prefix_free(prefix);
while ((route_prefix = network->static_route_prefixes))
route_prefix_free(route_prefix);
while ((rule = network->rules))
routing_policy_rule_free(rule);
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
hashmap_free(network->nexthops_by_section);
hashmap_free(network->fdb_entries_by_section);
hashmap_free(network->mdb_entries_by_section);
hashmap_free(network->neighbors_by_section);
hashmap_free(network->address_labels_by_section);
hashmap_free(network->prefixes_by_section);
hashmap_free(network->route_prefixes_by_section);
hashmap_free(network->rules_by_section);
set_free_free(network->ipv6_proxy_ndp_addresses);
ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
hashmap_free_with_destructor(network->routes_by_section, route_free);
hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free);
hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
@ -866,30 +783,33 @@ bool network_has_static_ipv6_configurations(Network *network) {
assert(network);
LIST_FOREACH(addresses, address, network->static_addresses)
ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
if (address->family == AF_INET6)
return true;
LIST_FOREACH(routes, route, network->static_routes)
HASHMAP_FOREACH(route, network->routes_by_section)
if (route->family == AF_INET6)
return true;
LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
HASHMAP_FOREACH(fdb, network->fdb_entries_by_section)
if (fdb->family == AF_INET6)
return true;
LIST_FOREACH(static_mdb_entries, mdb, network->static_mdb_entries)
HASHMAP_FOREACH(mdb, network->mdb_entries_by_section)
if (mdb->family == AF_INET6)
return true;
LIST_FOREACH(neighbors, neighbor, network->neighbors)
HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
if (neighbor->family == AF_INET6)
return true;
if (!LIST_IS_EMPTY(network->address_labels))
if (!hashmap_isempty(network->address_labels_by_section))
return true;
if (!LIST_IS_EMPTY(network->static_prefixes))
if (!hashmap_isempty(network->prefixes_by_section))
return true;
if (!hashmap_isempty(network->route_prefixes_by_section))
return true;
return false;
@ -1026,95 +946,6 @@ int config_parse_domains(
}
}
int config_parse_ipv6token(
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) {
union in_addr_union buffer;
struct in6_addr *token = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(token);
r = in_addr_from_string(AF_INET6, rvalue, &buffer);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse IPv6 token, ignoring: %s", rvalue);
return 0;
}
if (in_addr_is_null(AF_INET6, &buffer)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
return 0;
}
if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
return 0;
}
*token = buffer.in6;
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",
[IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
IPV6_PRIVACY_EXTENSIONS_YES);
int config_parse_ipv6_privacy_extensions(
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) {
IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(ipv6_privacy_extensions);
s = ipv6_privacy_extensions_from_string(rvalue);
if (s < 0) {
if (streq(rvalue, "kernel"))
s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
else {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
return 0;
}
}
*ipv6_privacy_extensions = s;
return 0;
}
int config_parse_hostname(
const char *unit,
const char *filename,

View File

@ -12,38 +12,21 @@
#include "conf-parser.h"
#include "hashmap.h"
#include "netdev.h"
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-brvlan.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
#include "networkd-dhcp-server.h"
#include "networkd-fdb.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-lldp-rx.h"
#include "networkd-lldp-tx.h"
#include "networkd-mdb.h"
#include "networkd-ndisc.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sysctl.h"
#include "networkd-util.h"
#include "ordered-set.h"
#include "resolve-util.h"
#include "socket-netlink.h"
typedef enum IPv6PrivacyExtensions {
/* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
IPV6_PRIVACY_EXTENSIONS_NO,
IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC,
IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */
_IPV6_PRIVACY_EXTENSIONS_MAX,
_IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
} IPv6PrivacyExtensions;
typedef enum KeepConfiguration {
KEEP_CONFIGURATION_NO = 0,
KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0,
@ -245,6 +228,7 @@ struct Network {
int ipv6_dad_transmits;
int ipv6_hop_limit;
int ipv6_proxy_ndp;
Set *ipv6_proxy_ndp_addresses;
int proxy_arp;
uint32_t ipv6_mtu;
@ -285,31 +269,7 @@ struct Network {
LLDPEmit lldp_emit; /* LLDP transmission */
char *lldp_mud; /* LLDP MUD URL */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
LIST_HEAD(NextHop, static_nexthops);
LIST_HEAD(FdbEntry, static_fdb_entries);
LIST_HEAD(MdbEntry, static_mdb_entries);
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
LIST_HEAD(Neighbor, neighbors);
LIST_HEAD(AddressLabel, address_labels);
LIST_HEAD(Prefix, static_prefixes);
LIST_HEAD(RoutePrefix, static_route_prefixes);
LIST_HEAD(RoutingPolicyRule, rules);
unsigned n_static_addresses;
unsigned n_static_routes;
unsigned n_static_nexthops;
unsigned n_static_fdb_entries;
unsigned n_static_mdb_entries;
unsigned n_ipv6_proxy_ndp_addresses;
unsigned n_neighbors;
unsigned n_address_labels;
unsigned n_static_prefixes;
unsigned n_static_route_prefixes;
unsigned n_rules;
Hashmap *addresses_by_section;
OrderedHashmap *addresses_by_section;
Hashmap *routes_by_section;
Hashmap *nexthops_by_section;
Hashmap *fdb_entries_by_section;
@ -360,8 +320,6 @@ bool network_has_static_ipv6_configurations(Network *network);
CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev);
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6token);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);
CONFIG_PARSER_PROTOTYPE(config_parse_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_hostname);
@ -374,9 +332,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
const char* keep_configuration_to_string(KeepConfiguration i) _const_;
KeepConfiguration keep_configuration_from_string(const char *s) _pure_;

View File

@ -5,17 +5,37 @@
#include <linux/nexthop.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "parse-util.h"
#include "set.h"
#include "string-util.h"
#include "util.h"
int nexthop_new(NextHop **ret) {
NextHop *nexthop_free(NextHop *nexthop) {
if (!nexthop)
return NULL;
if (nexthop->network) {
assert(nexthop->section);
hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section);
}
network_config_section_free(nexthop->section);
if (nexthop->link) {
set_remove(nexthop->link->nexthops, nexthop);
set_remove(nexthop->link->nexthops_foreign, nexthop);
}
return mfree(nexthop);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free);
static int nexthop_new(NextHop **ret) {
_cleanup_(nexthop_freep) NextHop *nexthop = NULL;
nexthop = new(NextHop, 1);
@ -38,19 +58,17 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
nexthop = hashmap_get(network->nexthops_by_section, n);
if (nexthop) {
*ret = TAKE_PTR(nexthop);
return 0;
}
nexthop = hashmap_get(network->nexthops_by_section, n);
if (nexthop) {
*ret = TAKE_PTR(nexthop);
return 0;
}
r = nexthop_new(&nexthop);
@ -59,55 +77,24 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
nexthop->protocol = RTPROT_STATIC;
nexthop->network = network;
LIST_PREPEND(nexthops, network->static_nexthops, nexthop);
network->n_static_nexthops++;
nexthop->section = TAKE_PTR(n);
if (filename) {
nexthop->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop);
if (r < 0)
return r;
}
r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop);
if (r < 0)
return r;
*ret = TAKE_PTR(nexthop);
return 0;
}
void nexthop_free(NextHop *nexthop) {
if (!nexthop)
return;
if (nexthop->network) {
LIST_REMOVE(nexthops, nexthop->network->static_nexthops, nexthop);
assert(nexthop->network->n_static_nexthops > 0);
nexthop->network->n_static_nexthops--;
if (nexthop->section)
hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section);
}
network_config_section_free(nexthop->section);
if (nexthop->link) {
set_remove(nexthop->link->nexthops, nexthop);
set_remove(nexthop->link->nexthops_foreign, nexthop);
}
free(nexthop);
}
static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
assert(nexthop);
siphash24_compress(&nexthop->id, sizeof(nexthop->id), state);
siphash24_compress(&nexthop->oif, sizeof(nexthop->oif), state);
siphash24_compress(&nexthop->family, sizeof(nexthop->family), state);
switch (nexthop->family) {
@ -129,27 +116,14 @@ static int nexthop_compare_func(const NextHop *a, const NextHop *b) {
if (r != 0)
return r;
r = CMP(a->oif, b->oif);
if (r != 0)
return r;
r = CMP(a->family, b->family);
if (r != 0)
return r;
switch (a->family) {
case AF_INET:
case AF_INET6:
if (IN_SET(a->family, AF_INET, AF_INET6))
return memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
return 0;
default:
/* treat any other address family as AF_UNSPEC */
return 0;
}
return 0;
}
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@ -159,17 +133,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
nexthop_compare_func,
nexthop_free);
bool nexthop_equal(NextHop *r1, NextHop *r2) {
if (r1 == r2)
return true;
if (!r1 || !r2)
return false;
return nexthop_compare_func(r1, r2) == 0;
}
int nexthop_get(Link *link, NextHop *in, NextHop **ret) {
static int nexthop_get(Link *link, NextHop *in, NextHop **ret) {
NextHop *existing;
assert(link);
@ -205,7 +169,6 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
return r;
nexthop->id = in->id;
nexthop->oif = in->oif;
nexthop->family = in->family;
nexthop->gw = in->gw;
@ -225,11 +188,11 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
return 0;
}
int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) {
static int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) {
return nexthop_add_internal(link, &link->nexthops_foreign, in, ret);
}
int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
static int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
NextHop *nexthop;
int r;
@ -258,26 +221,34 @@ int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
return 0;
}
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->ifname);
assert(link->nexthop_messages > 0);
link->nexthop_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring");
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set nexthop");
link_enter_failed(link);
return 1;
}
if (link->nexthop_messages == 0) {
log_link_debug(link, "Nexthop set");
link->static_nexthops_configured = true;
link_check_ready(link);
}
return 1;
}
int nexthop_remove(NextHop *nexthop, Link *link,
link_netlink_message_handler_t callback) {
static int nexthop_configure(NextHop *nexthop, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -287,52 +258,6 @@ int nexthop_remove(NextHop *nexthop, Link *link,
assert(link->ifindex > 0);
assert(IN_SET(nexthop->family, AF_INET, AF_INET6));
r = sd_rtnl_message_new_nexthop(link->manager->rtnl, &req,
RTM_DELNEXTHOP, nexthop->family,
nexthop->protocol);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_DELNEXTHOP message: %m");
if (DEBUG_LOGGING) {
_cleanup_free_ char *gw = NULL;
if (!in_addr_is_null(nexthop->family, &nexthop->gw))
(void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
log_link_debug(link, "Removing nexthop: gw: %s", strna(gw));
}
if (in_addr_is_null(nexthop->family, &nexthop->gw) == 0) {
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, nexthop->family, &nexthop->gw);
if (r < 0)
return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
}
r = netlink_call_async(link->manager->rtnl, NULL, req,
callback ?: nexthop_remove_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;
}
int nexthop_configure(
NextHop *nexthop,
Link *link,
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->ifindex > 0);
assert(IN_SET(nexthop->family, AF_INET, AF_INET6));
assert(callback);
if (DEBUG_LOGGING) {
_cleanup_free_ char *gw = NULL;
@ -366,7 +291,7 @@ int nexthop_configure(
return log_link_error_errno(link, r, "Could not set nexthop family: %m");
}
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
r = netlink_call_async(link->manager->rtnl, NULL, req, nexthop_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@ -380,7 +305,141 @@ int nexthop_configure(
return 1;
}
int nexthop_section_verify(NextHop *nh) {
int link_set_nexthop(Link *link) {
NextHop *nh;
int r;
assert(link);
assert(link->network);
link->static_nexthops_configured = false;
HASHMAP_FOREACH(nh, link->network->nexthops_by_section) {
r = nexthop_configure(nh, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set nexthop: %m");
link->nexthop_messages++;
}
if (link->nexthop_messages == 0) {
link->static_nexthops_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting nexthop");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 1;
}
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(nexthop_freep) NextHop *tmp = NULL;
_cleanup_free_ char *gateway = NULL;
NextHop *nexthop = NULL;
uint32_t ifindex;
uint16_t type;
Link *link;
int r;
assert(rtnl);
assert(message);
assert(m);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
return 0;
}
r = sd_netlink_message_get_type(message, &type);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
return 0;
} else if (!IN_SET(type, RTM_NEWNEXTHOP, RTM_DELNEXTHOP)) {
log_warning("rtnl: received unexpected message type %u when processing nexthop, ignoring.", type);
return 0;
}
r = sd_netlink_message_read_u32(message, NHA_OIF, &ifindex);
if (r == -ENODATA) {
log_warning_errno(r, "rtnl: received nexthop message without NHA_OIF attribute, ignoring: %m");
return 0;
} else if (r < 0) {
log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received nexthop message with invalid ifindex %"PRIu32", ignoring.", ifindex);
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0 || !link) {
if (!m->enumerating)
log_warning("rtnl: received nexthop message for link (%"PRIu32") we do not know about, ignoring", ifindex);
return 0;
}
r = nexthop_new(&tmp);
if (r < 0)
return log_oom();
r = sd_rtnl_message_get_family(message, &tmp->family);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: could not get nexthop family, ignoring: %m");
return 0;
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6))
return log_link_debug(link, "rtnl: received nexthop message with invalid family %d, ignoring.", tmp->family);
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, tmp->family, &tmp->gw);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u32(message, NHA_ID, &tmp->id);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: could not get NHA_ID attribute, ignoring: %m");
return 0;
}
(void) nexthop_get(link, tmp, &nexthop);
if (DEBUG_LOGGING)
(void) in_addr_to_string(tmp->family, &tmp->gw, &gateway);
switch (type) {
case RTM_NEWNEXTHOP:
if (nexthop)
log_link_debug(link, "Received remembered nexthop: %s, id: %d", strna(gateway), tmp->id);
else {
log_link_debug(link, "Remembering foreign nexthop: %s, id: %d", strna(gateway), tmp->id);
r = nexthop_add_foreign(link, tmp, &nexthop);
if (r < 0) {
log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m");
return 0;
}
}
break;
case RTM_DELNEXTHOP:
if (nexthop) {
log_link_debug(link, "Forgetting nexthop: %s, id: %d", strna(gateway), tmp->id);
nexthop_free(nexthop);
} else
log_link_debug(link, "Kernel removed a nexthop we don't remember: %s, id: %d, ignoring.",
strna(gateway), tmp->id);
break;
default:
assert_not_reached("Received invalid RTNL message type");
}
return 1;
}
static int nexthop_section_verify(NextHop *nh) {
if (section_is_invalid(nh->section))
return -EINVAL;
@ -390,6 +449,16 @@ int nexthop_section_verify(NextHop *nh) {
return 0;
}
void network_drop_invalid_nexthops(Network *network) {
NextHop *nh;
assert(network);
HASHMAP_FOREACH(nh, network->nexthops_by_section)
if (nexthop_section_verify(nh) < 0)
nexthop_free(nh);
}
int config_parse_nexthop_id(
const char *unit,
const char *filename,

View File

@ -4,16 +4,19 @@
#pragma once
#include <inttypes.h>
#include "sd-netlink.h"
#include "conf-parser.h"
#include "macro.h"
typedef struct NextHop NextHop;
typedef struct NetworkConfigSection NetworkConfigSection;
#include "networkd-network.h"
#include "in-addr-util.h"
#include "networkd-util.h"
struct NextHop {
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct NextHop {
Network *network;
NetworkConfigSection *section;
@ -21,30 +24,18 @@ struct NextHop {
unsigned char protocol;
int family;
uint32_t oif;
uint32_t id;
int family;
union in_addr_union gw;
} NextHop;
LIST_FIELDS(NextHop, nexthops);
};
NextHop *nexthop_free(NextHop *nexthop);
extern const struct hash_ops nexthop_hash_ops;
void network_drop_invalid_nexthops(Network *network);
int nexthop_new(NextHop **ret);
void nexthop_free(NextHop *nexthop);
int nexthop_configure(NextHop *nexthop, Link *link, link_netlink_message_handler_t callback);
int nexthop_remove(NextHop *nexthop, Link *link, link_netlink_message_handler_t callback);
int link_set_nexthop(Link *link);
int nexthop_get(Link *link, NextHop *in, NextHop **ret);
int nexthop_add(Link *link, NextHop *in, NextHop **ret);
int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret);
bool nexthop_equal(NextHop *r1, NextHop *r2);
int nexthop_section_verify(NextHop *nexthop);
DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free);
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);

View File

@ -7,35 +7,32 @@
#include <arpa/inet.h>
#include "dns-domain.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-radv.h"
#include "parse-util.h"
#include "sd-radv.h"
#include "string-util.h"
#include "string-table.h"
#include "strv.h"
void prefix_free(Prefix *prefix) {
Prefix *prefix_free(Prefix *prefix) {
if (!prefix)
return;
return NULL;
if (prefix->network) {
LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
assert(prefix->network->n_static_prefixes > 0);
prefix->network->n_static_prefixes--;
if (prefix->section)
hashmap_remove(prefix->network->prefixes_by_section,
prefix->section);
assert(prefix->section);
hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
}
network_config_section_free(prefix->section);
sd_radv_prefix_unref(prefix->radv_prefix);
free(prefix);
return mfree(prefix);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
static int prefix_new(Prefix **ret) {
_cleanup_(prefix_freep) Prefix *prefix = NULL;
@ -51,29 +48,24 @@ static int prefix_new(Prefix **ret) {
return 0;
}
static int prefix_new_static(Network *network, const char *filename,
unsigned section_line, Prefix **ret) {
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(prefix_freep) Prefix *prefix = NULL;
int r;
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
if (section_line) {
prefix = hashmap_get(network->prefixes_by_section, n);
if (prefix) {
*ret = TAKE_PTR(prefix);
return 0;
}
}
prefix = hashmap_get(network->prefixes_by_section, n);
if (prefix) {
*ret = TAKE_PTR(prefix);
return 0;
}
r = prefix_new(&prefix);
@ -81,26 +73,38 @@ static int prefix_new_static(Network *network, const char *filename,
return r;
prefix->network = network;
LIST_APPEND(prefixes, network->static_prefixes, prefix);
network->n_static_prefixes++;
prefix->section = TAKE_PTR(n);
if (filename) {
prefix->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
if (r < 0)
return r;
}
r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
if (r < 0)
return r;
*ret = TAKE_PTR(prefix);
return 0;
}
RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
if (!prefix)
return NULL;
if (prefix->network) {
assert(prefix->section);
hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
}
network_config_section_free(prefix->section);
sd_radv_route_prefix_unref(prefix->radv_route_prefix);
return mfree(prefix);
}
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
static int route_prefix_new(RoutePrefix **ret) {
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
@ -116,49 +120,24 @@ static int route_prefix_new(RoutePrefix **ret) {
return 0;
}
void route_prefix_free(RoutePrefix *prefix) {
if (!prefix)
return;
if (prefix->network) {
LIST_REMOVE(route_prefixes, prefix->network->static_route_prefixes, prefix);
assert(prefix->network->n_static_route_prefixes > 0);
prefix->network->n_static_route_prefixes--;
if (prefix->section)
hashmap_remove(prefix->network->route_prefixes_by_section,
prefix->section);
}
network_config_section_free(prefix->section);
sd_radv_route_prefix_unref(prefix->radv_route_prefix);
free(prefix);
}
static int route_prefix_new_static(Network *network, const char *filename,
unsigned section_line, RoutePrefix **ret) {
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
int r;
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
if (section_line) {
prefix = hashmap_get(network->route_prefixes_by_section, n);
if (prefix) {
*ret = TAKE_PTR(prefix);
return 0;
}
}
prefix = hashmap_get(network->route_prefixes_by_section, n);
if (prefix) {
*ret = TAKE_PTR(prefix);
return 0;
}
r = route_prefix_new(&prefix);
@ -166,36 +145,52 @@ static int route_prefix_new_static(Network *network, const char *filename,
return r;
prefix->network = network;
LIST_APPEND(route_prefixes, network->static_route_prefixes, prefix);
network->n_static_route_prefixes++;
prefix->section = TAKE_PTR(n);
if (filename) {
prefix->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
if (r < 0)
return r;
}
r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
if (r < 0)
return r;
*ret = TAKE_PTR(prefix);
return 0;
}
int config_parse_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) {
void network_drop_invalid_prefixes(Network *network) {
Prefix *prefix;
assert(network);
HASHMAP_FOREACH(prefix, network->prefixes_by_section)
if (section_is_invalid(prefix->section))
prefix_free(prefix);
}
void network_drop_invalid_route_prefixes(Network *network) {
RoutePrefix *prefix;
assert(network);
HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
if (section_is_invalid(prefix->section))
route_prefix_free(prefix);
}
int config_parse_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) {
Network *network = userdata;
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
@ -230,16 +225,18 @@ int config_parse_prefix(const char *unit,
return 0;
}
int config_parse_prefix_flags(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_prefix_flags(
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;
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
int r;
@ -274,16 +271,18 @@ int config_parse_prefix_flags(const char *unit,
return 0;
}
int config_parse_prefix_lifetime(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_prefix_lifetime(
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;
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
usec_t usec;
@ -362,16 +361,17 @@ int config_parse_prefix_assign(
return 0;
}
int config_parse_route_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_route_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) {
Network *network = userdata;
_cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
@ -406,16 +406,18 @@ int config_parse_route_prefix(const char *unit,
return 0;
}
int config_parse_route_prefix_lifetime(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_route_prefix_lifetime(
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;
_cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
usec_t usec;
@ -451,16 +453,15 @@ int config_parse_route_prefix_lifetime(const char *unit,
return 0;
}
static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
size_t *n_dns) {
static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
_cleanup_free_ struct in6_addr *addresses = NULL;
size_t i, n_addresses = 0, n_allocated = 0;
size_t n_addresses = 0, n_allocated = 0;
assert(network);
assert(dns);
assert(n_dns);
assert(ret_addresses);
assert(ret_size);
for (i = 0; i < network->n_dns; i++) {
for (size_t i = 0; i < network->n_dns; i++) {
union in_addr_union *addr;
if (network->dns[i]->family != AF_INET6)
@ -479,11 +480,8 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
addresses[n_addresses++] = addr->in6;
}
if (addresses) {
*dns = TAKE_PTR(addresses);
*n_dns = n_addresses;
}
*ret_addresses = TAKE_PTR(addresses);
*ret_size = n_addresses;
return n_addresses;
}
@ -520,7 +518,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
r = radv_get_ip6dns(link->network, &dns, &n_dns);
r = network_get_ipv6_dns(link->network, &dns, &n_dns);
if (r > 0)
goto set_dns;
@ -530,7 +528,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
return 0;
}
r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
if (r > 0)
goto set_dns;
}
@ -604,19 +602,29 @@ int radv_emit_dns(Link *link) {
return 0;
}
static bool link_radv_enabled(Link *link) {
assert(link);
if (!link_ipv6ll_enabled(link))
return false;
return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
}
int radv_configure(Link *link) {
RoutePrefix *q;
Prefix *p;
int r;
assert(link);
assert(link->network);
if (!link_radv_enabled(link))
return 0;
r = sd_radv_new(&link->radv);
if (r < 0)
return r;
r = sd_radv_attach_event(link->radv, NULL, 0);
r = sd_radv_attach_event(link->radv, link->manager->event, 0);
if (r < 0)
return r;
@ -651,7 +659,10 @@ int radv_configure(Link *link) {
}
if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
RoutePrefix *q;
Prefix *p;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
if (r == -EEXIST)
continue;
@ -663,7 +674,7 @@ int radv_configure(Link *link) {
return r;
}
LIST_FOREACH(route_prefixes, q, link->network->static_route_prefixes) {
HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
if (r == -EEXIST)
continue;
@ -675,8 +686,43 @@ int radv_configure(Link *link) {
return 0;
}
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
uint32_t lifetime_preferred, uint32_t lifetime_valid) {
int radv_update_mac(Link *link) {
bool restart;
int r;
assert(link);
if (!link->radv)
return 0;
restart = sd_radv_is_running(link->radv);
if (restart) {
r = sd_radv_stop(link->radv);
if (r < 0)
return r;
}
r = sd_radv_set_mac(link->radv, &link->mac);
if (r < 0)
return r;
if (restart) {
r = sd_radv_start(link->radv);
if (r < 0)
return r;
}
return 0;
}
int radv_add_prefix(
Link *link,
const struct in6_addr *prefix,
uint8_t prefix_len,
uint32_t lifetime_preferred,
uint32_t lifetime_valid) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r;
@ -822,10 +868,10 @@ int config_parse_radv_search_domains(
}
static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
[RADV_PREFIX_DELEGATION_NONE] = "no",
[RADV_PREFIX_DELEGATION_NONE] = "no",
[RADV_PREFIX_DELEGATION_STATIC] = "static",
[RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
[RADV_PREFIX_DELEGATION_BOTH] = "yes",
[RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
[RADV_PREFIX_DELEGATION_BOTH] = "yes",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
@ -833,21 +879,24 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
RADVPrefixDelegation,
RADV_PREFIX_DELEGATION_BOTH);
DEFINE_CONFIG_PARSE_ENUM(config_parse_router_prefix_delegation,
radv_prefix_delegation,
RADVPrefixDelegation,
"Invalid router prefix delegation");
DEFINE_CONFIG_PARSE_ENUM(
config_parse_router_prefix_delegation,
radv_prefix_delegation,
RADVPrefixDelegation,
"Invalid router prefix delegation");
int config_parse_router_preference(
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_router_preference(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;
assert(filename);

View File

@ -5,13 +5,17 @@
Copyright © 2017 Intel Corporation. All rights reserved.
***/
#include <inttypes.h>
#include <stdbool.h>
#include "sd-radv.h"
#include "in-addr-util.h"
#include "conf-parser.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-util.h"
typedef struct Prefix Prefix;
typedef struct RoutePrefix RoutePrefix;
typedef struct Network Network;
typedef struct Link Link;
typedef enum RADVPrefixDelegation {
RADV_PREFIX_DELEGATION_NONE = 0,
@ -22,36 +26,31 @@ typedef enum RADVPrefixDelegation {
_RADV_PREFIX_DELEGATION_INVALID = -1,
} RADVPrefixDelegation;
struct Prefix {
typedef struct Prefix {
Network *network;
NetworkConfigSection *section;
sd_radv_prefix *radv_prefix;
bool assign;
} Prefix;
LIST_FIELDS(Prefix, prefixes);
};
struct RoutePrefix {
typedef struct RoutePrefix {
Network *network;
NetworkConfigSection *section;
sd_radv_route_prefix *radv_route_prefix;
} RoutePrefix;
LIST_FIELDS(RoutePrefix, route_prefixes);
};
Prefix *prefix_free(Prefix *prefix);
RoutePrefix *route_prefix_free(RoutePrefix *prefix);
void prefix_free(Prefix *prefix);
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
void route_prefix_free(RoutePrefix *prefix);
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
void network_drop_invalid_prefixes(Network *network);
void network_drop_invalid_route_prefixes(Network *network);
int radv_emit_dns(Link *link);
int radv_configure(Link *link);
int radv_update_mac(Link *link);
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
uint32_t lifetime_preferred, uint32_t lifetime_valid);

View File

@ -3,16 +3,14 @@
#include <linux/icmpv6.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "missing_network.h"
#include "netlink-util.h"
#include "networkd-ipv4ll.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "parse-util.h"
#include "set.h"
#include "socket-netlink.h"
#include "string-table.h"
#include "string-util.h"
@ -23,6 +21,134 @@
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
static uint32_t link_get_vrf_table(Link *link) {
return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
}
uint32_t link_get_dhcp_route_table(Link *link) {
/* When the interface is part of an VRF use the VRFs routing table, unless
* another table is explicitly specified. */
if (link->network->dhcp_route_table_set)
return link->network->dhcp_route_table;
return link_get_vrf_table(link);
}
uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
if (link->network->ipv6_accept_ra_route_table_set)
return link->network->ipv6_accept_ra_route_table;
return link_get_vrf_table(link);
}
static const char * const route_type_table[__RTN_MAX] = {
[RTN_UNICAST] = "unicast",
[RTN_LOCAL] = "local",
[RTN_BROADCAST] = "broadcast",
[RTN_ANYCAST] = "anycast",
[RTN_MULTICAST] = "multicast",
[RTN_BLACKHOLE] = "blackhole",
[RTN_UNREACHABLE] = "unreachable",
[RTN_PROHIBIT] = "prohibit",
[RTN_THROW] = "throw",
[RTN_NAT] = "nat",
[RTN_XRESOLVE] = "xresolve",
};
assert_cc(__RTN_MAX <= UCHAR_MAX);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type, int);
static const char * const route_scope_table[] = {
[RT_SCOPE_UNIVERSE] = "global",
[RT_SCOPE_SITE] = "site",
[RT_SCOPE_LINK] = "link",
[RT_SCOPE_HOST] = "host",
[RT_SCOPE_NOWHERE] = "nowhere",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
static const char *format_route_scope(int scope, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_scope_to_string(scope);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", scope);
return buf;
}
static const char * const route_table_table[] = {
[RT_TABLE_DEFAULT] = "default",
[RT_TABLE_MAIN] = "main",
[RT_TABLE_LOCAL] = "local",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
static const char *format_route_table(int table, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_table_to_string(table);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", table);
return buf;
}
static const char * const route_protocol_table[] = {
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
static const char * const route_protocol_full_table[] = {
[RTPROT_REDIRECT] = "redirect",
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
[RTPROT_GATED] = "gated",
[RTPROT_RA] = "ra",
[RTPROT_MRT] = "mrt",
[RTPROT_ZEBRA] = "zebra",
[RTPROT_BIRD] = "bird",
[RTPROT_DNROUTED] = "dnrouted",
[RTPROT_XORP] = "xorp",
[RTPROT_NTK] = "ntk",
[RTPROT_DHCP] = "dhcp",
[RTPROT_MROUTED] = "mrouted",
[RTPROT_BABEL] = "babel",
[RTPROT_BGP] = "bgp",
[RTPROT_ISIS] = "isis",
[RTPROT_OSPF] = "ospf",
[RTPROT_RIP] = "rip",
[RTPROT_EIGRP] = "eigrp",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
static const char *format_route_protocol(int protocol, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_protocol_full_to_string(protocol);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", protocol);
return buf;
}
static unsigned routes_max(void) {
static thread_local unsigned cached = 0;
@ -82,22 +208,20 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
assert(network);
assert(ret);
assert(!!filename == (section_line > 0));
assert(filename);
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
r = network_config_section_new(filename, section_line, &n);
if (r < 0)
return r;
route = hashmap_get(network->routes_by_section, n);
if (route) {
*ret = TAKE_PTR(route);
return 0;
}
route = hashmap_get(network->routes_by_section, n);
if (route) {
*ret = TAKE_PTR(route);
return 0;
}
if (network->n_static_routes >= routes_max())
if (hashmap_size(network->routes_by_section) >= routes_max())
return -E2BIG;
r = route_new(&route);
@ -106,38 +230,27 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
route->protocol = RTPROT_STATIC;
route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
network->n_static_routes++;
route->section = TAKE_PTR(n);
if (filename) {
route->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
if (r < 0)
return r;
r = hashmap_put(network->routes_by_section, route->section, route);
if (r < 0)
return r;
}
r = hashmap_put(network->routes_by_section, route->section, route);
if (r < 0)
return r;
*ret = TAKE_PTR(route);
return 0;
}
void route_free(Route *route) {
Route *route_free(Route *route) {
if (!route)
return;
return NULL;
if (route->network) {
LIST_REMOVE(routes, route->network->static_routes, route);
assert(route->network->n_static_routes > 0);
route->network->n_static_routes--;
if (route->section)
hashmap_remove(route->network->routes_by_section, route->section);
assert(route->section);
hashmap_remove(route->network->routes_by_section, route->section);
}
network_config_section_free(route->section);
@ -162,7 +275,7 @@ void route_free(Route *route) {
sd_event_source_unref(route->expire);
free(route);
return mfree(route);
}
void route_hash_func(const Route *route, struct siphash *state) {
@ -280,7 +393,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
route_compare_func,
route_free);
bool route_equal(Route *r1, Route *r2) {
static bool route_equal(Route *r1, Route *r2) {
if (r1 == r2)
return true;
@ -290,7 +403,7 @@ bool route_equal(Route *r1, Route *r2) {
return route_compare_func(r1, r2) == 0;
}
int route_get(Link *link, Route *in, Route **ret) {
static int route_get(Link *link, Route *in, Route **ret) {
Route *existing;
@ -360,11 +473,11 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
return 0;
}
int route_add_foreign(Link *link, Route *in, Route **ret) {
static int route_add_foreign(Link *link, Route *in, Route **ret) {
return route_add_internal(link, &link->routes_foreign, in, ret);
}
int route_add(Link *link, Route *in, Route **ret) {
static int route_add(Link *link, Route *in, Route **ret) {
Route *route;
int r;
@ -509,7 +622,81 @@ int route_remove(Route *route, Link *link,
return 0;
}
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
static bool link_is_static_route_configured(Link *link, Route *route) {
Route *net_route;
assert(link);
assert(route);
if (!link->network)
return false;
HASHMAP_FOREACH(net_route, link->network->routes_by_section)
if (route_equal(net_route, route))
return true;
return false;
}
int link_drop_foreign_routes(Link *link) {
Route *route;
int k, r = 0;
assert(link);
SET_FOREACH(route, link->routes_foreign) {
/* do not touch routes managed by the kernel */
if (route->protocol == RTPROT_KERNEL)
continue;
/* do not touch multicast route added by kernel */
/* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
* https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
if (route->protocol == RTPROT_BOOT &&
route->family == AF_INET6 &&
route->dst_prefixlen == 8 &&
in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
continue;
if (route->protocol == RTPROT_STATIC && link->network &&
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;
if (route->protocol == RTPROT_DHCP && link->network &&
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
if (link_is_static_route_configured(link, route))
k = route_add(link, route, NULL);
else
k = route_remove(route, link, NULL);
if (k < 0 && r >= 0)
r = k;
}
return r;
}
int link_drop_routes(Link *link) {
Route *route;
int k, r = 0;
assert(link);
SET_FOREACH(route, link->routes) {
/* do not touch routes managed by the kernel */
if (route->protocol == RTPROT_KERNEL)
continue;
k = route_remove(route, link, NULL);
if (k < 0 && r >= 0)
r = k;
}
return r;
}
static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
Route *route = userdata;
int r;
@ -821,8 +1008,437 @@ int route_configure(
return 1;
}
static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->route_messages > 0);
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
LINK_STATE_FAILED, LINK_STATE_LINGER));
link->route_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set route");
link_enter_failed(link);
return 1;
}
if (link->route_messages == 0) {
log_link_debug(link, "Routes set");
link->static_routes_configured = true;
link_set_nexthop(link);
}
return 1;
}
int link_set_routes(Link *link) {
enum {
PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
PHASE_GATEWAY, /* Second phase: Routes with a gateway */
_PHASE_MAX
} phase;
Route *rt;
int r;
assert(link);
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
link->static_routes_configured = false;
if (!link->addresses_ready)
return 0;
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
/* During configuring addresses, the link lost its carrier. As networkd is dropping
* the addresses now, let's not configure the routes either. */
return 0;
r = link_set_routing_policy_rules(link);
if (r < 0)
return r;
/* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
for (phase = 0; phase < _PHASE_MAX; phase++)
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
if (rt->gateway_from_dhcp)
continue;
if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
continue;
r = route_configure(rt, link, route_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set routes: %m");
if (r > 0)
link->route_messages++;
}
if (link->route_messages == 0) {
link->static_routes_configured = true;
link_set_nexthop(link);
} else {
log_link_debug(link, "Setting routes");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(route_freep) Route *tmp = NULL;
Route *route = NULL;
Link *link = NULL;
uint32_t ifindex;
uint16_t type;
unsigned char table;
int r;
assert(rtnl);
assert(message);
assert(m);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
return 0;
}
r = sd_netlink_message_get_type(message, &type);
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
return 0;
} else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
return 0;
}
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
if (r == -ENODATA) {
log_debug("rtnl: received route message without ifindex, ignoring");
return 0;
} else if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0 || !link) {
/* when enumerating we might be out of sync, but we will
* get the route again, so just ignore it */
if (!m->enumerating)
log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
return 0;
}
r = route_new(&tmp);
if (r < 0)
return log_oom();
r = sd_rtnl_message_route_get_family(message, &tmp->family);
if (r < 0) {
log_link_warning(link, "rtnl: received route message without family, ignoring");
return 0;
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
return 0;
}
r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
if (r < 0) {
log_warning_errno(r, "rtnl: received route message without route protocol: %m");
return 0;
}
switch (tmp->family) {
case AF_INET:
r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
return 0;
}
break;
case AF_INET6:
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
return 0;
}
break;
default:
assert_not_reached("Received route message with unsupported address family");
return 0;
}
r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_type(message, &tmp->type);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
return 0;
}
r = sd_rtnl_message_route_get_table(message, &table);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
return 0;
}
tmp->table = table;
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
return 0;
}
r = sd_netlink_message_enter_container(message, RTA_METRICS);
if (r < 0 && r != -ENODATA) {
log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
return 0;
}
if (r >= 0) {
r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
if (r < 0 && r != -ENODATA) {
log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
return 0;
}
r = sd_netlink_message_exit_container(message);
if (r < 0) {
log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
return 0;
}
}
(void) route_get(link, tmp, &route);
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
*buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
buf_protocol[ROUTE_PROTOCOL_STR_MAX];
if (!in_addr_is_null(tmp->family, &tmp->dst)) {
(void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
(void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
}
if (!in_addr_is_null(tmp->family, &tmp->src))
(void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
if (!in_addr_is_null(tmp->family, &tmp->gw))
(void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
(void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
log_link_debug(link,
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
(!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
type == RTM_DELROUTE ? "Forgetting" :
route ? "Received remembered" : "Remembering",
strna(buf_dst), strempty(buf_dst_prefixlen),
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
format_route_table(tmp->table, buf_table, sizeof buf_table),
format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
strna(route_type_to_string(tmp->type)));
}
switch (type) {
case RTM_NEWROUTE:
if (!route && link->manager->manage_foreign_routes) {
/* A route appeared that we did not request */
r = route_add_foreign(link, tmp, &route);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
return 0;
}
}
break;
case RTM_DELROUTE:
route_free(route);
break;
default:
assert_not_reached("Received route message with invalid RTNL message type");
}
return 1;
}
int link_serialize_routes(Link *link, FILE *f) {
bool space = false;
Route *route;
assert(link);
assert(link->network);
assert(f);
fputs("ROUTES=", f);
SET_FOREACH(route, link->routes) {
_cleanup_free_ char *route_str = NULL;
if (in_addr_to_string(route->family, &route->dst, &route_str) < 0)
continue;
fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
space ? " " : "", route_str,
route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
space = true;
}
fputc('\n', f);
return 0;
}
int link_deserialize_routes(Link *link, const char *routes) {
int r;
assert(link);
for (const char *p = routes;; ) {
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
_cleanup_(route_freep) Route *tmp = NULL;
_cleanup_free_ char *route_str = NULL;
char *prefixlen_str;
Route *route;
r = extract_first_word(&p, &route_str, NULL, 0);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to parse ROUTES=: %m");
if (r == 0)
return 0;
prefixlen_str = strchr(route_str, '/');
if (!prefixlen_str) {
log_link_debug(link, "Failed to parse route, ignoring: %s", route_str);
continue;
}
*prefixlen_str++ = '\0';
r = route_new(&tmp);
if (r < 0)
return log_oom();
r = sscanf(prefixlen_str,
"%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
&tmp->dst_prefixlen,
&tmp->tos,
&tmp->priority,
&tmp->table,
&tmp->lifetime);
if (r != 5) {
log_link_debug(link,
"Failed to parse destination prefix length, tos, priority, table or expiration: %s",
prefixlen_str);
continue;
}
r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
if (r < 0) {
log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
continue;
}
r = route_add(link, tmp, &route);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to add route: %m");
if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
r = sd_event_add_time(link->manager->event, &expire,
clock_boottime_or_monotonic(),
route->lifetime, 0, route_expire_handler, route);
if (r < 0)
log_link_debug_errno(link, r, "Could not arm route expiration handler: %m");
}
sd_event_source_unref(route->expire);
route->expire = TAKE_PTR(expire);
}
}
int network_add_ipv4ll_route(Network *network) {
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
unsigned section_line;
int r;
assert(network);
@ -830,8 +1446,10 @@ int network_add_ipv4ll_route(Network *network) {
if (!network->ipv4ll_route)
return 0;
section_line = hashmap_find_free_section_line(network->routes_by_section);
/* IPv4LLRoute= is in [Network] section. */
r = route_new_static(network, NULL, 0, &n);
r = route_new_static(network, network->filename, section_line, &n);
if (r < 0)
return r;
@ -853,6 +1471,7 @@ int network_add_ipv4ll_route(Network *network) {
int network_add_default_route_on_device(Network *network) {
_cleanup_(route_free_or_set_invalidp) Route *n = NULL;
unsigned section_line;
int r;
assert(network);
@ -860,8 +1479,10 @@ int network_add_default_route_on_device(Network *network) {
if (!network->default_route_on_device)
return 0;
section_line = hashmap_find_free_section_line(network->routes_by_section);
/* DefaultRouteOnDevice= is in [Network] section. */
r = route_new_static(network, NULL, 0, &n);
r = route_new_static(network, network->filename, section_line, &n);
if (r < 0)
return r;
@ -874,113 +1495,6 @@ int network_add_default_route_on_device(Network *network) {
return 0;
}
static const char * const route_type_table[__RTN_MAX] = {
[RTN_UNICAST] = "unicast",
[RTN_LOCAL] = "local",
[RTN_BROADCAST] = "broadcast",
[RTN_ANYCAST] = "anycast",
[RTN_MULTICAST] = "multicast",
[RTN_BLACKHOLE] = "blackhole",
[RTN_UNREACHABLE] = "unreachable",
[RTN_PROHIBIT] = "prohibit",
[RTN_THROW] = "throw",
[RTN_NAT] = "nat",
[RTN_XRESOLVE] = "xresolve",
};
assert_cc(__RTN_MAX <= UCHAR_MAX);
DEFINE_STRING_TABLE_LOOKUP(route_type, int);
static const char * const route_scope_table[] = {
[RT_SCOPE_UNIVERSE] = "global",
[RT_SCOPE_SITE] = "site",
[RT_SCOPE_LINK] = "link",
[RT_SCOPE_HOST] = "host",
[RT_SCOPE_NOWHERE] = "nowhere",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
const char *format_route_scope(int scope, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_scope_to_string(scope);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", scope);
return buf;
}
static const char * const route_table_table[] = {
[RT_TABLE_DEFAULT] = "default",
[RT_TABLE_MAIN] = "main",
[RT_TABLE_LOCAL] = "local",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
const char *format_route_table(int table, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_table_to_string(table);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", table);
return buf;
}
static const char * const route_protocol_table[] = {
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
static const char * const route_protocol_full_table[] = {
[RTPROT_REDIRECT] = "redirect",
[RTPROT_KERNEL] = "kernel",
[RTPROT_BOOT] = "boot",
[RTPROT_STATIC] = "static",
[RTPROT_GATED] = "gated",
[RTPROT_RA] = "ra",
[RTPROT_MRT] = "mrt",
[RTPROT_ZEBRA] = "zebra",
[RTPROT_BIRD] = "bird",
[RTPROT_DNROUTED] = "dnrouted",
[RTPROT_XORP] = "xorp",
[RTPROT_NTK] = "ntk",
[RTPROT_DHCP] = "dhcp",
[RTPROT_MROUTED] = "mrouted",
[RTPROT_BABEL] = "babel",
[RTPROT_BGP] = "bgp",
[RTPROT_ISIS] = "isis",
[RTPROT_OSPF] = "ospf",
[RTPROT_RIP] = "rip",
[RTPROT_EIGRP] = "eigrp",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
const char *format_route_protocol(int protocol, char *buf, size_t size) {
const char *s;
char *p = buf;
s = route_protocol_full_to_string(protocol);
if (s)
strpcpy(&p, size, s);
else
strpcpyf(&p, size, "%d", protocol);
return buf;
}
int config_parse_gateway(
const char *unit,
const char *filename,
@ -1004,9 +1518,8 @@ int config_parse_gateway(
assert(data);
if (streq(section, "Network")) {
/* we are not in an Route section, so treat
* this as the special '0' section */
r = route_new_static(network, NULL, 0, &n);
/* we are not in an Route section, so use line number instead */
r = route_new_static(network, filename, line, &n);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
@ -1658,7 +2171,7 @@ int config_parse_multipath_route(
return 0;
}
int route_section_verify(Route *route, Network *network) {
static int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section))
return -EINVAL;
@ -1687,7 +2200,7 @@ int route_section_verify(Route *route, Network *network) {
route->scope = RT_SCOPE_LINK;
}
if (network->n_static_addresses == 0 &&
if (ordered_hashmap_isempty(network->addresses_by_section) &&
in_addr_is_null(route->family, &route->gw) == 0 &&
route->gateway_onlink < 0) {
log_warning("%s: Gateway= without static address configured. "
@ -1698,3 +2211,13 @@ int route_section_verify(Route *route, Network *network) {
return 0;
}
void network_drop_invalid_routes(Network *network) {
Route *route;
assert(network);
HASHMAP_FOREACH(route, network->routes_by_section)
if (route_section_verify(route, network) < 0)
route_free(route);
}

View File

@ -1,15 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include "sd-netlink.h"
#include "conf-parser.h"
#include "macro.h"
typedef struct Route Route;
typedef struct NetworkConfigSection NetworkConfigSection;
#include "networkd-network.h"
#include "in-addr-util.h"
#include "networkd-link.h"
#include "networkd-util.h"
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct MultipathRouteVia {
uint16_t family;
union in_addr_union address;
@ -21,7 +26,7 @@ typedef struct MultipathRoute {
uint32_t weight;
} MultipathRoute;
struct Route {
typedef struct Route {
Network *network;
NetworkConfigSection *section;
@ -58,43 +63,33 @@ struct Route {
usec_t lifetime;
sd_event_source *expire;
LIST_FIELDS(Route, routes);
};
} Route;
void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b);
extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
void route_free(Route *route);
Route *route_free(Route *route);
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback, Route **ret);
int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
int route_get(Link *link, Route *in, Route **ret);
int route_add(Link *link, Route *in, Route **ret);
int route_add_foreign(Link *link, Route *in, Route **ret);
bool route_equal(Route *r1, Route *r2);
int link_set_routes(Link *link);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);
int link_serialize_routes(Link *link, FILE *f);
int link_deserialize_routes(Link *link, const char *routes);
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
int route_section_verify(Route *route, Network *network);
uint32_t link_get_dhcp_route_table(Link *link);
uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(Network *network);
const char* route_type_to_string(int t) _const_;
int route_type_from_string(const char *s) _pure_;
#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
const char *format_route_scope(int scope, char *buf, size_t size);
#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
const char *format_route_table(int table, char *buf, size_t size);
#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
const char *format_route_protocol(int protocol, char *buf, size_t size);
void network_drop_invalid_routes(Network *network);
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);

File diff suppressed because it is too large Load Diff

View File

@ -2,28 +2,22 @@
#pragma once
#include <inttypes.h>
#include <netinet/in.h>
#include <linux/fib_rules.h>
#include <stdbool.h>
#include <stdio.h>
#include "in-addr-util.h"
#include "conf-parser.h"
typedef struct RoutingPolicyRule RoutingPolicyRule;
#include "networkd-link.h"
#include "networkd-network.h"
#include "in-addr-util.h"
#include "networkd-util.h"
#include "set.h"
typedef struct Network Network;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef struct Manager Manager;
struct RoutingPolicyRule {
typedef struct RoutingPolicyRule {
Manager *manager;
Network *network;
Link *link;
NetworkConfigSection *section;
bool invert_rule;
@ -52,25 +46,18 @@ struct RoutingPolicyRule {
struct fib_rule_uid_range uid_range;
int suppress_prefixlen;
} RoutingPolicyRule;
LIST_FIELDS(RoutingPolicyRule, rules);
};
RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule);
int routing_policy_rule_new(RoutingPolicyRule **ret);
void routing_policy_rule_free(RoutingPolicyRule *rule);
void network_drop_invalid_routing_policy_rules(Network *network);
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
int routing_policy_rule_section_verify(RoutingPolicyRule *rule);
int link_set_routing_policy_rules(Link *link);
int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule);
int routing_policy_serialize_rules(Set *rules, FILE *f);
int routing_policy_load_rules(const char *state_file, Set **rules);
void routing_policy_rule_purge(Manager *m, Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);

View File

@ -108,7 +108,7 @@ static int sr_iov_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return 1;
}
int sr_iov_configure(Link *link, SRIOV *sr_iov) {
static int sr_iov_configure(Link *link, SRIOV *sr_iov) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@ -226,7 +226,28 @@ int sr_iov_configure(Link *link, SRIOV *sr_iov) {
return 0;
}
int sr_iov_section_verify(SRIOV *sr_iov) {
int link_configure_sr_iov(Link *link) {
SRIOV *sr_iov;
int r;
link->sr_iov_configured = false;
link->sr_iov_messages = 0;
ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
r = sr_iov_configure(link, sr_iov);
if (r < 0)
return r;
}
if (link->sr_iov_messages == 0)
link->sr_iov_configured = true;
else
log_link_debug(link, "Configuring SR-IOV");
return 0;
}
static int sr_iov_section_verify(SRIOV *sr_iov) {
assert(sr_iov);
if (section_is_invalid(sr_iov->section))
@ -241,6 +262,16 @@ int sr_iov_section_verify(SRIOV *sr_iov) {
return 0;
}
void network_drop_invalid_sr_iov(Network *network) {
SRIOV *sr_iov;
assert(network);
ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
if (sr_iov_section_verify(sr_iov) < 0)
sr_iov_free(sr_iov);
}
int config_parse_sr_iov_uint32(
const char *unit,
const char *filename,

View File

@ -5,6 +5,7 @@
#include <linux/if_link.h>
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
@ -33,9 +34,8 @@ typedef struct SRIOV {
} SRIOV;
SRIOV *sr_iov_free(SRIOV *sr_iov);
int sr_iov_configure(Link *link, SRIOV *sr_iov);
int sr_iov_section_verify(SRIOV *sr_iov);
int link_configure_sr_iov(Link *link);
void network_drop_invalid_sr_iov(Network *network);
DEFINE_NETWORK_SECTION_FUNCTIONS(SRIOV, sr_iov_free);

View File

@ -0,0 +1,284 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <linux/if.h>
#include "missing_network.h"
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-sysctl.h"
#include "socket-util.h"
#include "string-table.h"
#include "sysctl-util.h"
static int link_update_ipv6_sysctl(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return 0;
if (!link_ipv6_enabled(link))
return 0;
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
}
static int link_set_proxy_arp(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return 0;
if (!link->network)
return 0;
if (link->network->proxy_arp < 0)
return 0;
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
}
bool link_ip_forward_enabled(Link *link, int family) {
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
if (family == AF_INET6 && !socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
if (!link->network)
return false;
return link->network->ip_forward & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
}
static int link_set_ipv4_forward(Link *link) {
assert(link);
if (!link_ip_forward_enabled(link, AF_INET))
return 0;
/* We propagate the forwarding flag from one interface to the
* global setting one way. This means: as long as at least one
* interface was configured at any time that had IP forwarding
* enabled the setting will stay on for good. We do this
* primarily to keep IPv4 and IPv6 packet forwarding behaviour
* somewhat in sync (see below). */
return sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
}
static int link_set_ipv6_forward(Link *link) {
assert(link);
if (!link_ip_forward_enabled(link, AF_INET6))
return 0;
/* On Linux, the IPv6 stack does not know a per-interface
* packet forwarding setting: either packet forwarding is on
* for all, or off for all. We hence don't bother with a
* per-interface setting, but simply propagate the interface
* flag, if it is set, to the global flag, one-way. Note that
* while IPv4 would allow a per-interface flag, we expose the
* same behaviour there and also propagate the setting from
* one to all, to keep things simple (see above). */
return sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
}
static int link_set_ipv6_privacy_extensions(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return 0;
if (link->flags & IFF_LOOPBACK)
return 0;
if (!link->network)
return 0;
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) link->network->ipv6_privacy_extensions);
}
static int link_set_ipv6_accept_ra(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;
return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
}
static int link_set_ipv6_dad_transmits(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_dad_transmits < 0)
return 0;
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
}
static int link_set_ipv6_hop_limit(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_hop_limit < 0)
return 0;
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
}
static int link_set_ipv4_accept_local(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return 0;
if (link->network->ipv4_accept_local < 0)
return 0;
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0);
}
int link_set_sysctl(Link *link) {
int r;
assert(link);
/* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
* for this interface, then enable IPv6 */
r = link_update_ipv6_sysctl(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
r = link_set_proxy_arp(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
r = link_set_ipv4_forward(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
r = link_set_ipv6_forward(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");;
r = link_set_ipv6_privacy_extensions(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface, ignorign: %m");
r = link_set_ipv6_accept_ra(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
r = link_set_ipv6_dad_transmits(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
r = link_set_ipv6_hop_limit(link);
if (r < 0)
log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, 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");
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",
[IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
IPV6_PRIVACY_EXTENSIONS_YES);
int config_parse_ipv6_privacy_extensions(
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) {
IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(ipv6_privacy_extensions);
s = ipv6_privacy_extensions_from_string(rvalue);
if (s < 0) {
if (streq(rvalue, "kernel"))
s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
else {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
return 0;
}
}
*ipv6_privacy_extensions = s;
return 0;
}

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include "conf-parser.h"
typedef struct Link Link;
typedef enum IPv6PrivacyExtensions {
/* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
IPV6_PRIVACY_EXTENSIONS_NO,
IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC,
IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */
_IPV6_PRIVACY_EXTENSIONS_MAX,
_IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
} IPv6PrivacyExtensions;
bool link_ip_forward_enabled(Link *link, int family);
int link_set_sysctl(Link *link);
int link_set_ipv6_mtu(Link *link);
const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);

View File

@ -151,3 +151,15 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
void network_config_section_free(NetworkConfigSection *cs) {
free(cs);
}
unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
NetworkConfigSection *cs;
unsigned n = 0;
void *entry;
HASHMAP_FOREACH_KEY(entry, cs, hashmap)
if (n < cs->line)
n = cs->line;
return n + 1;
}

View File

@ -2,10 +2,13 @@
#pragma once
#include "sd-dhcp-lease.h"
#include "sd-netlink.h"
#include "conf-parser.h"
#include "hash-funcs.h"
#include "hashmap.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
typedef enum AddressFamily {
/* This is a bitmask, though it usually doesn't feel that way! */
@ -49,6 +52,7 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
void network_config_section_free(NetworkConfigSection *network);
DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
extern const struct hash_ops network_config_hash_ops;
unsigned hashmap_find_free_section_line(Hashmap *hashmap);
static inline bool section_is_invalid(NetworkConfigSection *section) {
/* If this returns false, then it does _not_ mean the section is valid. */
@ -70,3 +74,10 @@ static inline bool section_is_invalid(NetworkConfigSection *section) {
} \
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
static inline int log_message_warning_errno(sd_netlink_message *m, int err, const char *msg) {
const char *err_msg = NULL;
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
return log_warning_errno(err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
}

View File

@ -6,6 +6,7 @@
#include "sd-bus.h"
#include "bus-util.h"
#include "ether-addr-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
#include "networkd-link.h"

View File

@ -88,29 +88,9 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Could not load configuration files: %m");
r = manager_rtnl_enumerate_links(m);
r = manager_enumerate(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate links: %m");
r = manager_rtnl_enumerate_addresses(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate addresses: %m");
r = manager_rtnl_enumerate_neighbors(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate neighbors: %m");
r = manager_rtnl_enumerate_routes(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate routes: %m");
r = manager_rtnl_enumerate_rules(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate rules: %m");
r = manager_rtnl_enumerate_nexthop(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate nexthop: %m");
return r;
r = manager_start(m);
if (r < 0)

View File

@ -21,7 +21,7 @@ void traffic_control_free(TrafficControl *tc) {
}
}
int traffic_control_configure(Link *link, TrafficControl *tc) {
static int traffic_control_configure(Link *link, TrafficControl *tc) {
assert(link);
assert(tc);
@ -35,7 +35,28 @@ int traffic_control_configure(Link *link, TrafficControl *tc) {
}
}
int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
int link_configure_traffic_control(Link *link) {
TrafficControl *tc;
int r;
link->tc_configured = false;
link->tc_messages = 0;
ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) {
r = traffic_control_configure(link, tc);
if (r < 0)
return r;
}
if (link->tc_messages == 0)
link->tc_configured = true;
else
log_link_debug(link, "Configuring traffic control");
return 0;
}
static int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
assert(tc);
switch(tc->kind) {
@ -47,3 +68,14 @@ int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, boo
assert_not_reached("Invalid traffic control type");
}
}
void network_drop_invalid_traffic_control(Network *network) {
bool has_root = false, has_clsact = false;
TrafficControl *tc;
assert(network);
ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section)
if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
traffic_control_free(tc);
}

View File

@ -28,5 +28,5 @@ typedef struct TrafficControl {
#define TC(tc) (&(tc)->meta)
void traffic_control_free(TrafficControl *tc);
int traffic_control_configure(Link *link, TrafficControl *tc);
int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact);
int link_configure_traffic_control(Link *link);
void network_drop_invalid_traffic_control(Network *network);

View File

@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "dhcp-lease-internal.h"
#include "ether-addr-util.h"
#include "hostname-util.h"
#include "network-internal.h"
#include "networkd-manager.h"
@ -252,6 +253,6 @@ int main(void) {
test_network_get(manager, loopback);
assert_se(manager_rtnl_enumerate_links(manager) >= 0);
assert_se(manager_enumerate(manager) >= 0);
return 0;
}

View File

@ -176,14 +176,16 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
assert_se(network->filename = strdup("hogehoge.network"));
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
assert_se(network->n_static_addresses == 1);
assert_se(ordered_hashmap_size(network->addresses_by_section) == 1);
assert_se(network_verify(network) >= 0);
assert_se(network->n_static_addresses == n_addresses);
assert_se(ordered_hashmap_size(network->addresses_by_section) == n_addresses);
if (n_addresses > 0) {
assert_se(network->static_addresses);
assert_se(network->static_addresses->prefixlen == prefixlen);
assert_se(network->static_addresses->family == family);
assert_se(in_addr_equal(family, &network->static_addresses->in_addr, u));
Address *a;
assert_se(a = ordered_hashmap_first(network->addresses_by_section));
assert_se(a->prefixlen == prefixlen);
assert_se(a->family == family);
assert_se(in_addr_equal(family, &a->in_addr, u));
/* TODO: check Address.in_addr and Address.broadcast */
}
}

View File

@ -1,13 +1,8 @@
/***
SPDX-License-Identifier: LGPL-2.1+
***/
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "network-internal.h"
#include "networkd-manager.h"
#include "networkd-routing-policy-rule.h"
#include "string-util.h"
#include "tests.h"
#include "tmpfile-util.h"

View File

@ -155,7 +155,6 @@ Address=10.3.3.98/16
Address=10.3.3.99/16
Address=10.3.3.100/16
Address=10.3.3.101/16
Address=10.3.3.101/16
Address=10.3.3.102/16
Address=10.3.3.103/16
Address=10.3.3.104/16

View File

@ -3,6 +3,7 @@ Name=eni99np1
[Network]
Address=192.168.100.100/24
IPv6AcceptRA=no
[SR-IOV]
VirtualFunction=0

View File

@ -382,6 +382,9 @@ def remove_routing_policy_rule_tables(tables):
rc = 0
while rc == 0:
rc = call('ip rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
rc = 0
while rc == 0:
rc = call('ip -6 rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def remove_routes(routes):
for route_type, addr in routes:
@ -745,6 +748,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
links = [
'6rdtun99',
'bareudp99',
'bond98',
'bond99',
'bridge99',
'dropin-test',
@ -870,6 +874,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'25-sit-tunnel.netdev',
'25-tap.netdev',
'25-tun.netdev',
'25-tunnel-any-any.network',
'25-tunnel-local-any.network',
'25-tunnel-remote-any.network',
'25-tunnel.network',