Blame src/devices/ovs/nm-ovs-factory.c

Packit Service 87a54e
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit 5756e2
/*
Packit 5756e2
 * Copyright (C) 2017 Red Hat, Inc.
Packit 5756e2
 */
Packit 5756e2
Packit 5756e2
#include "nm-default.h"
Packit 5756e2
Packit 5756e2
#include "nm-manager.h"
Packit 5756e2
#include "nm-ovsdb.h"
Packit 5756e2
#include "nm-device-ovs-interface.h"
Packit 5756e2
#include "nm-device-ovs-port.h"
Packit 5756e2
#include "nm-device-ovs-bridge.h"
Packit 5756e2
#include "platform/nm-platform.h"
Packit 5756e2
#include "nm-core-internal.h"
Packit 5756e2
#include "settings/nm-settings.h"
Packit 5756e2
#include "devices/nm-device-factory.h"
Packit 5756e2
#include "devices/nm-device-private.h"
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    NMDeviceFactory parent;
Packit 5756e2
} NMOvsFactory;
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    NMDeviceFactoryClass parent;
Packit 5756e2
} NMOvsFactoryClass;
Packit 5756e2
Packit Service a1bd4f
#define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type())
Packit Service a1bd4f
#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory))
Packit Service a1bd4f
#define NM_OVS_FACTORY_CLASS(klass) \
Packit Service a1bd4f
    (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass))
Packit Service a1bd4f
#define NM_IS_OVS_FACTORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVS_FACTORY))
Packit Service a1bd4f
#define NM_IS_OVS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVS_FACTORY))
Packit Service a1bd4f
#define NM_OVS_FACTORY_GET_CLASS(obj) \
Packit Service a1bd4f
    (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass))
Packit 5756e2
Packit Service a1bd4f
static GType nm_ovs_factory_get_type(void);
Packit Service a1bd4f
G_DEFINE_TYPE(NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY)
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
#define _NMLOG_DOMAIN LOGD_DEVICE
Packit Service a1bd4f
#define _NMLOG(level, ifname, con_uuid, ...)                                                  \
Packit Service a1bd4f
    G_STMT_START                                                                              \
Packit Service a1bd4f
    {                                                                                         \
Packit Service a1bd4f
        nm_log((level),                                                                       \
Packit Service a1bd4f
               _NMLOG_DOMAIN,                                                                 \
Packit Service a1bd4f
               (ifname),                                                                      \
Packit Service a1bd4f
               (con_uuid),                                                                    \
Packit Service a1bd4f
               "ovs: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
Packit Service a1bd4f
    }                                                                                         \
Packit Service a1bd4f
    G_STMT_END
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
NM_DEVICE_FACTORY_DECLARE_TYPES(
Packit Service a1bd4f
    NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH)
Packit Service a1bd4f
        NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_OVS_BRIDGE_SETTING_NAME,
Packit Service a1bd4f
                                                NM_SETTING_OVS_INTERFACE_SETTING_NAME,
Packit Service a1bd4f
                                                NM_SETTING_OVS_PORT_SETTING_NAME))
Packit 5756e2
Packit 5756e2
G_MODULE_EXPORT NMDeviceFactory *
Packit Service a1bd4f
                nm_device_factory_create(GError **error)
