Merge pull request #17240 from yuwata/network-cleanup

network: several cleanups and fix IPv4DAD and IP Masqurade
This commit is contained in:
Yu Watanabe 2020-10-07 07:42:40 +09:00 committed by GitHub
commit ab582fda48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 4840 additions and 5071 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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