diff options
Diffstat (limited to 'src/core/devices/ovs')
| -rw-r--r-- | src/core/devices/ovs/nm-device-ovs-interface.c | 95 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-ovsdb.c | 53 |
2 files changed, 114 insertions, 34 deletions
diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 74707d24..6b9d3d7e 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -13,6 +13,7 @@ #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-interface.h" #include "nm-setting-ovs-port.h" @@ -23,7 +24,10 @@ typedef struct { NMOvsdb *ovsdb; - bool waiting_for_interface : 1; + GSource *wait_link_idle_source; + gulong wait_link_signal_id; + int wait_link_ifindex; + bool wait_link_is_waiting : 1; } NMDeviceOvsInterfacePrivate; struct _NMDeviceOvsInterface { @@ -115,10 +119,10 @@ link_changed(NMDevice *device, const NMPlatformLink *pllink) { NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); - if (!pllink || !priv->waiting_for_interface) + if (!pllink || !priv->wait_link_is_waiting) return; - priv->waiting_for_interface = FALSE; + priv->wait_link_is_waiting = FALSE; if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { if (!nm_device_hw_addr_set_cloned(device, @@ -199,17 +203,83 @@ ready_for_ip_config(NMDevice *device) return nm_device_get_ip_ifindex(device) > 0; } +static gboolean +_set_ip_ifindex_tun(gpointer user_data) +{ + NMDevice *device = user_data; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->wait_link_idle_source); + + priv->wait_link_is_waiting = FALSE; + nm_device_set_ip_ifindex(device, priv->wait_link_ifindex); + + nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_activate_schedule_stage3_ip_config(device, FALSE); + + return G_SOURCE_CONTINUE; +} + +static void +_netdev_tun_link_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + NMPlatformLink *pllink, + int change_type_i, + NMDevice *device) +{ + const NMPlatformSignalChangeType change_type = change_type_i; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + + if (change_type == NM_PLATFORM_SIGNAL_ADDED) { + if (pllink->type == NM_LINK_TYPE_TUN + && nm_streq0(pllink->name, nm_device_get_iface(device))) { + nm_clear_g_signal_handler(platform, &priv->wait_link_signal_id); + + priv->wait_link_ifindex = ifindex; + + priv->wait_link_idle_source = nm_g_idle_add_source(_set_ip_ifindex_tun, device); + } + } +} + static void act_stage3_ip_config(NMDevice *device, int addr_family) { - NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + NMActiveConnection *controller_act = NULL; + NMSettingOvsBridge *s_ovs_bridge = NULL; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); if (!_is_internal_interface(device)) { nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); return; } + /* When the ovs-bridge controller is using netdev datapath, the interface + * link created is a tun device instead of a ovs-interface. NetworkManager must + * detect the creation of the tun link and attach the ifindex to the + * ovs-interface device. */ + controller_act = NM_ACTIVE_CONNECTION(nm_device_get_act_request(device)); + if (controller_act && nm_device_get_ip_ifindex(device) <= 0 && priv->wait_link_signal_id == 0) { + controller_act = nm_active_connection_get_master(controller_act); + if (controller_act) { + controller_act = nm_active_connection_get_master(controller_act); + if (controller_act) + s_ovs_bridge = nm_connection_get_setting_ovs_bridge( + nm_active_connection_get_applied_connection(controller_act)); + if (s_ovs_bridge + && nm_streq0(nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge), "netdev")) + priv->wait_link_signal_id = g_signal_connect(nm_device_get_platform(device), + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK(_netdev_tun_link_cb), + self); + } + } + /* FIXME(l3cfg): we should create the IP ifindex before stage3 start. * * For now it's here because when the ovs-interface enters stage3, then it's added to the @@ -219,11 +289,15 @@ act_stage3_ip_config(NMDevice *device, int addr_family) * This should change. */ if (nm_device_get_ip_ifindex(device) <= 0) { _LOGT(LOGD_DEVICE, "waiting for link to appear"); - priv->waiting_for_interface = TRUE; + priv->wait_link_is_waiting = TRUE; nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_PENDING, NULL); return; } + priv->wait_link_is_waiting = FALSE; + nm_clear_g_source_inst(&priv->wait_link_idle_source); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link_signal_id); + if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) { nm_device_devip_set_failed(device, addr_family, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; @@ -244,7 +318,8 @@ deactivate(NMDevice *device) NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - priv->waiting_for_interface = FALSE; + priv->wait_link_is_waiting = FALSE; + nm_clear_g_source_inst(&priv->wait_link_idle_source); } typedef struct { @@ -351,7 +426,7 @@ deactivate_async(NMDevice *device, .callback_user_data = callback_user_data, }; - if (!priv->waiting_for_interface + if (!priv->wait_link_is_waiting && !nm_platform_link_get_by_ifname(nm_device_get_platform(device), nm_device_get_iface(device))) { _LOGT(LOGD_CORE, "deactivate: link not present, proceeding"); @@ -360,7 +435,9 @@ deactivate_async(NMDevice *device, return; } - if (priv->waiting_for_interface) { + nm_clear_g_source_inst(&priv->wait_link_idle_source); + + if (priv->wait_link_is_waiting) { /* 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 diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 7c45e0e4..44e16cb7 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -104,6 +104,7 @@ typedef struct { OvsdbMethodCallback callback; gpointer user_data; OvsdbMethodPayload payload; + GObject *shutdown_wait_obj; } OvsdbMethodCall; /*****************************************************************************/ @@ -245,6 +246,8 @@ static NM_UTILS_LOOKUP_STR_DEFINE(_device_type_to_table, static void _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) { + g_clear_object(&call->shutdown_wait_obj); + if (response) { gs_free char *str = NULL; @@ -378,12 +381,14 @@ ovsdb_call_method(NMOvsdb *self, call = g_slice_new(OvsdbMethodCall); *call = (OvsdbMethodCall){ - .self = self, - .call_id = CALL_ID_UNSPEC, - .command = command, - .callback = callback, - .user_data = user_data, + .self = self, + .call_id = CALL_ID_UNSPEC, + .command = command, + .callback = callback, + .user_data = user_data, + .shutdown_wait_obj = g_object_new(G_TYPE_OBJECT, NULL), }; + nm_shutdown_wait_obj_register_object(call->shutdown_wait_obj, "ovsdb-call"); if (add_first) c_list_link_front(&priv->calls_lst_head, &call->calls_lst); @@ -2481,29 +2486,27 @@ typedef struct { 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; + OvsdbCall *call = user_data; + gs_free_error GError *local = NULL; + const char *err; + const char *err_details; + size_t index; + json_t *value; + + if (!error) { + json_array_foreach (result, index, value) { + if (json_unpack(value, "{s:s, s:s}", "error", &err, "details", &err_details) == 0) { + local = g_error_new(G_IO_ERROR, + G_IO_ERROR_FAILED, + "Error running the transaction: %s: %s", + err, + err_details); + break; + } } } -out: - call->callback(error, call->user_data); + call->callback(local ?: error, call->user_data); nm_g_slice_free(call); } |