diff options
| author | Michael Biebl <biebl@debian.org> | 2022-01-13 22:30:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2022-01-13 22:30:39 +0100 |
| commit | 88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (patch) | |
| tree | 71f32df6617802270e8a78574bd8e1637dc532f4 /src/core/nm-l3-config-data.c | |
| parent | e74c568b07b50b97873fb4ee1d776dedefbd54d6 (diff) | |
New upstream version 1.34.0 upstream/1.34.0
Diffstat (limited to 'src/core/nm-l3-config-data.c')
| -rw-r--r-- | src/core/nm-l3-config-data.c | 701 |
1 files changed, 428 insertions, 273 deletions
diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index f2ec040b..033c8942 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -131,6 +131,14 @@ struct _NML3ConfigData { guint32 ndisc_reachable_time_msec_val; guint32 ndisc_retrans_timer_msec_val; + union { + struct { + NMOptionBool never_default_6; + NMOptionBool never_default_4; + }; + NMOptionBool never_default_x[2]; + }; + NMTernary metered : 3; NMTernary proxy_browser_only : 3; @@ -323,7 +331,7 @@ _strv_ptrarray_merge(GPtrArray **p_dst, const GPtrArray *src) const char *s = src->pdata[i]; if (dst_initial_len > 0 - && nm_utils_strv_find_first((char **) ((*p_dst)->pdata), dst_initial_len, s) >= 0) + && nm_strv_find_first((const char *const *) ((*p_dst)->pdata), dst_initial_len, s) >= 0) continue; g_ptr_array_add(*p_dst, g_strdup(s)); @@ -439,27 +447,23 @@ nm_l3_config_data_log(const NML3ConfigData *self, const char *s_prefix = "ndisc: "; if (self->ndisc_hop_limit_set) { - nm_utils_strbuf_append(&p, - &l, - "%shop-limit=%d", - s_prefix, - self->ndisc_hop_limit_val); + nm_strbuf_append(&p, &l, "%shop-limit=%d", s_prefix, self->ndisc_hop_limit_val); s_prefix = ", "; } if (self->ndisc_reachable_time_msec_set) { - nm_utils_strbuf_append(&p, - &l, - "%sreachable-time-msec=%u", - s_prefix, - self->ndisc_reachable_time_msec_val); + nm_strbuf_append(&p, + &l, + "%sreachable-time-msec=%u", + s_prefix, + self->ndisc_reachable_time_msec_val); s_prefix = ", "; } if (self->ndisc_retrans_timer_msec_set) { - nm_utils_strbuf_append(&p, - &l, - "%sretrans-timer-msec=%u", - s_prefix, - self->ndisc_retrans_timer_msec_val); + nm_strbuf_append(&p, + &l, + "%sretrans-timer-msec=%u", + s_prefix, + self->ndisc_retrans_timer_msec_val); s_prefix = ", "; } _L("%s", sbuf); @@ -541,6 +545,9 @@ nm_l3_config_data_log(const NML3ConfigData *self, options[i].value_str); } } + + if (self->never_default_x[IS_IPv4] != NM_OPTION_BOOL_DEFAULT) + _L("never-default: %s", self->never_default_x[IS_IPv4] ? "yes" : "no"); } if (self->mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { @@ -643,12 +650,14 @@ _idx_type_init(DedupMultiIdxType *idx_type, NMPObjectType obj_type) } NML3ConfigData * -nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex) +nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSource source) { NML3ConfigData *self; nm_assert(multi_idx); nm_assert(ifindex > 0); + nm_assert(source == NM_IP_CONFIG_SOURCE_UNKNOWN + || (source >= NM_IP_CONFIG_SOURCE_KERNEL && source <= NM_IP_CONFIG_SOURCE_USER)); self = g_slice_new(NML3ConfigData); *self = (NML3ConfigData){ @@ -663,7 +672,9 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex) .proxy_method = NM_PROXY_CONFIG_METHOD_UNKNOWN, .route_table_sync_4 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, .route_table_sync_6 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, - .source = NM_IP_CONFIG_SOURCE_UNKNOWN, + .never_default_6 = NM_OPTION_BOOL_DEFAULT, + .never_default_4 = NM_OPTION_BOOL_DEFAULT, + .source = source, .ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, .ndisc_hop_limit_set = FALSE, .ndisc_reachable_time_msec_set = FALSE, @@ -691,17 +702,21 @@ nm_l3_config_data_ref(const NML3ConfigData *self) const NML3ConfigData * nm_l3_config_data_ref_and_seal(const NML3ConfigData *self) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); - ((NML3ConfigData *) self)->is_sealed = TRUE; - ((NML3ConfigData *) self)->ref_count++; + if (self) { + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + ((NML3ConfigData *) self)->is_sealed = TRUE; + ((NML3ConfigData *) self)->ref_count++; + } return self; } const NML3ConfigData * nm_l3_config_data_seal(const NML3ConfigData *self) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); - ((NML3ConfigData *) self)->is_sealed = TRUE; + if (self) { + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + ((NML3ConfigData *) self)->is_sealed = TRUE; + } return self; } @@ -871,6 +886,26 @@ nm_l3_config_data_lookup_obj(const NML3ConfigData *self, const NMPObject *obj) return nm_dedup_multi_index_lookup_obj(self->multi_idx, idx, obj); } +const NMPlatformIP4Address * +nm_l3_config_data_lookup_address_4(const NML3ConfigData *self, + in_addr_t addr, + guint8 plen, + in_addr_t peer_addr) +{ + const NMDedupMultiEntry *head; + NMPObject obj_stack; + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + nmp_object_stackinit_id_ip4_address(&obj_stack, self->ifindex, addr, plen, peer_addr); + + head = nm_l3_config_data_lookup_obj(self, &obj_stack); + if (!head) + return NULL; + + return NMP_OBJECT_CAST_IP4_ADDRESS(head->obj); +} + const NMPlatformIP6Address * nm_l3_config_data_lookup_address_6(const NML3ConfigData *self, const struct in6_addr *addr) { @@ -879,7 +914,7 @@ nm_l3_config_data_lookup_address_6(const NML3ConfigData *self, const struct in6_ nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); - /* this works only, because the primary key for a Ipv6 address is the + /* this works only, because the primary key for a IPv6 address is the * ifindex and the "struct in6_addr". */ nmp_object_stackinit_id_ip6_address(&obj_stack, self->ifindex, addr); @@ -1104,6 +1139,14 @@ _l3_config_data_add_obj(NMDedupMultiIndex * multi_idx, obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source; modified = TRUE; } + + /* OR assume_config_once flag */ + if (obj_new->ip_address.a_assume_config_once + && !obj_old->ip_address.a_assume_config_once) { + obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.a_assume_config_once = TRUE; + modified = TRUE; + } break; case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: @@ -1113,6 +1156,14 @@ _l3_config_data_add_obj(NMDedupMultiIndex * multi_idx, obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source; modified = TRUE; } + + /* OR assume_config_once flag */ + if (obj_new->ip_route.r_assume_config_once + && !obj_old->ip_route.r_assume_config_once) { + obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_route.r_assume_config_once = TRUE; + modified = TRUE; + } break; default: nm_assert_not_reached(); @@ -1168,11 +1219,11 @@ _l3_config_best_default_route_find_better(const NMPObject *obj_cur, const NMPObj NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) || NMP_OBJECT_GET_TYPE(obj_cur) == NMP_OBJECT_GET_TYPE(obj_cmp)); - nm_assert(!obj_cur || nmp_object_ip_route_is_best_defaut_route(obj_cur)); + nm_assert(!obj_cur || nmp_object_ip_route_is_best_default_route(obj_cur)); /* assumes that @obj_cur is already the best default route (or NULL). It checks whether * @obj_cmp is also a default route and returns the best of both. */ - if (obj_cmp && nmp_object_ip_route_is_best_defaut_route(obj_cmp)) { + if (obj_cmp && nmp_object_ip_route_is_best_default_route(obj_cmp)) { guint32 metric_cur, metric_cmp; if (!obj_cur) @@ -1297,9 +1348,16 @@ const NMPObject * nm_l3_config_data_get_best_default_route(const NML3ConfigData *self, int addr_family) { nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); - nm_assert_addr_family(addr_family); - return self->best_default_route_x[NM_IS_IPv4(addr_family)]; + switch (addr_family) { + case AF_INET: + return self->best_default_route_4; + case AF_INET6: + return self->best_default_route_6; + case AF_UNSPEC: + return self->best_default_route_4 ?: self->best_default_route_6; + } + return nm_assert_unreachable_val(NULL); } /*****************************************************************************/ @@ -1336,10 +1394,15 @@ _check_and_add_domain(GPtrArray **p_arr, const char *domain) gconstpointer nm_l3_config_data_get_nameservers(const NML3ConfigData *self, int addr_family, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); nm_assert(out_len); + if (!self) { + *out_len = 0; + return NULL; + } + return _garray_inaddr_get(self->nameservers_x[NM_IS_IPv4(addr_family)], out_len); } @@ -1372,7 +1435,13 @@ nm_l3_config_data_clear_nameservers(NML3ConfigData *self, int addr_family) const in_addr_t * nm_l3_config_data_get_wins(const NML3ConfigData *self, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(out_len); + + if (!self) { + *out_len = 0; + return NULL; + } return _garray_inaddr_get(self->wins, out_len); } @@ -1420,10 +1489,15 @@ nm_l3_config_data_set_nis_domain(NML3ConfigData *self, const char *nis_domain) const char *const * nm_l3_config_data_get_domains(const NML3ConfigData *self, int addr_family, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); nm_assert(out_len); + if (!self) { + *out_len = 0; + return NULL; + } + return nm_strv_ptrarray_get_unsafe(self->domains_x[NM_IS_IPv4(addr_family)], out_len); } @@ -1439,10 +1513,15 @@ nm_l3_config_data_add_domain(NML3ConfigData *self, int addr_family, const char * const char *const * nm_l3_config_data_get_searches(const NML3ConfigData *self, int addr_family, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); nm_assert(out_len); + if (!self) { + *out_len = 0; + return NULL; + } + return nm_strv_ptrarray_get_unsafe(self->searches_x[NM_IS_IPv4(addr_family)], out_len); } @@ -1492,10 +1571,15 @@ nm_l3_config_data_add_dns_option(NML3ConfigData *self, int addr_family, const ch const char *const * nm_l3_config_data_get_dns_options(const NML3ConfigData *self, int addr_family, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); nm_assert(out_len); + if (!self) { + *out_len = 0; + return NULL; + } + return nm_strv_ptrarray_get_unsafe(self->dns_options_x[NM_IS_IPv4(addr_family)], out_len); } @@ -1622,6 +1706,29 @@ nm_l3_config_data_set_route_table_sync(NML3ConfigData * self, } NMTernary +nm_l3_config_data_get_never_default(const NML3ConfigData *self, int addr_family) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return NM_TERNARY_FROM_OPTION_BOOL(self->never_default_x[NM_IS_IPv4(addr_family)]); +} + +gboolean +nm_l3_config_data_set_never_default(NML3ConfigData *self, int addr_family, NMTernary never_default) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMOptionBool v = NM_TERNARY_TO_OPTION_BOOL(never_default); + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + + if (self->never_default_x[IS_IPv4] == v) + return FALSE; + + self->never_default_x[IS_IPv4] = v; + return TRUE; +} + +NMTernary nm_l3_config_data_get_metered(const NML3ConfigData *self) { nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); @@ -1682,22 +1789,13 @@ nm_l3_config_data_set_ip6_mtu(NML3ConfigData *self, guint32 ip6_mtu) return TRUE; } -gboolean -nm_l3_config_data_set_source(NML3ConfigData *self, NMIPConfigSource source) -{ - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); - - if (self->source == source) - return FALSE; - - self->source = source; - return TRUE; -} - NMSettingIP6ConfigPrivacy nm_l3_config_data_get_ip6_privacy(const NML3ConfigData *self) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); + + if (!self) + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; return self->ip6_privacy; } @@ -1799,7 +1897,7 @@ nm_l3_config_data_set_proxy_pac_script(NML3ConfigData *self, const char *value) gboolean nm_l3_config_data_get_ndisc_hop_limit(const NML3ConfigData *self, int *out_val) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); if (!self->ndisc_hop_limit_set) { NM_SET_OUT(out_val, 0); @@ -1822,7 +1920,7 @@ nm_l3_config_data_set_ndisc_hop_limit(NML3ConfigData *self, int val) gboolean nm_l3_config_data_get_ndisc_reachable_time_msec(const NML3ConfigData *self, guint32 *out_val) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); if (!self->ndisc_reachable_time_msec_set) { NM_SET_OUT(out_val, 0); @@ -1845,7 +1943,7 @@ nm_l3_config_data_set_ndisc_reachable_time_msec(NML3ConfigData *self, guint32 va gboolean nm_l3_config_data_get_ndisc_retrans_timer_msec(const NML3ConfigData *self, guint32 *out_val) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); if (!self->ndisc_retrans_timer_msec_set) { NM_SET_OUT(out_val, 0); @@ -1922,14 +2020,26 @@ nm_l3_config_data_set_dhcp_lease_from_options(NML3ConfigData *self, /*****************************************************************************/ static int -_dedup_multi_index_cmp(const NML3ConfigData *a, const NML3ConfigData *b, NMPObjectType obj_type) +_dedup_multi_index_cmp(const NML3ConfigData *a, + const NML3ConfigData *b, + NMPObjectType obj_type, + gboolean ignore_ifindex) { const NMDedupMultiHeadEntry *h_a = nm_l3_config_data_lookup_objs(a, obj_type); const NMDedupMultiHeadEntry *h_b = nm_l3_config_data_lookup_objs(b, obj_type); NMDedupMultiIter iter_a; NMDedupMultiIter iter_b; + /* We handle ignore_index via NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX flag, which is + * only implemented for certain types. */ + nm_assert(NM_IN_SET(obj_type, + NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP6_ADDRESS, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); + NM_CMP_SELF(h_a, h_b); + NM_CMP_DIRECT(h_a->len, h_b->len); nm_assert(h_a->len > 0); @@ -1952,7 +2062,10 @@ _dedup_multi_index_cmp(const NML3ConfigData *a, const NML3ConfigData *b, NMPObje have_b = nm_platform_dedup_multi_iter_next_obj(&iter_b, &obj_b, obj_type); nm_assert(have_b); - NM_CMP_RETURN(nmp_object_cmp(obj_a, obj_b)); + NM_CMP_RETURN(nmp_object_cmp_full(obj_a, + obj_b, + ignore_ifindex ? NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX + : NMP_OBJECT_CMP_FLAGS_NONE)); } } @@ -1961,25 +2074,30 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, const NML3ConfigData *b, NML3ConfigCmpFlags cmp_flags) { - int IS_IPv4; + int IS_IPv4; + gboolean ignore_ifindex; NM_CMP_SELF(a, b); - if (!NM_FLAGS_HAS(cmp_flags, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX)) + ignore_ifindex = NM_FLAGS_HAS(cmp_flags, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX); + + if (!ignore_ifindex) NM_CMP_DIRECT(a->ifindex, b->ifindex); NM_CMP_DIRECT(a->flags, b->flags); - NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP4_ADDRESS)); - NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP6_ADDRESS)); - NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP4_ROUTE)); - NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP6_ROUTE)); + NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP4_ADDRESS, ignore_ifindex)); + NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP6_ADDRESS, ignore_ifindex)); + NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP4_ROUTE, ignore_ifindex)); + NM_CMP_RETURN(_dedup_multi_index_cmp(a, b, NMP_OBJECT_TYPE_IP6_ROUTE, ignore_ifindex)); for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; - NM_CMP_RETURN( - nmp_object_cmp(a->best_default_route_x[IS_IPv4], b->best_default_route_x[IS_IPv4])); + NM_CMP_RETURN(nmp_object_cmp_full(a->best_default_route_x[IS_IPv4], + b->best_default_route_x[IS_IPv4], + ignore_ifindex ? NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX + : NMP_OBJECT_CMP_FLAGS_NONE)); NM_CMP_RETURN( _garray_inaddr_cmp(a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4], addr_family)); @@ -1999,6 +2117,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_DIRECT(a->dns_priority_x[IS_IPv4], b->dns_priority_x[IS_IPv4]); NM_CMP_DIRECT(a->route_table_sync_x[IS_IPv4], b->route_table_sync_x[IS_IPv4]); + NM_CMP_DIRECT(a->never_default_x[IS_IPv4], b->never_default_x[IS_IPv4]); } NM_CMP_RETURN(_garray_inaddr_cmp(a->wins, b->wins, AF_INET)); @@ -2066,8 +2185,8 @@ _data_get_direct_route_for_host(const NML3ConfigData *self, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { const NMPlatformIPXRoute *item = NMP_OBJECT_CAST_IPX_ROUTE(item_obj); - if (nm_ip_addr_is_null(addr_family, - nm_platform_ip_route_get_gateway(addr_family, &item->rx))) + if (!nm_ip_addr_is_null(addr_family, + nm_platform_ip_route_get_gateway(addr_family, &item->rx))) continue; if (best_route && best_route->rx.plen > item->rx.plen) @@ -2114,7 +2233,7 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea const NMPObject * my_addr_obj; NMDedupMultiIter iter; - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); /* For IPv6 slaac, we explicitly add the device-routes (onlink). * As we don't do that for IPv4 and manual IPv6 addresses. Add them here @@ -2125,9 +2244,6 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea in_addr_t network_4; NMPlatformIPXRoute rx; - if (my_addr->external) - continue; - nm_assert(my_addr->plen <= 32); if (my_addr->plen == 0) continue; @@ -2176,120 +2292,137 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea /*****************************************************************************/ void -nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, - int addr_family, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf) +nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_family) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *extra_onlink_routes = NULL; - const NMPObject * my_addr_obj; - const NMPObject * my_route_obj; - NMPlatformIPXRoute rx; + const NMPObject * obj_src; NMDedupMultiIter iter; - in_addr_t network_4 = 0; + int IS_IPv4; guint i; + if (addr_family == AF_UNSPEC) { + nm_l3_config_data_add_dependent_onlink_routes(self, AF_INET); + nm_l3_config_data_add_dependent_onlink_routes(self, AF_INET6); + return; + } + + IS_IPv4 = NM_IS_IPv4(addr_family); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); - nm_assert_addr_family(addr_family); /* For IPv6 slaac, we explicitly add the device-routes (onlink). * As we don't do that for IPv4 and manual IPv6 addresses. Add them here * as dependent routes. */ - if (!IS_IPv4) { - /* Pre-generate multicast route */ - rx.r6 = (NMPlatformIP6Route){ - .ifindex = self->ifindex, - .network.s6_addr[0] = 0xffu, - .plen = 8, - .table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL), - .type_coerced = nm_platform_route_type_coerce(RTN_UNICAST), - .metric = 256, - }; - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); - } + nm_l3_config_data_iter_obj_for_each (&iter, self, &obj_src, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { + const NMPlatformIPXRoute *route_src = NMP_OBJECT_CAST_IPX_ROUTE(obj_src); + NMPObject * new_route; + NMPlatformIPXRoute * new_r; + const NMIPAddr * p_gateway; - nm_l3_config_data_iter_obj_for_each (&iter, - self, - &my_addr_obj, - NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { - const NMPlatformIPXAddress *const my_addr = NMP_OBJECT_CAST_IPX_ADDRESS(my_addr_obj); + p_gateway = nm_platform_ip_route_get_gateway(addr_family, &route_src->rx); + + if (nm_ip_addr_is_null(addr_family, p_gateway)) + continue; - if (my_addr->ax.external) + if (_data_get_direct_route_for_host( + self, + addr_family, + p_gateway, + nm_platform_route_table_uncoerce(route_src->rx.table_coerced, TRUE))) continue; + new_route = nmp_object_clone(obj_src, FALSE); + new_r = NMP_OBJECT_CAST_IPX_ROUTE(new_route); if (IS_IPv4) { - nm_assert(my_addr->a4.plen <= 32); - if (my_addr->a4.plen == 0) - continue; + new_r->r4.network = route_src->r4.gateway; + new_r->r4.plen = 32; + new_r->r4.gateway = 0; + } else { + new_r->r6.network = route_src->r6.gateway; + new_r->r6.plen = 128; + new_r->r6.gateway = in6addr_any; } - if (IS_IPv4) { - rx.r4 = (NMPlatformIP4Route){ - .ifindex = self->ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, - .network = my_addr->a4.address, - .plen = 32, - .pref_src = my_addr->a4.address, - .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), - .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), - .table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL), - }; - } else { - rx.r6 = (NMPlatformIP6Route){ - .ifindex = self->ifindex, - .network = my_addr->a6.address, - .plen = 128, - .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), - .metric = 0, - .table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL), - }; + /* we cannot add the route right away, because that invalidates the iteration. */ + if (!extra_onlink_routes) + extra_onlink_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + g_ptr_array_add(extra_onlink_routes, new_route); + } + if (extra_onlink_routes) { + for (i = 0; i < extra_onlink_routes->len; i++) { + nm_l3_config_data_add_route_full(self, + addr_family, + extra_onlink_routes->pdata[i], + NULL, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL, + NULL); } - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); + } +} - if (my_addr->ax.plen == 0) +void +nm_l3_config_data_add_dependent_device_routes(NML3ConfigData * self, + int addr_family, + guint32 route_table, + guint32 route_metric, + const NML3ConfigData *source) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMPObject * obj_src; + NMPlatformIPXRoute rx; + NMDedupMultiIter iter; + + nm_assert_addr_family(addr_family); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(source, TRUE)); + nm_assert(self != source); + + /* For IPv6 slaac, we explicitly add the device-routes (onlink) and track them + * as regular routes in NML3ConfigData. + * + * For IPv4 and for manual IPv6 addresses we don't do that. Instead, add those + * routes automatically afterwards. + * + * As route-table/metric is associated with the source l3cd, we need to process + * all source l3cds separately. */ + + nm_l3_config_data_iter_obj_for_each (&iter, + source, + &obj_src, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { + const NMPlatformIPXAddress *const addr_src = NMP_OBJECT_CAST_IPX_ADDRESS(obj_src); + const NMPlatformIPXAddress * addr_dst; + + addr_dst = NMP_OBJECT_CAST_IPX_ADDRESS( + nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj(self, obj_src))); + if (!addr_dst) continue; if (IS_IPv4) { - network_4 = - nm_utils_ip4_address_clear_host_address(my_addr->a4.peer_address, my_addr->a4.plen); + NMPlatformIPXRoute r_stack; + const NMPlatformIPRoute *r; - if (nm_utils_ip4_address_is_zeronet(network_4)) { - /* Kernel doesn't add device-routes for destinations that - * start with 0.x.y.z. Skip them. */ + if (addr_dst->a4.a_acd_not_ready) continue; - } - if (my_addr->a4.plen == 32 && my_addr->a4.address == my_addr->a4.peer_address) { - /* Kernel doesn't add device-routes for /32 addresses unless - * they have a peer. */ - continue; - } + r = (NMPlatformIPRoute *) nm_platform_ip4_address_generate_device_route(&addr_src->a4, + self->ifindex, + route_table, + route_metric, + &r_stack.r4); + if (r) + nm_l3_config_data_add_route(self, addr_family, NULL, r); } else { - if (NM_FLAGS_HAS(my_addr->a6.n_ifa_flags, IFA_F_NOPREFIXROUTE)) + const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED(&addr_src->a6.peer_address); + int routes_i; + + if (addr_src->ax.plen == 0) continue; - } - if (IS_IPv4) { - rx.r4 = (NMPlatformIP4Route){ - .ifindex = self->ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, - .network = network_4, - .plen = my_addr->a4.plen, - .pref_src = my_addr->a4.address, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - .scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK), - }; - nm_platform_ip_route_normalize(addr_family, &rx.rx); - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); - } else { - const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED(&my_addr->a6.peer_address); - int routes_i; + if (NM_FLAGS_HAS(addr_src->a6.n_ifa_flags, IFA_F_NOPREFIXROUTE)) + continue; /* If we have an IPv6 peer, we add two /128 routes * (unless, both addresses are identical). */ @@ -2299,20 +2432,20 @@ nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, guint8 plen; if (routes_i == 1 && has_peer - && IN6_ARE_ADDR_EQUAL(&my_addr->a6.address, &my_addr->a6.peer_address)) + && IN6_ARE_ADDR_EQUAL(&addr_src->a6.address, &addr_src->a6.peer_address)) break; if (has_peer) { if (routes_i == 0) - a6 = &my_addr->a6.address; + a6 = &addr_src->a6.address; else - a6 = &my_addr->a6.peer_address; + a6 = &addr_src->a6.peer_address; plen = 128; } else { a6 = nm_utils_ip6_address_clear_host_address(&a6_stack, - &my_addr->a6.address, - my_addr->a6.plen); - plen = my_addr->a6.plen; + &addr_src->a6.address, + addr_src->a6.plen); + plen = addr_src->a6.plen; } rx.r6 = (NMPlatformIP6Route){ @@ -2328,73 +2461,16 @@ nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, } } } - - nm_l3_config_data_iter_obj_for_each (&iter, - self, - &my_route_obj, - NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { - const NMPlatformIPXRoute *my_route = NMP_OBJECT_CAST_IPX_ROUTE(my_route_obj); - NMPObject * new_route; - NMPlatformIPXRoute * new_r; - const NMIPAddr * p_gateway; - - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(my_route) - || NM_IS_IP_CONFIG_SOURCE_RTPROT(my_route->rx.rt_source)) - continue; - - p_gateway = nm_platform_ip_route_get_gateway(addr_family, &my_route->rx); - - if (nm_ip_addr_is_null(addr_family, p_gateway)) - continue; - - if (_data_get_direct_route_for_host( - self, - addr_family, - p_gateway, - nm_platform_route_table_uncoerce(my_route->rx.table_coerced, TRUE))) - continue; - - new_route = nmp_object_clone(my_route_obj, FALSE); - new_r = NMP_OBJECT_CAST_IPX_ROUTE(new_route); - if (IS_IPv4) { - new_r->r4.network = my_route->r4.gateway; - new_r->r4.plen = 32; - new_r->r4.gateway = 0; - } else { - new_r->r6.network = my_route->r6.gateway; - new_r->r6.plen = 128; - new_r->r6.gateway = in6addr_any; - } - - /* we cannot add the route right away, because that invalidates the iteration. */ - if (!extra_onlink_routes) - extra_onlink_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - g_ptr_array_add(extra_onlink_routes, new_route); - } - if (extra_onlink_routes) { - for (i = 0; i < extra_onlink_routes->len; i++) { - nm_l3_config_data_add_route_full(self, - addr_family, - extra_onlink_routes->pdata[i], - NULL, - NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, - NULL, - NULL); - } - } } /*****************************************************************************/ static void -_init_from_connection_ip(NML3ConfigData *self, - int addr_family, - NMConnection * connection, - guint32 route_table, - guint32 route_metric) +_init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *connection) { const int IS_IPv4 = NM_IS_IPv4(addr_family); NMSettingIPConfig *s_ip; + gboolean never_default; guint naddresses; guint nroutes; guint nnameservers; @@ -2415,25 +2491,28 @@ _init_from_connection_ip(NML3ConfigData *self, if (!s_ip) return; - if (!nm_setting_ip_config_get_never_default(s_ip) - && (gateway_str = nm_setting_ip_config_get_gateway(s_ip)) + never_default = nm_setting_ip_config_get_never_default(s_ip); + + nm_l3_config_data_set_never_default(self, addr_family, !!never_default); + + if (!never_default && (gateway_str = nm_setting_ip_config_get_gateway(s_ip)) && inet_pton(addr_family, gateway_str, &gateway_bin) == 1 && !nm_ip_addr_is_null(addr_family, &gateway_bin)) { NMPlatformIPXRoute r; if (IS_IPv4) { r.r4 = (NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .gateway = gateway_bin.addr4, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .gateway = gateway_bin.addr4, + .table_any = TRUE, + .metric_any = TRUE, }; } else { r.r6 = (NMPlatformIP6Route){ - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .gateway = gateway_bin.addr6, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .gateway = gateway_bin.addr6, + .table_any = TRUE, + .metric_any = TRUE, }; } @@ -2488,6 +2567,7 @@ _init_from_connection_ip(NML3ConfigData *self, NMIPAddr next_hop_bin; gint64 metric64; guint32 metric; + gboolean metric_any; guint plen; nm_assert(nm_ip_route_get_family(s_route) == addr_family); @@ -2496,11 +2576,14 @@ _init_from_connection_ip(NML3ConfigData *self, nm_ip_route_get_next_hop_binary(s_route, &next_hop_bin); metric64 = nm_ip_route_get_metric(s_route); - if (metric64 < 0) - metric = route_metric; - else - metric = metric64; - metric = nm_utils_ip_route_metric_normalize(addr_family, metric); + if (metric64 < 0) { + metric_any = TRUE; + metric = 0; + } else { + metric_any = FALSE; + metric = metric64; + metric = nm_utils_ip_route_metric_normalize(addr_family, metric); + } plen = nm_ip_route_get_prefix(s_route); @@ -2508,25 +2591,27 @@ _init_from_connection_ip(NML3ConfigData *self, if (IS_IPv4) { r.r4 = (NMPlatformIP4Route){ - .network = network_bin.addr4, - .plen = nm_ip_route_get_prefix(s_route), - .gateway = next_hop_bin.addr4, - .metric = metric, - .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = network_bin.addr4, + .plen = nm_ip_route_get_prefix(s_route), + .gateway = next_hop_bin.addr4, + .metric_any = metric_any, + .metric = metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, }; nm_assert(r.r4.plen <= 32); } else { r.r6 = (NMPlatformIP6Route){ - .network = network_bin.addr6, - .plen = nm_ip_route_get_prefix(s_route), - .gateway = next_hop_bin.addr6, - .metric = metric, - .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = network_bin.addr6, + .plen = nm_ip_route_get_prefix(s_route), + .gateway = next_hop_bin.addr6, + .metric_any = metric_any, + .metric = metric, + .rt_source = NM_IP_CONFIG_SOURCE_USER, }; nm_assert(r.r6.plen <= 128); } - nm_utils_ip_route_attribute_to_platform(addr_family, s_route, &r.rx, route_table); + nm_utils_ip_route_attribute_to_platform(addr_family, s_route, &r.rx, -1); nm_l3_config_data_add_route(self, addr_family, NULL, &r.rx); } @@ -2550,34 +2635,36 @@ _init_from_connection_ip(NML3ConfigData *self, } idx = 0; - while ((idx = nm_setting_ip_config_next_valid_dns_option(s_ip, i)) >= 0) { + while ((idx = nm_setting_ip_config_next_valid_dns_option(s_ip, idx)) >= 0) { nm_l3_config_data_add_dns_option(self, addr_family, - nm_setting_ip_config_get_dns_option(s_ip, i)); + nm_setting_ip_config_get_dns_option(s_ip, idx)); idx++; } nm_l3_config_data_set_dns_priority(self, addr_family, nm_setting_ip_config_get_dns_priority(s_ip)); + + if (!IS_IPv4) { + nm_l3_config_data_set_ip6_privacy( + self, + nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip))); + } } NML3ConfigData * nm_l3_config_data_new_from_connection(NMDedupMultiIndex *multi_idx, int ifindex, - NMConnection * connection, - guint32 route_table_4, - guint32 route_table_6, - guint32 route_metric_4, - guint32 route_metric_6) + NMConnection * connection) { NML3ConfigData *self; NMSettingProxy *s_proxy; - self = nm_l3_config_data_new(multi_idx, ifindex); + self = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_USER); - _init_from_connection_ip(self, AF_INET, connection, route_table_4, route_metric_4); - _init_from_connection_ip(self, AF_INET6, connection, route_table_6, route_metric_6); + _init_from_connection_ip(self, AF_INET, connection); + _init_from_connection_ip(self, AF_INET6, connection); s_proxy = _nm_connection_get_setting(connection, NM_TYPE_SETTING_PROXY); if (s_proxy) { @@ -2693,7 +2780,7 @@ nm_l3_config_data_new_from_platform(NMDedupMultiIndex * multi_idx, if (nm_platform_link_get_master(platform, ifindex) > 0) return NULL; - self = nm_l3_config_data_new(multi_idx, ifindex); + self = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_KERNEL); _init_from_platform(self, AF_INET, platform, ipv6_privacy_rfc4941); _init_from_platform(self, AF_INET6, platform, ipv6_privacy_rfc4941); @@ -2710,13 +2797,16 @@ nm_l3_config_data_merge(NML3ConfigData * self, const guint32 * default_route_table_x /* length 2, for IS_IPv4 */, const guint32 * default_route_metric_x /* length 2, for IS_IPv4 */, const guint32 * default_route_penalty_x /* length 2, for IS_IPv4 */, - NML3ConfigMergeHookAddObj hook_add_addr, + const int * default_dns_priority_x /* length 2, for IS_IPv4 */, + NML3ConfigMergeHookAddObj hook_add_obj, gpointer hook_user_data) { static const guint32 x_default_route_table_x[2] = {RT_TABLE_MAIN, RT_TABLE_MAIN}; static const guint32 x_default_route_metric_x[2] = {NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4}; static const guint32 x_default_route_penalty_x[2] = {0, 0}; + static const int x_default_dns_priority_x[2] = {NM_DNS_PRIORITY_DEFAULT_NORMAL, + NM_DNS_PRIORITY_DEFAULT_NORMAL}; NMDedupMultiIter iter; const NMPObject * obj; int IS_IPv4; @@ -2730,6 +2820,8 @@ nm_l3_config_data_merge(NML3ConfigData * self, default_route_metric_x = x_default_route_metric_x; if (!default_route_penalty_x) default_route_penalty_x = x_default_route_penalty_x; + if (!default_dns_priority_x) + default_dns_priority_x = x_default_dns_priority_x; nm_assert(default_route_table_x[0] != 0); nm_assert(default_route_table_x[1] != 0); @@ -2747,51 +2839,100 @@ nm_l3_config_data_merge(NML3ConfigData * self, src, &obj, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { - NMPlatformIPXAddress addr_stack; - const NMPlatformIPAddress *addr = NULL; - NMTernary ip4acd_not_ready = NM_TERNARY_DEFAULT; + const NMPlatformIPAddress *a_src = NMP_OBJECT_CAST_IP_ADDRESS(obj); + NMPlatformIPXAddress a; + NML3ConfigMergeHookResult hook_result = { + .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .assume_config_once = NM_OPTION_BOOL_DEFAULT, + }; + +#define _ensure_a() \ + G_STMT_START \ + { \ + if (a_src != &a.ax) { \ + if (IS_IPv4) \ + a.a4 = *NMP_OBJECT_CAST_IP4_ADDRESS(obj); \ + else \ + a.a6 = *NMP_OBJECT_CAST_IP6_ADDRESS(obj); \ + a_src = &a.ax; \ + } \ + } \ + G_STMT_END - if (hook_add_addr && !hook_add_addr(src, obj, &ip4acd_not_ready, hook_user_data)) + if (hook_add_obj && !hook_add_obj(src, obj, &hook_result, hook_user_data)) continue; - if (IS_IPv4 && ip4acd_not_ready != NM_TERNARY_DEFAULT - && (!!ip4acd_not_ready) != NMP_OBJECT_CAST_IP4_ADDRESS(obj)->ip4acd_not_ready) { - addr_stack.a4 = *NMP_OBJECT_CAST_IP4_ADDRESS(obj); - addr_stack.a4.ip4acd_not_ready = (!!ip4acd_not_ready); - addr = &addr_stack.ax; - } else - nm_assert(IS_IPv4 || ip4acd_not_ready == NM_TERNARY_DEFAULT); + nm_assert(IS_IPv4 || hook_result.ip4acd_not_ready == NM_OPTION_BOOL_DEFAULT); + + if (a_src->ifindex != self->ifindex) { + _ensure_a(); + a.ax.ifindex = self->ifindex; + } + + if (hook_result.ip4acd_not_ready != NM_OPTION_BOOL_DEFAULT && IS_IPv4 + && (!!hook_result.ip4acd_not_ready) + != ((const NMPlatformIP4Address *) a_src)->a_acd_not_ready) { + _ensure_a(); + a.a4.a_acd_not_ready = (!!hook_result.ip4acd_not_ready); + } + + if (hook_result.assume_config_once != NM_OPTION_BOOL_DEFAULT + && (!!hook_result.assume_config_once) != a_src->a_assume_config_once) { + _ensure_a(); + a.ax.a_assume_config_once = (!!hook_result.assume_config_once); + } nm_l3_config_data_add_address_full(self, addr_family, - addr ? NULL : obj, - addr, + a_src == &a.ax ? NULL : obj, + a_src == &a.ax ? a_src : NULL, NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, NULL); } +#undef _ensure_a + if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES)) { nm_l3_config_data_iter_obj_for_each (&iter, src, &obj, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { - const NMPlatformIPRoute *r_src = NMP_OBJECT_CAST_IP_ROUTE(obj); - NMPlatformIPXRoute r; + const NMPlatformIPRoute * r_src = NMP_OBJECT_CAST_IP_ROUTE(obj); + NMPlatformIPXRoute r; + NML3ConfigMergeHookResult hook_result = { + .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .assume_config_once = NM_OPTION_BOOL_DEFAULT, + }; #define _ensure_r() \ G_STMT_START \ { \ if (r_src != &r.rx) { \ - r_src = &r.rx; \ if (IS_IPv4) \ r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE(obj); \ else \ r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE(obj); \ - r.rx.ifindex = self->ifindex; \ + r_src = &r.rx; \ } \ } \ G_STMT_END + if (hook_add_obj && !hook_add_obj(src, obj, &hook_result, hook_user_data)) + continue; + + nm_assert(hook_result.ip4acd_not_ready == NM_OPTION_BOOL_DEFAULT); + + if (r_src->ifindex != self->ifindex) { + _ensure_r(); + r.rx.ifindex = self->ifindex; + } + + if (hook_result.assume_config_once != NM_OPTION_BOOL_DEFAULT + && (!!hook_result.assume_config_once) != r_src->r_assume_config_once) { + _ensure_r(); + r.rx.r_assume_config_once = (!!hook_result.assume_config_once); + } + if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) { if (r_src->table_any) { _ensure_r(); @@ -2848,12 +2989,20 @@ nm_l3_config_data_merge(NML3ConfigData * self, if (!NM_FLAGS_ANY(self->flags, has_dns_priority_flag) && NM_FLAGS_ANY(src->flags, has_dns_priority_flag)) { - self->dns_priority_x[IS_IPv4] = src->dns_priority_x[IS_IPv4]; + int p = src->dns_priority_x[IS_IPv4]; + + if (p == 0 && !NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) + p = default_dns_priority_x[IS_IPv4]; + + self->dns_priority_x[IS_IPv4] = p; self->flags |= has_dns_priority_flag; } if (self->route_table_sync_x[IS_IPv4] == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE) self->route_table_sync_x[IS_IPv4] = src->route_table_sync_x[IS_IPv4]; + + if (self->never_default_x[IS_IPv4] == NM_OPTION_BOOL_DEFAULT) + self->never_default_x[IS_IPv4] = src->never_default_x[IS_IPv4]; } if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) { @@ -2933,7 +3082,7 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex) if (ifindex <= 0) ifindex = src->ifindex; - self = nm_l3_config_data_new(src->multi_idx, ifindex); + self = nm_l3_config_data_new(src->multi_idx, ifindex, src->source); nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_CLONE, @@ -2941,9 +3090,15 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex) NULL, NULL, NULL, + NULL, NULL); - nm_assert(nm_l3_config_data_cmp_full(src, self, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX) == 0); + nm_assert(nm_l3_config_data_cmp_full(src, + self, + src->ifindex != ifindex + ? NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX + : NM_L3_CONFIG_CMP_FLAGS_NONE) + == 0); nm_assert(nm_l3_config_data_get_ifindex(self) == ifindex); return self; |