mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [PATCH] bpftool: Add 'head' option for tcx attach to insert at chain start
       [not found] <20251023093150.25411-1-gyutae.bae@navercorp.com>
@ 2025-11-01 16:21 ` Quentin Monnet
  2026-01-06  8:55   ` [PATCH v2] bpftool: Add 'prepend' " gyutae.opensource
                     ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Quentin Monnet @ 2025-11-01 16:21 UTC (permalink / raw)
  To: Gyutae Bae, bpf
  Cc: linux-kernel, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
	Hao Luo, Jiri Olsa, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

2025-10-23 18:31 UTC+0900 ~ Gyutae Bae <gyutae.bae@navercorp.com>
> Add support for the 'head' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation queries the first program ID in the chain and uses
> BPF_F_BEFORE flag with the relative_id to insert the new program before
> the existing first program. If the chain is empty, the program is simply
> attached normally.
> 
> This change includes:
> - Add get_first_tcx_prog_id() helper to retrieve the first program ID
> - Modify do_attach_tcx() to support head insertion using BPF_F_BEFORE
> - Update documentation to describe the new 'head' option
> - Add bash completion support for the 'head' option on tcx attach types
> - Add example usage in the documentation
> 
> The 'head' option is only valid for tcx_ingress and tcx_egress attach
> types. For XDP attach types, the existing 'overwrite' option remains
> available.
> 
> Example usage:
>   # bpftool net attach tcx_ingress name tc_prog dev lo head
> 
> This feature is useful when the order of program execution in the TCX
> chain matters and users need to ensure certain programs run first.


Hi, thank you for this patch!

Sorry for the delay, your message was filtered as spam for some reason
and I just found it today; I note that I can't find it on Patchwork or
on Lore either, so you'll have to resend it. I also have some comments,
inline below.


> 
> Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
> ---
>  .../bpf/bpftool/Documentation/bpftool-net.rst | 17 ++++++-
>  tools/bpf/bpftool/bash-completion/bpftool     |  9 +++-
>  tools/bpf/bpftool/net.c                       | 51 +++++++++++++++++--
>  3 files changed, 70 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> index a9ed8992800f..e161039a7d1e 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> @@ -24,7 +24,7 @@ NET COMMANDS
>  ============
>  
>  | **bpftool** **net** { **show** | **list** } [ **dev** *NAME* ]
> -| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
> +| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** | **head** ]


How about "prepend" rather than "head"? The meaning would be more
explicit to me, and it would be consistent with "overwrite", which is a
verb as well.


>  | **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
>  | **bpftool** **net help**
>  |
> @@ -72,6 +72,10 @@ bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
>      **tcx_ingress** - Ingress TCX. runs on ingress net traffic;
>      **tcx_egress** - Egress TCX. runs on egress net traffic;
>  
> +    For **tcx_ingress** and **tcx_egress** attach types, the **head** option
> +    can be used to attach the program at the beginning of the chain instead of
> +    at the end.


Thanks! Would you mind updating the description of the "overwrite"
keyword above this, to mention that "overwrite" only applies to
XDP-related types (and to remove the note saying only XDP-related types
are supported by the command, while at it)?


> +
>  bpftool net detach *ATTACH_TYPE* dev *NAME*
>      Detach bpf program attached to network interface *NAME* with type specified
>      by *ATTACH_TYPE*. To detach bpf program, same *ATTACH_TYPE* previously used
> @@ -191,6 +195,17 @@ EXAMPLES
>        tc:
>        lo(1) tcx/ingress tc_prog prog_id 29
>  
> +|
> +| **# bpftool net attach tcx_ingress name tc_prog2 dev lo head**
> +| **# bpftool net**
> +|
> +
> +::
> +
> +      tc:
> +      lo(1) tcx/ingress tc_prog2 prog_id 30
> +      lo(1) tcx/ingress tc_prog prog_id 29
> +
>  |
>  | **# bpftool net attach tcx_ingress name tc_prog dev lo**
>  | **# bpftool net detach tcx_ingress dev lo**
> diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
> index 53bcfeb1a76e..7aba07e8629d 100644
> --- a/tools/bpf/bpftool/bash-completion/bpftool
> +++ b/tools/bpf/bpftool/bash-completion/bpftool
> @@ -1142,7 +1142,14 @@ _bpftool()
>                              return 0
>                              ;;
>                          8)
> -                            _bpftool_once_attr 'overwrite'
> +                            case ${words[3]} in
> +                                tcx_ingress|tcx_egress)
> +                                    _bpftool_once_attr 'head'
> +                                    ;;
> +                                *)
> +                                    _bpftool_once_attr 'overwrite'
> +                                    ;;
> +                            esac


Thanks for this!