Packit 5756e2
{
Packit Service a1bd4f
    nm_manager_set_capability(NM_MANAGER_GET, NM_CAPABILITY_OVS);
Packit Service a1bd4f
    return g_object_new(NM_TYPE_OVS_FACTORY, NULL);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static NMDevice *
Packit Service a1bd4f
new_device_from_type(const char *name, NMDeviceType device_type)
Packit 5756e2
{
Packit Service a1bd4f
    GType       type;
Packit Service a1bd4f
    const char *type_desc;
Packit Service a1bd4f
    NMLinkType  link_type = NM_LINK_TYPE_NONE;
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_manager_get_device(NM_MANAGER_GET, name, device_type))
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE) {
Packit Service a1bd4f
        type      = NM_TYPE_DEVICE_OVS_INTERFACE;
Packit Service a1bd4f
        type_desc = "Open vSwitch Interface";
Packit Service a1bd4f
        link_type = NM_LINK_TYPE_OPENVSWITCH;
Packit Service a1bd4f
    } else if (device_type == NM_DEVICE_TYPE_OVS_PORT) {
Packit Service a1bd4f
        type      = NM_TYPE_DEVICE_OVS_PORT;
Packit Service a1bd4f
        type_desc = "Open vSwitch Port";
Packit Service a1bd4f
    } else if (device_type == NM_DEVICE_TYPE_OVS_BRIDGE) {
Packit Service a1bd4f
        type      = NM_TYPE_DEVICE_OVS_BRIDGE;
Packit Service a1bd4f
        type_desc = "Open vSwitch Bridge";
Packit Service a1bd4f
    } else {
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return g_object_new(type,
Packit Service a1bd4f
                        NM_DEVICE_IFACE,
Packit Service a1bd4f
                        name,
Packit Service a1bd4f
                        NM_DEVICE_DRIVER,
Packit Service a1bd4f
                        "openvswitch",
Packit Service a1bd4f
                        NM_DEVICE_DEVICE_TYPE,
Packit Service a1bd4f
                        device_type,
Packit Service a1bd4f
                        NM_DEVICE_TYPE_DESC,
Packit Service a1bd4f
                        type_desc,
Packit Service a1bd4f
                        NM_DEVICE_LINK_TYPE,
Packit Service a1bd4f
                        link_type,
Packit Service a1bd4f
                        NULL);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service 018b0a
ovsdb_device_added(NMOvsdb *        ovsdb,
Packit Service 018b0a
                   const char *     name,
Packit Service 018b0a
                   guint            device_type_i,
Packit Service 018b0a
                   const char *     subtype,
Packit Service 018b0a
                   NMDeviceFactory *self)
Packit 5756e2
{
Packit Service a1bd4f
    const NMDeviceType device_type = device_type_i;
Packit Service a1bd4f
    NMDevice *         device;
Packit 5756e2
Packit Service 018b0a
    if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE
Packit Service 018b0a
        && !NM_IN_STRSET(subtype, "internal", "patch")) {
Packit Service 018b0a
        /* system interfaces refer to kernel devices and
Packit Service 018b0a
         * don't need to be created by this factory. Ignore
Packit Service 018b0a
         * anything that is not an internal or patch
Packit Service 018b0a
         * interface. */
Packit Service 018b0a
        return;
Packit Service 018b0a
    }
Packit Service 018b0a
Packit Service a1bd4f
    device = new_device_from_type(name, device_type);
Packit Service a1bd4f
    if (!device)
Packit Service a1bd4f
        return;
Packit 5756e2
Packit Service a1bd4f
    g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device);
Packit Service a1bd4f
    g_object_unref(device);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service 018b0a
ovsdb_device_removed(NMOvsdb *        ovsdb,
Packit Service 018b0a
                     const char *     name,
Packit Service 018b0a
                     guint            device_type_i,
Packit Service 018b0a
                     const char *     subtype,
Packit Service 018b0a
                     NMDeviceFactory *self)
Packit 5756e2
{
Packit Service a1bd4f
    const NMDeviceType device_type = device_type_i;
Packit Service 018b0a
    NMDevice *         device      = NULL;
Packit Service a1bd4f
    NMDeviceState      device_state;
Packit Service 018b0a
    gboolean           is_system_interface = FALSE;
Packit Service 018b0a
Packit Service 018b0a
    if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE
Packit Service 018b0a
        && !NM_IN_STRSET(subtype, "internal", "patch", "system"))
Packit Service 018b0a
        return;
