(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
- r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, 0, &route);
+ r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, NULL, 0, 0, 0, &route);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to add unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
strnull(buf),
table = link_get_dhcp_route_table(link);
- r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, table, &route);
+ r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, NULL, 0, 0, table, &route);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to add unreachable route for DHCPv6 delegated subnet %s/%u: %m",
strnull(buf),
assert_return(addr, -EINVAL);
r = route_add(link, AF_INET6, (union in_addr_union *) addr, 64,
- 0, 0, 0, &route);
+ NULL, 0, 0, 0, &route);
if (r < 0)
return r;
return -EINVAL;
(void) sd_radv_remove_prefix(l->radv, addr, 64);
- r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, 0, 0, 0, &route);
+ r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, NULL, 0, 0, 0, &route);
if (r < 0)
return r;
continue;
if (link_is_static_route_configured(link, route)) {
- r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
+ r = route_add(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, NULL);
if (r < 0)
return r;
} else {
continue;
}
- r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
+ r = route_add(link, family, &route_dst, prefixlen, NULL, tos, priority, table, &route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add route: %m");
return 0;
}
- (void) route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+ (void) route_get(link, family, &dst, dst_prefixlen, &gw, tos, priority, table, &route);
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
case RTM_NEWROUTE:
if (!route) {
/* A route appeared that we did not request */
- r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+ r = route_add_foreign(link, family, &dst, dst_prefixlen, &gw, tos, priority, table, &route);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
return 0;
if (r != 0)
return r;
- return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
+ r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
+ if (r != 0)
+ return r;
+
+ return memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
default:
/* treat any other address family as AF_UNSPEC */
return 0;
int family,
const union in_addr_union *dst,
unsigned char dst_prefixlen,
+ const union in_addr_union *gw,
unsigned char tos,
uint32_t priority,
uint32_t table,
.family = family,
.dst = *dst,
.dst_prefixlen = dst_prefixlen,
+ .gw = gw ? *gw : IN_ADDR_NULL,
.tos = tos,
.priority = priority,
.table = table,
int family,
const union in_addr_union *dst,
unsigned char dst_prefixlen,
+ const union in_addr_union *gw,
unsigned char tos,
uint32_t priority,
uint32_t table,
route->family = family;
route->dst = *dst;
route->dst_prefixlen = dst_prefixlen;
+ route->dst = *dst;
+ route->gw = gw ? *gw : IN_ADDR_NULL;
route->tos = tos;
route->priority = priority;
route->table = table;
int family,
const union in_addr_union *dst,
unsigned char dst_prefixlen,
+ const union in_addr_union *gw,
unsigned char tos,
uint32_t priority,
uint32_t table,
Route **ret) {
- return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
+ return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, gw, tos, priority, table, ret);
}
int route_add(Link *link,
int family,
const union in_addr_union *dst,
unsigned char dst_prefixlen,
+ const union in_addr_union *gw,
unsigned char tos,
uint32_t priority,
uint32_t table,
Route *route;
int r;
- r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
+ r = route_get(link, family, dst, dst_prefixlen, gw, tos, priority, table, &route);
if (r == -ENOENT) {
/* Route does not exist, create a new one */
- r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
+ r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, gw, tos, priority, table, &route);
if (r < 0)
return r;
} else if (r == 0) {
return 0;
}
- if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
+ if (route_get(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, NULL) <= 0 &&
set_size(link->routes) >= routes_max())
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
"Too many routes are configured, refusing: %m");
lifetime = route->lifetime;
- r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
+ r = route_add(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, &route);
if (r < 0)
return log_link_error_errno(link, r, "Could not add route: %m");
int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback);
int route_remove(Route *route, Link *link, link_netlink_message_handler_t callback);
-int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
-int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
-int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
+int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
+int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
+int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, const union in_addr_union *gw, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
void route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type);
bool route_equal(Route *r1, Route *r2);
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Address=149.10.124.58/28
+Gateway=149.10.124.60
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Address=149.10.124.58/28
+Gateway=149.10.124.59
'25-link-section-unmanaged.network',
'25-route-ipv6-src.network',
'25-route-static.network',
+ '25-gateway-static.network',
+ '25-gateway-next-static.network',
'25-sysctl-disable-ipv6.network',
'25-sysctl.network',
'configure-without-carrier.network',
print(output)
self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
+ def test_gateway_reconfigure(self):
+ copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+ print('### ip -4 route show dev dummy98 default')
+ output = check_output('ip -4 route show dev dummy98 default')
+ print(output)
+ self.assertRegex(output, 'default via 149.10.124.59 proto static')
+ self.assertNotRegex(output, '149.10.124.60')
+
+ remove_unit_from_networkd_path(['25-gateway-static.network'])
+ copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
+ restart_networkd(3)
+ self.wait_online(['dummy98:routable'])
+ print('### ip -4 route show dev dummy98 default')
+ output = check_output('ip -4 route show dev dummy98 default')
+ print(output)
+ self.assertNotRegex(output, '149.10.124.59')
+ self.assertRegex(output, 'default via 149.10.124.60 proto static')
+
def test_ip_route_ipv6_src_route(self):
# a dummy device does not make the addresses go through tentative state, so we
# reuse a bond from an earlier test, which does make the addresses go through