>                              return 0
>                              ;;
>                      esac
> diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> index cfc6f944f7c3..d8408a109478 100644
> --- a/tools/bpf/bpftool/net.c
> +++ b/tools/bpf/bpftool/net.c
> @@ -637,6 +637,25 @@ static int net_parse_dev(int *argc, char ***argv)
>  	return ifindex;
>  }
>  
> +static int get_first_tcx_prog_id(int ifindex, enum bpf_attach_type type, __u32 *first_id)
> +{
> +	int ret;
> +
> +	LIBBPF_OPTS(bpf_prog_query_opts, optq);
> +	__u32 prog_ids[1] = {};
> +
> +	optq.prog_ids = prog_ids;
> +	optq.count = ARRAY_SIZE(prog_ids);
> +
> +	ret = bpf_prog_query_opts(ifindex, type, &optq);
> +
> +	if (ret == 0 && optq.count > 0) {
> +		*first_id = prog_ids[0];
> +		return 0;
> +	}
> +	return -1;
> +}
> +
>  static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
>  				int ifindex, bool overwrite)
>  {
> @@ -666,10 +685,20 @@ static int get_tcx_type(enum net_attach_type attach_type)
>  	}
>  }
>  
> -static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
> +static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool head)
>  {
>  	int type = get_tcx_type(attach_type);
> -
> +	__u32 relative_id = 0;


Nit: Please move relative_id to the relevant scope, we don't need it
defined if "head" is false.


> +
> +	if (head) {
> +		if (get_first_tcx_prog_id(ifindex, type, &relative_id) == 0) {


Nit:

    if (!get_first_tcx_prog_id(ifindex, type, &relative_id)) {


> +			LIBBPF_OPTS(bpf_prog_attach_opts, opts,
> +				.flags = BPF_F_BEFORE | BPF_F_ID,
> +				.relative_id = relative_id
> +			);
> +			return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
> +		}
> +	}
>  	return bpf_prog_attach(progfd, ifindex, type, 0);
>  }
>  
> @@ -685,6 +714,7 @@ static int do_attach(int argc, char **argv)
>  	enum net_attach_type attach_type;
>  	int progfd, ifindex, err = 0;
>  	bool overwrite = false;
> +	bool head = false;
>  
>  	/* parse attach args */
>  	if (!REQ_ARGS(5))
> @@ -710,8 +740,16 @@ static int do_attach(int argc, char **argv)
>  	if (argc) {
>  		if (is_prefix(*argv, "overwrite")) {
>  			overwrite = true;


Note: Not directly related to your contribution, but we could also
filter program types here for the "overwrite" keyword, and raise an
error if it's not an XDP-related type, because we don't overwrite
existing programs for TCX (I think we silently ignore the keyword, at
the moment - not great)


> +		} else if (is_prefix(*argv, "head")) {
> +			if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
> +			    attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
> +				p_err("'head' is only supported for tcx_ingress/tcx_egress");
> +				err = -EINVAL;
> +				goto cleanup;
> +			}
> +			head = true;
>  		} else {
> -			p_err("expected 'overwrite', got: '%s'?", *argv);
> +			p_err("expected 'overwrite' or 'head', got: '%s'?", *argv);
>  			err = -EINVAL;
>  			goto cleanup;
>  		}
> @@ -728,7 +766,7 @@ static int do_attach(int argc, char **argv)
>  	/* attach tcx prog */
>  	case NET_ATTACH_TYPE_TCX_INGRESS:
>  	case NET_ATTACH_TYPE_TCX_EGRESS:
> -		err = do_attach_tcx(progfd, attach_type, ifindex);
> +		err = do_attach_tcx(progfd, attach_type, ifindex, head);
>  		break;
>  	default:
>  		break;
> @@ -985,7 +1023,7 @@ static int do_help(int argc, char **argv)
>  
>  	fprintf(stderr,
>  		"Usage: %1$s %2$s { show | list } [dev <devname>]\n"
> -		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
> +		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite | head ]\n"
>  		"       %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
>  		"       %1$s %2$s help\n"
>  		"\n"
> @@ -994,6 +1032,9 @@ static int do_help(int argc, char **argv)
>  		"                        | tcx_egress }\n"
>  		"       " HELP_SPEC_OPTIONS " }\n"
>  		"\n"
> +		"      For tcx_ingress/tcx_egress attach types:\n"
> +		"      head - option attaches the program at the beginning of the chain.\n"
> +		"\n"


I would probably drop that note. Not because it's incorrect, but because
we don't list or explain all keywords in the interactive help for other
commands and it's something that should remain consistent. The
documentation for such keywords at the moment is the man page, I don't
really want a mix of man pages and "--help" description that gets out of
sync.


>  		"Note: Only xdp, tcx, tc, netkit, flow_dissector and netfilter attachments\n"
>  		"      are currently supported.\n"
>  		"      For progs attached to cgroups, use \"bpftool cgroup\"\n"


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2025-11-01 16:21 ` [PATCH] bpftool: Add 'head' option for tcx attach to insert at chain start Quentin Monnet
@ 2026-01-06  8:55   ` gyutae.opensource
  2026-01-06 13:11     ` Daniel Borkmann
  2026-01-07  2:29   ` [PATCH v3] " gyutae.opensource
  2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
  2 siblings, 1 reply; 9+ messages in thread
From: gyutae.opensource @ 2026-01-06  8:55 UTC (permalink / raw)
  To: Quentin Monnet, bpf
  Cc: linux-kernel, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
	Hao Luo, Jiri Olsa, Gyutae Bae, Siwan Kim, Daniel Xu,
	Jiayuan Chen, Tao Chen, Kumar Kartikeya Dwivedi

From: Gyutae Bae <gyutae.bae@navercorp.com>

Add support for the 'prepend' option when attaching tcx_ingress and
tcx_egress programs. This option allows inserting a BPF program at
the beginning of the TCX chain instead of appending it at the end.

The implementation queries the first program ID in the chain and uses
BPF_F_BEFORE flag with the relative_id to insert the new program before
the existing first program. If the chain is empty, the program is simply
attached normally.

This change includes:
- Add get_first_tcx_prog_id() helper to retrieve the first program ID
- Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
- Update documentation to describe the new 'prepend' option
- Add bash completion support for the 'prepend' option on tcx attach types
- Add example usage in the documentation

The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
types. For XDP attach types, the existing 'overwrite' option remains
available.

Example usage:
  # bpftool net attach tcx_ingress name tc_prog dev lo prepend

This feature is useful when the order of program execution in the TCX
chain matters and users need to ensure certain programs run first.

Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
---
Hi Quentin.

Apologies for the delay in getting back to you. I had to sort out
some configuration issues with my mail system to ensure proper
delivery.

I really appreciate your detailed review and feedback on the first
version. I have incorporated your suggestions in this v2 patch.

Changes in v2:
- Renamed 'head' to 'prepend' for consistency with 'overwrite' (Quentin)
- Moved relative_id variable to relevant scope inside if block (Quentin)
- Changed condition style from '== 0' to '!' (Quentin)
- Updated documentation to clarify 'overwrite' is XDP-only (Quentin)
- Removed outdated "only XDP-related modes are supported" note (Quentin)
- Removed extra help text from do_help() for consistency (Quentin)
---
 .../bpf/bpftool/Documentation/bpftool-net.rst | 30 +++++++++---
 tools/bpf/bpftool/bash-completion/bpftool     |  9 +++-
 tools/bpf/bpftool/net.c                       | 47 +++++++++++++++++--
 3 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index a9ed8992800f..22da07087e42 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -24,7 +24,7 @@ NET COMMANDS
 ============

 | **bpftool** **net** { **show** | **list** } [ **dev** *NAME* ]
-| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
+| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** | **prepend** ]
 | **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
 | **bpftool** **net help**
 |
