all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not be configured directly. The user could only set ipv4.gateway, ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence the setting of the default-route (respectively for IPv6). That is a problematic limitation. For one, whether a route has prefix length zero or non-zero does not make a fundamental difference. Also, it makes it impossible to configure all the routing attributes that one can configure otherwise for static routes. For example, the default-route could not be configured as "onlink", could not have a special MTU, nor could it be placed in a dedicated routing table. Fix that by lifting the restriction. Note that "ipv4.never-default" does not apply to /0 manual routes. Likewise, the previous manners of configuring default-routes ("ipv4.gateway") don't conflict with manual default-routes. Server-side this all the pieces are already in place to accept a default-route as static routes. This was done by earlier commits like5c299454b4
('core: rework tracking of gateway/default-route in ip-config'). A long time ago, NMIPRoute would assert that the prefix length is positive. That was relaxed by commita2e93f2de4
('libnm: allow zero prefix length for NMIPRoute'), already before 1.0.0. Using libnm from before 1.0.0 would result in assertion failures. Note that the default-route-metric-penalty based on connectivity checking applies to all /0 routes, even these static routes. Be they added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes". I wonder whether doing that unconditionally is desirable, and maybe there should be a way to opt-out/opt-in for the entire profile or even per-routes. https://bugzilla.redhat.com/show_bug.cgi?id=1714438
This commit is contained in:
@@ -367,7 +367,7 @@ _parse_ip_route (int family,
|
||||
}
|
||||
prefix = MAX_PREFIX;
|
||||
if (plen) {
|
||||
if ((prefix = _nm_utils_ascii_str_to_int64 (plen, 10, 1, MAX_PREFIX, -1)) == -1) {
|
||||
if ((prefix = _nm_utils_ascii_str_to_int64 (plen, 10, 0, MAX_PREFIX, -1)) == -1) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("invalid prefix '%s'; <1-%d> allowed"),
|
||||
plen, MAX_PREFIX);
|
||||
|
@@ -248,15 +248,16 @@ static gpointer
|
||||
build_route (KeyfileReaderInfo *info,
|
||||
const char *property_name,
|
||||
int family,
|
||||
const char *dest_str, guint32 plen,
|
||||
const char *gateway_str, const char *metric_str)
|
||||
const char *dest_str,
|
||||
guint32 plen,
|
||||
const char *gateway_str,
|
||||
const char *metric_str)
|
||||
{
|
||||
NMIPRoute *route;
|
||||
guint32 u32;
|
||||
gint64 metric = -1;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_val_if_fail (plen, NULL);
|
||||
g_return_val_if_fail (dest_str, NULL);
|
||||
|
||||
/* Next hop */
|
||||
@@ -294,7 +295,10 @@ build_route (KeyfileReaderInfo *info,
|
||||
metric = u32;
|
||||
}
|
||||
|
||||
route = nm_ip_route_new (family, dest_str, plen, gateway_str,
|
||||
route = nm_ip_route_new (family,
|
||||
dest_str,
|
||||
plen,
|
||||
gateway_str,
|
||||
metric,
|
||||
&error);
|
||||
if (!route) {
|
||||
@@ -517,8 +521,7 @@ read_one_ip_address_or_route (KeyfileReaderInfo *info,
|
||||
|
||||
/* parse plen, fallback to defaults */
|
||||
if (plen_str) {
|
||||
if ( !get_one_int (info, property_name, plen_str, ipv6 ? 128 : 32, &plen)
|
||||
|| (route && plen == 0)) {
|
||||
if (!get_one_int (info, property_name, plen_str, ipv6 ? 128 : 32, &plen)) {
|
||||
plen = DEFAULT_PREFIX (route, ipv6);
|
||||
if ( info->error
|
||||
|| !handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
@@ -536,12 +539,19 @@ read_one_ip_address_or_route (KeyfileReaderInfo *info,
|
||||
|
||||
/* build the appropriate data structure for NetworkManager settings */
|
||||
if (route) {
|
||||
result = build_route (info, property_name,
|
||||
result = build_route (info,
|
||||
property_name,
|
||||
ipv6 ? AF_INET6 : AF_INET,
|
||||
address_str, plen, gateway_str, metric_str);
|
||||
address_str,
|
||||
plen,
|
||||
gateway_str,
|
||||
metric_str);
|
||||
} else {
|
||||
result = build_address (info, ipv6 ? AF_INET6 : AF_INET,
|
||||
address_str, plen, property_name);
|
||||
result = build_address (info,
|
||||
ipv6 ? AF_INET6 : AF_INET,
|
||||
address_str,
|
||||
plen,
|
||||
property_name);
|
||||
if (!result)
|
||||
return NULL;
|
||||
if (gateway_str)
|
||||
|
@@ -1335,7 +1335,7 @@ nm_ip_route_attribute_validate (const char *name,
|
||||
if (str) {
|
||||
addr = nm_strndup_a (200, addr, str - addr, &addr_free);
|
||||
str++;
|
||||
if (_nm_utils_ascii_str_to_int64 (str, 10, 1, family == AF_INET ? 32 : 128, -1) < 0) {
|
||||
if (_nm_utils_ascii_str_to_int64 (str, 10, 0, family == AF_INET ? 32 : 128, -1) < 0) {
|
||||
g_set_error (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_FAILED,
|
||||
@@ -5005,15 +5005,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES);
|
||||
return FALSE;
|
||||
}
|
||||
if (nm_ip_route_get_prefix (route) == 0) {
|
||||
g_set_error (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("%d. route cannot be a default route"),
|
||||
(int) (i + 1));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->routing_rules) {
|
||||
|
@@ -991,8 +991,6 @@ nm_ip4_config_merge_setting (NMIP4Config *self,
|
||||
|
||||
route.plen = nm_ip_route_get_prefix (s_route);
|
||||
nm_assert (route.plen <= 32);
|
||||
if (route.plen == 0)
|
||||
continue;
|
||||
|
||||
nm_ip_route_get_next_hop_binary (s_route, &route.gateway);
|
||||
if (nm_ip_route_get_metric (s_route) == -1)
|
||||
|
@@ -672,8 +672,6 @@ nm_ip6_config_merge_setting (NMIP6Config *self,
|
||||
|
||||
route.plen = nm_ip_route_get_prefix (s_route);
|
||||
nm_assert (route.plen <= 128);
|
||||
if (route.plen == 0)
|
||||
continue;
|
||||
|
||||
nm_ip_route_get_next_hop_binary (s_route, &route.gateway);
|
||||
if (nm_ip_route_get_metric (s_route) == -1)
|
||||
|
@@ -1116,15 +1116,6 @@ next:
|
||||
? info_to->v.addr.plen
|
||||
: (addr_family == AF_INET ? 32 : 128);
|
||||
|
||||
if ( ( (addr_family == AF_INET && !info_to->v.addr.addr.addr4)
|
||||
|| (addr_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&info_to->v.addr.addr.addr6)))
|
||||
&& prefix == 0) {
|
||||
/* we ignore default routes by returning -ERANGE. */
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Ignore manual default route");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
route = nm_ip_route_new_binary (addr_family,
|
||||
&info_to->v.addr.addr,
|
||||
prefix,
|
||||
@@ -1244,7 +1235,7 @@ read_one_ip4_route (shvarFile *ifcfg,
|
||||
return FALSE;
|
||||
if (has_key) {
|
||||
prefix = nm_utils_ip4_netmask_to_prefix (netmask);
|
||||
if (prefix == 0 || netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) {
|
||||
if (netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) {
|
||||
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf));
|
||||
return FALSE;
|
||||
|
@@ -1520,10 +1520,8 @@ test_read_wired_ipv6_manual (void)
|
||||
NMIPAddress *ip6_addr;
|
||||
NMIPRoute *ip6_route;
|
||||
|
||||
NMTST_EXPECT_NM_WARN ("*ignoring manual default route*");
|
||||
connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wired-ipv6-manual",
|
||||
NULL, TYPE_ETHERNET, &unmanaged);
|
||||
g_test_assert_expected_messages ();
|
||||
g_assert (!unmanaged);
|
||||
|
||||
/* ===== CONNECTION SETTING ===== */
|
||||
@@ -1581,7 +1579,7 @@ test_read_wired_ipv6_manual (void)
|
||||
g_assert_cmpint (nm_ip_address_get_prefix (ip6_addr), ==, 96);
|
||||
|
||||
/* Routes */
|
||||
g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 3);
|
||||
g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 4);
|
||||
/* Route #1 */
|
||||
ip6_route = nm_setting_ip_config_get_route (s_ip6, 0);
|
||||
g_assert (ip6_route);
|
||||
@@ -1592,12 +1590,19 @@ test_read_wired_ipv6_manual (void)
|
||||
/* Route #2 */
|
||||
ip6_route = nm_setting_ip_config_get_route (s_ip6, 1);
|
||||
g_assert (ip6_route);
|
||||
g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "::");
|
||||
g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 0);
|
||||
g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, "dead::beaf");
|
||||
g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, -1);
|
||||
/* Route #3 */
|
||||
ip6_route = nm_setting_ip_config_get_route (s_ip6, 2);
|
||||
g_assert (ip6_route);
|
||||
g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "abbe::cafe");
|
||||
g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
|
||||
g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, NULL);
|
||||
g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, 777);
|
||||
/* Route #3 */
|
||||
ip6_route = nm_setting_ip_config_get_route (s_ip6, 2);
|
||||
/* Route #4 */
|
||||
ip6_route = nm_setting_ip_config_get_route (s_ip6, 3);
|
||||
g_assert (ip6_route);
|
||||
g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "aaaa::cccc");
|
||||
g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
|
||||
|
Reference in New Issue
Block a user