From 4c2db6a3fd18f3c91709925a5038d74a404a8a1f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 9 Jan 2023 20:57:52 +0100 Subject: glib-aux,libnm: add nm_ascii_is_regular_char() to validate keys for "ovs-external-ids" The same will also be used by "ovs-other-config". Also, there should be a general concept, meaning, we should have a function whether a character is from some benign set, and not whether we have a character usable for keys of "ovs-external-ids". --- src/libnm-core-impl/nm-setting-ovs-external-ids.c | 11 +--------- src/libnm-glib-aux/nm-macros-internal.h | 26 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c index f4e31f81ce..44bb1d3e65 100644 --- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c +++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c @@ -53,15 +53,6 @@ G_DEFINE_TYPE(NMSettingOvsExternalIDs, nm_setting_ovs_external_ids, NM_TYPE_SETT /*****************************************************************************/ -static gboolean -_exid_key_char_is_regular(char ch) -{ - /* allow words of printable characters, plus some - * special characters, for example to support base64 encoding. */ - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') - || NM_IN_SET(ch, '-', '_', '+', '/', '=', '.'); -} - /** * nm_setting_ovs_external_ids_check_key: * @key: (allow-none): the key to check @@ -105,7 +96,7 @@ nm_setting_ovs_external_ids_check_key(const char *key, GError **error) _("key must be UTF8")); return FALSE; } - if (!NM_STRCHAR_ALL(key, ch, _exid_key_char_is_regular(ch))) { + if (!NM_STRCHAR_ALL(key, ch, nm_ascii_is_regular_char(ch))) { /* Probably OVS is more forgiving about what makes a valid key for * an external-id. However, we are strict (at least, for now). */ g_set_error_literal(error, diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h index 974355b263..71a17e3e37 100644 --- a/src/libnm-glib-aux/nm-macros-internal.h +++ b/src/libnm-glib-aux/nm-macros-internal.h @@ -1101,6 +1101,32 @@ nm_ascii_is_newline(char ch) return NM_IN_SET(ch, '\n', '\t'); } +static inline gboolean +nm_ascii_is_regular_char(char ch) +{ + /* Checks whether "ch" is "regular", which basically + * means it's either a digit, a alpha, or some special + * characters that are suitable for base64 encoding. + * + * The meaning of what "regular" means is not well defined, + * but it's used to validate the keys for "ovs.external-ids" + * dictionary. */ + switch (ch) { + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + case '-': + case '_': + case '+': + case '/': + case '=': + case '.': + return TRUE; + default: + return FALSE; + } +} + #define nm_str_skip_leading_spaces(str) \ ({ \ typeof(*(str)) *_str_sls = (str); \ -- cgit v1.2.1 From 96d01a5f8ba12f53f7c00666138ec21a10bfcdc4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 9 Jan 2023 22:33:28 +0100 Subject: libnm: make NMSettingOvsExternalIDs.verify() deterministic Iterating over a hash table is not deterministic. When we have two invalid keys in ovs-external-ids, we should deterministically get the same error message. Instead, iterate over the (sorted) keys. This does have an overhead, because we need to fetch the keys, and we need to lookup each value by key. Still, correctness and determinism is more important. --- src/libnm-core-impl/nm-setting-ovs-external-ids.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c index 44bb1d3e65..70b7c662aa 100644 --- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c +++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c @@ -293,12 +293,16 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (priv->data) { gs_free_error GError *local = NULL; - GHashTableIter iter; - const char *key; - const char *val; + const char *const *keys; + guint len; + guint i; + + keys = nm_setting_ovs_external_ids_get_data_keys(self, &len); + + for (i = 0; i < len; i++) { + const char *key = keys[i]; + const char *val = g_hash_table_lookup(priv->data, key); - g_hash_table_iter_init(&iter, priv->data); - while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { if (!nm_setting_ovs_external_ids_check_key(key, &local)) { g_set_error(error, NM_CONNECTION_ERROR, -- cgit v1.2.1 From 064fd6e6b05770246c4ccc132ff59791a016e8e7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 9 Jan 2023 22:41:54 +0100 Subject: libnm: fix message in GError in NMSettingOvsExternalIDs.verify() and documentation --- src/libnm-core-impl/nm-setting-ovs-external-ids.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c index 70b7c662aa..11c915a59d 100644 --- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c +++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c @@ -331,7 +331,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("maximum number of user data entries reached (%u instead of %u)"), + _("maximum number of entries reached (%u instead of %u)"), g_hash_table_size(priv->data), (unsigned) MAX_NUM_KEYS); g_prefix_error(error, @@ -514,7 +514,7 @@ nm_setting_ovs_external_ids_class_init(NMSettingOvsExternalIDsClass *klass) /** * NMSettingOvsExternalIDs:data: (type GHashTable(utf8,utf8)) * - * A dictionary of key/value pairs with exernal-ids for OVS. + * A dictionary of key/value pairs with external-ids for OVS. * * Since: 1.30 **/ -- cgit v1.2.1 From f79ecbd34aef33dbc470376e808395e9463ef55b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 11:41:21 +0100 Subject: libnm: move verify() for OVS connection type to separate function Will be used next. --- src/libnm-core-impl/nm-setting-ovs-external-ids.c | 90 +++++++++++++---------- src/libnm-core-impl/nm-utils-private.h | 3 + 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c index 11c915a59d..d0f9104165 100644 --- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c +++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c @@ -118,6 +118,56 @@ nm_setting_ovs_external_ids_check_key(const char *key, GError **error) return TRUE; } +gboolean +_nm_setting_ovs_verify_connection_type(GType gtype, NMConnection *connection, GError **error) +{ + NMSettingConnection *s_con; + const char *type; + const char *slave_type; + + nm_assert(!connection || NM_IS_CONNECTION(connection)); + nm_assert(NM_IN_SET(gtype, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + nm_assert(!error || !*error); + + if (!connection) { + /* We don't know. It's valid. */ + return TRUE; + } + + type = nm_connection_get_connection_type(connection); + if (!type) { + NMSetting *s_base; + + s_base = _nm_connection_find_base_type_setting(connection); + if (s_base) + type = nm_setting_get_name(s_base); + } + if (NM_IN_STRSET(type, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME)) + return TRUE; + + if ((s_con = nm_connection_get_setting_connection(connection)) + && _nm_connection_detect_slave_type_full(s_con, + connection, + &slave_type, + NULL, + NULL, + NULL, + NULL) + && nm_streq0(slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) + return TRUE; + + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("OVS %s can only be added to a profile of type OVS " + "bridge/port/interface or to OVS system interface"), + gtype == NM_TYPE_SETTING_OVS_EXTERNAL_IDS ? "external-ids" : "other-config"); + return FALSE; +} + /** * nm_setting_ovs_external_ids_check_val: * @val: (allow-none): the value to check @@ -341,44 +391,10 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - if (connection) { - NMSettingConnection *s_con; - const char *type; - const char *slave_type; - - type = nm_connection_get_connection_type(connection); - if (!type) { - NMSetting *s_base; - - s_base = _nm_connection_find_base_type_setting(connection); - if (s_base) - type = nm_setting_get_name(s_base); - } - if (NM_IN_STRSET(type, - NM_SETTING_OVS_BRIDGE_SETTING_NAME, - NM_SETTING_OVS_PORT_SETTING_NAME, - NM_SETTING_OVS_INTERFACE_SETTING_NAME)) - goto connection_type_is_good; - - if ((s_con = nm_connection_get_setting_connection(connection)) - && _nm_connection_detect_slave_type_full(s_con, - connection, - &slave_type, - NULL, - NULL, - NULL, - NULL) - && nm_streq0(slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) - goto connection_type_is_good; - - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("OVS external IDs can only be added to a profile of type OVS " - "bridge/port/interface or to OVS system interface")); + if (!_nm_setting_ovs_verify_connection_type(NM_TYPE_SETTING_OVS_EXTERNAL_IDS, + connection, + error)) return FALSE; - } -connection_type_is_good: return TRUE; } diff --git a/src/libnm-core-impl/nm-utils-private.h b/src/libnm-core-impl/nm-utils-private.h index a89a466983..e2e1aff789 100644 --- a/src/libnm-core-impl/nm-utils-private.h +++ b/src/libnm-core-impl/nm-utils-private.h @@ -70,4 +70,7 @@ const char *const *nmtst_system_encodings_for_lang(const char *lang); const char *const *nmtst_system_encodings_get_default(void); const char *const *nmtst_system_encodings_get(void); +gboolean +_nm_setting_ovs_verify_connection_type(GType gtype, NMConnection *connection, GError **error); + #endif -- cgit v1.2.1 From 17e16c8fa6b196712fa5b86183f143b489acd0e6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 16:16:38 +0100 Subject: ovs: fix _external_ids_to_string() to print strdict in logging Fixes: a4b13d50694e ('core/ovs: log external-ids of Interfaces/Ports/Bridges') --- src/core/devices/ovs/nm-ovsdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 8da232ab0f..f835a79f15 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -1592,9 +1592,9 @@ _external_ids_to_string(const GArray *arr) if (i > 0) nm_str_buf_append_c(&strbuf, ','); - nm_str_buf_append_printf(&strbuf, " \"%s\" = \"%s\"]", n->name, n->value_str); + nm_str_buf_append_printf(&strbuf, " \"%s\" = \"%s\" ", n->name, n->value_str); } - nm_str_buf_append(&strbuf, " ]"); + nm_str_buf_append(&strbuf, "]"); return nm_str_buf_finalize(&strbuf, NULL); } -- cgit v1.2.1 From 2641af2cc94bdfd1c4d20c886b195b070ab6e1c0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 19:51:18 +0100 Subject: ovs: don't replace all "other_config" in _set_bridge_mac() Doing an "update" is wrong, because that will replace all "other_config" entries. We only want to reset the "hwaddr". Note that https://www.rfc-editor.org/rfc/rfc7047 says about "": If is "insert", then each of the key-value pairs in the map in is added to only if its key is not already present. The required type of is slightly relaxed, in that it may have fewer than the minimum number of elements specified by the column's type. That means, we need to first delete, and then insert the key. Fixes: 5d4c8521a38c ('ovs: set MAC address on the bridge for local interfaces') --- src/core/devices/ovs/nm-ovsdb.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index f835a79f15..a8f284a3c7 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -592,21 +592,30 @@ _set_bridge_ports(json_t *params, const char *ifname, json_t *new_ports) static void _set_bridge_mac(json_t *params, const char *ifname, const char *mac) { - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Bridge", - "row", - "other_config", - "map", - "hwaddr", - mac, - "where", - "name", - "==", - ifname)); + json_array_append_new( + params, + json_pack("{s:s, s:s, s:[[s, s, [s, [s]]], [s, s, [s, [[s, s]]]]], s:[[s, s, s]]}", + "op", + "mutate", + "table", + "Bridge", + "mutations", + + "other_config", + "delete", + "set", + "hwaddr", + + "other_config", + "insert", + "map", + "hwaddr", + mac, + + "where", + "name", + "==", + ifname)); } /** -- cgit v1.2.1 From d219527dbaf3abb9e53be3b7fafc2519c2652e64 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 19:54:46 +0100 Subject: ovs: ensure existing "external-ids" get updated during reapply "mutate" with operation "insert" does not update existing entries. Delete them first. Otherwise, a reapply that only change the value of an external-ids entry does not work. Note that https://www.rfc-editor.org/rfc/rfc7047 says about "": If is "insert", then each of the key-value pairs in the map in is added to only if its key is not already present. The required type of is slightly relaxed, in that it may have fewer than the minimum number of elements specified by the column's type. Fixes: 7055539c9f7b ('core/ovs: support setting OVS external-ids') --- src/core/devices/ovs/nm-ovsdb.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index a8f284a3c7..34de2d6649 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -723,26 +723,27 @@ _j_create_external_ids_array_update(const char *connection_uuid, mutations = json_array(); + array = json_array(); if (exid_old) { - array = NULL; g_hash_table_iter_init(&iter, exid_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { - if (nm_g_hash_table_contains(exid_new, key)) - continue; - if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) - continue; - - if (!array) - array = json_array(); - json_array_append_new(array, json_string(key)); } - if (array) { - json_array_append_new( - mutations, - json_pack("[s, s, [s, o]]", "external_ids", "delete", "set", array)); + } + if (exid_new) { + g_hash_table_iter_init(&iter, exid_new); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (nm_g_hash_table_contains(exid_old, key)) + continue; + json_array_append_new(array, json_string(key)); } } + if (!nm_g_hash_table_contains(exid_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) + && !nm_g_hash_table_contains(exid_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + } + json_array_append_new(mutations, + json_pack("[s, s, [s, o]]", "external_ids", "delete", "set", array)); array = json_array(); -- cgit v1.2.1 From 79ca9b641288409999233e48cffe2d2bb80b2e79 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 14:04:27 +0100 Subject: ovs: rename internal code to make independent of "external-ids" We will add support for "other_config". This is in many aspects similar to "external-ids". So first do a renaming, so that the code can be sensibly reused. This is a separate patch, so that the followup commit has less noise in the diff. This function *only* renames (and reformats). No other changes. --- src/core/devices/ovs/nm-device-ovs-bridge.c | 13 +- src/core/devices/ovs/nm-ovsdb.c | 214 ++++++++++++++-------------- src/core/devices/ovs/nm-ovsdb.h | 12 +- 3 files changed, 119 insertions(+), 120 deletions(-) diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 048afb02b5..10c7cfdbd2 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -124,13 +124,12 @@ nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnec device_type = NM_DEVICE_TYPE_OVS_BRIDGE; } - nm_ovsdb_set_external_ids( - nm_ovsdb_get(), - device_type, - nm_device_get_ip_iface(self), - nm_connection_get_uuid(con_new), - _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), - _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + nm_ovsdb_set_reapply(nm_ovsdb_get(), + device_type, + nm_device_get_ip_iface(self), + nm_connection_get_uuid(con_new), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 34de2d6649..3feb95419c 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -66,7 +66,7 @@ typedef enum { OVSDB_ADD_INTERFACE, OVSDB_DEL_INTERFACE, OVSDB_SET_INTERFACE_MTU, - OVSDB_SET_EXTERNAL_IDS, + OVSDB_SET_REAPPLY, } OvsdbCommand; #define CALL_ID_UNSPEC G_MAXUINT64 @@ -92,9 +92,9 @@ typedef union { NMDeviceType device_type; char *ifname; char *connection_uuid; - GHashTable *exid_old; - GHashTable *exid_new; - } set_external_ids; + GHashTable *external_ids_old; + GHashTable *external_ids_new; + } set_reapply; } OvsdbMethodPayload; typedef struct { @@ -223,20 +223,20 @@ static void cleanup_check_ready(NMOvsdb *self); }, \ })) -#define OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(xdevice_type, \ - xifname, \ - xconnection_uuid, \ - xexid_old, \ - xexid_new) \ - (&((const OvsdbMethodPayload){ \ - .set_external_ids = \ - { \ - .device_type = xdevice_type, \ - .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ - .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ - .exid_old = (xexid_old), \ - .exid_new = (xexid_new), \ - }, \ +#define OVSDB_METHOD_PAYLOAD_SET_REAPPLY(xdevice_type, \ + xifname, \ + xconnection_uuid, \ + xexternal_ids_old, \ + xexternal_ids_new) \ + (&((const OvsdbMethodPayload){ \ + .set_reapply = \ + { \ + .device_type = xdevice_type, \ + .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ + .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ + .external_ids_old = (xexternal_ids_old), \ + .external_ids_new = (xexternal_ids_new), \ + }, \ })) /*****************************************************************************/ @@ -291,11 +291,11 @@ _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) case OVSDB_SET_INTERFACE_MTU: nm_clear_g_free(&call->payload.set_interface_mtu.ifname); break; - case OVSDB_SET_EXTERNAL_IDS: - nm_clear_g_free(&call->payload.set_external_ids.ifname); - nm_clear_g_free(&call->payload.set_external_ids.connection_uuid); - nm_clear_pointer(&call->payload.set_external_ids.exid_old, g_hash_table_destroy); - nm_clear_pointer(&call->payload.set_external_ids.exid_new, g_hash_table_destroy); + case OVSDB_SET_REAPPLY: + nm_clear_g_free(&call->payload.set_reapply.ifname); + nm_clear_g_free(&call->payload.set_reapply.connection_uuid); + nm_clear_pointer(&call->payload.set_reapply.external_ids_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.external_ids_new, g_hash_table_destroy); break; } @@ -447,19 +447,18 @@ ovsdb_call_method(NMOvsdb *self, call->payload.set_interface_mtu.ifname, call->payload.set_interface_mtu.mtu); break; - case OVSDB_SET_EXTERNAL_IDS: - call->payload.set_external_ids.device_type = payload->set_external_ids.device_type; - call->payload.set_external_ids.ifname = g_strdup(payload->set_external_ids.ifname); - call->payload.set_external_ids.connection_uuid = - g_strdup(payload->set_external_ids.connection_uuid); - call->payload.set_external_ids.exid_old = - nm_g_hash_table_ref(payload->set_external_ids.exid_old); - call->payload.set_external_ids.exid_new = - nm_g_hash_table_ref(payload->set_external_ids.exid_new); + case OVSDB_SET_REAPPLY: + call->payload.set_reapply.device_type = payload->set_reapply.device_type; + call->payload.set_reapply.ifname = g_strdup(payload->set_reapply.ifname); + call->payload.set_reapply.connection_uuid = g_strdup(payload->set_reapply.connection_uuid); + call->payload.set_reapply.external_ids_old = + nm_g_hash_table_ref(payload->set_reapply.external_ids_old); + call->payload.set_reapply.external_ids_new = + nm_g_hash_table_ref(payload->set_reapply.external_ids_new); _LOGT_call(call, "new: set-external-ids con-uuid=%s, interface=%s", - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.ifname); + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.ifname); break; } @@ -677,14 +676,14 @@ _set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) } static json_t * -_j_create_external_ids_array_new(NMConnection *connection) +_j_create_strdict_new(NMConnection *connection) { json_t *array; - const char *const *external_ids = NULL; - guint n_external_ids = 0; + const char *const *strv = NULL; + guint n_strv = 0; guint i; const char *uuid; - NMSettingOvsExternalIDs *s_exid; + NMSettingOvsExternalIDs *s_external_ids; nm_assert(NM_IS_CONNECTION(connection)); @@ -694,24 +693,22 @@ _j_create_external_ids_array_new(NMConnection *connection) nm_assert(uuid); json_array_append_new(array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); - s_exid = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); - if (s_exid) - external_ids = nm_setting_ovs_external_ids_get_data_keys(s_exid, &n_external_ids); - for (i = 0; i < n_external_ids; i++) { - const char *k = external_ids[i]; + s_external_ids = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); + if (s_external_ids) + strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); + for (i = 0; i < n_strv; i++) { + const char *k = strv[i]; json_array_append_new( array, - json_pack("[s, s]", k, nm_setting_ovs_external_ids_get_data(s_exid, k))); + json_pack("[s, s]", k, nm_setting_ovs_external_ids_get_data(s_external_ids, k))); } return json_pack("[s, o]", "map", array); } static json_t * -_j_create_external_ids_array_update(const char *connection_uuid, - GHashTable *exid_old, - GHashTable *exid_new) +_j_create_strv_array_update(const char *connection_uuid, GHashTable *hash_old, GHashTable *hash_new) { GHashTableIter iter; json_t *mutations; @@ -724,22 +721,22 @@ _j_create_external_ids_array_update(const char *connection_uuid, mutations = json_array(); array = json_array(); - if (exid_old) { - g_hash_table_iter_init(&iter, exid_old); + if (hash_old) { + g_hash_table_iter_init(&iter, hash_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { json_array_append_new(array, json_string(key)); } } - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { - if (nm_g_hash_table_contains(exid_old, key)) + if (nm_g_hash_table_contains(hash_old, key)) continue; json_array_append_new(array, json_string(key)); } } - if (!nm_g_hash_table_contains(exid_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) - && !nm_g_hash_table_contains(exid_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + if (!nm_g_hash_table_contains(hash_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) + && !nm_g_hash_table_contains(hash_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); } json_array_append_new(mutations, @@ -751,8 +748,8 @@ _j_create_external_ids_array_update(const char *connection_uuid, array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) continue; @@ -842,7 +839,7 @@ _insert_interface(json_t *params, "options", options, "external_ids", - _j_create_external_ids_array_new(interface)); + _j_create_strdict_new(interface)); if (cloned_mac) json_object_set_new(row, "mac", json_string(cloned_mac)); @@ -927,7 +924,7 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(port)); + json_object_set_new(row, "external_ids", _j_create_strdict_new(port)); /* Create a new one. */ json_array_append_new(params, @@ -987,7 +984,7 @@ _insert_bridge(json_t *params, json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(bridge))); json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(bridge)); + json_object_set_new(row, "external_ids", _j_create_strdict_new(bridge)); if (cloned_mac) { json_object_set_new(row, @@ -1421,23 +1418,22 @@ ovsdb_next_command(NMOvsdb *self) "==", call->payload.set_interface_mtu.ifname)); break; - case OVSDB_SET_EXTERNAL_IDS: + case OVSDB_SET_REAPPLY: json_array_append_new( params, json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", "op", "mutate", "table", - _device_type_to_table(call->payload.set_external_ids.device_type), + _device_type_to_table(call->payload.set_reapply.device_type), "mutations", - _j_create_external_ids_array_update( - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.exid_old, - call->payload.set_external_ids.exid_new), + _j_create_strv_array_update(call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.external_ids_old, + call->payload.set_reapply.external_ids_new), "where", "name", "==", - call->payload.set_external_ids.ifname)); + call->payload.set_reapply.ifname)); break; default: @@ -1523,7 +1519,7 @@ _uuids_to_array(const json_t *items) } static void -_external_ids_extract(json_t *external_ids, GArray **out_array, const char **out_connection_uuid) +_strdict_extract(json_t *strdict, GArray **out_array, const char **out_connection_uuid) { json_t *array; json_t *value; @@ -1532,10 +1528,10 @@ _external_ids_extract(json_t *external_ids, GArray **out_array, const char **out nm_assert(out_array && !*out_array); nm_assert(!out_connection_uuid || !*out_connection_uuid); - if (!nm_streq0("map", json_string_value(json_array_get(external_ids, 0)))) + if (!nm_streq0("map", json_string_value(json_array_get(strdict, 0)))) return; - array = json_array_get(external_ids, 1); + array = json_array_get(strdict, 1); json_array_foreach (array, index, value) { const char *key = json_string_value(json_array_get(value, 0)); @@ -1565,7 +1561,7 @@ _external_ids_extract(json_t *external_ids, GArray **out_array, const char **out } static gboolean -_external_ids_equal(const GArray *arr1, const GArray *arr2) +_strdict_equal(const GArray *arr1, const GArray *arr2) { guint n; guint i; @@ -1724,7 +1720,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_interface, _free_interface); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); if (ovs_interface) { gboolean changed = FALSE; @@ -1733,12 +1729,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) changed |= nm_strdup_reset(&ovs_interface->type, type); changed |= nm_strdup_reset(&ovs_interface->connection_uuid, connection_uuid); - if (!_external_ids_equal(ovs_interface->external_ids, external_ids_arr)) { + if (!_strdict_equal(ovs_interface->external_ids, external_ids_arr)) { NM_SWAP(&ovs_interface->external_ids, &external_ids_arr); changed = TRUE; } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s", key, @@ -1748,10 +1744,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_interface->external_ids))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; ovs_interface = g_slice_new(OpenvswitchInterface); *ovs_interface = (OpenvswitchInterface){ @@ -1770,7 +1766,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_interface->external_ids))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -1834,7 +1830,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_port, _free_port); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); interfaces = _uuids_to_array(items); if (ovs_port) { @@ -1848,12 +1844,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_port->interfaces, &interfaces); changed = TRUE; } - if (!_external_ids_equal(ovs_port->external_ids, external_ids_arr)) { + if (!_strdict_equal(ovs_port->external_ids, external_ids_arr)) { NM_SWAP(&ovs_port->external_ids, &external_ids_arr); changed = TRUE; } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s", key, @@ -1862,10 +1858,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_port->external_ids))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; ovs_port = g_slice_new(OpenvswitchPort); *ovs_port = (OpenvswitchPort){ @@ -1883,7 +1879,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_port->external_ids))); _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); } } @@ -1939,7 +1935,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_bridge, _free_bridge); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); ports = _uuids_to_array(items); if (ovs_bridge) { @@ -1953,12 +1949,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_bridge->ports, &ports); changed = TRUE; } - if (!_external_ids_equal(ovs_bridge->external_ids, external_ids_arr)) { + if (!_strdict_equal(ovs_bridge->external_ids, external_ids_arr)) { NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr); changed = TRUE; } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s", key, @@ -1967,10 +1963,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_bridge->external_ids))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; ovs_bridge = g_slice_new(OpenvswitchBridge); *ovs_bridge = (OpenvswitchBridge){ @@ -1988,7 +1984,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _external_ids_to_string(ovs_bridge->external_ids))); _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); } } @@ -2726,31 +2722,35 @@ nm_ovsdb_set_interface_mtu(NMOvsdb *self, } void -nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - NMSettingOvsExternalIDs *s_exid_old, - NMSettingOvsExternalIDs *s_exid_new) +nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new) { - gs_unref_hashtable GHashTable *exid_old = NULL; - gs_unref_hashtable GHashTable *exid_new = NULL; - - exid_old = - s_exid_old ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_old)) : NULL; - exid_new = - s_exid_new ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_new)) : NULL; + gs_unref_hashtable GHashTable *external_ids_old = NULL; + gs_unref_hashtable GHashTable *external_ids_new = NULL; + + external_ids_old = + s_external_ids_old + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_old)) + : NULL; + external_ids_new = + s_external_ids_new + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_new)) + : NULL; ovsdb_call_method(self, NULL, NULL, FALSE, - OVSDB_SET_EXTERNAL_IDS, - OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(device_type, - ifname, - connection_uuid, - exid_old, - exid_new)); + OVSDB_SET_REAPPLY, + OVSDB_METHOD_PAYLOAD_SET_REAPPLY(device_type, + ifname, + connection_uuid, + external_ids_old, + external_ids_new)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.h b/src/core/devices/ovs/nm-ovsdb.h index 610190ed7e..e6e35ccd7f 100644 --- a/src/core/devices/ovs/nm-ovsdb.h +++ b/src/core/devices/ovs/nm-ovsdb.h @@ -49,12 +49,12 @@ void nm_ovsdb_set_interface_mtu(NMOvsdb *self, struct _NMSettingOvsExternalIDs; -void nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - struct _NMSettingOvsExternalIDs *s_exid_old, - struct _NMSettingOvsExternalIDs *s_exid_new); +void nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + struct _NMSettingOvsExternalIDs *s_external_ids_old, + struct _NMSettingOvsExternalIDs *s_external_ids_new); gboolean nm_ovsdb_is_ready(NMOvsdb *self); -- cgit v1.2.1 From 8445b96b04f57e8aefff2c6a3e814efca53cfe66 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 15:04:30 +0100 Subject: ovs: extend "external-ids" handle for supporting "other_config" Next, support for "other_config" will be added. That is very similar to "external_ids". Extend the existing code, to make that next update simpler. The only purpose of this patch, is to reduce the diff of when actually adding "other_config". Only in light of that, do some of the changes here make sense. --- src/core/devices/ovs/nm-ovsdb.c | 184 +++++++++++++++++++++++++++------------- 1 file changed, 126 insertions(+), 58 deletions(-) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 3feb95419c..bda1fca3ad 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -30,6 +30,10 @@ #warning "requires at least libjansson 2.4" #endif +typedef enum { + STRDICT_TYPE_EXTERNAL_IDS, +} StrdictType; + typedef struct { char *port_uuid; char *name; @@ -676,26 +680,35 @@ _set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) } static json_t * -_j_create_strdict_new(NMConnection *connection) +_j_create_strdict_new(NMConnection *connection, StrdictType strdict_type) { + NMSettingOvsExternalIDs *s_external_ids = NULL; json_t *array; const char *const *strv = NULL; guint n_strv = 0; guint i; const char *uuid; - NMSettingOvsExternalIDs *s_external_ids; nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS)); array = json_array(); - uuid = nm_connection_get_uuid(connection); - nm_assert(uuid); - json_array_append_new(array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + uuid = nm_connection_get_uuid(connection); + nm_assert(uuid); + json_array_append_new(array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + } + + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + s_external_ids = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); + if (s_external_ids) + strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); + } else { + nm_assert_not_reached(); + } - s_external_ids = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); - if (s_external_ids) - strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); for (i = 0; i < n_strv; i++) { const char *k = strv[i]; @@ -707,23 +720,27 @@ _j_create_strdict_new(NMConnection *connection) return json_pack("[s, o]", "map", array); } -static json_t * -_j_create_strv_array_update(const char *connection_uuid, GHashTable *hash_old, GHashTable *hash_new) +static void +_j_create_strv_array_update(json_t *mutations, + StrdictType strdict_type, + const char *connection_uuid, + GHashTable *hash_old, + GHashTable *hash_new) { GHashTableIter iter; - json_t *mutations; json_t *array; const char *key; const char *val; - nm_assert(connection_uuid); + nm_assert((!!connection_uuid) == (strdict_type == STRDICT_TYPE_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS)); - mutations = json_array(); - - array = json_array(); + array = NULL; if (hash_old) { g_hash_table_iter_init(&iter, hash_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } @@ -732,34 +749,54 @@ _j_create_strv_array_update(const char *connection_uuid, GHashTable *hash_old, G while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { if (nm_g_hash_table_contains(hash_old, key)) continue; + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } - if (!nm_g_hash_table_contains(hash_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) - && !nm_g_hash_table_contains(hash_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { - json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (!nm_g_hash_table_contains(hash_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) + && !nm_g_hash_table_contains(hash_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + if (!array) + array = json_array(); + json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + } + } + if (array) { + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "delete", + "set", + array)); } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "delete", "set", array)); array = json_array(); - json_array_append_new( - array, - json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); - + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + json_array_append_new( + array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); + } if (hash_new) { g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { - if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) - continue; + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) + continue; + } json_array_append_new(array, json_pack("[s, s]", key, val)); } } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "insert", "map", array)); - return mutations; + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "insert", + "map", + array)); } /** @@ -839,7 +876,7 @@ _insert_interface(json_t *params, "options", options, "external_ids", - _j_create_strdict_new(interface)); + _j_create_strdict_new(interface, STRDICT_TYPE_EXTERNAL_IDS)); if (cloned_mac) json_object_set_new(row, "mac", json_string(cloned_mac)); @@ -924,7 +961,9 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); - json_object_set_new(row, "external_ids", _j_create_strdict_new(port)); + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(port, STRDICT_TYPE_EXTERNAL_IDS)); /* Create a new one. */ json_array_append_new(params, @@ -984,7 +1023,9 @@ _insert_bridge(json_t *params, json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(bridge))); json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); - json_object_set_new(row, "external_ids", _j_create_strdict_new(bridge)); + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(bridge, STRDICT_TYPE_EXTERNAL_IDS)); if (cloned_mac) { json_object_set_new(row, @@ -1419,6 +1460,17 @@ ovsdb_next_command(NMOvsdb *self) call->payload.set_interface_mtu.ifname)); break; case OVSDB_SET_REAPPLY: + { + json_t *mutations; + + mutations = json_array(); + + _j_create_strv_array_update(mutations, + STRDICT_TYPE_EXTERNAL_IDS, + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.external_ids_old, + call->payload.set_reapply.external_ids_new); + json_array_append_new( params, json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", @@ -1427,14 +1479,13 @@ ovsdb_next_command(NMOvsdb *self) "table", _device_type_to_table(call->payload.set_reapply.device_type), "mutations", - _j_create_strv_array_update(call->payload.set_reapply.connection_uuid, - call->payload.set_reapply.external_ids_old, - call->payload.set_reapply.external_ids_new), + mutations, "where", "name", "==", call->payload.set_reapply.ifname)); break; + } default: nm_assert_not_reached(); @@ -1519,14 +1570,13 @@ _uuids_to_array(const json_t *items) } static void -_strdict_extract(json_t *strdict, GArray **out_array, const char **out_connection_uuid) +_strdict_extract(json_t *strdict, GArray **out_array) { json_t *array; json_t *value; gsize index; nm_assert(out_array && !*out_array); - nm_assert(!out_connection_uuid || !*out_connection_uuid); if (!nm_streq0("map", json_string_value(json_array_get(strdict, 0)))) return; @@ -1552,16 +1602,26 @@ _strdict_extract(json_t *strdict, GArray **out_array, const char **out_connectio .name = g_strdup(key), .value_str = g_strdup(val), }; - - if (out_connection_uuid && nm_streq(v->name, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID)) { - *out_connection_uuid = v->value_str; - out_connection_uuid = NULL; - } } } +static const char * +_strdict_find_key(GArray *array, const char *key) +{ + gssize idx; + + idx = nm_utils_named_value_list_find(nm_g_array_first_p(array, NMUtilsNamedValue), + nm_g_array_len(array), + key, + FALSE); + if (idx < 0) + return NULL; + + return nm_g_array_index(array, NMUtilsNamedValue, idx).value_str; +} + static gboolean -_strdict_equal(const GArray *arr1, const GArray *arr2) +_strdict_equals(const GArray *arr1, const GArray *arr2) { guint n; guint i; @@ -1574,16 +1634,16 @@ _strdict_equal(const GArray *arr1, const GArray *arr2) const NMUtilsNamedValue *n1 = &nm_g_array_index(arr1, NMUtilsNamedValue, i); const NMUtilsNamedValue *n2 = &nm_g_array_index(arr2, NMUtilsNamedValue, i); - if (!nm_streq0(n1->name, n2->name)) + if (!nm_streq(n1->name, n2->name)) return FALSE; - if (!nm_streq0(n1->value_str, n2->value_str)) + if (!nm_streq(n1->value_str, n2->value_str)) return FALSE; } return TRUE; } static char * -_external_ids_to_string(const GArray *arr) +_strdict_to_string(const GArray *arr) { NMStrBuf strbuf; guint i; @@ -1720,7 +1780,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_interface, _free_interface); } - _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); if (ovs_interface) { gboolean changed = FALSE; @@ -1729,7 +1791,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) changed |= nm_strdup_reset(&ovs_interface->type, type); changed |= nm_strdup_reset(&ovs_interface->connection_uuid, connection_uuid); - if (!_strdict_equal(ovs_interface->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_interface->external_ids, external_ids_arr)) { NM_SWAP(&ovs_interface->external_ids, &external_ids_arr); changed = TRUE; } @@ -1744,7 +1806,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _strdict_to_string(ovs_interface->external_ids))); } } else { gs_free char *strtmp1 = NULL; @@ -1766,7 +1828,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _strdict_to_string(ovs_interface->external_ids))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -1830,7 +1892,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_port, _free_port); } - _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + interfaces = _uuids_to_array(items); if (ovs_port) { @@ -1844,7 +1909,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_port->interfaces, &interfaces); changed = TRUE; } - if (!_strdict_equal(ovs_port->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_port->external_ids, external_ids_arr)) { NM_SWAP(&ovs_port->external_ids, &external_ids_arr); changed = TRUE; } @@ -1858,7 +1923,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_port->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids))); } } else { gs_free char *strtmp1 = NULL; @@ -1879,7 +1944,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_port->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids))); _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); } } @@ -1935,7 +2000,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_bridge, _free_bridge); } - _strdict_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + ports = _uuids_to_array(items); if (ovs_bridge) { @@ -1949,7 +2017,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_bridge->ports, &ports); changed = TRUE; } - if (!_strdict_equal(ovs_bridge->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_bridge->external_ids, external_ids_arr)) { NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr); changed = TRUE; } @@ -1963,7 +2031,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_bridge->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids))); } } else { gs_free char *strtmp1 = NULL; @@ -1984,7 +2052,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_bridge->connection_uuid, ""), - (strtmp1 = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids))); _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); } } -- cgit v1.2.1 From a259303e1d5aa593cef2cfdff7b4d7f8c488288e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 Jan 2023 11:51:46 +0100 Subject: ovs: add support for "other_config" settings See `man ovs-vswitchd.conf.db` for documentation of "other_config" keys. https://bugzilla.redhat.com/show_bug.cgi?id=2151455 --- Makefile.am | 2 + docs/libnm/libnm-docs.xml | 1 + examples/python/gi/ovs-external-ids.py | 157 +++++--- po/POTFILES.in | 1 + src/core/devices/nm-device.c | 5 +- src/core/devices/ovs/nm-device-ovs-bridge.c | 5 +- src/core/devices/ovs/nm-ovsdb.c | 213 ++++++++--- src/core/devices/ovs/nm-ovsdb.h | 16 +- src/libnm-client-impl/libnm.ver | 7 +- src/libnm-core-aux-intern/nm-libnm-core-utils.c | 101 ++++++ src/libnm-core-aux-intern/nm-libnm-core-utils.h | 5 + .../gen-metadata-nm-settings-libnm-core.xml.in | 8 + src/libnm-core-impl/meson.build | 1 + src/libnm-core-impl/nm-keyfile.c | 101 ++++-- src/libnm-core-impl/nm-meta-setting-base-impl.c | 11 +- src/libnm-core-impl/nm-setting-ovs-external-ids.c | 5 +- src/libnm-core-impl/nm-setting-ovs-other-config.c | 403 +++++++++++++++++++++ src/libnm-core-impl/tests/test-setting.c | 2 +- src/libnm-core-intern/nm-core-internal.h | 1 + src/libnm-core-intern/nm-meta-setting-base-impl.h | 1 + src/libnm-core-public/meson.build | 1 + src/libnm-core-public/nm-core-types.h | 1 + .../nm-setting-ovs-other-config.h | 63 ++++ src/libnmc-setting/nm-meta-setting-base-impl.c | 11 +- src/libnmc-setting/nm-meta-setting-base-impl.h | 1 + src/libnmc-setting/nm-meta-setting-desc.c | 2 + src/libnmc-setting/settings-docs.h.in | 3 +- src/nmcli/gen-metadata-nm-settings-nmcli.xml.in | 2 + tools/check-docs.sh | 1 + 29 files changed, 978 insertions(+), 153 deletions(-) create mode 100644 src/libnm-core-impl/nm-setting-ovs-other-config.c create mode 100644 src/libnm-core-public/nm-setting-ovs-other-config.h diff --git a/Makefile.am b/Makefile.am index 3c294ab767..29d39b4c5e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1273,6 +1273,7 @@ src_libnm_core_impl_lib_h_pub_real = \ src/libnm-core-public/nm-setting-ovs-dpdk.h \ src/libnm-core-public/nm-setting-ovs-external-ids.h \ src/libnm-core-public/nm-setting-ovs-interface.h \ + src/libnm-core-public/nm-setting-ovs-other-config.h \ src/libnm-core-public/nm-setting-ovs-patch.h \ src/libnm-core-public/nm-setting-ovs-port.h \ src/libnm-core-public/nm-setting-ppp.h \ @@ -1353,6 +1354,7 @@ src_libnm_core_impl_lib_c_settings_real = \ src/libnm-core-impl/nm-setting-ovs-dpdk.c \ src/libnm-core-impl/nm-setting-ovs-external-ids.c \ src/libnm-core-impl/nm-setting-ovs-interface.c \ + src/libnm-core-impl/nm-setting-ovs-other-config.c \ src/libnm-core-impl/nm-setting-ovs-patch.c \ src/libnm-core-impl/nm-setting-ovs-port.c \ src/libnm-core-impl/nm-setting-ppp.c \ diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index d20f01a2e2..df668e4ee9 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -341,6 +341,7 @@ print ("NetworkManager version " + client.get_version())]]> + diff --git a/examples/python/gi/ovs-external-ids.py b/examples/python/gi/ovs-external-ids.py index 3bc9de8fd1..fe4fbd9dce 100755 --- a/examples/python/gi/ovs-external-ids.py +++ b/examples/python/gi/ovs-external-ids.py @@ -5,14 +5,15 @@ # # -# set and show OVS external-ids for a connection: +# set and show OVS external-ids and other-config for a connection: # -import sys +import collections import os -import re import pprint +import re import subprocess +import sys import gi @@ -178,14 +179,14 @@ def device_reapply(device, connection, version_id): raise result_error[0] -def ovs_print_external_ids(prefix): +def ovs_print_config(prefix): if not can_sudo(): _print(prefix + ": not running as root and cannot call ovs-vsctl") return cmds = [["ovs-vsctl", "show"]] for typ in ["Bridge", "Port", "Interface"]: - cmds += [["ovs-vsctl", "--columns=name,external-ids", "list", typ]] + cmds += [["ovs-vsctl", "--columns=name,external-ids,other-config", "list", typ]] out = "" for cmd in cmds: @@ -207,7 +208,11 @@ def usage(): ) _print(" DEVICE := [iface] STRING") _print(" GETTER := ( KEY | ~REGEX_KEY ) [... GETTER]") - _print(" SETTER := ( + | - | -KEY | [+]KEY VALUE ) [... SETTER]") + _print(" SETTER := ( +[e:|o:] | -[e:|o:] | -KEY | [+]KEY VALUE ) [... SETTER]") + _print("") + _print( + 'Prefix KEY with "e:" or "o:" to set external-ids or other-config ("e:" is the default)' + ) def die(msg, show_usage=False): @@ -221,6 +226,24 @@ def die_usage(msg): die(msg, show_usage=True) +DataTypeTuple = collections.namedtuple( + "DataTypeTuple", ["short", "name", "setting_type", "property_name"] +) + +DataTypeE = DataTypeTuple( + "external-ids", + "ovs-external-ids", + NM.SettingOvsExternalIDs, + NM.SETTING_OVS_EXTERNAL_IDS_DATA, +) +DataTypeO = DataTypeTuple( + "other-config", + "ovs-other-config", + NM.SettingOvsOtherConfig, + NM.SETTING_OVS_OTHER_CONFIG_DATA, +) + + def parse_args(argv): args = { "mode": MODE_GET, @@ -274,12 +297,14 @@ def parse_args(argv): continue if not a: - die_usage("argument should specify a external-id but is empty string") + die_usage( + "argument should specify a external-id/other-config but is empty string" + ) if a[0] == "-": v = (a, None) i += 1 - elif a == "+": + elif a in ["+", "+o:", "+e:"]: v = (a, None) i += 1 else: @@ -294,7 +319,7 @@ def parse_args(argv): if args["mode"] == MODE_SET: if not args["ids_arg"]: - die_usage("Requires one or more external-ids to set or delete") + die_usage("Requires one or more external-ids/other-config to set or delete") return args @@ -319,9 +344,6 @@ def devices_filter(devices, select_arg): devices = list(sorted(devices, key=device_to_str)) if not select_arg: return devices - # we preserve the order of the selected devices. And - # if devices are selected multiple times, we return - # them multiple times. l = [] f = select_arg for d in devices: @@ -342,9 +364,6 @@ def connections_filter(connections, select_arg): connections = list(sorted(connections, key=connection_to_str)) if not select_arg: return connections - # we preserve the order of the selected connections. And - # if connections are selected multiple times, we return - # them multiple times. l = [] f = select_arg for c in connections: @@ -352,7 +371,7 @@ def connections_filter(connections, select_arg): if f[1] == c.get_id(): l.append(c) elif f[0] == "~id": - if re.match(f[1], c.get_id()): + if re.search(f[1], c.get_id()): l.append(c) elif f[0] == "uuid": if f[1] == c.get_uuid(): @@ -361,7 +380,7 @@ def connections_filter(connections, select_arg): if f[1] == c.get_connection_type(): l.append(c) elif f[0] == "~type": - if re.match(f[1], c.get_connection_type()): + if re.search(f[1], c.get_connection_type()): l.append(c) else: assert f[0] == "*" @@ -384,7 +403,7 @@ def ids_select(ids, mode, ids_arg): if mode == MODE_GET: if d[0] == "~": r = re.compile(d[1:]) - keys.update([k for k in ids if r.match(k)]) + keys.update([k for k in ids if r.search(k)]) else: keys.update([k for k in ids if k == d]) if d not in requested: @@ -400,44 +419,67 @@ def ids_select(ids, mode, ids_arg): def connection_print(connection, mode, ids_arg, dbus_path, prefix=""): - sett = connection.get_setting(NM.SettingOvsExternalIDs) - - if sett is not None: - all_ids = list(sett.get_data_keys()) - keys, requested = ids_select(all_ids, mode, ids_arg) - num_str = "%s" % (len(all_ids)) - else: - keys = [] - requested = [] + def _num_str(connection, data_type): + sett = connection.get_setting(data_type.setting_type) num_str = "none" + if sett is not None: + all_ids = list(sett.get_data_keys()) + num_str = "%s" % (len(all_ids)) + return num_str _print( - "%s%s [%s]" % (prefix, connection_to_str(connection, show_type=True), num_str) + "%s%s [e:%s, o:%s]" + % ( + prefix, + connection_to_str(connection, show_type=True), + _num_str(connection, DataTypeE), + _num_str(connection, DataTypeO), + ) ) if dbus_path: _print("%s %s" % (prefix, dbus_path)) - if sett is not None: - dd = sett.get_property(NM.SETTING_OVS_EXTERNAL_IDS_DATA) - else: - dd = {} - for k in keys: - v = sett.get_data(k) - assert v is not None - assert v == dd.get(k, None) - _print('%s "%s" = "%s"' % (prefix, k, v)) - for k in requested: - _print('%s "%s" = ' % (prefix, k)) + for data_type in [DataTypeE, DataTypeO]: -def sett_update(connection, ids_arg): + sett = connection.get_setting(data_type.setting_type) + if sett is not None: + all_ids = list(sett.get_data_keys()) + keys, requested = ids_select(all_ids, mode, ids_arg) + else: + keys = [] + requested = [] - sett = connection.get_setting(NM.SettingOvsExternalIDs) + if sett is not None: + dd = sett.get_property(data_type.property_name) + else: + dd = {} + for k in keys: + v = sett.get_data(k) + assert v is not None + assert v == dd.get(k, None) + _print('%s %s: "%s" = "%s"' % (prefix, data_type.short, k, v)) + for k in requested: + _print('%s %s: "%s" = ' % (prefix, data_type.short, k)) + + +def sett_update(connection, ids_arg): for d in ids_arg: op = d[0][0] key = d[0][1:] val = d[1] + if key == "o" or key.startswith("o:"): + data_type = DataTypeO + key = key[2:] + elif key == "e" or key.startswith("e:"): + data_type = DataTypeE + key = key[2:] + else: + data_type = DataTypeE + + sett = connection.get_setting(data_type.setting_type) + oldval = None if sett is not None: oldval = sett.get_data(key) @@ -446,15 +488,17 @@ def sett_update(connection, ids_arg): assert val is None if key == "": if sett is None: - _print(" DEL: setting (ovs-external-ids group was not present)") + _print( + " DEL: setting (%s group was not present)" % (data_type.name,) + ) else: - connection.remove_setting(NM.SettingOvsExternalIDs) + connection.remove_setting(data_type.setting_type) sett = None - _print(" DEL: setting") + _print(" DEL: setting (%s)" % (data_type.name,)) continue if sett is None: - _print(' DEL: "%s" (ovs-external-ids group was not present)' % (key)) + _print(' DEL: "%s" (%s group was not present)' % (key, data_type.name)) continue if oldval is None: _print(' DEL: "%s" (id was unset)' % (key)) @@ -466,21 +510,22 @@ def sett_update(connection, ids_arg): if key == "": assert val is None if sett is None: - sett = NM.SettingOvsExternalIDs.new() + sett = data_type.setting_type.new() connection.add_setting(sett) - _print(" SET: setting (external-ids group was added)") + _print(" SET: setting (%s group was added)" % (data_type.name,)) continue - _print(" SET: setting (external-ids group was present)") + _print(" SET: setting (%s group was present)" % (data_type.name,)) continue assert val is not None if sett is None: - sett = NM.SettingOvsExternalIDs.new() + sett = data_type.setting_type.new() connection.add_setting(sett) _print( - ' SET: "%s" = "%s" (external-ids group was not present)' % (key, val) + ' SET: "%s" = "%s" (%s group was not present)' + % (key, val, data_type.name) ) elif oldval is None: _print(' SET: "%s" = "%s" (new)' % (key, val)) @@ -579,7 +624,7 @@ def do_apply(nmc, device, ids_arg, do_test): ) _print() - ovs_print_external_ids("BEFORE-OVS-VSCTL: ") + ovs_print_config("BEFORE-OVS-VSCTL: ") _print() connection = NM.SimpleConnection.new_clone(connection_orig) @@ -619,7 +664,7 @@ def do_apply(nmc, device, ids_arg, do_test): ) _print() - ovs_print_external_ids("AFTER-OVS-VSCTL: ") + ovs_print_config("AFTER-OVS-VSCTL: ") ############################################################################### @@ -636,7 +681,7 @@ if __name__ == "__main__": if len(devices) != 1: _print( - "To apply the external-ids of a device, exactly one connection must be selected. Instead, %s devices matched ([%s])" + "To apply the external-ids/other-config of a device, exactly one connection must be selected. Instead, %s devices matched ([%s])" % (len(devices), ", ".join([device_to_str(c) for c in devices])) ) die_usage("Select unique device to apply") @@ -649,7 +694,7 @@ if __name__ == "__main__": if args["mode"] == MODE_SET: if len(connections) != 1: _print( - "To set the external-ids of a connection, exactly one connection must be selected via id|uuid. Instead, %s connection matched ([%s])" + "To set the external-ids/other-config of a connection, exactly one connection must be selected via id|uuid. Instead, %s connection matched ([%s])" % ( len(connections), ", ".join([connection_to_str(c) for c in connections]), @@ -659,6 +704,8 @@ if __name__ == "__main__": do_set(nmc, connections[0], args["ids_arg"], do_test=args["do_test"]) else: if len(connections) < 1: - _print("No connection selected for printing the external ids") + _print( + "No connection selected for printing the external ids/other-config" + ) die_usage("Select connection to get") do_get(connections, args["ids_arg"]) diff --git a/po/POTFILES.in b/po/POTFILES.in index cb1fa08193..dcd2983d38 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -102,6 +102,7 @@ src/libnm-core-impl/nm-setting-olpc-mesh.c src/libnm-core-impl/nm-setting-ovs-bridge.c src/libnm-core-impl/nm-setting-ovs-external-ids.c src/libnm-core-impl/nm-setting-ovs-interface.c +src/libnm-core-impl/nm-setting-ovs-other-config.c src/libnm-core-impl/nm-setting-ovs-patch.c src/libnm-core-impl/nm-setting-ovs-port.c src/libnm-core-impl/nm-setting-ppp.c diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index c6232374d3..c4e163d1b7 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -59,6 +59,7 @@ #include "settings/nm-settings.h" #include "nm-setting-ethtool.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-user.h" #include "nm-auth-utils.h" #include "nm-keep-alive.h" @@ -12813,7 +12814,9 @@ can_reapply_change(NMDevice *self, goto out_fail; } - if (nm_streq(setting_name, NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME) + if (NM_IN_STRSET(setting_name, + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME) && NM_DEVICE_GET_CLASS(self)->can_reapply_change_ovs_external_ids) { /* TODO: this means, you cannot reapply changes to the external-ids for * OVS system interfaces. */ diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 10c7cfdbd2..7b319af344 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -16,6 +16,7 @@ #include "nm-setting-connection.h" #include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge @@ -129,7 +130,9 @@ nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnec nm_device_get_ip_iface(self), nm_connection_get_uuid(con_new), _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), - _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_OTHER_CONFIG), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index bda1fca3ad..d6422434c7 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -17,6 +17,7 @@ #include "devices/nm-device.h" #include "nm-manager.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-priv-helper-call.h" #include "libnm-platform/nm-platform.h" @@ -24,6 +25,8 @@ #define OVSDB_MAX_FAILURES 3 +#define OTHER_CONFIG_HWADDR "hwaddr" + /*****************************************************************************/ #if JANSSON_VERSION_HEX < 0x020400 @@ -32,6 +35,7 @@ typedef enum { STRDICT_TYPE_EXTERNAL_IDS, + STRDICT_TYPE_OTHER_CONFIG, } StrdictType; typedef struct { @@ -40,6 +44,7 @@ typedef struct { char *connection_uuid; GPtrArray *interfaces; /* interface uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchPort; typedef struct { @@ -48,6 +53,7 @@ typedef struct { char *connection_uuid; GPtrArray *ports; /* port uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchBridge; typedef struct { @@ -56,6 +62,7 @@ typedef struct { char *type; char *connection_uuid; GArray *external_ids; + GArray *other_config; } OpenvswitchInterface; /*****************************************************************************/ @@ -98,6 +105,8 @@ typedef union { char *connection_uuid; GHashTable *external_ids_old; GHashTable *external_ids_new; + GHashTable *other_config_old; + GHashTable *other_config_new; } set_reapply; } OvsdbMethodPayload; @@ -231,7 +240,9 @@ static void cleanup_check_ready(NMOvsdb *self); xifname, \ xconnection_uuid, \ xexternal_ids_old, \ - xexternal_ids_new) \ + xexternal_ids_new, \ + xother_config_old, \ + xother_config_new) \ (&((const OvsdbMethodPayload){ \ .set_reapply = \ { \ @@ -240,6 +251,8 @@ static void cleanup_check_ready(NMOvsdb *self); .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ .external_ids_old = (xexternal_ids_old), \ .external_ids_new = (xexternal_ids_new), \ + .other_config_old = (xother_config_old), \ + .other_config_new = (xother_config_new), \ }, \ })) @@ -300,6 +313,8 @@ _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) nm_clear_g_free(&call->payload.set_reapply.connection_uuid); nm_clear_pointer(&call->payload.set_reapply.external_ids_old, g_hash_table_destroy); nm_clear_pointer(&call->payload.set_reapply.external_ids_new, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_new, g_hash_table_destroy); break; } @@ -316,6 +331,7 @@ _free_bridge(OpenvswitchBridge *ovs_bridge) g_free(ovs_bridge->connection_uuid); g_ptr_array_free(ovs_bridge->ports, TRUE); nm_g_array_unref(ovs_bridge->external_ids); + nm_g_array_unref(ovs_bridge->other_config); nm_g_slice_free(ovs_bridge); } @@ -327,6 +343,7 @@ _free_port(OpenvswitchPort *ovs_port) g_free(ovs_port->connection_uuid); g_ptr_array_free(ovs_port->interfaces, TRUE); nm_g_array_unref(ovs_port->external_ids); + nm_g_array_unref(ovs_port->other_config); nm_g_slice_free(ovs_port); } @@ -338,6 +355,7 @@ _free_interface(OpenvswitchInterface *ovs_interface) g_free(ovs_interface->connection_uuid); g_free(ovs_interface->type); nm_g_array_unref(ovs_interface->external_ids); + nm_g_array_unref(ovs_interface->other_config); nm_g_slice_free(ovs_interface); } @@ -459,8 +477,12 @@ ovsdb_call_method(NMOvsdb *self, nm_g_hash_table_ref(payload->set_reapply.external_ids_old); call->payload.set_reapply.external_ids_new = nm_g_hash_table_ref(payload->set_reapply.external_ids_new); + call->payload.set_reapply.other_config_old = + nm_g_hash_table_ref(payload->set_reapply.other_config_old); + call->payload.set_reapply.other_config_new = + nm_g_hash_table_ref(payload->set_reapply.other_config_new); _LOGT_call(call, - "new: set-external-ids con-uuid=%s, interface=%s", + "new: set external-ids/other-config con-uuid=%s, interface=%s", call->payload.set_reapply.connection_uuid, call->payload.set_reapply.ifname); break; @@ -607,12 +629,12 @@ _set_bridge_mac(json_t *params, const char *ifname, const char *mac) "other_config", "delete", "set", - "hwaddr", + OTHER_CONFIG_HWADDR, "other_config", "insert", "map", - "hwaddr", + OTHER_CONFIG_HWADDR, mac, "where", @@ -680,8 +702,11 @@ _set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) } static json_t * -_j_create_strdict_new(NMConnection *connection, StrdictType strdict_type) +_j_create_strdict_new(NMConnection *connection, + StrdictType strdict_type, + const char *other_config_hwaddr) { + NMSettingOvsOtherConfig *s_other_config = NULL; NMSettingOvsExternalIDs *s_external_ids = NULL; json_t *array; const char *const *strv = NULL; @@ -690,7 +715,7 @@ _j_create_strdict_new(NMConnection *connection, StrdictType strdict_type) const char *uuid; nm_assert(NM_IS_CONNECTION(connection)); - nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); array = json_array(); @@ -699,6 +724,11 @@ _j_create_strdict_new(NMConnection *connection, StrdictType strdict_type) nm_assert(uuid); json_array_append_new(array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + } else { + if (other_config_hwaddr) { + json_array_append_new(array, + json_pack("[s, s]", OTHER_CONFIG_HWADDR, other_config_hwaddr)); + } } if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { @@ -706,15 +736,27 @@ _j_create_strdict_new(NMConnection *connection, StrdictType strdict_type) if (s_external_ids) strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); } else { - nm_assert_not_reached(); + s_other_config = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_OTHER_CONFIG); + if (s_other_config) + strv = nm_setting_ovs_other_config_get_data_keys(s_other_config, &n_strv); } for (i = 0; i < n_strv; i++) { const char *k = strv[i]; + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && other_config_hwaddr + && nm_streq(k, OTHER_CONFIG_HWADDR)) { + /* "hwaddr" is explicitly overwritten. */ + continue; + } + json_array_append_new( array, - json_pack("[s, s]", k, nm_setting_ovs_external_ids_get_data(s_external_ids, k))); + json_pack("[s, s]", + k, + strdict_type == STRDICT_TYPE_EXTERNAL_IDS + ? nm_setting_ovs_external_ids_get_data(s_external_ids, k) + : nm_setting_ovs_other_config_get_data(s_other_config, k))); } return json_pack("[s, o]", "map", array); @@ -732,13 +774,21 @@ _j_create_strv_array_update(json_t *mutations, const char *key; const char *val; + /* This is called during reapply. We accept reapplying all settings, + * except other_config:hwaddr. That one cannot change and is specially + * handled below. The reason is that we knew the correct "hwaddr" during + * _j_create_strdict_new(), but we don't do now. At least not easily, + * and it's not clear that reapply of the MAC address is really useful. */ + nm_assert((!!connection_uuid) == (strdict_type == STRDICT_TYPE_EXTERNAL_IDS)); - nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); array = NULL; if (hash_old) { g_hash_table_iter_init(&iter, hash_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) + continue; if (!array) array = json_array(); json_array_append_new(array, json_string(key)); @@ -747,6 +797,8 @@ _j_create_strv_array_update(json_t *mutations, if (hash_new) { g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) + continue; if (nm_g_hash_table_contains(hash_old, key)) continue; if (!array) @@ -786,6 +838,8 @@ _j_create_strv_array_update(json_t *mutations, if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) continue; } + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) + continue; json_array_append_new(array, json_pack("[s, s]", key, val)); } } @@ -868,7 +922,7 @@ _insert_interface(json_t *params, json_array_append_new(options, json_array()); } - row = json_pack("{s:s, s:s, s:o, s:o}", + row = json_pack("{s:s, s:s, s:o, s:o, s:o}", "name", nm_connection_get_interface_name(interface), "type", @@ -876,7 +930,9 @@ _insert_interface(json_t *params, "options", options, "external_ids", - _j_create_strdict_new(interface, STRDICT_TYPE_EXTERNAL_IDS)); + _j_create_strdict_new(interface, STRDICT_TYPE_EXTERNAL_IDS, NULL), + "other_config", + _j_create_strdict_new(interface, STRDICT_TYPE_OTHER_CONFIG, NULL)); if (cloned_mac) json_object_set_new(row, "mac", json_string(cloned_mac)); @@ -963,7 +1019,10 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); json_object_set_new(row, "external_ids", - _j_create_strdict_new(port, STRDICT_TYPE_EXTERNAL_IDS)); + _j_create_strdict_new(port, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(port, STRDICT_TYPE_OTHER_CONFIG, NULL)); /* Create a new one. */ json_array_append_new(params, @@ -1025,13 +1084,10 @@ _insert_bridge(json_t *params, json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); json_object_set_new(row, "external_ids", - _j_create_strdict_new(bridge, STRDICT_TYPE_EXTERNAL_IDS)); - - if (cloned_mac) { - json_object_set_new(row, - "other_config", - json_pack("[s, [[s, s]]]", "map", "hwaddr", cloned_mac)); - } + _j_create_strdict_new(bridge, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(bridge, STRDICT_TYPE_OTHER_CONFIG, cloned_mac)); /* Create a new one. */ json_array_append_new(params, @@ -1393,9 +1449,9 @@ ovsdb_next_command(NMOvsdb *self) switch (call->command) { case OVSDB_MONITOR: msg = json_pack("{s:I, s:s, s:[s, n, {" - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s]}]," " s:[{s:[s, s, s, s]}]," + " s:[{s:[s, s, s, s]}]," + " s:[{s:[s, s, s, s, s]}]," " s:[{s:[]}]" "}]}", "id", @@ -1409,16 +1465,19 @@ ovsdb_next_command(NMOvsdb *self) "name", "ports", "external_ids", + "other_config", "Port", "columns", "name", "interfaces", "external_ids", + "other_config", "Interface", "columns", "name", "type", "external_ids", + "other_config", "error", "Open_vSwitch", "columns"); @@ -1470,6 +1529,11 @@ ovsdb_next_command(NMOvsdb *self) call->payload.set_reapply.connection_uuid, call->payload.set_reapply.external_ids_old, call->payload.set_reapply.external_ids_new); + _j_create_strv_array_update(mutations, + STRDICT_TYPE_OTHER_CONFIG, + NULL, + call->payload.set_reapply.other_config_old, + call->payload.set_reapply.other_config_new); json_array_append_new( params, @@ -1684,6 +1748,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_t *interface = NULL; json_t *items; json_t *external_ids; + json_t *other_config; json_error_t json_error = { 0, }; @@ -1723,12 +1788,13 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_object_foreach (interface, key, value) { OpenvswitchInterface *ovs_interface; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; json_t *error = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:s, s?:o, s:o}}", + "{s:{s:s, s:s, s?:o, s:o, s:o}}", "new", "name", &name, @@ -1737,7 +1803,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) "error", &error, "external_ids", - &external_ids); + &external_ids, + "other_config", + &other_config); if (r != 0) { gpointer unused; @@ -1783,6 +1851,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) _strdict_extract(external_ids, &external_ids_arr); connection_uuid = _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); if (ovs_interface) { gboolean changed = FALSE; @@ -1795,10 +1864,16 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_interface->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_interface->other_config, other_config_arr)) { + NM_SWAP(&ovs_interface->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s", + _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s, " + "other-config=%s", key, type, ovs_interface->name, @@ -1806,10 +1881,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp1 = _strdict_to_string(ovs_interface->external_ids))); + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); } } else { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_interface = g_slice_new(OpenvswitchInterface); *ovs_interface = (OpenvswitchInterface){ @@ -1818,17 +1895,20 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .type = g_strdup(type), .connection_uuid = g_strdup(connection_uuid), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->interfaces, ovs_interface); - _LOGT("obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s", - key, - ovs_interface->type, - ovs_interface->name, - NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", - ovs_interface->connection_uuid, - ""), - (strtmp1 = _strdict_to_string(ovs_interface->external_ids))); + _LOGT( + "obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s, other-config=%s", + key, + ovs_interface->type, + ovs_interface->name, + NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, + ", ", + ovs_interface->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -1849,16 +1929,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *interfaces = NULL; OpenvswitchPort *ovs_port; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "interfaces", &items); if (r != 0) { @@ -1895,6 +1978,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) _strdict_extract(external_ids, &external_ids_arr); connection_uuid = _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); interfaces = _uuids_to_array(items); @@ -1913,20 +1997,27 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_port->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_port->other_config, other_config_arr)) { + NM_SWAP(&ovs_port->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp1 = _strdict_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); } } else { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_port = g_slice_new(OpenvswitchPort); *ovs_port = (OpenvswitchPort){ @@ -1935,16 +2026,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .interfaces = g_steal_pointer(&interfaces), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->ports, ovs_port); - _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp1 = _strdict_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); } } @@ -1953,16 +2046,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *ports = NULL; OpenvswitchBridge *ovs_bridge; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "ports", &items); @@ -2003,6 +2099,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) _strdict_extract(external_ids, &external_ids_arr); connection_uuid = _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); ports = _uuids_to_array(items); @@ -2021,20 +2118,27 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_bridge->other_config, other_config_arr)) { + NM_SWAP(&ovs_bridge->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp1 = _strdict_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->external_ids))); } } else { gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_bridge = g_slice_new(OpenvswitchBridge); *ovs_bridge = (OpenvswitchBridge){ @@ -2043,16 +2147,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .ports = g_steal_pointer(&ports), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->bridges, ovs_bridge); - _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp1 = _strdict_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->other_config))); _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); } } @@ -2795,10 +2901,14 @@ nm_ovsdb_set_reapply(NMOvsdb *self, const char *ifname, const char *connection_uuid, NMSettingOvsExternalIDs *s_external_ids_old, - NMSettingOvsExternalIDs *s_external_ids_new) + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new) { gs_unref_hashtable GHashTable *external_ids_old = NULL; gs_unref_hashtable GHashTable *external_ids_new = NULL; + gs_unref_hashtable GHashTable *other_config_old = NULL; + gs_unref_hashtable GHashTable *other_config_new = NULL; external_ids_old = s_external_ids_old @@ -2809,6 +2919,15 @@ nm_ovsdb_set_reapply(NMOvsdb *self, ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_new)) : NULL; + other_config_old = + s_other_config_old + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_old)) + : NULL; + other_config_new = + s_other_config_new + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_new)) + : NULL; + ovsdb_call_method(self, NULL, NULL, @@ -2818,7 +2937,9 @@ nm_ovsdb_set_reapply(NMOvsdb *self, ifname, connection_uuid, external_ids_old, - external_ids_new)); + external_ids_new, + other_config_old, + other_config_new)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.h b/src/core/devices/ovs/nm-ovsdb.h index e6e35ccd7f..a022ff00ad 100644 --- a/src/core/devices/ovs/nm-ovsdb.h +++ b/src/core/devices/ovs/nm-ovsdb.h @@ -47,14 +47,14 @@ void nm_ovsdb_set_interface_mtu(NMOvsdb *self, NMOvsdbCallback callback, gpointer user_data); -struct _NMSettingOvsExternalIDs; - -void nm_ovsdb_set_reapply(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - struct _NMSettingOvsExternalIDs *s_external_ids_old, - struct _NMSettingOvsExternalIDs *s_external_ids_new); +void nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new); gboolean nm_ovsdb_is_ready(NMOvsdb *self); diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 78d2467c01..e6807e9d82 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1894,6 +1894,7 @@ global: nm_range_ref; nm_range_to_str; nm_range_unref; + nm_setting_ip_config_get_auto_route_ext_gw; nm_setting_ip_config_get_dhcp_iaid; nm_setting_ip_config_get_dhcp_iaid; nm_setting_ip_tunnel_get_fwmark; @@ -1901,6 +1902,11 @@ global: nm_setting_loopback_get_type; nm_setting_loopback_new; nm_setting_ovs_interface_get_ofport_request; + nm_setting_ovs_other_config_get_data; + nm_setting_ovs_other_config_get_data_keys; + nm_setting_ovs_other_config_get_type; + nm_setting_ovs_other_config_new; + nm_setting_ovs_other_config_set_data; nm_setting_ovs_port_add_trunk; nm_setting_ovs_port_clear_trunks; nm_setting_ovs_port_get_num_trunks; @@ -1908,7 +1914,6 @@ global: nm_setting_ovs_port_remove_trunk; nm_setting_ovs_port_remove_trunk_by_value; nm_setting_vlan_get_protocol; - nm_setting_ip_config_get_auto_route_ext_gw; nm_utils_ensure_gtypes; nm_version_info_capability_get_type; } libnm_1_40_0; diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.c b/src/libnm-core-aux-intern/nm-libnm-core-utils.c index 0e464fba42..c4bfd2bd73 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.c +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.c @@ -630,3 +630,104 @@ nm_utils_dnsname_normalize(int addr_family, const char *dns, char **out_free) *out_free = s; return s; } + +/*****************************************************************************/ + +/** + * nm_setting_ovs_other_config_check_key: + * @key: (allow-none): the key to check + * @error: a #GError, %NULL to ignore. + * + * Checks whether @key is a valid key for OVS' other-config. + * This means, the key cannot be %NULL, not too large and valid ASCII. + * Also, only digits and numbers are allowed with a few special + * characters. + * + * Returns: %TRUE if @key is a valid user data key. + */ +gboolean +nm_setting_ovs_other_config_check_key(const char *key, GError **error) +{ + gsize len; + + g_return_val_if_fail(!error || !*error, FALSE); + + if (!key || !key[0]) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("missing key")); + return FALSE; + } + len = strlen(key); + if (len > 255u) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key is too long")); + return FALSE; + } + if (!g_utf8_validate(key, len, NULL)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key must be UTF8")); + return FALSE; + } + if (!NM_STRCHAR_ALL(key, ch, nm_ascii_is_regular_char(ch))) { + /* Probably OVS is more forgiving about what makes a valid key for + * an other-key. However, we are strict (at least, for now). */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key contains invalid characters")); + return FALSE; + } + + return TRUE; +} + +/** + * nm_setting_ovs_other_config_check_val: + * @val: (allow-none): the value to check + * @error: a #GError, %NULL to ignore. + * + * Checks whether @val is a valid user data value. This means, + * value is not %NULL, not too large and valid UTF-8. + * + * Returns: %TRUE if @val is a valid user data value. + */ +gboolean +nm_setting_ovs_other_config_check_val(const char *val, GError **error) +{ + gsize len; + + g_return_val_if_fail(!error || !*error, FALSE); + + if (!val) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is missing")); + return FALSE; + } + + len = strlen(val); + if (len > (2u * 1024u)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is too large")); + return FALSE; + } + + if (!g_utf8_validate(val, len, NULL)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is not valid UTF8")); + return FALSE; + } + + return TRUE; +} diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.h b/src/libnm-core-aux-intern/nm-libnm-core-utils.h index 63e8be4ec1..18af1e1a1c 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.h +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.h @@ -308,4 +308,9 @@ const char *nm_utils_dnsname_construct(int ad const char *nm_utils_dnsname_normalize(int addr_family, const char *dns, char **out_free); +/*****************************************************************************/ + +gboolean nm_setting_ovs_other_config_check_key(const char *key, GError **error); +gboolean nm_setting_ovs_other_config_check_val(const char *val, GError **error); + #endif /* __NM_LIBNM_SHARED_UTILS_H__ */ diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in index 0c2bdb9f74..a5c1fd1699 100644 --- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in +++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in @@ -1879,6 +1879,14 @@ gprop-type="gchararray" /> + + + diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index f1bd2a081c..6408ae178a 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -33,6 +33,7 @@ libnm_core_settings_sources = files( 'nm-setting-ovs-dpdk.c', 'nm-setting-ovs-external-ids.c', 'nm-setting-ovs-interface.c', + 'nm-setting-ovs-other-config.c', 'nm-setting-ovs-patch.c', 'nm-setting-ovs-port.c', 'nm-setting-ppp.c', diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index 724a51c7f1..9a6ffc6f24 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -28,12 +28,14 @@ #include "nm-setting-private.h" #include "nm-setting-user.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "libnm-core-intern/nm-keyfile-utils.h" #define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options" -#define OVS_EXTERNAL_IDS_DATA_PREFIX "data." +/* used for "ovs-external-ids.data" and "ovs-other-config.data". */ +#define STRDICT_DATA_PREFIX "data." /*****************************************************************************/ @@ -1060,23 +1062,29 @@ ip_routing_rule_parser_full(KeyfileReaderInfo *info, } static void -_parser_full_ovs_external_ids_data(KeyfileReaderInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +_parser_full_strdict_data(KeyfileReaderInfo *info, + const NMMetaSettingInfo *setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty *pip, + NMSetting *setting) { - const char *setting_name = NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME; - gs_strfreev char **keys = NULL; + gs_strfreev char **keys = NULL; gsize n_keys; gsize i; + gboolean is_exid; - nm_assert(NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)); - nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); - nm_assert(nm_streq(setting_name, setting_info->setting_name)); - nm_assert(nm_streq(setting_name, nm_setting_get_name(setting))); + if (NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)) { + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); + is_exid = TRUE; + } else { + nm_assert(NM_IS_SETTING_OVS_OTHER_CONFIG(setting)); + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_OTHER_CONFIG_DATA)); + is_exid = FALSE; + } - keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + nm_assert(nm_streq(setting_info->setting_name, nm_setting_get_name(setting))); + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_info->setting_name, &n_keys, NULL); for (i = 0; i < n_keys; i++) { const char *key = keys[i]; @@ -1084,16 +1092,20 @@ _parser_full_ovs_external_ids_data(KeyfileReaderInfo *info, gs_free char *value = NULL; const char *name; - if (!NM_STR_HAS_PREFIX(key, OVS_EXTERNAL_IDS_DATA_PREFIX)) + if (!NM_STR_HAS_PREFIX(key, STRDICT_DATA_PREFIX)) continue; - value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + value = + nm_keyfile_plugin_kf_get_string(info->keyfile, setting_info->setting_name, key, NULL); if (!value) continue; - name = &key[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)]; + name = &key[NM_STRLEN(STRDICT_DATA_PREFIX)]; name = nm_keyfile_key_decode(name, &name_to_free); - nm_setting_ovs_external_ids_set_data(NM_SETTING_OVS_EXTERNAL_IDS(setting), name, value); + if (is_exid) + nm_setting_ovs_external_ids_set_data(NM_SETTING_OVS_EXTERNAL_IDS(setting), name, value); + else + nm_setting_ovs_other_config_set_data(NM_SETTING_OVS_OTHER_CONFIG(setting), name, value); } } @@ -2569,24 +2581,32 @@ tfilter_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, con } static void -_writer_full_ovs_external_ids_data(KeyfileWriterInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +_writer_full_strdict_data(KeyfileWriterInfo *info, + const NMMetaSettingInfo *setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty *pip, + NMSetting *setting) { GHashTable *hash; NMUtilsNamedValue data_static[300u / sizeof(NMUtilsNamedValue)]; gs_free NMUtilsNamedValue *data_free = NULL; const NMUtilsNamedValue *data; guint data_len; - char full_key_static[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX) + 300u]; + char full_key_static[NM_STRLEN(STRDICT_DATA_PREFIX) + 300u]; guint i; + gboolean is_exid; - nm_assert(NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)); - nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); + if (NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)) { + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); + is_exid = TRUE; + } else { + nm_assert(NM_IS_SETTING_OVS_OTHER_CONFIG(setting)); + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_OTHER_CONFIG_DATA)); + is_exid = FALSE; + } - hash = _nm_setting_ovs_external_ids_get_data(NM_SETTING_OVS_EXTERNAL_IDS(setting)); + hash = is_exid ? _nm_setting_ovs_external_ids_get_data(NM_SETTING_OVS_EXTERNAL_IDS(setting)) + : _nm_setting_ovs_other_config_get_data(NM_SETTING_OVS_OTHER_CONFIG(setting)); if (!hash) return; @@ -2594,7 +2614,7 @@ _writer_full_ovs_external_ids_data(KeyfileWriterInfo *info, if (data_len == 0) return; - memcpy(full_key_static, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)); + memcpy(full_key_static, STRDICT_DATA_PREFIX, NM_STRLEN(STRDICT_DATA_PREFIX)); for (i = 0; i < data_len; i++) { const char *key = data[i].name; @@ -2608,15 +2628,16 @@ _writer_full_ovs_external_ids_data(KeyfileWriterInfo *info, escaped_key = nm_keyfile_key_encode(key, &escaped_key_to_free); len = strlen(escaped_key) + 1u; - if (len >= G_N_ELEMENTS(full_key_static) - NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)) { - full_key_free = g_new(char, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX) + len); + if (len >= G_N_ELEMENTS(full_key_static) - NM_STRLEN(STRDICT_DATA_PREFIX)) { + full_key_free = g_new(char, NM_STRLEN(STRDICT_DATA_PREFIX) + len); full_key = full_key_free; - memcpy(full_key, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)); + memcpy(full_key, STRDICT_DATA_PREFIX, NM_STRLEN(STRDICT_DATA_PREFIX)); } - memcpy(&full_key[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)], escaped_key, len); + memcpy(&full_key[NM_STRLEN(STRDICT_DATA_PREFIX)], escaped_key, len); nm_keyfile_plugin_kf_set_string(info->keyfile, - NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + is_exid ? NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME + : NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME, full_key, val); } @@ -3077,10 +3098,18 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_OVS_EXTERNAL_IDS_DATA, .parser_no_check_key = TRUE, - .parser_full = _parser_full_ovs_external_ids_data, - .writer_full = _writer_full_ovs_external_ids_data, - .has_parser_full = TRUE, - .has_writer_full = TRUE, ), ), ), + .parser_full = _parser_full_strdict_data, + .writer_full = _writer_full_strdict_data, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_OVS_OTHER_CONFIG_DATA, + .parser_no_check_key = TRUE, + .parser_full = _parser_full_strdict_data, + .writer_full = _writer_full_strdict_data, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), PARSE_INFO_SETTING(NM_META_SETTING_TYPE_SERIAL, PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SERIAL_PARITY, .parser = parity_parser, ), ), ), diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c index e93a1555dc..190826718a 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -40,9 +40,10 @@ #include "nm-setting-match.h" #include "nm-setting-olpc-mesh.h" #include "nm-setting-ovs-bridge.h" -#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-dpdk.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-interface.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" @@ -410,6 +411,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_dpdk_get_type, }, + [NM_META_SETTING_TYPE_OVS_OTHER_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_other_config_get_type, + }, [NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS] = { .meta_type = NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, @@ -654,6 +662,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_MATCH, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_TEAM_PORT, diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c index d0f9104165..5468438098 100644 --- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c +++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c @@ -10,6 +10,7 @@ #include "nm-setting-private.h" #include "nm-utils-private.h" #include "nm-connection-private.h" +#include "nm-setting-ovs-other-config.h" #define MAX_NUM_KEYS 256 @@ -126,7 +127,7 @@ _nm_setting_ovs_verify_connection_type(GType gtype, NMConnection *connection, GE const char *slave_type; nm_assert(!connection || NM_IS_CONNECTION(connection)); - nm_assert(NM_IN_SET(gtype, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(gtype, NM_TYPE_SETTING_OVS_EXTERNAL_IDS, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); nm_assert(!error || !*error); if (!connection) { @@ -245,6 +246,8 @@ nm_setting_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting, guin NMSettingOvsExternalIDs *self = setting; NMSettingOvsExternalIDsPrivate *priv; + NM_SET_OUT(out_len, 0); + g_return_val_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self), NULL); priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); diff --git a/src/libnm-core-impl/nm-setting-ovs-other-config.c b/src/libnm-core-impl/nm-setting-ovs-other-config.c new file mode 100644 index 0000000000..ca46ae9576 --- /dev/null +++ b/src/libnm-core-impl/nm-setting-ovs-other-config.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2020, 2022 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-ovs-other-config.h" + +#include "nm-setting-private.h" +#include "nm-utils-private.h" +#include "nm-connection-private.h" + +#define MAX_NUM_KEYS 256 + +/*****************************************************************************/ + +/** + * SECTION:nm-setting-ovs-other-config + * @short_description: Other-config settings for OVS + * + * The #NMSettingOvsOtherConfig object is a #NMSetting subclass that allows to + * configure other_config settings for OVS. See also "other_config" in the + * "ovs-vswitchd.conf.db" manual for the keys that OVS supports. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingOvsOtherConfig, PROP_DATA, ); + +typedef struct { + GHashTable *data; + const char **data_keys; +} NMSettingOvsOtherConfigPrivate; + +/** + * NMSettingOvsOtherConfig: + * + * OVS Other Config Settings + * + * Since: 1.42 + */ +struct _NMSettingOvsOtherConfig { + NMSetting parent; + NMSettingOvsOtherConfigPrivate _priv; +}; + +struct _NMSettingOvsOtherConfigClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingOvsOtherConfig, nm_setting_ovs_other_config, NM_TYPE_SETTING) + +#define NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingOvsOtherConfig, NM_IS_SETTING_OVS_OTHER_CONFIG) + +/*****************************************************************************/ + +static GHashTable * +_create_data_hash(void) +{ + return g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); +} + +GHashTable * +_nm_setting_ovs_other_config_get_data(NMSettingOvsOtherConfig *self) +{ + return NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self)->data; +} + +/** + * nm_setting_ovs_other_config_get_data_keys: + * @setting: the #NMSettingOvsOtherConfig + * @out_len: (out): the length of the returned array + * + * Returns: (array length=out_len) (transfer none): a + * %NULL-terminated array containing each key from the table. + * + * Since: 1.42 + **/ +const char *const * +nm_setting_ovs_other_config_get_data_keys(NMSettingOvsOtherConfig *setting, guint *out_len) +{ + NMSettingOvsOtherConfig *self = setting; + NMSettingOvsOtherConfigPrivate *priv; + + NM_SET_OUT(out_len, 0); + + g_return_val_if_fail(NM_IS_SETTING_OVS_OTHER_CONFIG(self), NULL); + + priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + if (priv->data_keys) { + NM_SET_OUT(out_len, g_hash_table_size(priv->data)); + return priv->data_keys; + } + + priv->data_keys = nm_strdict_get_keys(priv->data, TRUE, out_len); + + /* don't return %NULL, but hijack the @data_keys fields as a pseudo + * empty strv array. */ + return priv->data_keys ?: ((const char **) &priv->data_keys); +} + +/*****************************************************************************/ + +/** + * nm_setting_ovs_other_config_get_data: + * @setting: the #NMSettingOvsOtherConfig instance + * @key: the other-config to lookup + * + * Since: 1.42 + * + * Returns: (transfer none): the value associated with @key or %NULL if no such + * value exists. + */ +const char * +nm_setting_ovs_other_config_get_data(NMSettingOvsOtherConfig *setting, const char *key) +{ + NMSettingOvsOtherConfig *self = setting; + NMSettingOvsOtherConfigPrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_OVS_OTHER_CONFIG(self), NULL); + g_return_val_if_fail(key, NULL); + + priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + if (!priv->data) + return NULL; + + return g_hash_table_lookup(priv->data, key); +} + +/** + * nm_setting_ovs_other_config_set_data: + * @setting: the #NMSettingOvsOtherConfig instance + * @key: the key to set + * @val: (allow-none): the value to set or %NULL to clear a key. + * + * Since: 1.42 + */ +void +nm_setting_ovs_other_config_set_data(NMSettingOvsOtherConfig *setting, + const char *key, + const char *val) +{ + NMSettingOvsOtherConfig *self = setting; + NMSettingOvsOtherConfigPrivate *priv; + + g_return_if_fail(NM_IS_SETTING_OVS_OTHER_CONFIG(self)); + + priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + if (!val) { + if (priv->data && g_hash_table_remove(priv->data, key)) + goto out_changed; + return; + } + + if (priv->data) { + const char *val2; + + if (g_hash_table_lookup_extended(priv->data, key, NULL, (gpointer *) &val2)) { + if (nm_streq(val, val2)) + return; + } + } else + priv->data = _create_data_hash(); + + g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val)); + +out_changed: + nm_clear_g_free(&priv->data_keys); + _notify(self, PROP_DATA); +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsOtherConfig *self = NM_SETTING_OVS_OTHER_CONFIG(setting); + NMSettingOvsOtherConfigPrivate *priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + if (priv->data) { + gs_free_error GError *local = NULL; + const char *const *keys; + guint len; + guint i; + + keys = nm_setting_ovs_other_config_get_data_keys(self, &len); + + for (i = 0; i < len; i++) { + const char *key = keys[i]; + const char *val = g_hash_table_lookup(priv->data, key); + + if (!nm_setting_ovs_other_config_check_key(key, &local)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid key \"%s\": %s"), + key, + local->message); + } else if (!nm_setting_ovs_other_config_check_val(val, &local)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid value for \"%s\": %s"), + key, + local->message); + } else + continue; + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_DATA); + return FALSE; + } + } + + if (priv->data && g_hash_table_size(priv->data) > MAX_NUM_KEYS) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("maximum number of entries reached (%u instead of %u)"), + g_hash_table_size(priv->data), + (unsigned) MAX_NUM_KEYS); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_DATA); + return FALSE; + } + + if (!_nm_setting_ovs_verify_connection_type(NM_TYPE_SETTING_OVS_OTHER_CONFIG, + connection, + error)) + return FALSE; + + return TRUE; +} + +static NMTernary +compare_fcn_data(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil) +{ + NMSettingOvsOtherConfigPrivate *priv; + NMSettingOvsOtherConfigPrivate *pri2; + + if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) + return NM_TERNARY_DEFAULT; + + if (!set_b) + return TRUE; + + priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(NM_SETTING_OVS_OTHER_CONFIG(set_a)); + pri2 = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(NM_SETTING_OVS_OTHER_CONFIG(set_b)); + return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal); +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingOvsOtherConfig *self = NM_SETTING_OVS_OTHER_CONFIG(object); + NMSettingOvsOtherConfigPrivate *priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + GHashTableIter iter; + GHashTable *data; + const char *key; + const char *val; + + switch (prop_id) { + case PROP_DATA: + data = _create_data_hash(); + if (priv->data) { + g_hash_table_iter_init(&iter, priv->data); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert(data, g_strdup(key), g_strdup(val)); + } + g_value_take_boxed(value, data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsOtherConfig *self = NM_SETTING_OVS_OTHER_CONFIG(object); + NMSettingOvsOtherConfigPrivate *priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + switch (prop_id) { + case PROP_DATA: + { + gs_unref_hashtable GHashTable *old = NULL; + GHashTableIter iter; + GHashTable *data; + const char *key; + const char *val; + + nm_clear_g_free(&priv->data_keys); + + old = g_steal_pointer(&priv->data); + + data = g_value_get_boxed(value); + if (nm_g_hash_table_size(data) <= 0) + return; + + priv->data = _create_data_hash(); + g_hash_table_iter_init(&iter, data); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val)); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_other_config_init(NMSettingOvsOtherConfig *self) +{} + +/** + * nm_setting_ovs_other_config_new: + * + * Creates a new #NMSettingOvsOtherConfig object with default values. + * + * Returns: (transfer full) (type NMSettingOvsOtherConfig): the new empty + * #NMSettingOvsOtherConfig object + * + * Since: 1.42 + */ +NMSetting * +nm_setting_ovs_other_config_new(void) +{ + return g_object_new(NM_TYPE_SETTING_OVS_OTHER_CONFIG, NULL); +} + +static void +finalize(GObject *object) +{ + NMSettingOvsOtherConfig *self = NM_SETTING_OVS_OTHER_CONFIG(object); + NMSettingOvsOtherConfigPrivate *priv = NM_SETTING_OVS_OTHER_CONFIG_GET_PRIVATE(self); + + g_free(priv->data_keys); + if (priv->data) + g_hash_table_unref(priv->data); + + G_OBJECT_CLASS(nm_setting_ovs_other_config_parent_class)->finalize(object); +} + +static void +nm_setting_ovs_other_config_class_init(NMSettingOvsOtherConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + GArray *properties_override = _nm_sett_info_property_override_create_array(); + + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + setting_class->verify = verify; + + /** + * NMSettingOvsOtherConfig:data: (type GHashTable(utf8,utf8)) + * + * A dictionary of key/value pairs with other_config settings for OVS. + * See also "other_config" in the "ovs-vswitchd.conf.db" manual for the keys + * that OVS supports. + * + * Since: 1.42 + **/ + obj_properties[PROP_DATA] = g_param_spec_boxed(NM_SETTING_OVS_OTHER_CONFIG_DATA, + "", + "", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj( + properties_override, + obj_properties[PROP_DATA], + NM_SETT_INFO_PROPERT_TYPE_GPROP(NM_G_VARIANT_TYPE("a{ss}"), + .typdata_from_dbus.gprop_fcn = _nm_utils_strdict_from_dbus, + .typdata_to_dbus.gprop_type = + NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_STRDICT, + .compare_fcn = compare_fcn_data, + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, + .from_dbus_is_full = TRUE)); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + NULL, + properties_override, + 0); +} diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index b57c23888f..de60afd1cb 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -121,7 +121,7 @@ test_nm_meta_setting_types_by_priority(void) G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == G_N_ELEMENTS(nm_meta_setting_types_by_priority)); - G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 53); + G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 54); arr = g_ptr_array_new_with_free_func(g_object_unref); diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 5d07f2c2c8..9e9d55aa09 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -395,6 +395,7 @@ GSList *_nm_vpn_plugin_info_list_load_dir(const char *dirname, /*****************************************************************************/ GHashTable *_nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *self); +GHashTable *_nm_setting_ovs_other_config_get_data(NMSettingOvsOtherConfig *self); /*****************************************************************************/ diff --git a/src/libnm-core-intern/nm-meta-setting-base-impl.h b/src/libnm-core-intern/nm-meta-setting-base-impl.h index ea2175f84c..0c2def90cd 100644 --- a/src/libnm-core-intern/nm-meta-setting-base-impl.h +++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h @@ -135,6 +135,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, NM_META_SETTING_TYPE_OVS_INTERFACE, + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_PPP, diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build index beeeaedd47..c54071303c 100644 --- a/src/libnm-core-public/meson.build +++ b/src/libnm-core-public/meson.build @@ -38,6 +38,7 @@ libnm_core_headers = files( 'nm-setting-ovs-dpdk.h', 'nm-setting-ovs-external-ids.h', 'nm-setting-ovs-interface.h', + 'nm-setting-ovs-other-config.h', 'nm-setting-ovs-patch.h', 'nm-setting-ovs-port.h', 'nm-setting-ppp.h', diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h index 4db0c86e3d..f285a0f6f1 100644 --- a/src/libnm-core-public/nm-core-types.h +++ b/src/libnm-core-public/nm-core-types.h @@ -42,6 +42,7 @@ typedef struct _NMSettingMatch NMSettingMatch; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; typedef struct _NMSettingOvsBridge NMSettingOvsBridge; typedef struct _NMSettingOvsDpdk NMSettingOvsDpdk; +typedef struct _NMSettingOvsOtherConfig NMSettingOvsOtherConfig; typedef struct _NMSettingOvsExternalIDs NMSettingOvsExternalIDs; typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; diff --git a/src/libnm-core-public/nm-setting-ovs-other-config.h b/src/libnm-core-public/nm-setting-ovs-other-config.h new file mode 100644 index 0000000000..35de8ab2f8 --- /dev/null +++ b/src/libnm-core-public/nm-setting-ovs-other-config.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2020, 2022 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_OTHER_CONFIG_H__ +#define __NM_SETTING_OVS_OTHER_CONFIG_H__ + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_OTHER_CONFIG (nm_setting_ovs_other_config_get_type()) +#define NM_SETTING_OVS_OTHER_CONFIG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_OVS_OTHER_CONFIG, NMSettingOvsOtherConfig)) +#define NM_SETTING_OVS_OTHER_CONFIG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + NM_TYPE_SETTING_OVS_OTHER_CONFIG, \ + NMSettingOvsOtherConfigClass)) +#define NM_IS_SETTING_OVS_OTHER_CONFIG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_OVS_OTHER_CONFIG)) +#define NM_IS_SETTING_OVS_OTHER_CONFIG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_OVS_OTHER_CONFIG)) +#define NM_SETTING_OVS_OTHER_CONFIG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + NM_TYPE_SETTING_OVS_OTHER_CONFIG, \ + NMSettingOvsOtherConfigClass)) + +#define NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME "ovs-other-config" + +#define NM_SETTING_OVS_OTHER_CONFIG_DATA "data" + +typedef struct _NMSettingOvsOtherConfigClass NMSettingOvsOtherConfigClass; + +NM_AVAILABLE_IN_1_42 +GType nm_setting_ovs_other_config_get_type(void); + +NM_AVAILABLE_IN_1_42 +NMSetting *nm_setting_ovs_other_config_new(void); + +/*****************************************************************************/ + +NM_AVAILABLE_IN_1_42 +const char *const *nm_setting_ovs_other_config_get_data_keys(NMSettingOvsOtherConfig *setting, + guint *out_len); + +NM_AVAILABLE_IN_1_42 +const char *nm_setting_ovs_other_config_get_data(NMSettingOvsOtherConfig *setting, const char *key); + +NM_AVAILABLE_IN_1_42 +void nm_setting_ovs_other_config_set_data(NMSettingOvsOtherConfig *setting, + const char *key, + const char *val); + +/*****************************************************************************/ + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_OTHER_CONFIG_H__ */ diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index e93a1555dc..190826718a 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -40,9 +40,10 @@ #include "nm-setting-match.h" #include "nm-setting-olpc-mesh.h" #include "nm-setting-ovs-bridge.h" -#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-dpdk.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-interface.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" @@ -410,6 +411,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_dpdk_get_type, }, + [NM_META_SETTING_TYPE_OVS_OTHER_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_other_config_get_type, + }, [NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS] = { .meta_type = NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, @@ -654,6 +662,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_MATCH, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_TEAM_PORT, diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h index ea2175f84c..0c2def90cd 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.h +++ b/src/libnmc-setting/nm-meta-setting-base-impl.h @@ -135,6 +135,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, NM_META_SETTING_TYPE_OVS_INTERFACE, + NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_PPP, diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 4315c373a4..199f30bfb5 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -8413,6 +8413,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_OLPC_MESH N_("OLPC Mesh connection") #define SETTING_PRETTY_NAME_OVS_BRIDGE N_("Open vSwitch bridge settings") #define SETTING_PRETTY_NAME_OVS_DPDK N_("Open vSwitch DPDK interface settings") +#define SETTING_PRETTY_NAME_OVS_OTHER_CONFIG N_("OVS Other Config") #define SETTING_PRETTY_NAME_OVS_EXTERNAL_IDS N_("OVS External IDs") #define SETTING_PRETTY_NAME_OVS_INTERFACE N_("Open vSwitch interface settings") #define SETTING_PRETTY_NAME_OVS_PATCH N_("Open vSwitch patch interface settings") @@ -8611,6 +8612,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (OVS_DPDK, TRUE), ), ), + SETTING_INFO_EMPTY (OVS_OTHER_CONFIG), SETTING_INFO_EMPTY (OVS_EXTERNAL_IDS), SETTING_INFO (OVS_INTERFACE, .valid_parts = NM_META_SETTING_VALID_PARTS ( diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index e32ece0275..9d0a34883a 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -438,5 +438,6 @@ #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).") #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") #define DESCRIBE_DOC_NM_SETTING_LOOPBACK_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") -#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.") +#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with external-ids for OVS.") +#define DESCRIBE_DOC_NM_SETTING_OVS_OTHER_CONFIG_DATA N_("A dictionary of key/value pairs with other_config settings for OVS. See also \"other_config\" in the \"ovs-vswitchd.conf.db\" manual for the keys that OVS supports.") #define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 3fd4f6d3fc..469360e24b 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -848,6 +848,8 @@ + + diff --git a/tools/check-docs.sh b/tools/check-docs.sh index ecf42d0387..2746848c1e 100755 --- a/tools/check-docs.sh +++ b/tools/check-docs.sh @@ -88,6 +88,7 @@ F1_EXTRA=" xml/annotation-glossary.xml xml/api-index-full.xml xml/nm-setting-ovs-external-ids.xml +xml/nm-setting-ovs-other-config.xml xml/nm-version-macros.xml xml/nm-secret-agent-old.xml xml/nm-vpn-plugin-old.xml -- cgit v1.2.1