@@ -58,11 +58,9 @@ bpftool net { show | list } [ dev *NAME* ]
     then all bpf programs attached to non clsact qdiscs, and finally all bpf
     programs attached to root and clsact qdisc.

-bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
+bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite | prepend ]
     Attach bpf program *PROG* to network interface *NAME* with type specified
-    by *ATTACH_TYPE*. Previously attached bpf program can be replaced by the
-    command used with **overwrite** option. Currently, only XDP-related modes
-    are supported for *ATTACH_TYPE*.
+    by *ATTACH_TYPE*.

     *ATTACH_TYPE* can be of:
     **xdp** - try native XDP and fallback to generic XDP if NIC driver does not support it;
@@ -72,11 +70,18 @@ bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
     **tcx_ingress** - Ingress TCX. runs on ingress net traffic;
     **tcx_egress** - Egress TCX. runs on egress net traffic;

+    For XDP-related attach types (**xdp**, **xdpgeneric**, **xdpdrv**,
+    **xdpoffload**), the **overwrite** option can be used to replace a
+    previously attached bpf program.
+
+    For **tcx_ingress** and **tcx_egress** attach types, the **prepend** option
+    can be used to attach the program at the beginning of the chain instead of
+    at the end.
+
 bpftool net detach *ATTACH_TYPE* dev *NAME*
     Detach bpf program attached to network interface *NAME* with type specified
     by *ATTACH_TYPE*. To detach bpf program, same *ATTACH_TYPE* previously used
-    for attach must be specified. Currently, only XDP-related modes are
-    supported for *ATTACH_TYPE*.
+    for attach must be specified.

 bpftool net help
     Print short help message.
@@ -191,6 +196,17 @@ EXAMPLES
       tc:
       lo(1) tcx/ingress tc_prog prog_id 29

+|
+| **# bpftool net attach tcx_ingress name tc_prog2 dev lo prepend**
+| **# bpftool net**
+|
+
+::
+
+      tc:
+      lo(1) tcx/ingress tc_prog2 prog_id 30
+      lo(1) tcx/ingress tc_prog prog_id 29
+
 |
 | **# bpftool net attach tcx_ingress name tc_prog dev lo**
 | **# bpftool net detach tcx_ingress dev lo**
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 53bcfeb1a76e..a28f0cc522e4 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -1142,7 +1142,14 @@ _bpftool()
                             return 0
                             ;;
                         8)
-                            _bpftool_once_attr 'overwrite'
+                            case ${words[3]} in
+                                tcx_ingress|tcx_egress)
+                                    _bpftool_once_attr 'prepend'
+                                    ;;
+                                *)
+                                    _bpftool_once_attr 'overwrite'
+                                    ;;
+                            esac
                             return 0
                             ;;
                     esac
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index cfc6f944f7c3..7935a6ba1491 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -637,6 +637,25 @@ static int net_parse_dev(int *argc, char ***argv)
 	return ifindex;
 }

+static int get_first_tcx_prog_id(int ifindex, enum bpf_attach_type type, __u32 *first_id)
+{
+	int ret;
+
+	LIBBPF_OPTS(bpf_prog_query_opts, optq);
+	__u32 prog_ids[1] = {};
+
+	optq.prog_ids = prog_ids;
+	optq.count = ARRAY_SIZE(prog_ids);
+
+	ret = bpf_prog_query_opts(ifindex, type, &optq);
+
+	if (ret == 0 && optq.count > 0) {
+		*first_id = prog_ids[0];
+		return 0;
+	}
+	return -1;
+}
+
 static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
 				int ifindex, bool overwrite)
 {
@@ -666,10 +685,21 @@ static int get_tcx_type(enum net_attach_type attach_type)
 	}
 }

-static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
+static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool prepend)
 {
 	int type = get_tcx_type(attach_type);

+	if (prepend) {
+		__u32 relative_id;
+
+		if (!get_first_tcx_prog_id(ifindex, type, &relative_id)) {
+			LIBBPF_OPTS(bpf_prog_attach_opts, opts,
+				.flags = BPF_F_BEFORE | BPF_F_ID,
+				.relative_id = relative_id
+			);
+			return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
+		}
+	}
 	return bpf_prog_attach(progfd, ifindex, type, 0);
 }

@@ -685,6 +715,7 @@ static int do_attach(int argc, char **argv)
 	enum net_attach_type attach_type;
 	int progfd, ifindex, err = 0;
 	bool overwrite = false;
+	bool prepend = false;

 	/* parse attach args */
 	if (!REQ_ARGS(5))
@@ -710,8 +741,16 @@ static int do_attach(int argc, char **argv)
 	if (argc) {
 		if (is_prefix(*argv, "overwrite")) {
 			overwrite = true;
+		} else if (is_prefix(*argv, "prepend")) {
+			if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
+			    attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
+				p_err("'prepend' is only supported for tcx_ingress/tcx_egress");
+				err = -EINVAL;
+				goto cleanup;
+			}
+			prepend = true;
 		} else {
-			p_err("expected 'overwrite', got: '%s'?", *argv);
+			p_err("expected 'overwrite' or 'prepend', got: '%s'?", *argv);
 			err = -EINVAL;
 			goto cleanup;
 		}
