1
0
mirror of https://github.com/systemd/systemd synced 2025-12-29 12:24:45 +01:00

Compare commits

..

No commits in common. "ab582fda48d9cd594743312d0446676e32a52463" and "2084f8454a79e4dbafbbc9f20945fcd9f0bee113" have entirely different histories.

67 changed files with 5075 additions and 4844 deletions

View File

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

View File

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

View File

@ -77,20 +77,18 @@ int rtnl_log_create_error(int r);
userdata, 0, __func__); \ userdata, 0, __func__); \
}) })
#define netlink_add_match(nl, ret_slot, match, callback, destroy_callback, userdata, description) \ #define netlink_add_match(nl, ret_slot, metch, callback, destroy_callback, userdata) \
({ \ ({ \
int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \ int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \
void (*_destroy_)(typeof(userdata)) = destroy_callback; \ void (*_destroy_)(typeof(userdata)) = destroy_callback; \
sd_netlink_add_match(nl, ret_slot, match, \ sd_netlink_add_match(nl, ret_slot, match, \
(sd_netlink_message_handler_t) _callback_, \ (sd_netlink_message_handler_t) _callback_, \
(sd_netlink_destroy_t) _destroy_, \ (sd_netlink_destroy_t) _destroy_, \
userdata, description); \ userdata, __func__); \
}) })
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_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_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); 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); int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -3,22 +3,26 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include "sd-ipv4acd.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h" #include "in-addr-util.h"
typedef struct Address Address;
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h" #include "networkd-util.h"
#include "sd-ipv4acd.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU #define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
typedef struct Manager Manager;
typedef struct Network Network; typedef struct Network Network;
typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef int (*address_ready_callback_t)(Address *address); typedef int (*address_ready_callback_t)(Address *address);
typedef struct Address { struct Address {
Network *network; Network *network;
NetworkConfigSection *section; NetworkConfigSection *section;
@ -38,40 +42,39 @@ typedef struct Address {
bool scope_set:1; bool scope_set:1;
bool ip_masquerade_done: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; AddressFamily duplicate_address_detection;
/* Called when address become ready */ /* Called when address become ready */
address_ready_callback_t callback; address_ready_callback_t callback;
sd_ipv4acd *acd; sd_ipv4acd *acd;
} Address;
LIST_FIELDS(Address, addresses);
};
int address_new(Address **ret); int address_new(Address **ret);
Address *address_free(Address *address); 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);
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); 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); 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_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); int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2); bool address_equal(Address *a1, Address *a2);
bool address_is_ready(const Address *a); 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); int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); 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); void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2); int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops; 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; return 1;
} }
int link_set_bridge_vlan(Link *link) { int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
sd_netlink *rtnl;
uint16_t flags;
int r; int r;
assert(link); assert(link);
assert(link->manager); assert(link->manager);
assert(br_vid_bitmap);
assert(br_untagged_bitmap);
assert(link->network); assert(link->network);
if (!link->network->use_br_vlan)
return 0;
if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
return 0;
/* pvid might not be in br_vid_bitmap yet */ /* pvid might not be in br_vid_bitmap yet */
if (link->network->pvid) if (pvid)
set_bit(link->network->pvid, link->network->br_vid_bitmap); set_bit(pvid, br_vid_bitmap);
rtnl = link->manager->rtnl;
/* create new RTM message */ /* create new RTM message */
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
@ -179,14 +179,14 @@ int link_set_bridge_vlan(Link *link) {
/* master needs flag self */ /* master needs flag self */
if (!link->network->bridge) { if (!link->network->bridge) {
uint16_t flags = BRIDGE_FLAGS_SELF; flags = BRIDGE_FLAGS_SELF;
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(flags)); r = sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_BRIDGE_FLAGS: %m"); return log_link_error_errno(link, r, "Could not open IFLA_BRIDGE_FLAGS: %m");
} }
/* add vlan info */ /* add vlan info */
r = append_vlan_info_data(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap); r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append VLANs: %m"); return log_link_error_errno(link, r, "Could not append VLANs: %m");
@ -195,7 +195,7 @@ int link_set_bridge_vlan(Link *link) {
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
/* send message to the kernel */ /* send message to the kernel */
r = netlink_call_async(link->manager->rtnl, NULL, req, set_brvlan_handler, r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
link_netlink_destroy_callback, link); link_netlink_destroy_callback, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");

View File

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

View File

@ -1,231 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <linux/if_arp.h>
#include "dhcp-internal.h" #include "dhcp-internal.h"
#include "dhcp6-internal.h" #include "dhcp6-internal.h"
#include "escape.h" #include "escape.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "parse-util.h" #include "parse-util.h"
#include "socket-util.h"
#include "string-table.h" #include "string-table.h"
#include "strv.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( int config_parse_dhcp(
const char* unit, const char* unit,
const char *filename, const char *filename,

View File

@ -7,9 +7,6 @@
#define DHCP_ROUTE_METRIC 1024 #define DHCP_ROUTE_METRIC 1024
typedef struct Link Link;
typedef struct Manager Manager;
typedef enum DHCPUseDomains { typedef enum DHCPUseDomains {
DHCP_USE_DOMAINS_NO, DHCP_USE_DOMAINS_NO,
DHCP_USE_DOMAINS_YES, DHCP_USE_DOMAINS_YES,
@ -38,18 +35,6 @@ typedef struct DUID {
usec_t llt_time; usec_t llt_time;
} DUID; } 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_; const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;

View File

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

View File

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

View File

@ -18,9 +18,8 @@ typedef enum DHCPClientIdentifier {
} DHCPClientIdentifier; } DHCPClientIdentifier;
int dhcp4_configure(Link *link); int dhcp4_configure(Link *link);
int dhcp4_update_mac(Link *link); int dhcp4_set_client_identifier(Link *link);
int dhcp4_set_promote_secondaries(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_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);

View File

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

View File

@ -29,12 +29,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_pd_is_enabled(Link *link); bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_remove(Link *link); int dhcp6_pd_remove(Link *link);
int dhcp6_configure(Link *link); int dhcp6_configure(Link *link);
int dhcp6_update_mac(Link *link);
int dhcp6_request_address(Link *link, int ir); int dhcp6_request_address(Link *link, int ir);
int dhcp6_request_prefix_delegation(Link *link); 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_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_client_start_mode);

View File

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

View File

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

View File

@ -142,38 +142,24 @@ 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) { int ipv4ll_configure(Link *link) {
uint64_t seed; uint64_t seed;
int r; int r;
assert(link); assert(link);
assert(link->network);
assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4));
if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) if (!link->ipv4ll) {
return 0; r = sd_ipv4ll_new(&link->ipv4ll);
r = ipv4ll_init(link);
if (r < 0) if (r < 0)
return r; return r;
r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
if (r < 0)
return r;
}
if (link->sd_device && if (link->sd_device &&
net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) { net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
@ -196,82 +182,6 @@ int ipv4ll_configure(Link *link) {
return 0; 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( int config_parse_ipv4ll(
const char* unit, const char* unit,
const char *filename, const char *filename,

View File

@ -8,8 +8,5 @@
typedef struct Link Link; typedef struct Link Link;
int ipv4ll_configure(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); CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);

View File

@ -2,7 +2,9 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <linux/if.h> #include <linux/if.h>
#include <unistd.h>
#include "fileio.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-ipv6-proxy-ndp.h" #include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link.h" #include "networkd-link.h"
@ -12,50 +14,6 @@
#include "string-util.h" #include "string-util.h"
#include "sysctl-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) { static bool ipv6_proxy_ndp_is_needed(Link *link) {
assert(link); assert(link);
@ -68,7 +26,10 @@ static bool ipv6_proxy_ndp_is_needed(Link *link) {
if (link->network->ipv6_proxy_ndp >= 0) if (link->network->ipv6_proxy_ndp >= 0)
return link->network->ipv6_proxy_ndp; return link->network->ipv6_proxy_ndp;
return !set_isempty(link->network->ipv6_proxy_ndp_addresses); if (link->network->n_ipv6_proxy_ndp_addresses == 0)
return false;
return true;
} }
static int ipv6_proxy_ndp_set(Link *link) { static int ipv6_proxy_ndp_set(Link *link) {
@ -84,33 +45,49 @@ static int ipv6_proxy_ndp_set(Link *link) {
r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v); r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
if (r < 0) if (r < 0)
return log_link_warning_errno(link, r, "Cannot configure proxy NDP for the interface: %m"); log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
return v;
}
/* configure all ipv6 proxy ndp addresses */
int link_set_ipv6_proxy_ndp_addresses(Link *link) {
struct in6_addr *address;
int r;
assert(link);
assert(link->network);
/* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
r = ipv6_proxy_ndp_set(link);
if (r <= 0)
return r;
SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) {
r = ipv6_proxy_ndp_address_configure(link, address);
if (r < 0)
return r;
}
return 0; return 0;
} }
static int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
_cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
assert(network);
assert(ret);
/* allocate space for IPv6ProxyNDPAddress entry */
ipv6_proxy_ndp_address = new(IPv6ProxyNDPAddress, 1);
if (!ipv6_proxy_ndp_address)
return -ENOMEM;
*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--;
}
free(ipv6_proxy_ndp_address);
}
int config_parse_ipv6_proxy_ndp_address( int config_parse_ipv6_proxy_ndp_address(
const char *unit, const char *unit,
const char *filename, const char *filename,
@ -123,24 +100,26 @@ int config_parse_ipv6_proxy_ndp_address(
void *data, void *data,
void *userdata) { void *userdata) {
_cleanup_free_ struct in6_addr *address = NULL;
Network *network = userdata; Network *network = userdata;
union in_addr_union buffer; _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
int r; int r;
union in_addr_union buffer;
assert(filename); assert(filename);
assert(section);
assert(lvalue);
assert(rvalue); assert(rvalue);
assert(network); assert(data);
if (isempty(rvalue)) { r = ipv6_proxy_ndp_address_new_static(network, &ipv6_proxy_ndp_address);
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses); if (r < 0)
return 0; return log_oom();
}
r = in_addr_from_string(AF_INET6, rvalue, &buffer); r = in_addr_from_string(AF_INET6, rvalue, &buffer);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, 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; return 0;
} }
@ -150,15 +129,76 @@ int config_parse_ipv6_proxy_ndp_address(
return 0; return 0;
} }
address = newdup(struct in6_addr, &buffer.in6, 1); ipv6_proxy_ndp_address->in_addr = buffer.in6;
if (!address) ipv6_proxy_ndp_address = NULL;
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; 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,9 +2,24 @@
#pragma once #pragma once
#include "conf-parser.h" #include "conf-parser.h"
#include "list.h"
#include "macro.h"
typedef struct Network Network;
typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
typedef struct Link Link; typedef struct Link Link;
int link_set_ipv6_proxy_ndp_addresses(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);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address);

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -10,11 +10,12 @@
#include "dhcp-identifier.h" #include "dhcp-identifier.h"
#include "hashmap.h" #include "hashmap.h"
#include "list.h"
#include "time-util.h"
#include "networkd-address-pool.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "ordered-set.h"
#include "set.h"
#include "time-util.h"
struct Manager { struct Manager {
sd_netlink *rtnl; sd_netlink *rtnl;
@ -44,7 +45,7 @@ struct Manager {
OrderedHashmap *networks; OrderedHashmap *networks;
Hashmap *dhcp6_prefixes; Hashmap *dhcp6_prefixes;
Set *dhcp6_pd_prefixes; Set *dhcp6_pd_prefixes;
OrderedSet *address_pools; LIST_HEAD(AddressPool, address_pools);
usec_t network_dirs_ts_usec; usec_t network_dirs_ts_usec;
@ -81,13 +82,27 @@ int manager_start(Manager *m);
int manager_load_config(Manager *m); int manager_load_config(Manager *m);
bool manager_should_reload(Manager *m); bool manager_should_reload(Manager *m);
int manager_enumerate(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);
void manager_dirty(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); Link* manager_find_uplink(Manager *m, Link *exclude);
int manager_set_hostname(Manager *m, const char *hostname); int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone); 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); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);

View File

@ -3,32 +3,13 @@
#include <net/if.h> #include <net/if.h>
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-mdb.h" #include "networkd-mdb.h"
#include "networkd-network.h"
#include "string-util.h" #include "string-util.h"
#include "vlan-util.h" #include "vlan-util.h"
#define STATIC_MDB_ENTRIES_PER_NETWORK_MAX 1024U #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. */ /* create a new MDB entry or get an existing one. */
static int mdb_entry_new_static( static int mdb_entry_new_static(
Network *network, Network *network,
@ -42,21 +23,22 @@ static int mdb_entry_new_static(
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
/* search entry in hashmap first. */
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
/* search entry in hashmap first. */
mdb_entry = hashmap_get(network->mdb_entries_by_section, n); mdb_entry = hashmap_get(network->mdb_entries_by_section, n);
if (mdb_entry) { if (mdb_entry) {
*ret = TAKE_PTR(mdb_entry); *ret = TAKE_PTR(mdb_entry);
return 0; return 0;
} }
}
if (hashmap_size(network->mdb_entries_by_section) >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX) if (network->n_static_mdb_entries >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX)
return -E2BIG; return -E2BIG;
/* allocate space for an MDB entry. */ /* allocate space for an MDB entry. */
@ -67,9 +49,14 @@ static int mdb_entry_new_static(
/* init MDB structure. */ /* init MDB structure. */
*mdb_entry = (MdbEntry) { *mdb_entry = (MdbEntry) {
.network = network, .network = network,
.section = TAKE_PTR(n),
}; };
LIST_PREPEND(static_mdb_entries, network->static_mdb_entries, mdb_entry);
network->n_static_mdb_entries++;
if (filename) {
mdb_entry->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops);
if (r < 0) if (r < 0)
return r; return r;
@ -77,12 +64,33 @@ static int mdb_entry_new_static(
r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry); r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry);
if (r < 0) if (r < 0)
return r; return r;
}
/* return allocated MDB structure. */ /* return allocated MDB structure. */
*ret = TAKE_PTR(mdb_entry); *ret = TAKE_PTR(mdb_entry);
return 0; 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) { static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -204,7 +212,7 @@ int link_set_bridge_mdb(Link *link) {
if (!link->network) if (!link->network)
return 0; return 0;
if (hashmap_isempty(link->network->mdb_entries_by_section)) if (LIST_IS_EMPTY(link->network->static_mdb_entries))
goto finish; goto finish;
if (!link_has_carrier(link)) if (!link_has_carrier(link))
@ -228,7 +236,7 @@ int link_set_bridge_mdb(Link *link) {
goto finish; goto finish;
} }
HASHMAP_FOREACH(mdb_entry, link->network->mdb_entries_by_section) { LIST_FOREACH(static_mdb_entries, mdb_entry, link->network->static_mdb_entries) {
r = mdb_entry_configure(link, mdb_entry); r = mdb_entry_configure(link, mdb_entry);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m"); return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
@ -245,49 +253,6 @@ finish:
return 0; 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. */ /* parse the VLAN Id from config files. */
int config_parse_mdb_vlan_id( int config_parse_mdb_vlan_id(
const char *unit, const char *unit,
@ -363,3 +328,36 @@ int config_parse_mdb_group_address(
return 0; 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,29 +1,32 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once #pragma once
#include <inttypes.h>
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h" #include "list.h"
#include "macro.h"
#include "networkd-util.h" #include "networkd-util.h"
typedef struct Network Network; typedef struct Network Network;
typedef struct MdbEntry MdbEntry;
typedef struct Link Link; typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef struct MdbEntry { struct MdbEntry {
Network *network; Network *network;
NetworkConfigSection *section; NetworkConfigSection *section;
int family; int family;
union in_addr_union group_addr; union in_addr_union group_addr;
uint16_t vlan_id; 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); MdbEntry *mdb_entry_free(MdbEntry *mdb_entry);
void network_drop_invalid_mdb_entries(Network *network);
int link_set_bridge_mdb(Link *link); int link_set_bridge_mdb(Link *link);
DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry, mdb_entry_free);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address); CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id); CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id);

View File

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

View File

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

View File

@ -1,20 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include "sd-netlink.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "in-addr-util.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-neighbor.h" #include "networkd-neighbor.h"
#include "networkd-network.h"
#include "set.h" #include "set.h"
Neighbor *neighbor_free(Neighbor *neighbor) { void neighbor_free(Neighbor *neighbor) {
if (!neighbor) if (!neighbor)
return NULL; return;
if (neighbor->network) { if (neighbor->network) {
assert(neighbor->section); 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); hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
} }
@ -25,11 +33,9 @@ Neighbor *neighbor_free(Neighbor *neighbor) {
set_remove(neighbor->link->neighbors_foreign, neighbor); set_remove(neighbor->link->neighbors_foreign, neighbor);
} }
return mfree(neighbor); free(neighbor);
} }
DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) { static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL; _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
@ -37,9 +43,9 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -47,8 +53,10 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
neighbor = hashmap_get(network->neighbors_by_section, n); neighbor = hashmap_get(network->neighbors_by_section, n);
if (neighbor) { if (neighbor) {
*ret = TAKE_PTR(neighbor); *ret = TAKE_PTR(neighbor);
return 0; return 0;
} }
}
neighbor = new(Neighbor, 1); neighbor = new(Neighbor, 1);
if (!neighbor) if (!neighbor)
@ -57,9 +65,14 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
*neighbor = (Neighbor) { *neighbor = (Neighbor) {
.network = network, .network = network,
.family = AF_UNSPEC, .family = AF_UNSPEC,
.section = TAKE_PTR(n),
}; };
LIST_APPEND(neighbors, network->neighbors, neighbor);
network->n_neighbors++;
if (filename) {
neighbor->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops);
if (r < 0) if (r < 0)
return r; return r;
@ -67,8 +80,128 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor); r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor);
if (r < 0) if (r < 0)
return r; return r;
}
*ret = TAKE_PTR(neighbor); *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; return 0;
} }
@ -116,20 +249,28 @@ 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); DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) { 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 *existing; Neighbor neighbor, *existing;
assert(link); assert(link);
assert(in); assert(addr);
assert(lladdr);
existing = set_get(link->neighbors, in); neighbor = (Neighbor) {
.family = family,
.in_addr = *addr,
.lladdr = *lladdr,
.lladdr_size = lladdr_size,
};
existing = set_get(link->neighbors, &neighbor);
if (existing) { if (existing) {
if (ret) if (ret)
*ret = existing; *ret = existing;
return 1; return 1;
} }
existing = set_get(link->neighbors_foreign, in); existing = set_get(link->neighbors_foreign, &neighbor);
if (existing) { if (existing) {
if (ret) if (ret)
*ret = existing; *ret = existing;
@ -139,23 +280,24 @@ static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
return -ENOENT; return -ENOENT;
} }
static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in, Neighbor **ret) { 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) {
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL; _cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
int r; int r;
assert(link); assert(link);
assert(neighbors); assert(neighbors);
assert(in); assert(addr);
assert(lladdr);
neighbor = new(Neighbor, 1); neighbor = new(Neighbor, 1);
if (!neighbor) if (!neighbor)
return -ENOMEM; return -ENOMEM;
*neighbor = (Neighbor) { *neighbor = (Neighbor) {
.family = in->family, .family = family,
.in_addr = in->in_addr, .in_addr = *addr,
.lladdr = in->lladdr, .lladdr = *lladdr,
.lladdr_size = in->lladdr_size, .lladdr_size = lladdr_size,
}; };
r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor); r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor);
@ -168,19 +310,19 @@ static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in
if (ret) if (ret)
*ret = neighbor; *ret = neighbor;
TAKE_PTR(neighbor); TAKE_PTR(neighbor);
return 0; return 0;
} }
static int neighbor_add(Link *link, const Neighbor *in, 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) {
Neighbor *neighbor; Neighbor *neighbor;
int r; int r;
r = neighbor_get(link, in, &neighbor); r = neighbor_get(link, family, addr, lladdr, lladdr_size, &neighbor);
if (r == -ENOENT) { if (r == -ENOENT) {
/* Neighbor doesn't exist, make a new one */ /* Neighbor doesn't exist, make a new one */
r = neighbor_add_internal(link, &link->neighbors, in, &neighbor); r = neighbor_add_internal(link, &link->neighbors, family, addr, lladdr, lladdr_size, &neighbor);
if (r < 0) if (r < 0)
return r; return r;
} else if (r == 0) { } else if (r == 0) {
@ -200,11 +342,11 @@ static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) {
return 0; return 0;
} }
static int neighbor_add_foreign(Link *link, const Neighbor *in, 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) {
return neighbor_add_internal(link, &link->neighbors_foreign, in, ret); return neighbor_add_internal(link, &link->neighbors_foreign, family, addr, lladdr, lladdr_size, ret);
} }
static bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) { bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
if (n1 == n2) if (n1 == n2)
return true; return true;
@ -214,365 +356,7 @@ static bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
return neighbor_compare_func(n1, n2) == 0; return neighbor_compare_func(n1, n2) == 0;
} }
static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int neighbor_section_verify(Neighbor *neighbor) {
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)) if (section_is_invalid(neighbor->section))
return -EINVAL; return -EINVAL;
@ -591,17 +375,6 @@ static int neighbor_section_verify(Neighbor *neighbor) {
return 0; 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( int config_parse_neighbor_address(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

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

View File

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

View File

@ -14,16 +14,8 @@
#include "in-addr-util.h" #include "in-addr-util.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "network-internal.h" #include "network-internal.h"
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-fdb.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-mdb.h"
#include "networkd-neighbor.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-radv.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sriov.h" #include "networkd-sriov.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-lookup.h" #include "path-lookup.h"
@ -156,6 +148,19 @@ static int network_resolve_stacked_netdevs(Network *network) {
} }
int network_verify(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);
assert(network->filename); assert(network->filename);
@ -208,15 +213,18 @@ int network_verify(Network *network) {
network->filename); network->filename);
network->dhcp_server = false; network->dhcp_server = false;
} }
if (!ordered_hashmap_isempty(network->addresses_by_section)) if (network->n_static_addresses > 0) {
log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.", log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
network->filename); network->filename);
if (!hashmap_isempty(network->routes_by_section)) while ((address = network->static_addresses))
address_free(address);
}
if (network->n_static_routes > 0) {
log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.", log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
network->filename); network->filename);
while ((route = network->static_routes))
network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free); route_free(route);
network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free); }
} }
if (network->link_local < 0) if (network->link_local < 0)
@ -282,23 +290,54 @@ int network_verify(Network *network) {
if (network->keep_configuration < 0) if (network->keep_configuration < 0)
network->keep_configuration = KEEP_CONFIGURATION_NO; network->keep_configuration = KEEP_CONFIGURATION_NO;
if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) { LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename); if (address_section_verify(address) < 0)
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses); address_free(address);
}
network_drop_invalid_addresses(network); LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
network_drop_invalid_routes(network); if (route_section_verify(route, network) < 0)
network_drop_invalid_nexthops(network); route_free(route);
network_drop_invalid_fdb_entries(network);
network_drop_invalid_mdb_entries(network); LIST_FOREACH_SAFE(nexthops, nexthop, nextnop_next, network->static_nexthops)
network_drop_invalid_neighbors(network); if (nexthop_section_verify(nexthop) < 0)
network_drop_invalid_address_labels(network); nexthop_free(nexthop);
network_drop_invalid_prefixes(network);
network_drop_invalid_route_prefixes(network); LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
network_drop_invalid_routing_policy_rules(network); if (section_is_invalid(fdb->section))
network_drop_invalid_traffic_control(network); fdb_entry_free(fdb);
network_drop_invalid_sr_iov(network);
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);
return 0; return 0;
} }
@ -605,6 +644,18 @@ failure:
} }
static Network *network_free(Network *network) { 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) if (!network)
return NULL; return NULL;
@ -660,17 +711,49 @@ static Network *network_free(Network *network) {
netdev_unref(network->vrf); netdev_unref(network->vrf);
hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref); hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
set_free_free(network->ipv6_proxy_ndp_addresses); while ((route = network->static_routes))
ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free); route_free(route);
hashmap_free_with_destructor(network->routes_by_section, route_free);
hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free); while ((nexthop = network->static_nexthops))
hashmap_free_with_destructor(network->fdb_entries_by_section, fdb_entry_free); nexthop_free(nexthop);
hashmap_free_with_destructor(network->mdb_entries_by_section, mdb_entry_free);
hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free); while ((address = network->static_addresses))
hashmap_free_with_destructor(network->address_labels_by_section, address_label_free); address_free(address);
hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free); while ((fdb_entry = network->static_fdb_entries))
hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free); 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);
ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_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); ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
@ -783,33 +866,30 @@ bool network_has_static_ipv6_configurations(Network *network) {
assert(network); assert(network);
ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) LIST_FOREACH(addresses, address, network->static_addresses)
if (address->family == AF_INET6) if (address->family == AF_INET6)
return true; return true;
HASHMAP_FOREACH(route, network->routes_by_section) LIST_FOREACH(routes, route, network->static_routes)
if (route->family == AF_INET6) if (route->family == AF_INET6)
return true; return true;
HASHMAP_FOREACH(fdb, network->fdb_entries_by_section) LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
if (fdb->family == AF_INET6) if (fdb->family == AF_INET6)
return true; return true;
HASHMAP_FOREACH(mdb, network->mdb_entries_by_section) LIST_FOREACH(static_mdb_entries, mdb, network->static_mdb_entries)
if (mdb->family == AF_INET6) if (mdb->family == AF_INET6)
return true; return true;
HASHMAP_FOREACH(neighbor, network->neighbors_by_section) LIST_FOREACH(neighbors, neighbor, network->neighbors)
if (neighbor->family == AF_INET6) if (neighbor->family == AF_INET6)
return true; return true;
if (!hashmap_isempty(network->address_labels_by_section)) if (!LIST_IS_EMPTY(network->address_labels))
return true; return true;
if (!hashmap_isempty(network->prefixes_by_section)) if (!LIST_IS_EMPTY(network->static_prefixes))
return true;
if (!hashmap_isempty(network->route_prefixes_by_section))
return true; return true;
return false; return false;
@ -946,6 +1026,95 @@ 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( int config_parse_hostname(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

@ -12,21 +12,38 @@
#include "conf-parser.h" #include "conf-parser.h"
#include "hashmap.h" #include "hashmap.h"
#include "netdev.h" #include "netdev.h"
#include "networkd-address-label.h"
#include "networkd-address.h"
#include "networkd-brvlan.h" #include "networkd-brvlan.h"
#include "networkd-dhcp-common.h" #include "networkd-dhcp-common.h"
#include "networkd-dhcp4.h" #include "networkd-dhcp4.h"
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
#include "networkd-fdb.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-lldp-rx.h" #include "networkd-lldp-rx.h"
#include "networkd-lldp-tx.h" #include "networkd-lldp-tx.h"
#include "networkd-mdb.h"
#include "networkd-ndisc.h" #include "networkd-ndisc.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
#include "networkd-radv.h" #include "networkd-radv.h"
#include "networkd-sysctl.h" #include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-util.h" #include "networkd-util.h"
#include "ordered-set.h" #include "ordered-set.h"
#include "resolve-util.h" #include "resolve-util.h"
#include "socket-netlink.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 { typedef enum KeepConfiguration {
KEEP_CONFIGURATION_NO = 0, KEEP_CONFIGURATION_NO = 0,
KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0, KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0,
@ -228,7 +245,6 @@ struct Network {
int ipv6_dad_transmits; int ipv6_dad_transmits;
int ipv6_hop_limit; int ipv6_hop_limit;
int ipv6_proxy_ndp; int ipv6_proxy_ndp;
Set *ipv6_proxy_ndp_addresses;
int proxy_arp; int proxy_arp;
uint32_t ipv6_mtu; uint32_t ipv6_mtu;
@ -269,7 +285,31 @@ struct Network {
LLDPEmit lldp_emit; /* LLDP transmission */ LLDPEmit lldp_emit; /* LLDP transmission */
char *lldp_mud; /* LLDP MUD URL */ char *lldp_mud; /* LLDP MUD URL */
OrderedHashmap *addresses_by_section; 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;
Hashmap *routes_by_section; Hashmap *routes_by_section;
Hashmap *nexthops_by_section; Hashmap *nexthops_by_section;
Hashmap *fdb_entries_by_section; Hashmap *fdb_entries_by_section;
@ -320,6 +360,8 @@ bool network_has_static_ipv6_configurations(Network *network);
CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev); CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev);
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel); 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_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dns); CONFIG_PARSER_PROTOTYPE(config_parse_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_hostname); CONFIG_PARSER_PROTOTYPE(config_parse_hostname);
@ -332,6 +374,9 @@ 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 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_; const char* keep_configuration_to_string(KeepConfiguration i) _const_;
KeepConfiguration keep_configuration_from_string(const char *s) _pure_; KeepConfiguration keep_configuration_from_string(const char *s) _pure_;

