cloud-setup: create VLANs for multiple VNICs on OCI

The idea is to create a pair of VLAN and MACVLAN with AddAndActivate if
they are not present, and otherwise follow the ordinary (GetApplied &
Reapply) procedure if the devices are already present.
This commit is contained in:
Lubomir Rintel 2024-11-29 18:03:39 +01:00
parent 692cdf1ed6
commit c3f638ef22

View file

@ -427,9 +427,11 @@ _nmc_mangle_connection(NMDevice *device,
s_ip = nm_connection_get_setting_ip4_config(connection);
nm_assert(NM_IS_SETTING_IP4_CONFIG(s_ip));
if ((ac = nm_device_get_active_connection(device))
&& (remote_connection = NM_CONNECTION(nm_active_connection_get_connection(ac))))
remote_s_ip = nm_connection_get_setting_ip4_config(remote_connection);
if (device) {
if ((ac = nm_device_get_active_connection(device))
&& (remote_connection = NM_CONNECTION(nm_active_connection_get_connection(ac))))
remote_s_ip = nm_connection_get_setting_ip4_config(remote_connection);
}
addrs_new = g_ptr_array_new_full(config_data->ipv4s_len, (GDestroyNotify) nm_ip_address_unref);
rules_new =
@ -567,54 +569,105 @@ _nmc_mangle_connection(NMDevice *device,
/*****************************************************************************/
static gboolean
_config_one(SigTermData *sigterm_data,
NMClient *nmc,
const NMCSProviderGetConfigResult *result,
guint idx)
_config_new_vlan(SigTermData *sigterm_data,
const NMCSProviderGetConfigIfaceData *config_data,
NMClient *nmc,
const NMCSProviderGetConfigResult *result,
const char *connection_type,
const char *hwaddr,
const char *parent_hwaddr,
guint32 vlan_tag)
{
const NMCSProviderGetConfigIfaceData *config_data = result->iface_datas_arr[idx];
const char *hwaddr = config_data->hwaddr;
gs_unref_object NMDevice *device = NULL;
gs_unref_object NMConnection *applied_connection = NULL;
guint64 applied_version_id;
gs_free_error GError *error = NULL;
gboolean changed;
gboolean skipped_single_addr;
gboolean version_id_changed;
guint try_count;
gboolean any_changes = FALSE;
gboolean maybe_no_preserved_external_ip;
gs_unref_object NMConnection *connection = NULL;
gs_unref_object NMActiveConnection *active_connection = NULL;
gs_free_error GError *error = NULL;
gs_free char *ifname = NULL;
g_main_context_iteration(NULL, FALSE);
connection = nm_simple_connection_new();
if (g_cancellable_is_cancelled(sigterm_data->cancellable))
return FALSE;
device = nm_g_object_ref(_nmc_get_device_by_hwaddr(nmc, NM_DEVICE_TYPE_ETHERNET, hwaddr));
if (!device) {
_LOGD("config device %s: skip because device not found", hwaddr);
return FALSE;
if (strcmp(connection_type, NM_SETTING_MACVLAN_SETTING_NAME) == 0) {
ifname = g_strdup_printf("macvlan%ld", config_data->iface_idx);
nm_connection_add_setting(connection,
g_object_new(NM_TYPE_SETTING_MACVLAN,
NM_SETTING_MACVLAN_MODE,
NM_SETTING_MACVLAN_MODE_PASSTHRU,
NULL));
} else if (strcmp(connection_type, NM_SETTING_VLAN_SETTING_NAME) == 0) {
nm_connection_add_setting(
connection,
g_object_new(NM_TYPE_SETTING_VLAN, NM_SETTING_VLAN_ID, vlan_tag, NULL));
}
if (!nmcs_provider_get_config_iface_data_is_valid(config_data)) {
_LOGD("config device %s: skip because meta data not successfully fetched", hwaddr);
return FALSE;
nm_connection_add_setting(connection,
g_object_new(NM_TYPE_SETTING_CONNECTION,
NM_SETTING_CONNECTION_TYPE,
connection_type,
NM_SETTING_CONNECTION_INTERFACE_NAME,
ifname,
NULL));
nm_connection_add_setting(connection,
g_object_new(NM_TYPE_SETTING_IP4_CONFIG,
NM_SETTING_IP_CONFIG_METHOD,
NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
NULL));
nm_connection_add_setting(connection,
g_object_new(NM_TYPE_SETTING_WIRED,
NM_SETTING_WIRED_MAC_ADDRESS,
parent_hwaddr,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
hwaddr,
NULL));
_nmc_mangle_connection(NULL, connection, result, config_data, NULL, NULL);
_LOGD("config device %s: creating %s connection for VLAN %d on %s...",
hwaddr,
ifname ?: connection_type,
vlan_tag,
parent_hwaddr);
active_connection = nmcs_add_and_activate(nmc, NULL, connection, &error);
if (active_connection == NULL) {
if (!nm_utils_error_is_cancelled(error)) {
_LOGD("config device %s: failure to activate connection: %s", hwaddr, error->message);
}
return TRUE;
}
if (config_data->iface_idx >= 100) {
/* since we use the iface_idx to select a table number, the range is limited from
* 0 to 99. Note that the providers are required to provide increasing numbers,
* so this means we bail out after the first 100 devices. */
_LOGD("config device %s: skip because number of supported interfaces reached", hwaddr);
return FALSE;
}
_LOGD("config device %s: connection \"%s\" (%s) created",
hwaddr,
nm_active_connection_get_id(active_connection),
nm_active_connection_get_uuid(active_connection));
return TRUE;
}
static gboolean
_config_existing(SigTermData *sigterm_data,
const NMCSProviderGetConfigIfaceData *config_data,
NMClient *nmc,
const NMCSProviderGetConfigResult *result,
const char *connection_type,
NMDevice *device)
{
const char *hwaddr = config_data->hwaddr;
gs_unref_object NMConnection *applied_connection = NULL;
guint64 applied_version_id;
gs_free_error GError *error = NULL;
gboolean changed;
gboolean skipped_single_addr;
gboolean version_id_changed;
guint try_count;
gboolean any_changes;
gboolean maybe_no_preserved_external_ip;
_LOGD("config device %s: configuring \"%s\" (%s)...",
hwaddr,
nm_device_get_iface(device) ?: "/unknown/",
nm_object_get_path(NM_OBJECT(device)));
try_count = 0;
try_count = 0;
any_changes = FALSE;
try_again:
g_clear_object(&applied_connection);
@ -639,7 +692,7 @@ try_again:
return any_changes;
}
if (_nmc_skip_connection_by_type(applied_connection, NM_SETTING_WIRED_SETTING_NAME)) {
if (_nmc_skip_connection_by_type(applied_connection, connection_type)) {
_LOGD("config device %s: device has no suitable applied connection. Skip", hwaddr);
return any_changes;
}
@ -706,7 +759,7 @@ try_again:
nm_connection_get_uuid(applied_connection),
error->message);
}
return any_changes;
return TRUE;
}
_LOGD("config device %s: connection \"%s\" (%s) reapplied",
@ -714,17 +767,135 @@ try_again:
nm_connection_get_id(applied_connection),
nm_connection_get_uuid(applied_connection));
return TRUE;
}
static gboolean
_config_type(SigTermData *sigterm_data,
const NMCSProviderGetConfigIfaceData *config_data,
NMClient *nmc,
const NMCSProviderGetConfigResult *result,
NMDeviceType device_type,
const char *connection_type,
const char *hwaddr,
const char *parent_hwaddr,
guint32 vlan_tag)
{
gs_unref_object NMDevice *device = NULL;
device = nm_g_object_ref(_nmc_get_device_by_hwaddr(nmc, device_type, hwaddr));
if (device) {
/* There is a device. Modify and reapply the currently applied connection. */
return _config_existing(sigterm_data, config_data, nmc, result, connection_type, device);
} else {
if (vlan_tag) {
/* There is no device, but we're configuring a VLAN.
* We can just go ahead and create one with a new connection. */
return _config_new_vlan(sigterm_data,
config_data,
nmc,
result,
connection_type,
hwaddr,
parent_hwaddr,
vlan_tag);
} else {
_LOGD("config device %s: skip because device not found", hwaddr);
return FALSE;
}
}
}
static gboolean
_config_one(SigTermData *sigterm_data,
NMCSProvider *provider,
NMClient *nmc,
const NMCSProviderGetConfigResult *result,
guint idx)
{
const NMCSProviderGetConfigIfaceData *config_data = result->iface_datas_arr[idx];
const char *hwaddr = config_data->hwaddr;
const char *parent_hwaddr;
guint32 vlan_tag;
gboolean any_changes;
g_main_context_iteration(NULL, FALSE);
if (g_cancellable_is_cancelled(sigterm_data->cancellable))
return FALSE;
if (!nmcs_provider_get_config_iface_data_is_valid(config_data)) {
_LOGD("config device %s: skip because meta data not successfully fetched", hwaddr);
return FALSE;
}
if (config_data->iface_idx >= 100) {
/* since we use the iface_idx to select a table number, the range is limited from
* 0 to 99. Note that the providers are required to provide increasing numbers,
* so this means we bail out after the first 100 devices. */
_LOGD("config device %s: skip because number of supported interfaces reached", hwaddr);
return FALSE;
}
if (NMCS_IS_PROVIDER_OCI(provider)) {
vlan_tag = config_data->priv.oci.vlan_tag;
parent_hwaddr = config_data->priv.oci.parent_hwaddr;
} else {
vlan_tag = 0;
parent_hwaddr = NULL;
}
if (vlan_tag != 0 && parent_hwaddr == NULL) {
_LOGW("config device %s: has vlan id %d but no parent device", hwaddr, vlan_tag);
return FALSE;
}
if (vlan_tag) {
/* MACVLAN first, because VLAN is on top of it. */
any_changes += _config_type(sigterm_data,
config_data,
nmc,
result,
NM_DEVICE_TYPE_MACVLAN,
NM_SETTING_MACVLAN_SETTING_NAME,
hwaddr,
parent_hwaddr,
vlan_tag);
any_changes = _config_type(sigterm_data,
config_data,
nmc,
result,
NM_DEVICE_TYPE_VLAN,
NM_SETTING_VLAN_SETTING_NAME,
hwaddr,
hwaddr,
vlan_tag);
} else {
any_changes = _config_type(sigterm_data,
config_data,
nmc,
result,
NM_DEVICE_TYPE_ETHERNET,
NM_SETTING_WIRED_SETTING_NAME,
hwaddr,
NULL,
0);
}
return any_changes;
}
static gboolean
_config_all(SigTermData *sigterm_data, NMClient *nmc, const NMCSProviderGetConfigResult *result)
_config_all(SigTermData *sigterm_data,
NMCSProvider *provider,
NMClient *nmc,
const NMCSProviderGetConfigResult *result)
{
gboolean any_changes = FALSE;
guint i;
for (i = 0; i < result->n_iface_datas; i++) {
if (_config_one(sigterm_data, nmc, result, i))
if (_config_one(sigterm_data, provider, nmc, result, i))
any_changes = TRUE;
}
@ -809,7 +980,7 @@ main(int argc, const char *const *argv)
if (!result)
goto done;
if (_config_all(&sigterm_data, nmc, result))
if (_config_all(&sigterm_data, provider, nmc, result))
_LOGI("some changes were applied for provider %s", nmcs_provider_get_name(provider));
else
_LOGD("no changes were applied for provider %s", nmcs_provider_get_name(provider));