@@ -728,7 +767,7 @@ static int do_attach(int argc, char **argv)
 	/* attach tcx prog */
 	case NET_ATTACH_TYPE_TCX_INGRESS:
 	case NET_ATTACH_TYPE_TCX_EGRESS:
-		err = do_attach_tcx(progfd, attach_type, ifindex);
+		err = do_attach_tcx(progfd, attach_type, ifindex, prepend);
 		break;
 	default:
 		break;
@@ -985,7 +1024,7 @@ static int do_help(int argc, char **argv)

 	fprintf(stderr,
 		"Usage: %1$s %2$s { show | list } [dev <devname>]\n"
-		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
+		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite | prepend ]\n"
 		"       %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
 		"       %1$s %2$s help\n"
 		"\n"
--
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2026-01-06  8:55   ` [PATCH v2] bpftool: Add 'prepend' " gyutae.opensource
@ 2026-01-06 13:11     ` Daniel Borkmann
  0 siblings, 0 replies; 9+ messages in thread
From: Daniel Borkmann @ 2026-01-06 13:11 UTC (permalink / raw)
  To: gyutae.opensource, Quentin Monnet, bpf
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

Hi Gyutae,

On 1/6/26 9:55 AM, gyutae.opensource@navercorp.com wrote:
> From: Gyutae Bae <gyutae.bae@navercorp.com>
> 
> Add support for the 'prepend' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation queries the first program ID in the chain and uses
> BPF_F_BEFORE flag with the relative_id to insert the new program before
> the existing first program. If the chain is empty, the program is simply
> attached normally.
> 
> This change includes:
> - Add get_first_tcx_prog_id() helper to retrieve the first program ID
> - Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
> - Update documentation to describe the new 'prepend' option
> - Add bash completion support for the 'prepend' option on tcx attach types
> - Add example usage in the documentation
> 
> The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
> types. For XDP attach types, the existing 'overwrite' option remains
> available.
> 
> Example usage:
>    # bpftool net attach tcx_ingress name tc_prog dev lo prepend
> 
> This feature is useful when the order of program execution in the TCX
> chain matters and users need to ensure certain programs run first.

Could we make this a bit more generic? The internal API has BPF_F_BEFORE
and BPF_F_AFTER flags, so we could also support relative ids. Alternatively
"prepend" / "append" is imho also ok and the "before" / "after" could be
added at a later point to bpftool.

BPF_F_BEFORE as a standalone flag (and BPF_F_AFTER as a standalone) flag
will have prepend and append behavior, so your approach of adding
get_first_tcx_prog_id() helper to retrieve the first program id is not
necessary, see also tcx BPF selftests [0].

Thanks,
Daniel

   [0] tools/testing/selftests/bpf/prog_tests/tc_links.c

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2025-11-01 16:21 ` [PATCH] bpftool: Add 'head' option for tcx attach to insert at chain start Quentin Monnet
  2026-01-06  8:55   ` [PATCH v2] bpftool: Add 'prepend' " gyutae.opensource
@ 2026-01-07  2:29   ` gyutae.opensource
  2026-01-10  2:48     ` Quentin Monnet
  2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
  2 siblings, 1 reply; 9+ messages in thread
From: gyutae.opensource @ 2026-01-07  2:29 UTC (permalink / raw)
  To: Quentin Monnet, bpf, Daniel Borkmann
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

From: Gyutae Bae <gyutae.bae@navercorp.com>

Add support for the 'prepend' option when attaching tcx_ingress and
tcx_egress programs. This option allows inserting a BPF program at
the beginning of the TCX chain instead of appending it at the end.

The implementation uses BPF_F_BEFORE flag which automatically inserts
the program at the beginning of the chain when no relative reference
is specified.

This change includes:
- Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
- Update documentation to describe the new 'prepend' option
- Add bash completion support for the 'prepend' option on tcx attach types
- Add example usage in the documentation

The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
types. For XDP attach types, the existing 'overwrite' option remains
available.

Example usage:
  # bpftool net attach tcx_ingress name tc_prog dev lo prepend

This feature is useful when the order of program execution in the TCX
chain matters and users need to ensure certain programs run first.

Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
---
Hi Daniel.

Thank you for the detailed feedback. Thanks to your explanation,
I now understand that BPF_F_BEFORE and BPF_F_AFTER work as standalone flags.
This has made the implementation much simpler and cleaner.

Thanks,
Gyutae.

Changes in v3:
- Simplified implementation by using BPF_F_BEFORE alone (Daniel)
- Removed get_first_tcx_prog_id() helper function (Daniel)

Changes in v2:
- Renamed 'head' to 'prepend' for consistency with 'overwrite' (Quentin)
- Moved relative_id variable to relevant scope inside if block (Quentin)
- Changed condition style from '== 0' to '!' (Quentin)
- Updated documentation to clarify 'overwrite' is XDP-only (Quentin)
- Removed outdated "only XDP-related modes are supported" note (Quentin)
- Removed extra help text from do_help() for consistency (Quentin)

 .../bpf/bpftool/Documentation/bpftool-net.rst | 30 ++++++++++++++-----
 tools/bpf/bpftool/bash-completion/bpftool     |  9 +++++-
 tools/bpf/bpftool/net.c                       | 23 +++++++++++---
 3 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index a9ed8992800f..22da07087e42 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -24,7 +24,7 @@ NET COMMANDS
 ============

 | **bpftool** **net** { **show** | **list** } [ **dev** *NAME* ]
-| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
+| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** | **prepend** ]
 | **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
 | **bpftool** **net help**
 |
@@ -58,11 +58,9 @@ bpftool net { show | list } [ dev *NAME* ]
     then all bpf programs attached to non clsact qdiscs, and finally all bpf
     programs attached to root and clsact qdisc.

-bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
+bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite | prepend ]
     Attach bpf program *PROG* to network interface *NAME* with type specified
-    by *ATTACH_TYPE*. Previously attached bpf program can be replaced by the
-    command used with **overwrite** option. Currently, only XDP-related modes
-    are supported for *ATTACH_TYPE*.
+    by *ATTACH_TYPE*.

     *ATTACH_TYPE* can be of:
     **xdp** - try native XDP and fallback to generic XDP if NIC driver does not support it;
@@ -72,11 +70,18 @@ bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
     **tcx_ingress** - Ingress TCX. runs on ingress net traffic;
     **tcx_egress** - Egress TCX. runs on egress net traffic;

+    For XDP-related attach types (**xdp**, **xdpgeneric**, **xdpdrv**,
+    **xdpoffload**), the **overwrite** option can be used to replace a
+    previously attached bpf program.
+
+    For **tcx_ingress** and **tcx_egress** attach types, the **prepend** option
+    can be used to attach the program at the beginning of the chain instead of
+    at the end.
+
 bpftool net detach *ATTACH_TYPE* dev *NAME*
     Detach bpf program attached to network interface *NAME* with type specified
     by *ATTACH_TYPE*. To detach bpf program, same *ATTACH_TYPE* previously used
-    for attach must be specified. Currently, only XDP-related modes are
-    supported for *ATTACH_TYPE*.
+    for attach must be specified.

 bpftool net help
     Print short help message.
@@ -191,6 +196,17 @@ EXAMPLES
       tc:
       lo(1) tcx/ingress tc_prog prog_id 29

+|
+| **# bpftool net attach tcx_ingress name tc_prog2 dev lo prepend**
+| **# bpftool net**
+|
+
+::
+
+      tc:
+      lo(1) tcx/ingress tc_prog2 prog_id 30
+      lo(1) tcx/ingress tc_prog prog_id 29
+
 |
 | **# bpftool net attach tcx_ingress name tc_prog dev lo**
 | **# bpftool net detach tcx_ingress dev lo**
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 53bcfeb1a76e..a28f0cc522e4 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -1142,7 +1142,14 @@ _bpftool()
                             return 0
                             ;;
                         8)
-                            _bpftool_once_attr 'overwrite'
+                            case ${words[3]} in
+                                tcx_ingress|tcx_egress)
+                                    _bpftool_once_attr 'prepend'
+                                    ;;
+                                *)
+                                    _bpftool_once_attr 'overwrite'
+                                    ;;
+                            esac
                             return 0
                             ;;
                     esac
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index cfc6f944f7c3..1a2ba3312a82 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -666,10 +666,16 @@ static int get_tcx_type(enum net_attach_type attach_type)
 	}
 }

-static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
+static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool prepend)
 {
 	int type = get_tcx_type(attach_type);

+	if (prepend) {
+		LIBBPF_OPTS(bpf_prog_attach_opts, opts,
+			.flags = BPF_F_BEFORE
+		);
+		return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
+	}
 	return bpf_prog_attach(progfd, ifindex, type, 0);
 }

@@ -685,6 +691,7 @@ static int do_attach(int argc, char **argv)
 	enum net_attach_type attach_type;
 	int progfd, ifindex, err = 0;
 	bool overwrite = false;
+	bool prepend = false;

 	/* parse attach args */
 	if (!REQ_ARGS(5))
@@ -710,8 +717,16 @@ static int do_attach(int argc, char **argv)
 	if (argc) {
 		if (is_prefix(*argv, "overwrite")) {
 			overwrite = true;
+		} else if (is_prefix(*argv, "prepend")) {
+			if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
+			    attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
+				p_err("'prepend' is only supported for tcx_ingress/tcx_egress");
+				err = -EINVAL;
+				goto cleanup;
+			}
+			prepend = true;
 		} else {
-			p_err("expected 'overwrite', got: '%s'?", *argv);
+			p_err("expected 'overwrite' or 'prepend', got: '%s'?", *argv);
 			err = -EINVAL;
 			goto cleanup;
 		}
@@ -728,7 +743,7 @@ static int do_attach(int argc, char **argv)
 	/* attach tcx prog */
 	case NET_ATTACH_TYPE_TCX_INGRESS:
 	case NET_ATTACH_TYPE_TCX_EGRESS:
-		err = do_attach_tcx(progfd, attach_type, ifindex);
+		err = do_attach_tcx(progfd, attach_type, ifindex, prepend);
 		break;
 	default:
 		break;
@@ -985,7 +1000,7 @@ static int do_help(int argc, char **argv)

 	fprintf(stderr,
 		"Usage: %1$s %2$s { show | list } [dev <devname>]\n"
-		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
+		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite | prepend ]\n"
 		"       %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
 		"       %1$s %2$s help\n"
 		"\n"
--
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2026-01-07  2:29   ` [PATCH v3] " gyutae.opensource
@ 2026-01-10  2:48     ` Quentin Monnet
  0 siblings, 0 replies; 9+ messages in thread
From: Quentin Monnet @ 2026-01-10  2:48 UTC (permalink / raw)
  To: gyutae.opensource, bpf, Daniel Borkmann
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

