summary refs log tree commit diff
path: root/src/core/devices/ovs/nm-device-ovs-port.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/devices/ovs/nm-device-ovs-port.c')
-rw-r--r--src/core/devices/ovs/nm-device-ovs-port.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c
new file mode 100644
index 00000000..2ecb95e8
--- /dev/null
+++ b/src/core/devices/ovs/nm-device-ovs-port.c
@@ -0,0 +1,196 @@
+/* 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-port.h"
+
+#include "nm-device-ovs-interface.h"
+#include "nm-device-ovs-bridge.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"
+
+#define _NMLOG_DEVICE_TYPE NMDeviceOvsPort
+#include "devices/nm-device-logging.h"
+
+/*****************************************************************************/
+
+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;
+    device_class->can_reapply_change_ovs_external_ids = TRUE;
+    device_class->reapply_connection                  = nm_device_ovs_reapply_connection;
+}