Merge pull request #20728 from yuwata/network-introduce-source-and-state-neighbor-rule-and-nexthops

network: introduce NetworkConfigSource/State
This commit is contained in:
Yu Watanabe
2021-09-15 20:26:44 +09:00
committed by GitHub
13 changed files with 757 additions and 699 deletions
-2
View File
@@ -238,10 +238,8 @@ static Link *link_free(Link *link) {
link->ndisc_routes = set_free(link->ndisc_routes);
link->nexthops = set_free(link->nexthops);
link->nexthops_foreign = set_free(link->nexthops_foreign);
link->neighbors = set_free(link->neighbors);
link->neighbors_foreign = set_free(link->neighbors_foreign);
link->addresses = set_free(link->addresses);
link->addresses_foreign = set_free(link->addresses_foreign);
-4
View File
@@ -92,8 +92,6 @@ typedef struct Link {
unsigned static_route_messages;
unsigned static_routing_policy_rule_messages;
unsigned address_remove_messages;
unsigned neighbor_remove_messages;
unsigned nexthop_remove_messages;
unsigned route_remove_messages;
unsigned tc_messages;
unsigned sr_iov_messages;
@@ -108,11 +106,9 @@ typedef struct Link {
Set *pool_addresses;
Set *static_addresses;
Set *neighbors;
Set *neighbors_foreign;
Set *routes;
Set *routes_foreign;
Set *nexthops;
Set *nexthops_foreign;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
+1 -5
View File
@@ -473,10 +473,7 @@ Manager* manager_free(Manager *m) {
hashmap_free(m->route_table_names_by_number);
hashmap_free(m->route_table_numbers_by_name);
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */
m->rules = set_free(m->rules);
m->rules_foreign = set_free(m->rules_foreign);
set_free(m->rules);
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
@@ -490,7 +487,6 @@ Manager* manager_free(Manager *m) {
m->routes_foreign = set_free(m->routes_foreign);
m->nexthops = set_free(m->nexthops);
m->nexthops_foreign = set_free(m->nexthops_foreign);
m->nexthops_by_id = hashmap_free(m->nexthops_by_id);
sd_event_source_unref(m->speed_meter_event_source);
-4
View File
@@ -64,17 +64,13 @@ struct Manager {
char* dynamic_hostname;
char* dynamic_timezone;
unsigned routing_policy_rule_remove_messages;
Set *rules;
Set *rules_foreign;
/* Manage nexthops by id. */
Hashmap *nexthops_by_id;
/* Manager stores nexthops without RTA_OIF attribute. */
unsigned nexthop_remove_messages;
Set *nexthops;
Set *nexthops_foreign;
/* Manager stores routes without RTA_OIF attribute. */
unsigned route_remove_messages;
+129 -144
View File
@@ -21,10 +21,8 @@ Neighbor *neighbor_free(Neighbor *neighbor) {
network_config_section_free(neighbor->section);
if (neighbor->link) {
if (neighbor->link)
set_remove(neighbor->link->neighbors, neighbor);
set_remove(neighbor->link->neighbors_foreign, neighbor);
}
return mfree(neighbor);
}
@@ -59,6 +57,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
.network = network,
.family = AF_UNSPEC,
.section = TAKE_PTR(n),
.source = NETWORK_CONFIG_SOURCE_STATIC,
};
r = hashmap_ensure_put(&network->neighbors_by_section, &network_config_hash_ops, neighbor->section, neighbor);
@@ -69,6 +68,25 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
return 0;
}
static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
_cleanup_(neighbor_freep) Neighbor *dest = NULL;
assert(neighbor);
assert(ret);
dest = newdup(Neighbor, neighbor, 1);
if (!dest)
return -ENOMEM;
/* Unset all pointers */
dest->link = NULL;
dest->network = NULL;
dest->section = NULL;
*ret = TAKE_PTR(dest);
return 0;
}
void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
assert(neighbor);
@@ -120,100 +138,32 @@ static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
assert(in);
existing = set_get(link->neighbors, in);
if (existing) {
if (ret)
*ret = existing;
return 1;
}
if (!existing)
return -ENOENT;
existing = set_get(link->neighbors_foreign, in);
if (existing) {
if (ret)
*ret = existing;
return 0;
}
return -ENOENT;
if (ret)
*ret = existing;
return 0;
}
static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in, Neighbor **ret) {
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
static int neighbor_add(Link *link, Neighbor *neighbor) {
int r;
assert(link);
assert(neighbors);
assert(in);
assert(neighbor);
neighbor = new(Neighbor, 1);
if (!neighbor)
return -ENOMEM;
*neighbor = (Neighbor) {
.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);
r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
neighbor->link = link;
if (ret)
*ret = neighbor;
TAKE_PTR(neighbor);
return 0;
}
static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) {
Neighbor *neighbor;
int r;
r = neighbor_get(link, in, &neighbor);
if (r == -ENOENT) {
/* Neighbor doesn't exist, make a new one */
r = neighbor_add_internal(link, &link->neighbors, in, &neighbor);
if (r < 0)
return r;
} else if (r == 0) {
/* Neighbor is foreign, claim it as recognized */
r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
if (r < 0)
return r;
set_remove(link->neighbors_foreign, neighbor);
} else if (r == 1) {
/* Neighbor already exists */
;
} else
return r;
if (ret)
*ret = neighbor;
return 0;
}
static int neighbor_add_foreign(Link *link, const Neighbor *in, Neighbor **ret) {
return neighbor_add_internal(link, &link->neighbors_foreign, in, ret);
}
static bool neighbor_equal(const Neighbor *n1, const Neighbor *n2) {
if (n1 == n2)
return true;
if (!n1 || !n2)
return false;
return neighbor_compare_func(n1, n2) == 0;
}
static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const Link *link) {
_cleanup_free_ char *lladdr = NULL, *dst = NULL;
_cleanup_free_ char *state = NULL, *lladdr = NULL, *dst = NULL;
assert(neighbor);
assert(str);
@@ -221,6 +171,7 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
if (!DEBUG_LOGGING)
return;
(void) network_config_state_to_string_alloc(neighbor->state, &state);
if (neighbor->lladdr_size == sizeof(struct ether_addr))
(void) ether_addr_to_string_alloc(&neighbor->lladdr.mac, &lladdr);
else if (neighbor->lladdr_size == sizeof(struct in_addr))
@@ -231,14 +182,15 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
(void) in_addr_to_string(neighbor->family, &neighbor->in_addr, &dst);
log_link_debug(link,
"%s neighbor: lladdr: %s, dst: %s",
str, strna(lladdr), strna(dst));
"%s %s neighbor (%s): lladdr: %s, dst: %s",
str, strna(network_config_source_to_string(neighbor->source)), strna(state),
strna(lladdr), strna(dst));
}
static int neighbor_configure(
const Neighbor *neighbor,
Neighbor *neighbor,
Link *link,
link_netlink_message_handler_t callback,
Neighbor **ret) {
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@@ -269,10 +221,6 @@ static int neighbor_configure(
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
r = neighbor_add(link, neighbor, ret);
if (r < 0)
return log_link_error_errno(link, r, "Could not add neighbor: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
@@ -280,6 +228,7 @@ static int neighbor_configure(
link_ref(link);
neighbor_enter_configuring(neighbor);
return r;
}
@@ -313,18 +262,41 @@ static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_messag
static int link_request_neighbor(
Link *link,
Neighbor *neighbor,
bool consume_object,
const Neighbor *neighbor,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
Neighbor *existing;
int r;
assert(link);
assert(neighbor);
assert(neighbor->source != NETWORK_CONFIG_SOURCE_FOREIGN);
log_neighbor_debug(neighbor, "Requesting", link);
return link_queue_request(link, REQUEST_TYPE_NEIGHBOR, neighbor, consume_object,
message_counter, netlink_handler, ret);
if (neighbor_get(link, neighbor, &existing) < 0) {
_cleanup_(neighbor_freep) Neighbor *tmp = NULL;
r = neighbor_dup(neighbor, &tmp);
if (r < 0)
return r;
r = neighbor_add(link, tmp);
if (r < 0)
return r;
existing = TAKE_PTR(tmp);
} else
existing->source = neighbor->source;
log_neighbor_debug(existing, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_NEIGHBOR, existing, false,
message_counter, netlink_handler, ret);
if (r <= 0)
return r;
neighbor_enter_requesting(existing);
return 1;
}
int link_request_static_neighbors(Link *link) {
@@ -338,7 +310,7 @@ int link_request_static_neighbors(Link *link) {
link->static_neighbors_configured = false;
HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
r = link_request_neighbor(link, neighbor, false, &link->static_neighbor_messages,
r = link_request_neighbor(link, neighbor, &link->static_neighbor_messages,
static_neighbor_configure_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request neighbor: %m");
@@ -360,9 +332,6 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
assert(m);
assert(link);
assert(link->neighbor_remove_messages > 0);
link->neighbor_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@@ -375,15 +344,17 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
return 1;
}
static int neighbor_remove(Neighbor *neighbor, Link *link) {
static int neighbor_remove(Neighbor *neighbor) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
Link *link;
int r;
assert(neighbor);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
assert(neighbor->link);
assert(neighbor->link->manager);
assert(neighbor->link->manager->rtnl);
link = neighbor->link;
log_neighbor_debug(neighbor, "Removing", link);
@@ -402,45 +373,49 @@ static int neighbor_remove(Neighbor *neighbor, Link *link) {
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
link->neighbor_remove_messages++;
neighbor_enter_removing(neighbor);
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;
int k, r = 0;
assert(link);
assert(link->network);
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;
}
/* First, mark all neighbors. */
SET_FOREACH(neighbor, link->neighbors) {
/* Do not remove neighbors we configured. */
if (neighbor->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
return 0;
/* Ignore neighbors not assigned yet or already removing. */
if (!neighbor_exists(neighbor))
continue;
neighbor_mark(neighbor);
}
/* Next, unmark requested neighbors. They will be configured later. */
HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
Neighbor *existing;
if (neighbor_get(link, neighbor, &existing) >= 0)
neighbor_unmark(existing);
}
SET_FOREACH(neighbor, link->neighbors) {
if (!neighbor_is_marked(neighbor))
continue;
k = neighbor_remove(neighbor);
if (k < 0 && r >= 0)
r = k;
}
return r;
}
int link_drop_neighbors(Link *link) {
@@ -450,7 +425,11 @@ int link_drop_neighbors(Link *link) {
assert(link);
SET_FOREACH(neighbor, link->neighbors) {
k = neighbor_remove(neighbor, link);
/* Ignore neighbors not assigned yet or already removing. */
if (!neighbor_exists(neighbor))
continue;
k = neighbor_remove(neighbor);
if (k < 0 && r >= 0)
r = k;
}
@@ -459,7 +438,6 @@ int link_drop_neighbors(Link *link) {
}
int request_process_neighbor(Request *req) {
Neighbor *ret;
int r;
assert(req);
@@ -470,10 +448,7 @@ int request_process_neighbor(Request *req) {
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (req->link->neighbor_remove_messages > 0)
return 0;
r = neighbor_configure(req->neighbor, req->link, req->netlink_handler, &ret);
r = neighbor_configure(req->neighbor, req->link, req->netlink_handler);
if (r < 0)
return r;
@@ -566,22 +541,32 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
switch (type) {
case RTM_NEWNEIGH:
if (neighbor)
if (neighbor) {
neighbor_enter_configured(neighbor);
log_neighbor_debug(tmp, "Received remembered", link);
else {
log_neighbor_debug(tmp, "Remembering foreign", link);
r = neighbor_add_foreign(link, tmp, NULL);
} else {
neighbor_enter_configured(tmp);
log_neighbor_debug(tmp, "Remembering", link);
r = neighbor_add(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember foreign neighbor, ignoring: %m");
return 0;
}
TAKE_PTR(tmp);
}
break;
case RTM_DELNEIGH:
log_neighbor_debug(tmp, neighbor ? "Forgetting" : "Kernel removed unknown", link);
neighbor_free(neighbor);
if (neighbor) {
neighbor_enter_removed(neighbor);
if (neighbor->state == 0) {
log_neighbor_debug(neighbor, "Forgetting", link);
neighbor_free(neighbor);
} else
log_neighbor_debug(neighbor, "Removed", link);
} else
log_neighbor_debug(tmp, "Kernel removed unknown", link);
break;
+4
View File
@@ -24,6 +24,8 @@ typedef struct Neighbor {
Network *network;
Link *link;
NetworkConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
int family;
union in_addr_union in_addr;
@@ -46,6 +48,8 @@ int request_process_neighbor(Request *req);
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Neighbor, neighbor);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_lladdr);
+261 -277
View File
@@ -31,7 +31,6 @@ NextHop *nexthop_free(NextHop *nexthop) {
if (nexthop->link) {
set_remove(nexthop->link->nexthops, nexthop);
set_remove(nexthop->link->nexthops_foreign, nexthop);
if (nexthop->link->manager && nexthop->id > 0)
hashmap_remove(nexthop->link->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id));
@@ -39,7 +38,6 @@ NextHop *nexthop_free(NextHop *nexthop) {
if (nexthop->manager) {
set_remove(nexthop->manager->nexthops, nexthop);
set_remove(nexthop->manager->nexthops_foreign, nexthop);
if (nexthop->id > 0)
hashmap_remove(nexthop->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id));
@@ -96,6 +94,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
nexthop->protocol = RTPROT_STATIC;
nexthop->network = network;
nexthop->section = TAKE_PTR(n);
nexthop->source = NETWORK_CONFIG_SOURCE_STATIC;
r = hashmap_ensure_put(&network->nexthops_by_section, &network_config_hash_ops, nexthop->section, nexthop);
if (r < 0)
@@ -221,155 +220,133 @@ int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret) {
return 0;
}
static int nexthop_get(Manager *manager, Link *link, const NextHop *in, NextHop **ret) {
NextHop *existing;
static bool nexthop_owned_by_link(const NextHop *nexthop) {
return !nexthop->blackhole && hashmap_isempty(nexthop->group);
}
static int nexthop_get(Manager *manager, Link *link, NextHop *in, NextHop **ret) {
NextHop *nexthop;
Set *nexthops;
assert(manager || link);
assert(in);
existing = set_get(link ? link->nexthops : manager->nexthops, in);
if (existing) {
if (ret)
*ret = existing;
return 1;
if (nexthop_owned_by_link(in)) {
if (!link)
return -ENOENT;
nexthops = link->nexthops;
} else {
if (!manager)
return -ENOENT;
nexthops = manager->nexthops;
}
existing = set_get(link ? link->nexthops_foreign : manager->nexthops_foreign, in);
if (existing) {
nexthop = set_get(nexthops, in);
if (nexthop) {
if (ret)
*ret = existing;
*ret = nexthop;
return 0;
}
if (in->id > 0)
return -ENOENT;
/* Also find nexthop configured without ID. */
SET_FOREACH(nexthop, nexthops) {
uint32_t id;
bool found;
id = nexthop->id;
nexthop->id = 0;
found = nexthop_equal(nexthop, in);
nexthop->id = id;
if (!found)
continue;
if (ret)
*ret = nexthop;
return 0;
}
return -ENOENT;
}
static int nexthop_add_internal(Manager *manager, Link *link, Set **nexthops, const NextHop *in, NextHop **ret) {
_cleanup_(nexthop_freep) NextHop *nexthop = NULL;
static int nexthop_add(Manager *manager, Link *link, NextHop *nexthop) {
int r;
assert(manager || link);
assert(nexthops);
assert(in);
r = nexthop_dup(in, &nexthop);
if (r < 0)
return r;
r = set_ensure_put(nexthops, &nexthop_hash_ops, nexthop);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
nexthop->link = link;
nexthop->manager = manager;
if (ret)
*ret = nexthop;
TAKE_PTR(nexthop);
return 0;
}
static int nexthop_add_foreign(Manager *manager, Link *link, const NextHop *in, NextHop **ret) {
assert(manager || link);
return nexthop_add_internal(manager, link, link ? &link->nexthops_foreign : &manager->nexthops_foreign, in, ret);
}
static bool nexthop_has_link(const NextHop *nexthop) {
return !nexthop->blackhole && hashmap_isempty(nexthop->group);
}
static int nexthop_add(Link *link, const NextHop *in, NextHop **ret) {
bool by_manager;
NextHop *nexthop;
int r;
assert(link);
assert(in);
by_manager = !nexthop_has_link(in);
if (by_manager)
r = nexthop_get(link->manager, NULL, in, &nexthop);
else
r = nexthop_get(NULL, link, in, &nexthop);
if (r == -ENOENT) {
/* NextHop does not exist, create a new one */
r = nexthop_add_internal(link->manager,
by_manager ? NULL : link,
by_manager ? &link->manager->nexthops : &link->nexthops,
in, &nexthop);
if (r < 0)
return r;
} else if (r == 0) {
/* Take over a foreign nexthop */
r = set_ensure_put(by_manager ? &link->manager->nexthops : &link->nexthops,
&nexthop_hash_ops, nexthop);
if (r < 0)
return r;
set_remove(by_manager ? link->manager->nexthops_foreign : link->nexthops_foreign, nexthop);
} else if (r == 1) {
/* NextHop exists, do nothing */
;
} else
return r;
if (ret)
*ret = nexthop;
return 0;
}
static int nexthop_update(Manager *manager, Link *link, NextHop *nexthop, const NextHop *in) {
Set *nexthops;
int r;
/* link may be NULL. */
assert(manager);
assert(nexthop);
assert(in);
assert(in->id > 0);
assert(nexthop->id > 0);
/* This updates nexthop ID if necessary, and register the nexthop to Manager. */
if (nexthop_owned_by_link(nexthop)) {
assert(link);
if (nexthop->id > 0) {
if (nexthop->id == in->id)
goto set_manager;
return -EINVAL;
r = set_ensure_put(&link->nexthops, &nexthop_hash_ops, nexthop);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
nexthop->link = link;
manager = link->manager;
} else {
assert(manager);
r = set_ensure_put(&manager->nexthops, &nexthop_hash_ops, nexthop);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
nexthop->manager = manager;
}
nexthops = link ? link->nexthops : manager->nexthops;
nexthop = set_remove(nexthops, nexthop);
if (!nexthop)
return -ENOENT;
nexthop->id = in->id;
r = set_put(nexthops, nexthop);
if (r <= 0) {
int k;
/* On failure, revert the change. */
nexthop->id = 0;
k = set_put(nexthops, nexthop);
if (k <= 0) {
nexthop_free(nexthop);
return k < 0 ? k : -EEXIST;
}
return r < 0 ? r : -EEXIST;
}
set_manager:
return hashmap_ensure_put(&manager->nexthops_by_id, NULL, UINT32_TO_PTR(nexthop->id), nexthop);
}
static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *str, const Link *link) {
_cleanup_free_ char *gw = NULL, *group = NULL;
static int nexthop_acquire_id(Manager *manager, NextHop *nexthop) {
_cleanup_set_free_ Set *ids = NULL;
Network *network;
uint32_t id;
int r;
assert(manager);
assert(nexthop);
if (nexthop->id > 0)
return 0;
/* Find the lowest unused ID. */
ORDERED_HASHMAP_FOREACH(network, manager->networks) {
NextHop *tmp;
HASHMAP_FOREACH(tmp, network->nexthops_by_section) {
if (tmp->id == 0)
continue;
r = set_ensure_put(&ids, NULL, UINT32_TO_PTR(tmp->id));
if (r < 0)
return r;
}
}
for (id = 1; id < UINT32_MAX; id++) {
if (manager_get_nexthop_by_id(manager, id, NULL) >= 0)
continue;
if (set_contains(ids, UINT32_TO_PTR(id)))
continue;
break;
}
nexthop->id = id;
return 0;
}
static void log_nexthop_debug(const NextHop *nexthop, const char *str, const Link *link) {
_cleanup_free_ char *state = NULL, *gw = NULL, *group = NULL;
struct nexthop_grp *nhg;
assert(nexthop);
@@ -380,29 +357,25 @@ static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *s
if (!DEBUG_LOGGING)
return;
char new_id[STRLEN("→") + DECIMAL_STR_MAX(uint32_t)] = "";
if (nexthop->id != id)
xsprintf(new_id, "→%"PRIu32, id);
(void) network_config_state_to_string_alloc(nexthop->state, &state);
(void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw);
HASHMAP_FOREACH(nhg, nexthop->group)
(void) strextendf_with_separator(&group, ",", "%"PRIu32":%"PRIu32, nhg->id, nhg->weight+1);
log_link_debug(link, "%s nexthop: id: %"PRIu32"%s, gw: %s, blackhole: %s, group: %s",
str, nexthop->id, new_id, strna(gw), yes_no(nexthop->blackhole), strna(group));
log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s",
str, strna(network_config_source_to_string(nexthop->source)), strna(state),
nexthop->id, strna(gw), yes_no(nexthop->blackhole), strna(group));
}
static int link_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
assert(link);
assert(link->nexthop_remove_messages > 0);
link->nexthop_remove_messages--;
/* link may be NULL. */
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
@@ -412,37 +385,25 @@ static int link_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
static int manager_nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
int r;
assert(m);
assert(manager);
assert(manager->nexthop_remove_messages > 0);
manager->nexthop_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ENOENT)
log_message_warning_errno(m, r, "Could not drop nexthop, ignoring");
return 1;
}
static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link) {
static int nexthop_remove(NextHop *nexthop) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
Manager *manager;
Link *link;
int r;
assert(nexthop);
assert(manager);
assert(nexthop->manager || (nexthop->link && nexthop->link->manager));
/* link may be NULL. */
link = nexthop->link;
manager = nexthop->manager ?: nexthop->link->manager;
if (nexthop->id == 0) {
log_link_debug(link, "Cannot remove nexthop without valid ID, ignoring.");
return 0;
}
log_nexthop_debug(nexthop, nexthop->id, "Removing", link);
log_nexthop_debug(nexthop, "Removing", link);
r = sd_rtnl_message_new_nexthop(manager->rtnl, &req, RTM_DELNEXTHOP, AF_UNSPEC, RTPROT_UNSPEC);
if (r < 0)
@@ -452,30 +413,21 @@ static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link)
if (r < 0)
return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m");
if (link)
r = netlink_call_async(manager->rtnl, NULL, req, link_nexthop_remove_handler,
link_netlink_destroy_callback, link);
else
r = netlink_call_async(manager->rtnl, NULL, req, manager_nexthop_remove_handler,
NULL, manager);
r = netlink_call_async(manager->rtnl, NULL, req, nexthop_remove_handler,
link ? link_netlink_destroy_callback : NULL, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link); /* link may be NULL, link_ref() is OK with that */
if (link)
link->nexthop_remove_messages++;
else
manager->nexthop_remove_messages++;
nexthop_enter_removing(nexthop);
return 0;
}
static int nexthop_configure(
const NextHop *nexthop,
NextHop *nexthop,
Link *link,
link_netlink_message_handler_t callback,
NextHop **ret) {
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@@ -487,7 +439,7 @@ static int nexthop_configure(
assert(IN_SET(nexthop->family, AF_UNSPEC, AF_INET, AF_INET6));
assert(callback);
log_nexthop_debug(nexthop, nexthop->id, "Configuring", link);
log_nexthop_debug(nexthop, "Configuring", link);
r = sd_rtnl_message_new_nexthop(link->manager->rtnl, &req,
RTM_NEWNEXTHOP, nexthop->family,
@@ -539,10 +491,6 @@ static int nexthop_configure(
}
}
r = nexthop_add(link, nexthop, ret);
if (r < 0)
return log_link_error_errno(link, r, "Could not add nexthop: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
@@ -550,7 +498,8 @@ static int nexthop_configure(
link_ref(link);
return r;
nexthop_enter_configuring(nexthop);
return 0;
}
static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@@ -583,17 +532,44 @@ static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
static int link_request_nexthop(
Link *link,
NextHop *nexthop,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
NextHop *existing;
int r;
assert(link);
assert(nexthop);
assert(nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN);
log_nexthop_debug(nexthop, nexthop->id, "Requesting", link);
return link_queue_request(link, REQUEST_TYPE_NEXTHOP, nexthop, consume_object,
message_counter, netlink_handler, ret);
if (nexthop_get(link->manager, link, nexthop, &existing) < 0) {
_cleanup_(nexthop_freep) NextHop *tmp = NULL;
r = nexthop_dup(nexthop, &tmp);
if (r < 0)
return r;
r = nexthop_acquire_id(link->manager, tmp);
if (r < 0)
return r;
r = nexthop_add(link->manager, link, tmp);
if (r < 0)
return r;
existing = TAKE_PTR(tmp);
} else
existing->source = nexthop->source;
log_nexthop_debug(existing, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_NEXTHOP, existing, false,
message_counter, netlink_handler, ret);
if (r <= 0)
return r;
nexthop_enter_requesting(existing);
return 1;
}
int link_request_static_nexthops(Link *link, bool only_ipv4) {
@@ -609,7 +585,7 @@ int link_request_static_nexthops(Link *link, bool only_ipv4) {
if (only_ipv4 && nh->family != AF_INET)
continue;
r = link_request_nexthop(link, nh, false, &link->static_nexthop_messages,
r = link_request_nexthop(link, nh, &link->static_nexthop_messages,
static_nexthop_handler, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request nexthop: %m");
@@ -626,58 +602,52 @@ int link_request_static_nexthops(Link *link, bool only_ipv4) {
return 0;
}
static bool link_has_nexthop(const Link *link, const NextHop *nexthop) {
NextHop *net_nexthop;
assert(link);
assert(nexthop);
if (!link->network)
return false;
HASHMAP_FOREACH(net_nexthop, link->network->nexthops_by_section)
if (nexthop_equal(net_nexthop, nexthop))
return true;
return false;
}
static bool links_have_nexthop(const Manager *manager, const NextHop *nexthop, const Link *except) {
Link *link;
assert(manager);
HASHMAP_FOREACH(link, manager->links_by_index) {
if (link == except)
continue;
if (link_has_nexthop(link, nexthop))
return true;
}
return false;
}
static int manager_drop_nexthops_internal(Manager *manager, bool foreign, const Link *except) {
static int manager_drop_nexthops(Manager *manager, bool foreign, const Link *except) {
NextHop *nexthop;
Set *nexthops;
Link *link;
int k, r = 0;
assert(manager);
nexthops = foreign ? manager->nexthops_foreign : manager->nexthops;
SET_FOREACH(nexthop, nexthops) {
/* First, mark all nexthops. */
SET_FOREACH(nexthop, manager->nexthops) {
/* do not touch nexthop created by the kernel */
if (nexthop->protocol == RTPROT_KERNEL)
continue;
/* The nexthop will be configured later, or already configured by a link. */
if (links_have_nexthop(manager, nexthop, except))
/* When 'foreign' is true, do not remove nexthops we configured. */
if (foreign && nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
/* The existing links do not have the nexthop. Let's drop this now. It may be
* re-configured later. */
k = nexthop_remove(nexthop, manager, NULL);
/* Ignore nexthops not assigned yet or already removed. */
if (!nexthop_exists(nexthop))
continue;
nexthop_mark(nexthop);
}
/* Then, unmark all nexthops requested by active links. */
HASHMAP_FOREACH(link, manager->links_by_index) {
if (link == except)
continue;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
HASHMAP_FOREACH(nexthop, link->network->nexthops_by_section) {
NextHop *existing;
if (nexthop_get(manager, NULL, nexthop, &existing) >= 0)
nexthop_unmark(existing);
}
}
/* Finally, remove all marked nexthops. */
SET_FOREACH(nexthop, manager->nexthops) {
if (!nexthop_is_marked(nexthop))
continue;
k = nexthop_remove(nexthop);
if (k < 0 && r >= 0)
r = k;
}
@@ -685,35 +655,50 @@ static int manager_drop_nexthops_internal(Manager *manager, bool foreign, const
return r;
}
static int manager_drop_foreign_nexthops(Manager *manager) {
return manager_drop_nexthops_internal(manager, true, NULL);
}
static int manager_drop_nexthops(Manager *manager, const Link *except) {
return manager_drop_nexthops_internal(manager, false, except);
}
int link_drop_foreign_nexthops(Link *link) {
NextHop *nexthop;
int k, r = 0;
assert(link);
assert(link->manager);
assert(link->network);
SET_FOREACH(nexthop, link->nexthops_foreign) {
/* First, mark all nexthops. */
SET_FOREACH(nexthop, link->nexthops) {
/* do not touch nexthop created by the kernel */
if (nexthop->protocol == RTPROT_KERNEL)
continue;
if (link_has_nexthop(link, nexthop))
k = nexthop_add(link, nexthop, NULL);
else
k = nexthop_remove(nexthop, link->manager, link);
/* Do not remove nexthops we configured. */
if (nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
/* Ignore nexthops not assigned yet or already removed. */
if (!nexthop_exists(nexthop))
continue;
nexthop_mark(nexthop);
}
/* Then, unmark all nexthops requested by active links. */
HASHMAP_FOREACH(nexthop, link->network->nexthops_by_section) {
NextHop *existing;
if (nexthop_get(NULL, link, nexthop, &existing) >= 0)
nexthop_unmark(existing);
}
/* Finally, remove all marked rules. */
SET_FOREACH(nexthop, link->nexthops) {
if (!nexthop_is_marked(nexthop))
continue;
k = nexthop_remove(nexthop);
if (k < 0 && r >= 0)
r = k;
}
k = manager_drop_foreign_nexthops(link->manager);
k = manager_drop_nexthops(link->manager, /* foreign = */ true, NULL);
if (k < 0 && r >= 0)
r = k;
@@ -732,12 +717,16 @@ int link_drop_nexthops(Link *link) {
if (nexthop->protocol == RTPROT_KERNEL)
continue;
k = nexthop_remove(nexthop, link->manager, link);
/* Ignore nexthops not assigned yet or already removing. */
if (!nexthop_exists(nexthop))
continue;
k = nexthop_remove(nexthop);
if (k < 0 && r >= 0)
r = k;
}
k = manager_drop_nexthops(link->manager, link);
k = manager_drop_nexthops(link->manager, /* foreign = */ false, link);
if (k < 0 && r >= 0)
r = k;
@@ -753,10 +742,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
if (!link_is_ready_to_configure(link, false))
return false;
if (!nexthop_has_link(nexthop)) {
if (link->manager->nexthop_remove_messages > 0)
return false;
} else {
if (nexthop_owned_by_link(nexthop)) {
Link *l;
/* TODO: fdb nexthop does not require IFF_UP. The conditions below needs to be updated
@@ -770,18 +756,22 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
HASHMAP_FOREACH(l, link->manager->links_by_index) {
if (l->address_remove_messages > 0)
return false;
if (l->nexthop_remove_messages > 0)
return false;
if (l->route_remove_messages > 0)
return false;
}
}
/* All group members must be configured first. */
HASHMAP_FOREACH(nhg, nexthop->group)
if (manager_get_nexthop_by_id(link->manager, nhg->id, NULL) < 0)
HASHMAP_FOREACH(nhg, nexthop->group) {
NextHop *g;
if (manager_get_nexthop_by_id(link->manager, nhg->id, &g) < 0)
return false;
if (!nexthop_exists(g))
return false;
}
if (nexthop->id == 0) {
Request *req;
@@ -797,7 +787,6 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
}
int request_process_nexthop(Request *req) {
NextHop *ret;
int r;
assert(req);
@@ -808,7 +797,7 @@ int request_process_nexthop(Request *req) {
if (!nexthop_is_ready_to_configure(req->link, req->nexthop))
return 0;
r = nexthop_configure(req->nexthop, req->link, req->netlink_handler, &ret);
r = nexthop_configure(req->nexthop, req->link, req->netlink_handler);
if (r < 0)
return r;
@@ -956,45 +945,40 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
/* All blackhole or group nexthops are managed by Manager. Note that the linux kernel does not
* set NHA_OID attribute when NHA_BLACKHOLE or NHA_GROUP is set. Just for safety. */
if (!nexthop_has_link(tmp))
if (!nexthop_owned_by_link(tmp))
link = NULL;
r = nexthop_get(m, link, tmp, &nexthop);
if (r < 0) {
uint32_t id;
/* The nexthop may be created without setting NHA_ID. */
id = tmp->id;
tmp->id = 0;
(void) nexthop_get(m, link, tmp, &nexthop);
tmp->id = id;
}
(void) nexthop_get(m, link, tmp, &nexthop);
switch (type) {
case RTM_NEWNEXTHOP:
if (nexthop)
log_nexthop_debug(nexthop, tmp->id, "Received remembered", link);
else {
log_nexthop_debug(tmp, tmp->id, "Remembering foreign", link);
r = nexthop_add_foreign(m, link, tmp, &nexthop);
if (nexthop) {
nexthop_enter_configured(nexthop);
log_nexthop_debug(tmp, "Received remembered", link);
} else {
nexthop_enter_configured(tmp);
log_nexthop_debug(tmp, "Remembering", link);
r = nexthop_add(m, link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m");
return 0;
}
TAKE_PTR(tmp);
}
r = nexthop_update(m, link, nexthop, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Could not update nexthop, ignoring: %m");
return 0;
}
break;
case RTM_DELNEXTHOP:
log_nexthop_debug(tmp, tmp->id, nexthop ? "Forgetting" : "Kernel removed unknown", link);
nexthop_free(nexthop);
if (nexthop) {
nexthop_enter_removed(nexthop);
if (nexthop->state == 0) {
log_nexthop_debug(nexthop, "Forgetting", link);
nexthop_free(nexthop);
} else
log_nexthop_debug(nexthop, "Removed", link);
} else
log_nexthop_debug(tmp, "Kernel removed unknown", link);
break;
default:
+5 -2
View File
@@ -20,10 +20,11 @@ typedef struct Request Request;
typedef struct NextHop {
Network *network;
NetworkConfigSection *section;
Manager *manager;
Link *link;
NetworkConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
uint8_t protocol;
@@ -51,6 +52,8 @@ int request_process_nexthop(Request *req);
int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret);
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(NextHop, nexthop);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family);
+12 -7
View File
@@ -1709,14 +1709,21 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
if (manager_get_nexthop_by_id(link->manager, route->nexthop_id, &nh) < 0)
return false;
HASHMAP_FOREACH(nhg, nh->group)
if (manager_get_nexthop_by_id(link->manager, nhg->id, NULL) < 0)
if (!nexthop_exists(nh))
return false;
HASHMAP_FOREACH(nhg, nh->group) {
NextHop *g;
if (manager_get_nexthop_by_id(link->manager, nhg->id, &g) < 0)
return false;
if (!nexthop_exists(g))
return false;
}
}
if (route_type_is_reject(route) || (nh && nh->blackhole)) {
if (nh && link->manager->nexthop_remove_messages > 0)
return false;
if (route_type_is_reject(route)) {
if (link->manager->route_remove_messages > 0)
return false;
} else {
@@ -1725,8 +1732,6 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
HASHMAP_FOREACH(l, link->manager->links_by_index) {
if (l->address_remove_messages > 0)
return false;
if (l->nexthop_remove_messages > 0)
return false;
if (l->route_remove_messages > 0)
return false;
}
+199 -247
View File
@@ -41,10 +41,8 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
hashmap_remove(rule->network->rules_by_section, rule->section);
}
if (rule->manager) {
if (rule->manager)
set_remove(rule->manager->rules, rule);
set_remove(rule->manager->rules_foreign, rule);
}
network_config_section_free(rule->section);
free(rule->iif);
@@ -101,6 +99,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
rule->network = network;
rule->section = TAKE_PTR(n);
rule->source = NETWORK_CONFIG_SOURCE_STATIC;
rule->protocol = RTPROT_STATIC;
r = hashmap_ensure_put(&network->rules_by_section, &network_config_hash_ops, rule->section, rule);
@@ -163,9 +162,7 @@ void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash
siphash24_compress(&rule->type, sizeof(rule->type), state);
siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
siphash24_compress_boolean(rule->priority_set, state);
if (rule->priority_set)
siphash24_compress(&rule->priority, sizeof(rule->priority), state);
siphash24_compress(&rule->priority, sizeof(rule->priority), state);
siphash24_compress(&rule->table, sizeof(rule->table), state);
siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
@@ -231,16 +228,10 @@ int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPo
if (r != 0)
return r;
r = CMP(a->priority_set, b->priority_set);
r = CMP(a->priority, b->priority);
if (r != 0)
return r;
if (a->priority_set) {
r = CMP(a->priority, b->priority);
if (r != 0)
return r;
}
r = CMP(a->table, b->table);
if (r != 0)
return r;
@@ -301,130 +292,113 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
routing_policy_rule_compare_func,
routing_policy_rule_free);
static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, bool require_priority, RoutingPolicyRule **ret) {
RoutingPolicyRule *existing;
int r;
static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
RoutingPolicyRule *rule;
assert(m);
assert(in);
existing = set_get(m->rules, rule);
if (existing) {
rule = set_get(m->rules, in);
if (rule) {
if (ret)
*ret = existing;
return 1;
}
existing = set_get(m->rules_foreign, rule);
if (existing) {
if (ret)
*ret = existing;
*ret = rule;
return 0;
}
if (!require_priority && rule->priority_set) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
if (in->priority_set)
return -ENOENT;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
/* Also find rules configured without priority. */
SET_FOREACH(rule, m->rules) {
uint32_t priority;
bool found;
tmp->priority_set = false;
if (rule->priority_set)
/* The rule is configured with priority. */
continue;
existing = set_get(m->rules, tmp);
if (existing) {
priority = rule->priority;
rule->priority = 0;
found = routing_policy_rule_equal(rule, in);
rule->priority = priority;
if (found) {
if (ret)
*ret = existing;
return 1;
*ret = rule;
return 0;
}
}
return -ENOENT;
}
static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
RoutingPolicyRule *existing;
int r;
assert(m);
assert(in);
assert(IN_SET(in->family, AF_INET, AF_INET6));
r = routing_policy_rule_dup(in, &rule);
if (r < 0)
return r;
r = routing_policy_rule_get(m, rule, true, &existing);
if (r == -ENOENT) {
/* Rule does not exist, use a new one. */
r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
if (r < 0)
return r;
assert(r > 0);
rule->manager = m;
existing = TAKE_PTR(rule);
} else if (r < 0)
return r;
else if (r == 0) {
/* Take over a foreign rule. */
r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, existing);
if (r < 0)
return r;
assert(r > 0);
set_remove(m->rules_foreign, existing);
} /* else r > 0: already exists, do nothing. */
if (ret)
*ret = existing;
return 0;
}
static int routing_policy_rule_consume_foreign(Manager *m, RoutingPolicyRule *rule) {
static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule) {
int r;
assert(m);
assert(rule);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
r = set_ensure_consume(&m->rules_foreign, &routing_policy_rule_hash_ops, rule);
if (r <= 0)
r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
rule->manager = m;
return 1;
return 0;
}
static int routing_policy_rule_update_priority(RoutingPolicyRule *rule, uint32_t priority) {
static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyRule *rule) {
_cleanup_set_free_ Set *priorities = NULL;
RoutingPolicyRule *tmp;
uint32_t priority;
Network *network;
int r;
assert(manager);
assert(rule);
assert(rule->manager);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
if (rule->priority_set)
return 0;
if (!set_remove(rule->manager->rules, rule))
return -ENOENT;
/* Find the highest unused priority. Note that 32766 is already used by kernel.
* See kernel_rules[] below. */
rule->priority = priority;
rule->priority_set = true;
r = set_put(rule->manager->rules, rule);
if (r <= 0) {
/* Undo */
rule->priority_set = false;
assert_se(set_put(rule->manager->rules, rule) > 0);
return r == 0 ? -EEXIST : r;
SET_FOREACH(tmp, manager->rules) {
if (tmp->family != rule->family)
continue;
if (tmp->priority == 0 || tmp->priority > 32765)
continue;
r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
if (r < 0)
return r;
}
return 1;
ORDERED_HASHMAP_FOREACH(network, manager->networks)
HASHMAP_FOREACH(tmp, network->rules_by_section) {
if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
continue;
if (!tmp->priority_set)
continue;
if (tmp->priority == 0 || tmp->priority > 32765)
continue;
r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
if (r < 0)
return r;
}
for (priority = 32765; priority > 0; priority--)
if (!set_contains(priorities, UINT32_TO_PTR(priority)))
break;
rule->priority = priority;
return 0;
}
static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
_cleanup_free_ char *from = NULL, *to = NULL, *table = NULL;
_cleanup_free_ char *state = NULL, *from = NULL, *to = NULL, *table = NULL;
assert(rule);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
@@ -436,13 +410,15 @@ static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const c
if (!DEBUG_LOGGING)
return;
(void) network_config_state_to_string_alloc(rule->state, &state);
(void) in_addr_prefix_to_string(rule->family, &rule->from, rule->from_prefixlen, &from);
(void) in_addr_prefix_to_string(rule->family, &rule->to, rule->to_prefixlen, &to);
(void) manager_get_route_table_to_string(m, rule->table, &table);
log_link_debug(link,
"%s routing policy rule: priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s",
str, rule->priority, strna(from), strna(to),
"%s %s routing policy rule (%s): priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s",
str, strna(network_config_source_to_string(rule->source)), strna(state),
rule->priority, strna(from), strna(to),
strna(rule->iif), strna(rule->oif), strna(table));
}
@@ -474,11 +450,9 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
}
if (rule->priority_set) {
r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
}
r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
if (rule->tos > 0) {
r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
@@ -567,14 +541,10 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
return 0;
}
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
int r;
assert(m);
assert(manager);
assert(manager->routing_policy_rule_remove_messages > 0);
manager->routing_policy_rule_remove_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0)
@@ -583,18 +553,18 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
return 1;
}
static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *manager) {
static int routing_policy_rule_remove(RoutingPolicyRule *rule) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert(rule);
assert(manager);
assert(manager->rtnl);
assert(rule->manager);
assert(rule->manager->rtnl);
assert(IN_SET(rule->family, AF_INET, AF_INET6));
log_routing_policy_rule_debug(rule, "Removing", NULL, manager);
log_routing_policy_rule_debug(rule, "Removing", NULL, rule->manager);
r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family);
r = sd_rtnl_message_new_routing_policy_rule(rule->manager->rtnl, &m, RTM_DELRULE, rule->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
@@ -602,22 +572,20 @@ static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *ma
if (r < 0)
return r;
r = netlink_call_async(manager->rtnl, NULL, m,
r = netlink_call_async(rule->manager->rtnl, NULL, m,
routing_policy_rule_remove_handler,
NULL, manager);
NULL, NULL);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
manager->routing_policy_rule_remove_messages++;
routing_policy_rule_enter_removing(rule);
return 0;
}
static int routing_policy_rule_configure(
const RoutingPolicyRule *rule,
RoutingPolicyRule *rule,
Link *link,
link_netlink_message_handler_t callback,
RoutingPolicyRule **ret) {
link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
@@ -640,10 +608,6 @@ static int routing_policy_rule_configure(
if (r < 0)
return r;
r = routing_policy_rule_add(link->manager, rule, ret);
if (r < 0)
return log_link_error_errno(link, r, "Could not add rule: %m");
r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
link_netlink_destroy_callback, link);
if (r < 0)
@@ -651,94 +615,70 @@ static int routing_policy_rule_configure(
link_ref(link);
routing_policy_rule_enter_configuring(rule);
return r;
}
static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) {
Link *link;
int r;
assert(m);
assert(rule);
HASHMAP_FOREACH(link, m->links_by_index) {
RoutingPolicyRule *link_rule;
if (link == except)
continue;
if (!link->network)
continue;
HASHMAP_FOREACH(link_rule, link->network->rules_by_section)
if (IN_SET(link_rule->family, AF_INET, AF_INET6)) {
if (routing_policy_rule_equal(link_rule, rule))
return true;
} else {
/* The case Family=both. */
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(link_rule, &tmp);
if (r < 0)
return r;
tmp->family = AF_INET;
if (routing_policy_rule_equal(tmp, rule))
return true;
tmp->family = AF_INET6;
if (routing_policy_rule_equal(tmp, rule))
return true;
}
}
return false;
}
int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) {
RoutingPolicyRule *rule;
int k, r = 0;
Set *rules;
Link *link;
int k, r;
assert(m);
rules = foreign ? m->rules_foreign : m->rules;
SET_FOREACH(rule, rules) {
/* First, mark all existing rules. */
SET_FOREACH(rule, m->rules) {
/* Do not touch rules managed by kernel. */
if (rule->protocol == RTPROT_KERNEL)
continue;
/* The rule will be configured later, or already configured by a link. */
k = links_have_routing_policy_rule(m, rule, except);
if (k != 0) {
if (k < 0 && r >= 0)
r = k;
/* When 'foreign' is true, do not remove rules we configured. */
if (foreign && rule->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
}
if (!foreign) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
/* Ignore rules not assigned yet or already removing. */
if (!routing_policy_rule_exists(rule))
continue;
/* The rule may be configured without priority. Try to find without priority. */
routing_policy_rule_mark(rule);
}
k = routing_policy_rule_dup(rule, &tmp);
if (k < 0) {
if (r >= 0)
r = k;
continue;
}
/* Then, unmark all rules requested by active links. */
HASHMAP_FOREACH(link, m->links_by_index) {
if (link == except)
continue;
tmp->priority_set = false;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
k = links_have_routing_policy_rule(m, tmp, except);
if (k != 0) {
if (k < 0 && r >= 0)
r = k;
continue;
HASHMAP_FOREACH(rule, link->network->rules_by_section) {
RoutingPolicyRule *existing;
if (IN_SET(rule->family, AF_INET, AF_INET6)) {
if (routing_policy_rule_get(m, rule, &existing) >= 0)
routing_policy_rule_unmark(existing);
} else {
/* The case Family=both. */
rule->family = AF_INET;
if (routing_policy_rule_get(m, rule, &existing) >= 0)
routing_policy_rule_unmark(existing);
rule->family = AF_INET6;
if (routing_policy_rule_get(m, rule, &existing) >= 0)
routing_policy_rule_unmark(existing);
rule->family = AF_UNSPEC;
}
}
}
k = routing_policy_rule_remove(rule, m);
/* Finally, remove all marked rules. */
r = 0;
SET_FOREACH(rule, m->rules) {
if (!routing_policy_rule_is_marked(rule))
continue;
k = routing_policy_rule_remove(rule);
if (k < 0 && r >= 0)
r = k;
}
@@ -779,64 +719,73 @@ static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_net
static int link_request_routing_policy_rule(
Link *link,
RoutingPolicyRule *rule,
bool consume_object,
unsigned *message_counter,
link_netlink_message_handler_t netlink_handler,
Request **ret) {
RoutingPolicyRule *existing;
int r;
assert(link);
assert(link->manager);
assert(rule);
assert(rule->source != NETWORK_CONFIG_SOURCE_FOREIGN);
log_routing_policy_rule_debug(rule, "Requesting", link, link->manager);
return link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, rule, consume_object,
message_counter, netlink_handler, ret);
if (routing_policy_rule_get(link->manager, rule, &existing) < 0) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
r = routing_policy_rule_acquire_priority(link->manager, tmp);
if (r < 0)
return r;
r = routing_policy_rule_add(link->manager, tmp);
if (r < 0)
return r;
existing = TAKE_PTR(tmp);
} else
existing->source = rule->source;
log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
r = link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, existing, false,
message_counter, netlink_handler, ret);
if (r <= 0)
return r;
routing_policy_rule_enter_requesting(existing);
return 1;
}
static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
int r;
if (IN_SET(rule->family, AF_INET, AF_INET6))
return link_request_routing_policy_rule(link, rule, false,
return link_request_routing_policy_rule(link, rule,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
tmp->family = AF_INET;
r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (r < 0)
return r;
rule->family = AF_INET;
r = link_request_routing_policy_rule(link, rule,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (r < 0) {
rule->family = AF_UNSPEC;
return r;
}
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_dup(rule, &tmp);
if (r < 0)
return r;
tmp->family = AF_INET6;
r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
if (r < 0)
return r;
}
return 0;
rule->family = AF_INET6;
r = link_request_routing_policy_rule(link, rule,
&link->static_routing_policy_rule_messages,
static_routing_policy_rule_configure_handler,
NULL);
rule->family = AF_UNSPEC;
return r;
}
int link_request_static_routing_policy_rules(Link *link) {
@@ -866,7 +815,6 @@ int link_request_static_routing_policy_rules(Link *link) {
}
int request_process_routing_policy_rule(Request *req) {
RoutingPolicyRule *ret = NULL; /* avoid false maybe-uninitialized warning */
int r;
assert(req);
@@ -877,10 +825,7 @@ int request_process_routing_policy_rule(Request *req) {
if (!link_is_ready_to_configure(req->link, false))
return 0;
if (req->link->manager->routing_policy_rule_remove_messages > 0)
return 0;
r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler, &ret);
r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler);
if (r < 0)
return r;
@@ -1090,28 +1035,35 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
* protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
(void) routing_policy_rule_get(m, tmp, false, &rule);
(void) routing_policy_rule_get(m, tmp, &rule);
switch (type) {
case RTM_NEWRULE:
if (rule) {
log_routing_policy_rule_debug(tmp, "Received remembered", NULL, m);
r = routing_policy_rule_update_priority(rule, tmp->priority);
if (r < 0)
log_warning_errno(r, "Failed to update priority of remembered routing policy rule, ignoring: %m");
} else if (!m->manage_foreign_rules)
log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m);
else {
log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m);
r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp));
if (r < 0)
routing_policy_rule_enter_configured(rule);
log_routing_policy_rule_debug(rule, "Received remembered", NULL, m);
} else if (!m->manage_foreign_rules) {
routing_policy_rule_enter_configured(tmp);
log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
} else {
routing_policy_rule_enter_configured(tmp);
log_routing_policy_rule_debug(tmp, "Remembering", NULL, m);
r = routing_policy_rule_add(m, tmp);
if (r < 0) {
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
return 0;
}
TAKE_PTR(tmp);
}
break;
case RTM_DELRULE:
if (rule) {
log_routing_policy_rule_debug(tmp, "Forgetting", NULL, m);
routing_policy_rule_free(rule);
routing_policy_rule_enter_removed(rule);
if (rule->state == 0) {
log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
routing_policy_rule_free(rule);
} else
log_routing_policy_rule_debug(rule, "Removed", NULL, m);
} else
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
break;
@@ -18,6 +18,8 @@ typedef struct RoutingPolicyRule {
Manager *manager;
Network *network;
NetworkConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
bool invert_rule;
bool priority_set;
@@ -70,6 +72,8 @@ static inline int manager_drop_routing_policy_rules(Manager *m, const Link *exce
return manager_drop_routing_policy_rules_internal(m, false, except);
}
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(RoutingPolicyRule, routing_policy_rule);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_fwmark_mask);
+45 -7
View File
@@ -10,46 +10,84 @@
#include "string-util.h"
#include "web-util.h"
static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = {
/* This is used in log messages, and never used in parsing settings. So, upper cases are OK. */
static const char * const network_config_source_table[_NETWORK_CONFIG_SOURCE_MAX] = {
[NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
[NETWORK_CONFIG_SOURCE_STATIC] = "static",
[NETWORK_CONFIG_SOURCE_IPV4LL] = "IPv4LL",
[NETWORK_CONFIG_SOURCE_DHCP4] = "DHCPv4",
[NETWORK_CONFIG_SOURCE_DHCP6] = "DHCPv6",
[NETWORK_CONFIG_SOURCE_DHCP6PD] = "DHCPv6-PD",
[NETWORK_CONFIG_SOURCE_NDISC] = "NDisc",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource);
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
static const struct {
NetworkConfigState state;
const char *str;
} map[] = {
{ .state = NETWORK_CONFIG_STATE_PROBING, .str = "probing", },
{ .state = NETWORK_CONFIG_STATE_REQUESTING, .str = "requesting", },
{ .state = NETWORK_CONFIG_STATE_CONFIGURING, .str = "configuring", },
{ .state = NETWORK_CONFIG_STATE_CONFIGURED, .str = "configured", },
{ .state = NETWORK_CONFIG_STATE_MARKED, .str = "marked", },
{ .state = NETWORK_CONFIG_STATE_REMOVING, .str = "removing", },
};
_cleanup_free_ char *buf = NULL;
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (FLAGS_SET(s, map[i].state) &&
!strextend_with_separator(&buf, ",", map[i].str))
return -ENOMEM;
*ret = TAKE_PTR(buf);
return 0;
}
static const char * const address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "no",
[ADDRESS_FAMILY_YES] = "yes",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
static const char * const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_YES] = "both",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const nexthop_address_family_table[_ADDRESS_FAMILY_MAX] = {
static const char * const nexthop_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const duplicate_address_detection_address_family_table[_ADDRESS_FAMILY_MAX] = {
static const char * const duplicate_address_detection_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "none",
[ADDRESS_FAMILY_YES] = "both",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const dhcp_deprecated_address_family_table[_ADDRESS_FAMILY_MAX] = {
static const char * const dhcp_deprecated_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "none",
[ADDRESS_FAMILY_YES] = "both",
[ADDRESS_FAMILY_IPV4] = "v4",
[ADDRESS_FAMILY_IPV6] = "v6",
};
static const char* const ip_masquerade_address_family_table[_ADDRESS_FAMILY_MAX] = {
static const char * const ip_masquerade_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "no",
[ADDRESS_FAMILY_YES] = "both",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
static const char * const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
[SD_DHCP_LEASE_DNS] = "DNS servers",
[SD_DHCP_LEASE_NTP] = "NTP servers",
[SD_DHCP_LEASE_SIP] = "SIP servers",
+97
View File
@@ -19,11 +19,108 @@ typedef struct NetworkConfigSection {
char filename[];
} NetworkConfigSection;
typedef enum NetworkConfigSource {
NETWORK_CONFIG_SOURCE_FOREIGN, /* configured by kernel */
NETWORK_CONFIG_SOURCE_STATIC,
NETWORK_CONFIG_SOURCE_IPV4LL,
NETWORK_CONFIG_SOURCE_DHCP4,
NETWORK_CONFIG_SOURCE_DHCP6,
NETWORK_CONFIG_SOURCE_DHCP6PD,
NETWORK_CONFIG_SOURCE_NDISC,
_NETWORK_CONFIG_SOURCE_MAX,
_NETWORK_CONFIG_SOURCE_INVALID = -EINVAL,
} NetworkConfigSource;
typedef enum NetworkConfigState {
NETWORK_CONFIG_STATE_PROBING = 1 << 0, /* address is probing by IPv4ACD */
NETWORK_CONFIG_STATE_REQUESTING = 1 << 1, /* request is queued */
NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no responce is received yet */
NETWORK_CONFIG_STATE_CONFIGURED = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
* Note that address may not be ready yet, so please use address_is_ready()
* to check whether the address can be usable or not. */
NETWORK_CONFIG_STATE_MARKED = 1 << 4, /* used GC'ing the old config */
NETWORK_CONFIG_STATE_REMOVING = 1 << 5, /* e.g. address_remove() is called, but no responce is received yet */
} NetworkConfigState;
CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family);
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_masquerade);
CONFIG_PARSER_PROTOTYPE(config_parse_mud_url);
const char *network_config_source_to_string(NetworkConfigSource s) _const_;
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret);
#define DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(type, name) \
static inline void name##_update_state( \
type *t, \
NetworkConfigState mask, \
NetworkConfigState value) { \
\
assert(t); \
\
t->state = (t->state & ~mask) | (value & mask); \
} \
static inline bool name##_exists(type *t) { \
assert(t); \
\
if ((t->state & (NETWORK_CONFIG_STATE_CONFIGURING | \
NETWORK_CONFIG_STATE_CONFIGURED)) == 0) \
return false; /* Not assigned yet. */ \
if (FLAGS_SET(t->state, NETWORK_CONFIG_STATE_REMOVING)) \
return false; /* Already removing. */ \
return true; \
} \
static inline void name##_enter_requesting(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_REQUESTING, \
NETWORK_CONFIG_STATE_REQUESTING); \
} \
static inline void name##_cancel_requesting(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_REQUESTING, \
0); \
} \
static inline bool name##_is_requesting(type *t) { \
return FLAGS_SET(t->state, NETWORK_CONFIG_STATE_REQUESTING); \
} \
static inline void name##_enter_configuring(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_REQUESTING | \
NETWORK_CONFIG_STATE_CONFIGURING, \
NETWORK_CONFIG_STATE_CONFIGURING); \
} \
static inline void name##_enter_configured(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_CONFIGURING | \
NETWORK_CONFIG_STATE_CONFIGURED, \
NETWORK_CONFIG_STATE_CONFIGURED); \
} \
static inline void name##_mark(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_MARKED, \
NETWORK_CONFIG_STATE_MARKED); \
} \
static inline void name##_unmark(type *t) { \
name##_update_state(t, NETWORK_CONFIG_STATE_MARKED, 0); \
} \
static inline bool name##_is_marked(type *t) { \
assert(t); \
return FLAGS_SET(t->state, NETWORK_CONFIG_STATE_MARKED); \
} \
static inline void name##_enter_removing(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_MARKED | \
NETWORK_CONFIG_STATE_REMOVING, \
NETWORK_CONFIG_STATE_REMOVING); \
} \
static inline void name##_enter_removed(type *t) { \
name##_update_state(t, \
NETWORK_CONFIG_STATE_CONFIGURED | \
NETWORK_CONFIG_STATE_REMOVING, \
0); \
}
const char *address_family_to_string(AddressFamily b) _const_;
AddressFamily address_family_from_string(const char *s) _pure_;