diff options
Diffstat (limited to 'src/devices/ovs')
| -rw-r--r-- | src/devices/ovs/meson.build | 33 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-bridge.c | 125 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-bridge.h | 25 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.c | 398 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.h | 26 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-port.c | 192 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-port.h | 25 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovs-factory.c | 269 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovsdb.c | 2100 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovsdb.h | 49 |
10 files changed, 0 insertions, 3242 deletions
diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build deleted file mode 100644 index 8457e68a..00000000 --- a/src/devices/ovs/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -sources = files( - 'nm-device-ovs-bridge.c', - 'nm-device-ovs-interface.c', - 'nm-device-ovs-port.c', - 'nm-ovsdb.c', - 'nm-ovs-factory.c', -) - -deps = [ - daemon_nm_default_dep, - jansson_dep, -] - -libnm_device_plugin_ovs = shared_module( - 'nm-device-plugin-ovs', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, -) - -core_plugins += libnm_device_plugin_ovs - -test( - 'check-local-devices-ovs', - check_exports, - args: [libnm_device_plugin_ovs.full_path(), linker_script_devices], -) diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c deleted file mode 100644 index a7b7a539..00000000 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ /dev/null @@ -1,125 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-bridge.h" -#include "nm-device-ovs-port.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-bridge.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsBridge); - -/*****************************************************************************/ - -struct _NMDeviceOvsBridge { - NMDevice parent; -}; - -struct _NMDeviceOvsBridgeClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsBridge, nm_device_ovs_bridge, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-bridge"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The actual backing resources will be created on enslavement by the port - * when it can identify the port and the bridge. */ - - return TRUE; -} - -static gboolean -unrealize(NMDevice *device, GError **error) -{ - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - if (!configure) - return TRUE; - - if (!NM_IS_DEVICE_OVS_PORT(slave)) - return FALSE; - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{} - -/*****************************************************************************/ - -static void -nm_device_ovs_bridge_init(NMDeviceOvsBridge *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_bridge); - - device_class->connection_type_supported = NM_SETTING_OVS_BRIDGE_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_BRIDGE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(); - - device_class->is_master = TRUE; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->unrealize = unrealize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; -} diff --git a/src/devices/ovs/nm-device-ovs-bridge.h b/src/devices/ovs/nm-device-ovs-bridge.h deleted file mode 100644 index ba04bfeb..00000000 --- a/src/devices/ovs/nm-device-ovs-bridge.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ -#define __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ - -#define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type()) -#define NM_DEVICE_OVS_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) -#define NM_DEVICE_OVS_BRIDGE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) -#define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) -#define NM_IS_DEVICE_OVS_BRIDGE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_BRIDGE)) -#define NM_DEVICE_OVS_BRIDGE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) - -typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; -typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass; - -GType nm_device_ovs_bridge_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c deleted file mode 100644 index 16b6e04d..00000000 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ /dev/null @@ -1,398 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-interface.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-interface.h" -#include "nm-setting-ovs-port.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsInterface); - -/*****************************************************************************/ - -typedef struct { - bool waiting_for_interface : 1; -} NMDeviceOvsInterfacePrivate; - -struct _NMDeviceOvsInterface { - NMDevice parent; - NMDeviceOvsInterfacePrivate _priv; -}; - -struct _NMDeviceOvsInterfaceClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsInterface, nm_device_ovs_interface, NM_TYPE_DEVICE) - -#define NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceOvsInterface, NM_IS_DEVICE_OVS_INTERFACE, NMDevice) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-interface"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The actual backing resources will be created once an interface is - * added to a port of ours, since there can be neither an empty port nor - * an empty bridge. */ - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingOvsInterface *s_ovs_iface; - - if (!NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_ovs_iface = nm_connection_get_setting_ovs_interface(connection); - - if (!NM_IN_STRSET(nm_setting_ovs_interface_get_interface_type(s_ovs_iface), - "dpdk", - "internal", - "patch")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "unsupported OVS interface type in profile"); - return FALSE; - } - - return TRUE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); - - if (!pllink || !priv->waiting_for_interface) - return; - - priv->waiting_for_interface = FALSE; - - if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { - if (!nm_device_hw_addr_set_cloned(device, - nm_device_get_applied_connection(device), - FALSE)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - nm_device_bring_up(device, TRUE, NULL); - nm_device_activate_schedule_stage3_ip_config_start(device); - } -} - -static gboolean -_is_internal_interface(NMDevice *device) -{ - NMSettingOvsInterface *s_ovs_iface; - - s_ovs_iface = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OVS_INTERFACE); - - g_return_val_if_fail(s_ovs_iface, FALSE); - - return nm_streq(nm_setting_ovs_interface_get_interface_type(s_ovs_iface), "internal"); -} - -static void -set_platform_mtu_cb(GError *error, gpointer user_data) -{ - NMDevice * device = user_data; - NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - _LOGW(LOGD_DEVICE, - "could not change mtu of '%s': %s", - nm_device_get_iface(device), - error->message); - } - - g_object_unref(device); -} - -static gboolean -set_platform_mtu(NMDevice *device, guint32 mtu) -{ - /* - * If the MTU is not set in ovsdb, Open vSwitch will change - * the MTU of an internal interface to match the minimum of - * the other interfaces in the bridge. - */ - /* FIXME(shutdown): the function should become cancellable so - * that it doesn't need to hold a reference to the device, and - * it can be stopped during shutdown. - */ - if (_is_internal_interface(device)) { - nm_ovsdb_set_interface_mtu(nm_ovsdb_get(), - nm_device_get_ip_iface(device), - mtu, - set_platform_mtu_cb, - g_object_ref(device)); - } - - return NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class)->set_platform_mtu(device, mtu); -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); - - if (!_is_internal_interface(device)) - return NM_ACT_STAGE_RETURN_IP_FAIL; - - if (nm_device_get_ip_ifindex(device) <= 0) { - _LOGT(LOGD_DEVICE, "waiting for link to appear"); - priv->waiting_for_interface = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static gboolean -can_unmanaged_external_down(NMDevice *self) -{ - return FALSE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - - priv->waiting_for_interface = FALSE; -} - -typedef struct { - NMDeviceOvsInterface * self; - GCancellable * cancellable; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - gulong link_changed_id; - gulong cancelled_id; - guint link_timeout_id; -} DeactivateData; - -static void -deactivate_invoke_cb(DeactivateData *data, GError *error) -{ - NMDeviceOvsInterface *self = data->self; - - _LOGT(LOGD_CORE, "deactivate: async callback (%s)", error ? error->message : "success"); - data->callback(NM_DEVICE(data->self), error, data->callback_user_data); - - nm_clear_g_signal_handler(nm_device_get_platform(NM_DEVICE(data->self)), - &data->link_changed_id); - nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id); - nm_clear_g_source(&data->link_timeout_id); - g_object_unref(data->self); - g_object_unref(data->cancellable); - nm_g_slice_free(data); -} - -static void -deactivate_link_changed_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - DeactivateData *data) -{ - NMDeviceOvsInterface * self = data->self; - const NMPlatformSignalChangeType change_type = change_type_i; - - if (change_type == NM_PLATFORM_SIGNAL_REMOVED - && nm_streq0(info->name, nm_device_get_iface(NM_DEVICE(self)))) { - _LOGT(LOGD_DEVICE, "deactivate: link removed, proceeding"); - nm_device_update_from_platform_link(NM_DEVICE(self), NULL); - deactivate_invoke_cb(data, NULL); - return; - } -} - -static gboolean -deactivate_link_timeout(gpointer user_data) -{ - DeactivateData * data = user_data; - NMDeviceOvsInterface *self = data->self; - - _LOGT(LOGD_DEVICE, "deactivate: timeout waiting link removal"); - deactivate_invoke_cb(data, NULL); - return G_SOURCE_REMOVE; -} - -static void -deactivate_cancelled_cb(GCancellable *cancellable, gpointer user_data) -{ - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled(&error, FALSE, NULL); - deactivate_invoke_cb((DeactivateData *) user_data, error); -} - -static void -deactivate_cb_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DeactivateData *data = user_data; - gs_free_error GError *cancelled_error = NULL; - - g_cancellable_set_error_if_cancelled(data->cancellable, &cancelled_error); - deactivate_invoke_cb(data, cancelled_error); -} - -static void -deactivate_async(NMDevice * device, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer callback_user_data) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - DeactivateData * data; - - _LOGT(LOGD_CORE, "deactivate: start async"); - - /* We want to ensure that the kernel link for this device is - * removed upon disconnection so that it will not interfere with - * later activations of the same device. Unfortunately there is - * no synchronization mechanism with vswitchd, we only update - * ovsdb and wait that changes are picked up. - */ - - data = g_slice_new(DeactivateData); - *data = (DeactivateData){ - .self = g_object_ref(self), - .cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - }; - - if (!priv->waiting_for_interface - && !nm_platform_link_get_by_ifname(nm_device_get_platform(device), - nm_device_get_iface(device))) { - _LOGT(LOGD_CORE, "deactivate: link not present, proceeding"); - nm_device_update_from_platform_link(NM_DEVICE(self), NULL); - nm_utils_invoke_on_idle(cancellable, deactivate_cb_on_idle, data); - return; - } - - if (priv->waiting_for_interface) { - /* At this point we have issued an INSERT and a DELETE - * command for the interface to ovsdb. We don't know if - * vswitchd will see the two updates or only one. We - * must add a timeout to avoid waiting forever in case - * the link doesn't appear. - */ - data->link_timeout_id = g_timeout_add(6000, deactivate_link_timeout, data); - _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear in 6 seconds"); - } else - _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear"); - - data->cancelled_id = - g_cancellable_connect(cancellable, G_CALLBACK(deactivate_cancelled_cb), data, NULL); - data->link_changed_id = g_signal_connect(nm_device_get_platform(device), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(deactivate_link_changed_cb), - data); -} - -static gboolean -can_update_from_platform_link(NMDevice *device, const NMPlatformLink *plink) -{ - /* If the device is deactivating, we already sent the - * deletion command to ovsdb and we don't want to deal - * with any new link appearing from the previous - * activation. - */ - return !plink || nm_device_get_state(device) != NM_DEVICE_STATE_DEACTIVATING; -} - -/*****************************************************************************/ - -static void -nm_device_ovs_interface_init(NMDeviceOvsInterface *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_interface = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_interface_class_init(NMDeviceOvsInterfaceClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_interface); - - device_class->connection_type_supported = NM_SETTING_OVS_INTERFACE_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH); - - device_class->can_update_from_platform_link = can_update_from_platform_link; - device_class->deactivate = deactivate; - device_class->deactivate_async = deactivate_async; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->is_available = is_available; - device_class->check_connection_compatible = check_connection_compatible; - device_class->link_changed = link_changed; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->can_unmanaged_external_down = can_unmanaged_external_down; - device_class->set_platform_mtu = set_platform_mtu; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; -} diff --git a/src/devices/ovs/nm-device-ovs-interface.h b/src/devices/ovs/nm-device-ovs-interface.h deleted file mode 100644 index 902847de..00000000 --- a/src/devices/ovs/nm-device-ovs-interface.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ -#define __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ - -#define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type()) -#define NM_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) -#define NM_DEVICE_OVS_INTERFACE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) -#define NM_IS_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_INTERFACE)) -#define NM_IS_DEVICE_OVS_INTERFACE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_INTERFACE)) -#define NM_DEVICE_OVS_INTERFACE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) - -typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; -typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass; - -GType nm_device_ovs_interface_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c deleted file mode 100644 index de98e29e..00000000 --- a/src/devices/ovs/nm-device-ovs-port.c +++ /dev/null @@ -1,192 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-port.h" -#include "nm-device-ovs-interface.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-port.h" -#include "nm-setting-ovs-port.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsPort); - -/*****************************************************************************/ - -struct _NMDeviceOvsPort { - NMDevice parent; -}; - -struct _NMDeviceOvsPortClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsPort, nm_device_ovs_port, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-port"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The port will be added to ovsdb when an interface is enslaved, - * because there's no such thing like an empty port. */ - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static void -add_iface_cb(GError *error, gpointer user_data) -{ - NMDevice *slave = user_data; - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - nm_log_warn(LOGD_DEVICE, - "device %s could not be added to a ovs port: %s", - nm_device_get_iface(slave), - error->message); - nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); - } - - g_object_unref(slave); -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceOvsPort * self = NM_DEVICE_OVS_PORT(device); - NMActiveConnection *ac_port = NULL; - NMActiveConnection *ac_bridge = NULL; - NMDevice * bridge_device; - - if (!configure) - return TRUE; - - ac_port = NM_ACTIVE_CONNECTION(nm_device_get_act_request(device)); - ac_bridge = nm_active_connection_get_master(ac_port); - if (!ac_bridge) { - _LOGW(LOGD_DEVICE, - "can't enslave %s: bridge active-connection not found", - nm_device_get_iface(slave)); - return FALSE; - } - - bridge_device = nm_active_connection_get_device(ac_bridge); - if (!bridge_device) { - _LOGW(LOGD_DEVICE, "can't enslave %s: bridge device not found", nm_device_get_iface(slave)); - return FALSE; - } - - nm_ovsdb_add_interface(nm_ovsdb_get(), - nm_active_connection_get_applied_connection(ac_bridge), - nm_device_get_applied_connection(device), - nm_device_get_applied_connection(slave), - bridge_device, - slave, - add_iface_cb, - g_object_ref(slave)); - - return TRUE; -} - -static void -del_iface_cb(GError *error, gpointer user_data) -{ - NMDevice *slave = user_data; - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - nm_log_warn(LOGD_DEVICE, - "device %s could not be removed from a ovs port: %s", - nm_device_get_iface(slave), - error->message); - nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); - } - - g_object_unref(slave); -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device); - - if (configure) { - _LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave)); - nm_ovsdb_del_interface(nm_ovsdb_get(), - nm_device_get_iface(slave), - del_iface_cb, - g_object_ref(slave)); - /* Open VSwitch is going to delete this one. We must ignore what happens - * next with the interface. */ - if (NM_IS_DEVICE_OVS_INTERFACE(slave)) - nm_device_update_from_platform_link(slave, NULL); - } else - _LOGI(LOGD_DEVICE, "ovs interface %s was released", nm_device_get_ip_iface(slave)); -} - -/*****************************************************************************/ - -static void -nm_device_ovs_port_init(NMDeviceOvsPort *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_port = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_PORT, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_port); - - device_class->connection_type_supported = NM_SETTING_OVS_PORT_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_PORT_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(); - - device_class->is_master = TRUE; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; -} diff --git a/src/devices/ovs/nm-device-ovs-port.h b/src/devices/ovs/nm-device-ovs-port.h deleted file mode 100644 index 3f5d7793..00000000 --- a/src/devices/ovs/nm-device-ovs-port.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_PORT_H__ -#define __NETWORKMANAGER_DEVICE_OVS_PORT_H__ - -#define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type()) -#define NM_DEVICE_OVS_PORT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) -#define NM_DEVICE_OVS_PORT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) -#define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_PORT)) -#define NM_IS_DEVICE_OVS_PORT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_PORT)) -#define NM_DEVICE_OVS_PORT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) - -typedef struct _NMDeviceOvsPort NMDeviceOvsPort; -typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass; - -GType nm_device_ovs_port_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_PORT_H__ */ diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c deleted file mode 100644 index e1feacbd..00000000 --- a/src/devices/ovs/nm-ovs-factory.c +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-manager.h" -#include "nm-ovsdb.h" -#include "nm-device-ovs-interface.h" -#include "nm-device-ovs-port.h" -#include "nm-device-ovs-bridge.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" -#include "settings/nm-settings.h" -#include "devices/nm-device-factory.h" -#include "devices/nm-device-private.h" - -/*****************************************************************************/ - -typedef struct { - NMDeviceFactory parent; -} NMOvsFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMOvsFactoryClass; - -#define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type()) -#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) -#define NM_OVS_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) -#define NM_IS_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVS_FACTORY)) -#define NM_IS_OVS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVS_FACTORY)) -#define NM_OVS_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) - -static GType nm_ovs_factory_get_type(void); -G_DEFINE_TYPE(NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ifname, con_uuid, ...) \ - G_STMT_START \ - { \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - (ifname), \ - (con_uuid), \ - "ovs: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES( - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_OVS_BRIDGE_SETTING_NAME, - NM_SETTING_OVS_INTERFACE_SETTING_NAME, - NM_SETTING_OVS_PORT_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - nm_manager_set_capability(NM_MANAGER_GET, NM_CAPABILITY_OVS); - return (NMDeviceFactory *) g_object_new(NM_TYPE_OVS_FACTORY, NULL); -} - -static NMDevice * -new_device_from_type(const char *name, NMDeviceType device_type) -{ - GType type; - const char *type_desc; - NMLinkType link_type = NM_LINK_TYPE_NONE; - - if (nm_manager_get_device(NM_MANAGER_GET, name, device_type)) - return NULL; - - if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE) { - type = NM_TYPE_DEVICE_OVS_INTERFACE; - type_desc = "Open vSwitch Interface"; - link_type = NM_LINK_TYPE_OPENVSWITCH; - } else if (device_type == NM_DEVICE_TYPE_OVS_PORT) { - type = NM_TYPE_DEVICE_OVS_PORT; - type_desc = "Open vSwitch Port"; - } else if (device_type == NM_DEVICE_TYPE_OVS_BRIDGE) { - type = NM_TYPE_DEVICE_OVS_BRIDGE; - type_desc = "Open vSwitch Bridge"; - } else { - return NULL; - } - - return g_object_new(type, - NM_DEVICE_IFACE, - name, - NM_DEVICE_DRIVER, - "openvswitch", - NM_DEVICE_DEVICE_TYPE, - device_type, - NM_DEVICE_TYPE_DESC, - type_desc, - NM_DEVICE_LINK_TYPE, - link_type, - NULL); -} - -static void -ovsdb_device_added(NMOvsdb * ovsdb, - const char * name, - NMDeviceType device_type, - NMDeviceFactory *self) -{ - NMDevice *device = NULL; - - device = new_device_from_type(name, device_type); - if (!device) - return; - - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); - g_object_unref(device); -} - -static void -ovsdb_device_removed(NMOvsdb * ovsdb, - const char * name, - NMDeviceType device_type, - NMDeviceFactory *self) -{ - NMDevice * device; - NMDeviceState device_state; - - device = nm_manager_get_device(NM_MANAGER_GET, name, device_type); - if (!device) - return; - - device_state = nm_device_get_state(device); - if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE && device_state > NM_DEVICE_STATE_DISCONNECTED - && device_state < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - } else if (device_state == NM_DEVICE_STATE_UNMANAGED) { - nm_device_unrealize(device, TRUE, NULL); - } -} - -static void -ovsdb_interface_failed(NMOvsdb * ovsdb, - const char * name, - const char * connection_uuid, - const char * error, - NMDeviceFactory *self) -{ - NMDevice * device = NULL; - NMSettingsConnection * connection = NULL; - NMConnection * c; - const char * type; - NMSettingOvsInterface *s_ovs_int; - gboolean is_patch = FALSE; - gboolean ignore; - - device = nm_manager_get_device(NM_MANAGER_GET, name, NM_DEVICE_TYPE_OVS_INTERFACE); - if (device && connection_uuid) { - connection = - nm_settings_get_connection_by_uuid(nm_device_get_settings(device), connection_uuid); - } - - /* The patch interface which gets created first is expected to - * fail because the second patch doesn't exist yet. Ignore all - * failures of patch interfaces. */ - if (connection && (c = nm_settings_connection_get_connection(connection)) - && (type = nm_connection_get_connection_type(c)) - && nm_streq0(type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) - && (s_ovs_int = nm_connection_get_setting_ovs_interface(c)) - && nm_streq0(nm_setting_ovs_interface_get_interface_type(s_ovs_int), "patch")) - is_patch = TRUE; - - ignore = !device || is_patch; - - _NMLOG(ignore ? LOGL_DEBUG : LOGL_INFO, - name, - connection_uuid, - "ovs interface \"%s\" (%s) failed%s: %s", - name, - connection_uuid, - ignore ? " (ignored)" : "", - error); - - if (ignore) - return; - - if (connection) { - nm_settings_connection_autoconnect_blocked_reason_set( - connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, - TRUE); - } - - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); -} - -static void -start(NMDeviceFactory *self) -{ - NMOvsdb *ovsdb; - - ovsdb = nm_ovsdb_get(); - - g_signal_connect_object(ovsdb, - NM_OVSDB_DEVICE_ADDED, - G_CALLBACK(ovsdb_device_added), - self, - (GConnectFlags) 0); - g_signal_connect_object(ovsdb, - NM_OVSDB_DEVICE_REMOVED, - G_CALLBACK(ovsdb_device_removed), - self, - (GConnectFlags) 0); - g_signal_connect_object(ovsdb, - NM_OVSDB_INTERFACE_FAILED, - G_CALLBACK(ovsdb_interface_failed), - self, - (GConnectFlags) 0); -} - -static NMDevice * -create_device(NMDeviceFactory * self, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - NMDeviceType device_type = NM_DEVICE_TYPE_UNKNOWN; - const char * connection_type = NULL; - - if (g_strcmp0(iface, "ovs-system") == 0) { - *out_ignore = TRUE; - return NULL; - } - - if (connection) - connection_type = nm_connection_get_connection_type(connection); - - if (plink) - device_type = NM_DEVICE_TYPE_OVS_INTERFACE; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_INTERFACE; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_PORT; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_BRIDGE; - - return new_device_from_type(iface, device_type); -} - -static void -nm_ovs_factory_init(NMOvsFactory *self) -{} - -static void -nm_ovs_factory_class_init(NMOvsFactoryClass *klass) -{ - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - factory_class->get_supported_types = get_supported_types; - factory_class->start = start; - factory_class->create_device = create_device; -} diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c deleted file mode 100644 index 27ef789f..00000000 --- a/src/devices/ovs/nm-ovsdb.c +++ /dev/null @@ -1,2100 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-ovsdb.h" - -#include <gmodule.h> -#include <gio/gunixsocketaddress.h> - -#include "nm-glib-aux/nm-jansson.h" -#include "nm-core-utils.h" -#include "nm-core-internal.h" -#include "devices/nm-device.h" - -/*****************************************************************************/ - -#if JANSSON_VERSION_HEX < 0x020400 - #warning "requires at least libjansson 2.4" -#endif - -typedef struct { - char * name; - char * connection_uuid; - GPtrArray *interfaces; /* interface uuids */ -} OpenvswitchPort; - -typedef struct { - char * name; - char * connection_uuid; - GPtrArray *ports; /* port uuids */ -} OpenvswitchBridge; - -typedef struct { - char *name; - char *type; - char *connection_uuid; -} OpenvswitchInterface; - -/*****************************************************************************/ - -enum { DEVICE_ADDED, DEVICE_REMOVED, INTERFACE_FAILED, LAST_SIGNAL }; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - GSocketClient * client; - GSocketConnection *conn; - GCancellable * cancellable; - char buf[4096]; /* Input buffer */ - 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; - GArray * calls; /* Method calls waiting for a response. */ - GHashTable * interfaces; /* interface uuid => OpenvswitchInterface */ - GHashTable * ports; /* port uuid => OpenvswitchPort */ - GHashTable * bridges; /* bridge uuid => OpenvswitchBridge */ - char * db_uuid; - guint num_failures; -} NMOvsdbPrivate; - -struct _NMOvsdb { - GObject parent; - NMOvsdbPrivate _priv; -}; - -struct _NMOvsdbClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMOvsdb, nm_ovsdb, G_TYPE_OBJECT) - -#define NM_OVSDB_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMOvsdb, NM_IS_OVSDB) - -#define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "ovsdb", __VA_ARGS__) - -NM_DEFINE_SINGLETON_GETTER(NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB); - -/*****************************************************************************/ - -static void ovsdb_try_connect(NMOvsdb *self); -static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing); -static void ovsdb_read(NMOvsdb *self); -static void ovsdb_write(NMOvsdb *self); -static void ovsdb_next_command(NMOvsdb *self); - -/*****************************************************************************/ - -/* ovsdb command abstraction. */ - -typedef void (*OvsdbMethodCallback)(NMOvsdb *self, - json_t * response, - GError * error, - gpointer user_data); - -typedef enum { - OVSDB_MONITOR, - OVSDB_ADD_INTERFACE, - OVSDB_DEL_INTERFACE, - OVSDB_SET_INTERFACE_MTU, -} OvsdbCommand; - -typedef struct { - gint64 id; -#define COMMAND_PENDING -1 /* id not yet assigned */ - 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; - }; - }; -} OvsdbMethodCall; - -#define OVSDB_MAX_FAILURES 3 - -static void -_LOGT_call_do(const char *comment, OvsdbMethodCall *call, json_t *msg) -{ - gs_free char *str = NULL; - - if (msg) - str = json_dumps(msg, 0); - - switch (call->command) { - case OVSDB_MONITOR: - _LOGT("%s: monitor%s%s", comment, msg ? ": " : "", msg ? str : ""); - break; - case OVSDB_ADD_INTERFACE: - _LOGT("%s: add-iface 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 : ""); - break; - case OVSDB_DEL_INTERFACE: - _LOGT("%s: del-iface interface=%s%s%s", - comment, - call->ifname, - msg ? ": " : "", - msg ? str : ""); - break; - case OVSDB_SET_INTERFACE_MTU: - _LOGT("%s: set-iface-mtu interface=%s%s%s mtu=%u", - comment, - call->ifname, - msg ? ": " : "", - msg ? str : "", - call->mtu); - break; - } -} - -#define _LOGT_call(comment, call, message) \ - G_STMT_START \ - { \ - if (_LOGT_ENABLED()) \ - _LOGT_call_do((comment), (call), (message)); \ - } \ - G_STMT_END - -/** - * ovsdb_call_method: - * - * Queues the ovsdb command. Eventually fires the command right away if - * 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) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall *call; - - /* Ensure we're not unsynchronized before we queue the method call. */ - ovsdb_try_connect(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; - call->command = command; - call->callback = callback; - call->user_data = user_data; - - switch (call->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); - break; - case OVSDB_DEL_INTERFACE: - call->ifname = g_strdup(ifname); - break; - case OVSDB_SET_INTERFACE_MTU: - call->ifname = g_strdup(ifname); - call->mtu = mtu; - break; - } - - _LOGT_call("enqueue", call, NULL); - - ovsdb_next_command(self); -} - -/*****************************************************************************/ - -/* Create and process the JSON-RPC messages from ovsdb. */ - -/** - * _expect_ovs_bridges: - * - * Return a command that will fail the transaction if the actual set of - * bridges doesn't match @bridges. This is a way of detecting race conditions - * with other ovsdb clients that might be adding or removing bridges - * at the same time. - */ -static void -_expect_ovs_bridges(json_t *params, const char *db_uuid, json_t *bridges) -{ - json_array_append_new( - params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, [s, s]]]}", - "op", - "wait", - "table", - "Open_vSwitch", - "timeout", - 0, - "columns", - "bridges", - "until", - "==", - "rows", - "bridges", - "set", - bridges, - "where", - "_uuid", - "==", - "uuid", - db_uuid)); -} - -/** - * _set_ovs_bridges: - * - * Return a command that will update the list of bridges in @db_uuid - * database to @new_bridges. - */ -static void -_set_ovs_bridges(json_t *params, const char *db_uuid, json_t *new_bridges) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, [s, s]]]}", - "op", - "update", - "table", - "Open_vSwitch", - "row", - "bridges", - "set", - new_bridges, - "where", - "_uuid", - "==", - "uuid", - db_uuid)); -} - -/** - * _expect_bridge_ports: - * - * Return a command that will fail the transaction if the actual set of - * ports in bridge @ifname doesn't match @ports. This is a way of detecting - * race conditions with other ovsdb clients that might be adding or removing - * bridge ports at the same time. - */ -static void -_expect_bridge_ports(json_t *params, const char *ifname, json_t *ports) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", - "op", - "wait", - "table", - "Bridge", - "timeout", - 0, - "columns", - "ports", - "until", - "==", - "rows", - "ports", - "set", - ports, - "where", - "name", - "==", - ifname)); -} - -/** - * _set_bridge_ports: - * - * Return a command that will update the list of ports of bridge - * @ifname to @new_ports. - */ -static void -_set_bridge_ports(json_t *params, const char *ifname, json_t *new_ports) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Bridge", - "row", - "ports", - "set", - new_ports, - "where", - "name", - "==", - ifname)); -} - -static void -_set_bridge_mac(json_t *params, const char *ifname, const char *mac) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Bridge", - "row", - "other_config", - "map", - "hwaddr", - mac, - "where", - "name", - "==", - ifname)); -} - -/** - * _expect_port_interfaces: - * - * Return a command that will fail the transaction if the actual set of - * interfaces in port @ifname doesn't match @interfaces. This is a way of - * detecting race conditions with other ovsdb clients that might be adding - * or removing port interfaces at the same time. - */ -static void -_expect_port_interfaces(json_t *params, const char *ifname, json_t *interfaces) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", - "op", - "wait", - "table", - "Port", - "timeout", - 0, - "columns", - "interfaces", - "until", - "==", - "rows", - "interfaces", - "set", - interfaces, - "where", - "name", - "==", - ifname)); -} - -/** - * _set_port_interfaces: - * - * Return a command that will update the list of interfaces of port @ifname - * to @new_interfaces. - */ -static void -_set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Port", - "row", - "interfaces", - "set", - new_interfaces, - "where", - "name", - "==", - ifname)); -} - -/** - * _insert_interface: - * - * Returns an commands that adds new interface from a given connection. - */ -static void -_insert_interface(json_t * params, - NMConnection *interface, - NMDevice * interface_device, - const char * cloned_mac) -{ - const char * type = NULL; - NMSettingOvsInterface *s_ovs_iface; - NMSettingOvsDpdk * s_ovs_dpdk; - NMSettingOvsPatch * s_ovs_patch; - json_t * options = json_array(); - json_t * row; - guint32 mtu = 0; - - s_ovs_iface = nm_connection_get_setting_ovs_interface(interface); - if (s_ovs_iface) - type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); - - if (nm_streq0(type, "internal")) { - NMSettingWired *s_wired; - - s_wired = _nm_connection_get_setting(interface, NM_TYPE_SETTING_WIRED); - if (s_wired) - mtu = nm_setting_wired_get_mtu(s_wired); - } - - json_array_append_new(options, json_string("map")); - - s_ovs_dpdk = - (NMSettingOvsDpdk *) nm_connection_get_setting(interface, NM_TYPE_SETTING_OVS_DPDK); - if (!s_ovs_dpdk) - s_ovs_patch = nm_connection_get_setting_ovs_patch(interface); - - if (s_ovs_dpdk) { - json_array_append_new( - options, - json_pack("[[s, s]]", "dpdk-devargs", nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk))); - } else if (s_ovs_patch) { - json_array_append_new( - options, - json_pack("[[s, s]]", "peer", nm_setting_ovs_patch_get_peer(s_ovs_patch))); - } else { - json_array_append_new(options, json_array()); - } - - row = json_pack("{s:s, s:s, s:o, s:[s, [[s, s]]]}", - "name", - nm_connection_get_interface_name(interface), - "type", - type ?: "", - "options", - options, - "external_ids", - "map", - "NM.connection.uuid", - nm_connection_get_uuid(interface)); - - if (cloned_mac) - json_object_set_new(row, "mac", json_string(cloned_mac)); - - if (mtu != 0) - json_object_set_new(row, "mtu_request", json_integer(mtu)); - - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Interface", - "row", - row, - "uuid-name", - "rowInterface")); -} - -/** - * _insert_port: - * - * Returns an commands that adds new port from a given connection. - */ -static void -_insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) -{ - NMSettingOvsPort *s_ovs_port; - const char * vlan_mode = NULL; - guint tag = 0; - const char * lacp = NULL; - const char * bond_mode = NULL; - guint bond_updelay = 0; - guint bond_downdelay = 0; - json_t * row; - - s_ovs_port = nm_connection_get_setting_ovs_port(port); - - row = json_object(); - - if (s_ovs_port) { - vlan_mode = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); - tag = nm_setting_ovs_port_get_tag(s_ovs_port); - lacp = nm_setting_ovs_port_get_lacp(s_ovs_port); - bond_mode = nm_setting_ovs_port_get_bond_mode(s_ovs_port); - bond_updelay = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); - bond_downdelay = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); - } - - if (vlan_mode) - json_object_set_new(row, "vlan_mode", json_string(vlan_mode)); - if (tag) - json_object_set_new(row, "tag", json_integer(tag)); - if (lacp) - json_object_set_new(row, "lacp", json_string(lacp)); - if (bond_mode) - json_object_set_new(row, "bond_mode", json_string(bond_mode)); - if (bond_updelay) - json_object_set_new(row, "bond_updelay", json_integer(bond_updelay)); - if (bond_downdelay) - json_object_set_new(row, "bond_downdelay", json_integer(bond_downdelay)); - - 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))); - - /* Create a new one. */ - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Port", - "row", - row, - "uuid-name", - "rowPort")); -} - -/** - * _insert_bridge: - * - * Returns an commands that adds new bridge from a given connection. - */ -static void -_insert_bridge(json_t * params, - NMConnection *bridge, - NMDevice * bridge_device, - json_t * new_ports, - const char * cloned_mac) -{ - NMSettingOvsBridge *s_ovs_bridge; - const char * fail_mode = NULL; - gboolean mcast_snooping_enable = FALSE; - gboolean rstp_enable = FALSE; - gboolean stp_enable = FALSE; - const char * datapath_type = NULL; - json_t * row; - - s_ovs_bridge = nm_connection_get_setting_ovs_bridge(bridge); - - row = json_object(); - - if (s_ovs_bridge) { - fail_mode = nm_setting_ovs_bridge_get_fail_mode(s_ovs_bridge); - mcast_snooping_enable = nm_setting_ovs_bridge_get_mcast_snooping_enable(s_ovs_bridge); - rstp_enable = nm_setting_ovs_bridge_get_rstp_enable(s_ovs_bridge); - stp_enable = nm_setting_ovs_bridge_get_stp_enable(s_ovs_bridge); - datapath_type = nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge); - } - - if (fail_mode) - json_object_set_new(row, "fail_mode", json_string(fail_mode)); - if (mcast_snooping_enable) - json_object_set_new(row, "mcast_snooping_enable", json_boolean(mcast_snooping_enable)); - if (rstp_enable) - json_object_set_new(row, "rstp_enable", json_boolean(rstp_enable)); - if (stp_enable) - json_object_set_new(row, "stp_enable", json_boolean(stp_enable)); - if (datapath_type) - json_object_set_new(row, "datapath_type", json_string(datapath_type)); - - 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))); - - if (cloned_mac) { - json_object_set_new(row, - "other_config", - json_pack("[s, [[s, s]]]", "map", "hwaddr", cloned_mac)); - } - - /* Create a new one. */ - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Bridge", - "row", - row, - "uuid-name", - "rowBridge")); -} - -/** - * _inc_next_cfg: - * - * Returns an mutate command that bumps next_cfg upon successful completion - * of the transaction it is in. - */ -static json_t * -_inc_next_cfg(const char *db_uuid) -{ - return json_pack("{s:s, s:s, s:[[s, s, i]], s:[[s, s, [s, s]]]}", - "op", - "mutate", - "table", - "Open_vSwitch", - "mutations", - "next_cfg", - "+=", - 1, - "where", - "_uuid", - "==", - "uuid", - db_uuid); -} - -/** - * _add_interface: - * - * Adds an interface as specified by @interface connection, optionally creating - * a parent @port and @bridge if needed. - */ -static void -_add_interface(NMOvsdb * self, - json_t * params, - NMConnection *bridge, - NMConnection *port, - NMConnection *interface, - NMDevice * bridge_device, - NMDevice * interface_device) -{ - 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; - const char * port_name; - const char * interface_name; - OpenvswitchBridge * ovs_bridge = NULL; - OpenvswitchPort * ovs_port = NULL; - OpenvswitchInterface *ovs_interface = NULL; - nm_auto_decref_json json_t *bridges = NULL; - nm_auto_decref_json json_t *new_bridges = NULL; - nm_auto_decref_json json_t *ports = NULL; - nm_auto_decref_json json_t *new_ports = NULL; - nm_auto_decref_json json_t *interfaces = NULL; - nm_auto_decref_json json_t *new_interfaces = NULL; - gboolean has_interface = FALSE; - gboolean interface_is_local; - gs_free char * bridge_cloned_mac = NULL; - gs_free char * interface_cloned_mac = NULL; - GError * error = NULL; - int pi; - int ii; - - bridges = json_array(); - ports = json_array(); - interfaces = json_array(); - new_bridges = json_array(); - new_ports = json_array(); - new_interfaces = json_array(); - - bridge_name = nm_connection_get_interface_name(bridge); - port_name = nm_connection_get_interface_name(port); - interface_name = nm_connection_get_interface_name(interface); - interface_is_local = nm_streq0(bridge_name, interface_name); - - /* Determine cloned MAC addresses */ - if (!nm_device_hw_addr_get_cloned(bridge_device, - bridge, - FALSE, - &bridge_cloned_mac, - NULL, - &error)) { - _LOGW("Cannot determine cloned MAC for OVS %s '%s': %s", - "bridge", - bridge_name, - error->message); - g_clear_error(&error); - } - - if (!nm_device_hw_addr_get_cloned(interface_device, - interface, - FALSE, - &interface_cloned_mac, - NULL, - &error)) { - _LOGW("Cannot determine cloned MAC for OVS %s '%s': %s", - "interface", - interface_name, - error->message); - g_clear_error(&error); - } - - /* For local interfaces, ovs complains if it finds a - * MAC address in the Interface table because it only takes - * the MAC from the Bridge table. - * Set any cloned MAC present in a local interface connection - * into the Bridge table, unless conflicting with the bridge MAC. */ - if (interface_is_local && interface_cloned_mac) { - if (bridge_cloned_mac && !nm_streq(interface_cloned_mac, bridge_cloned_mac)) { - _LOGW("Cloned MAC '%s' of local ovs-interface '%s' conflicts with MAC '%s' of bridge " - "'%s'", - interface_cloned_mac, - interface_name, - bridge_cloned_mac, - bridge_name); - nm_clear_g_free(&interface_cloned_mac); - } else { - nm_clear_g_free(&bridge_cloned_mac); - bridge_cloned_mac = g_steal_pointer(&interface_cloned_mac); - _LOGT("'%s' is a local ovs-interface, the MAC will be set on ovs-bridge '%s'", - interface_name, - bridge_name); - } - } - - 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)); - - if (g_strcmp0(ovs_bridge->name, bridge_name) != 0 - || g_strcmp0(ovs_bridge->connection_uuid, nm_connection_get_uuid(bridge)) != 0) - 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); - - 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) { - 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); - - 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; - } - } - - break; - } - - break; - } - - json_array_extend(new_bridges, bridges); - json_array_extend(new_ports, ports); - json_array_extend(new_interfaces, interfaces); - - if (json_array_size(interfaces) == 0) { - /* Need to create a port. */ - if (json_array_size(ports) == 0) { - /* Need to create a bridge. */ - _expect_ovs_bridges(params, priv->db_uuid, bridges); - json_array_append_new(new_bridges, json_pack("[s, s]", "named-uuid", "rowBridge")); - _set_ovs_bridges(params, priv->db_uuid, new_bridges); - _insert_bridge(params, bridge, bridge_device, new_ports, bridge_cloned_mac); - } else { - /* Bridge already exists. */ - g_return_if_fail(ovs_bridge); - _expect_bridge_ports(params, ovs_bridge->name, ports); - _set_bridge_ports(params, bridge_name, new_ports); - if (bridge_cloned_mac && interface_is_local) - _set_bridge_mac(params, bridge_name, bridge_cloned_mac); - } - - json_array_append_new(new_ports, json_pack("[s, s]", "named-uuid", "rowPort")); - _insert_port(params, port, new_interfaces); - } else { - /* Port already exists */ - g_return_if_fail(ovs_port); - _expect_port_interfaces(params, ovs_port->name, interfaces); - _set_port_interfaces(params, port_name, new_interfaces); - } - - if (!has_interface) { - _insert_interface(params, interface, interface_device, interface_cloned_mac); - json_array_append_new(new_interfaces, json_pack("[s, s]", "named-uuid", "rowInterface")); - } -} - -/** - * _delete_interface: - * - * Removes an interface of @ifname name, collecting empty ports and bridge - * if last item is removed from them. - */ -static void -_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; - OpenvswitchPort * ovs_port; - OpenvswitchInterface *ovs_interface; - nm_auto_decref_json json_t *bridges = NULL; - nm_auto_decref_json json_t *new_bridges = NULL; - gboolean bridges_changed; - gboolean ports_changed; - gboolean interfaces_changed; - int pi; - int ii; - - bridges = json_array(); - new_bridges = json_array(); - bridges_changed = FALSE; - - g_hash_table_iter_init(&iter, priv->bridges); - while (g_hash_table_iter_next(&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { - nm_auto_decref_json json_t *ports = NULL; - nm_auto_decref_json json_t *new_ports = NULL; - - ports = json_array(); - new_ports = json_array(); - ports_changed = FALSE; - - json_array_append_new(bridges, json_pack("[s,s]", "uuid", bridge_uuid)); - - for (pi = 0; pi < ovs_bridge->ports->len; pi++) { - nm_auto_decref_json json_t *interfaces = NULL; - nm_auto_decref_json json_t *new_interfaces = NULL; - - 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); - - json_array_append_new(ports, json_pack("[s,s]", "uuid", port_uuid)); - - interfaces_changed = FALSE; - - 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; - } - - 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); - - json_array_append_new(interfaces, json_pack("[s,s]", "uuid", interface_uuid)); - - if (ovs_interface) { - if (strcmp(ovs_interface->name, ifname) == 0) { - /* skip the interface */ - interfaces_changed = TRUE; - continue; - } - } else { - /* This would be a violation of ovsdb's reference integrity (a bug). */ - _LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); - } - - json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid)); - } - - if (json_array_size(new_interfaces) == 0) { - ports_changed = TRUE; - } else { - if (interfaces_changed) { - _expect_port_interfaces(params, ovs_port->name, interfaces); - _set_port_interfaces(params, ovs_port->name, new_interfaces); - } - json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid)); - } - } - - if (json_array_size(new_ports) == 0) { - bridges_changed = TRUE; - } else { - if (ports_changed) { - _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)); - } - } - - if (bridges_changed) { - _expect_ovs_bridges(params, priv->db_uuid, bridges); - _set_ovs_bridges(params, priv->db_uuid, new_bridges); - } -} - -/** - * ovsdb_next_command: - * - * Translates a higher level operation (add/remove bridge/port) to a RFC 7047 - * command serialized into JSON ands sends it over to the database. - - * Only called when no command is waiting for a response, since the serialized - * command might depend on result of a previous one (add and remove need to - * include an up to date bridge list in their transactions to rule out races). - */ -static void -ovsdb_next_command(NMOvsdb *self) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall * call = NULL; - 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) - return; - call->id = priv->seq++; - - switch (call->command) { - case OVSDB_MONITOR: - msg = json_pack("{s:i, s:s, s:[s, n, {" - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s, s]}]," - " s:[{s:[]}]" - "}]}", - "id", - call->id, - "method", - "monitor", - "params", - "Open_vSwitch", - "Bridge", - "columns", - "name", - "ports", - "external_ids", - "Port", - "columns", - "name", - "interfaces", - "external_ids", - "Interface", - "columns", - "name", - "type", - "external_ids", - "error", - "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); - - 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)); - - 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); - break; - } - - g_return_if_fail(msg); - _LOGT_call("send", call, msg); - cmd = json_dumps(msg, 0); - - g_string_append(priv->output, cmd); - free(cmd); - - ovsdb_write(self); -} - -/** - * _uuids_to_array: - * - * This tidies up the somewhat non-straightforward way ovsdb represents an array - * of UUID elements. The single element is a tuple (called <atom> in RFC7047), - * - * [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ] - * - * while the list of multiple UUIDs are turned into a set of such tuples ("atoms"): - * - * [ "set", [ [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ], - * [ "uuid", "185c93f6-0b39-424e-8587-77d074aa7ce0" ], ... ] ] - */ -static void -_uuids_to_array(GPtrArray *array, const json_t *items) -{ - const char *key; - json_t * value; - size_t index = 0; - json_t * set_value; - size_t set_index; - - while (index < json_array_size(items)) { - key = json_string_value(json_array_get(items, index)); - index++; - value = json_array_get(items, index); - index++; - - if (!value) - 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); - } - } - } -} - -static char * -_connection_uuid_from_external_ids(json_t *external_ids) -{ - json_t *value; - size_t index; - - if (g_strcmp0("map", json_string_value(json_array_get(external_ids, 0))) != 0) - return NULL; - - 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))); - } - - return NULL; -} - -/** - * ovsdb_got_update: - * - * Called when we've got an "update" method call (we asked for it with the monitor - * command). We use it to maintain a consistent view of bridge list regardless of - * whether the changes are done by us or externally. - */ -static void -ovsdb_got_update(NMOvsdb *self, json_t *msg) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - json_t * ovs = NULL; - json_t * bridge = NULL; - json_t * port = NULL; - json_t * interface = NULL; - json_t * items; - json_t * external_ids; - 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; - - if (json_unpack_ex(msg, - &json_error, - 0, - "{s?:o, s?:o, s?:o, s?:o}", - "Open_vSwitch", - &ovs, - "Bridge", - &bridge, - "Port", - &port, - "Interface", - &interface) - == -1) { - /* This doesn't really have to be an error; the key might - * be missing if there really are no bridges present. */ - _LOGD("Bad update: %s", json_error.text); - } - - if (ovs) { - const char *s; - - iter = json_object_iter(ovs); - s = json_object_iter_key(iter); - if (s) - nm_utils_strdup_reset(&priv->db_uuid, s); - } - - /* Interfaces */ - json_object_foreach(interface, key, value) - { - json_t * error = NULL; - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:s, s?:o, s:o}}", - "new", - "name", - &name, - "type", - &type, - "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); - } - } - g_hash_table_remove(priv->interfaces, key); - } - - 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", - 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)); - } - } - } - - /* Ports */ - json_object_foreach(port, key, value) - { - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:o, s:o}}", - "new", - "name", - &name, - "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); - } - - 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->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); - } - } - } - - /* Bridges */ - json_object_foreach(bridge, key, value) - { - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:o, s:o}}", - "new", - "name", - &name, - "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); - } - - 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->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); - } - } - } -} - -/** - * ovsdb_got_echo: - * - * Only implemented because the specification mandates it. Actual ovsdb hasn't been - * seen doing this. - */ -static void -ovsdb_got_echo(NMOvsdb *self, json_int_t id, json_t *data) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - nm_auto_decref_json json_t *msg = NULL; - char * reply; - gboolean output_was_empty; - - output_was_empty = priv->output->len == 0; - - msg = json_pack("{s:I, s:O}", "id", id, "result", data); - reply = json_dumps(msg, 0); - g_string_append(priv->output, reply); - free(reply); - - if (output_was_empty) - ovsdb_write(self); -} - -/** - * ovsdb_got_msg:: - * - * Called when a complete JSON object was seen and unmarshalled. - * Either finishes a method call or processes a method call. - */ -static void -ovsdb_got_msg(NMOvsdb *self, json_t *msg) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - json_error_t json_error = { - 0, - }; - json_t * json_id = NULL; - gint64 id = -1; - const char * method = NULL; - json_t * params = NULL; - json_t * result = NULL; - json_t * error = NULL; - OvsdbMethodCall * call = NULL; - OvsdbMethodCallback callback; - gpointer user_data; - gs_free_error GError *local = NULL; - - if (json_unpack_ex(msg, - &json_error, - 0, - "{s?:o, s?:s, s?:o, s?:o, s?:o}", - "id", - &json_id, - "method", - &method, - "params", - ¶ms, - "result", - &result, - "error", - &error) - == -1) { - _LOGW("couldn't grok the message: %s", json_error.text); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - - if (json_is_number(json_id)) - id = json_integer_value(json_id); - - if (method) { - /* It's a method call! */ - if (!params) { - _LOGW("a method call with no params: '%s'", method); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - - if (g_strcmp0(method, "update") == 0) { - /* This is a update method call. */ - ovsdb_got_update(self, json_array_get(params, 1)); - } else if (g_strcmp0(method, "echo") == 0) { - /* This is an echo request. */ - ovsdb_got_echo(self, id, params); - } else { - _LOGW("got an unknown method call: '%s'", method); - } - return; - } - - if (id > -1) { - /* This is a response to a method call. */ - if (!priv->calls->len) { - _LOGE("there are no queued calls expecting response %" G_GUINT64_FORMAT, id); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - call = &g_array_index(priv->calls, OvsdbMethodCall, 0); - if (call->id != id) { - _LOGE("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT, - call->id, - id); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - /* Cool, we found a corresponding call. Finish it. */ - - _LOGT_call("response", call, msg); - - if (!json_is_null(error)) { - /* The response contains an error. */ - g_set_error(&local, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Error call to OVSDB returned an error: %s", - json_string_value(error)); - } - - callback = call->callback; - user_data = call->user_data; - g_array_remove_index(priv->calls, 0); - callback(self, result, local, user_data); - priv->num_failures = 0; - - /* Don't progress further commands in case the callback hit an error - * and disconnected us. */ - if (!priv->conn) - return; - - /* Now we're free to serialize and send the next command, if any. */ - ovsdb_next_command(self); - - return; - } - - /* This is a message we are not interested in. */ - _LOGW("got an unknown message, ignoring"); -} - -/*****************************************************************************/ - -/* Lower level marshalling and demarshalling of the JSON-RPC traffic on the - * ovsdb socket. */ - -static size_t -_json_callback(void *buffer, size_t buflen, void *user_data) -{ - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - if (priv->bufp == priv->input->len) { - /* No more bytes buffered for decoding. */ - return 0; - } - - /* Pass one more byte to the JSON decoder. */ - *(char *) buffer = priv->input->str[priv->bufp]; - priv->bufp++; - - return (size_t) 1; -} - -/** - * ovsdb_read_cb: - * - * Read out the data available from the ovsdb socket and try to deserialize - * the JSON. If we see a complete object, pass it upwards to ovsdb_got_msg(). - */ -static void -ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GInputStream * stream = G_INPUT_STREAM(source_object); - GError * error = NULL; - gssize size; - json_t * msg; - json_error_t json_error = { - 0, - }; - - size = g_input_stream_read_finish(stream, res, &error); - if (size == -1) { - /* ovsdb-server was possibly restarted */ - _LOGW("short read from ovsdb: %s", error->message); - priv->num_failures++; - g_clear_error(&error); - ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); - return; - } - - g_string_append_len(priv->input, priv->buf, size); - do { - priv->bufp = 0; - /* The callback always eats up only up to a single byte. This makes - * it possible for us to identify complete JSON objects in spite of - * us not knowing the length in advance. */ - msg = json_load_callback(_json_callback, self, JSON_DISABLE_EOF_CHECK, &json_error); - if (msg) { - ovsdb_got_msg(self, msg); - g_string_erase(priv->input, 0, priv->bufp); - } - json_decref(msg); - } while (msg); - - if (!priv->conn) - return; - - if (size) - ovsdb_read(self); -} - -static void -ovsdb_read(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(priv->conn)), - priv->buf, - sizeof(priv->buf), - G_PRIORITY_DEFAULT, - NULL, - ovsdb_read_cb, - self); -} - -static void -ovsdb_write_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GOutputStream * stream = G_OUTPUT_STREAM(source_object); - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GError * error = NULL; - gssize size; - - size = g_output_stream_write_finish(stream, res, &error); - if (size == -1) { - /* ovsdb-server was possibly restarted */ - _LOGW("short write to ovsdb: %s", error->message); - priv->num_failures++; - g_clear_error(&error); - ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); - return; - } - - if (!priv->conn) - return; - - g_string_erase(priv->output, 0, size); - - ovsdb_write(self); -} - -static void -ovsdb_write(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GOutputStream * stream; - - if (!priv->output->len) - return; - - stream = g_io_stream_get_output_stream(G_IO_STREAM(priv->conn)); - if (g_output_stream_has_pending(stream)) - return; - - g_output_stream_write_async(stream, - priv->output->str, - priv->output->len, - G_PRIORITY_DEFAULT, - NULL, - ovsdb_write_cb, - self); -} - -/*****************************************************************************/ - -/* Routines to maintain the ovsdb connection. */ - -/** - * ovsdb_disconnect: - * - * Clean up the internal state to the point equivalent to before connecting. - * Apart from clean shutdown this is a good response to unexpected trouble, - * since the next method call attempt a will trigger reconnect which hopefully - * puts us back in sync. - */ -static void -ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall * call; - OvsdbMethodCallback callback; - gpointer user_data; - gs_free_error GError *error = NULL; - - nm_assert(!retry || !is_disposing); - - if (!priv->client) - return; - - _LOGD("disconnecting from ovsdb, retry %d", retry); - - if (retry) { - if (priv->calls->len != 0) - g_array_index(priv->calls, OvsdbMethodCall, 0).id = COMMAND_PENDING; - } else { - nm_utils_error_set_cancelled(&error, is_disposing, "NMOvsdb"); - - while (priv->calls->len) { - call = &g_array_index(priv->calls, OvsdbMethodCall, priv->calls->len - 1); - callback = call->callback; - user_data = call->user_data; - g_array_remove_index(priv->calls, priv->calls->len - 1); - callback(self, NULL, error, user_data); - } - } - - priv->bufp = 0; - g_string_truncate(priv->input, 0); - g_string_truncate(priv->output, 0); - g_clear_object(&priv->client); - g_clear_object(&priv->conn); - nm_clear_g_free(&priv->db_uuid); - nm_clear_g_cancellable(&priv->cancellable); - - if (retry) - ovsdb_try_connect(self); -} - -static void -_monitor_bridges_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data) -{ - if (error) { - if (!nm_utils_error_is_cancelled_or_disposing(error)) { - _LOGI("%s", error->message); - ovsdb_disconnect(self, FALSE, FALSE); - } - return; - } - - /* Treat the first response the same as the subsequent "update" - * messages we eventually get. */ - ovsdb_got_update(self, result); -} - -static void -_client_connect_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GSocketClient * client = G_SOCKET_CLIENT(source_object); - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate * priv; - GError * error = NULL; - GSocketConnection *conn; - - conn = g_socket_client_connect_finish(client, res, &error); - if (conn == NULL) { - if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - _LOGI("%s", error->message); - - ovsdb_disconnect(self, FALSE, FALSE); - g_clear_error(&error); - return; - } - - priv = NM_OVSDB_GET_PRIVATE(self); - priv->conn = conn; - g_clear_object(&priv->cancellable); - - ovsdb_read(self); - ovsdb_next_command(self); -} - -/** - * ovsdb_try_connect: - * - * Establish a connection to ovsdb unless it's already established or being - * established. Queues a monitor command as a very first one so that we're in - * sync when other commands are issued. - */ -static void -ovsdb_try_connect(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GSocketAddress *addr; - - if (priv->client) - return; - - /* TODO: This should probably be made configurable via NetworkManager.conf */ - addr = g_unix_socket_address_new(RUNSTATEDIR "/openvswitch/db.sock"); - - priv->client = g_socket_client_new(); - priv->cancellable = g_cancellable_new(); - g_socket_client_connect_async(priv->client, - G_SOCKET_CONNECTABLE(addr), - priv->cancellable, - _client_connect_cb, - self); - g_object_unref(addr); - - /* 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); -} - -/*****************************************************************************/ - -/* Public functions useful for NMDeviceOpenvswitch to maintain the life cycle of - * their ovsdb entries without having to deal with ovsdb complexities themselves. */ - -typedef struct { - NMOvsdbCallback callback; - gpointer user_data; -} OvsdbCall; - -static void -_transact_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data) -{ - OvsdbCall * call = user_data; - const char *err; - const char *err_details; - size_t index; - json_t * value; - - if (error) - goto out; - - 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, - G_IO_ERROR_FAILED, - "Error running the transaction: %s: %s", - err, - err_details); - goto out; - } - } - -out: - call->callback(error, call->user_data); - g_slice_free(OvsdbCall, call); -} - -static OvsdbCall * -ovsdb_call_new(NMOvsdbCallback callback, gpointer user_data) -{ - OvsdbCall *call; - - call = g_slice_new(OvsdbCall); - call->callback = callback; - call->user_data = user_data; - - return call; -} - -void -nm_ovsdb_add_interface(NMOvsdb * self, - NMConnection * bridge, - NMConnection * port, - NMConnection * interface, - NMDevice * bridge_device, - NMDevice * interface_device, - NMOvsdbCallback callback, - 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); -} - -void -nm_ovsdb_del_interface(NMOvsdb * self, - const char * ifname, - NMOvsdbCallback callback, - 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); -} - -void -nm_ovsdb_set_interface_mtu(NMOvsdb * self, - const char * ifname, - guint32 mtu, - NMOvsdbCallback callback, - 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); -} - -/*****************************************************************************/ - -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); - - ovsdb_try_connect(self); -} - -static void -dispose(GObject *object) -{ - NMOvsdb * self = NM_OVSDB(object); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - ovsdb_disconnect(self, FALSE, TRUE); - - if (priv->input) { - g_string_free(priv->input, TRUE); - priv->input = NULL; - } - if (priv->output) { - g_string_free(priv->output, TRUE); - priv->output = NULL; - } - if (priv->calls) { - g_array_free(priv->calls, TRUE); - priv->calls = NULL; - } - - nm_clear_pointer(&priv->bridges, g_hash_table_destroy); - nm_clear_pointer(&priv->ports, g_hash_table_destroy); - nm_clear_pointer(&priv->interfaces, g_hash_table_destroy); - - G_OBJECT_CLASS(nm_ovsdb_parent_class)->dispose(object); -} - -static void -nm_ovsdb_class_init(NMOvsdbClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - - signals[DEVICE_ADDED] = g_signal_new(NM_OVSDB_DEVICE_ADDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_UINT); - - signals[DEVICE_REMOVED] = g_signal_new(NM_OVSDB_DEVICE_REMOVED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_UINT); - - signals[INTERFACE_FAILED] = g_signal_new(NM_OVSDB_INTERFACE_FAILED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); -} diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h deleted file mode 100644 index c9eee19c..00000000 --- a/src/devices/ovs/nm-ovsdb.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_OVSDB_H__ -#define __NETWORKMANAGER_OVSDB_H__ - -#define NM_TYPE_OVSDB (nm_ovsdb_get_type()) -#define NM_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) -#define NM_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVSDB, NMOvsdbClass)) -#define NM_IS_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVSDB)) -#define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVSDB)) -#define NM_OVSDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_OVSDB, NMOvsdbClass)) - -#define NM_OVSDB_DEVICE_ADDED "device-added" -#define NM_OVSDB_DEVICE_REMOVED "device-removed" -#define NM_OVSDB_INTERFACE_FAILED "interface-failed" - -typedef struct _NMOvsdb NMOvsdb; -typedef struct _NMOvsdbClass NMOvsdbClass; - -typedef void (*NMOvsdbCallback)(GError *error, gpointer user_data); - -NMOvsdb *nm_ovsdb_get(void); - -GType nm_ovsdb_get_type(void); - -void nm_ovsdb_add_interface(NMOvsdb * self, - NMConnection * bridge, - NMConnection * port, - NMConnection * interface, - NMDevice * bridge_device, - NMDevice * interface_device, - NMOvsdbCallback callback, - gpointer user_data); - -void nm_ovsdb_del_interface(NMOvsdb * self, - const char * ifname, - NMOvsdbCallback callback, - gpointer user_data); - -void nm_ovsdb_set_interface_mtu(NMOvsdb * self, - const char * ifname, - guint32 mtu, - NMOvsdbCallback callback, - gpointer user_data); - -#endif /* __NETWORKMANAGER_OVSDB_H__ */ |