diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 74707d2482..6b9d3d7ed4 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