Bug#1106602: unblock: iproute2/6.15.0-1
Control: tags -1 moreinfo
On 2025-05-27 00:53:10 +0100, Luca Boccassi wrote:
> Package: release.debian.org
> Severity: normal
> Control: affects -1 + src:iproute2
> User: release.debian.org@packages.debian.org
> Usertags: unblock
>
> Dear RT,
>
> Please unblock iproute2/6.15.0-1
Issues preventing migration:
∙ ∙ autopkgtest for iproute2/6.15.0-1: amd64: Pass, arm64: No tests, superficial or marked flaky ♻ (reference ♻), armel: No tests, superficial or marked flaky ♻ (reference ♻), armhf: No tests, superficial or marked flaky ♻ (reference ♻), i386: No tests, superficial or marked flaky ♻ (reference ♻), ppc64el: No tests, superficial or marked flaky ♻ (reference ♻), riscv64: No tests, superficial or marked flaky ♻ (reference ♻), s390x: No tests, superficial or marked flaky ♻ (reference ♻)
∙ ∙ autopkgtest for systemd/257.5-2: amd64: Regression or new test ♻ (reference ♻), arm64: Pass, armel: Pass, armhf: Pass, i386: Pass, ppc64el: Pass, riscv64: Pass, s390x: Pass
Could you check what's wrong with systemd?
Cheers
>
> The new bug fix release only contains small bug fixes and changes, and
> allows to drop all previously backported patches. Crucially, it fixes a
> regression introduced in 6.14 that broke a major and popular feature,
> #1106321.
>
> Full debdiff attached.
>
> Thanks.
> diff -Nru iproute2-6.14.0/bridge/bridge.c iproute2-6.15.0/bridge/bridge.c
> --- iproute2-6.14.0/bridge/bridge.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/bridge/bridge.c 2025-05-26 16:19:09.000000000 +0100
> @@ -103,7 +103,7 @@
> int
> main(int argc, char **argv)
> {
> - int color = CONF_COLOR;
> + int color = default_color_opt();
>
> while (argc > 1) {
> const char *opt = argv[1];
> diff -Nru iproute2-6.14.0/debian/changelog iproute2-6.15.0/debian/changelog
> --- iproute2-6.14.0/debian/changelog 2025-04-12 12:15:56.000000000 +0100
> +++ iproute2-6.15.0/debian/changelog 2025-05-27 00:16:26.000000000 +0100
> @@ -1,3 +1,12 @@
> +iproute2 (6.15.0-1) unstable; urgency=medium
> +
> + * Update upstream source from tag 'upstream/6.15.0'
> + (Closes: #1106321)
> + * Drop all backported patches, merged upstream
> + * d/copyright: use GPL URL instead of old FSF postal address
> +
> + -- Luca Boccassi <bluca@debian.org> Tue, 27 May 2025 00:16:26 +0100
> +
> iproute2 (6.14.0-3) unstable; urgency=medium
>
> * autopkgtest: remove build-essential and dpkg-dev deps, add gcc
> diff -Nru iproute2-6.14.0/debian/copyright iproute2-6.15.0/debian/copyright
> --- iproute2-6.14.0/debian/copyright 2024-11-24 11:21:07.000000000 +0000
> +++ iproute2-6.15.0/debian/copyright 2025-05-27 00:16:26.000000000 +0100
> @@ -52,8 +52,7 @@
> GNU General Public License for more details.
> .
> You should have received a copy of the GNU General Public License
> - along with this package; if not, write to the Free Software
> - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + along with this package; if not, see <https://www.gnu.org/licenses/>
> .
> On Debian systems, the complete text of the GNU General Public License version
> 2 can be found in `/usr/share/common-licenses/GPL-2'.
> diff -Nru iproute2-6.14.0/debian/patches/0002-color-Introduce-and-use-default_color_opt-function.patch iproute2-6.15.0/debian/patches/0002-color-Introduce-and-use-default_color_opt-function.patch
> --- iproute2-6.14.0/debian/patches/0002-color-Introduce-and-use-default_color_opt-function.patch 2025-04-12 12:14:49.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/0002-color-Introduce-and-use-default_color_opt-function.patch 1970-01-01 01:00:00.000000000 +0100
> @@ -1,61 +0,0 @@
> -Author: Ben Hutchings <benh@debian.org>
> -Description: color: Introduce and use default_color_opt() function
> -Origin: commit:446edf9ef8055125a8ef28a9d9218b05971ee465
> -Forwarded: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=446edf9ef8055125a8ef28a9d9218b05971ee465
> ---- a/bridge/bridge.c
> -+++ b/bridge/bridge.c
> -@@ -103,7 +103,7 @@
> - int
> - main(int argc, char **argv)
> - {
> -- int color = CONF_COLOR;
> -+ int color = default_color_opt();
> -
> - while (argc > 1) {
> - const char *opt = argv[1];
> ---- a/include/color.h
> -+++ b/include/color.h
> -@@ -20,6 +20,7 @@
> - COLOR_OPT_ALWAYS = 2
> - };
> -
> -+int default_color_opt(void);
> - bool check_enable_color(int color, int json);
> - bool matches_color(const char *arg, int *val);
> - int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
> ---- a/ip/ip.c
> -+++ b/ip/ip.c
> -@@ -180,7 +180,7 @@
> - const char *libbpf_version;
> - char *batch_file = NULL;
> - char *basename;
> -- int color = CONF_COLOR;
> -+ int color = default_color_opt();
> -
> - /* to run vrf exec without root, capabilities might be set, drop them
> - * if not needed as the first thing.
> ---- a/lib/color.c
> -+++ b/lib/color.c
> -@@ -81,6 +81,11 @@
> - set_color_palette();
> - }
> -
> -+int default_color_opt(void)
> -+{
> -+ return CONF_COLOR;
> -+}
> -+
> - bool check_enable_color(int color, int json)
> - {
> - if (json || color == COLOR_OPT_NEVER)
> ---- a/tc/tc.c
> -+++ b/tc/tc.c
> -@@ -254,7 +254,7 @@
> - {
> - const char *libbpf_version;
> - char *batch_file = NULL;
> -- int color = CONF_COLOR;
> -+ int color = default_color_opt();
> - int ret;
> -
> - while (argc > 1) {
> diff -Nru iproute2-6.14.0/debian/patches/0003-color-Handle-NO_COLOR-environment-variable-in-defaul.patch iproute2-6.15.0/debian/patches/0003-color-Handle-NO_COLOR-environment-variable-in-defaul.patch
> --- iproute2-6.14.0/debian/patches/0003-color-Handle-NO_COLOR-environment-variable-in-defaul.patch 2025-04-12 12:14:49.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/0003-color-Handle-NO_COLOR-environment-variable-in-defaul.patch 1970-01-01 01:00:00.000000000 +0100
> @@ -1,20 +0,0 @@
> -Author: Ben Hutchings <benh@debian.org>
> -Description: color: Handle NO_COLOR environment variable in default_color_opt()
> -Origin: commit:f0076a016cf7926f39c47b95dae0002249c082dc
> -Forwarded: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=f0076a016cf7926f39c47b95dae0002249c082dc
> ---- a/lib/color.c
> -+++ b/lib/color.c
> -@@ -83,6 +83,13 @@
> -
> - int default_color_opt(void)
> - {
> -+ const char *no_color;
> -+
> -+ /* If NO_COLOR has a non-empty value, coloured output is never wanted */
> -+ no_color = getenv("NO_COLOR");
> -+ if (no_color && *no_color)
> -+ return COLOR_OPT_NEVER;
> -+
> - return CONF_COLOR;
> - }
> -
> diff -Nru iproute2-6.14.0/debian/patches/0004-color-Assume-background-is-dark-if-unknown.patch iproute2-6.15.0/debian/patches/0004-color-Assume-background-is-dark-if-unknown.patch
> --- iproute2-6.14.0/debian/patches/0004-color-Assume-background-is-dark-if-unknown.patch 2025-04-12 12:14:49.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/0004-color-Assume-background-is-dark-if-unknown.patch 1970-01-01 01:00:00.000000000 +0100
> @@ -1,36 +0,0 @@
> -Author: Ben Hutchings <benh@debian.org>
> -Description: color: Assume background is dark if unknown
> -Origin: commit:cc0f1109d2864686180ba2ce6fba5fcb3bf437bf
> -Forwarded: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=cc0f1109d2864686180ba2ce6fba5fcb3bf437bf
> ---- a/lib/color.c
> -+++ b/lib/color.c
> -@@ -72,7 +72,11 @@
> - C_CLEAR
> - };
> -
> --static int is_dark_bg;
> -+/*
> -+ * Assume dark background until we know otherwise. The dark-background
> -+ * colours work better on a light background than vice versa.
> -+ */
> -+static int is_dark_bg = 1;
> - static int color_is_enabled;
> -
> - static void enable_color(void)
> -@@ -138,12 +142,12 @@
> - /*
> - * COLORFGBG environment variable usually contains either two or three
> - * values separated by semicolons; we want the last value in either case.
> -- * If this value is 0-6 or 8, background is dark.
> -+ * If this value is 0-6 or 8, background is dark; otherwise it's light.
> - */
> - if (p && (p = strrchr(p, ';')) != NULL
> -- && ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
> -- && p[2] == '\0')
> -- is_dark_bg = 1;
> -+ && !(((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
> -+ && p[2] == '\0'))
> -+ is_dark_bg = 0;
> - }
> -
> - __attribute__((format(printf, 3, 4)))
> diff -Nru iproute2-6.14.0/debian/patches/0005-color-Do-not-use-dark-blue-in-dark-background-palett.patch iproute2-6.15.0/debian/patches/0005-color-Do-not-use-dark-blue-in-dark-background-palett.patch
> --- iproute2-6.14.0/debian/patches/0005-color-Do-not-use-dark-blue-in-dark-background-palett.patch 2025-04-12 12:14:49.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/0005-color-Do-not-use-dark-blue-in-dark-background-palett.patch 1970-01-01 01:00:00.000000000 +0100
> @@ -1,33 +0,0 @@
> -Author: Ben Hutchings <benh@debian.org>
> -Description: color: Do not use dark blue in dark-background palette
> -Origin: commit:46a4659313c2610427a088d8f03b731819f2b87a
> -Forwarded: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=46a4659313c2610427a088d8f03b731819f2b87a
> ---- a/lib/color.c
> -+++ b/lib/color.c
> -@@ -24,7 +24,7 @@
> - C_BOLD_RED,
> - C_BOLD_GREEN,
> - C_BOLD_YELLOW,
> -- C_BOLD_BLUE,
> -+ C_BOLD_LIGHT_BLUE,
> - C_BOLD_MAGENTA,
> - C_BOLD_CYAN,
> - C_BOLD_WHITE,
> -@@ -42,7 +42,7 @@
> - "\e[1;31m",
> - "\e[1;32m",
> - "\e[1;33m",
> -- "\e[1;34m",
> -+ "\e[1;94m",
> - "\e[1;35m",
> - "\e[1;36m",
> - "\e[1;37m",
> -@@ -66,7 +66,7 @@
> - C_BOLD_CYAN,
> - C_BOLD_YELLOW,
> - C_BOLD_MAGENTA,
> -- C_BOLD_BLUE,
> -+ C_BOLD_LIGHT_BLUE,
> - C_BOLD_GREEN,
> - C_BOLD_RED,
> - C_CLEAR
> diff -Nru iproute2-6.14.0/debian/patches/0006-nstat-NULL-Dereference-when-no-entries-specified.patch iproute2-6.15.0/debian/patches/0006-nstat-NULL-Dereference-when-no-entries-specified.patch
> --- iproute2-6.14.0/debian/patches/0006-nstat-NULL-Dereference-when-no-entries-specified.patch 2025-04-12 12:15:36.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/0006-nstat-NULL-Dereference-when-no-entries-specified.patch 1970-01-01 01:00:00.000000000 +0100
> @@ -1,17 +0,0 @@
> -Author: ZiAo Li <23110240084@m.fudan.edu.cn>
> -Description: nstat: NULL Dereference when no entries specified
> -Origin: commit:866e1d107b7de68ca1fcd1d4d5ffecf9d96bff30
> -Forwarded: https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=866e1d107b7de68ca1fcd1d4d5ffecf9d96bff30
> ---- a/misc/nstat.c
> -+++ b/misc/nstat.c
> -@@ -218,6 +218,10 @@
> - p = next;
> - }
> - n = db;
> -+ if (n == NULL) {
> -+ fprintf(stderr, "Error: Invalid input – line has ':' but no entries. Add values after ':'.\n");
> -+ exit(-2);
> -+ }
> - nread = getline(&buf, &buflen, fp);
> - if (nread == -1) {
> - fprintf(stderr, "%s:%d: error parsing history file\n",
> diff -Nru iproute2-6.14.0/debian/patches/series iproute2-6.15.0/debian/patches/series
> --- iproute2-6.14.0/debian/patches/series 2025-04-12 12:13:53.000000000 +0100
> +++ iproute2-6.15.0/debian/patches/series 2025-05-27 00:16:02.000000000 +0100
> @@ -1,6 +1 @@
> 0001-Add-moo-feature.patch
> -0002-color-Introduce-and-use-default_color_opt-function.patch
> -0003-color-Handle-NO_COLOR-environment-variable-in-defaul.patch
> -0004-color-Assume-background-is-dark-if-unknown.patch
> -0005-color-Do-not-use-dark-blue-in-dark-background-palett.patch
> -0006-nstat-NULL-Dereference-when-no-entries-specified.patch
> diff -Nru iproute2-6.14.0/etc/iproute2/rt_protos iproute2-6.15.0/etc/iproute2/rt_protos
> --- iproute2-6.14.0/etc/iproute2/rt_protos 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/etc/iproute2/rt_protos 2025-05-26 16:19:09.000000000 +0100
> @@ -17,6 +17,7 @@
> 16 dhcp
> 18 keepalived
> 42 babel
> +84 ovn
> 99 openr
> 186 bgp
> 187 isis
> diff -Nru iproute2-6.14.0/include/color.h iproute2-6.15.0/include/color.h
> --- iproute2-6.14.0/include/color.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/color.h 2025-05-26 16:19:09.000000000 +0100
> @@ -20,6 +20,7 @@
> COLOR_OPT_ALWAYS = 2
> };
>
> +int default_color_opt(void);
> bool check_enable_color(int color, int json);
> bool matches_color(const char *arg, int *val);
> int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
> diff -Nru iproute2-6.14.0/include/uapi/linux/batman_adv.h iproute2-6.15.0/include/uapi/linux/batman_adv.h
> --- iproute2-6.14.0/include/uapi/linux/batman_adv.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/batman_adv.h 2025-05-26 16:19:09.000000000 +0100
> @@ -342,7 +342,7 @@
> BATADV_ATTR_MCAST_FLAGS_PRIV,
>
> /**
> - * @BATADV_ATTR_VLANID: VLAN id on top of soft interface
> + * @BATADV_ATTR_VLANID: VLAN id on top of mesh interface
> */
> BATADV_ATTR_VLANID,
>
> @@ -380,7 +380,7 @@
> /**
> * @BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED: whether the bridge loop
> * avoidance feature is enabled. This feature detects and avoids loops
> - * between the mesh and devices bridged with the soft interface
> + * between the mesh and devices bridged with the mesh interface
> */
> BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED,
>
> @@ -509,7 +509,7 @@
> BATADV_CMD_UNSPEC,
>
> /**
> - * @BATADV_CMD_GET_MESH: Get attributes from softif/mesh
> + * @BATADV_CMD_GET_MESH: Get attributes from mesh(if)
> */
> BATADV_CMD_GET_MESH,
>
> @@ -535,7 +535,7 @@
>
> /**
> * @BATADV_CMD_GET_HARDIF: Get attributes from a hardif of the
> - * current softif
> + * current mesh(if)
> */
> BATADV_CMD_GET_HARDIF,
>
> @@ -591,25 +591,25 @@
> BATADV_CMD_GET_MCAST_FLAGS,
>
> /**
> - * @BATADV_CMD_SET_MESH: Set attributes for softif/mesh
> + * @BATADV_CMD_SET_MESH: Set attributes for mesh(if)
> */
> BATADV_CMD_SET_MESH,
>
> /**
> * @BATADV_CMD_SET_HARDIF: Set attributes for hardif of the
> - * current softif
> + * current mesh(if)
> */
> BATADV_CMD_SET_HARDIF,
>
> /**
> * @BATADV_CMD_GET_VLAN: Get attributes from a VLAN of the
> - * current softif
> + * current mesh(if)
> */
> BATADV_CMD_GET_VLAN,
>
> /**
> * @BATADV_CMD_SET_VLAN: Set attributes for VLAN of the
> - * current softif
> + * current mesh(if)
> */
> BATADV_CMD_SET_VLAN,
>
> @@ -691,7 +691,7 @@
> */
> IFLA_BATADV_ALGO_NAME,
>
> - /* add attributes above here, update the policy in soft-interface.c */
> + /* add attributes above here, update the policy in mesh-interface.c */
>
> /**
> * @__IFLA_BATADV_MAX: internal use
> diff -Nru iproute2-6.14.0/include/uapi/linux/bpf.h iproute2-6.15.0/include/uapi/linux/bpf.h
> --- iproute2-6.14.0/include/uapi/linux/bpf.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/bpf.h 2025-05-26 16:19:09.000000000 +0100
> @@ -51,6 +51,9 @@
> #define BPF_XCHG (0xe0 | BPF_FETCH) /* atomic exchange */
> #define BPF_CMPXCHG (0xf0 | BPF_FETCH) /* atomic compare-and-write */
>
> +#define BPF_LOAD_ACQ 0x100 /* load-acquire */
> +#define BPF_STORE_REL 0x110 /* store-release */
> +
> enum bpf_cond_pseudo_jmp {
> BPF_MAY_GOTO = 0,
> };
> @@ -1207,6 +1210,7 @@
> #define BPF_F_BEFORE (1U << 3)
> #define BPF_F_AFTER (1U << 4)
> #define BPF_F_ID (1U << 5)
> +#define BPF_F_PREORDER (1U << 6)
> #define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
>
> /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
> @@ -1648,6 +1652,7 @@
> };
> __u32 next_id;
> __u32 open_flags;
> + __s32 fd_by_id_token_fd;
> };
>
> struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
> @@ -4963,6 +4968,9 @@
> * the netns switch takes place from ingress to ingress without
> * going through the CPU's backlog queue.
> *
> + * *skb*\ **->mark** and *skb*\ **->tstamp** are not cleared during
> + * the netns switch.
> + *
> * The *flags* argument is reserved and must be 0. The helper is
> * currently only supported for tc BPF program types at the
> * ingress hook and for veth and netkit target device types. The
> @@ -6019,7 +6027,10 @@
> FN(user_ringbuf_drain, 209, ##ctx) \
> FN(cgrp_storage_get, 210, ##ctx) \
> FN(cgrp_storage_delete, 211, ##ctx) \
> - /* */
> + /* This helper list is effectively frozen. If you are trying to \
> + * add a new helper, you should add a kfunc instead which has \
> + * less stability guarantees. See Documentation/bpf/kfuncs.rst \
> + */
>
> /* backwards-compatibility macros for users of __BPF_FUNC_MAPPER that don't
> * know or care about integer value that is now passed as second argument
> @@ -6913,6 +6924,12 @@
> BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
> };
>
> +enum {
> + SK_BPF_CB_TX_TIMESTAMPING = 1<<0,
> + SK_BPF_CB_MASK = (SK_BPF_CB_TX_TIMESTAMPING - 1) |
> + SK_BPF_CB_TX_TIMESTAMPING
> +};
> +
> /* List of known BPF sock_ops operators.
> * New entries can only be added at the end
> */
> @@ -7025,6 +7042,29 @@
> * by the kernel or the
> * earlier bpf-progs.
> */
> + BPF_SOCK_OPS_TSTAMP_SCHED_CB, /* Called when skb is passing
> + * through dev layer when
> + * SK_BPF_CB_TX_TIMESTAMPING
> + * feature is on.
> + */
> + BPF_SOCK_OPS_TSTAMP_SND_SW_CB, /* Called when skb is about to send
> + * to the nic when SK_BPF_CB_TX_TIMESTAMPING
> + * feature is on.
> + */
> + BPF_SOCK_OPS_TSTAMP_SND_HW_CB, /* Called in hardware phase when
> + * SK_BPF_CB_TX_TIMESTAMPING feature
> + * is on.
> + */
> + BPF_SOCK_OPS_TSTAMP_ACK_CB, /* Called when all the skbs in the
> + * same sendmsg call are acked
> + * when SK_BPF_CB_TX_TIMESTAMPING
> + * feature is on.
> + */
> + BPF_SOCK_OPS_TSTAMP_SENDMSG_CB, /* Called when every sendmsg syscall
> + * is triggered. It's used to correlate
> + * sendmsg timestamp with corresponding
> + * tskey.
> + */
> };
>
> /* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
> @@ -7091,6 +7131,7 @@
> TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
> TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
> TCP_BPF_SOCK_OPS_CB_FLAGS = 1008, /* Get or Set TCP sock ops flags */
> + SK_BPF_CB_FLAGS = 1009, /* Get or set sock ops flags in socket */
> };
>
> enum {
> diff -Nru iproute2-6.14.0/include/uapi/linux/btf.h iproute2-6.15.0/include/uapi/linux/btf.h
> --- iproute2-6.14.0/include/uapi/linux/btf.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/btf.h 2025-05-26 16:19:09.000000000 +0100
> @@ -36,7 +36,8 @@
> * bits 24-28: kind (e.g. int, ptr, array...etc)
> * bits 29-30: unused
> * bit 31: kind_flag, currently used by
> - * struct, union, enum, fwd and enum64
> + * struct, union, enum, fwd, enum64,
> + * decl_tag and type_tag
> */
> __u32 info;
> /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
> diff -Nru iproute2-6.14.0/include/uapi/linux/can.h iproute2-6.15.0/include/uapi/linux/can.h
> --- iproute2-6.14.0/include/uapi/linux/can.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/can.h 2025-05-26 16:19:09.000000000 +0100
> @@ -182,7 +182,7 @@
> /*
> * defined bits for canxl_frame.flags
> *
> - * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
> + * The canxl_frame.flags element contains three bits CANXL_[XLF|SEC|RRS]
> * and shares the relative position of the struct can[fd]_frame.len element.
> * The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
> * As a side effect setting this bit intentionally breaks the length checks
> @@ -192,6 +192,7 @@
> */
> #define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
> #define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
> +#define CANXL_RRS 0x02 /* Remote Request Substitution */
>
> /* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
> #define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
> diff -Nru iproute2-6.14.0/include/uapi/linux/capability.h iproute2-6.15.0/include/uapi/linux/capability.h
> --- iproute2-6.14.0/include/uapi/linux/capability.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/capability.h 2025-05-26 16:19:09.000000000 +0100
> @@ -273,6 +273,7 @@
> /* Allow setting encryption key on loopback filesystem */
> /* Allow setting zone reclaim policy */
> /* Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility */
> +/* Allow setting hardware protection emergency action */
>
> #define CAP_SYS_ADMIN 21
>
> diff -Nru iproute2-6.14.0/include/uapi/linux/const.h iproute2-6.15.0/include/uapi/linux/const.h
> --- iproute2-6.14.0/include/uapi/linux/const.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/const.h 2025-05-26 16:19:09.000000000 +0100
> @@ -33,7 +33,7 @@
> * Missing __asm__ support
> *
> * __BIT128() would not work in the __asm__ code, as it shifts an
> - * 'unsigned __init128' data type as direct representation of
> + * 'unsigned __int128' data type as direct representation of
> * 128 bit constants is not supported in the gcc compiler, as
> * they get silently truncated.
> *
> diff -Nru iproute2-6.14.0/include/uapi/linux/fib_rules.h iproute2-6.15.0/include/uapi/linux/fib_rules.h
> --- iproute2-6.14.0/include/uapi/linux/fib_rules.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/fib_rules.h 2025-05-26 16:19:09.000000000 +0100
> @@ -70,6 +70,9 @@
> FRA_DSCP, /* dscp */
> FRA_FLOWLABEL, /* flowlabel */
> FRA_FLOWLABEL_MASK, /* flowlabel mask */
> + FRA_SPORT_MASK, /* sport mask */
> + FRA_DPORT_MASK, /* dport mask */
> + FRA_DSCP_MASK, /* dscp mask */
> __FRA_MAX
> };
>
> diff -Nru iproute2-6.14.0/include/uapi/linux/if_link.h iproute2-6.15.0/include/uapi/linux/if_link.h
> --- iproute2-6.14.0/include/uapi/linux/if_link.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/if_link.h 2025-05-26 16:19:09.000000000 +0100
> @@ -378,6 +378,7 @@
> IFLA_GRO_IPV4_MAX_SIZE,
> IFLA_DPLL_PIN,
> IFLA_MAX_PACING_OFFLOAD_HORIZON,
> + IFLA_NETNS_IMMUTABLE,
> __IFLA_MAX
> };
>
> @@ -1436,6 +1437,7 @@
> IFLA_GENEVE_TTL_INHERIT,
> IFLA_GENEVE_DF,
> IFLA_GENEVE_INNER_PROTO_INHERIT,
> + IFLA_GENEVE_PORT_RANGE,
> __IFLA_GENEVE_MAX
> };
> #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
> @@ -1448,6 +1450,11 @@
> GENEVE_DF_MAX = __GENEVE_DF_END - 1,
> };
>
> +struct ifla_geneve_port_range {
> + __be16 low;
> + __be16 high;
> +};
> +
> /* Bareudp section */
> enum {
> IFLA_BAREUDP_UNSPEC,
> diff -Nru iproute2-6.14.0/include/uapi/linux/rtnetlink.h iproute2-6.15.0/include/uapi/linux/rtnetlink.h
> --- iproute2-6.14.0/include/uapi/linux/rtnetlink.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/rtnetlink.h 2025-05-26 16:19:09.000000000 +0100
> @@ -307,6 +307,7 @@
> #define RTPROT_MROUTED 17 /* Multicast daemon */
> #define RTPROT_KEEPALIVED 18 /* Keepalived daemon */
> #define RTPROT_BABEL 42 /* Babel daemon */
> +#define RTPROT_OVN 84 /* OVN daemon */
> #define RTPROT_OPENR 99 /* Open Routing (Open/R) Routes */
> #define RTPROT_BGP 186 /* BGP Routes */
> #define RTPROT_ISIS 187 /* ISIS Routes */
> diff -Nru iproute2-6.14.0/include/uapi/linux/snmp.h iproute2-6.15.0/include/uapi/linux/snmp.h
> --- iproute2-6.14.0/include/uapi/linux/snmp.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/snmp.h 2025-05-26 16:19:09.000000000 +0100
> @@ -23,9 +23,14 @@
> IPSTATS_MIB_INPKTS, /* InReceives */
> IPSTATS_MIB_INOCTETS, /* InOctets */
> IPSTATS_MIB_INDELIVERS, /* InDelivers */
> - IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */
> + IPSTATS_MIB_NOECTPKTS, /* InNoECTPkts */
> + IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */
> + IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */
> + IPSTATS_MIB_CEPKTS, /* InCEPkts */
> IPSTATS_MIB_OUTREQUESTS, /* OutRequests */
> + IPSTATS_MIB_OUTPKTS, /* OutTransmits */
> IPSTATS_MIB_OUTOCTETS, /* OutOctets */
> + IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */
> /* other fields */
> IPSTATS_MIB_INHDRERRORS, /* InHdrErrors */
> IPSTATS_MIB_INTOOBIGERRORS, /* InTooBigErrors */
> @@ -52,12 +57,7 @@
> IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */
> IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */
> IPSTATS_MIB_CSUMERRORS, /* InCsumErrors */
> - IPSTATS_MIB_NOECTPKTS, /* InNoECTPkts */
> - IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */
> - IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */
> - IPSTATS_MIB_CEPKTS, /* InCEPkts */
> IPSTATS_MIB_REASM_OVERLAPS, /* ReasmOverlaps */
> - IPSTATS_MIB_OUTPKTS, /* OutTransmits */
> __IPSTATS_MIB_MAX
> };
>
> @@ -186,6 +186,7 @@
> LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */
> LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */
> LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */
> + LINUX_MIB_TSECRREJECTED, /* TSEcrRejected */
> LINUX_MIB_PAWS_OLD_ACK, /* PAWSOldAck */
> LINUX_MIB_DELAYEDACKS, /* DelayedACKs */
> LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */
> diff -Nru iproute2-6.14.0/include/uapi/linux/stddef.h iproute2-6.15.0/include/uapi/linux/stddef.h
> --- iproute2-6.14.0/include/uapi/linux/stddef.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/stddef.h 2025-05-26 16:19:09.000000000 +0100
> @@ -70,4 +70,6 @@
> #define __counted_by_be(m)
> #endif
>
> +#define __kernel_nonstring
> +
> #endif /* _LINUX_STDDEF_H */
> diff -Nru iproute2-6.14.0/include/uapi/linux/tcp.h iproute2-6.15.0/include/uapi/linux/tcp.h
> --- iproute2-6.14.0/include/uapi/linux/tcp.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/tcp.h 2025-05-26 16:19:09.000000000 +0100
> @@ -28,7 +28,8 @@
> __be32 seq;
> __be32 ack_seq;
> #if defined(__LITTLE_ENDIAN_BITFIELD)
> - __u16 res1:4,
> + __u16 ae:1,
> + res1:3,
> doff:4,
> fin:1,
> syn:1,
> @@ -40,7 +41,8 @@
> cwr:1;
> #elif defined(__BIG_ENDIAN_BITFIELD)
> __u16 doff:4,
> - res1:4,
> + res1:3,
> + ae:1,
> cwr:1,
> ece:1,
> urg:1,
> @@ -70,6 +72,7 @@
> #define tcp_flag_word(tp) (((union tcp_word_hdr *)(tp))->words[3])
>
> enum {
> + TCP_FLAG_AE = __constant_cpu_to_be32(0x01000000),
> TCP_FLAG_CWR = __constant_cpu_to_be32(0x00800000),
> TCP_FLAG_ECE = __constant_cpu_to_be32(0x00400000),
> TCP_FLAG_URG = __constant_cpu_to_be32(0x00200000),
> @@ -78,7 +81,7 @@
> TCP_FLAG_RST = __constant_cpu_to_be32(0x00040000),
> TCP_FLAG_SYN = __constant_cpu_to_be32(0x00020000),
> TCP_FLAG_FIN = __constant_cpu_to_be32(0x00010000),
> - TCP_RESERVED_BITS = __constant_cpu_to_be32(0x0F000000),
> + TCP_RESERVED_BITS = __constant_cpu_to_be32(0x0E000000),
> TCP_DATA_OFFSET = __constant_cpu_to_be32(0xF0000000)
> };
>
> @@ -136,6 +139,9 @@
> #define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */
>
> #define TCP_IS_MPTCP 43 /* Is MPTCP being used? */
> +#define TCP_RTO_MAX_MS 44 /* max rto time in ms */
> +#define TCP_RTO_MIN_US 45 /* min rto time in us */
> +#define TCP_DELACK_MAX_US 46 /* max delayed ack time in us */
>
> #define TCP_REPAIR_ON 1
> #define TCP_REPAIR_OFF 0
> diff -Nru iproute2-6.14.0/include/uapi/linux/virtio_net.h iproute2-6.15.0/include/uapi/linux/virtio_net.h
> --- iproute2-6.14.0/include/uapi/linux/virtio_net.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/uapi/linux/virtio_net.h 2025-05-26 16:19:09.000000000 +0100
> @@ -327,6 +327,19 @@
> __u8 hash_key_data[/* hash_key_length */];
> };
>
> +struct virtio_net_rss_config_hdr {
> + __le32 hash_types;
> + __le16 indirection_table_mask;
> + __le16 unclassified_queue;
> + __le16 indirection_table[/* 1 + indirection_table_mask */];
> +};
> +
> +struct virtio_net_rss_config_trailer {
> + __le16 max_tx_vq;
> + __u8 hash_key_length;
> + __u8 hash_key_data[/* hash_key_length */];
> +};
> +
> #define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1
>
> /*
> diff -Nru iproute2-6.14.0/include/version.h iproute2-6.15.0/include/version.h
> --- iproute2-6.14.0/include/version.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/include/version.h 2025-05-26 16:19:09.000000000 +0100
> @@ -1 +1 @@
> -static const char version[] = "6.14.0";
> +static const char version[] = "6.15.0";
> diff -Nru iproute2-6.14.0/ip/ila_common.h iproute2-6.15.0/ip/ila_common.h
> --- iproute2-6.14.0/ip/ila_common.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/ila_common.h 2025-05-26 16:19:09.000000000 +0100
> @@ -31,8 +31,6 @@
> return ILA_CSUM_NEUTRAL_MAP_AUTO;
> else if (strcmp(name, "no-action") == 0)
> return ILA_CSUM_NO_ACTION;
> - else if (strcmp(name, "neutral-map-auto") == 0)
> - return ILA_CSUM_NEUTRAL_MAP_AUTO;
> else
> return -1;
> }
> diff -Nru iproute2-6.14.0/ip/ip.c iproute2-6.15.0/ip/ip.c
> --- iproute2-6.14.0/ip/ip.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/ip.c 2025-05-26 16:19:09.000000000 +0100
> @@ -166,7 +166,7 @@
> const char *libbpf_version;
> char *batch_file = NULL;
> char *basename;
> - int color = CONF_COLOR;
> + int color = default_color_opt();
>
> /* to run vrf exec without root, capabilities might be set, drop them
> * if not needed as the first thing.
> diff -Nru iproute2-6.14.0/ip/iplink_netkit.c iproute2-6.15.0/ip/iplink_netkit.c
> --- iproute2-6.14.0/ip/iplink_netkit.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/iplink_netkit.c 2025-05-26 16:19:09.000000000 +0100
> @@ -24,13 +24,19 @@
> [NETKIT_DROP] = "blackhole",
> };
>
> +static const char * const netkit_scrub_strings[] = {
> + [NETKIT_SCRUB_NONE] = "none",
> + [NETKIT_SCRUB_DEFAULT] = "default",
> +};
> +
> static void explain(struct link_util *lu, FILE *f)
> {
> fprintf(f,
> - "Usage: ... %s [ mode MODE ] [ POLICY ] [ peer [ POLICY <options> ] ]\n"
> + "Usage: ... %s [ mode MODE ] [ POLICY ] [ scrub SCRUB ] [ peer [ POLICY <options> ] ]\n"
> "\n"
> "MODE: l3 | l2\n"
> "POLICY: forward | blackhole\n"
> + "SCRUB: default | none\n"
> "(first values are the defaults if nothing is specified)\n"
> "\n"
> "To get <options> type 'ip link add help'.\n",
> @@ -91,6 +97,23 @@
> if (seen_peer)
> duparg("peer", *(argv + 1));
> seen_peer = true;
> + } else if (strcmp(*argv, "scrub") == 0) {
> + int attr_name = seen_peer ?
> + IFLA_NETKIT_PEER_SCRUB :
> + IFLA_NETKIT_SCRUB;
> + enum netkit_scrub scrub;
> +
> + NEXT_ARG();
> +
> + if (strcmp(*argv, "none") == 0) {
> + scrub = NETKIT_SCRUB_NONE;
> + } else if (strcmp(*argv, "default") == 0) {
> + scrub = NETKIT_SCRUB_DEFAULT;
> + } else {
> + fprintf(stderr, "Error: scrub must be either \"none\" or \"default\"\n");
> + return -1;
> + }
> + addattr32(n, 1024, attr_name, scrub);
> } else {
> char *type = NULL;
>
> @@ -144,6 +167,15 @@
> return netkit_mode_strings[mode] ? : inv;
> }
>
> +static const char *netkit_print_scrub(enum netkit_scrub scrub)
> +{
> + const char *inv = "UNKNOWN";
> +
> + if (scrub >= ARRAY_SIZE(netkit_scrub_strings))
> + return inv;
> + return netkit_scrub_strings[scrub] ? : inv;
> +}
> +
> static void netkit_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
> {
> if (!tb)
> @@ -172,6 +204,18 @@
> print_string(PRINT_ANY, "peer_policy", "peer policy %s ",
> netkit_print_policy(policy));
> }
> + if (tb[IFLA_NETKIT_SCRUB]) {
> + enum netkit_scrub scrub = rta_getattr_u32(tb[IFLA_NETKIT_SCRUB]);
> +
> + print_string(PRINT_ANY, "scrub", "scrub %s ",
> + netkit_print_scrub(scrub));
> + }
> + if (tb[IFLA_NETKIT_PEER_SCRUB]) {
> + enum netkit_scrub scrub = rta_getattr_u32(tb[IFLA_NETKIT_PEER_SCRUB]);
> +
> + print_string(PRINT_ANY, "peer_scrub", "peer scrub %s ",
> + netkit_print_scrub(scrub));
> + }
> }
>
> static void netkit_print_help(struct link_util *lu,
> diff -Nru iproute2-6.14.0/ip/ipmonitor.c iproute2-6.15.0/ip/ipmonitor.c
> --- iproute2-6.14.0/ip/ipmonitor.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/ipmonitor.c 2025-05-26 16:19:09.000000000 +0100
> @@ -5,6 +5,7 @@
> * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
> */
>
> +#include <errno.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> @@ -328,38 +329,46 @@
>
> if (lmask & IPMON_LNEXTHOP &&
> rtnl_add_nl_group(&rth, RTNLGRP_NEXTHOP) < 0) {
> - fprintf(stderr, "Failed to add nexthop group to list\n");
> - exit(1);
> + if (errno != EINVAL) {
> + fprintf(stderr, "Failed to add nexthop group to list\n");
> + exit(1);
> + }
> }
>
> if (lmask & IPMON_LSTATS &&
> rtnl_add_nl_group(&rth, RTNLGRP_STATS) < 0 &&
> nmask & IPMON_LSTATS) {
> - fprintf(stderr, "Failed to add stats group to list\n");
> - exit(1);
> + if (errno != EINVAL) {
> + fprintf(stderr, "Failed to add stats group to list\n");
> + exit(1);
> + }
> }
>
> if (lmask & IPMON_LMADDR) {
> if ((!preferred_family || preferred_family == AF_INET) &&
> rtnl_add_nl_group(&rth, RTNLGRP_IPV4_MCADDR) < 0) {
> - fprintf(stderr,
> - "Failed to add ipv4 mcaddr group to list\n");
> - exit(1);
> + if (errno != EINVAL) {
> + fprintf(stderr, "Failed to add ipv4 mcaddr group to list\n");
> + exit(1);
> + }
> }
> if ((!preferred_family || preferred_family == AF_INET6) &&
> rtnl_add_nl_group(&rth, RTNLGRP_IPV6_MCADDR) < 0) {
> - fprintf(stderr,
> - "Failed to add ipv6 mcaddr group to list\n");
> - exit(1);
> + if (errno != EINVAL) {
> + fprintf(stderr,
> + "Failed to add ipv6 mcaddr group to list\n");
> + exit(1);
> + }
> }
> }
>
> if (lmask & IPMON_LACADDR) {
> if ((!preferred_family || preferred_family == AF_INET6) &&
> rtnl_add_nl_group(&rth, RTNLGRP_IPV6_ACADDR) < 0) {
> - fprintf(stderr,
> - "Failed to add ipv6 acaddr group to list\n");
> - exit(1);
> + if (errno != EINVAL) {
> + fprintf(stderr, "Failed to add ipv6 acaddr group to list\n");
> + exit(1);
> + }
> }
> }
>
> diff -Nru iproute2-6.14.0/ip/iproute.c iproute2-6.15.0/ip/iproute.c
> --- iproute2-6.14.0/ip/iproute.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/iproute.c 2025-05-26 16:19:09.000000000 +0100
> @@ -1729,7 +1729,10 @@
>
> if (filter.cloned) {
> if (family != AF_INET6) {
> - iproute_flush_cache();
> + ret = iproute_flush_cache();
> + if (ret < 0)
> + return ret;
> +
> if (show_stats)
> printf("*** IPv4 routing cache is flushed.\n");
> }
> diff -Nru iproute2-6.14.0/ip/iprule.c iproute2-6.15.0/ip/iprule.c
> --- iproute2-6.14.0/ip/iprule.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/iprule.c 2025-05-26 16:19:09.000000000 +0100
> @@ -23,6 +23,9 @@
> #include "ip_common.h"
> #include "json_print.h"
>
> +#define PORT_MAX_MASK 0xFFFF
> +#define DSCP_MAX_MASK 0x3F
> +
> enum list_action {
> IPRULE_LIST,
> IPRULE_FLUSH,
> @@ -44,9 +47,9 @@
> " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
> " [ uidrange NUMBER-NUMBER ]\n"
> " [ ipproto PROTOCOL ]\n"
> - " [ sport [ NUMBER | NUMBER-NUMBER ]\n"
> - " [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
> - " [ dscp DSCP ] [ flowlabel FLOWLABEL[/MASK] ]\n"
> + " [ sport [ NUMBER[/MASK] | NUMBER-NUMBER ]\n"
> + " [ dport [ NUMBER[/MASK] | NUMBER-NUMBER ] ]\n"
> + " [ dscp DSCP[/MASK] ] [ flowlabel FLOWLABEL[/MASK] ]\n"
> "ACTION := [ table TABLE_ID ]\n"
> " [ protocol PROTO ]\n"
> " [ nat ADDRESS ]\n"
> @@ -80,6 +83,7 @@
> int protocolmask;
> struct fib_rule_port_range sport;
> struct fib_rule_port_range dport;
> + __u16 sport_mask, dport_mask;
> __u8 ipproto;
> } filter;
>
> @@ -186,8 +190,9 @@
> return false;
> }
>
> - if (filter.sport.start) {
> + if (filter.sport_mask) {
> const struct fib_rule_port_range *r;
> + __u16 sport_mask = PORT_MAX_MASK;
>
> if (!tb[FRA_SPORT_RANGE])
> return false;
> @@ -196,10 +201,16 @@
> if (r->start != filter.sport.start ||
> r->end != filter.sport.end)
> return false;
> +
> + if (tb[FRA_SPORT_MASK])
> + sport_mask = rta_getattr_u16(tb[FRA_SPORT_MASK]);
> + if (filter.sport_mask != sport_mask)
> + return false;
> }
>
> - if (filter.dport.start) {
> + if (filter.dport_mask) {
> const struct fib_rule_port_range *r;
> + __u16 dport_mask = PORT_MAX_MASK;
>
> if (!tb[FRA_DPORT_RANGE])
> return false;
> @@ -208,6 +219,11 @@
> if (r->start != filter.dport.start ||
> r->end != filter.dport.end)
> return false;
> +
> + if (tb[FRA_DPORT_MASK])
> + dport_mask = rta_getattr_u16(tb[FRA_DPORT_MASK]);
> + if (filter.dport_mask != dport_mask)
> + return false;
> }
>
> if (filter.tun_id) {
> @@ -223,14 +239,21 @@
> }
>
> if (filter.dscpmask) {
> - if (tb[FRA_DSCP]) {
> - __u8 dscp = rta_getattr_u8(tb[FRA_DSCP]);
> + __u8 dscp_mask = DSCP_MAX_MASK;
> + __u8 dscp;
>
> - if (filter.dscp != dscp)
> - return false;
> - } else {
> + if (!tb[FRA_DSCP])
> + return false;
> +
> + dscp = rta_getattr_u8(tb[FRA_DSCP]);
> + if (filter.dscp != dscp)
> + return false;
> +
> + if (tb[FRA_DSCP_MASK])
> + dscp_mask = rta_getattr_u8(tb[FRA_DSCP_MASK]);
> +
> + if (filter.dscpmask != dscp_mask)
> return false;
> - }
> }
>
> if (filter.flowlabel_mask) {
> @@ -390,7 +413,26 @@
> struct fib_rule_port_range *r = RTA_DATA(tb[FRA_SPORT_RANGE]);
>
> if (r->start == r->end) {
> - print_uint(PRINT_ANY, "sport", " sport %u", r->start);
> + if (tb[FRA_SPORT_MASK]) {
> + __u16 mask;
> +
> + mask = rta_getattr_u16(tb[FRA_SPORT_MASK]);
> + print_uint(PRINT_JSON, "sport", NULL, r->start);
> + print_0xhex(PRINT_JSON, "sport_mask", NULL,
> + mask);
> + if (mask == PORT_MAX_MASK) {
> + print_uint(PRINT_FP, NULL, " sport %u",
> + r->start);
> + } else {
> + print_0xhex(PRINT_FP, NULL,
> + " sport %#x", r->start);
> + print_0xhex(PRINT_FP, NULL, "/%#x",
> + mask);
> + }
> + } else {
> + print_uint(PRINT_ANY, "sport", " sport %u",
> + r->start);
> + }
> } else {
> print_uint(PRINT_ANY, "sport_start", " sport %u",
> r->start);
> @@ -402,7 +444,26 @@
> struct fib_rule_port_range *r = RTA_DATA(tb[FRA_DPORT_RANGE]);
>
> if (r->start == r->end) {
> - print_uint(PRINT_ANY, "dport", " dport %u", r->start);
> + if (tb[FRA_DPORT_MASK]) {
> + __u16 mask;
> +
> + mask = rta_getattr_u16(tb[FRA_DPORT_MASK]);
> + print_uint(PRINT_JSON, "dport", NULL, r->start);
> + print_0xhex(PRINT_JSON, "dport_mask", NULL,
> + mask);
> + if (mask == 0xFFFF) {
> + print_uint(PRINT_FP, NULL, " dport %u",
> + r->start);
> + } else {
> + print_0xhex(PRINT_FP, NULL,
> + " dport %#x", r->start);
> + print_0xhex(PRINT_FP, NULL, "/%#x",
> + mask);
> + }
> + } else {
> + print_uint(PRINT_ANY, "dport", " dport %u",
> + r->start);
> + }
> } else {
> print_uint(PRINT_ANY, "dport_start", " dport %u",
> r->start);
> @@ -499,8 +560,24 @@
> if (tb[FRA_DSCP]) {
> __u8 dscp = rta_getattr_u8(tb[FRA_DSCP]);
>
> - print_string(PRINT_ANY, "dscp", " dscp %s",
> - rtnl_dscp_n2a(dscp, b1, sizeof(b1)));
> + if (tb[FRA_DSCP_MASK]) {
> + __u8 mask = rta_getattr_u8(tb[FRA_DSCP_MASK]);
> +
> + print_string(PRINT_JSON, "dscp", NULL,
> + rtnl_dscp_n2a(dscp, b1, sizeof(b1)));
> + print_0xhex(PRINT_JSON, "dscp_mask", NULL, mask);
> + if (mask == DSCP_MAX_MASK) {
> + print_string(PRINT_FP, NULL, " dscp %s",
> + rtnl_dscp_n2a(dscp, b1,
> + sizeof(b1)));
> + } else {
> + print_0xhex(PRINT_FP, NULL, " dscp %#x", dscp);
> + print_0xhex(PRINT_FP, NULL, "/%#x", mask);
> + }
> + } else {
> + print_string(PRINT_ANY, "dscp", " dscp %s",
> + rtnl_dscp_n2a(dscp, b1, sizeof(b1)));
> + }
> }
>
> /* The kernel will either provide both attributes, or none */
> @@ -600,6 +677,55 @@
> return 0;
> }
>
> +static void iprule_port_parse(char *arg, struct fib_rule_port_range *r,
> + __u16 *mask)
> +{
> + char *sep;
> +
> + *mask = PORT_MAX_MASK;
> +
> + sep = strchr(arg, '-');
> + if (sep) {
> + *sep = '\0';
> +
> + if (get_u16(&r->start, arg, 0))
> + invarg("invalid port range start", arg);
> +
> + if (get_u16(&r->end, sep + 1, 0))
> + invarg("invalid port range end", sep + 1);
> +
> + return;
> + }
> +
> + sep = strchr(arg, '/');
> + if (sep) {
> + *sep = '\0';
> +
> + if (get_u16(mask, sep + 1, 0))
> + invarg("invalid mask", sep + 1);
> + }
> +
> + if (get_u16(&r->start, arg, 0))
> + invarg("invalid port", arg);
> +
> + r->end = r->start;
> +}
> +
> +static void iprule_dscp_parse(char *arg, __u32 *dscp, __u32 *mask)
> +{
> + char *slash;
> +
> + *mask = DSCP_MAX_MASK;
> +
> + slash = strchr(arg, '/');
> + if (slash != NULL)
> + *slash = '\0';
> + if (rtnl_dscp_a2n(dscp, arg))
> + invarg("invalid dscp", arg);
> + if (slash && get_u32(mask, slash + 1, 0))
> + invarg("invalid dscp mask", slash + 1);
> +}
> +
> static void iprule_flowlabel_parse(char *arg, __u32 *flowlabel,
> __u32 *flowlabel_mask)
> {
> @@ -746,35 +872,17 @@
> invarg("Invalid \"ipproto\" value\n", *argv);
> filter.ipproto = ipproto;
> } else if (strcmp(*argv, "sport") == 0) {
> - struct fib_rule_port_range r;
> - int ret;
> -
> NEXT_ARG();
> - ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
> - if (ret == 1)
> - r.end = r.start;
> - else if (ret != 2)
> - invarg("invalid port range\n", *argv);
> - filter.sport = r;
> + iprule_port_parse(*argv, &filter.sport,
> + &filter.sport_mask);
> } else if (strcmp(*argv, "dport") == 0) {
> - struct fib_rule_port_range r;
> - int ret;
> -
> NEXT_ARG();
> - ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
> - if (ret == 1)
> - r.end = r.start;
> - else if (ret != 2)
> - invarg("invalid dport range\n", *argv);
> - filter.dport = r;
> + iprule_port_parse(*argv, &filter.dport,
> + &filter.dport_mask);
> } else if (strcmp(*argv, "dscp") == 0) {
> - __u32 dscp;
> -
> NEXT_ARG();
> - if (rtnl_dscp_a2n(&dscp, *argv))
> - invarg("invalid dscp\n", *argv);
> - filter.dscp = dscp;
> - filter.dscpmask = 1;
> + iprule_dscp_parse(*argv, &filter.dscp,
> + &filter.dscpmask);
> } else if (strcmp(*argv, "flowlabel") == 0) {
> NEXT_ARG();
>
> @@ -1036,35 +1144,35 @@
> addattr8(&req.n, sizeof(req), FRA_IP_PROTO, ipproto);
> } else if (strcmp(*argv, "sport") == 0) {
> struct fib_rule_port_range r;
> - int ret = 0;
> + __u16 sport_mask;
>
> NEXT_ARG();
> - ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
> - if (ret == 1)
> - r.end = r.start;
> - else if (ret != 2)
> - invarg("invalid port range\n", *argv);
> + iprule_port_parse(*argv, &r, &sport_mask);
> addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &r,
> sizeof(r));
> + if (sport_mask != PORT_MAX_MASK)
> + addattr16(&req.n, sizeof(req), FRA_SPORT_MASK,
> + sport_mask);
> } else if (strcmp(*argv, "dport") == 0) {
> struct fib_rule_port_range r;
> - int ret = 0;
> + __u16 dport_mask;
>
> NEXT_ARG();
> - ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
> - if (ret == 1)
> - r.end = r.start;
> - else if (ret != 2)
> - invarg("invalid dport range\n", *argv);
> + iprule_port_parse(*argv, &r, &dport_mask);
> addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &r,
> sizeof(r));
> + if (dport_mask != PORT_MAX_MASK)
> + addattr16(&req.n, sizeof(req), FRA_DPORT_MASK,
> + dport_mask);
> } else if (strcmp(*argv, "dscp") == 0) {
> - __u32 dscp;
> + __u32 dscp, dscp_mask;
>
> NEXT_ARG();
> - if (rtnl_dscp_a2n(&dscp, *argv))
> - invarg("invalid dscp\n", *argv);
> + iprule_dscp_parse(*argv, &dscp, &dscp_mask);
> addattr8(&req.n, sizeof(req), FRA_DSCP, dscp);
> + if (dscp_mask != DSCP_MAX_MASK)
> + addattr8(&req.n, sizeof(req), FRA_DSCP_MASK,
> + dscp_mask);
> } else if (strcmp(*argv, "flowlabel") == 0) {
> __u32 flowlabel, flowlabel_mask;
>
> diff -Nru iproute2-6.14.0/ip/ipxfrm.c iproute2-6.15.0/ip/ipxfrm.c
> --- iproute2-6.14.0/ip/ipxfrm.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/ip/ipxfrm.c 2025-05-26 16:19:09.000000000 +0100
> @@ -351,7 +351,10 @@
> t = (long)time;
> tp = localtime(&t);
>
> - strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
> + if (!tp)
> + strcpy(str, "invalid-time");
> + else
> + strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
> }
>
> return str;
> diff -Nru iproute2-6.14.0/lib/color.c iproute2-6.15.0/lib/color.c
> --- iproute2-6.14.0/lib/color.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/lib/color.c 2025-05-26 16:19:09.000000000 +0100
> @@ -81,6 +81,18 @@
> set_color_palette();
> }
>
> +int default_color_opt(void)
> +{
> + const char *no_color;
> +
> + /* If NO_COLOR has a non-empty value, coloured output is never wanted */
> + no_color = getenv("NO_COLOR");
> + if (no_color && *no_color)
> + return COLOR_OPT_NEVER;
> +
> + return CONF_COLOR;
> +}
> +
> bool check_enable_color(int color, int json)
> {
> if (json || color == COLOR_OPT_NEVER)
> diff -Nru iproute2-6.14.0/lib/utils.c iproute2-6.15.0/lib/utils.c
> --- iproute2-6.14.0/lib/utils.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/lib/utils.c 2025-05-26 16:19:09.000000000 +0100
> @@ -304,10 +304,6 @@
> if (res == ULLONG_MAX && errno == ERANGE)
> return -1;
>
> - /* in case ULL is 128 bits */
> - if (res > 0xFFFFFFFFFFFFFFFFULL)
> - return -1;
> -
> *val = res;
> return 0;
> }
> @@ -399,8 +395,6 @@
> return -1;
> if ((res == LLONG_MIN || res == LLONG_MAX) && errno == ERANGE)
> return -1;
> - if (res > INT64_MAX || res < INT64_MIN)
> - return -1;
>
> *val = res;
> return 0;
> diff -Nru iproute2-6.14.0/MAINTAINERS iproute2-6.15.0/MAINTAINERS
> --- iproute2-6.14.0/MAINTAINERS 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/MAINTAINERS 2025-05-26 16:19:09.000000000 +0100
> @@ -26,7 +26,7 @@
> L: netdev@vger.kernel.org
>
> Ethernet Bridging - bridge
> -M: Roopa Prabhu <roopa@nvidia.com>
> +M: Ido Schimmel <idosch@nvidia.com>
> M: Nikolay Aleksandrov <razor@blackwall.org>
> L: bridge@lists.linux-foundation.org (moderated for non-subscribers)
> F: bridge/*
> diff -Nru iproute2-6.14.0/man/man8/ip-link.8.in iproute2-6.15.0/man/man8/ip-link.8.in
> --- iproute2-6.14.0/man/man8/ip-link.8.in 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/man/man8/ip-link.8.in 2025-05-26 16:19:09.000000000 +0100
> @@ -882,10 +882,14 @@
> [
> .BI mode " MODE "
> ] [
> +.BI scrub " SCRUB "
> +] [
> .I "POLICY "
> ] [
> .BR peer
> [
> +.BI scrub " SCRUB "
> +] [
> .I "POLICY "
> ] [
> .I "NAME "
> @@ -899,6 +903,17 @@
> as possible values. Default option is "l3".
>
> .sp
> +.BI scrub " SCRUB"
> +- specifies the scrub behavior of the netkit device with "default" and
> +"none" as possible values. With "default" the device zeroes the
> +skb->{mark,priority} fields before invoking the attached BPF program
> +when its peer device resides in a different network namespace. With
> +"none" the device leaves clearing skb->{mark,priority} up to the BPF
> +program. Default option is "default". Specifying scrub before the peer
> +option refers to the primary device, after the peer option refers to
> +the peer device.
> +
> +.sp
> .I "POLICY"
> - specifies the default device policy when no BPF programs are attached
> with "forward" and "blackhole" as possible values. Default option is
> diff -Nru iproute2-6.14.0/man/man8/ip-rule.8.in iproute2-6.15.0/man/man8/ip-rule.8.in
> --- iproute2-6.14.0/man/man8/ip-rule.8.in 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/man/man8/ip-rule.8.in 2025-05-26 16:19:09.000000000 +0100
> @@ -37,7 +37,7 @@
> .B tos
> .IR TOS " ] [ "
> .B dscp
> -.IR DSCP " ] [ "
> +.IR DSCP\fR[\fB/\fIMASK "] ] [ "
> .B fwmark
> .IR FWMARK\fR[\fB/\fIMASK "] ] [ "
> .B iif
> @@ -52,10 +52,10 @@
> .B ipproto
> .IR PROTOCOL " ] [ "
> .BR sport " [ "
> -.IR NUMBER " | "
> +.IR NUMBER\fR[\fB/\fIMASK "] | "
> .IR NUMBER "-" NUMBER " ] ] [ "
> .BR dport " [ "
> -.IR NUMBER " | "
> +.IR NUMBER\fR[\fB/\fIMASK "] | "
> .IR NUMBER "-" NUMBER " ] ] [ "
> .B tun_id
> .IR TUN_ID " ] [ "
> @@ -239,9 +239,10 @@
> select the TOS value to match.
>
> .TP
> -.BI dscp " DSCP"
> -select the DSCP value to match. DSCP values can be written either directly as
> -numeric values (valid values are 0-63), or using symbolic names specified in
> +.BI dscp " DSCP\fR[\fB/\fIMASK\fR]"
> +select the DSCP value to match with an optional mask. DSCP values can be
> +written either directly as numeric values (valid values are 0-63), or using
> +symbolic names specified in
> .BR @SYSCONF_USR_DIR@/rt_dsfield " or " @SYSCONF_ETC_DIR@/rt_dsfield
> (has precedence if exists).
> However, note that the file specifies full 8-bit dsfield values, whereas
> @@ -270,12 +271,14 @@
> select the ip protocol value to match.
>
> .TP
> -.BI sport " NUMBER | NUMBER-NUMBER"
> -select the source port value to match. supports port range.
> +.BI sport " NUMBER\fR[\fB/\fIMASK\fR] | NUMBER-NUMBER"
> +select the source port value to match with an optional mask. Supports port
> +range.
>
> .TP
> -.BI dport " NUMBER | NUMBER-NUMBER"
> -select the destination port value to match. supports port range.
> +.BI dport " NUMBER\fR[\fB/\fIMASK\fR] | NUMBER-NUMBER"
> +select the destination port value to match with an optional mask. Supports port
> +range.
>
> .TP
> .BI priority " PREFERENCE"
> diff -Nru iproute2-6.14.0/man/man8/rdma-statistic.8 iproute2-6.15.0/man/man8/rdma-statistic.8
> --- iproute2-6.14.0/man/man8/rdma-statistic.8 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/man/man8/rdma-statistic.8 2025-05-26 16:19:09.000000000 +0100
> @@ -39,6 +39,7 @@
> .B auto
> .RI "{ " CRITERIA " | "
> .BR off " }"
> +.B [ optional-counters | on/off ]
>
> .ti -8
> .B rdma statistic
> @@ -180,6 +181,11 @@
> On device mlx5_2 port 1, for each new user QP bind it with a counter automatically. Per counter for QPs with same qp type.
> .RE
> .PP
> +rdma statistic qp set link mlx5_2/1 auto type on optional-counters on
> +.RS 4
> +On device mlx5_2 port 1, for each new user QP bind it with a counter automatically. Per counter for QPs with same qp type. Whilst also binding the currently enabled optional-counters.
> +.RE
> +.PP
> rdma statistic qp set link mlx5_2/1 auto pid on
> .RS 4
> On device mlx5_2 port 1, for each new user QP bind it with a counter automatically. Per counter for QPs with same pid.
> diff -Nru iproute2-6.14.0/misc/nstat.c iproute2-6.15.0/misc/nstat.c
> --- iproute2-6.14.0/misc/nstat.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/misc/nstat.c 2025-05-26 16:19:09.000000000 +0100
> @@ -218,6 +218,10 @@
> p = next;
> }
> n = db;
> + if (n == NULL) {
> + fprintf(stderr, "Error: Invalid input – line has ':' but no entries. Add values after ':'.\n");
> + exit(-2);
> + }
> nread = getline(&buf, &buflen, fp);
> if (nread == -1) {
> fprintf(stderr, "%s:%d: error parsing history file\n",
> diff -Nru iproute2-6.14.0/rdma/include/uapi/rdma/rdma_netlink.h iproute2-6.15.0/rdma/include/uapi/rdma/rdma_netlink.h
> --- iproute2-6.14.0/rdma/include/uapi/rdma/rdma_netlink.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/rdma/include/uapi/rdma/rdma_netlink.h 2025-05-26 16:19:09.000000000 +0100
> @@ -580,6 +580,8 @@
> RDMA_NLDEV_ATTR_EVENT_TYPE, /* u8 */
>
> RDMA_NLDEV_SYS_ATTR_MONITOR_MODE, /* u8 */
> +
> + RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED, /* u8 */
> /*
> * Always the end
> */
> diff -Nru iproute2-6.14.0/rdma/stat.c iproute2-6.15.0/rdma/stat.c
> --- iproute2-6.14.0/rdma/stat.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/rdma/stat.c 2025-05-26 16:19:09.000000000 +0100
> @@ -7,6 +7,7 @@
> #include "rdma.h"
> #include "res.h"
> #include "stat.h"
> +#include "utils.h"
> #include <inttypes.h>
>
> static int stat_help(struct rd *rd)
> @@ -62,7 +63,8 @@
> { NULL },
> };
>
> -static int prepare_auto_mode_str(uint32_t mask, char *output, int len)
> +static int prepare_auto_mode_str(uint32_t mask, bool opcnt, char *output,
> + int len)
> {
> char s[] = "qp auto";
> int i, outlen = strlen(s);
> @@ -90,6 +92,10 @@
> if (outlen + strlen(" on") >= len)
> return -EINVAL;
> strcat(output, " on");
> +
> + strcat(output, " optional-counters ");
> + strcat(output, (opcnt) ? "on" : "off");
> +
> } else {
> if (outlen + strlen(" off") >= len)
> return -EINVAL;
> @@ -104,6 +110,7 @@
> struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
> uint32_t mode = 0, mask = 0;
> char output[128] = {};
> + bool opcnt = false;
> uint32_t idx, port;
> const char *name;
>
> @@ -126,7 +133,10 @@
> if (!tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK])
> return MNL_CB_ERROR;
> mask = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]);
> - prepare_auto_mode_str(mask, output, sizeof(output));
> + if (tb[RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED])
> + opcnt = mnl_attr_get_u8(
> + tb[RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED]);
> + prepare_auto_mode_str(mask, opcnt, output, sizeof(output));
> } else {
> snprintf(output, sizeof(output), "qp auto off");
> }
> @@ -351,6 +361,7 @@
> { .name = "lqpn", .is_number = true },
> { .name = "pid", .is_number = true },
> { .name = "qp-type", .is_number = false },
> + { .name = "optional-counters", .is_number = false },
> };
>
> static int stat_qp_show_one_link(struct rd *rd)
> @@ -395,9 +406,37 @@
> return rd_exec_cmd(rd, cmds, "parameter");
> }
>
> +static bool stat_get_on_off(struct rd *rd, const char *arg, int *ret)
> +{
> + bool value = false;
> +
> + if (strcmpx(rd_argv(rd), arg) != 0) {
> + *ret = -EINVAL;
> + return false;
> + }
> +
> + rd_arg_inc(rd);
> +
> + if (rd_is_multiarg(rd)) {
> + pr_err("The parameter %s shouldn't include range\n", arg);
> + *ret = EINVAL;
> + return false;
> + }
> +
> + value = parse_on_off(arg, rd_argv(rd), ret);
> + if (*ret)
> + return false;
> +
> + rd_arg_inc(rd);
> +
> + return value;
> +}
> +
> static int stat_qp_set_link_auto_sendmsg(struct rd *rd, uint32_t mask)
> {
> uint32_t seq;
> + bool opcnt;
> + int ret;
>
> rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET,
> &seq, (NLM_F_REQUEST | NLM_F_ACK));
> @@ -408,6 +447,13 @@
> mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
> RDMA_COUNTER_MODE_AUTO);
> mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask);
> + if (rd_argc(rd)) {
> + opcnt = stat_get_on_off(rd, "optional-counters", &ret);
> + if (ret)
> + return ret;
> + mnl_attr_put_u8(rd->nlh, RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED,
> + opcnt);
> + }
>
> return rd_sendrecv_msg(rd, seq);
> }
> diff -Nru iproute2-6.14.0/rdma/utils.c iproute2-6.15.0/rdma/utils.c
> --- iproute2-6.14.0/rdma/utils.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/rdma/utils.c 2025-05-26 16:19:09.000000000 +0100
> @@ -479,6 +479,7 @@
> [RDMA_NLDEV_ATTR_PARENT_NAME] = MNL_TYPE_STRING,
> [RDMA_NLDEV_ATTR_EVENT_TYPE] = MNL_TYPE_U8,
> [RDMA_NLDEV_SYS_ATTR_MONITOR_MODE] = MNL_TYPE_U8,
> + [RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED] = MNL_TYPE_U8,
> };
>
> static int rd_attr_check(const struct nlattr *attr, int *typep)
> diff -Nru iproute2-6.14.0/tc/tc.c iproute2-6.15.0/tc/tc.c
> --- iproute2-6.14.0/tc/tc.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/tc/tc.c 2025-05-26 16:19:09.000000000 +0100
> @@ -254,7 +254,7 @@
> {
> const char *libbpf_version;
> char *batch_file = NULL;
> - int color = CONF_COLOR;
> + int color = default_color_opt();
> int ret;
>
> while (argc > 1) {
> diff -Nru iproute2-6.14.0/tc/tc_core.c iproute2-6.15.0/tc/tc_core.c
> --- iproute2-6.14.0/tc/tc_core.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/tc/tc_core.c 2025-05-26 16:19:09.000000000 +0100
> @@ -23,12 +23,12 @@
> static double tick_in_usec = 1;
> static double clock_factor = 1;
>
> -static unsigned int tc_core_time2tick(unsigned int time)
> +static double tc_core_time2tick(double time)
> {
> return time * tick_in_usec;
> }
>
> -unsigned int tc_core_tick2time(unsigned int tick)
> +double tc_core_tick2time(double tick)
> {
> return tick / tick_in_usec;
> }
> @@ -45,7 +45,7 @@
>
> unsigned int tc_calc_xmittime(__u64 rate, unsigned int size)
> {
> - return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate));
> + return ceil(tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate)));
> }
>
> unsigned int tc_calc_xmitsize(__u64 rate, unsigned int ticks)
> diff -Nru iproute2-6.14.0/tc/tc_core.h iproute2-6.15.0/tc/tc_core.h
> --- iproute2-6.14.0/tc/tc_core.h 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/tc/tc_core.h 2025-05-26 16:19:09.000000000 +0100
> @@ -12,7 +12,7 @@
> };
>
>
> -unsigned tc_core_tick2time(unsigned tick);
> +double tc_core_tick2time(double tick);
> unsigned tc_core_time2ktime(unsigned time);
> unsigned tc_core_ktime2time(unsigned ktime);
> unsigned tc_calc_xmittime(__u64 rate, unsigned size);
> diff -Nru iproute2-6.14.0/tc/tc_util.c iproute2-6.15.0/tc/tc_util.c
> --- iproute2-6.14.0/tc/tc_util.c 2025-03-24 16:04:44.000000000 +0000
> +++ iproute2-6.15.0/tc/tc_util.c 2025-05-26 16:19:09.000000000 +0100
> @@ -665,7 +665,8 @@
> tm->expires / hz);
> }
>
> -static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix)
> +static void print_tcstats_basic_hw(struct rtattr **tbs, const char *prefix,
> + __u64 packets64, __u64 packets64_hw)
> {
> struct gnet_stats_basic bs_hw;
>
> @@ -674,8 +675,9 @@
>
> memcpy(&bs_hw, RTA_DATA(tbs[TCA_STATS_BASIC_HW]),
> MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC_HW]), sizeof(bs_hw)));
> + packets64_hw = packets64_hw ? : bs_hw.packets;
>
> - if (bs_hw.bytes == 0 && bs_hw.packets == 0)
> + if (bs_hw.bytes == 0 && packets64_hw == 0)
> return;
>
> if (tbs[TCA_STATS_BASIC]) {
> @@ -684,15 +686,16 @@
> memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]),
> MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]),
> sizeof(bs)));
> + packets64 = packets64 ? : bs.packets;
>
> - if (bs.bytes >= bs_hw.bytes && bs.packets >= bs_hw.packets) {
> + if (bs.bytes >= bs_hw.bytes && packets64 >= packets64_hw) {
> print_nl();
> print_string(PRINT_FP, NULL, "%s", prefix);
> print_lluint(PRINT_ANY, "sw_bytes",
> "Sent software %llu bytes",
> bs.bytes - bs_hw.bytes);
> - print_uint(PRINT_ANY, "sw_packets", " %u pkt",
> - bs.packets - bs_hw.packets);
> + print_lluint(PRINT_ANY, "sw_packets", " %llu pkt",
> + packets64 - packets64_hw);
> }
> }
>
> @@ -700,21 +703,40 @@
> print_string(PRINT_FP, NULL, "%s", prefix);
> print_lluint(PRINT_ANY, "hw_bytes", "Sent hardware %llu bytes",
> bs_hw.bytes);
> - print_uint(PRINT_ANY, "hw_packets", " %u pkt", bs_hw.packets);
> + print_lluint(PRINT_ANY, "hw_packets", " %llu pkt", packets64_hw);
> +}
> +
> +static void parse_packets64(const struct rtattr *nest, __u64 *p_packets64,
> + __u64 *p_packets64_hw)
> +{
> + unsigned short prev_type = __TCA_STATS_MAX;
> + const struct rtattr *pos;
> +
> + /* 'TCA_STATS_PKT64' can appear twice in the 'TCA_ACT_STATS' nest.
> + * Whether the attribute carries the combined or hardware only
> + * statistics depends on the attribute that precedes it in the nest.
> + */
> + rtattr_for_each_nested(pos, nest) {
> + if (pos->rta_type == TCA_STATS_PKT64 &&
> + prev_type == TCA_STATS_BASIC)
> + *p_packets64 = rta_getattr_u64(pos);
> + else if (pos->rta_type == TCA_STATS_PKT64 &&
> + prev_type == TCA_STATS_BASIC_HW)
> + *p_packets64_hw = rta_getattr_u64(pos);
> + prev_type = pos->rta_type;
> + }
> }
>
> void print_tcstats2_attr(struct rtattr *rta, const char *prefix, struct rtattr **xstats)
> {
> struct rtattr *tbs[TCA_STATS_MAX + 1];
> + __u64 packets64 = 0, packets64_hw = 0;
>
> parse_rtattr_nested(tbs, TCA_STATS_MAX, rta);
> + parse_packets64(rta, &packets64, &packets64_hw);
>
> if (tbs[TCA_STATS_BASIC]) {
> struct gnet_stats_basic bs = {0};
> - __u64 packets64 = 0;
> -
> - if (tbs[TCA_STATS_PKT64])
> - packets64 = rta_getattr_u64(tbs[TCA_STATS_PKT64]);
>
> memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]),
> MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), sizeof(bs)));
> @@ -740,7 +762,7 @@
> }
>
> if (tbs[TCA_STATS_BASIC_HW])
> - print_tcstats_basic_hw(tbs, prefix);
> + print_tcstats_basic_hw(tbs, prefix, packets64, packets64_hw);
>
> if (tbs[TCA_STATS_RATE_EST64]) {
> struct gnet_stats_rate_est64 re = {0};
--
Sebastian Ramacher
Reply to: