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