network: support IPv4 route with IPv6 gateway

This commit is contained in:
Yu Watanabe 2020-10-07 10:04:13 +09:00
parent 2c59a8a624
commit 6dd5398137
4 changed files with 83 additions and 29 deletions

View File

@ -312,6 +312,7 @@ static int link_set_dhcp_routes(Link *link) {
route->family = AF_INET;
route->protocol = RTPROT_DHCP;
route->gw_family = AF_INET;
assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
@ -374,6 +375,7 @@ static int link_set_dhcp_routes(Link *link) {
return log_link_error_errno(link, r, "Could not allocate route: %m");
route->family = AF_INET;
route->gw_family = AF_INET;
route->gw.in = router[0];
route->prefsrc.in = address;
route->protocol = RTPROT_DHCP;
@ -392,6 +394,7 @@ static int link_set_dhcp_routes(Link *link) {
if (rt->family != AF_INET)
continue;
rt->gw_family = AF_INET;
rt->gw.in = router[0];
r = dhcp_route_configure(rt, link);

View File

@ -513,6 +513,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->priority = link->network->dhcp6_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw_family = AF_INET6;
route->gw = gateway;
route->lifetime = time_now + lifetime * USEC_PER_SEC;
route->mtu = mtu;
@ -530,6 +531,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
continue;
route_gw->gw = gateway;
route_gw->gw_family = AF_INET6;
r = ndisc_route_configure(route_gw, link, rt);
if (r < 0)
@ -839,6 +841,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw.in6 = gateway;
route->gw_family = AF_INET6;
route->dst_prefixlen = prefixlen;
route->lifetime = time_now + lifetime * USEC_PER_SEC;

View File

@ -298,7 +298,10 @@ void route_hash_func(const Route *route, struct siphash *state) {
siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
siphash24_compress(&route->gw_family, sizeof(route->gw_family), state);
if (IN_SET(route->gw_family, AF_INET, AF_INET6))
siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->gw_family), state);
siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
@ -345,10 +348,16 @@ int route_compare_func(const Route *a, const Route *b) {
if (r != 0)
return r;
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
r = CMP(a->gw_family, b->gw_family);
if (r != 0)
return r;
if (IN_SET(a->gw_family, AF_INET, AF_INET6)) {
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
}
r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
@ -466,6 +475,7 @@ static int route_add_internal(Manager *manager, Link *link, Set **routes, Route
route->src_prefixlen = in->src_prefixlen;
route->dst = in->dst;
route->dst_prefixlen = in->dst_prefixlen;
route->gw_family = in->gw_family;
route->gw = in->gw;
route->prefsrc = in->prefsrc;
route->scope = in->scope;
@ -587,8 +597,8 @@ int route_remove(
}
if (!in_addr_is_null(route->family, &route->src))
(void) in_addr_to_string(route->family, &route->src, &src);
if (!in_addr_is_null(route->family, &route->gw))
(void) in_addr_to_string(route->family, &route->gw, &gw);
if (!in_addr_is_null(route->gw_family, &route->gw))
(void) in_addr_to_string(route->gw_family, &route->gw, &gw);
if (!in_addr_is_null(route->family, &route->prefsrc))
(void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
@ -600,10 +610,21 @@ int route_remove(
strna(route_type_to_string(route->type)));
}
if (in_addr_is_null(route->family, &route->gw) == 0) {
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
if (r < 0)
return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
if (in_addr_is_null(route->gw_family, &route->gw) == 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 log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
} 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 log_link_error_errno(link, r, "Could not append RTA_VIA attribute: %m");
}
}
if (route->dst_prefixlen) {
@ -860,8 +881,8 @@ int route_configure(
}
if (!in_addr_is_null(route->family, &route->src))
(void) in_addr_to_string(route->family, &route->src, &src);
if (!in_addr_is_null(route->family, &route->gw))
(void) in_addr_to_string(route->family, &route->gw, &gw);
if (!in_addr_is_null(route->gw_family, &route->gw))
(void) in_addr_to_string(route->gw_family, &route->gw, &gw);
if (!in_addr_is_null(route->family, &route->prefsrc))
(void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
@ -879,14 +900,21 @@ int route_configure(
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
if (in_addr_is_null(route->family, &route->gw) == 0) {
r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
if (r < 0)
return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
if (in_addr_is_null(route->gw_family, &route->gw) == 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 log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
} else {
RouteVia rtvia = {
.family = route->gw_family,
.address = route->gw,
};
r = sd_rtnl_message_route_set_family(req, route->family);
if (r < 0)
return log_link_error_errno(link, r, "Could not set route family: %m");
r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
if (r < 0)
return log_link_error_errno(link, r, "Could not append RTA_VIA attribute: %m");
}
}
if (route->dst_prefixlen > 0) {
@ -1109,7 +1137,7 @@ int link_set_routes(Link *link) {
if (rt->gateway_from_dhcp)
continue;
if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
if ((in_addr_is_null(rt->gw_family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
continue;
r = route_configure(rt, link, route_handler, NULL);
@ -1137,6 +1165,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
uint32_t ifindex;
uint16_t type;
unsigned char table;
RouteVia via;
int r;
assert(rtnl);
@ -1211,6 +1240,16 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
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 = AF_INET;
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 = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
@ -1238,7 +1277,8 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
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 = AF_INET6;
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
if (r < 0 && r != -ENODATA) {
@ -1341,8 +1381,8 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
}
if (!in_addr_is_null(tmp->family, &tmp->src))
(void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
if (!in_addr_is_null(tmp->family, &tmp->gw))
(void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
if (!in_addr_is_null(tmp->gw_family, &tmp->gw))
(void) in_addr_to_string(tmp->gw_family, &tmp->gw, &buf_gw);
if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
(void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
@ -1582,10 +1622,7 @@ int config_parse_gateway(
}
}
if (n->family == AF_UNSPEC)
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
else
r = in_addr_from_string(n->family, rvalue, &n->gw);
r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
@ -2213,6 +2250,9 @@ static int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section))
return -EINVAL;
if (route->family == AF_UNSPEC)
route->family = route->gw_family;
if (route->family == AF_UNSPEC) {
assert(route->section);
@ -2223,6 +2263,12 @@ static int route_section_verify(Route *route, Network *network) {
route->section->filename, route->section->line);
}
if (route->family == AF_INET6 && route->gw_family == AF_INET)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: IPv4 gateway is configured for IPv6 route. "
"Ignoring [Route] section from line %u.",
route->section->filename, route->section->line);
if (!route->table_set && network->vrf) {
route->table = VRF(network->vrf)->table;
route->table_set = true;
@ -2247,7 +2293,7 @@ static int route_section_verify(Route *route, Network *network) {
route->priority = IP6_RT_PRIO_USER;
if (ordered_hashmap_isempty(network->addresses_by_section) &&
in_addr_is_null(route->family, &route->gw) == 0 &&
in_addr_is_null(route->gw_family, &route->gw) == 0 &&
route->gateway_onlink < 0) {
log_warning("%s: Gateway= without static address configured. "
"Enabling GatewayOnLink= option.",

View File

@ -15,13 +15,14 @@
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct MultipathRouteVia {
/* See struct rtvia in rtnetlink.h */
typedef struct RouteVia {
uint16_t family;
union in_addr_union address;
} _packed_ MultipathRouteVia;
} _packed_ RouteVia;
typedef struct MultipathRoute {
MultipathRouteVia gateway;
RouteVia gateway;
int ifindex;
uint32_t weight;
} MultipathRoute;
@ -34,6 +35,7 @@ typedef struct Route {
Manager *manager;
int family;
int gw_family;
int quickack;
int fast_open_no_cookie;
int ttl_propagate;