Your message dated Tue, 27 May 2025 16:53:53 +0000
with message-id <e1ujxyn-00424q...@respighi.debian.org>
and subject line unblock iproute2
has caused the Debian Bug report #1106602,
regarding unblock: iproute2/6.15.0-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
1106602: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1106602
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
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

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};

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply via email to