Merge pull request #17240 from yuwata/network-cleanup
network: several cleanups and fix IPv4DAD and IP Masqurade
This commit is contained in:
commit
ab582fda48
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ? " " : "");
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,6 +3,7 @@ Name=eni99np1
|
|||
|
||||
[Network]
|
||||
Address=192.168.100.100/24
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[SR-IOV]
|
||||
VirtualFunction=0
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue