mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-24 18:29:06 +08:00
Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a26b51b1c | ||
|
|
2cc0829775 | ||
|
|
92cb475558 | ||
|
|
8b2782a1f2 | ||
|
|
886e8149a0 | ||
|
|
d275397111 | ||
|
|
ede18f80d8 | ||
|
|
07cd489681 | ||
|
|
d2f307c7f6 | ||
|
|
990cef2a0c | ||
|
|
4c2c521513 | ||
|
|
b1e911e9ba | ||
|
|
ae673dc91f | ||
|
|
5a256d12bf | ||
|
|
ae8edc7624 | ||
|
|
8f8b4a14fa | ||
|
|
476e158b07 | ||
|
|
13e1ee420e | ||
|
|
3e2bab6d2c | ||
|
|
9084f4cd4d | ||
|
|
66d20edaf0 | ||
|
|
d8d6772ab8 | ||
|
|
4397d09cd8 | ||
|
|
5771dacd3d | ||
|
|
d34efeeef1 | ||
|
|
db63a5aa5d | ||
|
|
d60f568961 | ||
|
|
e78a36f4b0 | ||
|
|
c8a7eb06bd | ||
|
|
b48c14807b | ||
|
|
a3b4055ec7 | ||
|
|
30603852f4 | ||
|
|
1a28fa5dac | ||
|
|
def5576b37 | ||
|
|
3e45a16621 | ||
|
|
2c0e53cb08 | ||
|
|
6227c6f8dd | ||
|
|
00ad180d07 | ||
|
|
715a58d593 | ||
|
|
11052fc1be | ||
|
|
97ecda3b25 | ||
|
|
342bcfa319 | ||
|
|
c020432531 | ||
|
|
99ce275b52 | ||
|
|
c0a5f7ee11 | ||
|
|
0da9ba439f | ||
|
|
c4735d9e05 | ||
|
|
563f1d3fff | ||
|
|
c5d4295fc5 | ||
|
|
b606dc725e | ||
|
|
f615047aa0 | ||
|
|
84a508a51f | ||
|
|
c59016e100 | ||
|
|
509ef92905 | ||
|
|
2c9394f2a3 | ||
|
|
0f4d83f3ab | ||
|
|
6a7b28b6a1 | ||
|
|
d76d264ac0 | ||
|
|
63a3bdf23a | ||
|
|
12fa15e89a | ||
|
|
b987dcfecb | ||
|
|
9c1ab4d070 | ||
|
|
550aa56dd4 | ||
|
|
54facd3fce | ||
|
|
1346b5b538 | ||
|
|
78d3666065 | ||
|
|
ce2eb85588 | ||
|
|
6d4104b077 | ||
|
|
43c14e871c | ||
|
|
e61f4b8269 | ||
|
|
80a0eca14b | ||
|
|
5a8c675d0a | ||
|
|
45ad862601 | ||
|
|
5e4da17d43 | ||
|
|
2d8ab5cf2c | ||
|
|
fe1ce6bd74 | ||
|
|
9007494e6c | ||
|
|
8b82b9c82b | ||
|
|
9a361d2fdd | ||
|
|
01272d3040 | ||
|
|
0a216f37f8 | ||
|
|
04f987a89a | ||
|
|
86171433b7 | ||
|
|
3e8f8914cb | ||
|
|
960ec9ace6 | ||
|
|
0cc3d9d332 | ||
|
|
50a63f31b6 | ||
|
|
32a605a9a6 | ||
|
|
5efb454851 | ||
|
|
e0ee1593fd | ||
|
|
421ecf02c8 | ||
|
|
38b91c640f | ||
|
|
f925686015 | ||
|
|
be0f832d40 | ||
|
|
f29b6fd1da | ||
|
|
1ed7b6ade1 | ||
|
|
ec13b30349 | ||
|
|
e64e62d19f | ||
|
|
115c0e02cb | ||
|
|
67057c6b7d | ||
|
|
bdf65f9fea | ||
|
|
0559e41969 | ||
|
|
abc096b71d | ||
|
|
7586f784e6 | ||
|
|
76ff616fcd | ||
|
|
04a05786c3 | ||
|
|
ddba4024c0 | ||
|
|
52ec16bce8 | ||
|
|
a4e4dbc35a | ||
|
|
21742bc952 | ||
|
|
39de671179 | ||
|
|
49967c1f5a | ||
|
|
4f260bccf5 | ||
|
|
80aeaa33e7 | ||
|
|
fcbc2604c8 | ||
|
|
896c231d8c | ||
|
|
e13049a667 | ||
|
|
8e01ffc179 | ||
|
|
c7b8b2e3a5 | ||
|
|
e977af8516 | ||
|
|
dd55058989 | ||
|
|
64852b2fb9 | ||
|
|
1aedc35d5d | ||
|
|
d5013de6a5 | ||
|
|
0e37e0d03a | ||
|
|
75db50f4a0 | ||
|
|
d714245dd9 | ||
|
|
1d0ddcdbda | ||
|
|
edf3123942 | ||
|
|
1f8e2f7208 | ||
|
|
ca76b123f1 | ||
|
|
4fe8a54efe | ||
|
|
5f3f74892a | ||
|
|
553db8ba73 | ||
|
|
939da1eb3f | ||
|
|
d557b32f71 | ||
|
|
e60460f4e5 |
1
BPF-CHECKPOINT-COMMIT
Normal file
1
BPF-CHECKPOINT-COMMIT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1bd63524593b964934a33afd442df16b8f90e2b5
|
||||||
@@ -1 +1 @@
|
|||||||
f49aa1de98363b6c5fba4637678d6b0ba3d18065
|
02dc96ef6c25f990452c114c59d75c368a1f4c8f
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -47,24 +47,3 @@ headers in a build directory /build/root/:
|
|||||||
$ cd src
|
$ cd src
|
||||||
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
||||||
```
|
```
|
||||||
|
|
||||||
To integrate libbpf into a project which uses Meson building system define
|
|
||||||
`[wrap-git]` file in `subprojects` folder.
|
|
||||||
To add libbpf dependency to the parent parent project, e.g. for
|
|
||||||
libbpf_static_dep:
|
|
||||||
```
|
|
||||||
libbpf_obj = subproject('libbpf', required : true)
|
|
||||||
libbpf_static_dep = libbpf_proj.get_variable('libbpf_static_dep')
|
|
||||||
```
|
|
||||||
|
|
||||||
To validate changes to meson.build
|
|
||||||
```bash
|
|
||||||
$ python3 meson.py build
|
|
||||||
$ ninja -C build/
|
|
||||||
```
|
|
||||||
|
|
||||||
To install headers, libs and pkgconfig
|
|
||||||
```bash
|
|
||||||
$ cd build
|
|
||||||
$ ninja install
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -30,4 +30,9 @@ static inline bool IS_ERR_OR_NULL(const void *ptr)
|
|||||||
return (!ptr) || IS_ERR_VALUE((unsigned long)ptr);
|
return (!ptr) || IS_ERR_VALUE((unsigned long)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline long PTR_ERR_OR_ZERO(const void *ptr)
|
||||||
|
{
|
||||||
|
return IS_ERR(ptr) ? PTR_ERR(ptr) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
MAP_FD, 0)
|
MAP_FD, 0)
|
||||||
|
|
||||||
#define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
|
#define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
|
||||||
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_FD, 0, 0, \
|
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_VALUE, 0, 0, \
|
||||||
MAP_FD, VALUE_OFF)
|
MAP_FD, VALUE_OFF)
|
||||||
|
|
||||||
#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
|
#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ enum bpf_cmd {
|
|||||||
BPF_TASK_FD_QUERY,
|
BPF_TASK_FD_QUERY,
|
||||||
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
||||||
BPF_MAP_FREEZE,
|
BPF_MAP_FREEZE,
|
||||||
|
BPF_BTF_GET_NEXT_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_map_type {
|
enum bpf_map_type {
|
||||||
@@ -134,6 +135,7 @@ enum bpf_map_type {
|
|||||||
BPF_MAP_TYPE_QUEUE,
|
BPF_MAP_TYPE_QUEUE,
|
||||||
BPF_MAP_TYPE_STACK,
|
BPF_MAP_TYPE_STACK,
|
||||||
BPF_MAP_TYPE_SK_STORAGE,
|
BPF_MAP_TYPE_SK_STORAGE,
|
||||||
|
BPF_MAP_TYPE_DEVMAP_HASH,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Note that tracing related programs such as
|
/* Note that tracing related programs such as
|
||||||
@@ -170,6 +172,7 @@ enum bpf_prog_type {
|
|||||||
BPF_PROG_TYPE_FLOW_DISSECTOR,
|
BPF_PROG_TYPE_FLOW_DISSECTOR,
|
||||||
BPF_PROG_TYPE_CGROUP_SYSCTL,
|
BPF_PROG_TYPE_CGROUP_SYSCTL,
|
||||||
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
|
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
|
||||||
|
BPF_PROG_TYPE_CGROUP_SOCKOPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_attach_type {
|
enum bpf_attach_type {
|
||||||
@@ -192,6 +195,10 @@ enum bpf_attach_type {
|
|||||||
BPF_LIRC_MODE2,
|
BPF_LIRC_MODE2,
|
||||||
BPF_FLOW_DISSECTOR,
|
BPF_FLOW_DISSECTOR,
|
||||||
BPF_CGROUP_SYSCTL,
|
BPF_CGROUP_SYSCTL,
|
||||||
|
BPF_CGROUP_UDP4_RECVMSG,
|
||||||
|
BPF_CGROUP_UDP6_RECVMSG,
|
||||||
|
BPF_CGROUP_GETSOCKOPT,
|
||||||
|
BPF_CGROUP_SETSOCKOPT,
|
||||||
__MAX_BPF_ATTACH_TYPE
|
__MAX_BPF_ATTACH_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,6 +267,27 @@ enum bpf_attach_type {
|
|||||||
*/
|
*/
|
||||||
#define BPF_F_ANY_ALIGNMENT (1U << 1)
|
#define BPF_F_ANY_ALIGNMENT (1U << 1)
|
||||||
|
|
||||||
|
/* BPF_F_TEST_RND_HI32 is used in BPF_PROG_LOAD command for testing purpose.
|
||||||
|
* Verifier does sub-register def/use analysis and identifies instructions whose
|
||||||
|
* def only matters for low 32-bit, high 32-bit is never referenced later
|
||||||
|
* through implicit zero extension. Therefore verifier notifies JIT back-ends
|
||||||
|
* that it is safe to ignore clearing high 32-bit for these instructions. This
|
||||||
|
* saves some back-ends a lot of code-gen. However such optimization is not
|
||||||
|
* necessary on some arches, for example x86_64, arm64 etc, whose JIT back-ends
|
||||||
|
* hence hasn't used verifier's analysis result. But, we really want to have a
|
||||||
|
* way to be able to verify the correctness of the described optimization on
|
||||||
|
* x86_64 on which testsuites are frequently exercised.
|
||||||
|
*
|
||||||
|
* So, this flag is introduced. Once it is set, verifier will randomize high
|
||||||
|
* 32-bit for those instructions who has been identified as safe to ignore them.
|
||||||
|
* Then, if verifier is not doing correct analysis, such randomization will
|
||||||
|
* regress tests to expose bugs.
|
||||||
|
*/
|
||||||
|
#define BPF_F_TEST_RND_HI32 (1U << 2)
|
||||||
|
|
||||||
|
/* The verifier internal test flag. Behavior is undefined */
|
||||||
|
#define BPF_F_TEST_STATE_FREQ (1U << 3)
|
||||||
|
|
||||||
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
||||||
* two extensions:
|
* two extensions:
|
||||||
*
|
*
|
||||||
@@ -313,6 +341,9 @@ enum bpf_attach_type {
|
|||||||
#define BPF_F_RDONLY_PROG (1U << 7)
|
#define BPF_F_RDONLY_PROG (1U << 7)
|
||||||
#define BPF_F_WRONLY_PROG (1U << 8)
|
#define BPF_F_WRONLY_PROG (1U << 8)
|
||||||
|
|
||||||
|
/* Clone map from listener for newly accepted socket */
|
||||||
|
#define BPF_F_CLONE (1U << 9)
|
||||||
|
|
||||||
/* flags for BPF_PROG_QUERY */
|
/* flags for BPF_PROG_QUERY */
|
||||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||||
|
|
||||||
@@ -552,6 +583,8 @@ union bpf_attr {
|
|||||||
* limited to five).
|
* limited to five).
|
||||||
*
|
*
|
||||||
* Each time the helper is called, it appends a line to the trace.
|
* Each time the helper is called, it appends a line to the trace.
|
||||||
|
* Lines are discarded while *\/sys/kernel/debug/tracing/trace* is
|
||||||
|
* open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this.
|
||||||
* The format of the trace is customizable, and the exact output
|
* The format of the trace is customizable, and the exact output
|
||||||
* one will get depends on the options set in
|
* one will get depends on the options set in
|
||||||
* *\/sys/kernel/debug/tracing/trace_options* (see also the
|
* *\/sys/kernel/debug/tracing/trace_options* (see also the
|
||||||
@@ -783,7 +816,7 @@ union bpf_attr {
|
|||||||
* based on a user-provided identifier for all traffic coming from
|
* based on a user-provided identifier for all traffic coming from
|
||||||
* the tasks belonging to the related cgroup. See also the related
|
* the tasks belonging to the related cgroup. See also the related
|
||||||
* kernel documentation, available from the Linux sources in file
|
* kernel documentation, available from the Linux sources in file
|
||||||
* *Documentation/cgroup-v1/net_cls.txt*.
|
* *Documentation/admin-guide/cgroup-v1/net_cls.rst*.
|
||||||
*
|
*
|
||||||
* The Linux kernel has two versions for cgroups: there are
|
* The Linux kernel has two versions for cgroups: there are
|
||||||
* cgroups v1 and cgroups v2. Both are available to users, who can
|
* cgroups v1 and cgroups v2. Both are available to users, who can
|
||||||
@@ -990,7 +1023,7 @@ union bpf_attr {
|
|||||||
* The realm of the route for the packet associated to *skb*, or 0
|
* The realm of the route for the packet associated to *skb*, or 0
|
||||||
* if none was found.
|
* if none was found.
|
||||||
*
|
*
|
||||||
* int bpf_perf_event_output(struct pt_reg *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
* int bpf_perf_event_output(struct pt_regs *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
||||||
* Description
|
* Description
|
||||||
* Write raw *data* blob into a special BPF perf event held by
|
* Write raw *data* blob into a special BPF perf event held by
|
||||||
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
||||||
@@ -1052,7 +1085,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_get_stackid(struct pt_reg *ctx, struct bpf_map *map, u64 flags)
|
* int bpf_get_stackid(struct pt_regs *ctx, struct bpf_map *map, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Walk a user or a kernel stack and return its id. To achieve
|
* Walk a user or a kernel stack and return its id. To achieve
|
||||||
* this, the helper needs *ctx*, which is a pointer to the context
|
* this, the helper needs *ctx*, which is a pointer to the context
|
||||||
@@ -1443,8 +1476,8 @@ union bpf_attr {
|
|||||||
* If no cookie has been set yet, generate a new cookie. Once
|
* If no cookie has been set yet, generate a new cookie. Once
|
||||||
* generated, the socket cookie remains stable for the life of the
|
* generated, the socket cookie remains stable for the life of the
|
||||||
* socket. This helper can be useful for monitoring per socket
|
* socket. This helper can be useful for monitoring per socket
|
||||||
* networking traffic statistics as it provides a unique socket
|
* networking traffic statistics as it provides a global socket
|
||||||
* identifier per namespace.
|
* identifier that can be assumed unique.
|
||||||
* Return
|
* Return
|
||||||
* A 8-byte long non-decreasing number on success, or 0 if the
|
* A 8-byte long non-decreasing number on success, or 0 if the
|
||||||
* socket field is missing inside *skb*.
|
* socket field is missing inside *skb*.
|
||||||
@@ -1548,8 +1581,11 @@ union bpf_attr {
|
|||||||
* but this is only implemented for native XDP (with driver
|
* but this is only implemented for native XDP (with driver
|
||||||
* support) as of this writing).
|
* support) as of this writing).
|
||||||
*
|
*
|
||||||
* All values for *flags* are reserved for future usage, and must
|
* The lower two bits of *flags* are used as the return code if
|
||||||
* be left at zero.
|
* the map lookup fails. This is so that the return value can be
|
||||||
|
* one of the XDP program return codes up to XDP_TX, as chosen by
|
||||||
|
* the caller. Any higher bits in the *flags* argument must be
|
||||||
|
* unset.
|
||||||
*
|
*
|
||||||
* When used to redirect packets to net devices, this helper
|
* When used to redirect packets to net devices, this helper
|
||||||
* provides a high performance increase over **bpf_redirect**\ ().
|
* provides a high performance increase over **bpf_redirect**\ ().
|
||||||
@@ -1698,7 +1734,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_override_return(struct pt_reg *regs, u64 rc)
|
* int bpf_override_return(struct pt_regs *regs, u64 rc)
|
||||||
* Description
|
* Description
|
||||||
* Used for error injection, this helper uses kprobes to override
|
* Used for error injection, this helper uses kprobes to override
|
||||||
* the return value of the probed function, and to set it to *rc*.
|
* the return value of the probed function, and to set it to *rc*.
|
||||||
@@ -1744,6 +1780,7 @@ union bpf_attr {
|
|||||||
* * **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out)
|
* * **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out)
|
||||||
* * **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission)
|
* * **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission)
|
||||||
* * **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change)
|
* * **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change)
|
||||||
|
* * **BPF_SOCK_OPS_RTT_CB_FLAG** (every RTT)
|
||||||
*
|
*
|
||||||
* Therefore, this function can be used to clear a callback flag by
|
* Therefore, this function can be used to clear a callback flag by
|
||||||
* setting the appropriate bit to zero. e.g. to disable the RTO
|
* setting the appropriate bit to zero. e.g. to disable the RTO
|
||||||
@@ -2672,6 +2709,47 @@ union bpf_attr {
|
|||||||
* 0 on success.
|
* 0 on success.
|
||||||
*
|
*
|
||||||
* **-ENOENT** if the bpf-local-storage cannot be found.
|
* **-ENOENT** if the bpf-local-storage cannot be found.
|
||||||
|
*
|
||||||
|
* int bpf_send_signal(u32 sig)
|
||||||
|
* Description
|
||||||
|
* Send signal *sig* to the current task.
|
||||||
|
* Return
|
||||||
|
* 0 on success or successfully queued.
|
||||||
|
*
|
||||||
|
* **-EBUSY** if work queue under nmi is full.
|
||||||
|
*
|
||||||
|
* **-EINVAL** if *sig* is invalid.
|
||||||
|
*
|
||||||
|
* **-EPERM** if no permission to send the *sig*.
|
||||||
|
*
|
||||||
|
* **-EAGAIN** if bpf program can try again.
|
||||||
|
*
|
||||||
|
* s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
|
||||||
|
* Description
|
||||||
|
* Try to issue a SYN cookie for the packet with corresponding
|
||||||
|
* IP/TCP headers, *iph* and *th*, on the listening socket in *sk*.
|
||||||
|
*
|
||||||
|
* *iph* points to the start of the IPv4 or IPv6 header, while
|
||||||
|
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
|
||||||
|
* **sizeof**\ (**struct ip6hdr**).
|
||||||
|
*
|
||||||
|
* *th* points to the start of the TCP header, while *th_len*
|
||||||
|
* contains the length of the TCP header.
|
||||||
|
*
|
||||||
|
* Return
|
||||||
|
* On success, lower 32 bits hold the generated SYN cookie in
|
||||||
|
* followed by 16 bits which hold the MSS value for that cookie,
|
||||||
|
* and the top 16 bits are unused.
|
||||||
|
*
|
||||||
|
* On failure, the returned value is one of the following:
|
||||||
|
*
|
||||||
|
* **-EINVAL** SYN cookie cannot be issued due to error
|
||||||
|
*
|
||||||
|
* **-ENOENT** SYN cookie should not be issued (no SYN flood)
|
||||||
|
*
|
||||||
|
* **-EOPNOTSUPP** kernel configuration does not enable SYN cookies
|
||||||
|
*
|
||||||
|
* **-EPROTONOSUPPORT** IP packet version is not 4 or 6
|
||||||
*/
|
*/
|
||||||
#define __BPF_FUNC_MAPPER(FN) \
|
#define __BPF_FUNC_MAPPER(FN) \
|
||||||
FN(unspec), \
|
FN(unspec), \
|
||||||
@@ -2782,7 +2860,9 @@ union bpf_attr {
|
|||||||
FN(strtol), \
|
FN(strtol), \
|
||||||
FN(strtoul), \
|
FN(strtoul), \
|
||||||
FN(sk_storage_get), \
|
FN(sk_storage_get), \
|
||||||
FN(sk_storage_delete),
|
FN(sk_storage_delete), \
|
||||||
|
FN(send_signal), \
|
||||||
|
FN(tcp_gen_syncookie),
|
||||||
|
|
||||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||||
* function eBPF program intends to call
|
* function eBPF program intends to call
|
||||||
@@ -3031,6 +3111,12 @@ struct bpf_tcp_sock {
|
|||||||
* sum(delta(snd_una)), or how many bytes
|
* sum(delta(snd_una)), or how many bytes
|
||||||
* were acked.
|
* were acked.
|
||||||
*/
|
*/
|
||||||
|
__u32 dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups
|
||||||
|
* total number of DSACK blocks received
|
||||||
|
*/
|
||||||
|
__u32 delivered; /* Total data packets delivered incl. rexmits */
|
||||||
|
__u32 delivered_ce; /* Like the above but only ECE marked packets */
|
||||||
|
__u32 icsk_retransmits; /* Number of unrecovered [RTO] timeouts */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_sock_tuple {
|
struct bpf_sock_tuple {
|
||||||
@@ -3050,6 +3136,10 @@ struct bpf_sock_tuple {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_xdp_sock {
|
||||||
|
__u32 queue_id;
|
||||||
|
};
|
||||||
|
|
||||||
#define XDP_PACKET_HEADROOM 256
|
#define XDP_PACKET_HEADROOM 256
|
||||||
|
|
||||||
/* User return codes for XDP prog type.
|
/* User return codes for XDP prog type.
|
||||||
@@ -3141,6 +3231,7 @@ struct bpf_prog_info {
|
|||||||
char name[BPF_OBJ_NAME_LEN];
|
char name[BPF_OBJ_NAME_LEN];
|
||||||
__u32 ifindex;
|
__u32 ifindex;
|
||||||
__u32 gpl_compatible:1;
|
__u32 gpl_compatible:1;
|
||||||
|
__u32 :31; /* alignment pad */
|
||||||
__u64 netns_dev;
|
__u64 netns_dev;
|
||||||
__u64 netns_ino;
|
__u64 netns_ino;
|
||||||
__u32 nr_jited_ksyms;
|
__u32 nr_jited_ksyms;
|
||||||
@@ -3195,7 +3286,7 @@ struct bpf_sock_addr {
|
|||||||
__u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
|
__u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
|
||||||
* Stored in network byte order.
|
* Stored in network byte order.
|
||||||
*/
|
*/
|
||||||
__u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write.
|
__u32 user_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write.
|
||||||
* Stored in network byte order.
|
* Stored in network byte order.
|
||||||
*/
|
*/
|
||||||
__u32 user_port; /* Allows 4-byte read and write.
|
__u32 user_port; /* Allows 4-byte read and write.
|
||||||
@@ -3204,12 +3295,13 @@ struct bpf_sock_addr {
|
|||||||
__u32 family; /* Allows 4-byte read, but no write */
|
__u32 family; /* Allows 4-byte read, but no write */
|
||||||
__u32 type; /* Allows 4-byte read, but no write */
|
__u32 type; /* Allows 4-byte read, but no write */
|
||||||
__u32 protocol; /* Allows 4-byte read, but no write */
|
__u32 protocol; /* Allows 4-byte read, but no write */
|
||||||
__u32 msg_src_ip4; /* Allows 1,2,4-byte read an 4-byte write.
|
__u32 msg_src_ip4; /* Allows 1,2,4-byte read and 4-byte write.
|
||||||
* Stored in network byte order.
|
* Stored in network byte order.
|
||||||
*/
|
*/
|
||||||
__u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write.
|
__u32 msg_src_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write.
|
||||||
* Stored in network byte order.
|
* Stored in network byte order.
|
||||||
*/
|
*/
|
||||||
|
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* User bpf_sock_ops struct to access socket values and specify request ops
|
/* User bpf_sock_ops struct to access socket values and specify request ops
|
||||||
@@ -3261,13 +3353,15 @@ struct bpf_sock_ops {
|
|||||||
__u32 sk_txhash;
|
__u32 sk_txhash;
|
||||||
__u64 bytes_received;
|
__u64 bytes_received;
|
||||||
__u64 bytes_acked;
|
__u64 bytes_acked;
|
||||||
|
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Definitions for bpf_sock_ops_cb_flags */
|
/* Definitions for bpf_sock_ops_cb_flags */
|
||||||
#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0)
|
#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0)
|
||||||
#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1)
|
#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1)
|
||||||
#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2)
|
#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2)
|
||||||
#define BPF_SOCK_OPS_ALL_CB_FLAGS 0x7 /* Mask of all currently
|
#define BPF_SOCK_OPS_RTT_CB_FLAG (1<<3)
|
||||||
|
#define BPF_SOCK_OPS_ALL_CB_FLAGS 0xF /* Mask of all currently
|
||||||
* supported cb flags
|
* supported cb flags
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -3322,6 +3416,8 @@ enum {
|
|||||||
BPF_SOCK_OPS_TCP_LISTEN_CB, /* Called on listen(2), right after
|
BPF_SOCK_OPS_TCP_LISTEN_CB, /* Called on listen(2), right after
|
||||||
* socket transition to LISTEN state.
|
* socket transition to LISTEN state.
|
||||||
*/
|
*/
|
||||||
|
BPF_SOCK_OPS_RTT_CB, /* Called on every RTT.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
|
/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
|
||||||
@@ -3376,8 +3472,8 @@ struct bpf_raw_tracepoint_args {
|
|||||||
/* DIRECT: Skip the FIB rules and go to FIB table associated with device
|
/* DIRECT: Skip the FIB rules and go to FIB table associated with device
|
||||||
* OUTPUT: Do lookup from egress perspective; default is ingress
|
* OUTPUT: Do lookup from egress perspective; default is ingress
|
||||||
*/
|
*/
|
||||||
#define BPF_FIB_LOOKUP_DIRECT BIT(0)
|
#define BPF_FIB_LOOKUP_DIRECT (1U << 0)
|
||||||
#define BPF_FIB_LOOKUP_OUTPUT BIT(1)
|
#define BPF_FIB_LOOKUP_OUTPUT (1U << 1)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BPF_FIB_LKUP_RET_SUCCESS, /* lookup successful */
|
BPF_FIB_LKUP_RET_SUCCESS, /* lookup successful */
|
||||||
@@ -3449,6 +3545,10 @@ enum bpf_task_fd_type {
|
|||||||
BPF_FD_TYPE_URETPROBE, /* filename + offset */
|
BPF_FD_TYPE_URETPROBE, /* filename + offset */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG (1U << 0)
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL (1U << 1)
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP (1U << 2)
|
||||||
|
|
||||||
struct bpf_flow_keys {
|
struct bpf_flow_keys {
|
||||||
__u16 nhoff;
|
__u16 nhoff;
|
||||||
__u16 thoff;
|
__u16 thoff;
|
||||||
@@ -3470,6 +3570,8 @@ struct bpf_flow_keys {
|
|||||||
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
__u32 flags;
|
||||||
|
__be32 flow_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_func_info {
|
struct bpf_func_info {
|
||||||
@@ -3500,4 +3602,15 @@ struct bpf_sysctl {
|
|||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_sockopt {
|
||||||
|
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||||
|
__bpf_md_ptr(void *, optval);
|
||||||
|
__bpf_md_ptr(void *, optval_end);
|
||||||
|
|
||||||
|
__s32 level;
|
||||||
|
__s32 optname;
|
||||||
|
__s32 optlen;
|
||||||
|
__s32 retval;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _UAPI__LINUX_BPF_H__ */
|
#endif /* _UAPI__LINUX_BPF_H__ */
|
||||||
|
|||||||
@@ -636,6 +636,7 @@ enum {
|
|||||||
IFLA_BOND_AD_USER_PORT_KEY,
|
IFLA_BOND_AD_USER_PORT_KEY,
|
||||||
IFLA_BOND_AD_ACTOR_SYSTEM,
|
IFLA_BOND_AD_ACTOR_SYSTEM,
|
||||||
IFLA_BOND_TLB_DYNAMIC_LB,
|
IFLA_BOND_TLB_DYNAMIC_LB,
|
||||||
|
IFLA_BOND_PEER_NOTIF_DELAY,
|
||||||
__IFLA_BOND_MAX,
|
__IFLA_BOND_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -694,6 +695,7 @@ enum {
|
|||||||
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
|
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
|
||||||
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
|
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
|
||||||
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
|
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
|
||||||
|
IFLA_VF_BROADCAST, /* VF broadcast */
|
||||||
__IFLA_VF_MAX,
|
__IFLA_VF_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -704,6 +706,10 @@ struct ifla_vf_mac {
|
|||||||
__u8 mac[32]; /* MAX_ADDR_LEN */
|
__u8 mac[32]; /* MAX_ADDR_LEN */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ifla_vf_broadcast {
|
||||||
|
__u8 broadcast[32];
|
||||||
|
};
|
||||||
|
|
||||||
struct ifla_vf_vlan {
|
struct ifla_vf_vlan {
|
||||||
__u32 vf;
|
__u32 vf;
|
||||||
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
||||||
|
|||||||
@@ -16,6 +16,18 @@
|
|||||||
#define XDP_SHARED_UMEM (1 << 0)
|
#define XDP_SHARED_UMEM (1 << 0)
|
||||||
#define XDP_COPY (1 << 1) /* Force copy-mode */
|
#define XDP_COPY (1 << 1) /* Force copy-mode */
|
||||||
#define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
|
#define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
|
||||||
|
/* If this option is set, the driver might go sleep and in that case
|
||||||
|
* the XDP_RING_NEED_WAKEUP flag in the fill and/or Tx rings will be
|
||||||
|
* set. If it is set, the application need to explicitly wake up the
|
||||||
|
* driver with a poll() (Rx and Tx) or sendto() (Tx only). If you are
|
||||||
|
* running the driver and the application on the same core, you should
|
||||||
|
* use this option so that the kernel will yield to the user space
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
#define XDP_USE_NEED_WAKEUP (1 << 3)
|
||||||
|
|
||||||
|
/* Flags for xsk_umem_config flags */
|
||||||
|
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||||
|
|
||||||
struct sockaddr_xdp {
|
struct sockaddr_xdp {
|
||||||
__u16 sxdp_family;
|
__u16 sxdp_family;
|
||||||
@@ -25,10 +37,14 @@ struct sockaddr_xdp {
|
|||||||
__u32 sxdp_shared_umem_fd;
|
__u32 sxdp_shared_umem_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* XDP_RING flags */
|
||||||
|
#define XDP_RING_NEED_WAKEUP (1 << 0)
|
||||||
|
|
||||||
struct xdp_ring_offset {
|
struct xdp_ring_offset {
|
||||||
__u64 producer;
|
__u64 producer;
|
||||||
__u64 consumer;
|
__u64 consumer;
|
||||||
__u64 desc;
|
__u64 desc;
|
||||||
|
__u64 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdp_mmap_offsets {
|
struct xdp_mmap_offsets {
|
||||||
@@ -46,12 +62,14 @@ struct xdp_mmap_offsets {
|
|||||||
#define XDP_UMEM_FILL_RING 5
|
#define XDP_UMEM_FILL_RING 5
|
||||||
#define XDP_UMEM_COMPLETION_RING 6
|
#define XDP_UMEM_COMPLETION_RING 6
|
||||||
#define XDP_STATISTICS 7
|
#define XDP_STATISTICS 7
|
||||||
|
#define XDP_OPTIONS 8
|
||||||
|
|
||||||
struct xdp_umem_reg {
|
struct xdp_umem_reg {
|
||||||
__u64 addr; /* Start of packet data area */
|
__u64 addr; /* Start of packet data area */
|
||||||
__u64 len; /* Length of packet data area */
|
__u64 len; /* Length of packet data area */
|
||||||
__u32 chunk_size;
|
__u32 chunk_size;
|
||||||
__u32 headroom;
|
__u32 headroom;
|
||||||
|
__u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdp_statistics {
|
struct xdp_statistics {
|
||||||
@@ -60,12 +78,24 @@ struct xdp_statistics {
|
|||||||
__u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
|
__u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct xdp_options {
|
||||||
|
__u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flags for the flags field of struct xdp_options */
|
||||||
|
#define XDP_OPTIONS_ZEROCOPY (1 << 0)
|
||||||
|
|
||||||
/* Pgoff for mmaping the rings */
|
/* Pgoff for mmaping the rings */
|
||||||
#define XDP_PGOFF_RX_RING 0
|
#define XDP_PGOFF_RX_RING 0
|
||||||
#define XDP_PGOFF_TX_RING 0x80000000
|
#define XDP_PGOFF_TX_RING 0x80000000
|
||||||
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
|
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
|
||||||
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
|
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
|
||||||
|
|
||||||
|
/* Masks for unaligned chunks mode */
|
||||||
|
#define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
|
||||||
|
#define XSK_UNALIGNED_BUF_ADDR_MASK \
|
||||||
|
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||||
|
|
||||||
/* Rx/Tx descriptor */
|
/* Rx/Tx descriptor */
|
||||||
struct xdp_desc {
|
struct xdp_desc {
|
||||||
__u64 addr;
|
__u64 addr;
|
||||||
|
|||||||
95
meson.build
95
meson.build
@@ -1,95 +0,0 @@
|
|||||||
# SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
|
|
||||||
project('libbpf', 'c',
|
|
||||||
version : '0.0.3',
|
|
||||||
license : 'LGPL-2.1 OR BSD-2-Clause',
|
|
||||||
default_options : [
|
|
||||||
'prefix=/usr',
|
|
||||||
],
|
|
||||||
meson_version : '>= 0.46',
|
|
||||||
)
|
|
||||||
|
|
||||||
patchlevel = meson.project_version().split('.')[1]
|
|
||||||
|
|
||||||
libbpf_source_dir = './'
|
|
||||||
|
|
||||||
libbpf_sources = files(run_command('find',
|
|
||||||
[
|
|
||||||
'@0@/src'.format(libbpf_source_dir),
|
|
||||||
'-type',
|
|
||||||
'f',
|
|
||||||
'-name',
|
|
||||||
'*.[h|c]']).stdout().split())
|
|
||||||
|
|
||||||
libbpf_headers = files(
|
|
||||||
join_paths(libbpf_source_dir, 'src/bpf.h'),
|
|
||||||
join_paths(libbpf_source_dir, 'src/btf.h'),
|
|
||||||
join_paths(libbpf_source_dir, 'src/libbpf.h'))
|
|
||||||
|
|
||||||
feature_rellocarray = run_command(join_paths(libbpf_source_dir, 'scripts/check-reallocarray.sh'))
|
|
||||||
|
|
||||||
libbpf_c_args = ['-g',
|
|
||||||
'-O2',
|
|
||||||
'-Werror',
|
|
||||||
'-Wall',
|
|
||||||
]
|
|
||||||
|
|
||||||
if feature_rellocarray.stdout().strip() != ''
|
|
||||||
libbpf_c_args += '-DCOMPAT_NEED_REALLOCARRAY'
|
|
||||||
endif
|
|
||||||
|
|
||||||
# bpf_includes are required to include bpf.h, btf.h, libbpf.h
|
|
||||||
bpf_includes = include_directories(
|
|
||||||
join_paths(libbpf_source_dir, 'src'))
|
|
||||||
|
|
||||||
libbpf_includes = include_directories(
|
|
||||||
join_paths(libbpf_source_dir, 'include'),
|
|
||||||
join_paths(libbpf_source_dir, 'include/uapi'))
|
|
||||||
|
|
||||||
libelf = dependency('libelf')
|
|
||||||
libelf = dependency('libelf', required: false)
|
|
||||||
if not libelf.found()
|
|
||||||
libelf = cc.find_library('elf', required: true)
|
|
||||||
endif
|
|
||||||
|
|
||||||
deps = [libelf]
|
|
||||||
|
|
||||||
libbpf_static = static_library(
|
|
||||||
'bpf',
|
|
||||||
libbpf_sources,
|
|
||||||
c_args : libbpf_c_args,
|
|
||||||
dependencies : deps,
|
|
||||||
include_directories : libbpf_includes,
|
|
||||||
install : true)
|
|
||||||
|
|
||||||
libbpf_static_dep = declare_dependency(link_with : libbpf_static)
|
|
||||||
|
|
||||||
libbpf_map_source_path = join_paths(libbpf_source_dir, 'src/libbpf.map')
|
|
||||||
libbpf_map_abs_path = join_paths(meson.current_source_dir(), libbpf_map_source_path)
|
|
||||||
|
|
||||||
libbpf_c_args += ['-fPIC', '-fvisibility=hidden']
|
|
||||||
|
|
||||||
libbpf_link_args = ['-Wl,--version-script=@0@'.format(libbpf_map_abs_path)]
|
|
||||||
|
|
||||||
libbpf_shared = shared_library(
|
|
||||||
'bpf',
|
|
||||||
libbpf_sources,
|
|
||||||
c_args : libbpf_c_args,
|
|
||||||
dependencies : deps,
|
|
||||||
include_directories : libbpf_includes,
|
|
||||||
install : true,
|
|
||||||
link_args : libbpf_link_args,
|
|
||||||
link_depends : libbpf_map_source_path,
|
|
||||||
soversion : patchlevel,
|
|
||||||
version : meson.project_version())
|
|
||||||
|
|
||||||
libbpf_shared_dep = declare_dependency(link_with : libbpf_shared)
|
|
||||||
|
|
||||||
install_headers(libbpf_headers, subdir : 'bpf')
|
|
||||||
|
|
||||||
pkg = import('pkgconfig')
|
|
||||||
pkg.generate(
|
|
||||||
name: meson.project_name(),
|
|
||||||
version: meson.project_version(),
|
|
||||||
libraries: libbpf_shared,
|
|
||||||
requires_private: ['libelf'],
|
|
||||||
description: '''BPF library''')
|
|
||||||
@@ -1,40 +1,210 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo "USAGE: ./sync-kernel.sh <kernel-repo> <libbpf-repo> [<baseline-commit>]"
|
echo "USAGE: ./sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>"
|
||||||
echo ""
|
echo ""
|
||||||
echo "If <baseline-commit> is not specified, it's read from <libbpf-repo>/CHECKPOINT-COMMIT"
|
echo "Set BPF_NEXT_BASELINE to override bpf-next tree commit, otherwise read from <libbpf-repo>/CHECKPOINT-COMMIT."
|
||||||
exit 1
|
echo "Set BPF_BASELINE to override bpf tree commit, otherwise read from <libbpf-repo>/BPF-CHECKPOINT-COMMIT."
|
||||||
|
echo "Set MANUAL_MODE to 1 to manually control every cherry-picked commits."
|
||||||
|
echo "Set IGNORE_CONSISTENCY to 1 to ignore failed contents consistency check."
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
LINUX_REPO=${1-""}
|
|
||||||
LIBBPF_REPO=${2-""}
|
|
||||||
|
|
||||||
if [ -z "${LINUX_REPO}" ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
if [ -z "${LIBBPF_REPO}" ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
WORKDIR=$(pwd)
|
LIBBPF_REPO=${1-""}
|
||||||
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
LINUX_REPO=${2-""}
|
||||||
|
BPF_BRANCH=${3-""}
|
||||||
|
BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||||
|
BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
|
||||||
|
|
||||||
echo "WORKDIR: ${WORKDIR}"
|
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ] || [ -z "${BPF_BRANCH}" ]; then
|
||||||
echo "LINUX REPO: ${LINUX_REPO}"
|
echo "Error: libbpf or linux repos are not specified"
|
||||||
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
usage
|
||||||
|
fi
|
||||||
|
if [ -z "${BPF_BRANCH}" ]; then
|
||||||
|
echo "Error: linux's bpf tree branch is not specified"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
if [ -z "${BASELINE_COMMIT}" ] || [ -z "${BPF_BASELINE_COMMIT}" ]; then
|
||||||
|
echo "Error: bpf or bpf-next baseline commits are not provided"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
|
SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
|
||||||
BASELINE_COMMIT=${3-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
WORKDIR=$(pwd)
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
||||||
|
|
||||||
|
declare -A PATH_MAP
|
||||||
|
PATH_MAP=( \
|
||||||
|
[tools/lib/bpf]=src \
|
||||||
|
[tools/include/uapi/linux/bpf_common.h]=include/uapi/linux/bpf_common.h \
|
||||||
|
[tools/include/uapi/linux/bpf.h]=include/uapi/linux/bpf.h \
|
||||||
|
[tools/include/uapi/linux/btf.h]=include/uapi/linux/btf.h \
|
||||||
|
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||||
|
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||||
|
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||||
|
[tools/include/tools/libc_compat.h]=include/tools/libc_compat.h \
|
||||||
|
)
|
||||||
|
|
||||||
|
LIBBPF_PATHS="${!PATH_MAP[@]}"
|
||||||
|
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||||
|
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf.cpp|\.gitignore)$'
|
||||||
|
|
||||||
|
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
||||||
|
for p in "${!PATH_MAP[@]}"; do
|
||||||
|
LIBBPF_TREE_FILTER+="git mv -kf ${p} __libbpf/${PATH_MAP[${p}]} && "$'\\\n'
|
||||||
|
done
|
||||||
|
LIBBPF_TREE_FILTER+="git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.cpp,.gitignore} >/dev/null"
|
||||||
|
|
||||||
|
cd_to()
|
||||||
|
{
|
||||||
|
cd ${WORKDIR} && cd "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output brief single-line commit description
|
||||||
|
# $1 - commit ref
|
||||||
|
commit_desc()
|
||||||
|
{
|
||||||
|
git log -n1 --pretty='%h ("%s")' $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create commit single-line signature, which consists of:
|
||||||
|
# - full commit hash
|
||||||
|
# - author date in ISO8601 format
|
||||||
|
# - full commit body with newlines replaced with vertical bars (|)
|
||||||
|
# - shortstat appended at the end
|
||||||
|
# The idea is that this single-line signature is good enough to make final
|
||||||
|
# decision about whether two commits are the same, across different repos.
|
||||||
|
# $1 - commit ref
|
||||||
|
commit_signature()
|
||||||
|
{
|
||||||
|
git log -n1 --pretty='("%s")|%aI|%b' --shortstat $1 | tr '\n' '|'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate there are no non-empty merges (we can't handle them)
|
||||||
|
# $1 - baseline tag
|
||||||
|
# $2 - tip tag
|
||||||
|
validate_merges()
|
||||||
|
{
|
||||||
|
local baseline_tag=$1
|
||||||
|
local tip_tag=$2
|
||||||
|
local new_merges
|
||||||
|
local merge_change_cnt
|
||||||
|
local ignore_merge_resolutions
|
||||||
|
local desc
|
||||||
|
|
||||||
|
new_merges=$(git rev-list --merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||||
|
for new_merge in ${new_merges}; do
|
||||||
|
desc=$(commit_desc ${new_merge})
|
||||||
|
echo "MERGE: ${desc}"
|
||||||
|
merge_change_cnt=$(git show --format='' ${new_merge} | wc -l)
|
||||||
|
if ((${merge_change_cnt} > 0)); then
|
||||||
|
read -p "Merge '${desc}' is non-empty, which will cause conflicts! Do you want to proceed? [y/N]: " ignore_merge_resolutions
|
||||||
|
case "${ignore_merge_resolutions}" in
|
||||||
|
"y" | "Y")
|
||||||
|
echo "Skipping '${desc}'..."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cherry-pick commits touching libbpf-related files
|
||||||
|
# $1 - baseline_tag
|
||||||
|
# $2 - tip_tag
|
||||||
|
cherry_pick_commits()
|
||||||
|
{
|
||||||
|
local manual_mode=${MANUAL_MODE:-0}
|
||||||
|
local baseline_tag=$1
|
||||||
|
local tip_tag=$2
|
||||||
|
local new_commits
|
||||||
|
local signature
|
||||||
|
local should_skip
|
||||||
|
local synced_cnt
|
||||||
|
local manual_check
|
||||||
|
local libbpf_conflict_cnt
|
||||||
|
local desc
|
||||||
|
|
||||||
|
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||||
|
for new_commit in ${new_commits}; do
|
||||||
|
desc="$(commit_desc ${new_commit})"
|
||||||
|
signature="$(commit_signature ${new_commit})"
|
||||||
|
synced_cnt=$(grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | wc -l)
|
||||||
|
manual_check=0
|
||||||
|
if ((${synced_cnt} > 0)); then
|
||||||
|
# commit with the same subject is already in libbpf, but it's
|
||||||
|
# not 100% the same commit, so check with user
|
||||||
|
echo "Commit '${desc}' is synced into libbpf as:"
|
||||||
|
grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | \
|
||||||
|
cut -d'|' -f1 | sed -e 's/^/- /'
|
||||||
|
if ((${manual_mode} != 1 && ${synced_cnt} == 1)); then
|
||||||
|
echo "Skipping '${desc}' due to unique match..."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ((${synced_cnt} > 1)); then
|
||||||
|
echo "'${desc} matches multiple commits, please, double-check!"
|
||||||
|
manual_check=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if ((${manual_mode} == 1 || ${manual_check} == 1)); then
|
||||||
|
read -p "Do you want to skip '${desc}'? [y/N]: " should_skip
|
||||||
|
case "${should_skip}" in
|
||||||
|
"y" | "Y")
|
||||||
|
echo "Skipping '${desc}'..."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
# commit hasn't been synced into libbpf yet
|
||||||
|
echo "Picking '${desc}'..."
|
||||||
|
if ! git cherry-pick ${new_commit} &>/dev/null; then
|
||||||
|
echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
|
||||||
|
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
|
||||||
|
conflict_cnt=$(git diff --name-only | wc -l)
|
||||||
|
|
||||||
|
if ((${libbpf_conflict_cnt} == 0)); then
|
||||||
|
echo "Looks like only non-libbpf files have conflicts, ignoring..."
|
||||||
|
if ((${conflict_cnt} == 0)); then
|
||||||
|
echo "Empty cherry-pick, skipping it..."
|
||||||
|
git cherry-pick --abort
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
git add .
|
||||||
|
# GIT_EDITOR=true to avoid editor popping up to edit commit message
|
||||||
|
if ! GIT_EDITOR=true git cherry-pick --continue &>/dev/null; then
|
||||||
|
echo "Error! That still failed! Please resolve manually."
|
||||||
|
else
|
||||||
|
echo "Success! All cherry-pick conflicts were resolved for '${desc}'!"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cd_to ${LIBBPF_REPO}
|
||||||
|
echo "Dumping existing libbpf commit signatures..."
|
||||||
|
for h in $(git log --pretty='%h' -n500); do
|
||||||
|
echo $h "$(commit_signature $h)" >> ${TMP_DIR}/libbpf_commits.txt
|
||||||
|
done
|
||||||
|
|
||||||
# Use current kernel repo HEAD as a source of patches
|
# Use current kernel repo HEAD as a source of patches
|
||||||
cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
|
TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
|
||||||
TIP_COMMIT=$(git rev-parse HEAD)
|
TIP_COMMIT=$(git rev-parse HEAD)
|
||||||
|
BPF_TIP_COMMIT=$(git rev-parse ${BPF_BRANCH})
|
||||||
BASELINE_TAG=libbpf-baseline-${SUFFIX}
|
BASELINE_TAG=libbpf-baseline-${SUFFIX}
|
||||||
TIP_TAG=libbpf-tip-${SUFFIX}
|
TIP_TAG=libbpf-tip-${SUFFIX}
|
||||||
|
BPF_BASELINE_TAG=libbpf-bpf-baseline-${SUFFIX}
|
||||||
|
BPF_TIP_TAG=libbpf-bpf-tip-${SUFFIX}
|
||||||
VIEW_TAG=libbpf-view-${SUFFIX}
|
VIEW_TAG=libbpf-view-${SUFFIX}
|
||||||
LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
|
LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
|
||||||
|
|
||||||
@@ -43,75 +213,41 @@ SQUASH_BASE_TAG=libbpf-squash-base-${SUFFIX}
|
|||||||
SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
|
SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
|
||||||
SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
|
SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
|
||||||
|
|
||||||
echo "SUFFIX: ${SUFFIX}"
|
echo "WORKDIR: ${WORKDIR}"
|
||||||
echo "BASELINE COMMIT: $(git log --pretty=oneline --no-walk ${BASELINE_COMMIT})"
|
echo "LINUX REPO: ${LINUX_REPO}"
|
||||||
echo "TIP COMMIT: $(git log --pretty=oneline --no-walk ${TIP_COMMIT})"
|
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
||||||
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
echo "TEMP DIR: ${TMP_DIR}"
|
||||||
echo "BASELINE TAG: ${BASELINE_TAG}"
|
echo "SUFFIX: ${SUFFIX}"
|
||||||
echo "TIP TAG: ${TIP_TAG}"
|
echo "BASE COMMIT: '$(commit_desc ${BASELINE_COMMIT})'"
|
||||||
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
echo "TIP COMMIT: '$(commit_desc ${TIP_COMMIT})'"
|
||||||
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
echo "BPF BASE COMMIT: '$(commit_desc ${BPF_BASELINE_COMMIT})'"
|
||||||
echo "VIEW TAG: ${VIEW_TAG}"
|
echo "BPF TIP COMMIT: '$(commit_desc ${BPF_TIP_COMMIT})'"
|
||||||
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
||||||
|
echo "BASELINE TAG: ${BASELINE_TAG}"
|
||||||
TMP_DIR=$(mktemp -d)
|
echo "TIP TAG: ${TIP_TAG}"
|
||||||
echo "TEMP DIR: ${TMP_DIR}"
|
echo "BPF BASELINE TAG: ${BPF_BASELINE_TAG}"
|
||||||
echo "PATCHES+COVER: ${TMP_DIR}/patches"
|
echo "BPF TIP TAG: ${BPF_TIP_TAG}"
|
||||||
echo "PATCHSET: ${TMP_DIR}/patchset.patch"
|
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
||||||
|
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
||||||
|
echo "VIEW TAG: ${VIEW_TAG}"
|
||||||
|
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
||||||
|
echo "PATCHES: ${TMP_DIR}/patches"
|
||||||
|
|
||||||
git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
|
git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
|
||||||
git branch ${TIP_TAG} ${TIP_COMMIT}
|
git branch ${TIP_TAG} ${TIP_COMMIT}
|
||||||
|
git branch ${BPF_BASELINE_TAG} ${BPF_BASELINE_COMMIT}
|
||||||
|
git branch ${BPF_TIP_TAG} ${BPF_TIP_COMMIT}
|
||||||
git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
|
git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
|
||||||
git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
|
git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
|
||||||
|
|
||||||
|
# Validate there are no non-empty merges in bpf-next and bpf trees
|
||||||
|
validate_merges ${BASELINE_TAG} ${TIP_TAG}
|
||||||
|
validate_merges ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||||
|
|
||||||
# Cherry-pick new commits onto squashed baseline commit
|
# Cherry-pick new commits onto squashed baseline commit
|
||||||
LIBBPF_PATHS=(tools/lib/bpf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,netlink.h} tools/include/tools/libc_compat.h)
|
cherry_pick_commits ${BASELINE_TAG} ${TIP_TAG}
|
||||||
|
cherry_pick_commits ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||||
|
|
||||||
LIBBPF_NEW_MERGES=$(git rev-list --merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
|
||||||
for LIBBPF_NEW_MERGE in ${LIBBPF_NEW_MERGES}; do
|
|
||||||
printf "MERGE:\t" && git log --oneline -n1 ${LIBBPF_NEW_MERGE}
|
|
||||||
MERGE_CHANGES=$(git log --format='' -n1 ${LIBBPF_NEW_MERGE} | wc -l)
|
|
||||||
if ((${MERGE_CHANGES} > 0)); then
|
|
||||||
echo "Merge is non empty, aborting!.."
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
|
||||||
git log --oneline -n500 > ${TMP_DIR}/libbpf_commits.txt
|
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
|
||||||
|
|
||||||
LIBBPF_NEW_COMMITS=$(git rev-list --no-merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
|
||||||
for LIBBPF_NEW_COMMIT in ${LIBBPF_NEW_COMMITS}; do
|
|
||||||
echo "Checking commit '${LIBBPF_NEW_COMMIT}'"
|
|
||||||
SYNCED_COMMITS=$(grep -F "$(git log -n1 --pretty=format:%s ${LIBBPF_NEW_COMMIT})" ${TMP_DIR}/libbpf_commits.txt || echo "")
|
|
||||||
if [ -n "${SYNCED_COMMITS}" ]; then
|
|
||||||
# commit with the same subject is already in libbpf, but it's not 100% the same commit, so check with user
|
|
||||||
echo "Commit '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})' appears to be already synced into libbpf..."
|
|
||||||
echo "Corresponding libbpf commit(s):"
|
|
||||||
echo "${SYNCED_COMMITS}"
|
|
||||||
read -p "Do you want to skip it? [y/N]: " SHOULD_SKIP
|
|
||||||
case "${SHOULD_SKIP}" in
|
|
||||||
"y" | "Y")
|
|
||||||
echo "Skipping '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})'..."
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
# commit hasn't been synced into libbpf yet
|
|
||||||
if ! git cherry-pick ${LIBBPF_NEW_COMMIT}; then
|
|
||||||
read -p "Cherry-picking '$(git log --oneline -n1 ${LIBBPF_NEW_COMMIT})' failed, please fix manually and press <return> to proceed..."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
LIBBPF_TREE_FILTER=' \
|
|
||||||
mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && \
|
|
||||||
git mv -kf tools/lib/bpf __libbpf/src && \
|
|
||||||
git mv -kf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} \
|
|
||||||
__libbpf/include/uapi/linux && \
|
|
||||||
git mv -kf tools/include/tools/libc_compat.h __libbpf/include/tools && \
|
|
||||||
git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.cpp,.gitignore} \
|
|
||||||
'
|
|
||||||
# Move all libbpf files into __libbpf directory.
|
# Move all libbpf files into __libbpf directory.
|
||||||
git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
|
git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
|
||||||
# Make __libbpf a new root directory
|
# Make __libbpf a new root directory
|
||||||
@@ -126,59 +262,76 @@ fi
|
|||||||
|
|
||||||
# Exclude baseline commit and generate nice cover letter with summary
|
# Exclude baseline commit and generate nice cover letter with summary
|
||||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
||||||
# Now generate single-file patchset w/o cover to apply on top of libbpf repo
|
|
||||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --stdout > ${TMP_DIR}/patchset.patch
|
|
||||||
|
|
||||||
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
||||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
git checkout -b ${LIBBPF_SYNC_TAG}
|
git checkout -b ${LIBBPF_SYNC_TAG}
|
||||||
git am --committer-date-is-author-date ${TMP_DIR}/patchset.patch
|
|
||||||
|
for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
||||||
|
if ! git am --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||||
|
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Use generated cover-letter as a template for "sync commit" with
|
# Use generated cover-letter as a template for "sync commit" with
|
||||||
# baseline and checkpoint commits from kernel repo (and leave summary
|
# baseline and checkpoint commits from kernel repo (and leave summary
|
||||||
# from cover letter intact, of course)
|
# from cover letter intact, of course)
|
||||||
echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
|
echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
|
||||||
|
echo ${BPF_TIP_COMMIT} > BPF-CHECKPOINT-COMMIT && \
|
||||||
git add CHECKPOINT-COMMIT && \
|
git add CHECKPOINT-COMMIT && \
|
||||||
|
git add BPF-CHECKPOINT-COMMIT && \
|
||||||
awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
|
awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
|
||||||
sed "s/\*\*\* BLURB HERE \*\*\*/\
|
sed "s/\*\*\* BLURB HERE \*\*\*/\
|
||||||
sync: latest libbpf changes from kernel\n\
|
sync: latest libbpf changes from kernel\n\
|
||||||
\n\
|
\n\
|
||||||
Syncing latest libbpf commits from kernel repository.\n\
|
Syncing latest libbpf commits from kernel repository.\n\
|
||||||
Baseline commit: ${BASELINE_COMMIT}\n\
|
Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
|
||||||
Checkpoint commit: ${TIP_COMMIT}/" | \
|
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
||||||
|
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
||||||
|
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
||||||
git commit --file=-
|
git commit --file=-
|
||||||
|
|
||||||
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
||||||
|
|
||||||
echo "Verifying Linux's and Github's libbpf state"
|
echo "Verifying Linux's and Github's libbpf state"
|
||||||
LIBBPF_VIEW_PATHS=(src include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} include/tools/libc_compat.h)
|
|
||||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf.cpp|\.gitignore)$'
|
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
LINUX_ABS_DIR=$(pwd)
|
LINUX_ABS_DIR=$(pwd)
|
||||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||||
git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
GITHUB_ABS_DIR=$(pwd)
|
GITHUB_ABS_DIR=$(pwd)
|
||||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
||||||
|
|
||||||
echo "Comparing list of files..."
|
echo "Comparing list of files..."
|
||||||
diff ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||||
echo "Comparing file contents..."
|
echo "Comparing file contents..."
|
||||||
|
CONSISTENT=1
|
||||||
for F in $(cat ${TMP_DIR}/linux-view.ls); do
|
for F in $(cat ${TMP_DIR}/linux-view.ls); do
|
||||||
diff "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"
|
if ! diff -u "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"; then
|
||||||
|
echo "${LINUX_ABS_DIR}/${F} and ${GITHUB_ABS_DIR}/${F} are different!"
|
||||||
|
CONSISTENT=0
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
echo "Contents appear identical!"
|
if ((${CONSISTENT} == 1)); then
|
||||||
|
echo "Great! Content is identical!"
|
||||||
|
else
|
||||||
|
echo "Unfortunately, there are consistency problems!"
|
||||||
|
if ((${IGNORE_CONSISTENCY-0} != 1)); then
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Cleaning up..."
|
echo "Cleaning up..."
|
||||||
rm -r ${TMP_DIR}
|
rm -r ${TMP_DIR}
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
git checkout ${TIP_SYM_REF}
|
git checkout ${TIP_SYM_REF}
|
||||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
|
||||||
|
${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
||||||
|
|
||||||
cd ${WORKDIR}
|
cd_to .
|
||||||
echo "DONE."
|
echo "DONE."
|
||||||
|
|
||||||
|
|||||||
4
src/.gitignore
vendored
4
src/.gitignore
vendored
@@ -1,2 +1,6 @@
|
|||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
/libbpf.pc
|
||||||
|
/libbpf.so*
|
||||||
|
/staticobjs
|
||||||
|
/sharedobjs
|
||||||
|
|||||||
66
src/Makefile
66
src/Makefile
@@ -1,10 +1,9 @@
|
|||||||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
VERSION = 0
|
LIBBPF_VERSION := $(shell \
|
||||||
PATCHLEVEL = 0
|
grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | \
|
||||||
EXTRAVERSION = 3
|
sort -rV | head -n1 | cut -d'_' -f2)
|
||||||
|
LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
|
||||||
LIBBPF_VERSION = $(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)
|
|
||||||
|
|
||||||
TOPDIR = ..
|
TOPDIR = ..
|
||||||
|
|
||||||
@@ -16,9 +15,7 @@ ifneq ($(FEATURE_REALLOCARRAY),)
|
|||||||
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef BUILD_STATIC_ONLY
|
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||||
ALL_CFLAGS += -fPIC -fvisibility=hidden
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS ?= -g -O2 -Werror -Wall
|
CFLAGS ?= -g -O2 -Werror -Wall
|
||||||
ALL_CFLAGS += $(CFLAGS)
|
ALL_CFLAGS += $(CFLAGS)
|
||||||
@@ -32,21 +29,25 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
OBJDIR ?= .
|
OBJDIR ?= .
|
||||||
|
SHARED_OBJDIR := $(OBJDIR)/sharedobjs
|
||||||
|
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||||
|
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||||
|
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
||||||
|
btf_dump.o hashmap.o
|
||||||
|
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||||
|
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||||
|
|
||||||
OBJS := $(addprefix $(OBJDIR)/,bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
STATIC_LIBS := $(OBJDIR)/libbpf.a
|
||||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o)
|
|
||||||
|
|
||||||
LIBS := $(OBJDIR)/libbpf.a
|
|
||||||
ifndef BUILD_STATIC_ONLY
|
ifndef BUILD_STATIC_ONLY
|
||||||
LIBS += $(OBJDIR)/libbpf.so \
|
SHARED_LIBS := $(OBJDIR)/libbpf.so \
|
||||||
$(OBJDIR)/libbpf.so.$(VERSION) \
|
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||||
VERSION_SCRIPT := libbpf.map
|
VERSION_SCRIPT := libbpf.map
|
||||||
endif
|
endif
|
||||||
|
|
||||||
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h
|
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h
|
||||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,bpf.h bpf_common.h \
|
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
||||||
btf.h)
|
bpf.h bpf_common.h btf.h)
|
||||||
|
|
||||||
PC_FILE := $(OBJDIR)/libbpf.pc
|
PC_FILE := $(OBJDIR)/libbpf.pc
|
||||||
|
|
||||||
@@ -65,21 +66,21 @@ LIBDIR ?= $(PREFIX)/$(LIBSUBDIR)
|
|||||||
INCLUDEDIR ?= $(PREFIX)/include
|
INCLUDEDIR ?= $(PREFIX)/include
|
||||||
UAPIDIR ?= $(PREFIX)/include
|
UAPIDIR ?= $(PREFIX)/include
|
||||||
|
|
||||||
all: $(LIBS) $(PC_FILE)
|
all: $(STATIC_LIBS) $(SHARED_LIBS) $(PC_FILE)
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.a: $(OBJS)
|
$(OBJDIR)/libbpf.a: $(STATIC_OBJS)
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(VERSION)
|
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION)
|
||||||
ln -sf $(^F) $@
|
ln -sf $(^F) $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so.$(VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||||
ln -sf $(^F) $@
|
ln -sf $(^F) $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(OBJS)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
|
||||||
$(CC) -shared $(ALL_LDFLAGS) -Wl,--version-script=$(VERSION_SCRIPT) \
|
$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||||
-Wl,-soname,libbpf.so.$(VERSION) \
|
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||||
$^ -o $@
|
$^ $(ALL_LDFLAGS) -o $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.pc:
|
$(OBJDIR)/libbpf.pc:
|
||||||
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||||
@@ -87,9 +88,18 @@ $(OBJDIR)/libbpf.pc:
|
|||||||
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
||||||
< libbpf.pc.template > $@
|
< libbpf.pc.template > $@
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.c
|
$(STATIC_OBJDIR):
|
||||||
|
mkdir -p $(STATIC_OBJDIR)
|
||||||
|
|
||||||
|
$(SHARED_OBJDIR):
|
||||||
|
mkdir -p $(SHARED_OBJDIR)
|
||||||
|
|
||||||
|
$(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
|
||||||
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
|
||||||
|
$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
define do_install
|
define do_install
|
||||||
if [ ! -d '$(DESTDIR)$2' ]; then \
|
if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||||
@@ -106,7 +116,7 @@ define do_s_install
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
install: all install_headers install_pkgconfig
|
install: all install_headers install_pkgconfig
|
||||||
$(call do_s_install,$(LIBS),$(LIBDIR))
|
$(call do_s_install,$(STATIC_LIBS) $(SHARED_LIBS),$(LIBDIR))
|
||||||
|
|
||||||
install_headers:
|
install_headers:
|
||||||
$(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
|
$(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
|
||||||
@@ -120,4 +130,4 @@ install_pkgconfig: $(PC_FILE)
|
|||||||
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a *.so *.so.* *.pc
|
rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ described here. It's recommended to follow these conventions whenever a
|
|||||||
new function or type is added to keep libbpf API clean and consistent.
|
new function or type is added to keep libbpf API clean and consistent.
|
||||||
|
|
||||||
All types and functions provided by libbpf API should have one of the
|
All types and functions provided by libbpf API should have one of the
|
||||||
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``.
|
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
|
||||||
|
``perf_buffer_``.
|
||||||
|
|
||||||
System call wrappers
|
System call wrappers
|
||||||
--------------------
|
--------------------
|
||||||
|
|||||||
32
src/bpf.c
32
src/bpf.c
@@ -26,10 +26,11 @@
|
|||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include "bpf.h"
|
#include "bpf.h"
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include <errno.h>
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When building perf, unistd.h is overridden. __NR_bpf is
|
* When building perf, unistd.h is overridden. __NR_bpf is
|
||||||
@@ -53,10 +54,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef min
|
|
||||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline __u64 ptr_to_u64(const void *ptr)
|
static inline __u64 ptr_to_u64(const void *ptr)
|
||||||
{
|
{
|
||||||
return (__u64) (unsigned long) ptr;
|
return (__u64) (unsigned long) ptr;
|
||||||
@@ -256,6 +253,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
if (load_attr->name)
|
if (load_attr->name)
|
||||||
memcpy(attr.prog_name, load_attr->name,
|
memcpy(attr.prog_name, load_attr->name,
|
||||||
min(strlen(load_attr->name), BPF_OBJ_NAME_LEN - 1));
|
min(strlen(load_attr->name), BPF_OBJ_NAME_LEN - 1));
|
||||||
|
attr.prog_flags = load_attr->prog_flags;
|
||||||
|
|
||||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
@@ -570,7 +568,7 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int err;
|
int err;
|
||||||
@@ -578,26 +576,26 @@ int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
|||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.start_id = start_id;
|
attr.start_id = start_id;
|
||||||
|
|
||||||
err = sys_bpf(BPF_PROG_GET_NEXT_ID, &attr, sizeof(attr));
|
err = sys_bpf(cmd, &attr, sizeof(attr));
|
||||||
if (!err)
|
if (!err)
|
||||||
*next_id = attr.next_id;
|
*next_id = attr.next_id;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_next_id(start_id, next_id, BPF_PROG_GET_NEXT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_map_get_next_id(__u32 start_id, __u32 *next_id)
|
int bpf_map_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
return bpf_obj_get_next_id(start_id, next_id, BPF_MAP_GET_NEXT_ID);
|
||||||
int err;
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
attr.start_id = start_id;
|
{
|
||||||
|
return bpf_obj_get_next_id(start_id, next_id, BPF_BTF_GET_NEXT_ID);
|
||||||
err = sys_bpf(BPF_MAP_GET_NEXT_ID, &attr, sizeof(attr));
|
|
||||||
if (!err)
|
|
||||||
*next_id = attr.next_id;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_fd_by_id(__u32 id)
|
int bpf_prog_get_fd_by_id(__u32 id)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ struct bpf_load_program_attr {
|
|||||||
const void *line_info;
|
const void *line_info;
|
||||||
__u32 line_info_cnt;
|
__u32 line_info_cnt;
|
||||||
__u32 log_level;
|
__u32 log_level;
|
||||||
|
__u32 prog_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags to direct loading requirements */
|
/* Flags to direct loading requirements */
|
||||||
@@ -155,6 +156,7 @@ LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
|||||||
__u32 *retval, __u32 *duration);
|
__u32 *retval, __u32 *duration);
|
||||||
LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
|
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||||
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
||||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||||
|
|||||||
@@ -6,10 +6,7 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
|
#include "libbpf_internal.h"
|
||||||
#ifndef min
|
|
||||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct bpf_prog_linfo {
|
struct bpf_prog_linfo {
|
||||||
void *raw_linfo;
|
void *raw_linfo;
|
||||||
|
|||||||
202
src/btf.h
202
src/btf.h
@@ -4,6 +4,8 @@
|
|||||||
#ifndef __LIBBPF_BTF_H
|
#ifndef __LIBBPF_BTF_H
|
||||||
#define __LIBBPF_BTF_H
|
#define __LIBBPF_BTF_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <linux/btf.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -16,6 +18,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define BTF_ELF_SEC ".BTF"
|
#define BTF_ELF_SEC ".BTF"
|
||||||
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
||||||
|
#define MAPS_ELF_SEC ".maps"
|
||||||
|
|
||||||
struct btf;
|
struct btf;
|
||||||
struct btf_ext;
|
struct btf_ext;
|
||||||
@@ -55,10 +58,16 @@ struct btf_ext_header {
|
|||||||
__u32 func_info_len;
|
__u32 func_info_len;
|
||||||
__u32 line_info_off;
|
__u32 line_info_off;
|
||||||
__u32 line_info_len;
|
__u32 line_info_len;
|
||||||
|
|
||||||
|
/* optional part of .BTF.ext header */
|
||||||
|
__u32 offset_reloc_off;
|
||||||
|
__u32 offset_reloc_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBBPF_API void btf__free(struct btf *btf);
|
LIBBPF_API void btf__free(struct btf *btf);
|
||||||
LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size);
|
LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size);
|
||||||
|
LIBBPF_API struct btf *btf__parse_elf(const char *path,
|
||||||
|
struct btf_ext **btf_ext);
|
||||||
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
||||||
LIBBPF_API int btf__load(struct btf *btf);
|
LIBBPF_API int btf__load(struct btf *btf);
|
||||||
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
||||||
@@ -100,6 +109,199 @@ struct btf_dedup_opts {
|
|||||||
LIBBPF_API int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
|
LIBBPF_API int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
|
||||||
const struct btf_dedup_opts *opts);
|
const struct btf_dedup_opts *opts);
|
||||||
|
|
||||||
|
struct btf_dump;
|
||||||
|
|
||||||
|
struct btf_dump_opts {
|
||||||
|
void *ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*btf_dump_printf_fn_t)(void *ctx, const char *fmt, va_list args);
|
||||||
|
|
||||||
|
LIBBPF_API struct btf_dump *btf_dump__new(const struct btf *btf,
|
||||||
|
const struct btf_ext *btf_ext,
|
||||||
|
const struct btf_dump_opts *opts,
|
||||||
|
btf_dump_printf_fn_t printf_fn);
|
||||||
|
LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
||||||
|
|
||||||
|
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A set of helpers for easier BTF types handling
|
||||||
|
*/
|
||||||
|
static inline __u16 btf_kind(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_KIND(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u16 btf_vlen(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_VLEN(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_kflag(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_KFLAG(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_int(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_ptr(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_array(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_struct(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_STRUCT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_union(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_UNION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_composite(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
__u16 kind = btf_kind(t);
|
||||||
|
|
||||||
|
return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_enum(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_ENUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_fwd(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FWD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_typedef(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_TYPEDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_volatile(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_VOLATILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_const(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_CONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_restrict(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_RESTRICT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_mod(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
__u16 kind = btf_kind(t);
|
||||||
|
|
||||||
|
return kind == BTF_KIND_VOLATILE ||
|
||||||
|
kind == BTF_KIND_CONST ||
|
||||||
|
kind == BTF_KIND_RESTRICT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_func(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_func_proto(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FUNC_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_var(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_datasec(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_DATASEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_offset(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_OFFSET(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_bits(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_BITS(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_array *btf_array(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_array *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_enum *btf_enum(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_enum *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_member *btf_members(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_member *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get bit offset of a member with specified index. */
|
||||||
|
static inline __u32 btf_member_bit_offset(const struct btf_type *t,
|
||||||
|
__u32 member_idx)
|
||||||
|
{
|
||||||
|
const struct btf_member *m = btf_members(t) + member_idx;
|
||||||
|
bool kflag = btf_kflag(t);
|
||||||
|
|
||||||
|
return kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Get bitfield size of a member, assuming t is BTF_KIND_STRUCT or
|
||||||
|
* BTF_KIND_UNION. If member is not a bitfield, zero is returned.
|
||||||
|
*/
|
||||||
|
static inline __u32 btf_member_bitfield_size(const struct btf_type *t,
|
||||||
|
__u32 member_idx)
|
||||||
|
{
|
||||||
|
const struct btf_member *m = btf_members(t) + member_idx;
|
||||||
|
bool kflag = btf_kflag(t);
|
||||||
|
|
||||||
|
return kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_param *btf_params(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_param *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_var *btf_var(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_var *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_var_secinfo *
|
||||||
|
btf_var_secinfos(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_var_secinfo *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1369
src/btf_dump.c
Normal file
1369
src/btf_dump.c
Normal file
File diff suppressed because it is too large
Load Diff
229
src/hashmap.c
Normal file
229
src/hashmap.c
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic non-thread safe hash map implementation.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Facebook
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
/* start with 4 buckets */
|
||||||
|
#define HASHMAP_MIN_CAP_BITS 2
|
||||||
|
|
||||||
|
static void hashmap_add_entry(struct hashmap_entry **pprev,
|
||||||
|
struct hashmap_entry *entry)
|
||||||
|
{
|
||||||
|
entry->next = *pprev;
|
||||||
|
*pprev = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hashmap_del_entry(struct hashmap_entry **pprev,
|
||||||
|
struct hashmap_entry *entry)
|
||||||
|
{
|
||||||
|
*pprev = entry->next;
|
||||||
|
entry->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
|
||||||
|
hashmap_equal_fn equal_fn, void *ctx)
|
||||||
|
{
|
||||||
|
map->hash_fn = hash_fn;
|
||||||
|
map->equal_fn = equal_fn;
|
||||||
|
map->ctx = ctx;
|
||||||
|
|
||||||
|
map->buckets = NULL;
|
||||||
|
map->cap = 0;
|
||||||
|
map->cap_bits = 0;
|
||||||
|
map->sz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
||||||
|
hashmap_equal_fn equal_fn,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
struct hashmap *map = malloc(sizeof(struct hashmap));
|
||||||
|
|
||||||
|
if (!map)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
hashmap__init(map, hash_fn, equal_fn, ctx);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap__clear(struct hashmap *map)
|
||||||
|
{
|
||||||
|
free(map->buckets);
|
||||||
|
map->cap = map->cap_bits = map->sz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap__free(struct hashmap *map)
|
||||||
|
{
|
||||||
|
if (!map)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hashmap__clear(map);
|
||||||
|
free(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hashmap__size(const struct hashmap *map)
|
||||||
|
{
|
||||||
|
return map->sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hashmap__capacity(const struct hashmap *map)
|
||||||
|
{
|
||||||
|
return map->cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hashmap_needs_to_grow(struct hashmap *map)
|
||||||
|
{
|
||||||
|
/* grow if empty or more than 75% filled */
|
||||||
|
return (map->cap == 0) || ((map->sz + 1) * 4 / 3 > map->cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hashmap_grow(struct hashmap *map)
|
||||||
|
{
|
||||||
|
struct hashmap_entry **new_buckets;
|
||||||
|
struct hashmap_entry *cur, *tmp;
|
||||||
|
size_t new_cap_bits, new_cap;
|
||||||
|
size_t h;
|
||||||
|
int bkt;
|
||||||
|
|
||||||
|
new_cap_bits = map->cap_bits + 1;
|
||||||
|
if (new_cap_bits < HASHMAP_MIN_CAP_BITS)
|
||||||
|
new_cap_bits = HASHMAP_MIN_CAP_BITS;
|
||||||
|
|
||||||
|
new_cap = 1UL << new_cap_bits;
|
||||||
|
new_buckets = calloc(new_cap, sizeof(new_buckets[0]));
|
||||||
|
if (!new_buckets)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
hashmap__for_each_entry_safe(map, cur, tmp, bkt) {
|
||||||
|
h = hash_bits(map->hash_fn(cur->key, map->ctx), new_cap_bits);
|
||||||
|
hashmap_add_entry(&new_buckets[h], cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
map->cap = new_cap;
|
||||||
|
map->cap_bits = new_cap_bits;
|
||||||
|
free(map->buckets);
|
||||||
|
map->buckets = new_buckets;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hashmap_find_entry(const struct hashmap *map,
|
||||||
|
const void *key, size_t hash,
|
||||||
|
struct hashmap_entry ***pprev,
|
||||||
|
struct hashmap_entry **entry)
|
||||||
|
{
|
||||||
|
struct hashmap_entry *cur, **prev_ptr;
|
||||||
|
|
||||||
|
if (!map->buckets)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (prev_ptr = &map->buckets[hash], cur = *prev_ptr;
|
||||||
|
cur;
|
||||||
|
prev_ptr = &cur->next, cur = cur->next) {
|
||||||
|
if (map->equal_fn(cur->key, key, map->ctx)) {
|
||||||
|
if (pprev)
|
||||||
|
*pprev = prev_ptr;
|
||||||
|
*entry = cur;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
||||||
|
enum hashmap_insert_strategy strategy,
|
||||||
|
const void **old_key, void **old_value)
|
||||||
|
{
|
||||||
|
struct hashmap_entry *entry;
|
||||||
|
size_t h;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (old_key)
|
||||||
|
*old_key = NULL;
|
||||||
|
if (old_value)
|
||||||
|
*old_value = NULL;
|
||||||
|
|
||||||
|
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||||
|
if (strategy != HASHMAP_APPEND &&
|
||||||
|
hashmap_find_entry(map, key, h, NULL, &entry)) {
|
||||||
|
if (old_key)
|
||||||
|
*old_key = entry->key;
|
||||||
|
if (old_value)
|
||||||
|
*old_value = entry->value;
|
||||||
|
|
||||||
|
if (strategy == HASHMAP_SET || strategy == HASHMAP_UPDATE) {
|
||||||
|
entry->key = key;
|
||||||
|
entry->value = value;
|
||||||
|
return 0;
|
||||||
|
} else if (strategy == HASHMAP_ADD) {
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strategy == HASHMAP_UPDATE)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (hashmap_needs_to_grow(map)) {
|
||||||
|
err = hashmap_grow(map);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = malloc(sizeof(struct hashmap_entry));
|
||||||
|
if (!entry)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
entry->key = key;
|
||||||
|
entry->value = value;
|
||||||
|
hashmap_add_entry(&map->buckets[h], entry);
|
||||||
|
map->sz++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap__find(const struct hashmap *map, const void *key, void **value)
|
||||||
|
{
|
||||||
|
struct hashmap_entry *entry;
|
||||||
|
size_t h;
|
||||||
|
|
||||||
|
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||||
|
if (!hashmap_find_entry(map, key, h, NULL, &entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
*value = entry->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap__delete(struct hashmap *map, const void *key,
|
||||||
|
const void **old_key, void **old_value)
|
||||||
|
{
|
||||||
|
struct hashmap_entry **pprev, *entry;
|
||||||
|
size_t h;
|
||||||
|
|
||||||
|
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||||
|
if (!hashmap_find_entry(map, key, h, &pprev, &entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (old_key)
|
||||||
|
*old_key = entry->key;
|
||||||
|
if (old_value)
|
||||||
|
*old_value = entry->value;
|
||||||
|
|
||||||
|
hashmap_del_entry(pprev, entry);
|
||||||
|
free(entry);
|
||||||
|
map->sz--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
178
src/hashmap.h
Normal file
178
src/hashmap.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic non-thread safe hash map implementation.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Facebook
|
||||||
|
*/
|
||||||
|
#ifndef __LIBBPF_HASHMAP_H
|
||||||
|
#define __LIBBPF_HASHMAP_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#include <bits/wordsize.h>
|
||||||
|
#else
|
||||||
|
#include <bits/reg.h>
|
||||||
|
#endif
|
||||||
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
static inline size_t hash_bits(size_t h, int bits)
|
||||||
|
{
|
||||||
|
/* shuffle bits and return requested number of upper bits */
|
||||||
|
return (h * 11400714819323198485llu) >> (__WORDSIZE - bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);
|
||||||
|
typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx);
|
||||||
|
|
||||||
|
struct hashmap_entry {
|
||||||
|
const void *key;
|
||||||
|
void *value;
|
||||||
|
struct hashmap_entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hashmap {
|
||||||
|
hashmap_hash_fn hash_fn;
|
||||||
|
hashmap_equal_fn equal_fn;
|
||||||
|
void *ctx;
|
||||||
|
|
||||||
|
struct hashmap_entry **buckets;
|
||||||
|
size_t cap;
|
||||||
|
size_t cap_bits;
|
||||||
|
size_t sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HASHMAP_INIT(hash_fn, equal_fn, ctx) { \
|
||||||
|
.hash_fn = (hash_fn), \
|
||||||
|
.equal_fn = (equal_fn), \
|
||||||
|
.ctx = (ctx), \
|
||||||
|
.buckets = NULL, \
|
||||||
|
.cap = 0, \
|
||||||
|
.cap_bits = 0, \
|
||||||
|
.sz = 0, \
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
|
||||||
|
hashmap_equal_fn equal_fn, void *ctx);
|
||||||
|
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
||||||
|
hashmap_equal_fn equal_fn,
|
||||||
|
void *ctx);
|
||||||
|
void hashmap__clear(struct hashmap *map);
|
||||||
|
void hashmap__free(struct hashmap *map);
|
||||||
|
|
||||||
|
size_t hashmap__size(const struct hashmap *map);
|
||||||
|
size_t hashmap__capacity(const struct hashmap *map);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hashmap insertion strategy:
|
||||||
|
* - HASHMAP_ADD - only add key/value if key doesn't exist yet;
|
||||||
|
* - HASHMAP_SET - add key/value pair if key doesn't exist yet; otherwise,
|
||||||
|
* update value;
|
||||||
|
* - HASHMAP_UPDATE - update value, if key already exists; otherwise, do
|
||||||
|
* nothing and return -ENOENT;
|
||||||
|
* - HASHMAP_APPEND - always add key/value pair, even if key already exists.
|
||||||
|
* This turns hashmap into a multimap by allowing multiple values to be
|
||||||
|
* associated with the same key. Most useful read API for such hashmap is
|
||||||
|
* hashmap__for_each_key_entry() iteration. If hashmap__find() is still
|
||||||
|
* used, it will return last inserted key/value entry (first in a bucket
|
||||||
|
* chain).
|
||||||
|
*/
|
||||||
|
enum hashmap_insert_strategy {
|
||||||
|
HASHMAP_ADD,
|
||||||
|
HASHMAP_SET,
|
||||||
|
HASHMAP_UPDATE,
|
||||||
|
HASHMAP_APPEND,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashmap__insert() adds key/value entry w/ various semantics, depending on
|
||||||
|
* provided strategy value. If a given key/value pair replaced already
|
||||||
|
* existing key/value pair, both old key and old value will be returned
|
||||||
|
* through old_key and old_value to allow calling code do proper memory
|
||||||
|
* management.
|
||||||
|
*/
|
||||||
|
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
||||||
|
enum hashmap_insert_strategy strategy,
|
||||||
|
const void **old_key, void **old_value);
|
||||||
|
|
||||||
|
static inline int hashmap__add(struct hashmap *map,
|
||||||
|
const void *key, void *value)
|
||||||
|
{
|
||||||
|
return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hashmap__set(struct hashmap *map,
|
||||||
|
const void *key, void *value,
|
||||||
|
const void **old_key, void **old_value)
|
||||||
|
{
|
||||||
|
return hashmap__insert(map, key, value, HASHMAP_SET,
|
||||||
|
old_key, old_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hashmap__update(struct hashmap *map,
|
||||||
|
const void *key, void *value,
|
||||||
|
const void **old_key, void **old_value)
|
||||||
|
{
|
||||||
|
return hashmap__insert(map, key, value, HASHMAP_UPDATE,
|
||||||
|
old_key, old_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hashmap__append(struct hashmap *map,
|
||||||
|
const void *key, void *value)
|
||||||
|
{
|
||||||
|
return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap__delete(struct hashmap *map, const void *key,
|
||||||
|
const void **old_key, void **old_value);
|
||||||
|
|
||||||
|
bool hashmap__find(const struct hashmap *map, const void *key, void **value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashmap__for_each_entry - iterate over all entries in hashmap
|
||||||
|
* @map: hashmap to iterate
|
||||||
|
* @cur: struct hashmap_entry * used as a loop cursor
|
||||||
|
* @bkt: integer used as a bucket loop cursor
|
||||||
|
*/
|
||||||
|
#define hashmap__for_each_entry(map, cur, bkt) \
|
||||||
|
for (bkt = 0; bkt < map->cap; bkt++) \
|
||||||
|
for (cur = map->buckets[bkt]; cur; cur = cur->next)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe
|
||||||
|
* against removals
|
||||||
|
* @map: hashmap to iterate
|
||||||
|
* @cur: struct hashmap_entry * used as a loop cursor
|
||||||
|
* @tmp: struct hashmap_entry * used as a temporary next cursor storage
|
||||||
|
* @bkt: integer used as a bucket loop cursor
|
||||||
|
*/
|
||||||
|
#define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \
|
||||||
|
for (bkt = 0; bkt < map->cap; bkt++) \
|
||||||
|
for (cur = map->buckets[bkt]; \
|
||||||
|
cur && ({tmp = cur->next; true; }); \
|
||||||
|
cur = tmp)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashmap__for_each_key_entry - iterate over entries associated with given key
|
||||||
|
* @map: hashmap to iterate
|
||||||
|
* @cur: struct hashmap_entry * used as a loop cursor
|
||||||
|
* @key: key to iterate entries for
|
||||||
|
*/
|
||||||
|
#define hashmap__for_each_key_entry(map, cur, _key) \
|
||||||
|
for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\
|
||||||
|
map->cap_bits); \
|
||||||
|
map->buckets ? map->buckets[bkt] : NULL; }); \
|
||||||
|
cur; \
|
||||||
|
cur = cur->next) \
|
||||||
|
if (map->equal_fn(cur->key, (_key), map->ctx))
|
||||||
|
|
||||||
|
#define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \
|
||||||
|
for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\
|
||||||
|
map->cap_bits); \
|
||||||
|
cur = map->buckets ? map->buckets[bkt] : NULL; }); \
|
||||||
|
cur && ({ tmp = cur->next; true; }); \
|
||||||
|
cur = tmp) \
|
||||||
|
if (map->equal_fn(cur->key, (_key), map->ctx))
|
||||||
|
|
||||||
|
#endif /* __LIBBPF_HASHMAP_H */
|
||||||
2859
src/libbpf.c
2859
src/libbpf.c
File diff suppressed because it is too large
Load Diff
158
src/libbpf.h
158
src/libbpf.h
@@ -57,7 +57,7 @@ enum libbpf_print_level {
|
|||||||
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
||||||
const char *, va_list ap);
|
const char *, va_list ap);
|
||||||
|
|
||||||
LIBBPF_API void libbpf_set_print(libbpf_print_fn_t fn);
|
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
|
||||||
|
|
||||||
/* Hide internal to user */
|
/* Hide internal to user */
|
||||||
struct bpf_object;
|
struct bpf_object;
|
||||||
@@ -89,18 +89,26 @@ LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
|
|||||||
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
||||||
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
||||||
|
|
||||||
|
struct bpf_object_load_attr {
|
||||||
|
struct bpf_object *obj;
|
||||||
|
int log_level;
|
||||||
|
const char *target_btf_path;
|
||||||
|
};
|
||||||
|
|
||||||
/* Load/unload object into/from kernel */
|
/* Load/unload object into/from kernel */
|
||||||
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
||||||
|
LIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);
|
||||||
LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
|
LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
|
||||||
LIBBPF_API const char *bpf_object__name(struct bpf_object *obj);
|
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
||||||
LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj);
|
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
||||||
|
|
||||||
struct btf;
|
struct btf;
|
||||||
LIBBPF_API struct btf *bpf_object__btf(struct bpf_object *obj);
|
LIBBPF_API struct btf *bpf_object__btf(const struct bpf_object *obj);
|
||||||
LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj);
|
LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj);
|
||||||
|
|
||||||
LIBBPF_API struct bpf_program *
|
LIBBPF_API struct bpf_program *
|
||||||
bpf_object__find_program_by_title(struct bpf_object *obj, const char *title);
|
bpf_object__find_program_by_title(const struct bpf_object *obj,
|
||||||
|
const char *title);
|
||||||
|
|
||||||
LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
||||||
#define bpf_object__for_each_safe(pos, tmp) \
|
#define bpf_object__for_each_safe(pos, tmp) \
|
||||||
@@ -112,7 +120,7 @@ LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
|||||||
typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *);
|
typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *);
|
||||||
LIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv,
|
LIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv,
|
||||||
bpf_object_clear_priv_t clear_priv);
|
bpf_object_clear_priv_t clear_priv);
|
||||||
LIBBPF_API void *bpf_object__priv(struct bpf_object *prog);
|
LIBBPF_API void *bpf_object__priv(const struct bpf_object *prog);
|
||||||
|
|
||||||
LIBBPF_API int
|
LIBBPF_API int
|
||||||
libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
|
libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
|
||||||
@@ -123,7 +131,7 @@ LIBBPF_API int libbpf_attach_type_by_name(const char *name,
|
|||||||
/* Accessors of bpf_program */
|
/* Accessors of bpf_program */
|
||||||
struct bpf_program;
|
struct bpf_program;
|
||||||
LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,
|
LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,
|
||||||
struct bpf_object *obj);
|
const struct bpf_object *obj);
|
||||||
|
|
||||||
#define bpf_object__for_each_program(pos, obj) \
|
#define bpf_object__for_each_program(pos, obj) \
|
||||||
for ((pos) = bpf_program__next(NULL, (obj)); \
|
for ((pos) = bpf_program__next(NULL, (obj)); \
|
||||||
@@ -131,24 +139,23 @@ LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,
|
|||||||
(pos) = bpf_program__next((pos), (obj)))
|
(pos) = bpf_program__next((pos), (obj)))
|
||||||
|
|
||||||
LIBBPF_API struct bpf_program *bpf_program__prev(struct bpf_program *prog,
|
LIBBPF_API struct bpf_program *bpf_program__prev(struct bpf_program *prog,
|
||||||
struct bpf_object *obj);
|
const struct bpf_object *obj);
|
||||||
|
|
||||||
typedef void (*bpf_program_clear_priv_t)(struct bpf_program *,
|
typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, void *);
|
||||||
void *);
|
|
||||||
|
|
||||||
LIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv,
|
LIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv,
|
||||||
bpf_program_clear_priv_t clear_priv);
|
bpf_program_clear_priv_t clear_priv);
|
||||||
|
|
||||||
LIBBPF_API void *bpf_program__priv(struct bpf_program *prog);
|
LIBBPF_API void *bpf_program__priv(const struct bpf_program *prog);
|
||||||
LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
|
LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
|
||||||
__u32 ifindex);
|
__u32 ifindex);
|
||||||
|
|
||||||
LIBBPF_API const char *bpf_program__title(struct bpf_program *prog,
|
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
|
||||||
bool needs_copy);
|
bool needs_copy);
|
||||||
|
|
||||||
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
|
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
|
||||||
__u32 kern_version);
|
__u32 kern_version);
|
||||||
LIBBPF_API int bpf_program__fd(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
|
||||||
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
|
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
|
||||||
const char *path,
|
const char *path,
|
||||||
int instance);
|
int instance);
|
||||||
@@ -159,6 +166,27 @@ LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path);
|
|||||||
LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);
|
LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);
|
||||||
LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
||||||
|
|
||||||
|
struct bpf_link;
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
|
||||||
|
const char *func_name);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
|
||||||
|
pid_t pid, const char *binary_path,
|
||||||
|
size_t func_offset);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_tracepoint(struct bpf_program *prog,
|
||||||
|
const char *tp_category,
|
||||||
|
const char *tp_name);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||||
|
const char *tp_name);
|
||||||
|
|
||||||
struct bpf_insn;
|
struct bpf_insn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -221,7 +249,7 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
|
|||||||
LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
|
LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
|
||||||
bpf_program_prep_t prep);
|
bpf_program_prep_t prep);
|
||||||
|
|
||||||
LIBBPF_API int bpf_program__nth_fd(struct bpf_program *prog, int n);
|
LIBBPF_API int bpf_program__nth_fd(const struct bpf_program *prog, int n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust type of BPF program. Default is kprobe.
|
* Adjust type of BPF program. Default is kprobe.
|
||||||
@@ -240,14 +268,14 @@ LIBBPF_API void
|
|||||||
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||||
enum bpf_attach_type type);
|
enum bpf_attach_type type);
|
||||||
|
|
||||||
LIBBPF_API bool bpf_program__is_socket_filter(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_socket_filter(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_tracepoint(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_tracepoint(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_raw_tracepoint(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_raw_tracepoint(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_kprobe(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_kprobe(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_sched_cls(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_sched_cls(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_sched_act(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_xdp(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_perf_event(struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No need for __attribute__((packed)), all members of 'bpf_map_def'
|
* No need for __attribute__((packed)), all members of 'bpf_map_def'
|
||||||
@@ -269,10 +297,10 @@ struct bpf_map_def {
|
|||||||
*/
|
*/
|
||||||
struct bpf_map;
|
struct bpf_map;
|
||||||
LIBBPF_API struct bpf_map *
|
LIBBPF_API struct bpf_map *
|
||||||
bpf_object__find_map_by_name(struct bpf_object *obj, const char *name);
|
bpf_object__find_map_by_name(const struct bpf_object *obj, const char *name);
|
||||||
|
|
||||||
LIBBPF_API int
|
LIBBPF_API int
|
||||||
bpf_object__find_map_fd_by_name(struct bpf_object *obj, const char *name);
|
bpf_object__find_map_fd_by_name(const struct bpf_object *obj, const char *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get bpf_map through the offset of corresponding struct bpf_map_def
|
* Get bpf_map through the offset of corresponding struct bpf_map_def
|
||||||
@@ -282,7 +310,7 @@ LIBBPF_API struct bpf_map *
|
|||||||
bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset);
|
bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset);
|
||||||
|
|
||||||
LIBBPF_API struct bpf_map *
|
LIBBPF_API struct bpf_map *
|
||||||
bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
|
bpf_map__next(const struct bpf_map *map, const struct bpf_object *obj);
|
||||||
#define bpf_object__for_each_map(pos, obj) \
|
#define bpf_object__for_each_map(pos, obj) \
|
||||||
for ((pos) = bpf_map__next(NULL, (obj)); \
|
for ((pos) = bpf_map__next(NULL, (obj)); \
|
||||||
(pos) != NULL; \
|
(pos) != NULL; \
|
||||||
@@ -290,22 +318,22 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
|
|||||||
#define bpf_map__for_each bpf_object__for_each_map
|
#define bpf_map__for_each bpf_object__for_each_map
|
||||||
|
|
||||||
LIBBPF_API struct bpf_map *
|
LIBBPF_API struct bpf_map *
|
||||||
bpf_map__prev(struct bpf_map *map, struct bpf_object *obj);
|
bpf_map__prev(const struct bpf_map *map, const struct bpf_object *obj);
|
||||||
|
|
||||||
LIBBPF_API int bpf_map__fd(struct bpf_map *map);
|
LIBBPF_API int bpf_map__fd(const struct bpf_map *map);
|
||||||
LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map);
|
LIBBPF_API const struct bpf_map_def *bpf_map__def(const struct bpf_map *map);
|
||||||
LIBBPF_API const char *bpf_map__name(struct bpf_map *map);
|
LIBBPF_API const char *bpf_map__name(const struct bpf_map *map);
|
||||||
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
|
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
|
||||||
LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
|
LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
|
||||||
|
|
||||||
typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
|
typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
|
||||||
LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
||||||
bpf_map_clear_priv_t clear_priv);
|
bpf_map_clear_priv_t clear_priv);
|
||||||
LIBBPF_API void *bpf_map__priv(struct bpf_map *map);
|
LIBBPF_API void *bpf_map__priv(const struct bpf_map *map);
|
||||||
LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
|
LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
|
||||||
LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
|
LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
|
||||||
LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
||||||
LIBBPF_API bool bpf_map__is_internal(struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
||||||
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
||||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||||
@@ -320,6 +348,7 @@ struct bpf_prog_load_attr {
|
|||||||
enum bpf_attach_type expected_attach_type;
|
enum bpf_attach_type expected_attach_type;
|
||||||
int ifindex;
|
int ifindex;
|
||||||
int log_level;
|
int log_level;
|
||||||
|
int prog_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
||||||
@@ -330,6 +359,26 @@ LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
|||||||
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
|
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
|
||||||
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
||||||
|
|
||||||
|
struct perf_buffer;
|
||||||
|
|
||||||
|
typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
|
||||||
|
void *data, __u32 size);
|
||||||
|
typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
|
||||||
|
|
||||||
|
/* common use perf buffer options */
|
||||||
|
struct perf_buffer_opts {
|
||||||
|
/* if specified, sample_cb is called for each sample */
|
||||||
|
perf_buffer_sample_fn sample_cb;
|
||||||
|
/* if specified, lost_cb is called for each batch of lost samples */
|
||||||
|
perf_buffer_lost_fn lost_cb;
|
||||||
|
/* ctx is provided to sample_cb and lost_cb */
|
||||||
|
void *ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBBPF_API struct perf_buffer *
|
||||||
|
perf_buffer__new(int map_fd, size_t page_cnt,
|
||||||
|
const struct perf_buffer_opts *opts);
|
||||||
|
|
||||||
enum bpf_perf_event_ret {
|
enum bpf_perf_event_ret {
|
||||||
LIBBPF_PERF_EVENT_DONE = 0,
|
LIBBPF_PERF_EVENT_DONE = 0,
|
||||||
LIBBPF_PERF_EVENT_ERROR = -1,
|
LIBBPF_PERF_EVENT_ERROR = -1,
|
||||||
@@ -337,6 +386,35 @@ enum bpf_perf_event_ret {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct perf_event_header;
|
struct perf_event_header;
|
||||||
|
|
||||||
|
typedef enum bpf_perf_event_ret
|
||||||
|
(*perf_buffer_event_fn)(void *ctx, int cpu, struct perf_event_header *event);
|
||||||
|
|
||||||
|
/* raw perf buffer options, giving most power and control */
|
||||||
|
struct perf_buffer_raw_opts {
|
||||||
|
/* perf event attrs passed directly into perf_event_open() */
|
||||||
|
struct perf_event_attr *attr;
|
||||||
|
/* raw event callback */
|
||||||
|
perf_buffer_event_fn event_cb;
|
||||||
|
/* ctx is provided to event_cb */
|
||||||
|
void *ctx;
|
||||||
|
/* if cpu_cnt == 0, open all on all possible CPUs (up to the number of
|
||||||
|
* max_entries of given PERF_EVENT_ARRAY map)
|
||||||
|
*/
|
||||||
|
int cpu_cnt;
|
||||||
|
/* if cpu_cnt > 0, cpus is an array of CPUs to open ring buffers on */
|
||||||
|
int *cpus;
|
||||||
|
/* if cpu_cnt > 0, map_keys specify map keys to set per-CPU FDs for */
|
||||||
|
int *map_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBBPF_API struct perf_buffer *
|
||||||
|
perf_buffer__new_raw(int map_fd, size_t page_cnt,
|
||||||
|
const struct perf_buffer_raw_opts *opts);
|
||||||
|
|
||||||
|
LIBBPF_API void perf_buffer__free(struct perf_buffer *pb);
|
||||||
|
LIBBPF_API int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms);
|
||||||
|
|
||||||
typedef enum bpf_perf_event_ret
|
typedef enum bpf_perf_event_ret
|
||||||
(*bpf_perf_event_print_t)(struct perf_event_header *hdr,
|
(*bpf_perf_event_print_t)(struct perf_event_header *hdr,
|
||||||
void *private_data);
|
void *private_data);
|
||||||
@@ -447,6 +525,22 @@ bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
|
|||||||
LIBBPF_API void
|
LIBBPF_API void
|
||||||
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
|
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A helper function to get the number of possible CPUs before looking up
|
||||||
|
* per-CPU maps. Negative errno is returned on failure.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* int ncpus = libbpf_num_possible_cpus();
|
||||||
|
* if (ncpus < 0) {
|
||||||
|
* // error handling
|
||||||
|
* }
|
||||||
|
* long values[ncpus];
|
||||||
|
* bpf_map_lookup_elem(per_cpu_map_fd, key, values);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
LIBBPF_API int libbpf_num_possible_cpus(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -164,3 +164,29 @@ LIBBPF_0.0.3 {
|
|||||||
bpf_map_freeze;
|
bpf_map_freeze;
|
||||||
btf__finalize_data;
|
btf__finalize_data;
|
||||||
} LIBBPF_0.0.2;
|
} LIBBPF_0.0.2;
|
||||||
|
|
||||||
|
LIBBPF_0.0.4 {
|
||||||
|
global:
|
||||||
|
bpf_link__destroy;
|
||||||
|
bpf_object__load_xattr;
|
||||||
|
bpf_program__attach_kprobe;
|
||||||
|
bpf_program__attach_perf_event;
|
||||||
|
bpf_program__attach_raw_tracepoint;
|
||||||
|
bpf_program__attach_tracepoint;
|
||||||
|
bpf_program__attach_uprobe;
|
||||||
|
btf_dump__dump_type;
|
||||||
|
btf_dump__free;
|
||||||
|
btf_dump__new;
|
||||||
|
btf__parse_elf;
|
||||||
|
libbpf_num_possible_cpus;
|
||||||
|
perf_buffer__free;
|
||||||
|
perf_buffer__new;
|
||||||
|
perf_buffer__new_raw;
|
||||||
|
perf_buffer__poll;
|
||||||
|
xsk_umem__create;
|
||||||
|
} LIBBPF_0.0.3;
|
||||||
|
|
||||||
|
LIBBPF_0.0.5 {
|
||||||
|
global:
|
||||||
|
bpf_btf_get_next_id;
|
||||||
|
} LIBBPF_0.0.4;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#ifndef __LIBBPF_LIBBPF_INTERNAL_H
|
#ifndef __LIBBPF_LIBBPF_INTERNAL_H
|
||||||
#define __LIBBPF_LIBBPF_INTERNAL_H
|
#define __LIBBPF_LIBBPF_INTERNAL_H
|
||||||
|
|
||||||
|
#include "libbpf.h"
|
||||||
|
|
||||||
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
||||||
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
||||||
#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
|
#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
|
||||||
@@ -21,6 +23,33 @@
|
|||||||
#define BTF_PARAM_ENC(name, type) (name), (type)
|
#define BTF_PARAM_ENC(name, type) (name), (type)
|
||||||
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
# define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
#ifndef max
|
||||||
|
# define max(x, y) ((x) < (y) ? (y) : (x))
|
||||||
|
#endif
|
||||||
|
#ifndef offsetofend
|
||||||
|
# define offsetofend(TYPE, FIELD) \
|
||||||
|
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Symbol versioning is different between static and shared library.
|
||||||
|
* Properly versioned symbols are needed for shared library, but
|
||||||
|
* only the symbol of the new version is needed for static library.
|
||||||
|
*/
|
||||||
|
#ifdef SHARED
|
||||||
|
# define COMPAT_VERSION(internal_name, api_name, version) \
|
||||||
|
asm(".symver " #internal_name "," #api_name "@" #version);
|
||||||
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||||
|
asm(".symver " #internal_name "," #api_name "@@" #version);
|
||||||
|
#else
|
||||||
|
# define COMPAT_VERSION(internal_name, api_name, version)
|
||||||
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||||
|
extern typeof(internal_name) api_name \
|
||||||
|
__attribute__((alias(#internal_name)));
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void libbpf_print(enum libbpf_print_level level,
|
extern void libbpf_print(enum libbpf_print_level level,
|
||||||
const char *format, ...)
|
const char *format, ...)
|
||||||
__attribute__((format(printf, 2, 3)));
|
__attribute__((format(printf, 2, 3)));
|
||||||
@@ -34,7 +63,108 @@ do { \
|
|||||||
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
||||||
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
|
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||||
const char *str_sec, size_t str_len);
|
const char *str_sec, size_t str_len);
|
||||||
|
|
||||||
|
struct btf_ext_info {
|
||||||
|
/*
|
||||||
|
* info points to the individual info section (e.g. func_info and
|
||||||
|
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
||||||
|
*/
|
||||||
|
void *info;
|
||||||
|
__u32 rec_size;
|
||||||
|
__u32 len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define for_each_btf_ext_sec(seg, sec) \
|
||||||
|
for (sec = (seg)->info; \
|
||||||
|
(void *)sec < (seg)->info + (seg)->len; \
|
||||||
|
sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
|
||||||
|
(seg)->rec_size * sec->num_info)
|
||||||
|
|
||||||
|
#define for_each_btf_ext_rec(seg, sec, i, rec) \
|
||||||
|
for (i = 0, rec = (void *)&(sec)->data; \
|
||||||
|
i < (sec)->num_info; \
|
||||||
|
i++, rec = (void *)rec + (seg)->rec_size)
|
||||||
|
|
||||||
|
struct btf_ext {
|
||||||
|
union {
|
||||||
|
struct btf_ext_header *hdr;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
struct btf_ext_info func_info;
|
||||||
|
struct btf_ext_info line_info;
|
||||||
|
struct btf_ext_info offset_reloc_info;
|
||||||
|
__u32 data_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct btf_ext_info_sec {
|
||||||
|
__u32 sec_name_off;
|
||||||
|
__u32 num_info;
|
||||||
|
/* Followed by num_info * record_size number of bytes */
|
||||||
|
__u8 data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_func_info checked by the loader */
|
||||||
|
struct bpf_func_info_min {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_line_info checked by the loader */
|
||||||
|
struct bpf_line_info_min {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 file_name_off;
|
||||||
|
__u32 line_off;
|
||||||
|
__u32 line_col;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_offset_reloc checked by the loader
|
||||||
|
*
|
||||||
|
* Offset relocation captures the following data:
|
||||||
|
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
||||||
|
* its insn->imm field to be relocated with actual offset;
|
||||||
|
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
||||||
|
* offset;
|
||||||
|
* - access_str_off - offset into corresponding .BTF string section. String
|
||||||
|
* itself encodes an accessed field using a sequence of field and array
|
||||||
|
* indicies, separated by colon (:). It's conceptually very close to LLVM's
|
||||||
|
* getelementptr ([0]) instruction's arguments for identifying offset to
|
||||||
|
* a field.
|
||||||
|
*
|
||||||
|
* Example to provide a better feel.
|
||||||
|
*
|
||||||
|
* struct sample {
|
||||||
|
* int a;
|
||||||
|
* struct {
|
||||||
|
* int b[10];
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct sample *s = ...;
|
||||||
|
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||||
|
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||||
|
* // b is field #0 inside anon struct, accessing elem #5)
|
||||||
|
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||||
|
*
|
||||||
|
* type_id for all relocs in this example will capture BTF type id of
|
||||||
|
* `struct sample`.
|
||||||
|
*
|
||||||
|
* Such relocation is emitted when using __builtin_preserve_access_index()
|
||||||
|
* Clang built-in, passing expression that captures field address, e.g.:
|
||||||
|
*
|
||||||
|
* bpf_probe_read(&dst, sizeof(dst),
|
||||||
|
* __builtin_preserve_access_index(&src->a.b.c));
|
||||||
|
*
|
||||||
|
* In this case Clang will emit offset relocation recording necessary data to
|
||||||
|
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
||||||
|
*
|
||||||
|
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
||||||
|
*/
|
||||||
|
struct bpf_offset_reloc {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
__u32 access_str_off;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
|||||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||||
|
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -133,8 +134,8 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
|
|||||||
return errno != EINVAL && errno != EOPNOTSUPP;
|
return errno != EINVAL && errno != EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
|
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||||
const char *str_sec, size_t str_len)
|
const char *str_sec, size_t str_len)
|
||||||
{
|
{
|
||||||
struct btf_header hdr = {
|
struct btf_header hdr = {
|
||||||
.magic = BTF_MAGIC,
|
.magic = BTF_MAGIC,
|
||||||
@@ -157,14 +158,9 @@ int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
|
|||||||
memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
|
memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
|
||||||
|
|
||||||
btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false);
|
btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false);
|
||||||
if (btf_fd < 0) {
|
|
||||||
free(raw_btf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(btf_fd);
|
|
||||||
free(raw_btf);
|
free(raw_btf);
|
||||||
return 1;
|
return btf_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_sk_storage_btf(void)
|
static int load_sk_storage_btf(void)
|
||||||
@@ -190,7 +186,7 @@ static int load_sk_storage_btf(void)
|
|||||||
BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
|
BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
|
||||||
};
|
};
|
||||||
|
|
||||||
return libbpf__probe_raw_btf((char *)types, sizeof(types),
|
return libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||||
strs, sizeof(strs));
|
strs, sizeof(strs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +244,7 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
|||||||
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||||
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||||
case BPF_MAP_TYPE_DEVMAP:
|
case BPF_MAP_TYPE_DEVMAP:
|
||||||
|
case BPF_MAP_TYPE_DEVMAP_HASH:
|
||||||
case BPF_MAP_TYPE_SOCKMAP:
|
case BPF_MAP_TYPE_SOCKMAP:
|
||||||
case BPF_MAP_TYPE_CPUMAP:
|
case BPF_MAP_TYPE_CPUMAP:
|
||||||
case BPF_MAP_TYPE_XSKMAP:
|
case BPF_MAP_TYPE_XSKMAP:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
char *libbpf_strerror_r(int err, char *dst, int len)
|
char *libbpf_strerror_r(int err, char *dst, int len)
|
||||||
{
|
{
|
||||||
int ret = strerror_r(err, dst, len);
|
int ret = strerror_r(err < 0 ? -err : err, dst, len);
|
||||||
if (ret)
|
if (ret)
|
||||||
snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret);
|
snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret);
|
||||||
return dst;
|
return dst;
|
||||||
|
|||||||
201
src/xsk.c
201
src/xsk.c
@@ -60,10 +60,8 @@ struct xsk_socket {
|
|||||||
struct xsk_umem *umem;
|
struct xsk_umem *umem;
|
||||||
struct xsk_socket_config config;
|
struct xsk_socket_config config;
|
||||||
int fd;
|
int fd;
|
||||||
int xsks_map;
|
|
||||||
int ifindex;
|
int ifindex;
|
||||||
int prog_fd;
|
int prog_fd;
|
||||||
int qidconf_map_fd;
|
|
||||||
int xsks_map_fd;
|
int xsks_map_fd;
|
||||||
__u32 queue_id;
|
__u32 queue_id;
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
@@ -75,23 +73,6 @@ struct xsk_nl_info {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For 32-bit systems, we need to use mmap2 as the offsets are 64-bit.
|
|
||||||
* Unfortunately, it is not part of glibc.
|
|
||||||
*/
|
|
||||||
static inline void *xsk_mmap(void *addr, size_t length, int prot, int flags,
|
|
||||||
int fd, __u64 offset)
|
|
||||||
{
|
|
||||||
#ifdef __NR_mmap2
|
|
||||||
unsigned int page_shift = __builtin_ffs(getpagesize()) - 1;
|
|
||||||
long ret = syscall(__NR_mmap2, addr, length, prot, flags, fd,
|
|
||||||
(off_t)(offset >> page_shift));
|
|
||||||
|
|
||||||
return (void *)ret;
|
|
||||||
#else
|
|
||||||
return mmap(addr, length, prot, flags, fd, offset);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int xsk_umem__fd(const struct xsk_umem *umem)
|
int xsk_umem__fd(const struct xsk_umem *umem)
|
||||||
{
|
{
|
||||||
return umem ? umem->fd : -EINVAL;
|
return umem ? umem->fd : -EINVAL;
|
||||||
@@ -117,6 +98,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
|||||||
cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
||||||
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
||||||
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
||||||
|
cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +106,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
|||||||
cfg->comp_size = usr_cfg->comp_size;
|
cfg->comp_size = usr_cfg->comp_size;
|
||||||
cfg->frame_size = usr_cfg->frame_size;
|
cfg->frame_size = usr_cfg->frame_size;
|
||||||
cfg->frame_headroom = usr_cfg->frame_headroom;
|
cfg->frame_headroom = usr_cfg->frame_headroom;
|
||||||
|
cfg->flags = usr_cfg->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
||||||
@@ -150,9 +133,10 @@ static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||||
struct xsk_ring_prod *fill, struct xsk_ring_cons *comp,
|
__u64 size, struct xsk_ring_prod *fill,
|
||||||
const struct xsk_umem_config *usr_config)
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *usr_config)
|
||||||
{
|
{
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
struct xdp_umem_reg mr;
|
struct xdp_umem_reg mr;
|
||||||
@@ -183,6 +167,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
mr.len = size;
|
mr.len = size;
|
||||||
mr.chunk_size = umem->config.frame_size;
|
mr.chunk_size = umem->config.frame_size;
|
||||||
mr.headroom = umem->config.frame_headroom;
|
mr.headroom = umem->config.frame_headroom;
|
||||||
|
mr.flags = umem->config.flags;
|
||||||
|
|
||||||
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
|
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -211,10 +196,9 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = xsk_mmap(NULL, off.fr.desc +
|
map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64),
|
||||||
umem->config.fill_size * sizeof(__u64),
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
XDP_UMEM_PGOFF_FILL_RING);
|
||||||
umem->fd, XDP_UMEM_PGOFF_FILL_RING);
|
|
||||||
if (map == MAP_FAILED) {
|
if (map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
@@ -225,13 +209,13 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
fill->size = umem->config.fill_size;
|
fill->size = umem->config.fill_size;
|
||||||
fill->producer = map + off.fr.producer;
|
fill->producer = map + off.fr.producer;
|
||||||
fill->consumer = map + off.fr.consumer;
|
fill->consumer = map + off.fr.consumer;
|
||||||
|
fill->flags = map + off.fr.flags;
|
||||||
fill->ring = map + off.fr.desc;
|
fill->ring = map + off.fr.desc;
|
||||||
fill->cached_cons = umem->config.fill_size;
|
fill->cached_cons = umem->config.fill_size;
|
||||||
|
|
||||||
map = xsk_mmap(NULL,
|
map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
||||||
off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
XDP_UMEM_PGOFF_COMPLETION_RING);
|
||||||
umem->fd, XDP_UMEM_PGOFF_COMPLETION_RING);
|
|
||||||
if (map == MAP_FAILED) {
|
if (map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_mmap;
|
goto out_mmap;
|
||||||
@@ -242,6 +226,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
comp->size = umem->config.comp_size;
|
comp->size = umem->config.comp_size;
|
||||||
comp->producer = map + off.cr.producer;
|
comp->producer = map + off.cr.producer;
|
||||||
comp->consumer = map + off.cr.consumer;
|
comp->consumer = map + off.cr.consumer;
|
||||||
|
comp->flags = map + off.cr.flags;
|
||||||
comp->ring = map + off.cr.desc;
|
comp->ring = map + off.cr.desc;
|
||||||
|
|
||||||
*umem_ptr = umem;
|
*umem_ptr = umem;
|
||||||
@@ -256,6 +241,29 @@ out_umem_alloc:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct xsk_umem_config_v1 {
|
||||||
|
__u32 fill_size;
|
||||||
|
__u32 comp_size;
|
||||||
|
__u32 frame_size;
|
||||||
|
__u32 frame_headroom;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
|
||||||
|
__u64 size, struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *usr_config)
|
||||||
|
{
|
||||||
|
struct xsk_umem_config config;
|
||||||
|
|
||||||
|
memcpy(&config, usr_config, sizeof(struct xsk_umem_config_v1));
|
||||||
|
config.flags = 0;
|
||||||
|
|
||||||
|
return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp,
|
||||||
|
&config);
|
||||||
|
}
|
||||||
|
COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
|
||||||
|
DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
|
||||||
|
|
||||||
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
static const int log_buf_size = 16 * 1024;
|
static const int log_buf_size = 16 * 1024;
|
||||||
@@ -265,15 +273,11 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
/* This is the C-program:
|
/* This is the C-program:
|
||||||
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
||||||
* {
|
* {
|
||||||
* int *qidconf, index = ctx->rx_queue_index;
|
* int index = ctx->rx_queue_index;
|
||||||
*
|
*
|
||||||
* // A set entry here means that the correspnding queue_id
|
* // A set entry here means that the correspnding queue_id
|
||||||
* // has an active AF_XDP socket bound to it.
|
* // has an active AF_XDP socket bound to it.
|
||||||
* qidconf = bpf_map_lookup_elem(&qidconf_map, &index);
|
* if (bpf_map_lookup_elem(&xsks_map, &index))
|
||||||
* if (!qidconf)
|
|
||||||
* return XDP_ABORTED;
|
|
||||||
*
|
|
||||||
* if (*qidconf)
|
|
||||||
* return bpf_redirect_map(&xsks_map, index, 0);
|
* return bpf_redirect_map(&xsks_map, index, 0);
|
||||||
*
|
*
|
||||||
* return XDP_PASS;
|
* return XDP_PASS;
|
||||||
@@ -286,15 +290,10 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, -4),
|
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, -4),
|
||||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
||||||
BPF_LD_MAP_FD(BPF_REG_1, xsk->qidconf_map_fd),
|
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
||||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||||
BPF_MOV32_IMM(BPF_REG_0, 0),
|
|
||||||
/* if r1 == 0 goto +8 */
|
|
||||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 8),
|
|
||||||
BPF_MOV32_IMM(BPF_REG_0, 2),
|
BPF_MOV32_IMM(BPF_REG_0, 2),
|
||||||
/* r1 = *(u32 *)(r1 + 0) */
|
|
||||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, 0),
|
|
||||||
/* if r1 == 0 goto +5 */
|
/* if r1 == 0 goto +5 */
|
||||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
|
||||||
/* r2 = *(u32 *)(r10 - 4) */
|
/* r2 = *(u32 *)(r10 - 4) */
|
||||||
@@ -327,24 +326,24 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
|
|
||||||
static int xsk_get_max_queues(struct xsk_socket *xsk)
|
static int xsk_get_max_queues(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
struct ethtool_channels channels;
|
struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
|
||||||
struct ifreq ifr;
|
struct ifreq ifr = {};
|
||||||
int fd, err, ret;
|
int fd, err, ret;
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
channels.cmd = ETHTOOL_GCHANNELS;
|
|
||||||
ifr.ifr_data = (void *)&channels;
|
ifr.ifr_data = (void *)&channels;
|
||||||
strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ);
|
memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
|
||||||
|
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||||
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
||||||
if (err && errno != EOPNOTSUPP) {
|
if (err && errno != EOPNOTSUPP) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channels.max_combined == 0 || errno == EOPNOTSUPP)
|
if (err || channels.max_combined == 0)
|
||||||
/* If the device says it has no channels, then all traffic
|
/* If the device says it has no channels, then all traffic
|
||||||
* is sent to a single stream, so max queues = 1.
|
* is sent to a single stream, so max queues = 1.
|
||||||
*/
|
*/
|
||||||
@@ -366,18 +365,11 @@ static int xsk_create_bpf_maps(struct xsk_socket *xsk)
|
|||||||
if (max_queues < 0)
|
if (max_queues < 0)
|
||||||
return max_queues;
|
return max_queues;
|
||||||
|
|
||||||
fd = bpf_create_map_name(BPF_MAP_TYPE_ARRAY, "qidconf_map",
|
fd = bpf_create_map_name(BPF_MAP_TYPE_XSKMAP, "xsks_map",
|
||||||
sizeof(int), sizeof(int), max_queues, 0);
|
sizeof(int), sizeof(int), max_queues, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
xsk->qidconf_map_fd = fd;
|
|
||||||
|
|
||||||
fd = bpf_create_map_name(BPF_MAP_TYPE_XSKMAP, "xsks_map",
|
|
||||||
sizeof(int), sizeof(int), max_queues, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
close(xsk->qidconf_map_fd);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
xsk->xsks_map_fd = fd;
|
xsk->xsks_map_fd = fd;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -385,10 +377,8 @@ static int xsk_create_bpf_maps(struct xsk_socket *xsk)
|
|||||||
|
|
||||||
static void xsk_delete_bpf_maps(struct xsk_socket *xsk)
|
static void xsk_delete_bpf_maps(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
close(xsk->qidconf_map_fd);
|
bpf_map_delete_elem(xsk->xsks_map_fd, &xsk->queue_id);
|
||||||
close(xsk->xsks_map_fd);
|
close(xsk->xsks_map_fd);
|
||||||
xsk->qidconf_map_fd = -1;
|
|
||||||
xsk->xsks_map_fd = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
||||||
@@ -417,10 +407,9 @@ static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out_map_ids;
|
goto out_map_ids;
|
||||||
|
|
||||||
for (i = 0; i < prog_info.nr_map_ids; i++) {
|
xsk->xsks_map_fd = -1;
|
||||||
if (xsk->qidconf_map_fd != -1 && xsk->xsks_map_fd != -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
for (i = 0; i < prog_info.nr_map_ids; i++) {
|
||||||
fd = bpf_map_get_fd_by_id(map_ids[i]);
|
fd = bpf_map_get_fd_by_id(map_ids[i]);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -431,11 +420,6 @@ static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(map_info.name, "qidconf_map")) {
|
|
||||||
xsk->qidconf_map_fd = fd;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(map_info.name, "xsks_map")) {
|
if (!strcmp(map_info.name, "xsks_map")) {
|
||||||
xsk->xsks_map_fd = fd;
|
xsk->xsks_map_fd = fd;
|
||||||
continue;
|
continue;
|
||||||
@@ -445,40 +429,18 @@ static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
if (xsk->qidconf_map_fd < 0 || xsk->xsks_map_fd < 0) {
|
if (xsk->xsks_map_fd == -1)
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
xsk_delete_bpf_maps(xsk);
|
|
||||||
}
|
|
||||||
|
|
||||||
out_map_ids:
|
out_map_ids:
|
||||||
free(map_ids);
|
free(map_ids);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xsk_clear_bpf_maps(struct xsk_socket *xsk)
|
|
||||||
{
|
|
||||||
int qid = false;
|
|
||||||
|
|
||||||
bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0);
|
|
||||||
bpf_map_delete_elem(xsk->xsks_map_fd, &xsk->queue_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xsk_set_bpf_maps(struct xsk_socket *xsk)
|
static int xsk_set_bpf_maps(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
int qid = true, fd = xsk->fd, err;
|
return bpf_map_update_elem(xsk->xsks_map_fd, &xsk->queue_id,
|
||||||
|
&xsk->fd, 0);
|
||||||
err = bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
err = bpf_map_update_elem(xsk->xsks_map_fd, &xsk->queue_id, &fd, 0);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
out:
|
|
||||||
xsk_clear_bpf_maps(xsk);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
|
static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
|
||||||
@@ -497,26 +459,27 @@ static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = xsk_load_xdp_prog(xsk);
|
err = xsk_load_xdp_prog(xsk);
|
||||||
if (err)
|
if (err) {
|
||||||
goto out_maps;
|
xsk_delete_bpf_maps(xsk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
||||||
err = xsk_lookup_bpf_maps(xsk);
|
err = xsk_lookup_bpf_maps(xsk);
|
||||||
if (err)
|
if (err) {
|
||||||
goto out_load;
|
close(xsk->prog_fd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xsk_set_bpf_maps(xsk);
|
err = xsk_set_bpf_maps(xsk);
|
||||||
if (err)
|
if (err) {
|
||||||
goto out_load;
|
xsk_delete_bpf_maps(xsk);
|
||||||
|
close(xsk->prog_fd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_load:
|
|
||||||
close(xsk->prog_fd);
|
|
||||||
out_maps:
|
|
||||||
xsk_delete_bpf_maps(xsk);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||||
@@ -561,7 +524,8 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
strncpy(xsk->ifname, ifname, IFNAMSIZ);
|
memcpy(xsk->ifname, ifname, IFNAMSIZ - 1);
|
||||||
|
xsk->ifname[IFNAMSIZ - 1] = '\0';
|
||||||
|
|
||||||
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
|
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -594,11 +558,10 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rx) {
|
if (rx) {
|
||||||
rx_map = xsk_mmap(NULL, off.rx.desc +
|
rx_map = mmap(NULL, off.rx.desc +
|
||||||
xsk->config.rx_size * sizeof(struct xdp_desc),
|
xsk->config.rx_size * sizeof(struct xdp_desc),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||||
MAP_SHARED | MAP_POPULATE,
|
xsk->fd, XDP_PGOFF_RX_RING);
|
||||||
xsk->fd, XDP_PGOFF_RX_RING);
|
|
||||||
if (rx_map == MAP_FAILED) {
|
if (rx_map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
@@ -608,16 +571,16 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
rx->size = xsk->config.rx_size;
|
rx->size = xsk->config.rx_size;
|
||||||
rx->producer = rx_map + off.rx.producer;
|
rx->producer = rx_map + off.rx.producer;
|
||||||
rx->consumer = rx_map + off.rx.consumer;
|
rx->consumer = rx_map + off.rx.consumer;
|
||||||
|
rx->flags = rx_map + off.rx.flags;
|
||||||
rx->ring = rx_map + off.rx.desc;
|
rx->ring = rx_map + off.rx.desc;
|
||||||
}
|
}
|
||||||
xsk->rx = rx;
|
xsk->rx = rx;
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
tx_map = xsk_mmap(NULL, off.tx.desc +
|
tx_map = mmap(NULL, off.tx.desc +
|
||||||
xsk->config.tx_size * sizeof(struct xdp_desc),
|
xsk->config.tx_size * sizeof(struct xdp_desc),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||||
MAP_SHARED | MAP_POPULATE,
|
xsk->fd, XDP_PGOFF_TX_RING);
|
||||||
xsk->fd, XDP_PGOFF_TX_RING);
|
|
||||||
if (tx_map == MAP_FAILED) {
|
if (tx_map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_mmap_rx;
|
goto out_mmap_rx;
|
||||||
@@ -627,6 +590,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
tx->size = xsk->config.tx_size;
|
tx->size = xsk->config.tx_size;
|
||||||
tx->producer = tx_map + off.tx.producer;
|
tx->producer = tx_map + off.tx.producer;
|
||||||
tx->consumer = tx_map + off.tx.consumer;
|
tx->consumer = tx_map + off.tx.consumer;
|
||||||
|
tx->flags = tx_map + off.tx.flags;
|
||||||
tx->ring = tx_map + off.tx.desc;
|
tx->ring = tx_map + off.tx.desc;
|
||||||
tx->cached_cons = xsk->config.tx_size;
|
tx->cached_cons = xsk->config.tx_size;
|
||||||
}
|
}
|
||||||
@@ -643,8 +607,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
goto out_mmap_tx;
|
goto out_mmap_tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
xsk->qidconf_map_fd = -1;
|
xsk->prog_fd = -1;
|
||||||
xsk->xsks_map_fd = -1;
|
|
||||||
|
|
||||||
if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
||||||
err = xsk_setup_xdp_prog(xsk);
|
err = xsk_setup_xdp_prog(xsk);
|
||||||
@@ -708,8 +671,10 @@ void xsk_socket__delete(struct xsk_socket *xsk)
|
|||||||
if (!xsk)
|
if (!xsk)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xsk_clear_bpf_maps(xsk);
|
if (xsk->prog_fd != -1) {
|
||||||
xsk_delete_bpf_maps(xsk);
|
xsk_delete_bpf_maps(xsk);
|
||||||
|
close(xsk->prog_fd);
|
||||||
|
}
|
||||||
|
|
||||||
optlen = sizeof(off);
|
optlen = sizeof(off);
|
||||||
err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
||||||
|
|||||||
35
src/xsk.h
35
src/xsk.h
@@ -32,6 +32,7 @@ struct name { \
|
|||||||
__u32 *producer; \
|
__u32 *producer; \
|
||||||
__u32 *consumer; \
|
__u32 *consumer; \
|
||||||
void *ring; \
|
void *ring; \
|
||||||
|
__u32 *flags; \
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_XSK_RING(xsk_ring_prod);
|
DEFINE_XSK_RING(xsk_ring_prod);
|
||||||
@@ -76,6 +77,11 @@ xsk_ring_cons__rx_desc(const struct xsk_ring_cons *rx, __u32 idx)
|
|||||||
return &descs[idx & rx->mask];
|
return &descs[idx & rx->mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int xsk_ring_prod__needs_wakeup(const struct xsk_ring_prod *r)
|
||||||
|
{
|
||||||
|
return *r->flags & XDP_RING_NEED_WAKEUP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
||||||
{
|
{
|
||||||
__u32 free_entries = r->cached_cons - r->cached_prod;
|
__u32 free_entries = r->cached_cons - r->cached_prod;
|
||||||
@@ -162,20 +168,37 @@ static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
|||||||
return &((char *)umem_area)[addr];
|
return &((char *)umem_area)[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__extract_addr(__u64 addr)
|
||||||
|
{
|
||||||
|
return addr & XSK_UNALIGNED_BUF_ADDR_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__extract_offset(__u64 addr)
|
||||||
|
{
|
||||||
|
return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)
|
||||||
|
{
|
||||||
|
return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);
|
||||||
|
}
|
||||||
|
|
||||||
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
||||||
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||||
|
|
||||||
#define XSK_RING_CONS__DEFAULT_NUM_DESCS 2048
|
#define XSK_RING_CONS__DEFAULT_NUM_DESCS 2048
|
||||||
#define XSK_RING_PROD__DEFAULT_NUM_DESCS 2048
|
#define XSK_RING_PROD__DEFAULT_NUM_DESCS 2048
|
||||||
#define XSK_UMEM__DEFAULT_FRAME_SHIFT 11 /* 2048 bytes */
|
#define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
|
||||||
#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
|
#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
|
||||||
#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
|
#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
|
||||||
|
#define XSK_UMEM__DEFAULT_FLAGS 0
|
||||||
|
|
||||||
struct xsk_umem_config {
|
struct xsk_umem_config {
|
||||||
__u32 fill_size;
|
__u32 fill_size;
|
||||||
__u32 comp_size;
|
__u32 comp_size;
|
||||||
__u32 frame_size;
|
__u32 frame_size;
|
||||||
__u32 frame_headroom;
|
__u32 frame_headroom;
|
||||||
|
__u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags for the libbpf_flags field. */
|
/* Flags for the libbpf_flags field. */
|
||||||
@@ -195,6 +218,16 @@ LIBBPF_API int xsk_umem__create(struct xsk_umem **umem,
|
|||||||
struct xsk_ring_prod *fill,
|
struct xsk_ring_prod *fill,
|
||||||
struct xsk_ring_cons *comp,
|
struct xsk_ring_cons *comp,
|
||||||
const struct xsk_umem_config *config);
|
const struct xsk_umem_config *config);
|
||||||
|
LIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||||
|
void *umem_area, __u64 size,
|
||||||
|
struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *config);
|
||||||
|
LIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||||
|
void *umem_area, __u64 size,
|
||||||
|
struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *config);
|
||||||
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
||||||
const char *ifname, __u32 queue_id,
|
const char *ifname, __u32 queue_id,
|
||||||
struct xsk_umem *umem,
|
struct xsk_umem *umem,
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ function info() {
|
|||||||
echo -e "\033[33;1m$1\033[0m"
|
echo -e "\033[33;1m$1\033[0m"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function error() {
|
||||||
|
echo -e "\033[31;1m$1\033[0m"
|
||||||
|
}
|
||||||
|
|
||||||
function docker_exec() {
|
function docker_exec() {
|
||||||
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
||||||
}
|
}
|
||||||
@@ -26,43 +30,41 @@ for phase in "${PHASES[@]}"; do
|
|||||||
SETUP)
|
SETUP)
|
||||||
info "Setup phase"
|
info "Setup phase"
|
||||||
info "Using Debian $DEBIAN_RELEASE"
|
info "Using Debian $DEBIAN_RELEASE"
|
||||||
docker pull debian:$DEBIAN_RELEASE
|
docker pull debian:$DEBIAN_RELEASE
|
||||||
info "Starting container $CONT_NAME"
|
info "Starting container $CONT_NAME"
|
||||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||||
-w /build --privileged=true --name $CONT_NAME \
|
-w /build --privileged=true --name $CONT_NAME \
|
||||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||||
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||||
docker_exec apt-get -y update
|
docker_exec apt-get -y update
|
||||||
docker_exec apt-get -y build-dep libelf-dev
|
docker_exec apt-get -y build-dep libelf-dev
|
||||||
docker_exec apt-get -y install libelf-dev
|
docker_exec apt-get -y install libelf-dev
|
||||||
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
||||||
;;
|
;;
|
||||||
RUN|RUN_CLANG|RUN_GCC8)
|
RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
||||||
if [[ "$phase" = "RUN_CLANG" ]]; then
|
if [[ "$phase" = *"CLANG"* ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
CC="clang"
|
CC="clang"
|
||||||
elif [[ "$phase" = "RUN_GCC8" ]]; then
|
elif [[ "$phase" = *"GCC8"* ]]; then
|
||||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
||||||
CC="gcc-8"
|
CC="gcc-8"
|
||||||
fi
|
fi
|
||||||
docker_exec mkdir build
|
if [[ "$phase" = *"ASAN"* ]]; then
|
||||||
docker_exec ${CC:-cc} --version
|
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
|
||||||
docker_exec rm -rf build
|
|
||||||
;;
|
|
||||||
RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
|
||||||
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
|
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
|
||||||
CC="clang"
|
|
||||||
elif [[ "$phase" = "RUN_GCC8_ASAN" ]]; then
|
|
||||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
|
||||||
CC="gcc-8"
|
|
||||||
fi
|
fi
|
||||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
docker_exec mkdir build install
|
||||||
docker_exec mkdir build
|
|
||||||
docker_exec ${CC:-cc} --version
|
docker_exec ${CC:-cc} --version
|
||||||
|
info "build"
|
||||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
docker_exec rm -rf build
|
info "ldd build/libbpf.so:"
|
||||||
|
docker_exec ldd build/libbpf.so
|
||||||
|
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||||
|
error "No reference to libelf.so in libbpf.so!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
info "install"
|
||||||
|
docker_exec make -C src OBJDIR=../build DESTDIR=../install install
|
||||||
|
docker_exec rm -rf build install
|
||||||
;;
|
;;
|
||||||
CLEANUP)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
|
|||||||
@@ -11,7 +11,13 @@ source "$(dirname $0)/travis_wait.bash"
|
|||||||
cd $REPO_ROOT
|
cd $REPO_ROOT
|
||||||
|
|
||||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
||||||
mkdir build
|
mkdir build install
|
||||||
cc --version
|
cc --version
|
||||||
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
rm -rf build
|
ldd build/libbpf.so
|
||||||
|
if ! ldd build/libbpf.so | grep -q libelf; then
|
||||||
|
echo "FAIL: No reference to libelf.so in libbpf.so!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
make -C src OBJDIR=../build DESTDIR=../install install
|
||||||
|
rm -rf build install
|
||||||
|
|||||||
Reference in New Issue
Block a user