On 07/01/2026 02:29, gyutae.opensource@navercorp.com wrote:
> From: Gyutae Bae <gyutae.bae@navercorp.com>
> 
> Add support for the 'prepend' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation uses BPF_F_BEFORE flag which automatically inserts
> the program at the beginning of the chain when no relative reference
> is specified.
> 
> This change includes:
> - Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
> - Update documentation to describe the new 'prepend' option
> - Add bash completion support for the 'prepend' option on tcx attach types
> - Add example usage in the documentation
> 
> The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
> types. For XDP attach types, the existing 'overwrite' option remains
> available.
> 
> Example usage:
>   # bpftool net attach tcx_ingress name tc_prog dev lo prepend
> 
> This feature is useful when the order of program execution in the TCX
> chain matters and users need to ensure certain programs run first.
> 
> Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
> ---
> Hi Daniel.
> 
> Thank you for the detailed feedback. Thanks to your explanation,
> I now understand that BPF_F_BEFORE and BPF_F_AFTER work as standalone flags.
> This has made the implementation much simpler and cleaner.
> 
> Thanks,
> Gyutae.
> 
> Changes in v3:
> - Simplified implementation by using BPF_F_BEFORE alone (Daniel)
> - Removed get_first_tcx_prog_id() helper function (Daniel)
> 
> Changes in v2:
> - Renamed 'head' to 'prepend' for consistency with 'overwrite' (Quentin)
> - Moved relative_id variable to relevant scope inside if block (Quentin)
> - Changed condition style from '== 0' to '!' (Quentin)
> - Updated documentation to clarify 'overwrite' is XDP-only (Quentin)
> - Removed outdated "only XDP-related modes are supported" note (Quentin)
> - Removed extra help text from do_help() for consistency (Quentin)
> 
>  .../bpf/bpftool/Documentation/bpftool-net.rst | 30 ++++++++++++++-----
>  tools/bpf/bpftool/bash-completion/bpftool     |  9 +++++-
>  tools/bpf/bpftool/net.c                       | 23 +++++++++++---
>  3 files changed, 50 insertions(+), 12 deletions(-)
> 

[...]

> diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> index cfc6f944f7c3..1a2ba3312a82 100644
> --- a/tools/bpf/bpftool/net.c
> +++ b/tools/bpf/bpftool/net.c
> @@ -666,10 +666,16 @@ static int get_tcx_type(enum net_attach_type attach_type)
>  	}
>  }
> 
> -static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
> +static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool prepend)
>  {
>  	int type = get_tcx_type(attach_type);
> 
> +	if (prepend) {
> +		LIBBPF_OPTS(bpf_prog_attach_opts, opts,
> +			.flags = BPF_F_BEFORE
> +		);
> +		return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
> +	}
>  	return bpf_prog_attach(progfd, ifindex, type, 0);
>  }
> 
> @@ -685,6 +691,7 @@ static int do_attach(int argc, char **argv)
>  	enum net_attach_type attach_type;
>  	int progfd, ifindex, err = 0;
>  	bool overwrite = false;
> +	bool prepend = false;
> 
>  	/* parse attach args */
>  	if (!REQ_ARGS(5))
> @@ -710,8 +717,16 @@ static int do_attach(int argc, char **argv)
>  	if (argc) {
>  		if (is_prefix(*argv, "overwrite")) {
>  			overwrite = true;


Just one minor thing, can we error out here if the attach type is tcx
please? Like you do for "prepend" below, when it's not tcx. So that we
don't let users believe they're overwriting their program.


> +		} else if (is_prefix(*argv, "prepend")) {
> +			if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
> +			    attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
> +				p_err("'prepend' is only supported for tcx_ingress/tcx_egress");
> +				err = -EINVAL;
> +				goto cleanup;
> +			}
> +			prepend = true;
>  		} else {
> -			p_err("expected 'overwrite', got: '%s'?", *argv);
> +			p_err("expected 'overwrite' or 'prepend', got: '%s'?", *argv);
>  			err = -EINVAL;
>  			goto cleanup;
>  		}


Looks good otherwise, thank you! Pending that change:

Reviewed-by: Quentin Monnet <qmo@kernel.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v4] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2025-11-01 16:21 ` [PATCH] bpftool: Add 'head' option for tcx attach to insert at chain start Quentin Monnet
  2026-01-06  8:55   ` [PATCH v2] bpftool: Add 'prepend' " gyutae.opensource
  2026-01-07  2:29   ` [PATCH v3] " gyutae.opensource
@ 2026-01-12  3:45   ` gyutae.opensource
  2026-01-12 10:20     ` Quentin Monnet
                       ` (2 more replies)
  2 siblings, 3 replies; 9+ messages in thread
From: gyutae.opensource @ 2026-01-12  3:45 UTC (permalink / raw)
  To: Quentin Monnet, bpf, Daniel Borkmann
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

From: Gyutae Bae <gyutae.bae@navercorp.com>

Add support for the 'prepend' option when attaching tcx_ingress and
tcx_egress programs. This option allows inserting a BPF program at
the beginning of the TCX chain instead of appending it at the end.

The implementation uses BPF_F_BEFORE flag which automatically inserts
the program at the beginning of the chain when no relative reference
is specified.

This change includes:
- Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
- Update documentation to describe the new 'prepend' option
- Add bash completion support for the 'prepend' option on tcx attach types
- Add example usage in the documentation
- Add validation to reject 'overwrite' for non-XDP attach types

The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
types. For XDP attach types, the existing 'overwrite' option remains
available.

Example usage:
  # bpftool net attach tcx_ingress name tc_prog dev lo prepend

This feature is useful when the order of program execution in the TCX
chain matters and users need to ensure certain programs run first.

Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
Reviewed-by: Quentin Monnet <qmo@kernel.org>
---
Hi Quentin.

Thank you for the review! I have added the validation for 'overwrite'
option as you suggested.

I used a whitelist approach (rejecting non-XDP types) rather than
a blacklist approach (rejecting TCX types) to be consistent with the
'prepend' validation style and to ensure that any future attach types
will also be rejected by default unless explicitly allowed.

Thanks,
Gyutae.

Changes in v4:
- Add validation to reject 'overwrite' for non-XDP attach types (Quentin)

Changes in v3:
- Simplified implementation by using BPF_F_BEFORE alone (Daniel)
- Removed get_first_tcx_prog_id() helper function (Daniel)

