ovs, dpdk: fix creating ovs-interface when the ovs-bridge is netdev

When the ovs-bridge datapath is netdev, OpenvSwitch will not create a
ovs-interface but a tun interface. The ovs-interface device must check
all the link-change signals and check if the link type is tun and the
interface name is the same than the device name. If so, the
ovs-interface device will get the ifindex of the tun device. This allow
NetworkManager to manage the interface properly, modifying MTU,
configuring IPv4/IPv6 and others.

Example:

```
55: ovsbridge-port0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 9000 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether fa:fb:07:98:e0:c6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.123.100/24 brd 192.168.123.255 scope global noprefixroute ovsbridge-port0
       valid_lft forever preferred_lft forever
    inet6 fe80::9805:55c4:4c5f:da1c/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
```

https://bugzilla.redhat.com/show_bug.cgi?id=2001792
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1179
This commit is contained in:
Fernando Fernandez Mancera 2022-04-04 14:10:00 +02:00
parent f3be419719
commit 99a6c6eda6

View file

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