2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-04 00:05:15 +00:00

dpif-netlink: Fix feature negotiation for older kernels.

Older kernels do not reject unsupported features. This can lead
to a situation in which 'ovs-vswitchd' believes that a feature is
supported when, in fact, it is not.

This patch probes for this by attempting to set a known unsupported
feature.

Reported-by: Dumitru Ceara <dceara@redhat.com>
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
Suggested-by: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
Tested-by: Dumitru Ceara <dceara@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Mark Gray
2021-09-15 11:08:03 -04:00
committed by Ilya Maximets
parent b12242e0ea
commit b841e3cd4a

View File

@@ -84,6 +84,8 @@ enum { MAX_PORTS = USHRT_MAX };
#define EPOLLEXCLUSIVE (1u << 28)
#endif
#define OVS_DP_F_UNSUPPORTED (1 << 31);
/* This PID is not used by the kernel datapath when using dispatch per CPU,
* but it is required to be set (not zero). */
#define DPIF_NETLINK_PER_CPU_PID UINT32_MAX
@@ -382,36 +384,62 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
dp_request.cmd = OVS_DP_CMD_SET;
}
/* The Open vSwitch kernel module has two modes for dispatching upcalls:
* per-vport and per-cpu.
*
* When dispatching upcalls per-vport, the kernel will
* send the upcall via a Netlink socket that has been selected based on the
* vport that received the packet that is causing the upcall.
*
* When dispatching upcall per-cpu, the kernel will send the upcall via
* a Netlink socket that has been selected based on the cpu that received
* the packet that is causing the upcall.
*
* First we test to see if the kernel module supports per-cpu dispatching
* (the preferred method). If it does not support per-cpu dispatching, we
* fall back to the per-vport dispatch mode.
/* Some older kernels will not reject unknown features. This will cause
* 'ovs-vswitchd' to incorrectly assume a feature is supported. In order to
* test for that, we attempt to set a feature that we know is not supported
* by any kernel. If this feature is not rejected, we can assume we are
* running on one of these older kernels.
*/
dp_request.user_features |= OVS_DP_F_UNALIGNED;
dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
dp_request.user_features |= OVS_DP_F_UNSUPPORTED;
error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
if (error) {
dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
/* The Open vSwitch kernel module has two modes for dispatching
* upcalls: per-vport and per-cpu.
*
* When dispatching upcalls per-vport, the kernel will
* send the upcall via a Netlink socket that has been selected based on
* the vport that received the packet that is causing the upcall.
*
* When dispatching upcall per-cpu, the kernel will send the upcall via
* a Netlink socket that has been selected based on the cpu that
* received the packet that is causing the upcall.
*
* First we test to see if the kernel module supports per-cpu
* dispatching (the preferred method). If it does not support per-cpu
* dispatching, we fall back to the per-vport dispatch mode.
*/
dp_request.user_features &= ~OVS_DP_F_UNSUPPORTED;
dp_request.user_features |= OVS_DP_F_UNALIGNED;
dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
if (error) {
dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
}
if (error) {
return error;
}
error = open_dpif(&dp, dpifp);
dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
} else {
VLOG_INFO("Kernel does not correctly support feature negotiation. "
"Using standard features.");
dp_request.cmd = OVS_DP_CMD_SET;
dp_request.user_features = 0;
dp_request.user_features |= OVS_DP_F_UNALIGNED;
dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
}
if (error) {
return error;
if (error) {
return error;
}
error = open_dpif(&dp, dpifp);
}
error = open_dpif(&dp, dpifp);
dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
ofpbuf_delete(buf);
if (create) {