Changes in v2:
- Renamed 'head' to 'prepend' for consistency with 'overwrite' (Quentin)
- Moved relative_id variable to relevant scope inside if block (Quentin)
- Changed condition style from '== 0' to '!' (Quentin)
- Updated documentation to clarify 'overwrite' is XDP-only (Quentin)
- Removed outdated "only XDP-related modes are supported" note (Quentin)
- Removed extra help text from do_help() for consistency (Quentin)

 .../bpf/bpftool/Documentation/bpftool-net.rst | 30 +++++++++++++-----
 tools/bpf/bpftool/bash-completion/bpftool     |  9 +++++-
 tools/bpf/bpftool/net.c                       | 31 ++++++++++++++++---
 3 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index a9ed8992800f..22da07087e42 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -24,7 +24,7 @@ NET COMMANDS
 ============
 
 | **bpftool** **net** { **show** | **list** } [ **dev** *NAME* ]
-| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
+| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** | **prepend** ]
 | **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
 | **bpftool** **net help**
 |
@@ -58,11 +58,9 @@ bpftool net { show | list } [ dev *NAME* ]
     then all bpf programs attached to non clsact qdiscs, and finally all bpf
     programs attached to root and clsact qdisc.
 
-bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
+bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite | prepend ]
     Attach bpf program *PROG* to network interface *NAME* with type specified
-    by *ATTACH_TYPE*. Previously attached bpf program can be replaced by the
-    command used with **overwrite** option. Currently, only XDP-related modes
-    are supported for *ATTACH_TYPE*.
+    by *ATTACH_TYPE*.
 
     *ATTACH_TYPE* can be of:
     **xdp** - try native XDP and fallback to generic XDP if NIC driver does not support it;
@@ -72,11 +70,18 @@ bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ]
     **tcx_ingress** - Ingress TCX. runs on ingress net traffic;
     **tcx_egress** - Egress TCX. runs on egress net traffic;
 
+    For XDP-related attach types (**xdp**, **xdpgeneric**, **xdpdrv**,
+    **xdpoffload**), the **overwrite** option can be used to replace a
+    previously attached bpf program.
+
+    For **tcx_ingress** and **tcx_egress** attach types, the **prepend** option
+    can be used to attach the program at the beginning of the chain instead of
+    at the end.
+
 bpftool net detach *ATTACH_TYPE* dev *NAME*
     Detach bpf program attached to network interface *NAME* with type specified
     by *ATTACH_TYPE*. To detach bpf program, same *ATTACH_TYPE* previously used
-    for attach must be specified. Currently, only XDP-related modes are
-    supported for *ATTACH_TYPE*.
+    for attach must be specified.
 
 bpftool net help
     Print short help message.
@@ -191,6 +196,17 @@ EXAMPLES
       tc:
       lo(1) tcx/ingress tc_prog prog_id 29
 
+|
+| **# bpftool net attach tcx_ingress name tc_prog2 dev lo prepend**
+| **# bpftool net**
+|
+
+::
+
+      tc:
+      lo(1) tcx/ingress tc_prog2 prog_id 30
+      lo(1) tcx/ingress tc_prog prog_id 29
+
 |
 | **# bpftool net attach tcx_ingress name tc_prog dev lo**
 | **# bpftool net detach tcx_ingress dev lo**
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 53bcfeb1a76e..a28f0cc522e4 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -1142,7 +1142,14 @@ _bpftool()
                             return 0
                             ;;
                         8)
-                            _bpftool_once_attr 'overwrite'
+                            case ${words[3]} in
+                                tcx_ingress|tcx_egress)
+                                    _bpftool_once_attr 'prepend'
+                                    ;;
+                                *)
+                                    _bpftool_once_attr 'overwrite'
+                                    ;;
+                            esac
                             return 0
                             ;;
                     esac
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index cfc6f944f7c3..f25d66c8395e 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -666,10 +666,16 @@ static int get_tcx_type(enum net_attach_type attach_type)
 	}
 }
 
-static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
+static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool prepend)
 {
 	int type = get_tcx_type(attach_type);
 
+	if (prepend) {
+		LIBBPF_OPTS(bpf_prog_attach_opts, opts,
+			.flags = BPF_F_BEFORE
+		);
+		return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
+	}
 	return bpf_prog_attach(progfd, ifindex, type, 0);
 }
 
@@ -685,6 +691,7 @@ static int do_attach(int argc, char **argv)
 	enum net_attach_type attach_type;
 	int progfd, ifindex, err = 0;
 	bool overwrite = false;
+	bool prepend = false;
 
 	/* parse attach args */
 	if (!REQ_ARGS(5))
@@ -709,9 +716,25 @@ static int do_attach(int argc, char **argv)
 
 	if (argc) {
 		if (is_prefix(*argv, "overwrite")) {
+			if (attach_type != NET_ATTACH_TYPE_XDP &&
+			    attach_type != NET_ATTACH_TYPE_XDP_GENERIC &&
+			    attach_type != NET_ATTACH_TYPE_XDP_DRIVER &&
+			    attach_type != NET_ATTACH_TYPE_XDP_OFFLOAD) {
+				p_err("'overwrite' is only supported for xdp types");
+				err = -EINVAL;
+				goto cleanup;
+			}
 			overwrite = true;
+		} else if (is_prefix(*argv, "prepend")) {
+			if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
+			    attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
+				p_err("'prepend' is only supported for tcx_ingress/tcx_egress");
+				err = -EINVAL;
+				goto cleanup;
+			}
+			prepend = true;
 		} else {
-			p_err("expected 'overwrite', got: '%s'?", *argv);
+			p_err("expected 'overwrite' or 'prepend', got: '%s'?", *argv);
 			err = -EINVAL;
 			goto cleanup;
 		}
@@ -728,7 +751,7 @@ static int do_attach(int argc, char **argv)
 	/* attach tcx prog */
 	case NET_ATTACH_TYPE_TCX_INGRESS:
 	case NET_ATTACH_TYPE_TCX_EGRESS:
-		err = do_attach_tcx(progfd, attach_type, ifindex);
+		err = do_attach_tcx(progfd, attach_type, ifindex, prepend);
 		break;
 	default:
 		break;
