summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-11-10 13:50:00 +0100
committerThomas Haller <thaller@redhat.com>2020-11-10 13:50:00 +0100
commitb55f13406f093d5cb9f6305a74b90c373e480713 (patch)
tree568db365ce407131657c396df041936f68c68f58
parent9c3cfebe14610a9dcf9b03681428916424b95eb8 (diff)
parentbac5dc99d7a983f6323aeb4c3484c178c3d90241 (diff)
downloadNetworkManager-b55f13406f093d5cb9f6305a74b90c373e480713.tar.gz
ovs: merge branch 'th/ovs-external-ids' (first part of feature)
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/673
-rw-r--r--.clang-format2
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.examples1
-rw-r--r--clients/cli/generate-docs-nm-settings-nmcli.xml.in2
-rw-r--r--clients/common/nm-meta-setting-desc.c2
-rw-r--r--clients/common/settings-docs.h.in1
-rw-r--r--docs/libnm/libnm-docs.xml1
-rwxr-xr-xexamples/python/gi/ovs-external-ids.py425
-rw-r--r--libnm-core/meson.build6
-rw-r--r--libnm-core/nm-core-internal.h4
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-keyfile/nm-keyfile.c107
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h5
-rw-r--r--libnm-core/nm-setting-ovs-external-ids.c536
-rw-r--r--libnm-core/nm-setting-ovs-external-ids.h68
-rw-r--r--libnm-core/nm-setting-user.c12
-rw-r--r--libnm-core/nm-setting.c8
-rw-r--r--libnm/libnm.ver8
-rw-r--r--libnm/nm-client.h5
-rw-r--r--libnm/nm-libnm-utils.c39
-rw-r--r--po/POTFILES.in1
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c154
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h50
-rw-r--r--shared/nm-glib-aux/nm-str-buf.h27
-rw-r--r--shared/nm-glib-aux/tests/test-shared-general.c10
-rw-r--r--shared/nm-meta-setting.c8
-rw-r--r--shared/nm-meta-setting.h1
-rw-r--r--src/devices/adsl/nm-device-adsl.c2
-rw-r--r--src/devices/bluetooth/nm-device-bt.c2
-rw-r--r--src/devices/nm-device-6lowpan.c2
-rw-r--r--src/devices/nm-device-bond.c2
-rw-r--r--src/devices/nm-device-bridge.c2
-rw-r--r--src/devices/nm-device-dummy.c2
-rw-r--r--src/devices/nm-device-ethernet.c2
-rw-r--r--src/devices/nm-device-ip-tunnel.c2
-rw-r--r--src/devices/nm-device-logging.h58
-rw-r--r--src/devices/nm-device-macsec.c2
-rw-r--r--src/devices/nm-device-macvlan.c2
-rw-r--r--src/devices/nm-device-ppp.c2
-rw-r--r--src/devices/nm-device-tun.c2
-rw-r--r--src/devices/nm-device-veth.c2
-rw-r--r--src/devices/nm-device-vlan.c2
-rw-r--r--src/devices/nm-device-vrf.c2
-rw-r--r--src/devices/nm-device-vxlan.c2
-rw-r--r--src/devices/nm-device-wireguard.c2
-rw-r--r--src/devices/nm-device-wpan.c2
-rw-r--r--src/devices/nm-device.c49
-rw-r--r--src/devices/ovs/nm-device-ovs-bridge.c2
-rw-r--r--src/devices/ovs/nm-device-ovs-interface.c2
-rw-r--r--src/devices/ovs/nm-device-ovs-port.c2
-rw-r--r--src/devices/ovs/nm-ovs-factory.c18
-rw-r--r--src/devices/ovs/nm-ovsdb.c1148
-rw-r--r--src/devices/team/nm-device-team.c2
-rw-r--r--src/devices/wifi/nm-device-iwd.c2
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c2
-rw-r--r--src/devices/wifi/nm-device-wifi-p2p.c2
-rw-r--r--src/devices/wifi/nm-device-wifi.c2
-rw-r--r--src/devices/wwan/nm-device-modem.c2
58 files changed, 2182 insertions, 631 deletions
diff --git a/.clang-format b/.clang-format
index f84ea591c3..f0331adefc 100644
--- a/.clang-format
+++ b/.clang-format
@@ -85,6 +85,8 @@ ForEachMacros: ['c_list_for_each',
'c_rbtree_for_each_safe',
'c_rbtree_for_each_safe_postorder',
'c_rbtree_for_each_safe_postorder_unlink',
+ 'json_array_foreach',
+ 'json_object_foreach',
'json_object_foreach_safe',
'ndp_msg_opt_dnssl_for_each_domain',
'ndp_msg_opt_for_each_offset',
diff --git a/Makefile.am b/Makefile.am
index 473a763d74..dce16fe8c8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -954,6 +954,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-setting-olpc-mesh.h \
libnm-core/nm-setting-ovs-bridge.h \
libnm-core/nm-setting-ovs-dpdk.h \
+ libnm-core/nm-setting-ovs-external-ids.h \
libnm-core/nm-setting-ovs-interface.h \
libnm-core/nm-setting-ovs-patch.h \
libnm-core/nm-setting-ovs-port.h \
@@ -1027,6 +1028,7 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-olpc-mesh.c \
libnm-core/nm-setting-ovs-bridge.c \
libnm-core/nm-setting-ovs-dpdk.c \
+ libnm-core/nm-setting-ovs-external-ids.c \
libnm-core/nm-setting-ovs-interface.c \
libnm-core/nm-setting-ovs-patch.c \
libnm-core/nm-setting-ovs-port.c \
diff --git a/Makefile.examples b/Makefile.examples
index 3ac292fdd8..3cb46293bb 100644
--- a/Makefile.examples
+++ b/Makefile.examples
@@ -181,6 +181,7 @@ EXTRA_DIST += \
examples/python/gi/nm-keyfile.py \
examples/python/gi/nm-update2.py \
examples/python/gi/nm-wg-set \
+ examples/python/gi/ovs-external-ids.py \
examples/python/gi/setting-user-data.py \
examples/python/gi/show-wifi-networks.py \
examples/python/gi/update-ip4-method.py \
diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml.in b/clients/cli/generate-docs-nm-settings-nmcli.xml.in
index 25675a1ec7..f2f589fe8d 100644
--- a/clients/cli/generate-docs-nm-settings-nmcli.xml.in
+++ b/clients/cli/generate-docs-nm-settings-nmcli.xml.in
@@ -784,6 +784,8 @@
<property name="devargs"
description="Open vSwitch DPDK device arguments." />
</setting>
+ <setting name="ovs-external-ids" >
+ </setting>
<setting name="ovs-interface" >
<property name="type"
description="The interface type. Either &quot;internal&quot;, &quot;system&quot;, &quot;patch&quot;, &quot;dpdk&quot;, or empty." />
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index 2609c706fe..86b555fe5f 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -7946,6 +7946,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_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")
#define SETTING_PRETTY_NAME_OVS_PORT N_("Open vSwitch port settings")
@@ -8129,6 +8130,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
),
),
SETTING_INFO (OVS_DPDK),
+ SETTING_INFO_EMPTY (OVS_EXTERNAL_IDS),
SETTING_INFO (OVS_INTERFACE,
.valid_parts = NM_META_SETTING_VALID_PARTS (
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 5b93627245..78198ec973 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -294,6 +294,7 @@
#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.")
#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.")
#define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_DEVARGS N_("Open vSwitch DPDK device arguments.")
+#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_INTERFACE_TYPE N_("The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or empty.")
#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer.")
#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.")
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index 47b1fa1c08..d0be0eb475 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -338,6 +338,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-setting-ovs-dpdk.xml"/>
<xi:include href="xml/nm-setting-ovs-patch.xml"/>
<xi:include href="xml/nm-setting-ovs-port.xml"/>
+ <xi:include href="xml/nm-setting-ovs-external-ids.xml"/>
<xi:include href="xml/nm-setting-ppp.xml"/>
<xi:include href="xml/nm-setting-pppoe.xml"/>
<xi:include href="xml/nm-setting-proxy.xml"/>
diff --git a/examples/python/gi/ovs-external-ids.py b/examples/python/gi/ovs-external-ids.py
new file mode 100755
index 0000000000..e80da51120
--- /dev/null
+++ b/examples/python/gi/ovs-external-ids.py
@@ -0,0 +1,425 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2017, 2020 Red Hat, Inc.
+#
+
+#
+# set and show OVS external-ids for a connection:
+#
+
+import sys
+import os
+import re
+import pprint
+
+import gi
+
+gi.require_version("NM", "1.0")
+from gi.repository import GLib, NM
+
+MODE_GET = "get"
+MODE_SET = "set"
+
+
+def pr(v):
+ pprint.pprint(v, indent=4, depth=5, width=60)
+
+
+HAS_LIBNM_DEBUG = os.getenv("LIBNM_CLIENT_DEBUG") is not None
+
+
+def _print(msg=""):
+ if HAS_LIBNM_DEBUG:
+ # we want to use the same logging mechanism as libnm's debug
+ # logging with "LIBNM_CLIENT_DEBUG=trace,stdout".
+ NM.utils_print(0, msg + "\n")
+ return
+ print(msg)
+
+
+def mainloop_run(timeout_msec=0, mainloop=None):
+ if mainloop is None:
+ mainloop = GLib.MainLoop()
+
+ timeout_id = None
+ timeout_reached = []
+
+ if timeout_msec > 0:
+
+ def _timeout_cb(unused):
+ # it can happen that the caller already quit the mainloop
+ # otherwise. In that case, we don't want to signal a timeout.
+ if mainloop.is_running():
+ timeout_reached.append(1)
+ mainloop.quit()
+ return True
+
+ timeout_id = GLib.timeout_add(timeout_msec, _timeout_cb, None)
+
+ mainloop.run()
+ if timeout_id:
+ GLib.source_remove(timeout_id)
+ return not timeout_reached
+
+
+def usage():
+ _print("%s g[et] PROFILE [ GETTER ]" % (sys.argv[0]))
+ _print("%s s[et] [--test] PROFILE SETTER" % (sys.argv[0]))
+ _print(
+ " PROFILE := [id | uuid | type] STRING | [ ~id | ~type ] REGEX_STRING | STRING"
+ )
+ _print(" GETTER := ( KEY | ~REGEX_KEY ) [... GETTER]")
+ _print(" SETTER := ( + | - | -KEY | [+]KEY VALUE ) [... SETTER]")
+
+
+def die(msg, show_usage=False):
+ _print("FAILED: %s" % (msg))
+ if show_usage:
+ usage()
+ sys.exit(1)
+
+
+def die_usage(msg):
+ die(msg, show_usage=True)
+
+
+def parse_args(argv):
+ had_dash_dash = False
+ args = {
+ "mode": MODE_GET,
+ "profile_arg": None,
+ "ids_arg": [],
+ "do_test": False,
+ }
+ i = 1
+ while i < len(argv):
+ a = argv[i]
+
+ if i == 1:
+ if a in ["s", "set"]:
+ args["mode"] = MODE_SET
+ elif a in ["g", "get"]:
+ args["mode"] = MODE_GET
+ else:
+ die_usage("unexpected mode argument '%s'" % (a))
+ i += 1
+ continue
+
+ if a == "--test":
+ args["do_test"] = True
+ i += 1
+ continue
+
+ if args["profile_arg"] is None:
+ if a in ["id", "~id", "uuid", "type", "~type"]:
+ if i + 1 >= len(argv):
+ die_usage("'%s' requires an argument'" % (a))
+ args["profile_arg"] = (a, argv[i + 1])
+ i += 2
+ continue
+
+ if a == "*":
+ a = None
+ args["profile_arg"] = ("*", a)
+ i += 1
+ continue
+
+ if args["mode"] == MODE_GET:
+ args["ids_arg"].append(a)
+ i += 1
+ continue
+
+ if not a:
+ die_usage("argument should specify a external-id but is empty string")
+
+ if a[0] == "-":
+ v = (a, None)
+ i += 1
+ elif a == "+":
+ v = (a, None)
+ i += 1
+ else:
+ if a[0] != "+":
+ a = "+" + a
+ if i + 1 >= len(argv):
+ die_usage("'%s' requires an argument'" % (a))
+ v = (a, argv[i + 1])
+ i += 2
+
+ args["ids_arg"].append(v)
+
+ if args["mode"] == MODE_SET:
+ if not args["ids_arg"]:
+ die_usage("Requires one or more external-ids to set or delete")
+
+ return args
+
+
+def connection_to_str(connection, show_type=False):
+ if show_type:
+ return "%s (%s, %s)" % (
+ connection.get_id(),
+ connection.get_uuid(),
+ connection.get_connection_type(),
+ )
+ return "%s (%s)" % (connection.get_id(), connection.get_uuid())
+
+
+def connections_filter(connections, profile_arg):
+ connections = list(sorted(connections, key=connection_to_str))
+ if not profile_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 = profile_arg
+ for c in connections:
+ if f[0] == "id":
+ if f[1] == c.get_id():
+ l.append(c)
+ elif f[0] == "~id":
+ if re.match(f[1], c.get_id()):
+ l.append(c)
+ elif f[0] == "uuid":
+ if f[1] == c.get_uuid():
+ l.append(c)
+ elif f[0] == "type":
+ if f[1] == c.get_connection_type():
+ l.append(c)
+ elif f[0] == "~type":
+ if re.match(f[1], c.get_connection_type()):
+ l.append(c)
+ else:
+ assert f[0] == "*"
+ if f[1] is None:
+ l.append(c)
+ else:
+ if f[1] in [c.get_uuid(), c.get_id()]:
+ l.append(c)
+ return l
+
+
+def ids_select(ids, mode, ids_arg):
+ ids = list(ids)
+ if not ids_arg:
+ return (ids, [])
+
+ keys = set()
+ requested = []
+ for d in 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)])
+ else:
+ keys.update([k for k in ids if k == d])
+ if d not in requested:
+ requested.append(d)
+ else:
+ d2 = d[0]
+ assert d2[0] in ["-", "+"]
+ d3 = d2[1:]
+ if d3 in ids:
+ keys.add(d3)
+ return (list([k for k in ids if k in keys]), requested)
+
+
+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 = []
+ num_str = "none"
+
+ _print(
+ "%s%s [%s]" % (prefix, connection_to_str(connection, show_type=True), num_str)
+ )
+ _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" = <unset>' % (prefix, k))
+
+
+def do_get(connections, ids_arg):
+ first_line = True
+ for c in connections:
+ if first_line:
+ first_line = False
+ else:
+ _print()
+ connection_print(c, MODE_GET, ids_arg, dbus_path=c.get_path())
+
+
+def do_set(nmc, connection, ids_arg, do_test):
+
+ remote_connection = connection
+ connection = NM.SimpleConnection.new_clone(remote_connection)
+
+ connection_print(
+ connection, MODE_SET, [], remote_connection.get_path(), prefix="BEFORE: "
+ )
+ _print()
+
+ sett = connection.get_setting(NM.SettingOvsExternalIDs)
+
+ for d in ids_arg:
+ op = d[0][0]
+ key = d[0][1:]
+ val = d[1]
+
+ oldval = None
+ if sett is not None:
+ oldval = sett.get_data(key)
+
+ if op == "-":
+ assert val is None
+ if key == "":
+ if sett is None:
+ _print(" DEL: setting (ovs-external-ids group was not present)")
+ else:
+ connection.remove_setting(NM.SettingOvsExternalIDs)
+ sett = None
+ _print(" DEL: setting")
+ continue
+
+ if sett is None:
+ _print(' DEL: "%s" (ovs-external-ids group was not present)' % (key))
+ continue
+ if oldval is None:
+ _print(' DEL: "%s" (id was unset)' % (key))
+ continue
+ _print(' DEL: "%s" (id was set to"%s")' % (key, oldval))
+ sett.set_data(key, None)
+ continue
+
+ if key == "":
+ assert val is None
+ if sett is None:
+ sett = NM.SettingOvsExternalIDs.new()
+ connection.add_setting(sett)
+ _print(" SET: setting (external-ids group was added)")
+ continue
+
+ _print(" SET: setting (external-ids group was present)")
+ continue
+
+ assert val is not None
+
+ if sett is None:
+ sett = NM.SettingOvsExternalIDs.new()
+ connection.add_setting(sett)
+ _print(
+ ' SET: "%s" = "%s" (external-ids group was not present)' % (key, val)
+ )
+ elif oldval is None:
+ _print(' SET: "%s" = "%s" (new)' % (key, val))
+ elif oldval != val:
+ _print(' SET: "%s" = "%s" (was "%s")' % (key, val, oldval))
+ else:
+ _print(' SET: "%s" = "%s" (unchanged)' % (key, val))
+ sett.set_data(key, val)
+
+ if do_test:
+ _print()
+ _print("Only show. Run without --test to set")
+ return
+
+ mainloop = GLib.MainLoop()
+ result_error = []
+
+ def callback(c, result):
+ try:
+ c.update2_finish(result)
+ except Exception as e:
+ result_error.append(e)
+ mainloop.quit()
+
+ remote_connection.update2(
+ connection.to_dbus(NM.ConnectionSerializationFlags.ALL),
+ NM.SettingsUpdate2Flags.NO_REAPPLY,
+ None,
+ None,
+ callback,
+ )
+
+ mainloop_run(mainloop=mainloop)
+
+ if result_error:
+ _print()
+ _print("FAILURE to commit connection: %s" % (result_error[0]))
+ return
+
+ # NMClient received the completion of Update2() call. It also received
+ # a property changed signal that the profile changed, and it is about
+ # to fetch the new value. However, that value is not yet here.
+ #
+ # libnm should provide a better API for this. For example, not signal
+ # completion of update2() until the profile was refetched. Or, indicate
+ # that the settings are dirty, so we would know how long to wait.
+ #
+ # Add an ugly workaround here and wait a bit.
+ _print()
+ _print("WORKAROUND: wait for connection to change")
+ mainloop_run(timeout_msec=500)
+
+ if remote_connection is not nmc.get_object_by_path(remote_connection.get_path()):
+ _print()
+ _print(
+ "Connection %s no longer exists after commit"
+ % (remote_connection.get_path())
+ )
+ return
+
+ _print()
+ connection_print(
+ remote_connection, MODE_SET, [], remote_connection.get_path(), prefix="AFTER: "
+ )
+
+ _print()
+ if remote_connection.compare(connection, NM.SettingCompareFlags.EXACT):
+ _print("resulting connection is as expected")
+ else:
+ _print("WARNING: resulting connection is not as expected")
+
+
+###############################################################################
+
+if __name__ == "__main__":
+
+ args = parse_args(sys.argv)
+
+ nmc = NM.Client.new(None)
+
+ connections = connections_filter(nmc.get_connections(), args["profile_arg"])
+
+ 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])"
+ % (
+ len(connections),
+ ", ".join([connection_to_str(c) for c in connections]),
+ )
+ )
+ die_usage("Select unique connection to set")
+ 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")
+ die_usage("Select connection to get")
+ do_get(connections, args["ids_arg"])
diff --git a/libnm-core/meson.build b/libnm-core/meson.build
index aa8823c991..7b59a8c204 100644
--- a/libnm-core/meson.build
+++ b/libnm-core/meson.build
@@ -43,8 +43,9 @@ libnm_core_headers = files(
'nm-setting-match.h',
'nm-setting-olpc-mesh.h',
'nm-setting-ovs-bridge.h',
- 'nm-setting-ovs-interface.h',
'nm-setting-ovs-dpdk.h',
+ 'nm-setting-ovs-external-ids.h',
+ 'nm-setting-ovs-interface.h',
'nm-setting-ovs-patch.h',
'nm-setting-ovs-port.h',
'nm-setting-ppp.h',
@@ -143,8 +144,9 @@ libnm_core_settings_sources = files(
'nm-setting-match.c',
'nm-setting-olpc-mesh.c',
'nm-setting-ovs-bridge.c',
- 'nm-setting-ovs-interface.c',
'nm-setting-ovs-dpdk.c',
+ 'nm-setting-ovs-external-ids.c',
+ 'nm-setting-ovs-interface.c',
'nm-setting-ovs-patch.c',
'nm-setting-ovs-port.c',
'nm-setting-ppp.c',
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index f296a77fa6..fcc38565d3 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -476,6 +476,10 @@ GSList *_nm_vpn_plugin_info_list_load_dir(const char * dirname,
/*****************************************************************************/
+GHashTable *_nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *self);
+
+/*****************************************************************************/
+
typedef struct {
const char *name;
gboolean numeric;
diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h
index c2ac48e618..64d6464e2b 100644
--- a/libnm-core/nm-core-types.h
+++ b/libnm-core/nm-core-types.h
@@ -39,6 +39,7 @@ typedef struct _NMSettingMatch NMSettingMatch;
typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh;
typedef struct _NMSettingOvsBridge NMSettingOvsBridge;
typedef struct _NMSettingOvsDpdk NMSettingOvsDpdk;
+typedef struct _NMSettingOvsExternalIDs NMSettingOvsExternalIDs;
typedef struct _NMSettingOvsInterface NMSettingOvsInterface;
typedef struct _NMSettingOvsPatch NMSettingOvsPatch;
typedef struct _NMSettingOvsPort NMSettingOvsPort;
diff --git a/libnm-core/nm-keyfile/nm-keyfile.c b/libnm-core/nm-keyfile/nm-keyfile.c
index 1042d2d604..d3a1357281 100644
--- a/libnm-core/nm-keyfile/nm-keyfile.c
+++ b/libnm-core/nm-keyfile/nm-keyfile.c
@@ -24,9 +24,14 @@
#include "nm-core-internal.h"
#include "nm-keyfile.h"
#include "nm-setting-user.h"
+#include "nm-setting-ovs-external-ids.h"
#include "nm-keyfile-utils.h"
+#define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options"
+
+#define OVS_EXTERNAL_IDS_DATA_PREFIX "data."
+
/*****************************************************************************/
typedef struct _ParseInfoProperty ParseInfoProperty;
@@ -990,6 +995,44 @@ 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)
+{
+ const char * setting_name = NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME;
+ gs_strfreev char **keys = NULL;
+ gsize n_keys;
+ gsize i;
+
+ 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)));
+
+ keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL);
+
+ for (i = 0; i < n_keys; i++) {
+ const char * key = keys[i];
+ gs_free char *name_to_free = NULL;
+ gs_free char *value = NULL;
+ const char * name;
+
+ if (!NM_STR_HAS_PREFIX(key, OVS_EXTERNAL_IDS_DATA_PREFIX))
+ continue;
+
+ value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL);
+ if (!value)
+ continue;
+
+ name = &key[NM_STRLEN(OVS_EXTERNAL_IDS_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);
+ }
+}
+
+static void
ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
int addr_family;
@@ -2214,8 +2257,6 @@ bridge_vlan_writer(KeyfileWriterInfo *info,
}
}
-#define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options"
-
static void
wired_s390_options_parser_full(KeyfileReaderInfo * info,
const NMMetaSettingInfo * setting_info,
@@ -2361,6 +2402,60 @@ 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)
+{
+ 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];
+ guint i;
+
+ nm_assert(NM_IS_SETTING_OVS_EXTERNAL_IDS(setting));
+ nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA));
+
+ hash = _nm_setting_ovs_external_ids_get_data(NM_SETTING_OVS_EXTERNAL_IDS(setting));
+ if (!hash)
+ return;
+
+ data = nm_utils_named_values_from_strdict(hash, &data_len, data_static, &data_free);
+ if (data_len == 0)
+ return;
+
+ memcpy(full_key_static, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX));
+
+ for (i = 0; i < data_len; i++) {
+ const char * key = data[i].name;
+ const char * val = data[i].value_str;
+ gs_free char *escaped_key_to_free = NULL;
+ const char * escaped_key;
+ gsize len;
+ gs_free char *full_key_free = NULL;
+ char * full_key = full_key_static;
+
+ 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);
+ full_key = full_key_free;
+ memcpy(full_key, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX));
+ }
+ memcpy(&full_key[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)], escaped_key, len);
+
+ nm_keyfile_plugin_kf_set_string(info->keyfile,
+ NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME,
+ full_key,
+ val);
+ }
+}
+
+static void
write_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value)
{
GHashTable * hash;
@@ -2799,6 +2894,14 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
.writer_full = ip_routing_rule_writer_full,
.has_parser_full = TRUE,
.has_writer_full = TRUE, ), ), ),
+ PARSE_INFO_SETTING(
+ 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, ), ), ),
PARSE_INFO_SETTING(NM_META_SETTING_TYPE_SERIAL,
PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SERIAL_PARITY,
.parser = parity_parser, ), ), ),
diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h
index ca29eade24..ac7b3cc8e8 100644
--- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h
+++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h
@@ -98,6 +98,11 @@ gboolean nm_utils_vlan_priority_map_parse_str(NMVlanPriorityMap map_type,
/*****************************************************************************/
+#define NM_OVS_EXTERNAL_ID_NM_PREFIX "NM."
+#define NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID "NM.connection.uuid"
+
+/*****************************************************************************/
+
static inline int
nm_setting_ip_config_get_addr_family(NMSettingIPConfig *s_ip)
{
diff --git a/libnm-core/nm-setting-ovs-external-ids.c b/libnm-core/nm-setting-ovs-external-ids.c
new file mode 100644
index 0000000000..90fda48317
--- /dev/null
+++ b/libnm-core/nm-setting-ovs-external-ids.c
@@ -0,0 +1,536 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/*
+ * Copyright (C) 2017 - 2020 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-setting-ovs-external-ids.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-external-ids
+ * @short_description: External-IDs for OVS database
+ *
+ * The #NMSettingOvsExternalIDs object is a #NMSetting subclass that allow to
+ * configure external ids for OVS.
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingOvsExternalIDs, PROP_DATA, );
+
+typedef struct {
+ GHashTable * data;
+ const char **data_keys;
+} NMSettingOvsExternalIDsPrivate;
+
+/**
+ * NMSettingOvsExternalIDs:
+ *
+ * OVS External IDs Settings
+ */
+struct _NMSettingOvsExternalIDs {
+ NMSetting parent;
+ NMSettingOvsExternalIDsPrivate _priv;
+};
+
+struct _NMSettingOvsExternalIDsClass {
+ NMSettingClass parent;
+};
+
+G_DEFINE_TYPE(NMSettingOvsExternalIDs, nm_setting_ovs_external_ids, NM_TYPE_SETTING)
+
+#define NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self) \
+ _NM_GET_PRIVATE(self, NMSettingOvsExternalIDs, NM_IS_SETTING_OVS_EXTERNAL_IDS)
+
+/*****************************************************************************/
+
+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
+ * @error: a #GError, %NULL to ignore.
+ *
+ * Checks whether @key is a valid key for OVS' external-ids.
+ * 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. They key must also not start with "NM.".
+ *
+ * Since: 1.30
+ *
+ * Returns: %TRUE if @key is a valid user data key.
+ */
+gboolean
+nm_setting_ovs_external_ids_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, _exid_key_char_is_regular(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,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("key contains invalid characters"));
+ return FALSE;
+ }
+
+ if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) {
+ /* these keys are reserved. */
+ g_set_error_literal(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("key cannot start with \"NM.\""));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * nm_setting_ovs_external_ids_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.
+ *
+ * Since: 1.30
+ *
+ * Returns: %TRUE if @val is a valid user data value.
+ */
+gboolean
+nm_setting_ovs_external_ids_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 > (8u * 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;
+}
+
+/*****************************************************************************/
+
+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_external_ids_get_data(NMSettingOvsExternalIDs *self)
+{
+ return NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self)->data;
+}
+
+/**
+ * nm_setting_ovs_external_ids_get_data_keys:
+ * @setting: the #NMSettingOvsExternalIDs
+ * @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.
+ **/
+const char *const *
+nm_setting_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting, guint *out_len)
+{
+ NMSettingOvsExternalIDs * self = setting;
+ NMSettingOvsExternalIDsPrivate *priv;
+
+ g_return_val_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self), NULL);
+
+ priv = NM_SETTING_OVS_EXTERNAL_IDS_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_utils_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_external_ids_get_data:
+ * @setting: the #NMSettingOvsExternalIDs instance
+ * @key: the external-id to lookup
+ *
+ * Since: 1.30
+ *
+ * Returns: (transfer none): the value associated with @key or %NULL if no such
+ * value exists.
+ */
+const char *
+nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *setting, const char *key)
+{
+ NMSettingOvsExternalIDs * self = setting;
+ NMSettingOvsExternalIDsPrivate *priv;
+
+ g_return_val_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self), NULL);
+ g_return_val_if_fail(key, NULL);
+
+ priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self);
+
+ if (!priv->data)
+ return NULL;
+
+ return g_hash_table_lookup(priv->data, key);
+}
+
+/**
+ * nm_setting_ovs_external_ids_set_data:
+ * @setting: the #NMSettingOvsExternalIDs instance
+ * @key: the key to set
+ * @val: (allow-none): the value to set or %NULL to clear a key.
+ *
+ * Since: 1.30
+ */
+void
+nm_setting_ovs_external_ids_set_data(NMSettingOvsExternalIDs *setting,
+ const char * key,
+ const char * val)
+{
+ NMSettingOvsExternalIDs * self = setting;
+ NMSettingOvsExternalIDsPrivate *priv;
+
+ g_return_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self));
+
+ priv = NM_SETTING_OVS_EXTERNAL_IDS_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)
+{
+ NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(setting);
+ NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self);
+
+ if (priv->data) {
+ gs_free_error GError *local = NULL;
+ GHashTableIter iter;
+ const char * key;
+ const char * val;
+
+ 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,
+ NM_CONNECTION_ERROR_FAILED,
+ _("invalid key \"%s\": %s"),
+ key,
+ local->message);
+ } else if (!nm_setting_ovs_external_ids_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_EXTERNAL_IDS_SETTING_NAME,
+ NM_SETTING_OVS_EXTERNAL_IDS_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 user data 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_EXTERNAL_IDS_SETTING_NAME,
+ NM_SETTING_OVS_EXTERNAL_IDS_DATA);
+ return FALSE;
+ }
+
+ if (connection) {
+ const char *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)) {
+ 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"));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static NMTernary
+compare_property(const NMSettInfoSetting *sett_info,
+ guint property_idx,
+ NMConnection * con_a,
+ NMSetting * set_a,
+ NMConnection * con_b,
+ NMSetting * set_b,
+ NMSettingCompareFlags flags)
+{
+ NMSettingOvsExternalIDsPrivate *priv;
+ NMSettingOvsExternalIDsPrivate *pri2;
+
+ if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)) {
+ if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
+ return NM_TERNARY_DEFAULT;
+
+ if (!set_b)
+ return TRUE;
+
+ priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(NM_SETTING_OVS_EXTERNAL_IDS(set_a));
+ pri2 = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(NM_SETTING_OVS_EXTERNAL_IDS(set_b));
+ return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal);
+ }
+
+ return NM_SETTING_CLASS(nm_setting_ovs_external_ids_parent_class)
+ ->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags);
+}
+
+/*****************************************************************************/
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object);
+ NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_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)
+{
+ NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object);
+ NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_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_external_ids_init(NMSettingOvsExternalIDs *self)
+{}
+
+/**
+ * nm_setting_ovs_external_ids_new:
+ *
+ * Creates a new #NMSettingOvsExternalIDs object with default values.
+ *
+ * Returns: (transfer full) (type NMSettingOvsExternalIDs): the new empty
+ * #NMSettingOvsExternalIDs object
+ *
+ * Since: 1.30
+ */
+gpointer
+nm_setting_ovs_external_ids_new(void)
+{
+ return g_object_new(NM_TYPE_SETTING_OVS_EXTERNAL_IDS, NULL);
+}
+
+static void
+finalize(GObject *object)
+{
+ NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object);
+ NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self);
+
+ g_free(priv->data_keys);
+ if (priv->data)
+ g_hash_table_unref(priv->data);
+
+ G_OBJECT_CLASS(nm_setting_ovs_external_ids_parent_class)->finalize(object);
+}
+
+static void
+nm_setting_ovs_external_ids_class_init(NMSettingOvsExternalIDsClass *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->compare_property = compare_property;
+ setting_class->verify = verify;
+
+ /**
+ * NMSettingOvsExternalIDs:data: (type GHashTable(utf8,utf8))
+ *
+ * A dictionary of key/value pairs with exernal-ids for OVS.
+ *
+ * Since: 1.30
+ **/
+ obj_properties[PROP_DATA] = g_param_spec_boxed(NM_SETTING_OVS_EXTERNAL_IDS_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_strdict);
+
+ g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ _nm_setting_class_commit_full(setting_class,
+ NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS,
+ NULL,
+ properties_override);
+}
diff --git a/libnm-core/nm-setting-ovs-external-ids.h b/libnm-core/nm-setting-ovs-external-ids.h
new file mode 100644
index 0000000000..0f2442b48f
--- /dev/null
+++ b/libnm-core/nm-setting-ovs-external-ids.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/*
+ * Copyright (C) 2017 - 2020 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_OVS_EXTERNAL_IDS_H__
+#define __NM_SETTING_OVS_EXTERNAL_IDS_H__
+
+#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION)
+ #error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include "nm-setting.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_SETTING_OVS_EXTERNAL_IDS (nm_setting_ovs_external_ids_get_type())
+#define NM_SETTING_OVS_EXTERNAL_IDS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_OVS_EXTERNAL_IDS, NMSettingOvsExternalIDs))
+#define NM_SETTING_OVS_EXTERNAL_IDS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ NM_TYPE_SETTING_OVS_EXTERNAL_IDS, \
+ NMSettingOvsExternalIDsClass))
+#define NM_IS_SETTING_OVS_EXTERNAL_IDS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_OVS_EXTERNAL_IDS))
+#define NM_IS_SETTING_OVS_EXTERNAL_IDS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_OVS_EXTERNAL_IDS))
+#define NM_SETTING_OVS_EXTERNAL_IDS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ NM_TYPE_SETTING_OVS_EXTERNAL_IDS, \
+ NMSettingOvsExternalIDsClass))
+
+#define NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME "ovs-external-ids"
+
+#define NM_SETTING_OVS_EXTERNAL_IDS_DATA "data"
+
+typedef struct _NMSettingOvsExternalIDsClass NMSettingOvsExternalIDsClass;
+
+NM_AVAILABLE_IN_1_30
+GType nm_setting_ovs_external_ids_get_type(void);
+
+NM_AVAILABLE_IN_1_30
+void *nm_setting_ovs_external_ids_new(void);
+
+/*****************************************************************************/
+
+NM_AVAILABLE_IN_1_30
+const char *const *nm_setting_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting,
+ guint * out_len);
+
+NM_AVAILABLE_IN_1_30
+const char *nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *setting, const char *key);
+
+NM_AVAILABLE_IN_1_30
+void nm_setting_ovs_external_ids_set_data(NMSettingOvsExternalIDs *setting,
+ const char * key,
+ const char * val);
+
+/*****************************************************************************/
+
+NM_AVAILABLE_IN_1_30
+gboolean nm_setting_ovs_external_ids_check_key(const char *key, GError **error);
+NM_AVAILABLE_IN_1_30
+gboolean nm_setting_ovs_external_ids_check_val(const char *val, GError **error);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_OVS_EXTERNAL_IDS_H__ */
diff --git a/libnm-core/nm-setting-user.c b/libnm-core/nm-setting-user.c
index 3f0e03fb2a..ad3010e65c 100644
--- a/libnm-core/nm-setting-user.c
+++ b/libnm-core/nm-setting-user.c
@@ -288,7 +288,7 @@ nm_setting_user_set_data(NMSettingUser *setting, const char *key, const char *va
NMSettingUserPrivate *priv;
gboolean changed = FALSE;
- g_return_val_if_fail(NM_IS_SETTING(self), FALSE);
+ g_return_val_if_fail(NM_IS_SETTING_USER(self), FALSE);
g_return_val_if_fail(!error || !*error, FALSE);
if (!nm_setting_user_check_key(key, error))
@@ -416,11 +416,11 @@ compare_property(const NMSettInfoSetting *sett_info,
priv = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_a));
pri2 = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_b));
- return nm_utils_hash_table_equal(priv->data, pri2->data, TRUE, g_str_equal)
- && nm_utils_hash_table_equal(priv->data_invalid,
- pri2->data_invalid,
- TRUE,
- g_str_equal);
+ return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal)
+ && nm_utils_hashtable_equal(priv->data_invalid,
+ pri2->data_invalid,
+ TRUE,
+ g_str_equal);
}
return NM_SETTING_CLASS(nm_setting_user_parent_class)
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 0f62128908..28f1fedb06 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -1481,10 +1481,10 @@ _nm_setting_compare(NMConnection * con_a,
GenData *a_gendata = _gendata_hash(a, FALSE);
GenData *b_gendata = _gendata_hash(b, FALSE);
- return nm_utils_hash_table_equal(a_gendata ? a_gendata->hash : NULL,
- b_gendata ? b_gendata->hash : NULL,
- TRUE,
- g_variant_equal);
+ return nm_utils_hashtable_equal(a_gendata ? a_gendata->hash : NULL,
+ b_gendata ? b_gendata->hash : NULL,
+ TRUE,
+ g_variant_equal);
}
for (i = 0; i < sett_info->property_infos_len; i++) {
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 552e550646..0086fc01d2 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1766,4 +1766,12 @@ global:
nm_keyfile_read;
nm_keyfile_warn_severity_get_type;
nm_keyfile_write;
+ nm_setting_ovs_external_ids_check_key;
+ nm_setting_ovs_external_ids_check_val;
+ nm_setting_ovs_external_ids_get_data;
+ nm_setting_ovs_external_ids_get_data_keys;
+ nm_setting_ovs_external_ids_get_type;
+ nm_setting_ovs_external_ids_new;
+ nm_setting_ovs_external_ids_set_data;
+ nm_utils_print;
} libnm_1_28_0;
diff --git a/libnm/nm-client.h b/libnm/nm-client.h
index 86e9486e29..befd454f96 100644
--- a/libnm/nm-client.h
+++ b/libnm/nm-client.h
@@ -480,6 +480,11 @@ void nm_client_dbus_set_property(NMClient * client,
NM_AVAILABLE_IN_1_24
gboolean nm_client_dbus_set_property_finish(NMClient *client, GAsyncResult *result, GError **error);
+/*****************************************************************************/
+
+NM_AVAILABLE_IN_1_30
+void nm_utils_print(int output_mode, const char *msg);
+
G_END_DECLS
#endif /* __NM_CLIENT_H__ */
diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c
index 9c27f64de8..775aebf803 100644
--- a/libnm/nm-libnm-utils.c
+++ b/libnm/nm-libnm-utils.c
@@ -869,3 +869,42 @@ nm_utils_g_param_spec_is_default(const GParamSpec *pspec)
* strictly asserts and only support argument types that we expect. */
g_return_val_if_reached(FALSE);
}
+
+/*****************************************************************************/
+
+/**
+ * nm_utils_print:
+ * @output_mode: if 1 it uses g_print(). If 2, it uses g_printerr().
+ * If 0, it uses either g_print() or g_printerr(), depending
+ * on LIBNM_CLIENT_DEBUG (and the "stdout" flag).
+ * @msg: the message to print. The function does not append
+ * a trailing newline.
+ *
+ * The only purpose of this function is to give access to g_print()
+ * or g_printerr() from pygobject. libnm can do debug logging by
+ * setting LIBNM_CLIENT_DEBUG and uses thereby g_printerr() or
+ * g_print(). A plain "print()" function in python is not in sync
+ * with these functions (it implements additional buffering). By
+ * using nm_utils_print(), the same logging mechanisms can be used.
+ *
+ * Since: 1.30
+ */
+void
+nm_utils_print(int output_mode, const char *msg)
+{
+ gboolean use_stdout;
+
+ g_return_if_fail(msg);
+
+ if (output_mode == 0) {
+ nml_dbus_log_enabled_full(NML_DBUS_LOG_LEVEL_ANY, &use_stdout);
+ output_mode = use_stdout ? 1 : 2;
+ }
+
+ if (output_mode == 1)
+ g_print("%s", msg);
+ else if (output_mode == 2)
+ g_printerr("%s", msg);
+ else
+ g_return_if_reached();
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ea2eafa3f3..f2718ac648 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -82,6 +82,7 @@ libnm-core/nm-setting-macvlan.c
libnm-core/nm-setting-match.c
libnm-core/nm-setting-olpc-mesh.c
libnm-core/nm-setting-ovs-bridge.c
+libnm-core/nm-setting-ovs-external-ids.c
libnm-core/nm-setting-ovs-interface.c
libnm-core/nm-setting-ovs-patch.c
libnm-core/nm-setting-ovs-port.c
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 7f766871f6..b46e0c486e 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -434,6 +434,24 @@ nm_g_variant_singleton_u_0(void)
/*****************************************************************************/
+GHashTable *
+nm_utils_strdict_clone(GHashTable *src)
+{
+ GHashTable * dst;
+ GHashTableIter iter;
+ const char * key;
+ const char * val;
+
+ if (!src)
+ return NULL;
+
+ dst = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
+ g_hash_table_iter_init(&iter, src);
+ while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val))
+ g_hash_table_insert(dst, g_strdup(key), g_strdup(val));
+ return dst;
+}
+
/* Convert a hash table with "char *" keys and values to an "a{ss}" GVariant.
* The keys will be sorted asciibetically.
* Returns a floating reference.
@@ -3066,6 +3084,18 @@ nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll)
/*****************************************************************************/
+void
+nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val)
+{
+ if (val) {
+ gs_free gpointer x_name = NULL;
+ gs_free gpointer x_value = NULL;
+
+ x_name = (gpointer) g_steal_pointer(&val->name);
+ x_value = g_steal_pointer(&val->value_ptr);
+ }
+}
+
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, name) == 0);
NMUtilsNamedValue *
@@ -3262,6 +3292,62 @@ nm_utils_hash_values_to_array(GHashTable * hash,
return arr;
}
+/*****************************************************************************/
+
+/**
+ * nm_utils_hashtable_equal:
+ * @a: one #GHashTable
+ * @b: other #GHashTable
+ * @treat_null_as_empty: if %TRUE, when either @a or @b is %NULL, it is
+ * treated like an empty hash. It means, a %NULL hash will compare equal
+ * to an empty hash.
+ * @equal_func: the equality function, for comparing the values.
+ * If %NULL, the values are not compared. In that case, the function
+ * only checks, if both dictionaries have the same keys -- according
+ * to @b's key equality function.
+ * Note that the values of @a will be passed as first argument
+ * to @equal_func.
+ *
+ * Compares two hash tables, whether they have equal content.
+ * This only makes sense, if @a and @b have the same key types and
+ * the same key compare-function.
+ *
+ * Returns: %TRUE, if both dictionaries have the same content.
+ */
+gboolean
+nm_utils_hashtable_equal(const GHashTable *a,
+ const GHashTable *b,
+ gboolean treat_null_as_empty,
+ GEqualFunc equal_func)
+{
+ guint n;
+ GHashTableIter iter;
+ gconstpointer key, v_a, v_b;
+
+ if (a == b)
+ return TRUE;
+ if (!treat_null_as_empty) {
+ if (!a || !b)
+ return FALSE;
+ }
+
+ n = a ? g_hash_table_size((GHashTable *) a) : 0;
+ if (n != (b ? g_hash_table_size((GHashTable *) b) : 0))
+ return FALSE;
+
+ if (n > 0) {
+ g_hash_table_iter_init(&iter, (GHashTable *) a);
+ while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &v_a)) {
+ if (!g_hash_table_lookup_extended((GHashTable *) b, key, NULL, (gpointer *) &v_b))
+ return FALSE;
+ if (equal_func && !equal_func(v_a, v_b))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
static gboolean
_utils_hashtable_equal(GHashTable * hash_a,
GHashTable * hash_b,
@@ -3301,7 +3387,7 @@ _utils_hashtable_equal(GHashTable * hash_a,
}
/**
- * nm_utils_hashtable_equal:
+ * nm_utils_hashtable_cmp_equal:
* @a: (allow-none): the hash table or %NULL
* @b: (allow-none): the other hash table or %NULL
* @cmp_values: (allow-none): if %NULL, only the keys
@@ -3316,10 +3402,10 @@ _utils_hashtable_equal(GHashTable * hash_a,
* @cmp_values is given) all values are the same.
*/
gboolean
-nm_utils_hashtable_equal(const GHashTable *a,
- const GHashTable *b,
- GCompareDataFunc cmp_values,
- gpointer user_data)
+nm_utils_hashtable_cmp_equal(const GHashTable *a,
+ const GHashTable *b,
+ GCompareDataFunc cmp_values,
+ gpointer user_data)
{
GHashTable *hash_a = (GHashTable *) a;
GHashTable *hash_b = (GHashTable *) b;
@@ -3374,7 +3460,7 @@ _hashtable_cmp_func(gconstpointer a, gconstpointer b, gpointer user_data)
* @a: (allow-none): the hash to compare. May be %NULL.
* @b: (allow-none): the other hash to compare. May be %NULL.
* @do_fast_precheck: if %TRUE, assume that the hashes are equal
- * and that it is worth calling nm_utils_hashtable_equal() first.
+ * and that it is worth calling nm_utils_hashtable_cmp_equal() first.
* That requires, that both hashes have the same equals function
* which is compatible with the @cmp_keys function.
* @cmp_keys: the compare function for keys. Usually, the hash/equal function
@@ -3827,62 +3913,6 @@ nm_utils_array_find_binary_search(gconstpointer list,
/*****************************************************************************/
/**
- * nm_utils_hash_table_equal:
- * @a: one #GHashTable
- * @b: other #GHashTable
- * @treat_null_as_empty: if %TRUE, when either @a or @b is %NULL, it is
- * treated like an empty hash. It means, a %NULL hash will compare equal
- * to an empty hash.
- * @equal_func: the equality function, for comparing the values.
- * If %NULL, the values are not compared. In that case, the function
- * only checks, if both dictionaries have the same keys -- according
- * to @b's key equality function.
- * Note that the values of @a will be passed as first argument
- * to @equal_func.
- *
- * Compares two hash tables, whether they have equal content.
- * This only makes sense, if @a and @b have the same key types and
- * the same key compare-function.
- *
- * Returns: %TRUE, if both dictionaries have the same content.
- */
-gboolean
-nm_utils_hash_table_equal(const GHashTable * a,
- const GHashTable * b,
- gboolean treat_null_as_empty,
- NMUtilsHashTableEqualFunc equal_func)
-{
- guint n;
- GHashTableIter iter;
- gconstpointer key, v_a, v_b;
-
- if (a == b)
- return TRUE;
- if (!treat_null_as_empty) {
- if (!a || !b)
- return FALSE;
- }
-
- n = a ? g_hash_table_size((GHashTable *) a) : 0;
- if (n != (b ? g_hash_table_size((GHashTable *) b) : 0))
- return FALSE;
-
- if (n > 0) {
- g_hash_table_iter_init(&iter, (GHashTable *) a);
- while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &v_a)) {
- if (!g_hash_table_lookup_extended((GHashTable *) b, key, NULL, (gpointer *) &v_b))
- return FALSE;
- if (equal_func && !equal_func(v_a, v_b))
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-/*****************************************************************************/
-
-/**
* nm_utils_get_start_time_for_pid:
* @pid: the process identifier
* @out_state: return the state character, like R, S, Z. See `man 5 proc`.
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index e8aba6104c..cf01169d1c 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -320,6 +320,8 @@ gboolean nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize
GVariant *nm_utils_gbytes_to_variant_ay(GBytes *bytes);
+GHashTable *nm_utils_strdict_clone(GHashTable *src);
+
GVariant *nm_utils_strdict_to_variant_ass(GHashTable *strdict);
GVariant *nm_utils_strdict_to_variant_asv(GHashTable *strdict);
@@ -1460,6 +1462,8 @@ void nm_utils_named_value_list_sort(NMUtilsNamedValue *arr,
GCompareDataFunc compare_func,
gpointer user_data);
+void nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val);
+
/*****************************************************************************/
gpointer *nm_utils_hash_keys_to_array(GHashTable * hash,
@@ -1483,13 +1487,18 @@ nm_utils_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_le
gboolean nm_utils_hashtable_equal(const GHashTable *a,
const GHashTable *b,
- GCompareDataFunc cmp_values,
- gpointer user_data);
+ gboolean treat_null_as_empty,
+ GEqualFunc equal_func);
+
+gboolean nm_utils_hashtable_cmp_equal(const GHashTable *a,
+ const GHashTable *b,
+ GCompareDataFunc cmp_values,
+ gpointer user_data);
static inline gboolean
nm_utils_hashtable_same_keys(const GHashTable *a, const GHashTable *b)
{
- return nm_utils_hashtable_equal(a, b, NULL, NULL);
+ return nm_utils_hashtable_cmp_equal(a, b, NULL, NULL);
}
int nm_utils_hashtable_cmp(const GHashTable *a,
@@ -1534,6 +1543,13 @@ nm_g_array_len(const GArray *arr)
return arr ? arr->len : 0u;
}
+static inline void
+nm_g_array_unref(GArray *arr)
+{
+ if (arr)
+ g_array_unref(arr);
+}
+
#define nm_g_array_append_new(arr, type) \
({ \
GArray *const _arr = (arr); \
@@ -1689,15 +1705,6 @@ gssize nm_utils_array_find_binary_search(gconstpointer list,
/*****************************************************************************/
-typedef gboolean (*NMUtilsHashTableEqualFunc)(gconstpointer a, gconstpointer b);
-
-gboolean nm_utils_hash_table_equal(const GHashTable * a,
- const GHashTable * b,
- gboolean treat_null_as_empty,
- NMUtilsHashTableEqualFunc equal_func);
-
-/*****************************************************************************/
-
void _nm_utils_strv_sort(const char **strv, gssize len);
#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort(NM_CAST_STRV_MC(strv), len)
@@ -2204,6 +2211,25 @@ nm_utils_strdup_reset(char **dst, const char *src)
return TRUE;
}
+static inline gboolean
+nm_utils_strdup_reset_take(char **dst, char *src)
+{
+ char *old;
+
+ nm_assert(dst);
+ nm_assert(src != *dst);
+
+ if (nm_streq0(*dst, src)) {
+ if (src)
+ g_free(src);
+ return FALSE;
+ }
+ old = *dst;
+ *dst = src;
+ g_free(old);
+ return TRUE;
+}
+
void nm_indirect_g_free(gpointer arg);
/*****************************************************************************/
diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h
index 062630a5d2..f5e0bd8fe9 100644
--- a/shared/nm-glib-aux/nm-str-buf.h
+++ b/shared/nm-glib-aux/nm-str-buf.h
@@ -31,7 +31,7 @@ typedef struct _NMStrBuf {
/*****************************************************************************/
static inline void
-_nm_str_buf_assert(NMStrBuf *strbuf)
+_nm_str_buf_assert(const NMStrBuf *strbuf)
{
nm_assert(strbuf);
nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0));
@@ -361,6 +361,31 @@ nm_str_buf_get_str_unsafe(NMStrBuf *strbuf)
return strbuf->_priv_str;
}
+static inline char *
+nm_str_buf_get_str_at_unsafe(NMStrBuf *strbuf, gsize index)
+{
+ _nm_str_buf_assert(strbuf);
+
+ /* it is acceptable to ask for a pointer at the end of the buffer -- even
+ * if there is no data there. The caller is anyway required to take care
+ * of the length (that's the "unsafe" part), and in that case, the length
+ * is merely zero. */
+ nm_assert(index <= strbuf->allocated);
+
+ if (!strbuf->_priv_str)
+ return NULL;
+
+ return &strbuf->_priv_str[index];
+}
+
+static inline char
+nm_str_buf_get_char(const NMStrBuf *strbuf, gsize index)
+{
+ _nm_str_buf_assert(strbuf);
+ nm_assert(index < strbuf->allocated);
+ return strbuf->_priv_str[index];
+}
+
/**
* nm_str_buf_finalize:
* @strbuf: an initilized #NMStrBuf
diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c
index dbb8ed275e..13dd26f240 100644
--- a/shared/nm-glib-aux/tests/test-shared-general.c
+++ b/shared/nm-glib-aux/tests/test-shared-general.c
@@ -1190,8 +1190,8 @@ test_utils_hashtable_cmp(void)
}
g_assert(nm_utils_hashtable_same_keys(h1, h2));
- g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL));
- g_assert(nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL));
+ g_assert(nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
+ g_assert(nm_utils_hashtable_cmp_equal(h1, h2, func_val_cmp, NULL));
g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0);
@@ -1221,16 +1221,16 @@ again:
if (has_same_keys) {
g_assert(nm_utils_hashtable_same_keys(h1, h2));
- g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL));
+ g_assert(nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
} else {
g_assert(!nm_utils_hashtable_same_keys(h1, h2));
- g_assert(!nm_utils_hashtable_equal(h1, h2, NULL, NULL));
+ g_assert(!nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0);
g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0);
}
- g_assert(!nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL));
+ g_assert(!nm_utils_hashtable_cmp_equal(h1, h2, func_val_cmp, NULL));
g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0);
g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0);
}
diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c
index 51b90e6f05..5356b9a5de 100644
--- a/shared/nm-meta-setting.c
+++ b/shared/nm-meta-setting.c
@@ -33,6 +33,7 @@
#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-patch.h"
#include "nm-setting-ovs-port.h"
#include "nm-setting-ppp.h"
@@ -312,6 +313,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_EXTERNAL_IDS] =
+ {
+ .meta_type = NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS,
+ .setting_priority = NM_SETTING_PRIORITY_AUX,
+ .setting_name = NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME,
+ .get_setting_gtype = nm_setting_ovs_external_ids_get_type,
+ },
[NM_META_SETTING_TYPE_OVS_INTERFACE] =
{
.meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE,
diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h
index dadf2f7217..9d268e0ec2 100644
--- a/shared/nm-meta-setting.h
+++ b/shared/nm-meta-setting.h
@@ -128,6 +128,7 @@ typedef enum {
NM_META_SETTING_TYPE_MATCH,
NM_META_SETTING_TYPE_OVS_BRIDGE,
NM_META_SETTING_TYPE_OVS_DPDK,
+ NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS,
NM_META_SETTING_TYPE_OVS_INTERFACE,
NM_META_SETTING_TYPE_OVS_PATCH,
NM_META_SETTING_TYPE_OVS_PORT,
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
index 3261562399..556dfd829b 100644
--- a/src/devices/adsl/nm-device-adsl.c
+++ b/src/devices/adsl/nm-device-adsl.c
@@ -23,8 +23,8 @@
#include "nm-setting-adsl.h"
#include "nm-utils.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceAdsl
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceAdsl);
/*****************************************************************************/
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c
index c31961df92..ca2a59731d 100644
--- a/src/devices/bluetooth/nm-device-bt.c
+++ b/src/devices/bluetooth/nm-device-bt.c
@@ -30,8 +30,8 @@
#include "devices/wwan/nm-modem-manager.h"
#include "devices/wwan/nm-modem.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceBt
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceBt);
/*****************************************************************************/
diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c
index bf63fb7337..5ab0b933f6 100644
--- a/src/devices/nm-device-6lowpan.c
+++ b/src/devices/nm-device-6lowpan.c
@@ -14,8 +14,8 @@
#include "nm-setting-6lowpan.h"
#include "nm-utils.h"
+#define _NMLOG_DEVICE_TYPE NMDevice6Lowpan
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDevice6Lowpan);
/*****************************************************************************/
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 43f2a92ef4..0fa4be9158 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -17,8 +17,8 @@
#include "nm-core-internal.h"
#include "nm-ip4-config.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceBond
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceBond);
/*****************************************************************************/
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index 48dcec1b1d..930c93489f 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -15,8 +15,8 @@
#include "nm-device-factory.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceBridge
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceBridge);
/*****************************************************************************/
diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c
index 4f6b8cc234..364a634647 100644
--- a/src/devices/nm-device-dummy.c
+++ b/src/devices/nm-device-dummy.c
@@ -18,8 +18,8 @@
#include "nm-setting-dummy.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceDummy
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceDummy);
/*****************************************************************************/
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 2569c4262c..a1ea1cf93a 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -35,8 +35,8 @@
#include "NetworkManagerUtils.h"
#include "nm-udev-aux/nm-udev-utils.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceEthernet
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceEthernet);
/*****************************************************************************/
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
index e01cc7ff74..21307cab9e 100644
--- a/src/devices/nm-device-ip-tunnel.c
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -22,8 +22,8 @@
#include "nm-act-request.h"
#include "nm-ip4-config.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceIPTunnel
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceIPTunnel);
/*****************************************************************************/
diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h
index d12910207e..ff3d4180dc 100644
--- a/src/devices/nm-device-logging.h
+++ b/src/devices/nm-device-logging.h
@@ -8,36 +8,40 @@
#include "nm-device.h"
-#define _LOG_DECLARE_SELF(t) \
- _nm_unused static inline NMDevice *_nm_device_log_self_to_device(t *self) \
- { \
- return (NMDevice *) self; \
- }
+#if !_NM_CC_SUPPORT_GENERIC
+ #define _NM_DEVICE_CAST(self) ((NMDevice *) (self))
+#elif !defined(_NMLOG_DEVICE_TYPE)
+ #define _NM_DEVICE_CAST(self) _NM_ENSURE_TYPE(NMDevice *, self)
+#else
+ #define _NM_DEVICE_CAST(self) \
+ _Generic((self), _NMLOG_DEVICE_TYPE * \
+ : ((NMDevice *) (self)), NMDevice * \
+ : ((NMDevice *) (self)))
+#endif
#undef _NMLOG_ENABLED
#define _NMLOG_ENABLED(level, domain) (nm_logging_enabled((level), (domain)))
-#define _NMLOG(level, domain, ...) \
- G_STMT_START \
- { \
- const NMLogLevel _level = (level); \
- const NMLogDomain _domain = (domain); \
- \
- if (nm_logging_enabled(_level, _domain)) { \
- typeof(*self) *const _self = (self); \
- const char *const _ifname = \
- _nm_device_get_iface(_nm_device_log_self_to_device(_self)); \
- \
- nm_log_obj(_level, \
- _domain, \
- _ifname, \
- NULL, \
- _self, \
- "device", \
- "%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- NM_PRINT_FMT_QUOTED(_ifname, "(", _ifname, ")", "[null]") \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } \
+#define _NMLOG(level, domain, ...) \
+ G_STMT_START \
+ { \
+ const NMLogLevel _level = (level); \
+ const NMLogDomain _domain = (domain); \
+ \
+ if (nm_logging_enabled(_level, _domain)) { \
+ typeof(*self) *const _self = (self); \
+ const char *const _ifname = _nm_device_get_iface(_NM_DEVICE_CAST(_self)); \
+ \
+ nm_log_obj(_level, \
+ _domain, \
+ _ifname, \
+ NULL, \
+ _self, \
+ "device", \
+ "%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ NM_PRINT_FMT_QUOTED(_ifname, "(", _ifname, ")", "[null]") \
+ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+ } \
+ } \
G_STMT_END
#endif /* __NETWORKMANAGER_DEVICE_LOGGING_H__ */
diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c
index 7d738b4243..3e3ed30f4d 100644
--- a/src/devices/nm-device-macsec.c
+++ b/src/devices/nm-device-macsec.c
@@ -18,8 +18,8 @@
#include "supplicant/nm-supplicant-interface.h"
#include "supplicant/nm-supplicant-config.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceMacsec
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceMacsec);
/*****************************************************************************/
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index d9e71c8ca8..12c53a3b08 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -21,8 +21,8 @@
#include "nm-ip4-config.h"
#include "nm-utils.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceMacvlan
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceMacvlan);
/*****************************************************************************/
diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c
index 82861bdafc..0cdb7ac935 100644
--- a/src/devices/nm-device-ppp.c
+++ b/src/devices/nm-device-ppp.c
@@ -18,8 +18,8 @@
#include "ppp/nm-ppp-manager-call.h"
#include "ppp/nm-ppp-status.h"
+#define _NMLOG_DEVICE_TYPE NMDevicePpp
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDevicePpp);
/*****************************************************************************/
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index 9480525502..ae1550809b 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -19,8 +19,8 @@
#include "nm-setting-tun.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceTun
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceTun);
/*****************************************************************************/
diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c
index f61bc99f2a..7982a7faa4 100644
--- a/src/devices/nm-device-veth.c
+++ b/src/devices/nm-device-veth.c
@@ -13,8 +13,8 @@
#include "platform/nm-platform.h"
#include "nm-device-factory.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceVeth
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceVeth);
/*****************************************************************************/
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 8a743d1e62..5f036cd54b 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -22,8 +22,8 @@
#include "nm-core-internal.h"
#include "platform/nmp-object.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceVlan
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceVlan);
/*****************************************************************************/
diff --git a/src/devices/nm-device-vrf.c b/src/devices/nm-device-vrf.c
index ae0ecc60aa..9c3927e146 100644
--- a/src/devices/nm-device-vrf.c
+++ b/src/devices/nm-device-vrf.c
@@ -12,8 +12,8 @@
#include "platform/nm-platform.h"
#include "settings/nm-settings.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceVrf
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceVrf);
/*****************************************************************************/
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index 2ed66a644d..e9dd969886 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -19,8 +19,8 @@
#include "nm-ip4-config.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceVxlan
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceVxlan);
/*****************************************************************************/
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index 9bd23e6564..c8bc4bfcb2 100644
--- a/src/devices/nm-device-wireguard.c
+++ b/src/devices/nm-device-wireguard.c
@@ -22,8 +22,8 @@
#include "nm-act-request.h"
#include "dns/nm-dns-manager.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceWireGuard
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceWireGuard);
/*****************************************************************************/
diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c
index 195603dcde..f8e2b641ca 100644
--- a/src/devices/nm-device-wpan.c
+++ b/src/devices/nm-device-wpan.c
@@ -20,8 +20,8 @@
#include "nm-setting-wpan.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceWpan
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceWpan);
/*****************************************************************************/
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 6e53048bb4..b905855cf5 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -74,7 +74,6 @@
#include "nm-device-wireguard.h"
#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDevice);
/*****************************************************************************/
@@ -12388,28 +12387,34 @@ can_reapply_change(NMDevice * self,
NM_SETTING_CONNECTION_LLDP,
NM_SETTING_CONNECTION_MDNS,
NM_SETTING_CONNECTION_LLMNR);
- } else if (NM_IN_STRSET(setting_name,
- NM_SETTING_USER_SETTING_NAME,
- NM_SETTING_PROXY_SETTING_NAME,
- NM_SETTING_IP4_CONFIG_SETTING_NAME,
- NM_SETTING_IP6_CONFIG_SETTING_NAME)) {
+ }
+
+ if (NM_IN_STRSET(setting_name,
+ NM_SETTING_USER_SETTING_NAME,
+ NM_SETTING_PROXY_SETTING_NAME,
+ NM_SETTING_IP4_CONFIG_SETTING_NAME,
+ NM_SETTING_IP6_CONFIG_SETTING_NAME))
return TRUE;
- } else if (nm_streq(setting_name, NM_SETTING_WIRED_SETTING_NAME)
- && NM_IN_SET(NM_DEVICE_GET_CLASS(self)->get_configured_mtu,
- nm_device_get_configured_mtu_wired_parent,
- nm_device_get_configured_mtu_for_wired)) {
- return nm_device_hash_check_invalid_keys(diffs,
- NM_SETTING_WIRED_SETTING_NAME,
- error,
- NM_SETTING_WIRED_MTU);
- } else {
- g_set_error(error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "Can't reapply any changes to '%s' setting",
- setting_name);
- return FALSE;
+
+ if (nm_streq(setting_name, NM_SETTING_WIRED_SETTING_NAME)) {
+ if (NM_IN_SET(NM_DEVICE_GET_CLASS(self)->get_configured_mtu,
+ nm_device_get_configured_mtu_wired_parent,
+ nm_device_get_configured_mtu_for_wired)) {
+ return nm_device_hash_check_invalid_keys(diffs,
+ NM_SETTING_WIRED_SETTING_NAME,
+ error,
+ NM_SETTING_WIRED_MTU);
+ }
+ goto out_fail;
}
+
+out_fail:
+ g_set_error(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ "Can't reapply any changes to '%s' setting",
+ setting_name);
+ return FALSE;
}
static void
@@ -12552,6 +12557,8 @@ check_and_reapply_connection(NMDevice * self,
con_old = applied_clone = nm_simple_connection_new_clone(applied);
con_new = applied;
+ /* FIXME(applied-connection-immutable): we should not modify the applied
+ * connection but replace it with a new (immutable) instance. */
nm_connection_replace_settings_from_connection(applied, connection_clean);
nm_connection_clear_secrets(applied);
} else
diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c
index a7b7a539e2..6c92544c9c 100644
--- a/src/devices/ovs/nm-device-ovs-bridge.c
+++ b/src/devices/ovs/nm-device-ovs-bridge.c
@@ -14,8 +14,8 @@
#include "nm-setting-connection.h"
#include "nm-setting-ovs-bridge.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceOvsBridge);
/*****************************************************************************/
diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
index 16b6e04da0..0084c8bc58 100644
--- a/src/devices/ovs/nm-device-ovs-interface.c
+++ b/src/devices/ovs/nm-device-ovs-interface.c
@@ -14,8 +14,8 @@
#include "nm-setting-ovs-interface.h"
#include "nm-setting-ovs-port.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceOvsInterface
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceOvsInterface);
/*****************************************************************************/
diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c
index de98e29e06..d3a462753a 100644
--- a/src/devices/ovs/nm-device-ovs-port.c
+++ b/src/devices/ovs/nm-device-ovs-port.c
@@ -15,8 +15,8 @@
#include "nm-setting-ovs-port.h"
#include "nm-setting-ovs-port.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceOvsPort
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceOvsPort);
/*****************************************************************************/
diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c
index e1feacbd02..e25f94bf89 100644
--- a/src/devices/ovs/nm-ovs-factory.c
+++ b/src/devices/ovs/nm-ovs-factory.c
@@ -106,12 +106,10 @@ new_device_from_type(const char *name, NMDeviceType device_type)
}
static void
-ovsdb_device_added(NMOvsdb * ovsdb,
- const char * name,
- NMDeviceType device_type,
- NMDeviceFactory *self)
+ovsdb_device_added(NMOvsdb *ovsdb, const char *name, guint device_type_i, NMDeviceFactory *self)
{
- NMDevice *device = NULL;
+ const NMDeviceType device_type = device_type_i;
+ NMDevice * device;
device = new_device_from_type(name, device_type);
if (!device)
@@ -122,13 +120,11 @@ ovsdb_device_added(NMOvsdb * ovsdb,
}
static void
-ovsdb_device_removed(NMOvsdb * ovsdb,
- const char * name,
- NMDeviceType device_type,
- NMDeviceFactory *self)
+ovsdb_device_removed(NMOvsdb *ovsdb, const char *name, guint device_type_i, NMDeviceFactory *self)
{
- NMDevice * device;
- NMDeviceState device_state;
+ const NMDeviceType device_type = device_type_i;
+ NMDevice * device;
+ NMDeviceState device_state;
device = nm_manager_get_device(NM_MANAGER_GET, name, device_type);
if (!device)
diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
index 9826c1b7c5..bd55a8b341 100644
--- a/src/devices/ovs/nm-ovsdb.c
+++ b/src/devices/ovs/nm-ovsdb.c
@@ -17,26 +17,36 @@
/*****************************************************************************/
+#define OVSDB_MAX_FAILURES 3
+
+/*****************************************************************************/
+
#if JANSSON_VERSION_HEX < 0x020400
#warning "requires at least libjansson 2.4"
#endif
typedef struct {
+ char * port_uuid;
char * name;
char * connection_uuid;
GPtrArray *interfaces; /* interface uuids */
+ GArray * external_ids;
} OpenvswitchPort;
typedef struct {
+ char * bridge_uuid;
char * name;
char * connection_uuid;
GPtrArray *ports; /* port uuids */
+ GArray * external_ids;
} OpenvswitchBridge;
typedef struct {
- char *name;
- char *type;
- char *connection_uuid;
+ char * interface_uuid;
+ char * name;
+ char * type;
+ char * connection_uuid;
+ GArray *external_ids;
} OpenvswitchInterface;
/*****************************************************************************/
@@ -53,7 +63,7 @@ typedef struct {
size_t bufp; /* Last decoded byte in the input buffer. */
GString * input; /* JSON stream waiting for decoding. */
GString * output; /* JSON stream to be sent. */
- gint64 seq;
+ guint64 call_id_counter;
GArray * calls; /* Method calls waiting for a response. */
GHashTable * interfaces; /* interface uuid => OpenvswitchInterface */
GHashTable * ports; /* port uuid => OpenvswitchPort */
@@ -104,64 +114,107 @@ typedef enum {
OVSDB_SET_INTERFACE_MTU,
} OvsdbCommand;
+#define CALL_ID_UNSPEC G_MAXUINT64
+
+typedef union {
+ struct {
+ } monitor;
+ struct {
+ NMConnection *bridge;
+ NMConnection *port;
+ NMConnection *interface;
+ NMDevice * bridge_device;
+ NMDevice * interface_device;
+ } add_interface;
+ struct {
+ char *ifname;
+ } del_interface;
+ struct {
+ char * ifname;
+ guint32 mtu;
+ } set_interface_mtu;
+} OvsdbMethodPayload;
+
+#define OVSDB_METHOD_PAYLOAD_MONITOR() \
+ (&((const OvsdbMethodPayload){ \
+ .monitor = {}, \
+ }))
+
+#define OVSDB_METHOD_PAYLOAD_ADD_INTERFACE(xbridge, \
+ xport, \
+ xinterface, \
+ xbridge_device, \
+ xinterface_device) \
+ (&((const OvsdbMethodPayload){ \
+ .add_interface = \
+ { \
+ .bridge = (xbridge), \
+ .port = (xport), \
+ .interface = (xinterface), \
+ .bridge_device = (xbridge_device), \
+ .interface_device = (xinterface_device), \
+ }, \
+ }))
+
+#define OVSDB_METHOD_PAYLOAD_DEL_INTERFACE(xifname) \
+ (&((const OvsdbMethodPayload){ \
+ .del_interface = \
+ { \
+ .ifname = (char *) NM_CONSTCAST(char, (xifname)), \
+ }, \
+ }))
+
+#define OVSDB_METHOD_PAYLOAD_SET_INTERFACE_MTU(xifname, xmtu) \
+ (&((const OvsdbMethodPayload){ \
+ .set_interface_mtu = \
+ { \
+ .ifname = (char *) NM_CONSTCAST(char, (xifname)), \
+ .mtu = (xmtu), \
+ }, \
+ }))
+
typedef struct {
- gint64 id;
-#define COMMAND_PENDING -1 /* id not yet assigned */
+ guint64 call_id;
OvsdbCommand command;
OvsdbMethodCallback callback;
gpointer user_data;
- union {
- struct {
- char * ifname;
- guint32 mtu;
- };
- struct {
- NMConnection *bridge;
- NMConnection *port;
- NMConnection *interface;
- NMDevice * bridge_device;
- NMDevice * interface_device;
- };
- };
+ OvsdbMethodPayload payload;
} OvsdbMethodCall;
-#define OVSDB_MAX_FAILURES 3
+/*****************************************************************************/
static void
_LOGT_call_do(const char *comment, OvsdbMethodCall *call, json_t *msg)
{
- gs_free char *str = NULL;
+ gs_free char *msg_as_str = NULL;
- if (msg)
- str = json_dumps(msg, 0);
+#define _QUOTE_MSG(msg, msg_as_str) \
+ (msg) ? ": " : "", (msg) ? (msg_as_str = json_dumps((msg), 0)) : ""
switch (call->command) {
case OVSDB_MONITOR:
- _LOGT("%s: monitor%s%s", comment, msg ? ": " : "", msg ? str : "");
+ _LOGT("%s: monitor%s%s", comment, _QUOTE_MSG(msg, msg_as_str));
break;
case OVSDB_ADD_INTERFACE:
- _LOGT("%s: add-iface bridge=%s port=%s interface=%s%s%s",
+ _LOGT("%s: add-interface bridge=%s port=%s interface=%s%s%s",
comment,
- nm_connection_get_interface_name(call->bridge),
- nm_connection_get_interface_name(call->port),
- nm_connection_get_interface_name(call->interface),
- msg ? ": " : "",
- msg ? str : "");
+ nm_connection_get_interface_name(call->payload.add_interface.bridge),
+ nm_connection_get_interface_name(call->payload.add_interface.port),
+ nm_connection_get_interface_name(call->payload.add_interface.interface),
+ _QUOTE_MSG(msg, msg_as_str));
break;
case OVSDB_DEL_INTERFACE:
- _LOGT("%s: del-iface interface=%s%s%s",
+ _LOGT("%s: del-interface interface=%s%s%s",
comment,
- call->ifname,
- msg ? ": " : "",
- msg ? str : "");
+ call->payload.del_interface.ifname,
+ _QUOTE_MSG(msg, msg_as_str));
break;
case OVSDB_SET_INTERFACE_MTU:
- _LOGT("%s: set-iface-mtu interface=%s%s%s mtu=%u",
+ _LOGT("%s: set-interface-mtu interface=%s mtu=%u%s%s",
comment,
- call->ifname,
- msg ? ": " : "",
- msg ? str : "",
- call->mtu);
+ call->payload.set_interface_mtu.ifname,
+ call->payload.set_interface_mtu.mtu,
+ _QUOTE_MSG(msg, msg_as_str));
break;
}
}
@@ -174,6 +227,100 @@ _LOGT_call_do(const char *comment, OvsdbMethodCall *call, json_t *msg)
} \
G_STMT_END
+/*****************************************************************************/
+
+static void
+_clear_call(gpointer data)
+{
+ OvsdbMethodCall *call = data;
+
+ switch (call->command) {
+ case OVSDB_MONITOR:
+ break;
+ case OVSDB_ADD_INTERFACE:
+ g_clear_object(&call->payload.add_interface.bridge);
+ g_clear_object(&call->payload.add_interface.port);
+ g_clear_object(&call->payload.add_interface.interface);
+ g_clear_object(&call->payload.add_interface.bridge_device);
+ g_clear_object(&call->payload.add_interface.interface_device);
+ break;
+ case OVSDB_DEL_INTERFACE:
+ nm_clear_g_free(&call->payload.del_interface.ifname);
+ break;
+ case OVSDB_SET_INTERFACE_MTU:
+ nm_clear_g_free(&call->payload.set_interface_mtu.ifname);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+_free_bridge(OpenvswitchBridge *ovs_bridge)
+{
+ g_free(ovs_bridge->bridge_uuid);
+ g_free(ovs_bridge->name);
+ g_free(ovs_bridge->connection_uuid);
+ g_ptr_array_free(ovs_bridge->ports, TRUE);
+ nm_g_array_unref(ovs_bridge->external_ids);
+ nm_g_slice_free(ovs_bridge);
+}
+
+static void
+_free_port(OpenvswitchPort *ovs_port)
+{
+ g_free(ovs_port->port_uuid);
+ g_free(ovs_port->name);
+ g_free(ovs_port->connection_uuid);
+ g_ptr_array_free(ovs_port->interfaces, TRUE);
+ nm_g_array_unref(ovs_port->external_ids);
+ nm_g_slice_free(ovs_port);
+}
+
+static void
+_free_interface(OpenvswitchInterface *ovs_interface)
+{
+ g_free(ovs_interface->interface_uuid);
+ g_free(ovs_interface->name);
+ g_free(ovs_interface->connection_uuid);
+ g_free(ovs_interface->type);
+ nm_g_array_unref(ovs_interface->external_ids);
+ nm_g_slice_free(ovs_interface);
+}
+
+static gboolean
+_openvswitch_interface_should_emit_signal(const OpenvswitchInterface *ovs_interface)
+{
+ /* Currently, the factory only creates NMDevices for
+ * internal interfaces. We ignore the rest. */
+ return nm_streq0(ovs_interface->type, "internal");
+}
+
+/*****************************************************************************/
+
+static void
+_signal_emit_device_added(NMOvsdb *self, const char *name, NMDeviceType device_type)
+{
+ g_signal_emit(self, signals[DEVICE_ADDED], 0, name, (guint) device_type);
+}
+
+static void
+_signal_emit_device_removed(NMOvsdb *self, const char *name, NMDeviceType device_type)
+{
+ g_signal_emit(self, signals[DEVICE_REMOVED], 0, name, (guint) device_type);
+}
+
+static void
+_signal_emit_interface_failed(NMOvsdb * self,
+ const char *name,
+ const char *connection_uuid,
+ const char *error)
+{
+ g_signal_emit(self, signals[INTERFACE_FAILED], 0, name, connection_uuid, error);
+}
+
+/*****************************************************************************/
+
/**
* ovsdb_call_method:
*
@@ -181,18 +328,12 @@ _LOGT_call_do(const char *comment, OvsdbMethodCall *call, json_t *msg)
* there's no command pending completion.
*/
static void
-ovsdb_call_method(NMOvsdb * self,
- OvsdbCommand command,
- const char * ifname,
- NMConnection * bridge,
- NMConnection * port,
- NMConnection * interface,
- NMDevice * bridge_device,
- NMDevice * interface_device,
- guint32 mtu,
- OvsdbMethodCallback callback,
- gpointer user_data,
- gboolean add_first)
+ovsdb_call_method(NMOvsdb * self,
+ OvsdbMethodCallback callback,
+ gpointer user_data,
+ gboolean add_first,
+ OvsdbCommand command,
+ const OvsdbMethodPayload *payload)
{
NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self);
OvsdbMethodCall *call;
@@ -203,31 +344,42 @@ ovsdb_call_method(NMOvsdb * self,
if (add_first) {
g_array_prepend_val(priv->calls, (OvsdbMethodCall){});
call = &g_array_index(priv->calls, OvsdbMethodCall, 0);
- } else {
- g_array_set_size(priv->calls, priv->calls->len + 1);
- call = &g_array_index(priv->calls, OvsdbMethodCall, priv->calls->len - 1);
- }
- call->id = COMMAND_PENDING;
+ } else
+ call = nm_g_array_append_new(priv->calls, OvsdbMethodCall);
+
+ call->call_id = CALL_ID_UNSPEC;
call->command = command;
call->callback = callback;
call->user_data = user_data;
- switch (call->command) {
+ /* Mmigrate the arguments from @payload to @call->payload. Technically,
+ * this is not a plain copy, because
+ * - call->payload is not initialized (thus no need to free the previous data).
+ * - payload does not own the data. It is merely initialized using the
+ * OVSDB_METHOD_PAYLOAD_*() macros. */
+ switch (command) {
case OVSDB_MONITOR:
break;
case OVSDB_ADD_INTERFACE:
- call->bridge = nm_simple_connection_new_clone(bridge);
- call->port = nm_simple_connection_new_clone(port);
- call->interface = nm_simple_connection_new_clone(interface);
- call->bridge_device = g_object_ref(bridge_device);
- call->interface_device = g_object_ref(interface_device);
+ /* FIXME(applied-connection-immutable): we should not modify the applied
+ * connection, consequently there is no need to clone the connections. */
+ call->payload.add_interface.bridge =
+ nm_simple_connection_new_clone(payload->add_interface.bridge);
+ call->payload.add_interface.port =
+ nm_simple_connection_new_clone(payload->add_interface.port);
+ call->payload.add_interface.interface =
+ nm_simple_connection_new_clone(payload->add_interface.interface);
+ call->payload.add_interface.bridge_device =
+ g_object_ref(payload->add_interface.bridge_device);
+ call->payload.add_interface.interface_device =
+ g_object_ref(payload->add_interface.interface_device);
break;
case OVSDB_DEL_INTERFACE:
- call->ifname = g_strdup(ifname);
+ call->payload.del_interface.ifname = g_strdup(payload->del_interface.ifname);
break;
case OVSDB_SET_INTERFACE_MTU:
- call->ifname = g_strdup(ifname);
- call->mtu = mtu;
+ call->payload.set_interface_mtu.ifname = g_strdup(payload->set_interface_mtu.ifname);
+ call->payload.set_interface_mtu.mtu = payload->set_interface_mtu.mtu;
break;
}
@@ -496,7 +648,7 @@ _insert_interface(json_t * params,
options,
"external_ids",
"map",
- "NM.connection.uuid",
+ NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID,
nm_connection_get_uuid(interface));
if (cloned_mac)
@@ -562,10 +714,12 @@ _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",
- json_pack("[s, [[s, s]]]", "map", "NM.connection.uuid", nm_connection_get_uuid(port)));
+ json_object_set_new(row,
+ "external_ids",
+ json_pack("[s, [[s, s]]]",
+ "map",
+ NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID,
+ nm_connection_get_uuid(port)));
/* Create a new one. */
json_array_append_new(params,
@@ -625,10 +779,12 @@ _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",
- json_pack("[s, [[s, s]]]", "map", "NM.connection.uuid", nm_connection_get_uuid(bridge)));
+ json_object_set_new(row,
+ "external_ids",
+ json_pack("[s, [[s, s]]]",
+ "map",
+ NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID,
+ nm_connection_get_uuid(bridge)));
if (cloned_mac) {
json_object_set_new(row,
@@ -691,7 +847,6 @@ _add_interface(NMOvsdb * self,
{
NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self);
GHashTableIter iter;
- const char * bridge_uuid;
const char * port_uuid;
const char * interface_uuid;
const char * bridge_name;
@@ -761,43 +916,43 @@ _add_interface(NMOvsdb * self,
}
g_hash_table_iter_init(&iter, priv->bridges);
- while (g_hash_table_iter_next(&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) {
- json_array_append_new(bridges, json_pack("[s, s]", "uuid", bridge_uuid));
+ while (g_hash_table_iter_next(&iter, (gpointer) &ovs_bridge, NULL)) {
+ json_array_append_new(bridges, json_pack("[s, s]", "uuid", ovs_bridge->bridge_uuid));
- if (g_strcmp0(ovs_bridge->name, bridge_name) != 0
- || g_strcmp0(ovs_bridge->connection_uuid, nm_connection_get_uuid(bridge)) != 0)
+ if (!nm_streq0(ovs_bridge->name, bridge_name)
+ || !nm_streq0(ovs_bridge->connection_uuid, nm_connection_get_uuid(bridge)))
continue;
for (pi = 0; pi < ovs_bridge->ports->len; pi++) {
port_uuid = g_ptr_array_index(ovs_bridge->ports, pi);
- ovs_port = g_hash_table_lookup(priv->ports, port_uuid);
+ ovs_port = g_hash_table_lookup(priv->ports, &port_uuid);
json_array_append_new(ports, json_pack("[s, s]", "uuid", port_uuid));
if (!ovs_port) {
/* This would be a violation of ovsdb's reference integrity (a bug). */
- _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid);
- continue;
- } else if (strcmp(ovs_port->name, port_name) != 0
- || g_strcmp0(ovs_port->connection_uuid, nm_connection_get_uuid(port)) != 0) {
+ _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, ovs_bridge->bridge_uuid);
continue;
}
+ if (!nm_streq(ovs_port->name, port_name)
+ || !nm_streq0(ovs_port->connection_uuid, nm_connection_get_uuid(port)))
+ continue;
+
for (ii = 0; ii < ovs_port->interfaces->len; ii++) {
interface_uuid = g_ptr_array_index(ovs_port->interfaces, ii);
- ovs_interface = g_hash_table_lookup(priv->interfaces, interface_uuid);
+ ovs_interface = g_hash_table_lookup(priv->interfaces, &interface_uuid);
json_array_append_new(interfaces, json_pack("[s, s]", "uuid", interface_uuid));
if (!ovs_interface) {
/* This would be a violation of ovsdb's reference integrity (a bug). */
_LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid);
- } else if (strcmp(ovs_interface->name, interface_name) == 0
- && g_strcmp0(ovs_interface->connection_uuid,
- nm_connection_get_uuid(interface))
- == 0) {
- has_interface = TRUE;
+ continue;
}
+ if (nm_streq(ovs_interface->name, interface_name)
+ && nm_streq0(ovs_interface->connection_uuid, nm_connection_get_uuid(interface)))
+ has_interface = TRUE;
}
break;
@@ -853,7 +1008,6 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
{
NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self);
GHashTableIter iter;
- char * bridge_uuid;
char * port_uuid;
char * interface_uuid;
OpenvswitchBridge * ovs_bridge;
@@ -872,7 +1026,7 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
bridges_changed = FALSE;
g_hash_table_iter_init(&iter, priv->bridges);
- while (g_hash_table_iter_next(&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) {
+ while (g_hash_table_iter_next(&iter, (gpointer) &ovs_bridge, NULL)) {
nm_auto_decref_json json_t *ports = NULL;
nm_auto_decref_json json_t *new_ports = NULL;
@@ -880,7 +1034,7 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
new_ports = json_array();
ports_changed = FALSE;
- json_array_append_new(bridges, json_pack("[s,s]", "uuid", bridge_uuid));
+ json_array_append_new(bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
for (pi = 0; pi < ovs_bridge->ports->len; pi++) {
nm_auto_decref_json json_t *interfaces = NULL;
@@ -889,7 +1043,7 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
interfaces = json_array();
new_interfaces = json_array();
port_uuid = g_ptr_array_index(ovs_bridge->ports, pi);
- ovs_port = g_hash_table_lookup(priv->ports, port_uuid);
+ ovs_port = g_hash_table_lookup(priv->ports, &port_uuid);
json_array_append_new(ports, json_pack("[s,s]", "uuid", port_uuid));
@@ -897,18 +1051,18 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
if (!ovs_port) {
/* This would be a violation of ovsdb's reference integrity (a bug). */
- _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid);
+ _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, ovs_bridge->bridge_uuid);
continue;
}
for (ii = 0; ii < ovs_port->interfaces->len; ii++) {
interface_uuid = g_ptr_array_index(ovs_port->interfaces, ii);
- ovs_interface = g_hash_table_lookup(priv->interfaces, interface_uuid);
+ ovs_interface = g_hash_table_lookup(priv->interfaces, &interface_uuid);
json_array_append_new(interfaces, json_pack("[s,s]", "uuid", interface_uuid));
if (ovs_interface) {
- if (strcmp(ovs_interface->name, ifname) == 0) {
+ if (nm_streq(ovs_interface->name, ifname)) {
/* skip the interface */
interfaces_changed = TRUE;
continue;
@@ -939,7 +1093,7 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname)
_expect_bridge_ports(params, ovs_bridge->name, ports);
_set_bridge_ports(params, ovs_bridge->name, new_ports);
}
- json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", bridge_uuid));
+ json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid));
}
}
@@ -963,30 +1117,31 @@ static void
ovsdb_next_command(NMOvsdb *self)
{
NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self);
- OvsdbMethodCall * call = NULL;
+ OvsdbMethodCall * call;
char * cmd;
nm_auto_decref_json json_t *msg = NULL;
- json_t * params;
if (!priv->conn)
return;
if (!priv->calls->len)
return;
+
call = &g_array_index(priv->calls, OvsdbMethodCall, 0);
- if (call->id != COMMAND_PENDING)
+ if (call->call_id != CALL_ID_UNSPEC)
return;
- call->id = priv->seq++;
+
+ call->call_id = ++priv->call_id_counter;
switch (call->command) {
case OVSDB_MONITOR:
- msg = json_pack("{s:i, s:s, s:[s, n, {"
+ 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:[]}]"
"}]}",
"id",
- call->id,
+ (json_int_t) call->call_id,
"method",
"monitor",
"params",
@@ -1010,57 +1165,62 @@ ovsdb_next_command(NMOvsdb *self)
"Open_vSwitch",
"columns");
break;
- case OVSDB_ADD_INTERFACE:
- params = json_array();
- json_array_append_new(params, json_string("Open_vSwitch"));
- json_array_append_new(params, _inc_next_cfg(priv->db_uuid));
-
- _add_interface(self,
- params,
- call->bridge,
- call->port,
- call->interface,
- call->bridge_device,
- call->interface_device);
+ default:
+ {
+ json_t *params = NULL;
- msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params);
- break;
- case OVSDB_DEL_INTERFACE:
params = json_array();
json_array_append_new(params, json_string("Open_vSwitch"));
json_array_append_new(params, _inc_next_cfg(priv->db_uuid));
- _delete_interface(self, params, call->ifname);
-
- msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params);
- break;
- case OVSDB_SET_INTERFACE_MTU:
- params = json_array();
- json_array_append_new(params, json_string("Open_vSwitch"));
- json_array_append_new(params, _inc_next_cfg(priv->db_uuid));
+ switch (call->command) {
+ case OVSDB_ADD_INTERFACE:
+ _add_interface(self,
+ params,
+ call->payload.add_interface.bridge,
+ call->payload.add_interface.port,
+ call->payload.add_interface.interface,
+ call->payload.add_interface.bridge_device,
+ call->payload.add_interface.interface_device);
+ break;
+ case OVSDB_DEL_INTERFACE:
+ _delete_interface(self, params, call->payload.del_interface.ifname);
+ break;
+ case OVSDB_SET_INTERFACE_MTU:
+ json_array_append_new(params,
+ json_pack("{s:s, s:s, s:{s: I}, s:[[s, s, s]]}",
+ "op",
+ "update",
+ "table",
+ "Interface",
+ "row",
+ "mtu_request",
+ (json_int_t) call->payload.set_interface_mtu.mtu,
+ "where",
+ "name",
+ "==",
+ call->payload.set_interface_mtu.ifname));
+ break;
+ default:
+ nm_assert_not_reached();
+ break;
+ }
- json_array_append_new(params,
- json_pack("{s:s, s:s, s:{s: i}, s:[[s, s, s]]}",
- "op",
- "update",
- "table",
- "Interface",
- "row",
- "mtu_request",
- call->mtu,
- "where",
- "name",
- "==",
- call->ifname));
-
- msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params);
+ msg = json_pack("{s:I, s:s, s:o}",
+ "id",
+ (json_int_t) call->call_id,
+ "method",
+ "transact",
+ "params",
+ params);
break;
}
+ }
g_return_if_fail(msg);
_LOGT_call("send", call, msg);
- cmd = json_dumps(msg, 0);
+ cmd = json_dumps(msg, 0);
g_string_append(priv->output, cmd);
free(cmd);
@@ -1081,7 +1241,7 @@ ovsdb_next_command(NMOvsdb *self)
* [ "uuid", "185c93f6-0b39-424e-8587-77d074aa7ce0" ], ... ] ]
*/
static void
-_uuids_to_array(GPtrArray *array, const json_t *items)
+_uuids_to_array_inplace(GPtrArray *array, const json_t *items)
{
const char *key;
json_t * value;
@@ -1095,38 +1255,100 @@ _uuids_to_array(GPtrArray *array, const json_t *items)
value = json_array_get(items, index);
index++;
- if (!value)
+ if (!value || !key)
return;
- if (g_strcmp0(key, "uuid") == 0 && json_is_string(value)) {
- g_ptr_array_add(array, g_strdup(json_string_value(value)));
- } else if (g_strcmp0(key, "set") == 0 && json_is_array(value)) {
- json_array_foreach(value, set_index, set_value)
- {
- _uuids_to_array(array, set_value);
+ if (nm_streq(key, "uuid")) {
+ if (json_is_string(value))
+ g_ptr_array_add(array, g_strdup(json_string_value(value)));
+ continue;
+ }
+ if (nm_streq(key, "set")) {
+ if (json_is_array(value)) {
+ json_array_foreach (value, set_index, set_value)
+ _uuids_to_array_inplace(array, set_value);
}
+ continue;
}
}
}
-static char *
-_connection_uuid_from_external_ids(json_t *external_ids)
+static GPtrArray *
+_uuids_to_array(const json_t *items)
+{
+ GPtrArray *array;
+
+ array = g_ptr_array_new_with_free_func(g_free);
+ _uuids_to_array_inplace(array, items);
+ return array;
+}
+
+static void
+_external_ids_extract(json_t *external_ids, GArray **out_array, const char **out_connection_uuid)
{
+ json_t *array;
json_t *value;
- size_t index;
+ gsize index;
- if (g_strcmp0("map", json_string_value(json_array_get(external_ids, 0))) != 0)
- return NULL;
+ nm_assert(out_array && !*out_array);
+ nm_assert(!out_connection_uuid || !*out_connection_uuid);
- json_array_foreach(json_array_get(external_ids, 1), index, value)
- {
- if (g_strcmp0("NM.connection.uuid", json_string_value(json_array_get(value, 0))) == 0)
- return g_strdup(json_string_value(json_array_get(value, 1)));
+ if (!nm_streq0("map", json_string_value(json_array_get(external_ids, 0))))
+ return;
+
+ array = json_array_get(external_ids, 1);
+
+ json_array_foreach (array, index, value) {
+ const char * key = json_string_value(json_array_get(value, 0));
+ const char * val = json_string_value(json_array_get(value, 1));
+ NMUtilsNamedValue *v;
+
+ if (!key || !val)
+ continue;
+
+ if (!*out_array) {
+ *out_array = g_array_new(FALSE, FALSE, sizeof(NMUtilsNamedValue));
+ g_array_set_clear_func(*out_array,
+ (GDestroyNotify) nm_utils_named_value_clear_with_g_free);
+ }
+
+ v = nm_g_array_append_new(*out_array, NMUtilsNamedValue);
+ *v = (NMUtilsNamedValue){
+ .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 gboolean
+_external_ids_equal(const GArray *arr1, const GArray *arr2)
+{
+ guint n;
+ guint i;
- return NULL;
+ n = nm_g_array_len(arr1);
+
+ if (n != nm_g_array_len(arr2))
+ return FALSE;
+ for (i = 0; i < n; i++) {
+ const NMUtilsNamedValue *n1 = &g_array_index(arr1, NMUtilsNamedValue, i);
+ const NMUtilsNamedValue *n2 = &g_array_index(arr2, NMUtilsNamedValue, i);
+
+ if (!nm_streq0(n1->name, n2->name))
+ return FALSE;
+ if (!nm_streq0(n1->value_str, n2->value_str))
+ return FALSE;
+ }
+ return TRUE;
}
+/*****************************************************************************/
+
/**
* ovsdb_got_update:
*
@@ -1147,14 +1369,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
json_error_t json_error = {
0,
};
- void * iter;
- const char * name;
- const char * key;
- const char * type;
- json_t * value;
- OpenvswitchBridge * ovs_bridge;
- OpenvswitchPort * ovs_port;
- OpenvswitchInterface *ovs_interface;
+ void * iter;
+ const char *name;
+ const char *key;
+ const char *type;
+ json_t * value;
if (json_unpack_ex(msg,
&json_error,
@@ -1175,21 +1394,22 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
}
if (ovs) {
- iter = json_object_iter(ovs);
- priv->db_uuid = iter ? g_strdup(json_object_iter_key(iter)) : NULL;
- }
+ const char *s;
- /* Interfaces */
- json_object_foreach(interface, key, value)
- {
- json_t * error = NULL;
- gboolean old = FALSE;
- gboolean new = FALSE;
+ iter = json_object_iter(ovs);
+ s = json_object_iter_key(iter);
+ if (s)
+ nm_utils_strdup_reset(&priv->db_uuid, s);
+ }
- if (json_unpack(value, "{s:{}}", "old") == 0)
- old = TRUE;
+ json_object_foreach (interface, key, value) {
+ OpenvswitchInterface *ovs_interface;
+ gs_unref_array GArray *external_ids_arr = NULL;
+ const char * connection_uuid = NULL;
+ json_t * error = NULL;
+ int r;
- if (json_unpack(value,
+ r = json_unpack(value,
"{s:{s:s, s:s, s?:o, s:o}}",
"new",
"name",
@@ -1199,85 +1419,114 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
"error",
&error,
"external_ids",
- &external_ids)
- == 0)
- new = TRUE;
-
- if (old) {
- ovs_interface = g_hash_table_lookup(priv->interfaces, key);
- if (!ovs_interface) {
- _LOGW("Interface '%s' was not seen", key);
- } else if (!new || strcmp(ovs_interface->name, name) != 0) {
- old = FALSE;
- _LOGT("removed an '%s' interface: %s%s%s",
- ovs_interface->type,
- ovs_interface->name,
- ovs_interface->connection_uuid ? ", " : "",
- ovs_interface->connection_uuid ?: "");
- if (g_strcmp0(ovs_interface->type, "internal") == 0) {
- /* Currently, the factory only creates NMDevices for
- * internal interfaces. Ignore the rest. */
- g_signal_emit(self,
- signals[DEVICE_REMOVED],
- 0,
- ovs_interface->name,
- NM_DEVICE_TYPE_OVS_INTERFACE);
- }
+ &external_ids);
+ if (r != 0) {
+ gpointer unused;
+
+ r = json_unpack(value, "{s:{}}", "old");
+ if (r != 0)
+ continue;
+
+ if (!g_hash_table_steal_extended(priv->interfaces,
+ &key,
+ (gpointer *) &ovs_interface,
+ &unused))
+ continue;
+
+ _LOGT("obj[iface:%s]: removed an '%s' interface: %s%s%s",
+ key,
+ ovs_interface->type,
+ ovs_interface->name,
+ NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
+ ", ",
+ ovs_interface->connection_uuid,
+ ""));
+ if (_openvswitch_interface_should_emit_signal(ovs_interface)) {
+ _signal_emit_device_removed(self,
+ ovs_interface->name,
+ NM_DEVICE_TYPE_OVS_INTERFACE);
}
- g_hash_table_remove(priv->interfaces, key);
+ _free_interface(ovs_interface);
+ continue;
}
- if (new) {
- ovs_interface = g_slice_new(OpenvswitchInterface);
- ovs_interface->name = g_strdup(name);
- ovs_interface->type = g_strdup(type);
- ovs_interface->connection_uuid = _connection_uuid_from_external_ids(external_ids);
- g_hash_table_insert(priv->interfaces, g_strdup(key), ovs_interface);
- if (old) {
- _LOGT("changed an '%s' interface: %s%s%s",
+ ovs_interface = g_hash_table_lookup(priv->interfaces, &key);
+
+ if (ovs_interface
+ && (!nm_streq0(ovs_interface->name, name) || !nm_streq0(ovs_interface->type, type))) {
+ if (!g_hash_table_steal(priv->interfaces, ovs_interface))
+ nm_assert_not_reached();
+ if (_openvswitch_interface_should_emit_signal(ovs_interface)) {
+ _signal_emit_device_removed(self,
+ ovs_interface->name,
+ NM_DEVICE_TYPE_OVS_INTERFACE);
+ }
+ nm_clear_pointer(&ovs_interface, _free_interface);
+ }
+
+ _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid);
+
+ if (ovs_interface) {
+ gboolean changed = FALSE;
+
+ nm_assert(nm_streq0(ovs_interface->name, name));
+
+ changed |= nm_utils_strdup_reset(&ovs_interface->type, type);
+ changed |= nm_utils_strdup_reset(&ovs_interface->connection_uuid, connection_uuid);
+ if (!_external_ids_equal(ovs_interface->external_ids, external_ids_arr)) {
+ NM_SWAP(&ovs_interface->external_ids, &external_ids_arr);
+ changed = TRUE;
+ }
+ if (changed) {
+ _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s",
+ key,
type,
ovs_interface->name,
- ovs_interface->connection_uuid ? ", " : "",
- ovs_interface->connection_uuid ?: "");
- } else {
- _LOGT("added an '%s' interface: %s%s%s",
- ovs_interface->type,
- ovs_interface->name,
- ovs_interface->connection_uuid ? ", " : "",
- ovs_interface->connection_uuid ?: "");
- if (g_strcmp0(ovs_interface->type, "internal") == 0) {
- /* Currently, the factory only creates NMDevices for
- * internal interfaces. Ignore the rest. */
- g_signal_emit(self,
- signals[DEVICE_ADDED],
- 0,
- ovs_interface->name,
- NM_DEVICE_TYPE_OVS_INTERFACE);
- }
- }
- /* The error is a string. No error is indicated by an empty set,
- * because why the fuck not: [ "set": [] ] */
- if (error && json_is_string(error)) {
- g_signal_emit(self,
- signals[INTERFACE_FAILED],
- 0,
- ovs_interface->name,
- ovs_interface->connection_uuid,
- json_string_value(error));
+ NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
+ ", ",
+ ovs_interface->connection_uuid,
+ ""));
}
+ } else {
+ ovs_interface = g_slice_new(OpenvswitchInterface);
+ *ovs_interface = (OpenvswitchInterface){
+ .interface_uuid = g_strdup(key),
+ .name = g_strdup(name),
+ .type = g_strdup(type),
+ .connection_uuid = g_strdup(connection_uuid),
+ .external_ids = g_steal_pointer(&external_ids_arr),
+ };
+ g_hash_table_add(priv->interfaces, ovs_interface);
+ _LOGT("obj[iface:%s]: added an '%s' interface: %s%s%s",
+ key,
+ ovs_interface->type,
+ ovs_interface->name,
+ NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid,
+ ", ",
+ ovs_interface->connection_uuid,
+ ""));
+ if (_openvswitch_interface_should_emit_signal(ovs_interface))
+ _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE);
}
- }
- /* Ports */
- json_object_foreach(port, key, value)
- {
- gboolean old = FALSE;
- gboolean new = FALSE;
+ /* The error is a string. No error is indicated by an empty set,
+ * Why not: [ "set": [] ] ? */
+ if (error && json_is_string(error)) {
+ _signal_emit_interface_failed(self,
+ ovs_interface->name,
+ ovs_interface->connection_uuid,
+ json_string_value(error));
+ }
+ }
- if (json_unpack(value, "{s:{}}", "old") == 0)
- old = TRUE;
+ json_object_foreach (port, key, value) {
+ gs_unref_ptrarray GPtrArray *interfaces = NULL;
+ OpenvswitchPort * ovs_port;
+ gs_unref_array GArray *external_ids_arr = NULL;
+ const char * connection_uuid = NULL;
+ int r;
- if (json_unpack(value,
+ r = json_unpack(value,
"{s:{s:s, s:o, s:o}}",
"new",
"name",
@@ -1285,63 +1534,94 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
"external_ids",
&external_ids,
"interfaces",
- &items)
- == 0)
- new = TRUE;
-
- if (old) {
- ovs_port = g_hash_table_lookup(priv->ports, key);
- if (!new || g_strcmp0(ovs_port->name, name) != 0) {
- old = FALSE;
- _LOGT("removed a port: %s%s%s",
- ovs_port->name,
- ovs_port->connection_uuid ? ", " : "",
- ovs_port->connection_uuid ?: "");
- g_signal_emit(self,
- signals[DEVICE_REMOVED],
- 0,
- ovs_port->name,
- NM_DEVICE_TYPE_OVS_PORT);
- }
- g_hash_table_remove(priv->ports, key);
+ &items);
+ if (r != 0) {
+ gpointer unused;
+
+ r = json_unpack(value, "{s:{}}", "old");
+ if (r != 0)
+ continue;
+
+ if (!g_hash_table_steal_extended(priv->ports, &key, (gpointer *) &ovs_port, &unused))
+ continue;
+
+ _LOGT("obj[port:%s]: removed a port: %s%s%s",
+ key,
+ ovs_port->name,
+ NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
+ ", ",
+ ovs_port->connection_uuid,
+ ""));
+ _signal_emit_device_removed(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT);
+ _free_port(ovs_port);
+ continue;
}
- if (new) {
- ovs_port = g_slice_new(OpenvswitchPort);
- ovs_port->name = g_strdup(name);
- ovs_port->connection_uuid = _connection_uuid_from_external_ids(external_ids);
- ovs_port->interfaces = g_ptr_array_new_with_free_func(g_free);
- _uuids_to_array(ovs_port->interfaces, items);
- g_hash_table_insert(priv->ports, g_strdup(key), ovs_port);
- if (old) {
- _LOGT("changed a port: %s%s%s",
- ovs_port->name,
- ovs_port->connection_uuid ? ", " : "",
- ovs_port->connection_uuid ?: "");
- } else {
- _LOGT("added a port: %s%s%s",
+ ovs_port = g_hash_table_lookup(priv->ports, &key);
+
+ if (ovs_port && !nm_streq0(ovs_port->name, name)) {
+ if (!g_hash_table_steal(priv->ports, ovs_port))
+ nm_assert_not_reached();
+ _signal_emit_device_removed(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT);
+ nm_clear_pointer(&ovs_port, _free_port);
+ }
+
+ _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid);
+ interfaces = _uuids_to_array(items);
+
+ if (ovs_port) {
+ gboolean changed = FALSE;
+
+ nm_assert(nm_streq0(ovs_port->name, name));
+
+ changed |= nm_utils_strdup_reset(&ovs_port->name, name);
+ changed |= nm_utils_strdup_reset(&ovs_port->connection_uuid, g_strdup(connection_uuid));
+ if (nm_strv_ptrarray_cmp(ovs_port->interfaces, interfaces) != 0) {
+ NM_SWAP(&ovs_port->interfaces, &interfaces);
+ changed = TRUE;
+ }
+ if (!_external_ids_equal(ovs_port->external_ids, external_ids_arr)) {
+ NM_SWAP(&ovs_port->external_ids, &external_ids_arr);
+ changed = TRUE;
+ }
+ if (changed) {
+ _LOGT("obj[port:%s]: changed a port: %s%s%s",
+ key,
ovs_port->name,
- ovs_port->connection_uuid ? ", " : "",
- ovs_port->connection_uuid ?: "");
- g_signal_emit(self,
- signals[DEVICE_ADDED],
- 0,
- ovs_port->name,
- NM_DEVICE_TYPE_OVS_PORT);
+ NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
+ ", ",
+ ovs_port->connection_uuid,
+ ""));
}
+ } else {
+ ovs_port = g_slice_new(OpenvswitchPort);
+ *ovs_port = (OpenvswitchPort){
+ .port_uuid = g_strdup(key),
+ .name = g_strdup(name),
+ .connection_uuid = g_strdup(connection_uuid),
+ .interfaces = g_steal_pointer(&interfaces),
+ .external_ids = g_steal_pointer(&external_ids_arr),
+ };
+ g_hash_table_add(priv->ports, ovs_port);
+ _LOGT("obj[port:%s]: added a port: %s%s%s",
+ key,
+ ovs_port->name,
+ NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid,
+ ", ",
+ ovs_port->connection_uuid,
+ ""));
+ _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT);
}
}
- /* Bridges */
- json_object_foreach(bridge, key, value)
- {
- gboolean old = FALSE;
- gboolean new = FALSE;
+ json_object_foreach (bridge, key, value) {
+ gs_unref_ptrarray GPtrArray *ports = NULL;
+ OpenvswitchBridge * ovs_bridge;
+ gs_unref_array GArray *external_ids_arr = NULL;
+ const char * connection_uuid = NULL;
+ int r;
- if (json_unpack(value, "{s:{}}", "old") == 0)
- old = TRUE;
-
- if (json_unpack(value,
+ r = json_unpack(value,
"{s:{s:s, s:o, s:o}}",
"new",
"name",
@@ -1349,50 +1629,88 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
"external_ids",
&external_ids,
"ports",
- &items)
- == 0)
- new = TRUE;
-
- if (old) {
- ovs_bridge = g_hash_table_lookup(priv->bridges, key);
- if (!new || g_strcmp0(ovs_bridge->name, name) != 0) {
- old = FALSE;
- _LOGT("removed a bridge: %s%s%s",
- ovs_bridge->name,
- ovs_bridge->connection_uuid ? ", " : "",
- ovs_bridge->connection_uuid ?: "");
- g_signal_emit(self,
- signals[DEVICE_REMOVED],
- 0,
- ovs_bridge->name,
- NM_DEVICE_TYPE_OVS_BRIDGE);
- }
- g_hash_table_remove(priv->bridges, key);
+ &items);
+
+ if (r != 0) {
+ gpointer unused;
+
+ r = json_unpack(value, "{s:{}}", "old");
+ if (r != 0)
+ continue;
+
+ if (!g_hash_table_steal_extended(priv->bridges,
+ &key,
+ (gpointer *) &ovs_bridge,
+ &unused))
+ continue;
+
+ _LOGT("obj[bridge:%s]: removed a bridge: %s%s%s",
+ key,
+ ovs_bridge->name,
+ NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
+ ", ",
+ ovs_bridge->connection_uuid,
+ ""));
+ _signal_emit_device_removed(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE);
+ _free_bridge(ovs_bridge);
+ continue;
}
- if (new) {
- ovs_bridge = g_slice_new(OpenvswitchBridge);
- ovs_bridge->name = g_strdup(name);
- ovs_bridge->connection_uuid = _connection_uuid_from_external_ids(external_ids);
- ovs_bridge->ports = g_ptr_array_new_with_free_func(g_free);
- _uuids_to_array(ovs_bridge->ports, items);
- g_hash_table_insert(priv->bridges, g_strdup(key), ovs_bridge);
- if (old) {
- _LOGT("changed a bridge: %s%s%s",
- ovs_bridge->name,
- ovs_bridge->connection_uuid ? ", " : "",
- ovs_bridge->connection_uuid ?: "");
- } else {
- _LOGT("added a bridge: %s%s%s",
+ ovs_bridge = g_hash_table_lookup(priv->bridges, &key);
+
+ if (ovs_bridge && !nm_streq0(ovs_bridge->name, name)) {
+ if (!g_hash_table_steal(priv->bridges, ovs_bridge))
+ nm_assert_not_reached();
+ _signal_emit_device_removed(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE);
+ nm_clear_pointer(&ovs_bridge, _free_bridge);
+ }
+
+ _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid);
+ ports = _uuids_to_array(items);
+
+ if (ovs_bridge) {
+ gboolean changed = FALSE;
+
+ nm_assert(nm_streq0(ovs_bridge->name, name));
+
+ changed = nm_utils_strdup_reset(&ovs_bridge->name, name);
+ changed =
+ nm_utils_strdup_reset(&ovs_bridge->connection_uuid, g_strdup(connection_uuid));
+ if (nm_strv_ptrarray_cmp(ovs_bridge->ports, ports) != 0) {
+ NM_SWAP(&ovs_bridge->ports, &ports);
+ changed = TRUE;
+ }
+ if (!_external_ids_equal(ovs_bridge->external_ids, external_ids_arr)) {
+ NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr);
+ changed = TRUE;
+ }
+ if (changed) {
+ _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s",
+ key,
ovs_bridge->name,
- ovs_bridge->connection_uuid ? ", " : "",
- ovs_bridge->connection_uuid ?: "");
- g_signal_emit(self,
- signals[DEVICE_ADDED],
- 0,
- ovs_bridge->name,
- NM_DEVICE_TYPE_OVS_BRIDGE);
+ NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
+ ", ",
+ ovs_bridge->connection_uuid,
+ ""));
}
+ } else {
+ ovs_bridge = g_slice_new(OpenvswitchBridge);
+ *ovs_bridge = (OpenvswitchBridge){
+ .bridge_uuid = g_strdup(key),
+ .name = g_strdup(name),
+ .connection_uuid = g_strdup(connection_uuid),
+ .ports = g_steal_pointer(&ports),
+ .external_ids = g_steal_pointer(&external_ids_arr),
+ };
+ g_hash_table_add(priv->bridges, ovs_bridge);
+ _LOGT("obj[bridge:%s]: added a bridge: %s%s%s",
+ key,
+ ovs_bridge->name,
+ NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid,
+ ", ",
+ ovs_bridge->connection_uuid,
+ ""));
+ _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE);
}
}
}
@@ -1436,7 +1754,7 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
0,
};
json_t * json_id = NULL;
- gint64 id = -1;
+ json_int_t id = (json_int_t) -1;
const char * method = NULL;
json_t * params = NULL;
json_t * result = NULL;
@@ -1477,10 +1795,10 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
return;
}
- if (g_strcmp0(method, "update") == 0) {
+ if (nm_streq0(method, "update")) {
/* This is a update method call. */
ovsdb_got_update(self, json_array_get(params, 1));
- } else if (g_strcmp0(method, "echo") == 0) {
+ } else if (nm_streq0(method, "echo")) {
/* This is an echo request. */
ovsdb_got_echo(self, id, params);
} else {
@@ -1489,18 +1807,18 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
return;
}
- if (id > -1) {
+ if (id >= 0) {
/* This is a response to a method call. */
if (!priv->calls->len) {
- _LOGE("there are no queued calls expecting response %" G_GUINT64_FORMAT, id);
+ _LOGE("there are no queued calls expecting response %" G_GUINT64_FORMAT, (guint64) id);
ovsdb_disconnect(self, FALSE, FALSE);
return;
}
call = &g_array_index(priv->calls, OvsdbMethodCall, 0);
- if (call->id != id) {
+ if (call->call_id != id) {
_LOGE("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT,
- call->id,
- id);
+ call->call_id,
+ (guint64) id);
ovsdb_disconnect(self, FALSE, FALSE);
return;
}
@@ -1704,7 +2022,7 @@ ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing)
if (retry) {
if (priv->calls->len != 0)
- g_array_index(priv->calls, OvsdbMethodCall, 0).id = COMMAND_PENDING;
+ g_array_index(priv->calls, OvsdbMethodCall, 0).call_id = CALL_ID_UNSPEC;
} else {
nm_utils_error_set_cancelled(&error, is_disposing, "NMOvsdb");
@@ -1803,17 +2121,11 @@ ovsdb_try_connect(NMOvsdb *self)
/* Queue a monitor call before any other command, ensuring that we have an up
* to date view of existing bridged that we need for add and remove ops. */
ovsdb_call_method(self,
- OVSDB_MONITOR,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
_monitor_bridges_cb,
NULL,
- TRUE);
+ TRUE,
+ OVSDB_MONITOR,
+ OVSDB_METHOD_PAYLOAD_MONITOR());
}
/*****************************************************************************/
@@ -1838,8 +2150,7 @@ _transact_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data)
if (error)
goto out;
- json_array_foreach(result, index, value)
- {
+ json_array_foreach (result, index, value) {
if (json_unpack(value, "{s:s, s:s}", "error", &err, "details", &err_details) == 0) {
g_set_error(&error,
G_IO_ERROR,
@@ -1853,7 +2164,7 @@ _transact_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data)
out:
call->callback(error, call->user_data);
- g_slice_free(OvsdbCall, call);
+ nm_g_slice_free(call);
}
static OvsdbCall *
@@ -1861,10 +2172,11 @@ ovsdb_call_new(NMOvsdbCallback callback, gpointer user_data)
{
OvsdbCall *call;
- call = g_slice_new(OvsdbCall);
- call->callback = callback;
- call->user_data = user_data;
-
+ call = g_slice_new(OvsdbCall);
+ *call = (OvsdbCall){
+ .callback = callback,
+ .user_data = user_data,
+ };
return call;
}
@@ -1879,17 +2191,15 @@ nm_ovsdb_add_interface(NMOvsdb * self,
gpointer user_data)
{
ovsdb_call_method(self,
- OVSDB_ADD_INTERFACE,
- NULL,
- bridge,
- port,
- interface,
- bridge_device,
- interface_device,
- 0,
_transact_cb,
ovsdb_call_new(callback, user_data),
- FALSE);
+ FALSE,
+ OVSDB_ADD_INTERFACE,
+ OVSDB_METHOD_PAYLOAD_ADD_INTERFACE(bridge,
+ port,
+ interface,
+ bridge_device,
+ interface_device));
}
void
@@ -1899,17 +2209,11 @@ nm_ovsdb_del_interface(NMOvsdb * self,
gpointer user_data)
{
ovsdb_call_method(self,
- OVSDB_DEL_INTERFACE,
- ifname,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
_transact_cb,
ovsdb_call_new(callback, user_data),
- FALSE);
+ FALSE,
+ OVSDB_DEL_INTERFACE,
+ OVSDB_METHOD_PAYLOAD_DEL_INTERFACE(ifname));
}
void
@@ -1920,88 +2224,30 @@ nm_ovsdb_set_interface_mtu(NMOvsdb * self,
gpointer user_data)
{
ovsdb_call_method(self,
- OVSDB_SET_INTERFACE_MTU,
- ifname,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- mtu,
_transact_cb,
ovsdb_call_new(callback, user_data),
- FALSE);
+ FALSE,
+ OVSDB_SET_INTERFACE_MTU,
+ OVSDB_METHOD_PAYLOAD_SET_INTERFACE_MTU(ifname, mtu));
}
/*****************************************************************************/
static void
-_clear_call(gpointer data)
-{
- OvsdbMethodCall *call = data;
-
- switch (call->command) {
- case OVSDB_MONITOR:
- break;
- case OVSDB_ADD_INTERFACE:
- g_clear_object(&call->bridge);
- g_clear_object(&call->port);
- g_clear_object(&call->interface);
- g_clear_object(&call->bridge_device);
- g_clear_object(&call->interface_device);
- break;
- case OVSDB_DEL_INTERFACE:
- case OVSDB_SET_INTERFACE_MTU:
- nm_clear_g_free(&call->ifname);
- break;
- }
-}
-
-static void
-_free_bridge(gpointer data)
-{
- OpenvswitchBridge *ovs_bridge = data;
-
- g_free(ovs_bridge->name);
- g_free(ovs_bridge->connection_uuid);
- g_ptr_array_free(ovs_bridge->ports, TRUE);
- g_slice_free(OpenvswitchBridge, ovs_bridge);
-}
-
-static void
-_free_port(gpointer data)
-{
- OpenvswitchPort *ovs_port = data;
-
- g_free(ovs_port->name);
- g_free(ovs_port->connection_uuid);
- g_ptr_array_free(ovs_port->interfaces, TRUE);
- g_slice_free(OpenvswitchPort, ovs_port);
-}
-
-static void
-_free_interface(gpointer data)
-{
- OpenvswitchInterface *ovs_interface = data;
-
- g_free(ovs_interface->name);
- g_free(ovs_interface->connection_uuid);
- g_free(ovs_interface->type);
- g_slice_free(OpenvswitchInterface, ovs_interface);
-}
-
-static void
nm_ovsdb_init(NMOvsdb *self)
{
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
priv->calls = g_array_new(FALSE, TRUE, sizeof(OvsdbMethodCall));
g_array_set_clear_func(priv->calls, _clear_call);
- priv->input = g_string_new(NULL);
- priv->output = g_string_new(NULL);
- priv->bridges = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_bridge);
- priv->ports = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_port);
- priv->interfaces = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_interface);
+ priv->input = g_string_new(NULL);
+ priv->output = g_string_new(NULL);
+ priv->bridges =
+ g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_bridge, NULL);
+ priv->ports =
+ g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_port, NULL);
+ priv->interfaces =
+ g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_interface, NULL);
ovsdb_try_connect(self);
}
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
index 27aa300430..65fd70c78a 100644
--- a/src/devices/team/nm-device-team.c
+++ b/src/devices/team/nm-device-team.c
@@ -25,8 +25,8 @@
#include "nm-ip4-config.h"
#include "nm-std-aux/nm-dbus-compat.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceTeam
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceTeam);
/*****************************************************************************/
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index c479b3d453..e59dafdefe 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -28,8 +28,8 @@
#include "settings/nm-settings.h"
#include "supplicant/nm-supplicant-types.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceIwd
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceIwd);
/*****************************************************************************/
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index 22e94a6dcc..4b9c640149 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -30,8 +30,8 @@
#include "nm-manager.h"
#include "platform/nm-platform.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceOlpcMesh
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceOlpcMesh);
/*****************************************************************************/
diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c
index 2e5317fd95..0780d80b34 100644
--- a/src/devices/wifi/nm-device-wifi-p2p.c
+++ b/src/devices/wifi/nm-device-wifi-p2p.c
@@ -27,8 +27,8 @@
#include "platform/nmp-object.h"
#include "settings/nm-settings.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceWifiP2P
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceWifiP2P);
/*****************************************************************************/
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 7c749f1e3c..24de0cdeca 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -41,8 +41,8 @@
#include "nm-core-internal.h"
#include "nm-config.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceWifi
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceWifi);
#define SCAN_INTERVAL_SEC_MIN 3
#define SCAN_INTERVAL_SEC_STEP 20
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index f77de85aac..5b8b3bd29d 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -16,8 +16,8 @@
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
+#define _NMLOG_DEVICE_TYPE NMDeviceModem
#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceModem);
/*****************************************************************************/