ndisc: generate routes with nexthops

This commit is contained in:
Beniamino Galvani 2025-12-10 14:19:57 +01:00
parent c63db13d97
commit f5aa4c8e46
2 changed files with 22 additions and 15 deletions

View file

@ -107,6 +107,7 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_ndisc_dhcp_level_to_string,
NML3ConfigData * NML3ConfigData *
nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
int ifindex, int ifindex,
const char *ifname,
const NMNDiscData *rdata, const NMNDiscData *rdata,
NMSettingIP6ConfigPrivacy ip6_privacy, NMSettingIP6ConfigPrivacy ip6_privacy,
NMUtilsIPv6IfaceId *token) NMUtilsIPv6IfaceId *token)
@ -170,8 +171,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
} }
if (rdata->gateways_n > 0) { if (rdata->gateways_n > 0) {
guint metric_offset = 0; guint metric_offset = 0;
NMIcmpv6RouterPref prev_pref = NM_ICMPV6_ROUTER_PREF_INVALID;
NMPlatformIP6Route r = { NMPlatformIP6Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_NDISC, .rt_source = NM_IP_CONFIG_SOURCE_NDISC,
@ -183,24 +183,29 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
}; };
for (i = 0; i < rdata->gateways_n; i++) { for (i = 0; i < rdata->gateways_n; i++) {
/* If we add multiple default routes with the same metric and NMPlatformIP6NextHop nh = {
* different preferences, kernel merges them into a single ECMP .ifindex = ifindex,
* route, with overall preference equal to the preference of the .gateway = rdata->gateways[i].address,
* first route added. Therefore, the preference of individual routes };
* is not respected. CSipHash state;
* To avoid that, add routes with different metrics if they have guint64 id64;
* different preferences, so that they are not merged together. Here
* the gateways are already ordered by increasing preference. */ c_siphash_init(&state, NM_HASH_SEED_16_U64(725697701u));
if (i != 0 && rdata->gateways[i].preference != prev_pref) { c_siphash_append(&state, (const uint8_t *) ifname, strlen(ifname) + 1);
metric_offset++; c_siphash_append(&state,
} (const uint8_t *) &rdata->gateways[i].address,
sizeof(struct in6_addr));
id64 = c_siphash_finalize(&state);
nh.id = ((guint32) (id64 >> 32u)) | (1 << 31u);
// XXX: find a strategy to generate stable ID avoiding
// collisions with existing ones
prev_pref = rdata->gateways[i].preference;
r.metric = metric_offset; r.metric = metric_offset;
r.gateway = rdata->gateways[i].address;
r.rt_pref = rdata->gateways[i].preference; r.rt_pref = rdata->gateways[i].preference;
r.nhid = nh.id;
nm_assert((NMIcmpv6RouterPref) r.rt_pref == rdata->gateways[i].preference); nm_assert((NMIcmpv6RouterPref) r.rt_pref == rdata->gateways[i].preference);
nm_l3_config_data_add_route_6(l3cd, &r); nm_l3_config_data_add_route_6(l3cd, &r);
nm_l3_config_data_add_nexthop(l3cd, AF_INET6, NULL, (const NMPlatformIPNextHop *) &nh);
} }
} }
@ -435,6 +440,7 @@ nm_ndisc_emit_config_change(NMNDisc *self, NMNDiscConfigMap changed)
l3cd = nm_ndisc_data_to_l3cd(nm_l3cfg_get_multi_idx(priv->config.l3cfg), l3cd = nm_ndisc_data_to_l3cd(nm_l3cfg_get_multi_idx(priv->config.l3cfg),
nm_l3cfg_get_ifindex(priv->config.l3cfg), nm_l3cfg_get_ifindex(priv->config.l3cfg),
nm_l3cfg_get_ifname(priv->config.l3cfg, FALSE),
rdata, rdata,
priv->config.ip6_privacy, priv->config.ip6_privacy,
priv->iid_is_token ? &priv->iid : NULL); priv->iid_is_token ? &priv->iid : NULL);

View file

@ -280,6 +280,7 @@ struct _NML3ConfigData;
struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
int ifindex, int ifindex,
const char *ifname,
const NMNDiscData *rdata, const NMNDiscData *rdata,
NMSettingIP6ConfigPrivacy ip6_privacy, NMSettingIP6ConfigPrivacy ip6_privacy,
NMUtilsIPv6IfaceId *token); NMUtilsIPv6IfaceId *token);