@@ -985,7 +1008,7 @@ static int do_help(int argc, char **argv)
 
 	fprintf(stderr,
 		"Usage: %1$s %2$s { show | list } [dev <devname>]\n"
-		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
+		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite | prepend ]\n"
 		"       %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
 		"       %1$s %2$s help\n"
 		"\n"
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
@ 2026-01-12 10:20     ` Quentin Monnet
  2026-01-14 14:19     ` Daniel Borkmann
  2026-01-16 22:50     ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 9+ messages in thread
From: Quentin Monnet @ 2026-01-12 10:20 UTC (permalink / raw)
  To: gyutae.opensource, bpf, Daniel Borkmann
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

2026-01-12 12:45 UTC+0900 ~ gyutae.opensource@navercorp.com
> From: Gyutae Bae <gyutae.bae@navercorp.com>
> 
> Add support for the 'prepend' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation uses BPF_F_BEFORE flag which automatically inserts
> the program at the beginning of the chain when no relative reference
> is specified.
> 
> This change includes:
> - Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
> - Update documentation to describe the new 'prepend' option
> - Add bash completion support for the 'prepend' option on tcx attach types
> - Add example usage in the documentation
> - Add validation to reject 'overwrite' for non-XDP attach types
> 
> The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
> types. For XDP attach types, the existing 'overwrite' option remains
> available.
> 
> Example usage:
>   # bpftool net attach tcx_ingress name tc_prog dev lo prepend
> 
> This feature is useful when the order of program execution in the TCX
> chain matters and users need to ensure certain programs run first.
> 
> Co-developed-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Siwan Kim <siwan.kim@navercorp.com>
> Signed-off-by: Gyutae Bae <gyutae.bae@navercorp.com>
> Reviewed-by: Quentin Monnet <qmo@kernel.org>
> ---
> Hi Quentin.
> 
> Thank you for the review! I have added the validation for 'overwrite'
> option as you suggested.
> 
> I used a whitelist approach (rejecting non-XDP types) rather than
> a blacklist approach (rejecting TCX types) to be consistent with the
> 'prepend' validation style and to ensure that any future attach types
> will also be rejected by default unless explicitly allowed.


Looks good, thank you!
Quentin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
  2026-01-12 10:20     ` Quentin Monnet
@ 2026-01-14 14:19     ` Daniel Borkmann
  2026-01-16 22:50     ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 9+ messages in thread
From: Daniel Borkmann @ 2026-01-14 14:19 UTC (permalink / raw)
  To: gyutae.opensource, Quentin Monnet, bpf
  Cc: linux-kernel, Alexei Starovoitov, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Gyutae Bae, Siwan Kim, Daniel Xu, Jiayuan Chen, Tao Chen,
	Kumar Kartikeya Dwivedi

On 1/12/26 4:45 AM, gyutae.opensource@navercorp.com wrote:
> From: Gyutae Bae <gyutae.bae@navercorp.com>
> 
> Add support for the 'prepend' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation uses BPF_F_BEFORE flag which automatically inserts
> the program at the beginning of the chain when no relative reference
> is specified.
> 
> This change includes:
> - Modify do_attach_tcx() to support prepend insertion using BPF_F_BEFORE
> - Update documentation to describe the new 'prepend' option
> - Add bash completion support for the 'prepend' option on tcx attach types
> - Add example usage in the documentation
> - Add validation to reject 'overwrite' for non-XDP attach types
> 
> The 'prepend' option is only valid for tcx_ingress and tcx_egress attach
> types. For XDP attach types, the existing 'overwrite' option remains
> available.
> 
> Example usage:
>    # bpftool net attach tcx_ingress name tc_prog dev lo prepend
> 
> This feature is useful when the order of program execution in the TCX
> chain matters and users need to ensure certain programs run first.
Acked-by: Daniel Borkmann <daniel@iogearbox.net>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4] bpftool: Add 'prepend' option for tcx attach to insert at chain start
  2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
  2026-01-12 10:20     ` Quentin Monnet
  2026-01-14 14:19     ` Daniel Borkmann
@ 2026-01-16 22:50     ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 9+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-01-16 22:50 UTC (permalink / raw)
  To: None
  Cc: qmo, bpf, daniel, linux-kernel, ast, andrii, martin.lau, eddyz87,
	song, yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
	gyutae.bae, siwan.kim, dxu, jiayuan.chen, chen.dylane, memxor

Hello:

This patch was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Mon, 12 Jan 2026 12:45:16 +0900 you wrote:
> From: Gyutae Bae <gyutae.bae@navercorp.com>
> 
> Add support for the 'prepend' option when attaching tcx_ingress and
> tcx_egress programs. This option allows inserting a BPF program at
> the beginning of the TCX chain instead of appending it at the end.
> 
> The implementation uses BPF_F_BEFORE flag which automatically inserts
> the program at the beginning of the chain when no relative reference
> is specified.
> 
> [...]

Here is the summary with links:
  - [v4] bpftool: Add 'prepend' option for tcx attach to insert at chain start
    https://git.kernel.org/bpf/bpf-next/c/999b2395e3c3

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-01-16 22:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20251023093150.25411-1-gyutae.bae@navercorp.com>
2025-11-01 16:21 ` [PATCH] bpftool: Add 'head' option for tcx attach to insert at chain start Quentin Monnet
2026-01-06  8:55   ` [PATCH v2] bpftool: Add 'prepend' " gyutae.opensource
2026-01-06 13:11     ` Daniel Borkmann
2026-01-07  2:29   ` [PATCH v3] " gyutae.opensource
2026-01-10  2:48     ` Quentin Monnet
2026-01-12  3:45   ` [PATCH v4] " gyutae.opensource
2026-01-12 10:20     ` Quentin Monnet
2026-01-14 14:19     ` Daniel Borkmann
2026-01-16 22:50     ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®