|
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 |
}
|