On 6/26/26 11:38 AM, Matteo Perin via dev wrote:
> This commit adds the peer_ifindex to the interface status column for
> Linux veth devices, allowing applications like OVN to programmatically
> discover veth pairs without requiring additional system calls or manual
> configuration.
>
> The implementation leverages the existing ethtool infrastructure:
> - Uses ETHTOOL_GDRVINFO to identify veth devices and get n_stats
> - Queries ETH_SS_STATS string set to get statistic names
> - Dynamically allocates buffer based on n_stats
> - Uses ETHTOOL_GSTATS to retrieve veth statistics
> - Finds peer_ifindex by name in the statistics array
>
> The ifindex value is cached to avoid scalability issues with a
> considerable amount of ports.
> The cached peer_ifindex is then properly invalidated when the
> corresponding veth device is removed.
> This ensures that, when veth pairs are deleted and recreated with
> the same name, the new peer_ifindex is correctly detected and reported.
>
> A test that create veth pairs across network namespaces, verifies
> peer_ifindex reporting, and validates correct detection of ifindex
> changes when pairs are recreated was added as well.
>
> Signed-off-by: Matteo Perin <[email protected]>
> ---
> NEWS | 6 +++++
> lib/netdev-linux-private.h | 1 +
> lib/netdev-linux.c | 52 ++++++++++++++++++++++++++++++++++++++
> tests/system-interface.at | 48 +++++++++++++++++++++++++++++++++++
> vswitchd/vswitch.xml | 13 ++++++++++
> 5 files changed, 120 insertions(+)
>
> diff --git a/NEWS b/NEWS
> index a64fa065d..3c83a7327 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -19,6 +19,12 @@ Post-v3.7.0
> * AVX512-optimized action handling.
> * AVX512-optimized packet parsing (miniflow extraction).
> * AVX512-optimized DPIF input processing.
> + - Linux:
> + * For veth interfaces, the interface index of the peer veth device is
> + now reported as 'peer_ifindex' in the Interface status column. This
> + allows applications to programmatically discover veth pairs without
> + additional system calls. See the 'status' column in the 'Interface'
> + table in ovs-vswitchd.conf.db(5) for details.
This is a little too long. And there are actually no other details in the
man page. :) I'll trim that on commit.
> - Windows:
> * The previously deprecated Windows kernel datapath implementation is
> now fully removed as well as support for running or building userspace
> diff --git a/lib/netdev-linux-private.h b/lib/netdev-linux-private.h
> index cf4a021d3..3f3fc04b5 100644
> --- a/lib/netdev-linux-private.h
> +++ b/lib/netdev-linux-private.h
> @@ -97,6 +97,7 @@ struct netdev_linux {
> uint8_t current_duplex; /* Cached from ETHTOOL_GSET. */
>
> struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */
> + uint64_t peer_ifindex; /* Cached from ETHTOOL_GSTATS (veth). */
> struct tc *tc;
>
> /* For devices of class netdev_tap_class only. */
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index fa2ecfa6b..7503fd0fe 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -3814,6 +3814,51 @@ netdev_linux_get_next_hop(const struct in_addr *host,
> struct in_addr *next_hop,
> return ENXIO;
> }
>
> +/* For veth devices, query peer_ifindex via ethtool statistics. */
> +static void
> +netdev_linux_get_peer_ifindex(struct netdev_linux *netdev)
> +{
> + struct ethtool_gstrings *names = NULL;
> + struct ethtool_stats *stats = NULL;
> + size_t n_stats = netdev->drvinfo.n_stats;
> + struct ethtool_cmd *cmd;
> + int error;
> +
> + if (strcmp(netdev->drvinfo.driver, "veth") || !n_stats) {
> + return;
> + }
> +
> + error = netdev_linux_read_definitions(netdev, ETH_SS_STATS, &names);
> + if (error) {
> + return;
> + }
> +
> + stats = xzalloc(sizeof *stats + n_stats * sizeof stats->data[0]);
> + stats->cmd = ETHTOOL_GSTATS;
> + stats->n_stats = n_stats;
> +
> + cmd = (struct ethtool_cmd *) stats;
> + error = netdev_linux_do_ethtool(netdev->up.name, cmd,
> + ETHTOOL_GSTATS, "ETHTOOL_GSTATS");
> + if (error) {
> + free(stats);
> + free(names);
> + return;
> + }
> +
> + for (uint32_t i = 0; i < names->len && i < stats->n_stats; i++) {
> + char *name = (char *) &names->data[i * ETH_GSTRING_LEN];
> +
> + if (!strcmp(name, "peer_ifindex")) {
> + netdev->peer_ifindex = stats->data[i];
> + break;
> + }
> + }
> +
> + free(stats);
> + free(names);
> +}
> +
> int
> netdev_linux_get_status(const struct netdev *netdev_, struct smap *smap)
> {
> @@ -3826,11 +3871,13 @@ netdev_linux_get_status(const struct netdev *netdev_,
> struct smap *smap)
>
> COVERAGE_INC(netdev_get_ethtool);
> memset(&netdev->drvinfo, 0, sizeof netdev->drvinfo);
> + netdev->peer_ifindex = 0;
> error = netdev_linux_do_ethtool(netdev->up.name,
> cmd,
> ETHTOOL_GDRVINFO,
> "ETHTOOL_GDRVINFO");
> if (!error) {
> + netdev_linux_get_peer_ifindex(netdev);
> netdev->cache_valid |= VALID_DRVINFO;
> }
> }
> @@ -3839,6 +3886,11 @@ netdev_linux_get_status(const struct netdev *netdev_,
> struct smap *smap)
> smap_add(smap, "driver_name", netdev->drvinfo.driver);
> smap_add(smap, "driver_version", netdev->drvinfo.version);
> smap_add(smap, "firmware_version", netdev->drvinfo.fw_version);
> +
> + if (netdev->peer_ifindex) {
> + smap_add_format(smap, "peer_ifindex",
> + "%"PRIu64, netdev->peer_ifindex);
> + }
> }
> ovs_mutex_unlock(&netdev->mutex);
>
> diff --git a/tests/system-interface.at b/tests/system-interface.at
> index 640bfd638..1bfb07095 100644
> --- a/tests/system-interface.at
> +++ b/tests/system-interface.at
> @@ -255,3 +255,51 @@ AT_CHECK([ovs-vswitchd --detach --no-chdir --pidfile
> --log-file -vvconn -vofprot
>
> OVS_TRAFFIC_VSWITCHD_STOP
> AT_CLEANUP
> +
> +dnl Test that peer_ifindex is correctly reported for veth devices.
> +AT_SETUP([interface - veth peer_ifindex status])
> +AT_SKIP_IF([test $HAVE_ETHTOOL = "no"])
> +
> +OVS_TRAFFIC_VSWITCHD_START()
> +
> +ADD_NAMESPACES(testns)
> +
> +dnl Create a veth pair: ovs-veth0 (main ns) <-> ovs-veth1 (testns).
> +AT_CHECK([ip link add ovs-veth0 type veth peer name ovs-veth1])
> +on_exit 'ip link del ovs-veth0'
> +AT_CHECK([ip link set ovs-veth1 netns testns])
> +
> +AT_CHECK([ovs-vsctl add-port br0 ovs-veth0])
> +
> +dnl Get the actual ifindex of ovs-veth1 in testns.
> +AT_CHECK([ip netns exec testns ip link show ovs-veth1], [0], [stdout])
> +peer1_ifindex=$(sed -n 's/^\([[0-9]]*\):.*/\1/p' stdout)
> +
> +dnl Verify OVS reports the correct peer_ifindex.
> +OVS_WAIT_UNTIL_EQUAL([ovs-vsctl get interface ovs-veth0 status:peer_ifindex],
> + ["\"$peer1_ifindex\""])
> +
> +dnl Recreate veth pair with the same name to test stale ifindex detection.
> +AT_CHECK([ip link del ovs-veth0])
> +AT_CHECK([ip link add ovs-veth0 type veth peer name ovs-veth1])
> +AT_CHECK([ip link set ovs-veth1 netns testns])
> +
> +dnl Get the new peer's ifindex.
> +AT_CHECK([ip netns exec testns ip link show ovs-veth1], [0], [stdout])
> +peer2_ifindex=$(sed -n 's/^\([[0-9]]*\):.*/\1/p' stdout)
> +
> +dnl Verify OVS detects the change and reports the new peer_ifindex.
> +OVS_WAIT_UNTIL_EQUAL([ovs-vsctl get interface ovs-veth0 status:peer_ifindex],
> + ["\"$peer2_ifindex\""])
> +
> +dnl Verify the two peer ifindexes are different.
> +AT_CHECK([test "$peer1_ifindex" != "$peer2_ifindex"])
> +
> +OVS_TRAFFIC_VSWITCHD_STOP(["dnl
> +/could not open network device ovs-veth0/d
> +/cannot get .*STP status on nonexistent port/d
> +/ethtool command .*on network device ovs-veth0 failed/d
> +/error receiving .*ovs-veth0/d
> +/ovs-veth0: removing policing failed/d"])
> +
> +AT_CLEANUP
> \ No newline at end of file
The new line is missing.
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 5f80e7f43..4eec70fe4 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -3762,6 +3762,19 @@ ovs-vsctl add-port br0 p0 -- set Interface p0
> type=patch options:peer=p1 \
> The version string of the network adapter's firmware, if available.
> </column>
>
> + <column name="status" key="peer_ifindex">
> + <p>
> + For veth devices on Linux, this column contains the interface index
> + of the peer veth device. This allows applications to
> + programmatically discover veth pairs without requiring additional
> + system calls or parsing network interface information.
> + </p>
> + <p>
> + Only present for veth devices (when <ref column="status"
> + key="driver_name"/> is "veth"). Not available on non-Linux
> systems.
> + </p>
> + </column>
> +
> <column name="status" key="source_ip">
> The source IP address used for an IPv4/IPv6 tunnel end-point, such as
> <code>gre</code>.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev