cloud-setup: reorder addresses to honor "primary_ip_address"

The order of IPv4 addresses matters, in particular if they are in
the same subnet. Kernel will mark all but the first one as "secondary".
In NetworkManager's ipv4.addresses, the first address is the primary.

It seems that on aliyun cloud, "private-ipv4s" URL may give the
addresses in arbitrary order. The primary can be fetched from
"primary-ip-address".

Fix that by also fetching "primary-ip-address". Then, resort the array
so that the primary is the first one in the list.

https://bugzilla.redhat.com/show_bug.cgi?id=2079849
(cherry picked from commit 191baf84e2)
This commit is contained in:
Thomas Haller 2022-04-28 13:56:17 +02:00
parent a845a3425f
commit 3a9ec3c5a3
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
2 changed files with 73 additions and 1 deletions

View file

@ -123,6 +123,7 @@ detect(NMCSProvider *provider, GTask *task)
typedef enum {
GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK,
GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S,
GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS,
GET_CONFIG_FETCH_DONE_TYPE_NETMASK,
GET_CONFIG_FETCH_DONE_TYPE_GATEWAY,
} GetConfigFetchDoneType;
@ -177,6 +178,16 @@ _get_config_fetch_done_cb(NMHttpClient *http_client,
}
break;
case GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS:
if (nm_utils_parse_inaddr_bin(AF_INET, g_bytes_get_data(response, NULL), NULL, &tmp_addr)) {
nm_assert(config_iface_data->priv.aliyun.primary_ip_address == 0);
nm_assert(!config_iface_data->priv.aliyun.has_primary_ip_address);
config_iface_data->priv.aliyun.primary_ip_address = tmp_addr;
config_iface_data->priv.aliyun.has_primary_ip_address = TRUE;
}
break;
case GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK:
if (nm_utils_parse_inaddr_prefix_bin(AF_INET,
@ -212,6 +223,26 @@ _get_config_fetch_done_cb(NMHttpClient *http_client,
break;
}
if (!config_iface_data->priv.aliyun.ipv4s_arr_ordered
&& config_iface_data->priv.aliyun.has_primary_ip_address
&& config_iface_data->ipv4s_len > 0) {
for (i = 0; i < config_iface_data->ipv4s_len; i++) {
if (config_iface_data->ipv4s_arr[i]
!= config_iface_data->priv.aliyun.primary_ip_address)
continue;
if (i > 0) {
/* OK, at position [i] we found the primary address.
* Move the elements from [0..(i-1)] to [1..i] and then set [0]. */
memmove(&config_iface_data->ipv4s_arr[1],
&config_iface_data->ipv4s_arr[0],
i * sizeof(in_addr_t));
config_iface_data->ipv4s_arr[0] = config_iface_data->priv.aliyun.primary_ip_address;
}
break;
}
config_iface_data->priv.aliyun.ipv4s_arr_ordered = TRUE;
}
out:
get_config_data->n_pending--;
_nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error));
@ -235,6 +266,17 @@ _get_config_fetch_done_cb_private_ipv4s(GObject *source, GAsyncResult *result, g
GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S);
}
static void
_get_config_fetch_done_cb_primary_ip_address(GObject *source,
GAsyncResult *result,
gpointer user_data)
{
_get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
result,
user_data,
GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS);
}
static void
_get_config_fetch_done_cb_netmask(GObject *source, GAsyncResult *result, gpointer user_data)
{
@ -297,6 +339,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
gs_free char *uri2 = NULL;
gs_free char *uri3 = NULL;
gs_free char *uri4 = NULL;
gs_free char *uri5 = NULL;
config_iface_data = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
@ -361,6 +404,23 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
nm_http_client_poll_get(
http_client,
(uri3 = _aliyun_uri_interfaces(v_mac_data->path,
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
"primary-ip-address")),
HTTP_TIMEOUT_MS,
512 * 1024,
10000,
1000,
NULL,
get_config_data->intern_cancellable,
NULL,
NULL,
_get_config_fetch_done_cb_primary_ip_address,
nm_utils_user_data_pack(get_config_data, config_iface_data));
get_config_data->n_pending++;
nm_http_client_poll_get(
http_client,
(uri4 = _aliyun_uri_interfaces(v_mac_data->path,
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
"netmask")),
HTTP_TIMEOUT_MS,
@ -377,7 +437,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
get_config_data->n_pending++;
nm_http_client_poll_get(
http_client,
(uri4 = _aliyun_uri_interfaces(v_mac_data->path,
(uri5 = _aliyun_uri_interfaces(v_mac_data->path,
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
"gateway")),
HTTP_TIMEOUT_MS,

View file

@ -36,6 +36,18 @@ typedef struct {
* nmcs_provider_get_config(). */
bool was_requested : 1;
/* Usually we would want that the parent class NMCSProvider is not aware about
* the implementations. However, it's convenient to track implementation specific data
* here, thus we violate such separation. In practice, all subclasses are known
* at compile time, and it will be simpler this way. */
struct {
struct {
in_addr_t primary_ip_address;
bool has_primary_ip_address : 1;
bool ipv4s_arr_ordered : 1;
} aliyun;
} priv;
} NMCSProviderGetConfigIfaceData;
static inline gboolean