/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ #include "src/core/nm-default-daemon.h" #include "nm-device-ovs-bridge.h" #include "nm-device-ovs-interface.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 "nm-setting-ovs-external-ids.h" #include "nm-setting-ovs-other-config.h" #include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge #include "devices/nm-device-logging.h" /*****************************************************************************/ 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 attachment 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 gboolean ready_for_ip_config(NMDevice *device, gboolean is_manual) { return FALSE; } static void act_stage3_ip_config(NMDevice *device, int addr_family) { nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); } static NMTernary attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure, GCancellable *cancellable, NMDeviceAttachPortCallback callback, gpointer user_data) { if (!configure) return TRUE; if (!NM_IS_DEVICE_OVS_PORT(port)) return FALSE; return TRUE; } static NMTernary detach_port(NMDevice *device, NMDevice *port, gboolean configure, GCancellable *cancellable, NMDeviceAttachPortCallback callback, gpointer user_data) { return TRUE; } void nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) { NMDeviceType device_type; GType type; nm_assert(NM_IS_DEVICE(self)); nm_assert(g_type_parent(G_TYPE_FROM_INSTANCE(self)) == NM_TYPE_DEVICE); /* NMDevice's reapply_connection() doesn't do anything. No need to call the parent * implementation. */ _LOGD(LOGD_DEVICE, "reapplying settings for OVS device"); type = G_OBJECT_TYPE(self); if (type == NM_TYPE_DEVICE_OVS_INTERFACE) device_type = NM_DEVICE_TYPE_OVS_INTERFACE; else if (type == NM_TYPE_DEVICE_OVS_PORT) device_type = NM_DEVICE_TYPE_OVS_PORT; else { nm_assert(type == NM_TYPE_DEVICE_OVS_BRIDGE); device_type = NM_DEVICE_TYPE_OVS_BRIDGE; } nm_ovsdb_set_reapply(nm_ovsdb_get(), device_type, nm_device_get_ip_iface(self), nm_simple_connection_new_clone(con_new), _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_OTHER_CONFIG), _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); } static gboolean can_reapply_change(NMDevice *device, const char *setting_name, NMSetting *s_old, NMSetting *s_new, GHashTable *diffs, GError **error) { NMDeviceClass *device_class = NM_DEVICE_CLASS(nm_device_ovs_bridge_parent_class); if (nm_streq(setting_name, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { return nm_device_hash_check_invalid_keys(diffs, NM_SETTING_OVS_BRIDGE_SETTING_NAME, error, NM_SETTING_OVS_BRIDGE_FAIL_MODE, NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, NM_SETTING_OVS_BRIDGE_STP_ENABLE); } if (NM_IN_STRSET(setting_name, NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME)) return TRUE; return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); } /*****************************************************************************/ 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, .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; 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_controller = 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 = act_stage3_ip_config; device_class->ready_for_ip_config = ready_for_ip_config; device_class->attach_port = attach_port; device_class->detach_port = detach_port; device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = nm_device_ovs_reapply_connection; }