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