You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says:
====================
pull-request: bpf-next 2018-05-17
The following pull-request contains BPF updates for your *net-next* tree.
The main changes are:
1) Provide a new BPF helper for doing a FIB and neighbor lookup
in the kernel tables from an XDP or tc BPF program. The helper
provides a fast-path for forwarding packets. The API supports
IPv4, IPv6 and MPLS protocols, but currently IPv4 and IPv6 are
implemented in this initial work, from David (Ahern).
2) Just a tiny diff but huge feature enabled for nfp driver by
extending the BPF offload beyond a pure host processing offload.
Offloaded XDP programs are allowed to set the RX queue index and
thus opening the door for defining a fully programmable RSS/n-tuple
filter replacement. Once BPF decided on a queue already, the device
data-path will skip the conventional RSS processing completely,
from Jakub.
3) The original sockmap implementation was array based similar to
devmap. However unlike devmap where an ifindex has a 1:1 mapping
into the map there are use cases with sockets that need to be
referenced using longer keys. Hence, sockhash map is added reusing
as much of the sockmap code as possible, from John.
4) Introduce BTF ID. The ID is allocatd through an IDR similar as
with BPF maps and progs. It also makes BTF accessible to user
space via BPF_BTF_GET_FD_BY_ID and adds exposure of the BTF data
through BPF_OBJ_GET_INFO_BY_FD, from Martin.
5) Enable BPF stackmap with build_id also in NMI context. Due to the
up_read() of current->mm->mmap_sem build_id cannot be parsed.
This work defers the up_read() via a per-cpu irq_work so that
at least limited support can be enabled, from Song.
6) Various BPF JIT follow-up cleanups and fixups after the LD_ABS/LD_IND
JIT conversion as well as implementation of an optimized 32/64 bit
immediate load in the arm64 JIT that allows to reduce the number of
emitted instructions; in case of tested real-world programs they
were shrinking by three percent, from Daniel.
7) Add ifindex parameter to the libbpf loader in order to enable
BPF offload support. Right now only iproute2 can load offloaded
BPF and this will also enable libbpf for direct integration into
other applications, from David (Beckett).
8) Convert the plain text documentation under Documentation/bpf/ into
RST format since this is the appropriate standard the kernel is
moving to for all documentation. Also add an overview README.rst,
from Jesper.
9) Add __printf verification attribute to the bpf_verifier_vlog()
helper. Though it uses va_list we can still allow gcc to check
the format string, from Mathieu.
10) Fix a bash reference in the BPF selftest's Makefile. The '|& ...'
is a bash 4.0+ feature which is not guaranteed to be available
when calling out to shell, therefore use a more portable variant,
from Joe.
11) Fix a 64 bit division in xdp_umem_reg() by using div_u64()
instead of relying on the gcc built-in, from Björn.
12) Fix a sock hashmap kmalloc warning reported by syzbot when an
overly large key size is used in hashmap then causing overflows
in htab->elem_size. Reject bogus attr->key_size early in the
sock_hash_alloc(), from Yonghong.
13) Ensure in BPF selftests when urandom_read is being linked that
--build-id is always enabled so that test_stacktrace_build_id[_nmi]
won't be failing, from Alexei.
14) Add bitsperlong.h as well as errno.h uapi headers into the tools
header infrastructure which point to one of the arch specific
uapi headers. This was needed in order to fix a build error on
some systems for the BPF selftests, from Sirio.
15) Allow for short options to be used in the xdp_monitor BPF sample
code. And also a bpf.h tools uapi header sync in order to fix a
selftest build failure. Both from Prashant.
16) More formally clarify the meaning of ID in the direct packet access
section of the BPF documentation, from Wang.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
=================
|
||||
BPF documentation
|
||||
=================
|
||||
|
||||
This directory contains documentation for the BPF (Berkeley Packet
|
||||
Filter) facility, with a focus on the extended BPF version (eBPF).
|
||||
|
||||
This kernel side documentation is still work in progress. The main
|
||||
textual documentation is (for historical reasons) described in
|
||||
`Documentation/networking/filter.txt`_, which describe both classical
|
||||
and extended BPF instruction-set.
|
||||
The Cilium project also maintains a `BPF and XDP Reference Guide`_
|
||||
that goes into great technical depth about the BPF Architecture.
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_.
|
||||
|
||||
|
||||
|
||||
Frequently asked questions (FAQ)
|
||||
================================
|
||||
|
||||
Two sets of Questions and Answers (Q&A) are maintained.
|
||||
|
||||
* QA for common questions about BPF see: bpf_design_QA_
|
||||
|
||||
* QA for developers interacting with BPF subsystem: bpf_devel_QA_
|
||||
|
||||
|
||||
.. Links:
|
||||
.. _bpf_design_QA: bpf_design_QA.rst
|
||||
.. _bpf_devel_QA: bpf_devel_QA.rst
|
||||
.. _Documentation/networking/filter.txt: ../networking/filter.txt
|
||||
.. _man-pages: https://www.kernel.org/doc/man-pages/
|
||||
.. _bpf(2): http://man7.org/linux/man-pages/man2/bpf.2.html
|
||||
.. _BPF and XDP Reference Guide: http://cilium.readthedocs.io/en/latest/bpf/
|
||||
@@ -0,0 +1,221 @@
|
||||
==============
|
||||
BPF Design Q&A
|
||||
==============
|
||||
|
||||
BPF extensibility and applicability to networking, tracing, security
|
||||
in the linux kernel and several user space implementations of BPF
|
||||
virtual machine led to a number of misunderstanding on what BPF actually is.
|
||||
This short QA is an attempt to address that and outline a direction
|
||||
of where BPF is heading long term.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 3
|
||||
|
||||
Questions and Answers
|
||||
=====================
|
||||
|
||||
Q: Is BPF a generic instruction set similar to x64 and arm64?
|
||||
-------------------------------------------------------------
|
||||
A: NO.
|
||||
|
||||
Q: Is BPF a generic virtual machine ?
|
||||
-------------------------------------
|
||||
A: NO.
|
||||
|
||||
BPF is generic instruction set *with* C calling convention.
|
||||
-----------------------------------------------------------
|
||||
|
||||
Q: Why C calling convention was chosen?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A: Because BPF programs are designed to run in the linux kernel
|
||||
which is written in C, hence BPF defines instruction set compatible
|
||||
with two most used architectures x64 and arm64 (and takes into
|
||||
consideration important quirks of other architectures) and
|
||||
defines calling convention that is compatible with C calling
|
||||
convention of the linux kernel on those architectures.
|
||||
|
||||
Q: can multiple return values be supported in the future?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: NO. BPF allows only register R0 to be used as return value.
|
||||
|
||||
Q: can more than 5 function arguments be supported in the future?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: NO. BPF calling convention only allows registers R1-R5 to be used
|
||||
as arguments. BPF is not a standalone instruction set.
|
||||
(unlike x64 ISA that allows msft, cdecl and other conventions)
|
||||
|
||||
Q: can BPF programs access instruction pointer or return address?
|
||||
-----------------------------------------------------------------
|
||||
A: NO.
|
||||
|
||||
Q: can BPF programs access stack pointer ?
|
||||
------------------------------------------
|
||||
A: NO.
|
||||
|
||||
Only frame pointer (register R10) is accessible.
|
||||
From compiler point of view it's necessary to have stack pointer.
|
||||
For example LLVM defines register R11 as stack pointer in its
|
||||
BPF backend, but it makes sure that generated code never uses it.
|
||||
|
||||
Q: Does C-calling convention diminishes possible use cases?
|
||||
-----------------------------------------------------------
|
||||
A: YES.
|
||||
|
||||
BPF design forces addition of major functionality in the form
|
||||
of kernel helper functions and kernel objects like BPF maps with
|
||||
seamless interoperability between them. It lets kernel call into
|
||||
BPF programs and programs call kernel helpers with zero overhead.
|
||||
As all of them were native C code. That is particularly the case
|
||||
for JITed BPF programs that are indistinguishable from
|
||||
native kernel C code.
|
||||
|
||||
Q: Does it mean that 'innovative' extensions to BPF code are disallowed?
|
||||
------------------------------------------------------------------------
|
||||
A: Soft yes.
|
||||
|
||||
At least for now until BPF core has support for
|
||||
bpf-to-bpf calls, indirect calls, loops, global variables,
|
||||
jump tables, read only sections and all other normal constructs
|
||||
that C code can produce.
|
||||
|
||||
Q: Can loops be supported in a safe way?
|
||||
----------------------------------------
|
||||
A: It's not clear yet.
|
||||
|
||||
BPF developers are trying to find a way to
|
||||
support bounded loops where the verifier can guarantee that
|
||||
the program terminates in less than 4096 instructions.
|
||||
|
||||
Instruction level questions
|
||||
---------------------------
|
||||
|
||||
Q: LD_ABS and LD_IND instructions vs C code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Q: How come LD_ABS and LD_IND instruction are present in BPF whereas
|
||||
C code cannot express them and has to use builtin intrinsics?
|
||||
|
||||
A: This is artifact of compatibility with classic BPF. Modern
|
||||
networking code in BPF performs better without them.
|
||||
See 'direct packet access'.
|
||||
|
||||
Q: BPF instructions mapping not one-to-one to native CPU
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Q: It seems not all BPF instructions are one-to-one to native CPU.
|
||||
For example why BPF_JNE and other compare and jumps are not cpu-like?
|
||||
|
||||
A: This was necessary to avoid introducing flags into ISA which are
|
||||
impossible to make generic and efficient across CPU architectures.
|
||||
|
||||
Q: why BPF_DIV instruction doesn't map to x64 div?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because if we picked one-to-one relationship to x64 it would have made
|
||||
it more complicated to support on arm64 and other archs. Also it
|
||||
needs div-by-zero runtime check.
|
||||
|
||||
Q: why there is no BPF_SDIV for signed divide operation?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because it would be rarely used. llvm errors in such case and
|
||||
prints a suggestion to use unsigned divide instead
|
||||
|
||||
Q: Why BPF has implicit prologue and epilogue?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because architectures like sparc have register windows and in general
|
||||
there are enough subtle differences between architectures, so naive
|
||||
store return address into stack won't work. Another reason is BPF has
|
||||
to be safe from division by zero (and legacy exception path
|
||||
of LD_ABS insn). Those instructions need to invoke epilogue and
|
||||
return implicitly.
|
||||
|
||||
Q: Why BPF_JLT and BPF_JLE instructions were not introduced in the beginning?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because classic BPF didn't have them and BPF authors felt that compiler
|
||||
workaround would be acceptable. Turned out that programs lose performance
|
||||
due to lack of these compare instructions and they were added.
|
||||
These two instructions is a perfect example what kind of new BPF
|
||||
instructions are acceptable and can be added in the future.
|
||||
These two already had equivalent instructions in native CPUs.
|
||||
New instructions that don't have one-to-one mapping to HW instructions
|
||||
will not be accepted.
|
||||
|
||||
Q: BPF 32-bit subregister requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Q: BPF 32-bit subregisters have a requirement to zero upper 32-bits of BPF
|
||||
registers which makes BPF inefficient virtual machine for 32-bit
|
||||
CPU architectures and 32-bit HW accelerators. Can true 32-bit registers
|
||||
be added to BPF in the future?
|
||||
|
||||
A: NO. The first thing to improve performance on 32-bit archs is to teach
|
||||
LLVM to generate code that uses 32-bit subregisters. Then second step
|
||||
is to teach verifier to mark operations where zero-ing upper bits
|
||||
is unnecessary. Then JITs can take advantage of those markings and
|
||||
drastically reduce size of generated code and improve performance.
|
||||
|
||||
Q: Does BPF have a stable ABI?
|
||||
------------------------------
|
||||
A: YES. BPF instructions, arguments to BPF programs, set of helper
|
||||
functions and their arguments, recognized return codes are all part
|
||||
of ABI. However when tracing programs are using bpf_probe_read() helper
|
||||
to walk kernel internal datastructures and compile with kernel
|
||||
internal headers these accesses can and will break with newer
|
||||
kernels. The union bpf_attr -> kern_version is checked at load time
|
||||
to prevent accidentally loading kprobe-based bpf programs written
|
||||
for a different kernel. Networking programs don't do kern_version check.
|
||||
|
||||
Q: How much stack space a BPF program uses?
|
||||
-------------------------------------------
|
||||
A: Currently all program types are limited to 512 bytes of stack
|
||||
space, but the verifier computes the actual amount of stack used
|
||||
and both interpreter and most JITed code consume necessary amount.
|
||||
|
||||
Q: Can BPF be offloaded to HW?
|
||||
------------------------------
|
||||
A: YES. BPF HW offload is supported by NFP driver.
|
||||
|
||||
Q: Does classic BPF interpreter still exist?
|
||||
--------------------------------------------
|
||||
A: NO. Classic BPF programs are converted into extend BPF instructions.
|
||||
|
||||
Q: Can BPF call arbitrary kernel functions?
|
||||
-------------------------------------------
|
||||
A: NO. BPF programs can only call a set of helper functions which
|
||||
is defined for every program type.
|
||||
|
||||
Q: Can BPF overwrite arbitrary kernel memory?
|
||||
---------------------------------------------
|
||||
A: NO.
|
||||
|
||||
Tracing bpf programs can *read* arbitrary memory with bpf_probe_read()
|
||||
and bpf_probe_read_str() helpers. Networking programs cannot read
|
||||
arbitrary memory, since they don't have access to these helpers.
|
||||
Programs can never read or write arbitrary memory directly.
|
||||
|
||||
Q: Can BPF overwrite arbitrary user memory?
|
||||
-------------------------------------------
|
||||
A: Sort-of.
|
||||
|
||||
Tracing BPF programs can overwrite the user memory
|
||||
of the current task with bpf_probe_write_user(). Every time such
|
||||
program is loaded the kernel will print warning message, so
|
||||
this helper is only useful for experiments and prototypes.
|
||||
Tracing BPF programs are root only.
|
||||
|
||||
Q: bpf_trace_printk() helper warning
|
||||
------------------------------------
|
||||
Q: When bpf_trace_printk() helper is used the kernel prints nasty
|
||||
warning message. Why is that?
|
||||
|
||||
A: This is done to nudge program authors into better interfaces when
|
||||
programs need to pass data to user space. Like bpf_perf_event_output()
|
||||
can be used to efficiently stream data via perf ring buffer.
|
||||
BPF maps can be used for asynchronous data sharing between kernel
|
||||
and user space. bpf_trace_printk() should only be used for debugging.
|
||||
|
||||
Q: New functionality via kernel modules?
|
||||
----------------------------------------
|
||||
Q: Can BPF functionality such as new program or map types, new
|
||||
helpers, etc be added out of kernel module code?
|
||||
|
||||
A: NO.
|
||||
@@ -1,156 +0,0 @@
|
||||
BPF extensibility and applicability to networking, tracing, security
|
||||
in the linux kernel and several user space implementations of BPF
|
||||
virtual machine led to a number of misunderstanding on what BPF actually is.
|
||||
This short QA is an attempt to address that and outline a direction
|
||||
of where BPF is heading long term.
|
||||
|
||||
Q: Is BPF a generic instruction set similar to x64 and arm64?
|
||||
A: NO.
|
||||
|
||||
Q: Is BPF a generic virtual machine ?
|
||||
A: NO.
|
||||
|
||||
BPF is generic instruction set _with_ C calling convention.
|
||||
|
||||
Q: Why C calling convention was chosen?
|
||||
A: Because BPF programs are designed to run in the linux kernel
|
||||
which is written in C, hence BPF defines instruction set compatible
|
||||
with two most used architectures x64 and arm64 (and takes into
|
||||
consideration important quirks of other architectures) and
|
||||
defines calling convention that is compatible with C calling
|
||||
convention of the linux kernel on those architectures.
|
||||
|
||||
Q: can multiple return values be supported in the future?
|
||||
A: NO. BPF allows only register R0 to be used as return value.
|
||||
|
||||
Q: can more than 5 function arguments be supported in the future?
|
||||
A: NO. BPF calling convention only allows registers R1-R5 to be used
|
||||
as arguments. BPF is not a standalone instruction set.
|
||||
(unlike x64 ISA that allows msft, cdecl and other conventions)
|
||||
|
||||
Q: can BPF programs access instruction pointer or return address?
|
||||
A: NO.
|
||||
|
||||
Q: can BPF programs access stack pointer ?
|
||||
A: NO. Only frame pointer (register R10) is accessible.
|
||||
From compiler point of view it's necessary to have stack pointer.
|
||||
For example LLVM defines register R11 as stack pointer in its
|
||||
BPF backend, but it makes sure that generated code never uses it.
|
||||
|
||||
Q: Does C-calling convention diminishes possible use cases?
|
||||
A: YES. BPF design forces addition of major functionality in the form
|
||||
of kernel helper functions and kernel objects like BPF maps with
|
||||
seamless interoperability between them. It lets kernel call into
|
||||
BPF programs and programs call kernel helpers with zero overhead.
|
||||
As all of them were native C code. That is particularly the case
|
||||
for JITed BPF programs that are indistinguishable from
|
||||
native kernel C code.
|
||||
|
||||
Q: Does it mean that 'innovative' extensions to BPF code are disallowed?
|
||||
A: Soft yes. At least for now until BPF core has support for
|
||||
bpf-to-bpf calls, indirect calls, loops, global variables,
|
||||
jump tables, read only sections and all other normal constructs
|
||||
that C code can produce.
|
||||
|
||||
Q: Can loops be supported in a safe way?
|
||||
A: It's not clear yet. BPF developers are trying to find a way to
|
||||
support bounded loops where the verifier can guarantee that
|
||||
the program terminates in less than 4096 instructions.
|
||||
|
||||
Q: How come LD_ABS and LD_IND instruction are present in BPF whereas
|
||||
C code cannot express them and has to use builtin intrinsics?
|
||||
A: This is artifact of compatibility with classic BPF. Modern
|
||||
networking code in BPF performs better without them.
|
||||
See 'direct packet access'.
|
||||
|
||||
Q: It seems not all BPF instructions are one-to-one to native CPU.
|
||||
For example why BPF_JNE and other compare and jumps are not cpu-like?
|
||||
A: This was necessary to avoid introducing flags into ISA which are
|
||||
impossible to make generic and efficient across CPU architectures.
|
||||
|
||||
Q: why BPF_DIV instruction doesn't map to x64 div?
|
||||
A: Because if we picked one-to-one relationship to x64 it would have made
|
||||
it more complicated to support on arm64 and other archs. Also it
|
||||
needs div-by-zero runtime check.
|
||||
|
||||
Q: why there is no BPF_SDIV for signed divide operation?
|
||||
A: Because it would be rarely used. llvm errors in such case and
|
||||
prints a suggestion to use unsigned divide instead
|
||||
|
||||
Q: Why BPF has implicit prologue and epilogue?
|
||||
A: Because architectures like sparc have register windows and in general
|
||||
there are enough subtle differences between architectures, so naive
|
||||
store return address into stack won't work. Another reason is BPF has
|
||||
to be safe from division by zero (and legacy exception path
|
||||
of LD_ABS insn). Those instructions need to invoke epilogue and
|
||||
return implicitly.
|
||||
|
||||
Q: Why BPF_JLT and BPF_JLE instructions were not introduced in the beginning?
|
||||
A: Because classic BPF didn't have them and BPF authors felt that compiler
|
||||
workaround would be acceptable. Turned out that programs lose performance
|
||||
due to lack of these compare instructions and they were added.
|
||||
These two instructions is a perfect example what kind of new BPF
|
||||
instructions are acceptable and can be added in the future.
|
||||
These two already had equivalent instructions in native CPUs.
|
||||
New instructions that don't have one-to-one mapping to HW instructions
|
||||
will not be accepted.
|
||||
|
||||
Q: BPF 32-bit subregisters have a requirement to zero upper 32-bits of BPF
|
||||
registers which makes BPF inefficient virtual machine for 32-bit
|
||||
CPU architectures and 32-bit HW accelerators. Can true 32-bit registers
|
||||
be added to BPF in the future?
|
||||
A: NO. The first thing to improve performance on 32-bit archs is to teach
|
||||
LLVM to generate code that uses 32-bit subregisters. Then second step
|
||||
is to teach verifier to mark operations where zero-ing upper bits
|
||||
is unnecessary. Then JITs can take advantage of those markings and
|
||||
drastically reduce size of generated code and improve performance.
|
||||
|
||||
Q: Does BPF have a stable ABI?
|
||||
A: YES. BPF instructions, arguments to BPF programs, set of helper
|
||||
functions and their arguments, recognized return codes are all part
|
||||
of ABI. However when tracing programs are using bpf_probe_read() helper
|
||||
to walk kernel internal datastructures and compile with kernel
|
||||
internal headers these accesses can and will break with newer
|
||||
kernels. The union bpf_attr -> kern_version is checked at load time
|
||||
to prevent accidentally loading kprobe-based bpf programs written
|
||||
for a different kernel. Networking programs don't do kern_version check.
|
||||
|
||||
Q: How much stack space a BPF program uses?
|
||||
A: Currently all program types are limited to 512 bytes of stack
|
||||
space, but the verifier computes the actual amount of stack used
|
||||
and both interpreter and most JITed code consume necessary amount.
|
||||
|
||||
Q: Can BPF be offloaded to HW?
|
||||
A: YES. BPF HW offload is supported by NFP driver.
|
||||
|
||||
Q: Does classic BPF interpreter still exist?
|
||||
A: NO. Classic BPF programs are converted into extend BPF instructions.
|
||||
|
||||
Q: Can BPF call arbitrary kernel functions?
|
||||
A: NO. BPF programs can only call a set of helper functions which
|
||||
is defined for every program type.
|
||||
|
||||
Q: Can BPF overwrite arbitrary kernel memory?
|
||||
A: NO. Tracing bpf programs can _read_ arbitrary memory with bpf_probe_read()
|
||||
and bpf_probe_read_str() helpers. Networking programs cannot read
|
||||
arbitrary memory, since they don't have access to these helpers.
|
||||
Programs can never read or write arbitrary memory directly.
|
||||
|
||||
Q: Can BPF overwrite arbitrary user memory?
|
||||
A: Sort-of. Tracing BPF programs can overwrite the user memory
|
||||
of the current task with bpf_probe_write_user(). Every time such
|
||||
program is loaded the kernel will print warning message, so
|
||||
this helper is only useful for experiments and prototypes.
|
||||
Tracing BPF programs are root only.
|
||||
|
||||
Q: When bpf_trace_printk() helper is used the kernel prints nasty
|
||||
warning message. Why is that?
|
||||
A: This is done to nudge program authors into better interfaces when
|
||||
programs need to pass data to user space. Like bpf_perf_event_output()
|
||||
can be used to efficiently stream data via perf ring buffer.
|
||||
BPF maps can be used for asynchronous data sharing between kernel
|
||||
and user space. bpf_trace_printk() should only be used for debugging.
|
||||
|
||||
Q: Can BPF functionality such as new program or map types, new
|
||||
helpers, etc be added out of kernel module code?
|
||||
A: NO.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1142,6 +1142,7 @@ into a register from memory, the register's top 56 bits are known zero, while
|
||||
the low 8 are unknown - which is represented as the tnum (0x0; 0xff). If we
|
||||
then OR this with 0x40, we get (0x40; 0xbf), then if we add 1 we get (0x0;
|
||||
0x1ff), because of potential carries.
|
||||
|
||||
Besides arithmetic, the register state can also be updated by conditional
|
||||
branches. For instance, if a SCALAR_VALUE is compared > 8, in the 'true' branch
|
||||
it will have a umin_value (unsigned minimum value) of 9, whereas in the 'false'
|
||||
@@ -1150,14 +1151,16 @@ BPF_JSGE) would instead update the signed minimum/maximum values. Information
|
||||
from the signed and unsigned bounds can be combined; for instance if a value is
|
||||
first tested < 8 and then tested s> 4, the verifier will conclude that the value
|
||||
is also > 4 and s< 8, since the bounds prevent crossing the sign boundary.
|
||||
|
||||
PTR_TO_PACKETs with a variable offset part have an 'id', which is common to all
|
||||
pointers sharing that same variable offset. This is important for packet range
|
||||
checks: after adding some variable to a packet pointer, if you then copy it to
|
||||
another register and (say) add a constant 4, both registers will share the same
|
||||
'id' but one will have a fixed offset of +4. Then if it is bounds-checked and
|
||||
found to be less than a PTR_TO_PACKET_END, the other register is now known to
|
||||
have a safe range of at least 4 bytes. See 'Direct packet access', below, for
|
||||
more on PTR_TO_PACKET ranges.
|
||||
checks: after adding a variable to a packet pointer register A, if you then copy
|
||||
it to another register B and then add a constant 4 to A, both registers will
|
||||
share the same 'id' but the A will have a fixed offset of +4. Then if A is
|
||||
bounds-checked and found to be less than a PTR_TO_PACKET_END, the register B is
|
||||
now known to have a safe range of at least 4 bytes. See 'Direct packet access',
|
||||
below, for more on PTR_TO_PACKET ranges.
|
||||
|
||||
The 'id' field is also used on PTR_TO_MAP_VALUE_OR_NULL, common to all copies of
|
||||
the pointer returned from a map lookup. This means that when one copy is
|
||||
checked and found to be non-NULL, all copies can become PTR_TO_MAP_VALUEs.
|
||||
|
||||
@@ -234,18 +234,11 @@ static void jit_fill_hole(void *area, unsigned int size)
|
||||
#define SCRATCH_SIZE 80
|
||||
|
||||
/* total stack size used in JITed code */
|
||||
#define _STACK_SIZE \
|
||||
(ctx->prog->aux->stack_depth + \
|
||||
+ SCRATCH_SIZE + \
|
||||
+ 4 /* extra for skb_copy_bits buffer */)
|
||||
|
||||
#define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
|
||||
#define _STACK_SIZE (ctx->prog->aux->stack_depth + SCRATCH_SIZE)
|
||||
#define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT)
|
||||
|
||||
/* Get the offset of eBPF REGISTERs stored on scratch space. */
|
||||
#define STACK_VAR(off) (STACK_SIZE-off-4)
|
||||
|
||||
/* Offset of skb_copy_bits buffer */
|
||||
#define SKB_BUFFER STACK_VAR(SCRATCH_SIZE)
|
||||
#define STACK_VAR(off) (STACK_SIZE - off)
|
||||
|
||||
#if __LINUX_ARM_ARCH__ < 7
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
@@ -80,37 +79,6 @@ static inline void emit(const u32 insn, struct jit_ctx *ctx)
|
||||
ctx->idx++;
|
||||
}
|
||||
|
||||
static inline void emit_a64_mov_i64(const int reg, const u64 val,
|
||||
struct jit_ctx *ctx)
|
||||
{
|
||||
u64 tmp = val;
|
||||
int shift = 0;
|
||||
|
||||
emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
||||
tmp >>= 16;
|
||||
shift += 16;
|
||||
while (tmp) {
|
||||
if (tmp & 0xffff)
|
||||
emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
||||
tmp >>= 16;
|
||||
shift += 16;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
||||
struct jit_ctx *ctx)
|
||||
{
|
||||
u64 tmp = val;
|
||||
int shift = 0;
|
||||
|
||||
emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
||||
for (;shift < 48;) {
|
||||
tmp >>= 16;
|
||||
shift += 16;
|
||||
emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void emit_a64_mov_i(const int is64, const int reg,
|
||||
const s32 val, struct jit_ctx *ctx)
|
||||
{
|
||||
@@ -122,7 +90,8 @@ static inline void emit_a64_mov_i(const int is64, const int reg,
|
||||
emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
|
||||
} else {
|
||||
emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
|
||||
emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
||||
if (lo != 0xffff)
|
||||
emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
||||
}
|
||||
} else {
|
||||
emit(A64_MOVZ(is64, reg, lo, 0), ctx);
|
||||
@@ -131,6 +100,59 @@ static inline void emit_a64_mov_i(const int is64, const int reg,
|
||||
}
|
||||
}
|
||||
|
||||
static int i64_i16_blocks(const u64 val, bool inverse)
|
||||
{
|
||||
return (((val >> 0) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
||||
(((val >> 16) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
||||
(((val >> 32) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
||||
(((val >> 48) & 0xffff) != (inverse ? 0xffff : 0x0000));
|
||||
}
|
||||
|
||||
static inline void emit_a64_mov_i64(const int reg, const u64 val,
|
||||
struct jit_ctx *ctx)
|
||||
{
|
||||
u64 nrm_tmp = val, rev_tmp = ~val;
|
||||
bool inverse;
|
||||
int shift;
|
||||
|
||||
if (!(nrm_tmp >> 32))
|
||||
return emit_a64_mov_i(0, reg, (u32)val, ctx);
|
||||
|
||||
inverse = i64_i16_blocks(nrm_tmp, true) < i64_i16_blocks(nrm_tmp, false);
|
||||
shift = max(round_down((inverse ? (fls64(rev_tmp) - 1) :
|
||||
(fls64(nrm_tmp) - 1)), 16), 0);
|
||||
if (inverse)
|
||||
emit(A64_MOVN(1, reg, (rev_tmp >> shift) & 0xffff, shift), ctx);
|
||||
else
|
||||
emit(A64_MOVZ(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
||||
shift -= 16;
|
||||
while (shift >= 0) {
|
||||
if (((nrm_tmp >> shift) & 0xffff) != (inverse ? 0xffff : 0x0000))
|
||||
emit(A64_MOVK(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
||||
shift -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an unoptimized 64 immediate emission used for BPF to BPF call
|
||||
* addresses. It will always do a full 64 bit decomposition as otherwise
|
||||
* more complexity in the last extra pass is required since we previously
|
||||
* reserved 4 instructions for the address.
|
||||
*/
|
||||
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
||||
struct jit_ctx *ctx)
|
||||
{
|
||||
u64 tmp = val;
|
||||
int shift = 0;
|
||||
|
||||
emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
||||
for (;shift < 48;) {
|
||||
tmp >>= 16;
|
||||
shift += 16;
|
||||
emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int bpf2a64_offset(int bpf_to, int bpf_from,
|
||||
const struct jit_ctx *ctx)
|
||||
{
|
||||
@@ -163,7 +185,7 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
||||
/* Tail call offset to jump into */
|
||||
#define PROLOGUE_OFFSET 7
|
||||
|
||||
static int build_prologue(struct jit_ctx *ctx)
|
||||
static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
|
||||
{
|
||||
const struct bpf_prog *prog = ctx->prog;
|
||||
const u8 r6 = bpf2a64[BPF_REG_6];
|
||||
@@ -188,7 +210,7 @@ static int build_prologue(struct jit_ctx *ctx)
|
||||
* | ... | BPF prog stack
|
||||
* | |
|
||||
* +-----+ <= (BPF_FP - prog->aux->stack_depth)
|
||||
* |RSVD | JIT scratchpad
|
||||
* |RSVD | padding
|
||||
* current A64_SP => +-----+ <= (BPF_FP - ctx->stack_size)
|
||||
* | |
|
||||
* | ... | Function call stack
|
||||
@@ -210,19 +232,19 @@ static int build_prologue(struct jit_ctx *ctx)
|
||||
/* Set up BPF prog stack base register */
|
||||
emit(A64_MOV(1, fp, A64_SP), ctx);
|
||||
|
||||
/* Initialize tail_call_cnt */
|
||||
emit(A64_MOVZ(1, tcc, 0, 0), ctx);
|
||||
if (!ebpf_from_cbpf) {
|
||||
/* Initialize tail_call_cnt */
|
||||
emit(A64_MOVZ(1, tcc, 0, 0), ctx);
|
||||
|
||||
cur_offset = ctx->idx - idx0;
|
||||
if (cur_offset != PROLOGUE_OFFSET) {
|
||||
pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
|
||||
cur_offset, PROLOGUE_OFFSET);
|
||||
return -1;
|
||||
cur_offset = ctx->idx - idx0;
|
||||
if (cur_offset != PROLOGUE_OFFSET) {
|
||||
pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
|
||||
cur_offset, PROLOGUE_OFFSET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4 byte extra for skb_copy_bits buffer */
|
||||
ctx->stack_size = prog->aux->stack_depth + 4;
|
||||
ctx->stack_size = STACK_ALIGN(ctx->stack_size);
|
||||
ctx->stack_size = STACK_ALIGN(prog->aux->stack_depth);
|
||||
|
||||
/* Set up function call stack */
|
||||
emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
|
||||
@@ -786,6 +808,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct bpf_binary_header *header;
|
||||
struct arm64_jit_data *jit_data;
|
||||
bool was_classic = bpf_prog_was_classic(prog);
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
struct jit_ctx ctx;
|
||||
@@ -840,7 +863,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
if (build_prologue(&ctx)) {
|
||||
if (build_prologue(&ctx, was_classic)) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
@@ -863,7 +886,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
skip_init_ctx:
|
||||
ctx.idx = 0;
|
||||
|
||||
build_prologue(&ctx);
|
||||
build_prologue(&ctx, was_classic);
|
||||
|
||||
if (build_body(&ctx)) {
|
||||
bpf_jit_binary_free(header);
|
||||
|
||||
@@ -95,7 +95,6 @@ enum reg_val_type {
|
||||
* struct jit_ctx - JIT context
|
||||
* @skf: The sk_filter
|
||||
* @stack_size: eBPF stack size
|
||||
* @tmp_offset: eBPF $sp offset to 8-byte temporary memory
|
||||
* @idx: Instruction index
|
||||
* @flags: JIT flags
|
||||
* @offsets: Instruction offsets
|
||||
@@ -105,7 +104,6 @@ enum reg_val_type {
|
||||
struct jit_ctx {
|
||||
const struct bpf_prog *skf;
|
||||
int stack_size;
|
||||
int tmp_offset;
|
||||
u32 idx;
|
||||
u32 flags;
|
||||
u32 *offsets;
|
||||
@@ -293,7 +291,6 @@ static int gen_int_prologue(struct jit_ctx *ctx)
|
||||
locals_size = (ctx->flags & EBPF_SEEN_FP) ? MAX_BPF_STACK : 0;
|
||||
|
||||
stack_adjust += locals_size;
|
||||
ctx->tmp_offset = locals_size;
|
||||
|
||||
ctx->stack_size = stack_adjust;
|
||||
|
||||
@@ -399,7 +396,6 @@ static void gen_imm_to_reg(const struct bpf_insn *insn, int reg,
|
||||
emit_instr(ctx, lui, reg, upper >> 16);
|
||||
emit_instr(ctx, addiu, reg, reg, lower);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int gen_imm_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
||||
@@ -547,28 +543,6 @@ static int gen_imm_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void * __must_check
|
||||
ool_skb_header_pointer(const struct sk_buff *skb, int offset,
|
||||
int len, void *buffer)
|
||||
{
|
||||
return skb_header_pointer(skb, offset, len, buffer);
|
||||
}
|
||||
|
||||
static int size_to_len(const struct bpf_insn *insn)
|
||||
{
|
||||
switch (BPF_SIZE(insn->code)) {
|
||||
case BPF_B:
|
||||
return 1;
|
||||
case BPF_H:
|
||||
return 2;
|
||||
case BPF_W:
|
||||
return 4;
|
||||
case BPF_DW:
|
||||
return 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emit_const_to_reg(struct jit_ctx *ctx, int dst, u64 value)
|
||||
{
|
||||
if (value >= 0xffffffffffff8000ull || value < 0x8000ull) {
|
||||
|
||||
@@ -894,7 +894,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
const int i = insn - ctx->prog->insnsi;
|
||||
const s16 off = insn->off;
|
||||
const s32 imm = insn->imm;
|
||||
u32 *func;
|
||||
|
||||
if (insn->src_reg == BPF_REG_FP)
|
||||
ctx->saw_frame_pointer = true;
|
||||
|
||||
@@ -301,9 +301,9 @@ do { \
|
||||
* jmp *%edx for x86_32
|
||||
*/
|
||||
#ifdef CONFIG_RETPOLINE
|
||||
#ifdef CONFIG_X86_64
|
||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 17
|
||||
# define RETPOLINE_RAX_BPF_JIT() \
|
||||
# ifdef CONFIG_X86_64
|
||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 17
|
||||
# define RETPOLINE_RAX_BPF_JIT() \
|
||||
do { \
|
||||
EMIT1_off32(0xE8, 7); /* callq do_rop */ \
|
||||
/* spec_trap: */ \
|
||||
@@ -314,8 +314,8 @@ do { \
|
||||
EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \
|
||||
EMIT1(0xC3); /* retq */ \
|
||||
} while (0)
|
||||
#else
|
||||
# define RETPOLINE_EDX_BPF_JIT() \
|
||||
# else /* !CONFIG_X86_64 */
|
||||
# define RETPOLINE_EDX_BPF_JIT() \
|
||||
do { \
|
||||
EMIT1_off32(0xE8, 7); /* call do_rop */ \
|
||||
/* spec_trap: */ \
|
||||
@@ -326,17 +326,16 @@ do { \
|
||||
EMIT3(0x89, 0x14, 0x24); /* mov %edx,(%esp) */ \
|
||||
EMIT1(0xC3); /* ret */ \
|
||||
} while (0)
|
||||
#endif
|
||||
# endif
|
||||
#else /* !CONFIG_RETPOLINE */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 2
|
||||
# define RETPOLINE_RAX_BPF_JIT() \
|
||||
EMIT2(0xFF, 0xE0); /* jmp *%rax */
|
||||
#else
|
||||
# define RETPOLINE_EDX_BPF_JIT() \
|
||||
EMIT2(0xFF, 0xE2) /* jmp *%edx */
|
||||
#endif
|
||||
# ifdef CONFIG_X86_64
|
||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 2
|
||||
# define RETPOLINE_RAX_BPF_JIT() \
|
||||
EMIT2(0xFF, 0xE0); /* jmp *%rax */
|
||||
# else /* !CONFIG_X86_64 */
|
||||
# define RETPOLINE_EDX_BPF_JIT() \
|
||||
EMIT2(0xFF, 0xE2) /* jmp *%edx */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
|
||||
|
||||
@@ -50,6 +50,7 @@ enum bpf_cap_tlv_type {
|
||||
NFP_BPF_CAP_TYPE_ADJUST_HEAD = 2,
|
||||
NFP_BPF_CAP_TYPE_MAPS = 3,
|
||||
NFP_BPF_CAP_TYPE_RANDOM = 4,
|
||||
NFP_BPF_CAP_TYPE_QUEUE_SELECT = 5,
|
||||
};
|
||||
|
||||
struct nfp_bpf_cap_tlv_func {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include "../nfp_asm.h"
|
||||
#include "../nfp_net_ctrl.h"
|
||||
|
||||
/* --- NFP prog --- */
|
||||
/* Foreach "multiple" entries macros provide pos and next<n> pointers.
|
||||
@@ -1470,6 +1471,38 @@ nfp_perf_event_output(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_queue_select(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
u32 jmp_tgt;
|
||||
|
||||
jmp_tgt = nfp_prog_current_offset(nfp_prog) + 5;
|
||||
|
||||
/* Make sure the queue id fits into FW field */
|
||||
emit_alu(nfp_prog, reg_none(), reg_a(meta->insn.src_reg * 2),
|
||||
ALU_OP_AND_NOT_B, reg_imm(0xff));
|
||||
emit_br(nfp_prog, BR_BEQ, jmp_tgt, 2);
|
||||
|
||||
/* Set the 'queue selected' bit and the queue value */
|
||||
emit_shf(nfp_prog, pv_qsel_set(nfp_prog),
|
||||
pv_qsel_set(nfp_prog), SHF_OP_OR, reg_imm(1),
|
||||
SHF_SC_L_SHF, PKT_VEL_QSEL_SET_BIT);
|
||||
emit_ld_field(nfp_prog,
|
||||
pv_qsel_val(nfp_prog), 0x1, reg_b(meta->insn.src_reg * 2),
|
||||
SHF_SC_NONE, 0);
|
||||
/* Delay slots end here, we will jump over next instruction if queue
|
||||
* value fits into the field.
|
||||
*/
|
||||
emit_ld_field(nfp_prog,
|
||||
pv_qsel_val(nfp_prog), 0x1, reg_imm(NFP_NET_RXR_MAX),
|
||||
SHF_SC_NONE, 0);
|
||||
|
||||
if (!nfp_prog_confirm_current_offset(nfp_prog, jmp_tgt))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- Callbacks --- */
|
||||
static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
@@ -2160,6 +2193,17 @@ mem_stx_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
false, wrp_lmem_store);
|
||||
}
|
||||
|
||||
static int mem_stx_xdp(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
switch (meta->insn.off) {
|
||||
case offsetof(struct xdp_md, rx_queue_index):
|
||||
return nfp_queue_select(nfp_prog, meta);
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(1); /* verifier should have rejected bad accesses */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mem_stx(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
unsigned int size)
|
||||
@@ -2186,6 +2230,9 @@ static int mem_stx2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
|
||||
static int mem_stx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
|
||||
{
|
||||
if (meta->ptr.type == PTR_TO_CTX)
|
||||
if (nfp_prog->type == BPF_PROG_TYPE_XDP)
|
||||
return mem_stx_xdp(nfp_prog, meta);
|
||||
return mem_stx(nfp_prog, meta, 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -334,6 +334,13 @@ nfp_bpf_parse_cap_random(struct nfp_app_bpf *bpf, void __iomem *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_bpf_parse_cap_qsel(struct nfp_app_bpf *bpf, void __iomem *value, u32 length)
|
||||
{
|
||||
bpf->queue_select = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfp_bpf_parse_capabilities(struct nfp_app *app)
|
||||
{
|
||||
struct nfp_cpp *cpp = app->pf->cpp;
|
||||
@@ -376,6 +383,10 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app)
|
||||
if (nfp_bpf_parse_cap_random(app->priv, value, length))
|
||||
goto err_release_free;
|
||||
break;
|
||||
case NFP_BPF_CAP_TYPE_QUEUE_SELECT:
|
||||
if (nfp_bpf_parse_cap_qsel(app->priv, value, length))
|
||||
goto err_release_free;
|
||||
break;
|
||||
default:
|
||||
nfp_dbg(cpp, "unknown BPF capability: %d\n", type);
|
||||
break;
|
||||
|
||||
@@ -82,10 +82,16 @@ enum static_regs {
|
||||
enum pkt_vec {
|
||||
PKT_VEC_PKT_LEN = 0,
|
||||
PKT_VEC_PKT_PTR = 2,
|
||||
PKT_VEC_QSEL_SET = 4,
|
||||
PKT_VEC_QSEL_VAL = 6,
|
||||
};
|
||||
|
||||
#define PKT_VEL_QSEL_SET_BIT 4
|
||||
|
||||
#define pv_len(np) reg_lm(1, PKT_VEC_PKT_LEN)
|
||||
#define pv_ctm_ptr(np) reg_lm(1, PKT_VEC_PKT_PTR)
|
||||
#define pv_qsel_set(np) reg_lm(1, PKT_VEC_QSEL_SET)
|
||||
#define pv_qsel_val(np) reg_lm(1, PKT_VEC_QSEL_VAL)
|
||||
|
||||
#define stack_reg(np) reg_a(STATIC_REG_STACK)
|
||||
#define stack_imm(np) imm_b(np)
|
||||
@@ -139,6 +145,7 @@ enum pkt_vec {
|
||||
* @helpers.perf_event_output: output perf event to a ring buffer
|
||||
*
|
||||
* @pseudo_random: FW initialized the pseudo-random machinery (CSRs)
|
||||
* @queue_select: BPF can set the RX queue ID in packet vector
|
||||
*/
|
||||
struct nfp_app_bpf {
|
||||
struct nfp_app *app;
|
||||
@@ -181,6 +188,7 @@ struct nfp_app_bpf {
|
||||
} helpers;
|
||||
|
||||
bool pseudo_random;
|
||||
bool queue_select;
|
||||
};
|
||||
|
||||
enum nfp_bpf_map_use {
|
||||
|
||||
@@ -467,6 +467,30 @@ nfp_bpf_check_ptr(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_bpf_check_store(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
struct bpf_verifier_env *env)
|
||||
{
|
||||
const struct bpf_reg_state *reg = cur_regs(env) + meta->insn.dst_reg;
|
||||
|
||||
if (reg->type == PTR_TO_CTX) {
|
||||
if (nfp_prog->type == BPF_PROG_TYPE_XDP) {
|
||||
/* XDP ctx accesses must be 4B in size */
|
||||
switch (meta->insn.off) {
|
||||
case offsetof(struct xdp_md, rx_queue_index):
|
||||
if (nfp_prog->bpf->queue_select)
|
||||
goto exit_check_ptr;
|
||||
pr_vlog(env, "queue selection not supported by FW\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
pr_vlog(env, "unsupported store to context field\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
exit_check_ptr:
|
||||
return nfp_bpf_check_ptr(nfp_prog, meta, env, meta->insn.dst_reg);
|
||||
}
|
||||
|
||||
static int
|
||||
nfp_bpf_check_xadd(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
|
||||
struct bpf_verifier_env *env)
|
||||
@@ -522,8 +546,8 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx)
|
||||
return nfp_bpf_check_ptr(nfp_prog, meta, env,
|
||||
meta->insn.src_reg);
|
||||
if (is_mbpf_store(meta))
|
||||
return nfp_bpf_check_ptr(nfp_prog, meta, env,
|
||||
meta->insn.dst_reg);
|
||||
return nfp_bpf_check_store(nfp_prog, meta, env);
|
||||
|
||||
if (is_mbpf_xadd(meta))
|
||||
return nfp_bpf_check_xadd(nfp_prog, meta, env);
|
||||
|
||||
|
||||
@@ -183,16 +183,18 @@ enum shf_sc {
|
||||
#define OP_ALU_DST_LMEXTN 0x80000000000ULL
|
||||
|
||||
enum alu_op {
|
||||
ALU_OP_NONE = 0x00,
|
||||
ALU_OP_ADD = 0x01,
|
||||
ALU_OP_NOT = 0x04,
|
||||
ALU_OP_ADD_2B = 0x05,
|
||||
ALU_OP_AND = 0x08,
|
||||
ALU_OP_SUB_C = 0x0d,
|
||||
ALU_OP_ADD_C = 0x11,
|
||||
ALU_OP_OR = 0x14,
|
||||
ALU_OP_SUB = 0x15,
|
||||
ALU_OP_XOR = 0x18,
|
||||
ALU_OP_NONE = 0x00,
|
||||
ALU_OP_ADD = 0x01,
|
||||
ALU_OP_NOT = 0x04,
|
||||
ALU_OP_ADD_2B = 0x05,
|
||||
ALU_OP_AND = 0x08,
|
||||
ALU_OP_AND_NOT_A = 0x0c,
|
||||
ALU_OP_SUB_C = 0x0d,
|
||||
ALU_OP_AND_NOT_B = 0x10,
|
||||
ALU_OP_ADD_C = 0x11,
|
||||
ALU_OP_OR = 0x14,
|
||||
ALU_OP_SUB = 0x15,
|
||||
ALU_OP_XOR = 0x18,
|
||||
};
|
||||
|
||||
enum alu_dst_ab {
|
||||
|
||||
+9
-1
@@ -627,7 +627,7 @@ bool bpf_offload_dev_match(struct bpf_prog *prog, struct bpf_map *map);
|
||||
#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
|
||||
int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
|
||||
|
||||
static inline bool bpf_prog_is_dev_bound(struct bpf_prog_aux *aux)
|
||||
static inline bool bpf_prog_is_dev_bound(const struct bpf_prog_aux *aux)
|
||||
{
|
||||
return aux->offload_requested;
|
||||
}
|
||||
@@ -668,6 +668,7 @@ static inline void bpf_map_offload_map_free(struct bpf_map *map)
|
||||
|
||||
#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_INET)
|
||||
struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
|
||||
struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key);
|
||||
int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
|
||||
#else
|
||||
static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
|
||||
@@ -675,6 +676,12 @@ static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct sock *__sock_hash_lookup_elem(struct bpf_map *map,
|
||||
void *key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int sock_map_prog(struct bpf_map *map,
|
||||
struct bpf_prog *prog,
|
||||
u32 type)
|
||||
@@ -724,6 +731,7 @@ extern const struct bpf_func_proto bpf_get_current_comm_proto;
|
||||
extern const struct bpf_func_proto bpf_get_stackid_proto;
|
||||
extern const struct bpf_func_proto bpf_get_stack_proto;
|
||||
extern const struct bpf_func_proto bpf_sock_map_update_proto;
|
||||
extern const struct bpf_func_proto bpf_sock_hash_update_proto;
|
||||
|
||||
/* Shared helpers among cBPF and eBPF. */
|
||||
void bpf_user_rnd_init_once(void);
|
||||
|
||||
@@ -47,6 +47,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
|
||||
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
|
||||
#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_INET)
|
||||
BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKMAP, sock_map_ops)
|
||||
BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKHASH, sock_hash_ops)
|
||||
#endif
|
||||
BPF_MAP_TYPE(BPF_MAP_TYPE_CPUMAP, cpu_map_ops)
|
||||
#if defined(CONFIG_XDP_SOCKETS)
|
||||
|
||||
@@ -200,8 +200,8 @@ struct bpf_verifier_env {
|
||||
u32 subprog_cnt;
|
||||
};
|
||||
|
||||
void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt,
|
||||
va_list args);
|
||||
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,
|
||||
const char *fmt, va_list args);
|
||||
__printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env,
|
||||
const char *fmt, ...);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user