mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #30932 from yuwata/network-route-split-out-more
network/route: split out more functions to networkd-route-nexthop.[ch]
This commit is contained in:
@@ -6,12 +6,352 @@
|
||||
#include "extract-word.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-nexthop.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-route-nexthop.h"
|
||||
#include "networkd-route-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int multipath_route_get_link(Manager *manager, Link *link, const MultipathRoute *m, Link **ret) {
|
||||
assert(manager);
|
||||
assert(m);
|
||||
|
||||
if (m->ifindex > 0)
|
||||
return link_get_by_index(manager, m->ifindex, ret);
|
||||
if (m->ifname)
|
||||
return link_get_by_name(manager, m->ifname, ret);
|
||||
|
||||
if (link) {
|
||||
if (ret)
|
||||
*ret = link;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static bool multipath_route_is_ready_to_configure(const MultipathRoute *m, Link *link, bool onlink) {
|
||||
union in_addr_union a = m->gateway.address;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
|
||||
if (multipath_route_get_link(link->manager, link, m, &link) < 0)
|
||||
return false;
|
||||
|
||||
if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ true))
|
||||
return false;
|
||||
|
||||
/* If the interface is not managed by us, we request that the interface has carrier.
|
||||
* That is, ConfigureWithoutCarrier=no is the default even for unamanaged interfaces. */
|
||||
if (!link->network && !link_has_carrier(link))
|
||||
return false;
|
||||
|
||||
return gateway_is_ready(link, onlink, m->gateway.family, &a);
|
||||
}
|
||||
|
||||
int route_nexthops_is_ready_to_configure(const Route *route, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(link);
|
||||
|
||||
Manager *manager = ASSERT_PTR(link->manager);
|
||||
|
||||
if (route->nexthop_id != 0) {
|
||||
struct nexthop_grp *nhg;
|
||||
NextHop *nh;
|
||||
|
||||
r = nexthop_is_ready(manager, route->nexthop_id, &nh);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(nhg, nh->group) {
|
||||
r = nexthop_is_ready(manager, nhg->id, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (route_type_is_reject(route))
|
||||
return true;
|
||||
|
||||
if (ordered_set_isempty(route->multipath_routes))
|
||||
return gateway_is_ready(link, FLAGS_SET(route->flags, RTNH_F_ONLINK), route->gw_family, &route->gw);
|
||||
|
||||
MultipathRoute *m;
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes)
|
||||
if (!multipath_route_is_ready_to_configure(m, link, FLAGS_SET(route->flags, RTNH_F_ONLINK)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int route_nexthops_to_string(const Route *route, char **ret) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(ret);
|
||||
|
||||
if (route->nexthop_id != 0) {
|
||||
if (asprintf(&buf, "nexthop: %"PRIu32, route->nexthop_id) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (route_type_is_reject(route)) {
|
||||
buf = strdup("gw: n/a");
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ordered_set_isempty(route->multipath_routes)) {
|
||||
if (in_addr_is_set(route->gw_family, &route->gw))
|
||||
buf = strjoin("gw: ", IN_ADDR_TO_STRING(route->gw_family, &route->gw));
|
||||
else if (route->gateway_from_dhcp_or_ra) {
|
||||
if (route->gw_family == AF_INET)
|
||||
buf = strdup("gw: _dhcp4");
|
||||
else if (route->gw_family == AF_INET6)
|
||||
buf = strdup("gw: _ipv6ra");
|
||||
else
|
||||
buf = strdup("gw: _dhcp");
|
||||
} else
|
||||
buf = strdup("gw: n/a");
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MultipathRoute *m;
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
||||
union in_addr_union a = m->gateway.address;
|
||||
const char *s = in_addr_is_set(m->gateway.family, &a) ? IN_ADDR_TO_STRING(m->gateway.family, &a) : NULL;
|
||||
|
||||
if (m->ifindex > 0)
|
||||
r = strextendf_with_separator(&buf, ",", "%s@%i:%"PRIu32, strempty(s), m->ifindex, m->weight + 1);
|
||||
else if (m->ifname)
|
||||
r = strextendf_with_separator(&buf, ",", "%s@%s:%"PRIu32, strempty(s), m->ifname, m->weight + 1);
|
||||
else
|
||||
r = strextendf_with_separator(&buf, ",", "%s:%"PRIu32, strempty(s), m->weight + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
char *p = strjoin("gw: ", strna(buf));
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_nexthop_one(Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
|
||||
struct rtnexthop *rtnh;
|
||||
struct rtattr *new_rta;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
||||
assert(m);
|
||||
assert(rta);
|
||||
assert(*rta);
|
||||
|
||||
if (m->ifindex <= 0) {
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
r = multipath_route_get_link(link->manager, link, m, &link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
|
||||
if (!new_rta)
|
||||
return -ENOMEM;
|
||||
*rta = new_rta;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
*rtnh = (struct rtnexthop) {
|
||||
.rtnh_len = sizeof(*rtnh),
|
||||
.rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
|
||||
.rtnh_hops = m->weight,
|
||||
};
|
||||
|
||||
(*rta)->rta_len += sizeof(struct rtnexthop);
|
||||
|
||||
if (m->gateway.family == route->family) {
|
||||
r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
|
||||
|
||||
} else if (m->gateway.family == AF_INET6) {
|
||||
assert(route->family == AF_INET);
|
||||
|
||||
r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, sizeof(RouteVia));
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
rtnh->rtnh_len += RTA_SPACE(sizeof(RouteVia));
|
||||
|
||||
} else if (m->gateway.family == AF_INET)
|
||||
assert_not_reached();
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
(*rta)->rta_len -= sizeof(struct rtnexthop);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int netlink_message_append_multipath_route(Link *link, const Route *route, sd_netlink_message *message) {
|
||||
_cleanup_free_ struct rtattr *rta = NULL;
|
||||
size_t offset;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(message);
|
||||
|
||||
if (ordered_set_isempty(route->multipath_routes))
|
||||
return 0;
|
||||
|
||||
rta = new(struct rtattr, 1);
|
||||
if (!rta)
|
||||
return -ENOMEM;
|
||||
|
||||
*rta = (struct rtattr) {
|
||||
.rta_type = RTA_MULTIPATH,
|
||||
.rta_len = RTA_LENGTH(0),
|
||||
};
|
||||
offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
|
||||
|
||||
MultipathRoute *m;
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
||||
struct rtnexthop *rtnh;
|
||||
|
||||
r = append_nexthop_one(link, route, m, &rta, offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
|
||||
offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
|
||||
}
|
||||
|
||||
return sd_netlink_message_append_data(message, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||
}
|
||||
|
||||
int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message) {
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(IN_SET(route->family, AF_INET, AF_INET6));
|
||||
assert(message);
|
||||
|
||||
if (route->nexthop_id != 0)
|
||||
return sd_netlink_message_append_u32(message, RTA_NH_ID, route->nexthop_id);
|
||||
|
||||
if (route_type_is_reject(route))
|
||||
return 0;
|
||||
|
||||
if (ordered_set_isempty(route->multipath_routes)) {
|
||||
|
||||
if (in_addr_is_set(route->gw_family, &route->gw)) {
|
||||
if (route->gw_family == route->family)
|
||||
r = netlink_message_append_in_addr_union(message, RTA_GATEWAY, route->gw_family, &route->gw);
|
||||
else {
|
||||
assert(route->family == AF_INET);
|
||||
r = sd_netlink_message_append_data(message, RTA_VIA,
|
||||
&(const RouteVia) {
|
||||
.family = route->gw_family,
|
||||
.address = route->gw,
|
||||
}, sizeof(RouteVia));
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
assert(link);
|
||||
return sd_netlink_message_append_u32(message, RTA_OIF, link->ifindex);
|
||||
}
|
||||
|
||||
return netlink_message_append_multipath_route(link, route, message);
|
||||
}
|
||||
|
||||
int route_nexthops_read_netlink_message(Route *route, sd_netlink_message *message) {
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(message);
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTA_NH_ID, &route->nexthop_id);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return log_warning_errno(r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
|
||||
|
||||
if (route->nexthop_id != 0 || route_type_is_reject(route))
|
||||
/* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
|
||||
* fib6_nh_init() in net/ipv6/route.c. However, we'd like to make it consistent with IPv4
|
||||
* routes. Hence, skip reading of RTA_OIF. */
|
||||
return 0;
|
||||
|
||||
uint32_t ifindex = 0;
|
||||
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
|
||||
|
||||
if (ifindex > 0) {
|
||||
r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, route->family, &route->gw);
|
||||
if (r >= 0) {
|
||||
route->gw_family = route->family;
|
||||
return 0;
|
||||
}
|
||||
if (r != -ENODATA)
|
||||
return log_warning_errno(r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
|
||||
if (route->family != AF_INET)
|
||||
return 0;
|
||||
|
||||
RouteVia via;
|
||||
r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
|
||||
if (r >= 0) {
|
||||
route->gw_family = via.family;
|
||||
route->gw = via.address;
|
||||
return 0;
|
||||
}
|
||||
if (r != -ENODATA)
|
||||
return log_warning_errno(r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t rta_len;
|
||||
_cleanup_free_ void *rta = NULL;
|
||||
r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
|
||||
|
||||
r = rtattr_read_nexthop(rta, rta_len, route->family, &route->multipath_routes);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_section_verify_nexthops(Route *route) {
|
||||
assert(route);
|
||||
assert(route->section);
|
||||
|
||||
@@ -3,8 +3,19 @@
|
||||
|
||||
#include "conf-parser.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct MultipathRoute MultipathRoute;
|
||||
typedef struct Route Route;
|
||||
|
||||
int multipath_route_get_link(Manager *manager, Link *link, const MultipathRoute *m, Link **ret);
|
||||
int route_nexthops_is_ready_to_configure(const Route *route, Link *link);
|
||||
|
||||
int route_nexthops_to_string(const Route *route, char **ret);
|
||||
|
||||
int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message);
|
||||
int route_nexthops_read_netlink_message(Route *route, sd_netlink_message *message);
|
||||
|
||||
int route_section_verify_nexthops(Route *route);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
|
||||
|
||||
@@ -348,26 +348,6 @@ static void route_apply_multipath_route(Route *route, const MultipathRoute *m) {
|
||||
route->gw_weight = m->weight;
|
||||
}
|
||||
|
||||
static int multipath_route_get_link(Manager *manager, const MultipathRoute *m, Link **ret) {
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(m);
|
||||
|
||||
if (m->ifname) {
|
||||
r = link_get_by_name(manager, m->ifname, ret);
|
||||
return r < 0 ? r : 1;
|
||||
|
||||
} else if (m->ifindex > 0) { /* Always ignore ifindex if ifname is set. */
|
||||
r = link_get_by_index(manager, m->ifindex, ret);
|
||||
return r < 0 ? r : 1;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct ConvertedRoutes {
|
||||
size_t n;
|
||||
Route **routes;
|
||||
@@ -425,7 +405,7 @@ static bool route_needs_convert(const Route *route) {
|
||||
return route->nexthop_id > 0 || !ordered_set_isempty(route->multipath_routes);
|
||||
}
|
||||
|
||||
static int route_convert(Manager *manager, const Route *route, ConvertedRoutes **ret) {
|
||||
static int route_convert(Manager *manager, Link *link, const Route *route, ConvertedRoutes **ret) {
|
||||
_cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
|
||||
int r;
|
||||
|
||||
@@ -433,6 +413,8 @@ static int route_convert(Manager *manager, const Route *route, ConvertedRoutes *
|
||||
assert(route);
|
||||
assert(ret);
|
||||
|
||||
/* link may be NULL */
|
||||
|
||||
if (!route_needs_convert(route)) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
@@ -504,7 +486,7 @@ static int route_convert(Manager *manager, const Route *route, ConvertedRoutes *
|
||||
|
||||
route_apply_multipath_route(c->routes[i], m);
|
||||
|
||||
r = multipath_route_get_link(manager, m, &c->links[i]);
|
||||
r = multipath_route_get_link(manager, link, m, &c->links[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -529,9 +511,9 @@ void link_mark_routes(Link *link, NetworkConfigSource source) {
|
||||
}
|
||||
|
||||
static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
|
||||
_cleanup_free_ char *state = NULL, *gw_alloc = NULL, *prefsrc = NULL,
|
||||
_cleanup_free_ char *state = NULL, *nexthop = NULL, *prefsrc = NULL,
|
||||
*table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
|
||||
const char *gw = NULL, *dst, *src;
|
||||
const char *dst, *src;
|
||||
|
||||
assert(route);
|
||||
assert(str);
|
||||
@@ -549,32 +531,8 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
|
||||
src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
|
||||
IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
|
||||
|
||||
if (in_addr_is_set(route->gw_family, &route->gw)) {
|
||||
(void) in_addr_to_string(route->gw_family, &route->gw, &gw_alloc);
|
||||
gw = gw_alloc;
|
||||
} else if (route->gateway_from_dhcp_or_ra) {
|
||||
if (route->gw_family == AF_INET)
|
||||
gw = "_dhcp4";
|
||||
else if (route->gw_family == AF_INET6)
|
||||
gw = "_ipv6ra";
|
||||
} else {
|
||||
MultipathRoute *m;
|
||||
(void) route_nexthops_to_string(route, &nexthop);
|
||||
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
union in_addr_union a = m->gateway.address;
|
||||
|
||||
(void) in_addr_to_string(m->gateway.family, &a, &buf);
|
||||
(void) strextend_with_separator(&gw_alloc, ",", strna(buf));
|
||||
if (m->ifname)
|
||||
(void) strextend(&gw_alloc, "@", m->ifname);
|
||||
else if (m->ifindex > 0)
|
||||
(void) strextendf(&gw_alloc, "@%i", m->ifindex);
|
||||
/* See comments in config_parse_multipath_route(). */
|
||||
(void) strextendf(&gw_alloc, ":%"PRIu32, m->weight + 1);
|
||||
}
|
||||
gw = gw_alloc;
|
||||
}
|
||||
if (in_addr_is_set(route->family, &route->prefsrc))
|
||||
(void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
|
||||
(void) route_scope_to_string_alloc(route->scope, &scope);
|
||||
@@ -583,13 +541,13 @@ static void log_route_debug(const Route *route, const char *str, const Link *lin
|
||||
(void) route_flags_to_string_alloc(route->flags, &flags);
|
||||
|
||||
log_link_debug(link,
|
||||
"%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
|
||||
"proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32", flags: %s",
|
||||
"%s %s route (%s): dst: %s, src: %s, %s, prefsrc: %s, "
|
||||
"table: %s, priority: %"PRIu32", "
|
||||
"proto: %s, scope: %s, type: %s, flags: %s",
|
||||
str, strna(network_config_source_to_string(route->source)), strna(state),
|
||||
strna(dst), strna(src), strna(gw), strna(prefsrc),
|
||||
strna(scope), strna(table), strna(proto),
|
||||
strna(route_type_to_string(route->type)),
|
||||
route->nexthop_id, route->priority, strna(flags));
|
||||
strna(dst), strna(src), strna(nexthop), strna(prefsrc),
|
||||
strna(table), route->priority,
|
||||
strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags));
|
||||
}
|
||||
|
||||
static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) {
|
||||
@@ -600,23 +558,6 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
|
||||
|
||||
/* link may be NULL */
|
||||
|
||||
if (in_addr_is_set(route->gw_family, &route->gw) && route->nexthop_id == 0) {
|
||||
if (route->gw_family == route->family) {
|
||||
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
RouteVia rtvia = {
|
||||
.family = route->gw_family,
|
||||
.address = route->gw,
|
||||
};
|
||||
|
||||
r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (route->dst_prefixlen > 0) {
|
||||
r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
|
||||
if (r < 0)
|
||||
@@ -666,22 +607,6 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!route_type_is_reject(route) &&
|
||||
route->nexthop_id == 0 &&
|
||||
ordered_set_isempty(route->multipath_routes)) {
|
||||
assert(link); /* Those routes must be attached to a specific link */
|
||||
|
||||
r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (route->nexthop_id > 0) {
|
||||
r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -690,6 +615,11 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* nexthops */
|
||||
r = route_nexthops_set_netlink_message(link, route, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -820,7 +750,7 @@ static void manager_mark_routes(Manager *manager, bool foreign, const Link *exce
|
||||
_cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
|
||||
Route *existing;
|
||||
|
||||
r = route_convert(manager, route, &converted);
|
||||
r = route_convert(manager, link, route, &converted);
|
||||
if (r < 0)
|
||||
continue;
|
||||
if (r == 0) {
|
||||
@@ -919,7 +849,7 @@ int link_drop_foreign_routes(Link *link) {
|
||||
_cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
|
||||
Route *existing;
|
||||
|
||||
r = route_convert(link->manager, route, &converted);
|
||||
r = route_convert(link->manager, link, route, &converted);
|
||||
if (r < 0)
|
||||
continue;
|
||||
if (r == 0) {
|
||||
@@ -1035,91 +965,6 @@ static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int append_nexthop_one(const Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
|
||||
struct rtnexthop *rtnh;
|
||||
struct rtattr *new_rta;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(m);
|
||||
assert(rta);
|
||||
assert(*rta);
|
||||
|
||||
new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
|
||||
if (!new_rta)
|
||||
return -ENOMEM;
|
||||
*rta = new_rta;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
*rtnh = (struct rtnexthop) {
|
||||
.rtnh_len = sizeof(*rtnh),
|
||||
.rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
|
||||
.rtnh_hops = m->weight,
|
||||
};
|
||||
|
||||
(*rta)->rta_len += sizeof(struct rtnexthop);
|
||||
|
||||
if (route->family == m->gateway.family) {
|
||||
r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
|
||||
} else {
|
||||
r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
|
||||
rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
(*rta)->rta_len -= sizeof(struct rtnexthop);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int append_nexthops(const Link *link, const Route *route, sd_netlink_message *req) {
|
||||
_cleanup_free_ struct rtattr *rta = NULL;
|
||||
struct rtnexthop *rtnh;
|
||||
MultipathRoute *m;
|
||||
size_t offset;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(route);
|
||||
assert(req);
|
||||
|
||||
if (ordered_set_isempty(route->multipath_routes))
|
||||
return 0;
|
||||
|
||||
rta = new(struct rtattr, 1);
|
||||
if (!rta)
|
||||
return -ENOMEM;
|
||||
|
||||
*rta = (struct rtattr) {
|
||||
.rta_type = RTA_MULTIPATH,
|
||||
.rta_len = RTA_LENGTH(0),
|
||||
};
|
||||
offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
|
||||
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
||||
r = append_nexthop_one(link, route, m, &rta, offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
|
||||
offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, Route *route, const char *error_msg) {
|
||||
int r;
|
||||
|
||||
@@ -1186,15 +1031,6 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!ordered_set_isempty(route->multipath_routes)) {
|
||||
assert(route->nexthop_id == 0);
|
||||
assert(!in_addr_is_set(route->gw_family, &route->gw));
|
||||
|
||||
r = append_nexthops(link, route, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return request_call_netlink_async(link->manager->rtnl, m, req);
|
||||
}
|
||||
|
||||
@@ -1210,51 +1046,13 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
|
||||
if (set_size(link->routes) >= routes_max())
|
||||
return false;
|
||||
|
||||
if (route->nexthop_id > 0) {
|
||||
struct nexthop_grp *nhg;
|
||||
NextHop *nh;
|
||||
|
||||
r = nexthop_is_ready(link->manager, route->nexthop_id, &nh);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(nhg, nh->group) {
|
||||
r = nexthop_is_ready(link->manager, nhg->id, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
|
||||
r = manager_has_address(link->manager, route->family, &route->prefsrc);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!gateway_is_ready(link, FLAGS_SET(route->flags, RTNH_F_ONLINK), route->gw_family, &route->gw))
|
||||
return false;
|
||||
|
||||
MultipathRoute *m;
|
||||
ORDERED_SET_FOREACH(m, route->multipath_routes) {
|
||||
union in_addr_union a = m->gateway.address;
|
||||
Link *l = NULL;
|
||||
|
||||
r = multipath_route_get_link(link->manager, m, &l);
|
||||
if (r < 0)
|
||||
return false;
|
||||
if (r > 0) {
|
||||
if (!link_is_ready_to_configure(l, /* allow_unmanaged = */ true) ||
|
||||
!link_has_carrier(l))
|
||||
return false;
|
||||
|
||||
m->ifindex = l->ifindex;
|
||||
}
|
||||
|
||||
if (!gateway_is_ready(l ?: link, FLAGS_SET(route->flags, RTNH_F_ONLINK), m->gateway.family, &a))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return route_nexthops_is_ready_to_configure(route, link);
|
||||
}
|
||||
|
||||
static int route_process_request(Request *req, Link *link, Route *route) {
|
||||
@@ -1273,7 +1071,7 @@ static int route_process_request(Request *req, Link *link, Route *route) {
|
||||
return 0;
|
||||
|
||||
if (route_needs_convert(route)) {
|
||||
r = route_convert(link->manager, route, &converted);
|
||||
r = route_convert(link->manager, link, route, &converted);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to convert route: %m");
|
||||
|
||||
@@ -1610,13 +1408,11 @@ static int process_route_one(
|
||||
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
_cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
|
||||
_cleanup_(route_freep) Route *tmp = NULL;
|
||||
_cleanup_free_ void *rta_multipath = NULL;
|
||||
struct rta_cacheinfo cacheinfo;
|
||||
bool has_cacheinfo;
|
||||
Link *link = NULL;
|
||||
uint32_t ifindex;
|
||||
uint16_t type;
|
||||
size_t rta_len;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
@@ -1691,25 +1487,6 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0)
|
||||
tmp->gw_family = tmp->family;
|
||||
else if (tmp->family == AF_INET) {
|
||||
RouteVia via;
|
||||
|
||||
r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0) {
|
||||
tmp->gw_family = via.family;
|
||||
tmp->gw = via.address;
|
||||
}
|
||||
}
|
||||
|
||||
r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
|
||||
@@ -1771,28 +1548,14 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
|
||||
/* nexthops */
|
||||
if (route_nexthops_read_netlink_message(tmp, message) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* metrics */
|
||||
if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
|
||||
return 0;
|
||||
|
||||
r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0) {
|
||||
r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &tmp->multipath_routes);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
|
||||
@@ -1809,7 +1572,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
if (!route_needs_convert(tmp))
|
||||
return process_route_one(m, link, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
|
||||
|
||||
r = route_convert(m, tmp, &converted);
|
||||
r = route_convert(m, link, tmp, &converted);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: failed to convert received route, ignoring: %m");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user