Packit Service 018b0a
Packit Service 018b0a
    if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE && nm_streq0(subtype, "system")) {
Packit Service 018b0a
        NMDevice *             d;
Packit Service 018b0a
        const CList *          list;
Packit Service 018b0a
        NMSettingOvsInterface *s_ovs_int;
Packit Service 018b0a
Packit Service 018b0a
        /* The device associated to an OVS system interface can be of
Packit Service 018b0a
         * any kind. Find an interface with the same name and which has
Packit Service 018b0a
         * the OVS-interface setting. */
Packit Service 018b0a
        is_system_interface = TRUE;
Packit Service 018b0a
        nm_manager_for_each_device (NM_MANAGER_GET, d, list) {
Packit Service 018b0a
            if (!nm_streq0(nm_device_get_iface(d), name))
Packit Service 018b0a
                continue;
Packit Service 018b0a
            s_ovs_int = nm_device_get_applied_setting(d, NM_TYPE_SETTING_OVS_INTERFACE);
Packit Service 018b0a
            if (!s_ovs_int)
Packit Service 018b0a
                continue;
Packit Service 018b0a
            if (!nm_streq0(nm_setting_ovs_interface_get_interface_type(s_ovs_int), "system"))
Packit Service 018b0a
                continue;
Packit Service 018b0a
            device = d;
Packit Service 018b0a
        }
Packit Service 018b0a
    } else {
Packit Service 018b0a
        device = nm_manager_get_device(NM_MANAGER_GET, name, device_type);
Packit Service 018b0a
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!device)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    device_state = nm_device_get_state(device);
Packit Service 018b0a
Packit Service 018b0a
    if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE && nm_device_get_act_request(device)
Packit Service a1bd4f
        && device_state < NM_DEVICE_STATE_DEACTIVATING) {
Packit Service a1bd4f
        nm_device_state_changed(device,
Packit Service a1bd4f
                                NM_DEVICE_STATE_DEACTIVATING,
Packit Service 018b0a
                                NM_DEVICE_STATE_REASON_REMOVED);
Packit Service 018b0a
        return;
Packit Service 018b0a
    }
Packit Service 018b0a
Packit Service 018b0a
    /* OVS system interfaces still exist even without the ovsdb entry */
