]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpftool: Add 'prepend' option for tcx attach to insert at chain start
authorGyutae Bae <gyutae.bae@navercorp.com>
Mon, 12 Jan 2026 03:45:16 +0000 (12:45 +0900)
committerAndrii Nakryiko <andrii@kernel.org>
Fri, 16 Jan 2026 22:51:23 +0000 (14:51 -0800)
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>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Quentin Monnet <qmo@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20260112034516.22723-1-gyutae.opensource@navercorp.com
tools/bpf/bpftool/Documentation/bpftool-net.rst
tools/bpf/bpftool/bash-completion/bpftool
tools/bpf/bpftool/net.c

index a9ed8992800fb517d476a3735ffd36bcb2f4a504..22da07087e42d1c985e7fdaaee637ec8b7d107f7 100644 (file)
@@ -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**
index 53bcfeb1a76e628615ea8e39511ee83af4fe8f12..a28f0cc522e48dd08cde4d287d0575c1f3c8c3fd 100644 (file)
@@ -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
index cfc6f944f7c33a05679baf9ffca31eb1269fdaf5..f25d66c8395e45a936a89ecddaf95a4242c1b433 100644 (file)
@@ -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"