diff --git a/NEWS b/NEWS index b33d76d8be..daead33e0b 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! type instances would have been created by NMClient for a while now. * DHCP: switch "internal" DHCPv4 plugin from code based on systemd to use nettools' n-dhcp4 library. +* Add support for "scope" attribute for IPv4 routes. * libnm: heavily internal rework NMClient. This slims down libnm and makes the implementation more efficient. NMClient should work now well with a separate GMainContext. diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index bc0bf39426..06456e6577 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -874,4 +874,13 @@ const char *nm_utils_wifi_freq_to_band (guint32 freq); gboolean _nm_utils_iaid_verify (const char *str, gint64 *out_value); +/*****************************************************************************/ + +gboolean _nmtst_variant_attribute_spec_assert_sorted (const NMVariantAttributeSpec *const*array, + gsize len); + +const NMVariantAttributeSpec *_nm_variant_attribute_spec_find_binary_search (const NMVariantAttributeSpec *const*array, + gsize len, + const char *name); + #endif diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index f966a53743..cd833e09fc 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1197,21 +1197,22 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value) } static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = { - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, .v4 = TRUE, .v6 = TRUE, .str_type = 'a', ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, .v6 = TRUE, .str_type = 'p', ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_ONLINK, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, .v6 = TRUE, .str_type = 'p', ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), - NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_ONLINK, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SCOPE, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, .v4 = TRUE, .v6 = TRUE, .str_type = 'a', ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), NULL, }; @@ -1250,21 +1251,16 @@ nm_ip_route_attribute_validate (const char *name, gboolean *known, GError **error) { - const NMVariantAttributeSpec *const *iter; - const NMVariantAttributeSpec *spec = NULL; + const NMVariantAttributeSpec *spec; g_return_val_if_fail (name, FALSE); g_return_val_if_fail (value, FALSE); g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - for (iter = ip_route_attribute_spec; *iter; iter++) { - if (nm_streq (name, (*iter)->name)) { - spec = *iter; - break; - } - } - + spec = _nm_variant_attribute_spec_find_binary_search (ip_route_attribute_spec, + G_N_ELEMENTS (ip_route_attribute_spec) - 1, + name); if (!spec) { NM_SET_OUT (known, FALSE); g_set_error_literal (error, diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index 440ebe5a6c..07581976db 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -127,21 +127,22 @@ gboolean nm_ip_route_attribute_validate (const char *name, gboolean *known, GError **error); -#define NM_IP_ROUTE_ATTRIBUTE_TABLE "table" -#define NM_IP_ROUTE_ATTRIBUTE_SRC "src" -#define NM_IP_ROUTE_ATTRIBUTE_FROM "from" -#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" -#define NM_IP_ROUTE_ATTRIBUTE_ONLINK "onlink" -#define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" #define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd" +#define NM_IP_ROUTE_ATTRIBUTE_FROM "from" #define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd" #define NM_IP_ROUTE_ATTRIBUTE_INITRWND "initrwnd" -#define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu" -#define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND "lock-cwnd" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND "lock-initcwnd" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND "lock-initrwnd" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU "lock-mtu" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window" +#define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu" +#define NM_IP_ROUTE_ATTRIBUTE_ONLINK "onlink" +#define NM_IP_ROUTE_ATTRIBUTE_SCOPE "scope" +#define NM_IP_ROUTE_ATTRIBUTE_SRC "src" +#define NM_IP_ROUTE_ATTRIBUTE_TABLE "table" +#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" +#define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" /*****************************************************************************/ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index c825bb12ba..347ef84093 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -5555,6 +5555,48 @@ attribute_unescape (const char *start, const char *end) return ret; } +gboolean +_nmtst_variant_attribute_spec_assert_sorted (const NMVariantAttributeSpec *const*array, + gsize len) +{ + gsize i; + + g_assert (array); + g_assert (len > 0); + g_assert_cmpint(len, ==, NM_PTRARRAY_LEN (array)); + + for (i = 0; i < len; i++) { + nm_assert (array[i]->name); + nm_assert (array[i]->name[0]); + if (i > 0) + nm_assert (strcmp (array[i - 1]->name, array[i]->name) < 0); + } + nm_assert (!array[i]); + + return TRUE; +} + +const NMVariantAttributeSpec * +_nm_variant_attribute_spec_find_binary_search (const NMVariantAttributeSpec *const*array, + gsize len, + const char *name) +{ + gssize idx; + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMVariantAttributeSpec, name) == 0); + + idx = nm_utils_ptrarray_find_binary_search ((gconstpointer *) array, + len, + &name, + nm_strcmp_p_with_data, + NULL, + NULL, + NULL); + if (idx < 0) + return NULL; + return array[idx]; +} + /** * nm_utils_parse_variant_attributes: * @string: the input string diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 40eabc1208..cbc1a2f2ff 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -7986,6 +7986,33 @@ test_route_attributes_format (void) /*****************************************************************************/ +static void +test_variant_attribute_spec (void) +{ + const NMVariantAttributeSpec *const *const specs_list[] = { + nm_ip_route_get_variant_attribute_spec (), + }; + int i_specs; + + for (i_specs = 0; i_specs < G_N_ELEMENTS (specs_list); i_specs++) { + const NMVariantAttributeSpec *const *const specs = specs_list[i_specs]; + gsize len; + gsize i; + + g_assert (specs); + + len = NM_PTRARRAY_LEN (specs); + g_assert_cmpint (len, >, 0u); + + _nmtst_variant_attribute_spec_assert_sorted (specs, len); + for (i = 0; i < len; i++) + g_assert (specs[i] == _nm_variant_attribute_spec_find_binary_search (specs, len, specs[i]->name)); + g_assert (!_nm_variant_attribute_spec_find_binary_search (specs, len, "bogus")); + } +} + +/*****************************************************************************/ + static gboolean do_test_nm_set_out_called (int *call_count) { @@ -8448,6 +8475,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/nm-set-out", test_nm_set_out); g_test_add_func ("/core/general/route_attributes/parse", test_route_attributes_parse); g_test_add_func ("/core/general/route_attributes/format", test_route_attributes_format); + g_test_add_func ("/core/general/test_variant_attribute_spec", test_variant_attribute_spec); g_test_add_func ("/core/general/get_start_time_for_pid", test_get_start_time_for_pid); g_test_add_func ("/core/general/test_nm_va_args_macros", test_nm_va_args_macros); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 30bd5c6790..cd14fb8f94 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -862,8 +862,13 @@ _nm_ip_config_merge_route_attributes (int addr_family, GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); - if (addr_family == AF_INET) + if (addr_family == AF_INET) { + guint8 scope; + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_SCOPE, scope, BYTE, byte, RT_SCOPE_NOWHERE); + r4->scope_inv = nm_platform_route_scope_inv (scope); + } GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 0340136c86..4bd8e34d1e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -496,7 +496,7 @@ struct _NMPlatformIP4Route { /* The bitwise inverse of the route scope rtm_scope. It is inverted so that the * default value (RT_SCOPE_NOWHERE) is zero. Use nm_platform_route_scope_inv() - * to convert back and forth between the inverese representation and the + * to convert back and forth between the inverse representation and the * real value. * * rtm_scope is part of the primary key for IPv4 routes. When deleting a route, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index c4c4b344d0..5f61d4fb0f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "nm-glib-aux/nm-secret-utils.h" #include "nm-connection.h" @@ -739,25 +740,36 @@ parse_route_line_is_comment (const char *line) /*****************************************************************************/ +typedef enum { + PARSE_LINE_AF_FLAG_FOR_IPV4 = 0x01, + PARSE_LINE_AF_FLAG_FOR_IPV6 = 0x02, +} ParseLineAFFlag; + typedef struct { const char *key; /* the element is not available in this case. */ - bool disabled:1; + ParseLineAFFlag disabled:3; + + bool disabled_with_options_route:1; /* whether the element is to be ignored. Ignord is different from * "disabled", because we still parse the option, but don't use it. */ - bool ignore:1; + ParseLineAFFlag ignore:3; bool int_base_16:1; + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + +} ParseLineInfo; + +typedef struct { + /* whether the command line option was found, and @v is * initialized. */ bool has:1; - /* the type, one of PARSE_LINE_TYPE_* */ - char type; - union { guint8 uint8; guint32 uint32; @@ -772,7 +784,7 @@ typedef struct { } addr; } v; -} ParseLineInfo; +} ParseLineData; enum { /* route attributes */ @@ -780,6 +792,7 @@ enum { PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_SCOPE, PARSE_LINE_ATTR_ROUTE_ONLINK, PARSE_LINE_ATTR_ROUTE_WINDOW, PARSE_LINE_ATTR_ROUTE_CWND, @@ -803,6 +816,7 @@ enum { #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' #define PARSE_LINE_TYPE_FLAG 'f' +#define PARSE_LINE_TYPE_ROUTE_SCOPE 'S' /** * parse_route_line: @@ -833,29 +847,23 @@ parse_route_line (const char *line, NMIPRoute **out_route, GError **error) { - nm_auto_unref_ip_route NMIPRoute *route = NULL; - gs_free const char **words_free = NULL; - const char *const*words; - const char *s; - gsize i_words; - guint i; - char buf1[256]; - char buf2[256]; - ParseLineInfo infos[] = { + static const ParseLineInfo parse_infos[] = { [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, .type = PARSE_LINE_TYPE_UINT32, }, [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, .type = PARSE_LINE_TYPE_ADDR, }, [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (addr_family != AF_INET6), }, + .disabled = PARSE_LINE_AF_FLAG_FOR_IPV4, }, [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, .type = PARSE_LINE_TYPE_UINT8, .int_base_16 = TRUE, - .ignore = (addr_family != AF_INET), }, + .ignore = PARSE_LINE_AF_FLAG_FOR_IPV6, }, + [PARSE_LINE_ATTR_ROUTE_SCOPE] = { .key = NM_IP_ROUTE_ATTRIBUTE_SCOPE, + .type = PARSE_LINE_TYPE_ROUTE_SCOPE, + .ignore = PARSE_LINE_AF_FLAG_FOR_IPV6, }, [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, - .type = PARSE_LINE_TYPE_FLAG, - .ignore = (addr_family != AF_INET), }, + .type = PARSE_LINE_TYPE_FLAG, }, [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, @@ -869,19 +877,31 @@ parse_route_line (const char *line, [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (options_route != NULL), }, + .disabled_with_options_route = TRUE, }, [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", .type = PARSE_LINE_TYPE_ADDR, - .disabled = (options_route != NULL), }, + .disabled_with_options_route = TRUE, }, [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", .type = PARSE_LINE_TYPE_UINT32, - .disabled = (options_route != NULL), }, + .disabled_with_options_route = TRUE, }, [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", .type = PARSE_LINE_TYPE_IFNAME, - .ignore = TRUE, - .disabled = (options_route != NULL), }, + .ignore = PARSE_LINE_AF_FLAG_FOR_IPV4 | PARSE_LINE_AF_FLAG_FOR_IPV6, + .disabled_with_options_route = TRUE, }, }; + nm_auto_unref_ip_route NMIPRoute *route = NULL; + gs_free const char **words_free = NULL; + const char *const*words; + const char *s; + gsize i_words; + guint i; + char buf1[256]; + char buf2[256]; + ParseLineData parse_datas[G_N_ELEMENTS (parse_infos)] = { }; + const ParseLineAFFlag af_flag = (addr_family == AF_INET) + ? PARSE_LINE_AF_FLAG_FOR_IPV4 + : PARSE_LINE_AF_FLAG_FOR_IPV6; nm_assert (line); nm_assert_addr_family (addr_family); @@ -909,19 +929,22 @@ parse_route_line (const char *line, for (i_words = 0; words[i_words]; ) { const gsize i_words0 = i_words; const char *const w = words[i_words0]; - ParseLineInfo *info; + const ParseLineInfo *p_info; + ParseLineData *p_data; gboolean unqualified_addr = FALSE; - for (i = 0; i < G_N_ELEMENTS (infos); i++) { - info = &infos[i]; + for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) { + p_info = &parse_infos[i]; + p_data = &parse_datas[i]; - if (info->disabled) + if ( (p_info->disabled & af_flag) + || (p_info->disabled_with_options_route && options_route)) continue; - if (!nm_streq (w, info->key)) + if (!nm_streq (w, p_info->key)) continue; - if (info->has) { + if (p_data->has) { /* iproute2 for most arguments allows specifying them multiple times. * Let's not do that. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -929,8 +952,8 @@ parse_route_line (const char *line, return -EINVAL; } - info->has = TRUE; - switch (info->type) { + p_data->has = TRUE; + switch (p_info->type) { case PARSE_LINE_TYPE_UINT8: i_words++; goto parse_line_type_uint8; @@ -952,16 +975,22 @@ parse_route_line (const char *line, case PARSE_LINE_TYPE_FLAG: i_words++; goto next; + case PARSE_LINE_TYPE_ROUTE_SCOPE: + i_words++; + goto parse_line_type_route_scope; default: nm_assert_not_reached (); } } /* "to" is also accepted unqualified... (once) */ - info = &infos[PARSE_LINE_ATTR_ROUTE_TO]; - if (!info->has && !info->disabled) { + p_info = &parse_infos[PARSE_LINE_ATTR_ROUTE_TO]; + p_data = &parse_datas[PARSE_LINE_ATTR_ROUTE_TO]; + if ( !p_data->has + && !(p_info->disabled & af_flag) + && !(p_info->disabled_with_options_route && options_route)) { unqualified_addr = TRUE; - info->has = TRUE; + p_data->has = TRUE; goto parse_line_type_addr; } @@ -969,15 +998,44 @@ parse_route_line (const char *line, "Unrecognized argument (\"to\" is duplicate or \"%s\" is garbage)", w); return -EINVAL; +parse_line_type_route_scope: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + if (nm_streq (s, "global")) + p_data->v.uint8 = RT_SCOPE_UNIVERSE; + else if (nm_streq (s, "nowhere")) + p_data->v.uint8 = RT_SCOPE_NOWHERE; + else if (nm_streq (s, "host")) + p_data->v.uint8 = RT_SCOPE_HOST; + else if (nm_streq (s, "link")) + p_data->v.uint8 = RT_SCOPE_LINK; + else if (nm_streq (s, "site")) + p_data->v.uint8 = RT_SCOPE_SITE; + else { + p_data->v.uint8 = _nm_utils_ascii_str_to_int64 (s, + 0, + 0, + G_MAXUINT8, + 0);; + if (errno) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not a valid number", w); + return -EINVAL; + } + } + i_words++; + goto next; + parse_line_type_uint8: s = words[i_words]; if (!s) goto err_word_missing_argument; - info->v.uint8 = _nm_utils_ascii_str_to_int64 (s, - info->int_base_16 ? 16 : 10, - 0, - G_MAXUINT8, - 0);; + p_data->v.uint8 = _nm_utils_ascii_str_to_int64 (s, + p_info->int_base_16 ? 16 : 10, + 0, + G_MAXUINT8, + 0);; if (errno) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Argument for \"%s\" is not a valid number", w); @@ -991,17 +1049,17 @@ parse_line_type_uint32_with_lock: s = words[i_words]; if (!s) goto err_word_missing_argument; - if (info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) { + if (p_info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) { if (nm_streq (s, "lock")) { s = words[++i_words]; if (!s) goto err_word_missing_argument; - info->v.uint32_with_lock.lock = TRUE; + p_data->v.uint32_with_lock.lock = TRUE; } else - info->v.uint32_with_lock.lock = FALSE; - info->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);; + p_data->v.uint32_with_lock.lock = FALSE; + p_data->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);; } else { - info->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0); + p_data->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0); } if (errno) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -1026,16 +1084,16 @@ parse_line_type_addr_with_prefix: { int prefix = -1; - if (info->type == PARSE_LINE_TYPE_ADDR) { + if (p_info->type == PARSE_LINE_TYPE_ADDR) { if (!nm_utils_parse_inaddr_bin (addr_family, s, NULL, - &info->v.addr.addr)) { - if ( info == &infos[PARSE_LINE_ATTR_ROUTE_VIA] + &p_data->v.addr.addr)) { + if ( p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_VIA] && nm_streq (s, "(null)")) { /* Due to a bug, would older versions of NM write "via (null)" * (rh#1452648). Workaround that, and accept it.*/ - memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); + memset (&p_data->v.addr.addr, 0, sizeof (p_data->v.addr.addr)); } else { if (unqualified_addr) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -1050,15 +1108,15 @@ parse_line_type_addr_with_prefix: } } } else { - nm_assert (info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX); - if ( info == &infos[PARSE_LINE_ATTR_ROUTE_TO] + nm_assert (p_info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX); + if ( p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_TO] && nm_streq (s, "default")) { - memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); + memset (&p_data->v.addr.addr, 0, sizeof (p_data->v.addr.addr)); prefix = 0; } else if (!nm_utils_parse_inaddr_prefix_bin (addr_family, s, NULL, - &info->v.addr.addr, + &p_data->v.addr.addr, &prefix)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Argument for \"%s\" is not ADDR/PREFIX format", w); @@ -1066,10 +1124,10 @@ parse_line_type_addr_with_prefix: } } if (prefix == -1) - info->v.addr.has_plen = FALSE; + p_data->v.addr.has_plen = FALSE; else { - info->v.addr.has_plen = TRUE; - info->v.addr.plen = prefix; + p_data->v.addr.has_plen = TRUE; + p_data->v.addr.plen = prefix; } } i_words++; @@ -1087,70 +1145,76 @@ next: route = options_route; nm_ip_route_ref (route); } else { - ParseLineInfo *info_to = &infos[PARSE_LINE_ATTR_ROUTE_TO]; - ParseLineInfo *info_via = &infos[PARSE_LINE_ATTR_ROUTE_VIA]; - ParseLineInfo *info_metric = &infos[PARSE_LINE_ATTR_ROUTE_METRIC]; + ParseLineData *data_to = &parse_datas[PARSE_LINE_ATTR_ROUTE_TO]; + ParseLineData *data_via = &parse_datas[PARSE_LINE_ATTR_ROUTE_VIA]; + ParseLineData *data_metric = &parse_datas[PARSE_LINE_ATTR_ROUTE_METRIC]; guint prefix; - if (!info_to->has) { + if (!data_to->has) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing destination prefix"); return -EINVAL; } - prefix = info_to->v.addr.has_plen - ? info_to->v.addr.plen + prefix = data_to->v.addr.has_plen + ? data_to->v.addr.plen : (addr_family == AF_INET ? 32 : 128); route = nm_ip_route_new_binary (addr_family, - &info_to->v.addr.addr, + &data_to->v.addr.addr, prefix, - info_via->has ? &info_via->v.addr.addr : NULL, - info_metric->has ? (gint64) info_metric->v.uint32 : (gint64) -1, + data_via->has ? &data_via->v.addr.addr : NULL, + data_metric->has ? (gint64) data_metric->v.uint32 : (gint64) -1, error); - info_to->has = FALSE; - info_via->has = FALSE; - info_metric->has = FALSE; + data_to->has = FALSE; + data_via->has = FALSE; + data_metric->has = FALSE; if (!route) return -EINVAL; } - for (i = 0; i < G_N_ELEMENTS (infos); i++) { - ParseLineInfo *info = &infos[i]; + for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) { + const ParseLineInfo *p_info = &parse_infos[i]; + ParseLineData *p_data = &parse_datas[i]; - if (!info->has) + if (!p_data->has) continue; - if (info->ignore || info->disabled) + + if ( (p_info->ignore & af_flag) + || (p_info->disabled & af_flag) + || (p_info->disabled_with_options_route && options_route)) continue; - switch (info->type) { + + switch (p_info->type) { case PARSE_LINE_TYPE_UINT8: + case PARSE_LINE_TYPE_ROUTE_SCOPE: nm_ip_route_set_attribute (route, - info->key, - g_variant_new_byte (info->v.uint8)); + p_info->key, + g_variant_new_byte (p_data->v.uint8)); break; case PARSE_LINE_TYPE_UINT32: nm_ip_route_set_attribute (route, - info->key, - g_variant_new_uint32 (info->v.uint32)); + p_info->key, + g_variant_new_uint32 (p_data->v.uint32)); break; case PARSE_LINE_TYPE_UINT32_WITH_LOCK: - if (info->v.uint32_with_lock.lock) { + if (p_data->v.uint32_with_lock.lock) { nm_ip_route_set_attribute (route, - nm_sprintf_buf (buf1, "lock-%s", info->key), + nm_sprintf_buf (buf1, "lock-%s", p_info->key), g_variant_new_boolean (TRUE)); } nm_ip_route_set_attribute (route, - info->key, - g_variant_new_uint32 (info->v.uint32_with_lock.uint32)); + p_info->key, + g_variant_new_uint32 (p_data->v.uint32_with_lock.uint32)); break; case PARSE_LINE_TYPE_ADDR: case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: nm_ip_route_set_attribute (route, - info->key, + p_info->key, g_variant_new_printf ("%s%s", - inet_ntop (addr_family, &info->v.addr.addr, buf1, sizeof (buf1)), - info->v.addr.has_plen - ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) + inet_ntop (addr_family, &p_data->v.addr.addr, buf1, sizeof (buf1)), + p_data->v.addr.has_plen + ? nm_sprintf_buf (buf2, "/%u", (unsigned) p_data->v.addr.plen) : "")); break; case PARSE_LINE_TYPE_FLAG: @@ -1159,7 +1223,7 @@ next: * of this attribute, hence, the file format cannot encode * that configuration. */ nm_ip_route_set_attribute (route, - info->key, + p_info->key, g_variant_new_boolean (TRUE)); break; default: diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index c457b810ea..ea2cef803c 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2084,6 +2084,8 @@ get_route_attributes_string (NMIPRoute *route, int family) /* we also have a corresponding attribute with the numeric value. The * lock setting is handled above. */ } + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SCOPE)) { + g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_byte (attr)); } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr)); } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) { diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 8d6aaac2f6..5d02c62ef3 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -6,10 +6,10 @@ ADDRESS1=44.55.66.77 NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 -OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" +OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14" ADDRESS2=44.55.66.78 NETMASK2=255.255.255.255 GATEWAY2=192.168.1.8 METRIC2=3 -OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14" +OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14 scope link" diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 459a78eca0..d3651978f2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1334,6 +1334,7 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 10); ip4_route = nm_setting_ip_config_get_route (s_ip4, 2); g_assert (ip4_route); @@ -1351,6 +1352,7 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 253); g_object_unref (connection); }