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....@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 <bl...@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 <b...@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 <b...@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 <b...@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 <b...@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 <23110240...@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, <kuz...@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: net...@vger.kernel.org
>  
>  Ethernet Bridging - bridge
> -M: Roopa Prabhu <ro...@nvidia.com>
> +M: Ido Schimmel <ido...@nvidia.com>
>  M: Nikolay Aleksandrov <ra...@blackwall.org>
>  L: bri...@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 via email to