diff options
| author | Michael Biebl <biebl@debian.org> | 2020-06-29 22:15:58 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-06-29 22:15:58 +0200 |
| commit | 10ae7d8cd706062742d0cdb1803d49909aef9e06 (patch) | |
| tree | cb89e8b475cec18f22b1abfe45f1d63da7e3f440 /clients | |
| parent | a54ac63bbf9b2c71026ac9028a8ffaf186cf3c82 (diff) | |
New upstream version 1.25.91 upstream/1.25.91
Diffstat (limited to 'clients')
| -rw-r--r-- | clients/cli/devices.c | 1 | ||||
| -rw-r--r-- | clients/cli/generate-docs-nm-settings-nmcli.xml | 8 | ||||
| -rw-r--r-- | clients/cloud-setup/main.c | 131 | ||||
| -rw-r--r-- | clients/cloud-setup/meson.build | 1 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup-utils.c | 3 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup.service.in | 1 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-http-client.c | 63 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-http-client.h | 2 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-ec2.c | 4 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-gcp.c | 520 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-gcp.h | 24 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider.c | 1 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider.h | 8 | ||||
| -rw-r--r-- | clients/common/settings-docs.h | 8 | ||||
| -rw-r--r-- | clients/common/settings-docs.h.in | 8 |
15 files changed, 699 insertions, 84 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index e83d3472..27f72e77 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -4192,7 +4192,6 @@ do_device_wifi_hotspot (const NMCCommand *cmd, NmCli *nmc, int argc, const char g_return_if_fail (s_wsec); if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) { - g_object_unref (connection); g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message); g_clear_error (&error); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml b/clients/cli/generate-docs-nm-settings-nmcli.xml index 860a0fd4..9a3316a3 100644 --- a/clients/cli/generate-docs-nm-settings-nmcli.xml +++ b/clients/cli/generate-docs-nm-settings-nmcli.xml @@ -754,13 +754,13 @@ </setting> <setting name="match" > <property name="interface-name" - description="A list of interface names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match." /> + description="A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element "foo" behaves the same as "|foo". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, "&\!a" is an mandatory match for literally "!a"." /> <property name="kernel-command-line" - description="A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching." /> + description="A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\' are used for optional and mandatory matches and inverting the pattern." /> <property name="driver" - description="A list of driver names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate driver name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match." /> + description="A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\' are used for optional and mandatory matches and inverting the pattern." /> <property name="path" - description="A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). Each element of the list is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate path is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match." /> + description="A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\' are used for optional and mandatory matches and inverting the pattern." /> </setting> <setting name="ovs-bridge" > <property name="fail-mode" diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c index 4e1a9a4e..78260b97 100644 --- a/clients/cloud-setup/main.c +++ b/clients/cloud-setup/main.c @@ -6,6 +6,7 @@ #include "nm-cloud-setup-utils.h" #include "nmcs-provider-ec2.h" +#include "nmcs-provider-gcp.h" #include "nm-libnm-core-intern/nm-libnm-core-utils.h" /*****************************************************************************/ @@ -84,6 +85,7 @@ _provider_detect (GCancellable *sigterm_cancellable) }; const GType gtypes[] = { NMCS_TYPE_PROVIDER_EC2, + NMCS_TYPE_PROVIDER_GCP, }; int i; gulong cancellable_signal_id; @@ -276,21 +278,21 @@ _nmc_skip_connection (NMConnection *connection) static gboolean _nmc_mangle_connection (NMDevice *device, NMConnection *connection, - gboolean is_single_nic, const NMCSProviderGetConfigIfaceData *config_data, gboolean *out_changed) { NMSettingIPConfig *s_ip; - gboolean addrs_changed; - gboolean routes_changed; - gboolean rules_changed; gsize i; in_addr_t gateway; gint64 rt_metric; guint32 rt_table; + NMIPRoute *route_entry; + gboolean addrs_changed = FALSE; + gboolean rules_changed = FALSE; + gboolean routes_changed = FALSE; gs_unref_ptrarray GPtrArray *addrs_new = NULL; gs_unref_ptrarray GPtrArray *rules_new = NULL; - nm_auto_unref_ip_route NMIPRoute *route_new = NULL; + gs_unref_ptrarray GPtrArray *routes_new = NULL; if (!nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_WIRED_SETTING_NAME)) return FALSE; @@ -299,62 +301,80 @@ _nmc_mangle_connection (NMDevice *device, if (!s_ip) return FALSE; - addrs_new = g_ptr_array_new_full (config_data->ipv4s_len, (GDestroyNotify) nm_ip_address_unref); - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPAddress *entry; + addrs_new = g_ptr_array_new_full (config_data->ipv4s_len, + (GDestroyNotify) nm_ip_address_unref); + rules_new = g_ptr_array_new_full (config_data->ipv4s_len, + (GDestroyNotify) nm_ip_routing_rule_unref); + routes_new = g_ptr_array_new_full (config_data->iproutes_len + !!config_data->ipv4s_len, + (GDestroyNotify) nm_ip_route_unref); + + if ( config_data->has_ipv4s + && config_data->has_cidr) { + for (i = 0; i < config_data->ipv4s_len; i++) { + NMIPAddress *entry; + + entry = nm_ip_address_new_binary (AF_INET, + &config_data->ipv4s_arr[i], + config_data->cidr_prefix, + NULL); + if (entry) + g_ptr_array_add (addrs_new, entry); + } - entry = nm_ip_address_new_binary (AF_INET, - &config_data->ipv4s_arr[i], - config_data->cidr_prefix, - NULL); - if (entry) - g_ptr_array_add (addrs_new, entry); + gateway = nm_utils_ip4_address_clear_host_address (config_data->cidr_addr, config_data->cidr_prefix); + ((guint8 *) &gateway)[3] += 1; + + rt_metric = 10; + rt_table = 30400 + config_data->iface_idx; + + route_entry = nm_ip_route_new_binary (AF_INET, + &nm_ip_addr_zero, + 0, + &gateway, + rt_metric, + NULL); + nm_ip_route_set_attribute (route_entry, + NM_IP_ROUTE_ATTRIBUTE_TABLE, + g_variant_new_uint32 (rt_table)); + g_ptr_array_add (routes_new, route_entry); + + for (i = 0; i < config_data->ipv4s_len; i++) { + NMIPRoutingRule *entry; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + + entry = nm_ip_routing_rule_new (AF_INET); + nm_ip_routing_rule_set_priority (entry, rt_table); + nm_ip_routing_rule_set_from (entry, + _nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf), + 32); + nm_ip_routing_rule_set_table (entry, rt_table); + + nm_assert (nm_ip_routing_rule_validate (entry, NULL)); + + g_ptr_array_add (rules_new, entry); + } } - gateway = nm_utils_ip4_address_clear_host_address (config_data->cidr_addr, config_data->cidr_prefix); - ((guint8 *) &gateway)[3] += 1; - - rt_metric = 10; - rt_table = 30400 + config_data->iface_idx; - - route_new = nm_ip_route_new_binary (AF_INET, - &nm_ip_addr_zero, - 0, - &gateway, - rt_metric, - NULL); - nm_ip_route_set_attribute (route_new, - NM_IP_ROUTE_ATTRIBUTE_TABLE, - g_variant_new_uint32 (rt_table)); - - rules_new = g_ptr_array_new_full (config_data->ipv4s_len, (GDestroyNotify) nm_ip_routing_rule_unref); - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPRoutingRule *entry; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - entry = nm_ip_routing_rule_new (AF_INET); - nm_ip_routing_rule_set_priority (entry, rt_table); - nm_ip_routing_rule_set_from (entry, - _nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf), - 32); - nm_ip_routing_rule_set_table (entry, rt_table); - - nm_assert (nm_ip_routing_rule_validate (entry, NULL)); - - g_ptr_array_add (rules_new, entry); - } + for (i = 0; i < config_data->iproutes_len; ++i) + g_ptr_array_add (routes_new, config_data->iproutes_arr[i]); - addrs_changed = nmcs_setting_ip_replace_ipv4_addresses (s_ip, - (NMIPAddress **) addrs_new->pdata, - addrs_new->len); + if (addrs_new->len) { + addrs_changed = nmcs_setting_ip_replace_ipv4_addresses (s_ip, + (NMIPAddress **) addrs_new->pdata, + addrs_new->len); + } - routes_changed = nmcs_setting_ip_replace_ipv4_routes (s_ip, - &route_new, - 1); + if (routes_new->len) { + routes_changed = nmcs_setting_ip_replace_ipv4_routes (s_ip, + (NMIPRoute **) routes_new->pdata, + routes_new->len); + } - rules_changed = nmcs_setting_ip_replace_ipv4_rules (s_ip, - (NMIPRoutingRule **) rules_new->pdata, - rules_new->len); + if (rules_new->len) { + rules_changed = nmcs_setting_ip_replace_ipv4_rules (s_ip, + (NMIPRoutingRule **) rules_new->pdata, + rules_new->len); + } NM_SET_OUT (out_changed, addrs_changed || routes_changed @@ -438,7 +458,6 @@ try_again: if (!_nmc_mangle_connection (device, applied_connection, - is_single_nic, config_data, &changed)) { _LOGD ("config device %s: device has no suitable applied connection. Skip", hwaddr); diff --git a/clients/cloud-setup/meson.build b/clients/cloud-setup/meson.build index d8f96539..805d4681 100644 --- a/clients/cloud-setup/meson.build +++ b/clients/cloud-setup/meson.build @@ -28,6 +28,7 @@ sources = files( 'nm-cloud-setup-utils.c', 'nm-http-client.c', 'nmcs-provider-ec2.c', + 'nmcs-provider-gcp.c', 'nmcs-provider.c', ) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index 13c9566a..a32003cb 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -345,7 +345,8 @@ _poll_timeout_cb (gpointer user_data) { PollTaskData *poll_task_data = user_data; - _poll_return (poll_task_data, FALSE, NULL); + _poll_return (poll_task_data, FALSE, nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "timeout expired")); return G_SOURCE_CONTINUE; } diff --git a/clients/cloud-setup/nm-cloud-setup.service.in b/clients/cloud-setup/nm-cloud-setup.service.in index 69a1a29c..9866acd8 100644 --- a/clients/cloud-setup/nm-cloud-setup.service.in +++ b/clients/cloud-setup/nm-cloud-setup.service.in @@ -12,6 +12,7 @@ ExecStart=@libexecdir@/nm-cloud-setup # Opt-in by setting the right environment variable for # the provider. #Environment=NM_CLOUD_SETUP_EC2=yes +#Environment=NM_CLOUD_SETUP_GCP=yes CapabilityBoundingSet= LockPersonality=yes diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 94f3fe2b..946ed8ce 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -16,7 +16,7 @@ typedef struct { GMainContext *context; CURLM *mhandle; GSource *mhandle_source_timeout; - GSource *mhandle_source_socket; + GHashTable *source_sockets_hashtable; } NMHttpClientPrivate; struct _NMHttpClient { @@ -119,6 +119,7 @@ typedef struct { CURL *ehandle; char *url; GString *recv_data; + struct curl_slist *headers; gssize max_data; gulong cancellable_id; } EHandleData; @@ -145,6 +146,8 @@ _ehandle_free (EHandleData *edata) if (edata->recv_data) g_string_free (edata->recv_data, TRUE); + if (edata->headers) + curl_slist_free_all (edata->headers); g_free (edata->url); nm_g_slice_free (edata); } @@ -159,8 +162,8 @@ _ehandle_complete (EHandleData *edata, nm_clear_pointer (&edata->timeout_source, nm_g_source_destroy_and_unref); - nm_clear_g_cancellable_disconnect (g_task_get_cancellable (edata->task), - &edata->cancellable_id); + nm_clear_g_cancellable_disconnect (g_task_get_cancellable (edata->task), + &edata->cancellable_id); if (error_take) { if (nm_utils_error_is_cancelled (error_take)) @@ -260,12 +263,14 @@ nm_http_client_get (NMHttpClient *self, const char *url, int timeout_msec, gssize max_data, + const char *const *http_headers, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { NMHttpClientPrivate *priv; EHandleData *edata; + guint i; g_return_if_fail (NM_IS_HTTP_CLIENT (self)); g_return_if_fail (url); @@ -281,6 +286,7 @@ nm_http_client_get (NMHttpClient *self, .recv_data = g_string_sized_new (NM_MIN (max_data, 245)), .max_data = max_data, .url = g_strdup (url), + .headers = NULL, }; nmcs_wait_for_objects_register (edata->task); @@ -302,6 +308,23 @@ nm_http_client_get (NMHttpClient *self, curl_easy_setopt (edata->ehandle, CURLOPT_WRITEDATA, edata); curl_easy_setopt (edata->ehandle, CURLOPT_PRIVATE, edata); + if (http_headers) { + for (i = 0; http_headers[i]; ++i) { + struct curl_slist *tmp; + + tmp = curl_slist_append (edata->headers, + http_headers[i]); + if (!tmp) { + curl_slist_free_all (tmp); + _LOGE ("curl: curl_slist_append() failed adding %s", http_headers[i]); + continue; + } + edata->headers = tmp; + } + + curl_easy_setopt (edata->ehandle, CURLOPT_HTTPHEADER, edata->headers); + } + if (timeout_msec > 0) { edata->timeout_source = _source_attach (self, nm_g_timeout_source_new (timeout_msec, @@ -362,6 +385,7 @@ nm_http_client_get_finish (NMHttpClient *self, typedef struct { GTask *task; char *uri; + const char *const *http_headers; NMHttpClientPollGetCheckFcn check_fcn; gpointer check_user_data; GBytes *response_data; @@ -378,6 +402,7 @@ _poll_get_data_free (gpointer data) g_free (poll_get_data->uri); nm_clear_pointer (&poll_get_data->response_data, g_bytes_unref); + g_strfreev ((char **) poll_get_data->http_headers); nm_g_slice_free (poll_get_data); } @@ -397,6 +422,7 @@ _poll_get_probe_start_fcn (GCancellable *cancellable, poll_get_data->uri, poll_get_data->request_timeout_ms, poll_get_data->request_max_data, + poll_get_data->http_headers, cancellable, callback, user_data); @@ -476,6 +502,7 @@ nm_http_client_poll_get (NMHttpClient *self, gssize request_max_data, int poll_timeout_ms, int ratelimit_timeout_ms, + const char *const *http_headers, GCancellable *cancellable, NMHttpClientPollGetCheckFcn check_fcn, gpointer check_user_data, @@ -502,6 +529,7 @@ nm_http_client_poll_get (NMHttpClient *self, .check_fcn = check_fcn, .check_user_data = check_user_data, .response_code = -1, + .http_headers = NM_CAST_STRV_CC (g_strdupv ((char **) http_headers)), }; nmcs_wait_for_objects_register (poll_get_data->task); @@ -615,12 +643,13 @@ _mhandle_socket_cb (int fd, static int _mhandle_socketfunction_cb (CURL *e_handle, curl_socket_t fd, int what, void *user_data, void *socketp) { + GSource *source_socket; NMHttpClient *self = user_data; NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); (void) _NM_ENSURE_TYPE (int, fd); - nm_clear_g_source_inst (&priv->mhandle_source_socket); + g_hash_table_remove (priv->source_sockets_hashtable, GINT_TO_POINTER (fd)); if (what != CURL_POLL_REMOVE) { GIOCondition condition = 0; @@ -635,13 +664,17 @@ _mhandle_socketfunction_cb (CURL *e_handle, curl_socket_t fd, int what, void *us condition = 0; if (condition) { - priv->mhandle_source_socket = nm_g_unix_fd_source_new (fd, - condition, - G_PRIORITY_DEFAULT, - _mhandle_socket_cb, - self, + source_socket = nm_g_unix_fd_source_new (fd, + condition, + G_PRIORITY_DEFAULT, + _mhandle_socket_cb, + self, NULL); - g_source_attach (priv->mhandle_source_socket, priv->context); + g_source_attach (source_socket, priv->context); + + g_hash_table_insert (priv->source_sockets_hashtable, + GINT_TO_POINTER (fd), + source_socket); } } @@ -652,7 +685,7 @@ static gboolean _mhandle_timeout_cb (gpointer user_data) { _mhandle_action (user_data, CURL_SOCKET_TIMEOUT, 0); - return G_SOURCE_CONTINUE; + return G_SOURCE_REMOVE; } static int @@ -678,6 +711,12 @@ _mhandle_timerfunction_cb (CURLM *multi, long timeout_msec, void *user_data) static void nm_http_client_init (NMHttpClient *self) { + NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); + + priv->source_sockets_hashtable = g_hash_table_new_full (nm_direct_hash, + NULL, + NULL, + (GDestroyNotify) nm_g_source_destroy_and_unref); } static void @@ -714,9 +753,9 @@ dispose (GObject *object) NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); nm_clear_pointer (&priv->mhandle, curl_multi_cleanup); + nm_clear_pointer (&priv->source_sockets_hashtable, g_hash_table_unref); nm_clear_g_source_inst (&priv->mhandle_source_timeout); - nm_clear_g_source_inst (&priv->mhandle_source_socket); G_OBJECT_CLASS (nm_http_client_parent_class)->dispose (object); } diff --git a/clients/cloud-setup/nm-http-client.h b/clients/cloud-setup/nm-http-client.h index 86ee938e..ef7c984a 100644 --- a/clients/cloud-setup/nm-http-client.h +++ b/clients/cloud-setup/nm-http-client.h @@ -29,6 +29,7 @@ void nm_http_client_get (NMHttpClient *self, const char *uri, int timeout_msec, gssize max_data, + const char *const *http_headers, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -50,6 +51,7 @@ void nm_http_client_poll_get (NMHttpClient *self, gssize request_max_data, int poll_timeout_ms, int ratelimit_timeout_ms, + const char *const *http_headers, GCancellable *cancellable, NMHttpClientPollGetCheckFcn check_fcn, gpointer check_user_data, diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index 82ed0949..c8db31f9 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -138,6 +138,7 @@ detect (NMCSProvider *provider, 256*1024, 7000, 1000, + NULL, g_task_get_cancellable (task), _detect_get_meta_data_check_cb, NULL, @@ -396,6 +397,7 @@ _get_config_metadata_ready_cb (GObject *source, 512*1024, 10000, 1000, + NULL, iface_data->cancellable, NULL, NULL, @@ -413,6 +415,7 @@ _get_config_metadata_ready_cb (GObject *source, 512*1024, 10000, 1000, + NULL, iface_data->cancellable, NULL, NULL, @@ -529,6 +532,7 @@ get_config (NMCSProvider *provider, 256 * 1024, 15000, 1000, + NULL, g_task_get_cancellable (get_config_data->task), _get_config_metadata_ready_check, metadata_data, diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c new file mode 100644 index 00000000..ba4016dd --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nmcs-provider-gcp.h" + +#include "nm-cloud-setup-utils.h" + +/*****************************************************************************/ + +#define HTTP_TIMEOUT_MS 3000 +#define HTTP_REQ_MAX_DATA 512*1024 +#define HTTP_POLL_TIMEOUT_MS 10000 +#define HTTP_RATE_LIMIT_MS 1000 + +#define NM_GCP_HOST "metadata.google.internal" +#define NM_GCP_BASE "http://" NM_GCP_HOST +#define NM_GCP_API_VERSION "/v1" +#define NM_GCP_METADATA_URL_BASE NM_GCP_BASE "/computeMetadata" NM_GCP_API_VERSION "/instance" +#define NM_GCP_METADATA_URL_NET "/network-interfaces/" + +#define NM_GCP_METADATA_HEADER "Metadata-Flavor: Google" + +#define _gcp_uri_concat(...) nmcs_utils_uri_build_concat (NM_GCP_METADATA_URL_BASE, __VA_ARGS__) +#define _gcp_uri_interfaces(...) _gcp_uri_concat (NM_GCP_METADATA_URL_NET, ##__VA_ARGS__) + +/*****************************************************************************/ + +struct _NMCSProviderGCP { + NMCSProvider parent; +}; + +struct _NMCSProviderGCPClass { + NMCSProviderClass parent; +}; + +G_DEFINE_TYPE (NMCSProviderGCP, nmcs_provider_gcp, NMCS_TYPE_PROVIDER); + +/*****************************************************************************/ + +static void +_detect_get_meta_data_done_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + gboolean success; + + success = nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + NULL, + &get_error); + + if (nm_utils_error_is_cancelled (get_error)) { + g_task_return_error (task, g_steal_pointer (&get_error)); + return; + } + + if (get_error) { + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "failure to get GCP metadata: %s", + get_error->message); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + if (!success) { + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "failure to detect GCP metadata"); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_boolean (task, TRUE); +} + +static void +detect (NMCSProvider *provider, + GTask *task) +{ + NMHttpClient *http_client; + gs_free char *uri = NULL; + + http_client = nmcs_provider_get_http_client (provider); + + nm_http_client_poll_get (http_client, + (uri = _gcp_uri_concat ("id")), + HTTP_TIMEOUT_MS, + 256*1024, + 7000, + 1000, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (task), + NULL, + NULL, + _detect_get_meta_data_done_cb, + task); +} + +/*****************************************************************************/ + +typedef struct { + NMCSProviderGetConfigTaskData *config_data; + guint n_ifaces_pending; + GError *error; + bool success:1; +} GCPData; + +typedef struct { + NMCSProviderGetConfigIfaceData *iface_get_config; + GCPData *gcp_data; + gssize iface_idx; + guint n_fips_pending; +} GCPIfaceData; + +static void +_get_config_maybe_task_return (GCPData *gcp_data, + GError *error_take) +{ + NMCSProviderGetConfigTaskData *config_data = gcp_data->config_data; + gs_free_error GError *gcp_error = NULL; + + if (error_take) { + nm_clear_error (&gcp_data->error); + gcp_data->error = error_take; + } + + if (gcp_data->n_ifaces_pending) + return; + + gcp_error = gcp_data->error; + + if (!gcp_data->success) { + nm_assert (gcp_error); + + if (nm_utils_error_is_cancelled (gcp_error)) + _LOGD ("get-config: cancelled"); + else + _LOGD ("get-config: failed: %s", gcp_error->message); + g_task_return_error (config_data->task, g_steal_pointer (&gcp_error)); + } else { + _LOGD ("get-config: success"); + g_task_return_pointer (config_data->task, + g_hash_table_ref (config_data->result_dict), + (GDestroyNotify) g_hash_table_unref); + } + + nm_g_slice_free (gcp_data); + g_object_unref (config_data->task); +} + +static void +_get_config_fip_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMCSProviderGetConfigIfaceData *iface_get_config; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + const char *fip_str = NULL; + NMIPRoute **routes_arr; + NMIPRoute *route_new; + GCPData *gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto iface_done; + + fip_str = g_bytes_get_data (response, NULL); + if (!nm_utils_ipaddr_valid (AF_INET, fip_str)) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "forwarded-ip is not a valid ip address"); + goto iface_done; + } + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: adding forwarded-ip %s", + iface_data->iface_idx, + fip_str); + + iface_get_config = iface_data->iface_get_config; + iface_get_config->iface_idx = iface_data->iface_idx; + routes_arr = iface_get_config->iproutes_arr; + + route_new = nm_ip_route_new (AF_INET, + fip_str, + 32, + NULL, + 100, + &error); + if (error) + goto iface_done; + + nm_ip_route_set_attribute (route_new, + NM_IP_ROUTE_ATTRIBUTE_TYPE, + g_variant_new_string ("local")); + routes_arr[iface_get_config->iproutes_len] = route_new; + ++iface_get_config->iproutes_len; + gcp_data->success = TRUE; + +iface_done: + --iface_data->n_fips_pending; + if (iface_data->n_fips_pending == 0) { + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + } +} + +static void +_get_config_ips_list_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_ptrarray GPtrArray *uri_arr = NULL; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + const char *response_str = NULL; + gsize response_len; + GCPData *gcp_data; + const char *line; + gsize line_len; + guint i; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto fips_error; + + + uri_arr = g_ptr_array_new_with_free_func (g_free); + response_str = g_bytes_get_data (response, &response_len); + + while (nm_utils_parse_next_line (&response_str, + &response_len, + &line, + &line_len)) { + nm_auto_free_gstring GString *gstr = NULL; + gint64 fip_index; + + gstr = g_string_new_len (line, line_len); + fip_index = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXINT64, -1); + + if (fip_index < 0) { + continue; + } + + g_string_printf (gstr, + "%"G_GSSIZE_FORMAT"/forwarded-ips/%"G_GINT64_FORMAT, + iface_data->iface_idx, + fip_index); + g_ptr_array_add (uri_arr, g_string_free (g_steal_pointer (&gstr), FALSE)); + } + + iface_data->n_fips_pending = uri_arr->len; + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found %u forwarded ips", + iface_data->iface_idx, + iface_data->n_fips_pending); + + if (iface_data->n_fips_pending == 0) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "found no forwarded ip"); + goto fips_error; + } + + iface_data->iface_get_config->iproutes_arr = + g_new (NMIPRoute *, iface_data->n_fips_pending); + + for (i = 0; i < uri_arr->len; ++i) { + const char *str = uri_arr->pdata[i]; + gs_free const char *uri = NULL; + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_fip_cb, + iface_data); + } + return; + +fips_error: + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); +} + +static void +_get_config_iface_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + gs_free const char *hwaddr = NULL; + gs_free const char *uri = NULL; + gs_free char *str = NULL; + GCPData *gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto iface_error; + + hwaddr = nmcs_utils_hwaddr_normalize (g_bytes_get_data (response, NULL), -1); + iface_data->iface_get_config = g_hash_table_lookup (gcp_data->config_data->result_dict, + hwaddr); + if (!iface_data->iface_get_config) { + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: did not find a matching device", + iface_data->iface_idx); + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "no matching hwaddr found for GCP interface"); + goto iface_error; + } + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found a matching device with hwaddr %s", + iface_data->iface_idx, + hwaddr); + + str = g_strdup_printf ("%"G_GSSIZE_FORMAT"/forwarded-ips/", + iface_data->iface_idx); + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_ips_list_cb, + iface_data); + return; + +iface_error: + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); +} + +static void +_get_net_ifaces_list_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; + nm_auto_free_gstring GString *gstr = NULL; + gs_unref_bytes GBytes *response = NULL; + gs_free_error GError *error = NULL; + GCPData *gcp_data = user_data; + const char *response_str; + const char *token_start; + const char *token_end; + gsize response_len; + const char *line; + gsize line_len; + guint i; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) { + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + return; + } + + response_str = g_bytes_get_data (response, &response_len); + ifaces_arr = g_ptr_array_new (); + gstr = g_string_new (NULL); + + while (nm_utils_parse_next_line (&response_str, + &response_len, + &line, + &line_len)) { + GCPIfaceData *iface_data; + gssize iface_idx; + + token_start = line; + token_end = memchr (token_start, '/', line_len); + + if (!token_end) + continue; + + g_string_truncate (gstr, 0); + g_string_append_len (gstr, token_start, token_end - token_start); + iface_idx = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXSSIZE, -1); + + if (iface_idx < 0) + continue; + + iface_data = g_slice_new (GCPIfaceData); + *iface_data = (GCPIfaceData) { + .iface_get_config = NULL, + .gcp_data = gcp_data, + .iface_idx = iface_idx, + .n_fips_pending = 0, + }; + g_ptr_array_add (ifaces_arr, iface_data); + } + + gcp_data->n_ifaces_pending = ifaces_arr->len; + _LOGI ("found GCP interfaces: %u", ifaces_arr->len); + + for (i = 0; i < ifaces_arr->len; ++i) { + GCPIfaceData *data = ifaces_arr->pdata[i]; + gs_free const char *uri = NULL; + + _LOGD ("GCP interface[%"G_GSSIZE_FORMAT"]: retrieving configuration", + data->iface_idx); + + g_string_printf (gstr, "%"G_GSSIZE_FORMAT"/mac", data->iface_idx); + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (gstr->str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_iface_cb, + data); + + } + + if (ifaces_arr->len == 0) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "no GCP interfaces found"); + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + } +} + + +static void +get_config (NMCSProvider *provider, + NMCSProviderGetConfigTaskData *get_config_data) +{ + gs_free const char *uri = NULL; + GCPData *gcp_data; + + gcp_data = g_slice_new (GCPData); + *gcp_data = (GCPData) { + .config_data = get_config_data, + .n_ifaces_pending = 0, + .error = NULL, + .success = FALSE, + + }; + + nm_http_client_poll_get (nmcs_provider_get_http_client (provider), + (uri = _gcp_uri_interfaces ()), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_net_ifaces_list_cb, + gcp_data); +} + +/*****************************************************************************/ + +static void +nmcs_provider_gcp_init (NMCSProviderGCP *self) +{ +} + +static void +nmcs_provider_gcp_class_init (NMCSProviderGCPClass *klass) +{ + NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS (klass); + + provider_class->_name = "GCP"; + provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE ("NM_CLOUD_SETUP_GCP"); + provider_class->detect = detect; + provider_class->get_config = get_config; +} diff --git a/clients/cloud-setup/nmcs-provider-gcp.h b/clients/cloud-setup/nmcs-provider-gcp.h new file mode 100644 index 00000000..b0d3ec7d --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-gcp.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NMCS_PROVIDER_GCP_H__ +#define __NMCS_PROVIDER_GCP_H__ + +#include "nmcs-provider.h" + +/*****************************************************************************/ + +typedef struct _NMCSProviderGCP NMCSProviderGCP; +typedef struct _NMCSProviderGCPClass NMCSProviderGCPClass; + +#define NMCS_TYPE_PROVIDER_GCP (nmcs_provider_gcp_get_type ()) +#define NMCS_PROVIDER_GCP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCP)) +#define NMCS_PROVIDER_GCP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) +#define NMCS_IS_PROVIDER_GCP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMCS_TYPE_PROVIDER_GCP)) +#define NMCS_IS_PROVIDER_GCP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMCS_TYPE_PROVIDER_GCP)) +#define NMCS_PROVIDER_GCP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) + +GType nmcs_provider_gcp_get_type (void); + +/*****************************************************************************/ + +#endif /* __NMCS_PROVIDER_GCP_H__ */ diff --git a/clients/cloud-setup/nmcs-provider.c b/clients/cloud-setup/nmcs-provider.c index 1f1b6e60..bc21d876 100644 --- a/clients/cloud-setup/nmcs-provider.c +++ b/clients/cloud-setup/nmcs-provider.c @@ -114,6 +114,7 @@ _iface_data_free (gpointer data) NMCSProviderGetConfigIfaceData *iface_data = data; g_free (iface_data->ipv4s_arr); + g_free (iface_data->iproutes_arr); nm_g_slice_free (iface_data); } diff --git a/clients/cloud-setup/nmcs-provider.h b/clients/cloud-setup/nmcs-provider.h index e5a44da1..e5950f93 100644 --- a/clients/cloud-setup/nmcs-provider.h +++ b/clients/cloud-setup/nmcs-provider.h @@ -18,6 +18,9 @@ typedef struct { bool has_ipv4s:1; bool has_cidr:1; + NMIPRoute **iproutes_arr; + gsize iproutes_len; + /* TRUE, if the configuration was requested via hwaddrs argument to * nmcs_provider_get_config(). */ bool was_requested:1; @@ -29,8 +32,9 @@ nmcs_provider_get_config_iface_data_is_valid (const NMCSProviderGetConfigIfaceDa { return config_data && config_data->iface_idx >= 0 - && config_data->has_cidr - && config_data->has_ipv4s; + && ( ( config_data->has_ipv4s + && config_data->has_cidr) + || config_data->iproutes_len); } NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new (gboolean was_requested); diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.h index d9bb7575..7b891500 100644 --- a/clients/common/settings-docs.h +++ b/clients/common/settings-docs.h @@ -280,10 +280,10 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate driver name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate path is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") +#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index d9bb7575..7b891500 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -280,10 +280,10 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate driver name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate path is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") +#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") |