Packit Service 018b0a
    if (!is_system_interface && device_state == NM_DEVICE_STATE_UNMANAGED) {
Packit Service a1bd4f
        nm_device_unrealize(device, TRUE, NULL);
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
ovsdb_interface_failed(NMOvsdb *        ovsdb,
Packit Service a1bd4f
                       const char *     name,
Packit Service a1bd4f
                       const char *     connection_uuid,
Packit Service a1bd4f
                       const char *     error,
Packit Service a1bd4f
                       NMDeviceFactory *self)
Packit 5756e2
{
Packit Service a1bd4f
    NMDevice *             device     = NULL;
Packit Service a1bd4f
    NMSettingsConnection * connection = NULL;
Packit Service a1bd4f
    NMConnection *         c;
Packit Service a1bd4f
    const char *           type;
Packit Service a1bd4f
    NMSettingOvsInterface *s_ovs_int;
Packit Service a1bd4f
    gboolean               is_patch = FALSE;
Packit Service a1bd4f
    gboolean               ignore;
Packit Service a1bd4f
Packit Service a1bd4f
    device = nm_manager_get_device(NM_MANAGER_GET, name, NM_DEVICE_TYPE_OVS_INTERFACE);
Packit Service a1bd4f
    if (device && connection_uuid) {
Packit Service a1bd4f
        connection =
Packit Service a1bd4f
            nm_settings_get_connection_by_uuid(nm_device_get_settings(device), connection_uuid);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    /* The patch interface which gets created first is expected to
Packit Service a1bd4f
     * fail because the second patch doesn't exist yet. Ignore all
Packit Service a1bd4f
     * failures of patch interfaces. */
Packit Service a1bd4f
    if (connection && (c = nm_settings_connection_get_connection(connection))
Packit Service a1bd4f
        && (type = nm_connection_get_connection_type(c))
Packit Service a1bd4f
        && nm_streq0(type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)
Packit Service a1bd4f
        && (s_ovs_int = nm_connection_get_setting_ovs_interface(c))
Packit Service a1bd4f
        && nm_streq0(nm_setting_ovs_interface_get_interface_type(s_ovs_int), "patch"))
Packit Service a1bd4f
        is_patch = TRUE;
Packit Service a1bd4f
Packit Service a1bd4f
    ignore = !device || is_patch;
Packit Service a1bd4f
Packit Service a1bd4f
    _NMLOG(ignore ? LOGL_DEBUG : LOGL_INFO,
Packit Service a1bd4f
           name,
Packit Service a1bd4f
           connection_uuid,
Packit Service a1bd4f
           "ovs interface \"%s\" (%s) failed%s: %s",
Packit Service a1bd4f
           name,
Packit Service a1bd4f
           connection_uuid,
Packit Service a1bd4f
           ignore ? " (ignored)" : "",
Packit Service a1bd4f
           error);
Packit Service a1bd4f
Packit Service a1bd4f
    if (ignore)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    if (connection) {
Packit Service a1bd4f
        nm_settings_connection_autoconnect_blocked_reason_set(
Packit Service a1bd4f
            connection,
Packit Service a1bd4f
            NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
Packit Service a1bd4f
            TRUE);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
start(NMDeviceFactory *self)
Packit 5756e2
{
Packit Service a1bd4f
    NMOvsdb *ovsdb;
Packit Service a1bd4f
Packit Service a1bd4f
    ovsdb = nm_ovsdb_get();
Packit Service a1bd4f
Packit Service a1bd4f
    g_signal_connect_object(ovsdb,
Packit Service a1bd4f
                            NM_OVSDB_DEVICE_ADDED,
Packit Service a1bd4f
                            G_CALLBACK(ovsdb_device_added),
Packit Service a1bd4f
                            self,
Packit Service a1bd4f
                            (GConnectFlags) 0);
Packit Service a1bd4f
    g_signal_connect_object(ovsdb,
Packit Service a1bd4f
                            NM_OVSDB_DEVICE_REMOVED,
Packit Service a1bd4f
                            G_CALLBACK(ovsdb_device_removed),
Packit Service a1bd4f
                            self,
Packit Service a1bd4f
                            (GConnectFlags) 0);
Packit Service a1bd4f
    g_signal_connect_object(ovsdb,
Packit Service a1bd4f
                            NM_OVSDB_INTERFACE_FAILED,
Packit Service a1bd4f
                            G_CALLBACK(ovsdb_interface_failed),
Packit Service a1bd4f
                            self,
Packit Service a1bd4f
                            (GConnectFlags) 0);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static NMDevice *
Packit Service a1bd4f
create_device(NMDeviceFactory *     self,
Packit Service a1bd4f
              const char *          iface,
Packit Service a1bd4f
              const NMPlatformLink *plink,
Packit Service a1bd4f
              NMConnection *        connection,
Packit Service a1bd4f
              gboolean *            out_ignore)
Packit 5756e2
{
Packit Service a1bd4f
    NMDeviceType device_type     = NM_DEVICE_TYPE_UNKNOWN;
Packit Service a1bd4f
    const char * connection_type = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (g_strcmp0(iface, "ovs-system") == 0) {
Packit Service a1bd4f
        *out_ignore = TRUE;
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (connection)
Packit Service a1bd4f
        connection_type = nm_connection_get_connection_type(connection);
Packit Service a1bd4f
Packit Service a1bd4f
    if (plink)
Packit Service a1bd4f
        device_type = NM_DEVICE_TYPE_OVS_INTERFACE;
Packit Service a1bd4f
    else if (g_strcmp0(connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0)
Packit Service a1bd4f
        device_type = NM_DEVICE_TYPE_OVS_INTERFACE;
Packit Service a1bd4f
    else if (g_strcmp0(connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0)
Packit Service a1bd4f
        device_type = NM_DEVICE_TYPE_OVS_PORT;
Packit Service a1bd4f
    else if (g_strcmp0(connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0)
Packit Service a1bd4f
        device_type = NM_DEVICE_TYPE_OVS_BRIDGE;
Packit Service a1bd4f
Packit Service a1bd4f
    return new_device_from_type(iface, device_type);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
nm_ovs_factory_init(NMOvsFactory *self)
Packit Service a1bd4f
{}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
nm_ovs_factory_class_init(NMOvsFactoryClass *klass)
Packit 5756e2
{
Packit Service a1bd4f
    NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass);
Packit 5756e2
Packit Service a1bd4f
    factory_class->get_supported_types = get_supported_types;
Packit Service a1bd4f
    factory_class->start               = start;
Packit Service a1bd4f
    factory_class->create_device       = create_device;
Packit 5756e2
}