From 39b4101d1916b20506b916d6d791effee68f43a9 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Wed, 1 Oct 2025 10:32:33 +0200 Subject: [PATCH 1/2] common: has-quirk: Add support for matching based on "ethtool -i" In addition to matching on interface names, add support for matching on ethtool information. Example: { "@ethtool:driver=st_gmac": { "broken-mqprio": true } } This would mark any interface using the "st_gmac" driver as having a broken mqprio implementation. Whereas this: { "@ethtool:driver=st_gmac;bus-info:30bf0000.ethernet": { "broken-mqprio": true } } Only matches an st_gmac-backed interface at the specified location. As matching becomes more complicated, use the shell implementation from confd as well, to make sure that they are always in agreement. --- .../common/rootfs/usr/libexec/infix/has-quirk | 49 ++++++++++++++++--- src/confd/src/ietf-interfaces.c | 14 +----- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/board/common/rootfs/usr/libexec/infix/has-quirk b/board/common/rootfs/usr/libexec/infix/has-quirk index 4f9a9bbc..7dc24d91 100755 --- a/board/common/rootfs/usr/libexec/infix/has-quirk +++ b/board/common/rootfs/usr/libexec/infix/has-quirk @@ -1,12 +1,49 @@ -#!/bin/sh +#!/bin/bash + +IFQUIRKSFILE=${IFQUIRKSFILE:-/etc/product/interface-quirks.json} + if [ $# -lt 2 ]; then echo "usage: $0 " exit 1 fi + quirk=$1 ifname=$2 -if [ -f "/etc/product/interface-quirks.json" ]; then - echo "$(jq -r --arg iface "$ifname" --arg quirk "$quirk" '.[$iface][$quirk] // "false"' /etc/product/interface-quirks.json)" -else - echo "false" -fi + +[ -f "$IFQUIRKSFILE" ] || { echo false && exit; } + +match() +{ + jq -e \ + --arg quirk "$quirk" --arg pattern "$1" \ + '.[$pattern][$quirk]' "$IFQUIRKSFILE" >/dev/null || return + + echo true + exit 0 +} + +ethtoolmatch() +{ + local pattern="${1#@ethtool:}" + + grep -qFxvf \ + <(ethtool -i "$ifname") \ + <(echo -n "$pattern" | awk -v FS="=" -v RS=";" '{ printf("%s: %s\n", $1, $2); }') \ + && return + + match "@ethtool:$pattern" +} + + +for pattern in $(jq -r 'keys[]' "$IFQUIRKSFILE"); do + case "$pattern" in + @ethtool:*) + ethtoolmatch "$pattern" + ;; + "$ifname") + match "$ifname" + ;; + esac +done + +echo "false" diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c index 28045ff0..db017cc3 100644 --- a/src/confd/src/ietf-interfaces.c +++ b/src/confd/src/ietf-interfaces.c @@ -17,18 +17,8 @@ bool iface_has_quirk(const char *ifname, const char *quirkname) { - struct json_t *iface, *quirk; - - if (!confd.ifquirks) - return false; - - iface = json_object_get(confd.ifquirks, ifname); - if (!iface) - return false; - - quirk = json_object_get(iface, quirkname); - - return quirk ? json_is_true(quirk) : false; + return systemf("[ $(/usr/libexec/infix/has-quirk %s %s) = true ]", + quirkname, ifname) == 0; } static bool iface_is_phys(const char *ifname) From 94f8d1a7008e324be5cd261a14cf6d87e98b36e7 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Wed, 1 Oct 2025 14:13:05 +0200 Subject: [PATCH 2/2] common: nameif: Handle nested dsa ports In setups like this... CPU eth0 | .----0----. | dst0sw0 | '-1-2-3-4-' | .----0----. | dst1sw0 | '-1-2-3-4-' ...both eth0 and dst0sw0p4 are DSA ports. But the latter is _also_ a physical port as far as devlink is concerned. As a result, it would first be marked as "internal" and is then instantly reclassified as a "port". Catch this condition and stick with the initial "internal" classification. --- board/common/rootfs/usr/libexec/infix/init.d/20-nameif | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/board/common/rootfs/usr/libexec/infix/init.d/20-nameif b/board/common/rootfs/usr/libexec/infix/init.d/20-nameif index 33039259..0356ce10 100755 --- a/board/common/rootfs/usr/libexec/infix/init.d/20-nameif +++ b/board/common/rootfs/usr/libexec/infix/init.d/20-nameif @@ -34,6 +34,12 @@ ports=$(devlink -j port | jq -r '.port[] | select(.flavour == "physical") | .netdev') for iface in $ports; do + # On systems with multiple switch trees, a port may be _both_ + # a physical port, registered with devlink, _and_ a DSA + # port. In those cases, hold on to our initial "internal" + # classification. + [ $(ip -j link show dev "$iface" | jq -r '.[0].group') = internal ] && continue + ip link set "$iface" group port done