View File

@ -5,37 +5,17 @@
#include <linux/nexthop.h> #include <linux/nexthop.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h" #include "networkd-nexthop.h"
#include "parse-util.h" #include "parse-util.h"
#include "set.h" #include "set.h"
#include "string-util.h" #include "string-util.h"
#include "util.h"
NextHop *nexthop_free(NextHop *nexthop) { int nexthop_new(NextHop **ret) {
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; _cleanup_(nexthop_freep) NextHop *nexthop = NULL;
nexthop = new(NextHop, 1); nexthop = new(NextHop, 1);
@ -58,9 +38,9 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -68,8 +48,10 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
nexthop = hashmap_get(network->nexthops_by_section, n); nexthop = hashmap_get(network->nexthops_by_section, n);
if (nexthop) { if (nexthop) {
*ret = TAKE_PTR(nexthop); *ret = TAKE_PTR(nexthop);
return 0; return 0;
} }
}
r = nexthop_new(&nexthop); r = nexthop_new(&nexthop);
if (r < 0) if (r < 0)
@ -77,6 +59,10 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
nexthop->protocol = RTPROT_STATIC; nexthop->protocol = RTPROT_STATIC;
nexthop->network = network; nexthop->network = network;
LIST_PREPEND(nexthops, network->static_nexthops, nexthop);
network->n_static_nexthops++;
if (filename) {
nexthop->section = TAKE_PTR(n); nexthop->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops);
@ -86,15 +72,42 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop); r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop);
if (r < 0) if (r < 0)
return r; return r;
}
*ret = TAKE_PTR(nexthop); *ret = TAKE_PTR(nexthop);
return 0; 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) { static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) {
assert(nexthop); assert(nexthop);
siphash24_compress(&nexthop->id, sizeof(nexthop->id), state); siphash24_compress(&nexthop->id, sizeof(nexthop->id), state);
siphash24_compress(&nexthop->oif, sizeof(nexthop->oif), state);
siphash24_compress(&nexthop->family, sizeof(nexthop->family), state); siphash24_compress(&nexthop->family, sizeof(nexthop->family), state);
switch (nexthop->family) { switch (nexthop->family) {
@ -116,14 +129,27 @@ static int nexthop_compare_func(const NextHop *a, const NextHop *b) {
if (r != 0) if (r != 0)
return r; return r;
r = CMP(a->oif, b->oif);
if (r != 0)
return r;
r = CMP(a->family, b->family); r = CMP(a->family, b->family);
if (r != 0) if (r != 0)
return r; return r;
if (IN_SET(a->family, AF_INET, AF_INET6)) switch (a->family) {
return memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family)); case AF_INET:
case AF_INET6:
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
return 0; return 0;
default:
/* treat any other address family as AF_UNSPEC */
return 0;
}
} }
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@ -133,7 +159,17 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
nexthop_compare_func, nexthop_compare_func,
nexthop_free); nexthop_free);
static int nexthop_get(Link *link, NextHop *in, NextHop **ret) { 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) {
NextHop *existing; NextHop *existing;
assert(link); assert(link);
@ -169,6 +205,7 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
return r; return r;
nexthop->id = in->id; nexthop->id = in->id;
nexthop->oif = in->oif;
nexthop->family = in->family; nexthop->family = in->family;
nexthop->gw = in->gw; nexthop->gw = in->gw;
@ -188,11 +225,11 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop
return 0; return 0;
} }
static int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) { int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) {
return nexthop_add_internal(link, &link->nexthops_foreign, in, ret); return nexthop_add_internal(link, &link->nexthops_foreign, in, ret);
} }
static int nexthop_add(Link *link, NextHop *in, NextHop **ret) { int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
NextHop *nexthop; NextHop *nexthop;
int r; int r;
@ -221,34 +258,26 @@ static int nexthop_add(Link *link, NextHop *in, NextHop **ret) {
return 0; return 0;
} }
static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
assert(m);
assert(link); assert(link);
assert(link->nexthop_messages > 0); assert(link->ifname);
link->nexthop_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1; return 1;
r = sd_netlink_message_get_errno(m); r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) { if (r < 0 && r != -ESRCH)
log_link_message_warning_errno(link, m, r, "Could not set nexthop"); log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring");
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; return 1;
} }
static int nexthop_configure(NextHop *nexthop, Link *link) { int nexthop_remove(NextHop *nexthop, Link *link,
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r; int r;
@ -258,6 +287,52 @@ static int nexthop_configure(NextHop *nexthop, Link *link) {
assert(link->ifindex > 0); assert(link->ifindex > 0);
assert(IN_SET(nexthop->family, AF_INET, AF_INET6)); 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) { if (DEBUG_LOGGING) {
_cleanup_free_ char *gw = NULL; _cleanup_free_ char *gw = NULL;
@ -291,7 +366,7 @@ static int nexthop_configure(NextHop *nexthop, Link *link) {
return log_link_error_errno(link, r, "Could not set nexthop family: %m"); return log_link_error_errno(link, r, "Could not set nexthop family: %m");
} }
r = netlink_call_async(link->manager->rtnl, NULL, req, nexthop_handler, r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link); link_netlink_destroy_callback, link);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@ -305,141 +380,7 @@ static int nexthop_configure(NextHop *nexthop, Link *link) {
return 1; return 1;
} }
int link_set_nexthop(Link *link) { int nexthop_section_verify(NextHop *nh) {
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)) if (section_is_invalid(nh->section))
return -EINVAL; return -EINVAL;
@ -449,16 +390,6 @@ static int nexthop_section_verify(NextHop *nh) {
return 0; 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( int config_parse_nexthop_id(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

@ -4,19 +4,16 @@
#pragma once #pragma once
#include <inttypes.h>
#include "sd-netlink.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h" #include "macro.h"
typedef struct NextHop NextHop;
typedef struct NetworkConfigSection NetworkConfigSection;
#include "networkd-network.h"
#include "networkd-util.h" #include "networkd-util.h"
typedef struct Link Link; struct NextHop {
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct NextHop {
Network *network; Network *network;
NetworkConfigSection *section; NetworkConfigSection *section;
@ -24,18 +21,30 @@ typedef struct NextHop {
unsigned char protocol; unsigned char protocol;
uint32_t id;
int family; int family;
uint32_t oif;
uint32_t id;
union in_addr_union gw; union in_addr_union gw;
} NextHop;
NextHop *nexthop_free(NextHop *nexthop); LIST_FIELDS(NextHop, nexthops);
};
void network_drop_invalid_nexthops(Network *network); extern const struct hash_ops nexthop_hash_ops;
int link_set_nexthop(Link *link); 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 manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); 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);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id); CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);

View File

@ -7,32 +7,35 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "dns-domain.h" #include "dns-domain.h"
#include "networkd-link.h" #include "networkd-address.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-radv.h" #include "networkd-radv.h"
#include "parse-util.h" #include "parse-util.h"
#include "sd-radv.h"
#include "string-util.h" #include "string-util.h"
#include "string-table.h" #include "string-table.h"
#include "strv.h" #include "strv.h"
Prefix *prefix_free(Prefix *prefix) { void prefix_free(Prefix *prefix) {
if (!prefix) if (!prefix)
return NULL; return;
if (prefix->network) { if (prefix->network) {
assert(prefix->section); LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
hashmap_remove(prefix->network->prefixes_by_section, prefix->section); assert(prefix->network->n_static_prefixes > 0);
prefix->network->n_static_prefixes--;
if (prefix->section)
hashmap_remove(prefix->network->prefixes_by_section,
prefix->section);
} }
network_config_section_free(prefix->section); network_config_section_free(prefix->section);
sd_radv_prefix_unref(prefix->radv_prefix); sd_radv_prefix_unref(prefix->radv_prefix);
return mfree(prefix); free(prefix);
} }
DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
static int prefix_new(Prefix **ret) { static int prefix_new(Prefix **ret) {
_cleanup_(prefix_freep) Prefix *prefix = NULL; _cleanup_(prefix_freep) Prefix *prefix = NULL;
@ -48,31 +51,40 @@ static int prefix_new(Prefix **ret) {
return 0; 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_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(prefix_freep) Prefix *prefix = NULL; _cleanup_(prefix_freep) Prefix *prefix = NULL;
int r; int r;
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
if (section_line) {
prefix = hashmap_get(network->prefixes_by_section, n); prefix = hashmap_get(network->prefixes_by_section, n);
if (prefix) { if (prefix) {
*ret = TAKE_PTR(prefix); *ret = TAKE_PTR(prefix);
return 0; return 0;
} }
}
}
r = prefix_new(&prefix); r = prefix_new(&prefix);
if (r < 0) if (r < 0)
return r; return r;
prefix->network = network; prefix->network = network;
LIST_APPEND(prefixes, network->static_prefixes, prefix);
network->n_static_prefixes++;
if (filename) {
prefix->section = TAKE_PTR(n); prefix->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
@ -82,29 +94,13 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
r = hashmap_put(network->prefixes_by_section, prefix->section, prefix); r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
if (r < 0) if (r < 0)
return r; return r;
}
*ret = TAKE_PTR(prefix); *ret = TAKE_PTR(prefix);
return 0; 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) { static int route_prefix_new(RoutePrefix **ret) {
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL; _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
@ -120,31 +116,60 @@ static int route_prefix_new(RoutePrefix **ret) {
return 0; return 0;
} }
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) { 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) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL; _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
int r; int r;
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
if (section_line) {
prefix = hashmap_get(network->route_prefixes_by_section, n); prefix = hashmap_get(network->route_prefixes_by_section, n);
if (prefix) { if (prefix) {
*ret = TAKE_PTR(prefix); *ret = TAKE_PTR(prefix);
return 0; return 0;
} }
}
}
r = route_prefix_new(&prefix); r = route_prefix_new(&prefix);
if (r < 0) if (r < 0)
return r; return r;
prefix->network = network; prefix->network = network;
LIST_APPEND(route_prefixes, network->static_route_prefixes, prefix);
network->n_static_route_prefixes++;
if (filename) {
prefix->section = TAKE_PTR(n); prefix->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
@ -154,34 +179,14 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix); r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
if (r < 0) if (r < 0)
return r; return r;
}
*ret = TAKE_PTR(prefix); *ret = TAKE_PTR(prefix);
return 0; return 0;
} }
void network_drop_invalid_prefixes(Network *network) { int config_parse_prefix(const char *unit,
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, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -225,8 +230,7 @@ int config_parse_prefix(
return 0; return 0;
} }
int config_parse_prefix_flags( int config_parse_prefix_flags(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -236,7 +240,6 @@ int config_parse_prefix_flags(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
Network *network = userdata; Network *network = userdata;
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
int r; int r;
@ -271,8 +274,7 @@ int config_parse_prefix_flags(
return 0; return 0;
} }
int config_parse_prefix_lifetime( int config_parse_prefix_lifetime(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -282,7 +284,6 @@ int config_parse_prefix_lifetime(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
Network *network = userdata; Network *network = userdata;
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL; _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
usec_t usec; usec_t usec;
@ -361,8 +362,7 @@ int config_parse_prefix_assign(
return 0; return 0;
} }
int config_parse_route_prefix( int config_parse_route_prefix(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -406,8 +406,7 @@ int config_parse_route_prefix(
return 0; return 0;
} }
int config_parse_route_prefix_lifetime( int config_parse_route_prefix_lifetime(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -417,7 +416,6 @@ int config_parse_route_prefix_lifetime(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
Network *network = userdata; Network *network = userdata;
_cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL; _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
usec_t usec; usec_t usec;
@ -453,15 +451,16 @@ int config_parse_route_prefix_lifetime(
return 0; return 0;
} }
static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) { static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
size_t *n_dns) {
_cleanup_free_ struct in6_addr *addresses = NULL; _cleanup_free_ struct in6_addr *addresses = NULL;
size_t n_addresses = 0, n_allocated = 0; size_t i, n_addresses = 0, n_allocated = 0;
assert(network); assert(network);
assert(ret_addresses); assert(dns);
assert(ret_size); assert(n_dns);
for (size_t i = 0; i < network->n_dns; i++) { for (i = 0; i < network->n_dns; i++) {
union in_addr_union *addr; union in_addr_union *addr;
if (network->dns[i]->family != AF_INET6) if (network->dns[i]->family != AF_INET6)
@ -480,8 +479,11 @@ static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresse
addresses[n_addresses++] = addr->in6; addresses[n_addresses++] = addr->in6;
} }
*ret_addresses = TAKE_PTR(addresses); if (addresses) {
*ret_size = n_addresses; *dns = TAKE_PTR(addresses);
*n_dns = n_addresses;
}
return n_addresses; return n_addresses;
} }
@ -518,7 +520,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
r = network_get_ipv6_dns(link->network, &dns, &n_dns); r = radv_get_ip6dns(link->network, &dns, &n_dns);
if (r > 0) if (r > 0)
goto set_dns; goto set_dns;
@ -528,7 +530,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
return 0; return 0;
} }
r = network_get_ipv6_dns(uplink->network, &dns, &n_dns); r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
if (r > 0) if (r > 0)
goto set_dns; goto set_dns;
} }
@ -602,29 +604,19 @@ int radv_emit_dns(Link *link) {
return 0; 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) { int radv_configure(Link *link) {
RoutePrefix *q;
Prefix *p;
int r; int r;
assert(link); assert(link);
assert(link->network); assert(link->network);
if (!link_radv_enabled(link))
return 0;
r = sd_radv_new(&link->radv); r = sd_radv_new(&link->radv);
if (r < 0) if (r < 0)
return r; return r;
r = sd_radv_attach_event(link->radv, link->manager->event, 0); r = sd_radv_attach_event(link->radv, NULL, 0);
if (r < 0) if (r < 0)
return r; return r;
@ -659,10 +651,7 @@ int radv_configure(Link *link) {
} }
if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) { if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
RoutePrefix *q; LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
Prefix *p;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false); r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
@ -674,7 +663,7 @@ int radv_configure(Link *link) {
return r; return r;
} }
HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) { LIST_FOREACH(route_prefixes, q, link->network->static_route_prefixes) {
r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false); r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
if (r == -EEXIST) if (r == -EEXIST)
continue; continue;
@ -686,43 +675,8 @@ int radv_configure(Link *link) {
return 0; return 0;
} }
int radv_update_mac(Link *link) { int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
bool restart; uint32_t lifetime_preferred, uint32_t lifetime_valid) {
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; _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r; int r;
@ -879,14 +833,12 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
RADVPrefixDelegation, RADVPrefixDelegation,
RADV_PREFIX_DELEGATION_BOTH); RADV_PREFIX_DELEGATION_BOTH);
DEFINE_CONFIG_PARSE_ENUM( DEFINE_CONFIG_PARSE_ENUM(config_parse_router_prefix_delegation,
config_parse_router_prefix_delegation,
radv_prefix_delegation, radv_prefix_delegation,
RADVPrefixDelegation, RADVPrefixDelegation,
"Invalid router prefix delegation"); "Invalid router prefix delegation");
int config_parse_router_preference( int config_parse_router_preference(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -896,7 +848,6 @@ int config_parse_router_preference(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
Network *network = userdata; Network *network = userdata;
assert(filename); assert(filename);

View File

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

View File

@ -3,14 +3,16 @@
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "missing_network.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-ipv4ll.h" #include "networkd-ipv4ll.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-ndisc.h"
#include "networkd-nexthop.h"
#include "networkd-route.h" #include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "parse-util.h" #include "parse-util.h"
#include "set.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "string-table.h" #include "string-table.h"
#include "string-util.h" #include "string-util.h"
@ -21,134 +23,6 @@
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U #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 unsigned routes_max(void) {
static thread_local unsigned cached = 0; static thread_local unsigned cached = 0;
@ -208,9 +82,9 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
assert(network); assert(network);
assert(ret); assert(ret);
assert(filename); assert(!!filename == (section_line > 0));
assert(section_line > 0);
if (filename) {
r = network_config_section_new(filename, section_line, &n); r = network_config_section_new(filename, section_line, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -218,10 +92,12 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
route = hashmap_get(network->routes_by_section, n); route = hashmap_get(network->routes_by_section, n);
if (route) { if (route) {
*ret = TAKE_PTR(route); *ret = TAKE_PTR(route);
return 0; return 0;
} }
}
if (hashmap_size(network->routes_by_section) >= routes_max()) if (network->n_static_routes >= routes_max())
return -E2BIG; return -E2BIG;
r = route_new(&route); r = route_new(&route);
@ -230,6 +106,10 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
route->protocol = RTPROT_STATIC; route->protocol = RTPROT_STATIC;
route->network = network; route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
network->n_static_routes++;
if (filename) {
route->section = TAKE_PTR(n); route->section = TAKE_PTR(n);
r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops); r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
@ -239,17 +119,24 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
r = hashmap_put(network->routes_by_section, route->section, route); r = hashmap_put(network->routes_by_section, route->section, route);
if (r < 0) if (r < 0)
return r; return r;
}
*ret = TAKE_PTR(route); *ret = TAKE_PTR(route);
return 0; return 0;
} }
Route *route_free(Route *route) { void route_free(Route *route) {
if (!route) if (!route)
return NULL; return;
if (route->network) { if (route->network) {
assert(route->section); 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); hashmap_remove(route->network->routes_by_section, route->section);
} }
@ -275,7 +162,7 @@ Route *route_free(Route *route) {
sd_event_source_unref(route->expire); sd_event_source_unref(route->expire);
return mfree(route); free(route);
} }
void route_hash_func(const Route *route, struct siphash *state) { void route_hash_func(const Route *route, struct siphash *state) {
@ -393,7 +280,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
route_compare_func, route_compare_func,
route_free); route_free);
static bool route_equal(Route *r1, Route *r2) { bool route_equal(Route *r1, Route *r2) {
if (r1 == r2) if (r1 == r2)
return true; return true;
@ -403,7 +290,7 @@ static bool route_equal(Route *r1, Route *r2) {
return route_compare_func(r1, r2) == 0; return route_compare_func(r1, r2) == 0;
} }
static int route_get(Link *link, Route *in, Route **ret) { int route_get(Link *link, Route *in, Route **ret) {
Route *existing; Route *existing;
@ -473,11 +360,11 @@ static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret)
return 0; return 0;
} }
static int route_add_foreign(Link *link, Route *in, Route **ret) { int route_add_foreign(Link *link, Route *in, Route **ret) {
return route_add_internal(link, &link->routes_foreign, in, ret); return route_add_internal(link, &link->routes_foreign, in, ret);
} }
static int route_add(Link *link, Route *in, Route **ret) { int route_add(Link *link, Route *in, Route **ret) {
Route *route; Route *route;
int r; int r;
@ -622,81 +509,7 @@ int route_remove(Route *route, Link *link,
return 0; return 0;
} }
static bool link_is_static_route_configured(Link *link, Route *route) { int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
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; Route *route = userdata;
int r; int r;
@ -1008,437 +821,8 @@ int route_configure(
return 1; 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) { int network_add_ipv4ll_route(Network *network) {
_cleanup_(route_free_or_set_invalidp) Route *n = NULL; _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
unsigned section_line;
int r; int r;
assert(network); assert(network);
@ -1446,10 +830,8 @@ int network_add_ipv4ll_route(Network *network) {
if (!network->ipv4ll_route) if (!network->ipv4ll_route)
return 0; return 0;
section_line = hashmap_find_free_section_line(network->routes_by_section);
/* IPv4LLRoute= is in [Network] section. */ /* IPv4LLRoute= is in [Network] section. */
r = route_new_static(network, network->filename, section_line, &n); r = route_new_static(network, NULL, 0, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -1471,7 +853,6 @@ int network_add_ipv4ll_route(Network *network) {
int network_add_default_route_on_device(Network *network) { int network_add_default_route_on_device(Network *network) {
_cleanup_(route_free_or_set_invalidp) Route *n = NULL; _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
unsigned section_line;
int r; int r;
assert(network); assert(network);
@ -1479,10 +860,8 @@ int network_add_default_route_on_device(Network *network) {
if (!network->default_route_on_device) if (!network->default_route_on_device)
return 0; return 0;
section_line = hashmap_find_free_section_line(network->routes_by_section);
/* DefaultRouteOnDevice= is in [Network] section. */ /* DefaultRouteOnDevice= is in [Network] section. */
r = route_new_static(network, network->filename, section_line, &n); r = route_new_static(network, NULL, 0, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -1495,6 +874,113 @@ int network_add_default_route_on_device(Network *network) {
return 0; 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( int config_parse_gateway(
const char *unit, const char *unit,
const char *filename, const char *filename,
@ -1518,8 +1004,9 @@ int config_parse_gateway(
assert(data); assert(data);
if (streq(section, "Network")) { if (streq(section, "Network")) {
/* we are not in an Route section, so use line number instead */ /* we are not in an Route section, so treat
r = route_new_static(network, filename, line, &n); * this as the special '0' section */
r = route_new_static(network, NULL, 0, &n);
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) { if (r < 0) {
@ -2171,7 +1658,7 @@ int config_parse_multipath_route(
return 0; return 0;
} }
static int route_section_verify(Route *route, Network *network) { int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section)) if (section_is_invalid(route->section))
return -EINVAL; return -EINVAL;
@ -2200,7 +1687,7 @@ static int route_section_verify(Route *route, Network *network) {
route->scope = RT_SCOPE_LINK; route->scope = RT_SCOPE_LINK;
} }
if (ordered_hashmap_isempty(network->addresses_by_section) && if (network->n_static_addresses == 0 &&
in_addr_is_null(route->family, &route->gw) == 0 && in_addr_is_null(route->family, &route->gw) == 0 &&
route->gateway_onlink < 0) { route->gateway_onlink < 0) {
log_warning("%s: Gateway= without static address configured. " log_warning("%s: Gateway= without static address configured. "
@ -2211,13 +1698,3 @@ static int route_section_verify(Route *route, Network *network) {
return 0; 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,19 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once #pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include "sd-netlink.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "in-addr-util.h" #include "macro.h"
#include "networkd-link.h"
#include "networkd-util.h"
typedef struct Manager Manager; typedef struct Route Route;
typedef struct Network Network; typedef struct NetworkConfigSection NetworkConfigSection;
#include "networkd-network.h"
#include "networkd-util.h"
typedef struct MultipathRouteVia { typedef struct MultipathRouteVia {
uint16_t family; uint16_t family;
@ -26,7 +21,7 @@ typedef struct MultipathRoute {
uint32_t weight; uint32_t weight;
} MultipathRoute; } MultipathRoute;
typedef struct Route { struct Route {
Network *network; Network *network;
NetworkConfigSection *section; NetworkConfigSection *section;
@ -63,33 +58,43 @@ typedef struct Route {
usec_t lifetime; usec_t lifetime;
sd_event_source *expire; sd_event_source *expire;
} Route;
LIST_FIELDS(Route, routes);
};
void route_hash_func(const Route *route, struct siphash *state); void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b); int route_compare_func(const Route *a, const Route *b);
extern const struct hash_ops route_hash_ops; extern const struct hash_ops route_hash_ops;
int route_new(Route **ret); int route_new(Route **ret);
Route *route_free(Route *route); void 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_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_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
int link_set_routes(Link *link); int route_get(Link *link, Route *in, Route **ret);
int link_drop_routes(Link *link); int route_add(Link *link, Route *in, Route **ret);
int link_drop_foreign_routes(Link *link); int route_add_foreign(Link *link, Route *in, Route **ret);
int link_serialize_routes(Link *link, FILE *f); bool route_equal(Route *r1, Route *r2);
int link_deserialize_routes(Link *link, const char *routes);
uint32_t link_get_dhcp_route_table(Link *link); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
uint32_t link_get_ipv6_accept_ra_route_table(Link *link); int route_section_verify(Route *route, Network *network);
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
int network_add_ipv4ll_route(Network *network); int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(Network *network); int network_add_default_route_on_device(Network *network);
void network_drop_invalid_routes(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);
CONFIG_PARSER_PROTOTYPE(config_parse_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src); CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);

File diff suppressed because it is too large Load Diff

View File

@ -2,22 +2,28 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <netinet/in.h>
#include <linux/fib_rules.h> #include <linux/fib_rules.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include "conf-parser.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "conf-parser.h"
typedef struct RoutingPolicyRule RoutingPolicyRule;
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h" #include "networkd-util.h"
#include "set.h"
typedef struct Network Network; typedef struct Network Network;
typedef struct Link Link; typedef struct Link Link;
typedef struct NetworkConfigSection NetworkConfigSection;
typedef struct Manager Manager; typedef struct Manager Manager;
typedef struct RoutingPolicyRule { struct RoutingPolicyRule {
Manager *manager; Manager *manager;
Network *network; Network *network;
Link *link;
NetworkConfigSection *section; NetworkConfigSection *section;
bool invert_rule; bool invert_rule;
@ -46,18 +52,25 @@ typedef struct RoutingPolicyRule {
struct fib_rule_uid_range uid_range; struct fib_rule_uid_range uid_range;
int suppress_prefixlen; int suppress_prefixlen;
} RoutingPolicyRule;
RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule); LIST_FIELDS(RoutingPolicyRule, rules);
};
void network_drop_invalid_routing_policy_rules(Network *network); int routing_policy_rule_new(RoutingPolicyRule **ret);
void routing_policy_rule_free(RoutingPolicyRule *rule);
int link_set_routing_policy_rules(Link *link); DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
int routing_policy_rule_section_verify(RoutingPolicyRule *rule);
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); 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 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_serialize_rules(Set *rules, FILE *f);
int routing_policy_load_rules(const char *state_file, Set **rules); 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_tos);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table); 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; return 1;
} }
static int sr_iov_configure(Link *link, SRIOV *sr_iov) { int sr_iov_configure(Link *link, SRIOV *sr_iov) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r; int r;
@ -226,28 +226,7 @@ static int sr_iov_configure(Link *link, SRIOV *sr_iov) {
return 0; return 0;
} }
int link_configure_sr_iov(Link *link) { int sr_iov_section_verify(SRIOV *sr_iov) {
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); assert(sr_iov);
if (section_is_invalid(sr_iov->section)) if (section_is_invalid(sr_iov->section))
@ -262,16 +241,6 @@ static int sr_iov_section_verify(SRIOV *sr_iov) {
return 0; 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( int config_parse_sr_iov_uint32(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

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

View File

@ -1,284 +0,0 @@
/* 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

@ -1,26 +0,0 @@
/* 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,15 +151,3 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
void network_config_section_free(NetworkConfigSection *cs) { void network_config_section_free(NetworkConfigSection *cs) {
free(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,13 +2,10 @@
#pragma once #pragma once
#include "sd-dhcp-lease.h" #include "sd-dhcp-lease.h"
#include "sd-netlink.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "hashmap.h" #include "hash-funcs.h"
#include "log.h"
#include "macro.h" #include "macro.h"
#include "string-util.h"
typedef enum AddressFamily { typedef enum AddressFamily {
/* This is a bitmask, though it usually doesn't feel that way! */ /* This is a bitmask, though it usually doesn't feel that way! */
@ -52,7 +49,6 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
void network_config_section_free(NetworkConfigSection *network); void network_config_section_free(NetworkConfigSection *network);
DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free); DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
extern const struct hash_ops network_config_hash_ops; 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) { static inline bool section_is_invalid(NetworkConfigSection *section) {
/* If this returns false, then it does _not_ mean the section is valid. */ /* If this returns false, then it does _not_ mean the section is valid. */
@ -74,10 +70,3 @@ static inline bool section_is_invalid(NetworkConfigSection *section) {
} \ } \
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \ DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid); 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,7 +6,6 @@
#include "sd-bus.h" #include "sd-bus.h"
#include "bus-util.h" #include "bus-util.h"
#include "ether-addr-util.h"
#include "netlink-internal.h" #include "netlink-internal.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-link.h" #include "networkd-link.h"

View File

@ -88,9 +88,29 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Could not load configuration files: %m"); return log_error_errno(r, "Could not load configuration files: %m");
r = manager_enumerate(m); r = manager_rtnl_enumerate_links(m);
if (r < 0) if (r < 0)
return r; 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");
r = manager_start(m); r = manager_start(m);
if (r < 0) if (r < 0)

View File

@ -21,7 +21,7 @@ void traffic_control_free(TrafficControl *tc) {
} }
} }
static int traffic_control_configure(Link *link, TrafficControl *tc) { int traffic_control_configure(Link *link, TrafficControl *tc) {
assert(link); assert(link);
assert(tc); assert(tc);
@ -35,28 +35,7 @@ static int traffic_control_configure(Link *link, TrafficControl *tc) {
} }
} }
int link_configure_traffic_control(Link *link) { int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact) {
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); assert(tc);
switch(tc->kind) { switch(tc->kind) {
@ -68,14 +47,3 @@ static int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_ro
assert_not_reached("Invalid traffic control type"); 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) #define TC(tc) (&(tc)->meta)
void traffic_control_free(TrafficControl *tc); void traffic_control_free(TrafficControl *tc);
int link_configure_traffic_control(Link *link); int traffic_control_configure(Link *link, TrafficControl *tc);
void network_drop_invalid_traffic_control(Network *network); int traffic_control_section_verify(TrafficControl *tc, bool *qdisc_has_root, bool *qdisc_has_clsact);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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