Learn some structures, functions and concepts commonly used in XDP/eBPF

preface

As a record and reference for learning XDP and eBPF, it also includes the understanding of some concepts, which will be supplemented in the future;

Structure (in libbpf)

doubt:
Why can some structures in the linux source code find two definitions?

xdp_md

/* user accessible metadata for XDP packet hook
 * new fields must be added to the end of this structure
 * XDP The eBPF program on the hook can access the packet metadata, md, that is, meta data
 */
struct xdp_md {
	__u32 data; // Point to the starting point of the packet
	__u32 data_end; // Point to the end of the packet
	__u32 data_meta; // ...
	/* Below access go through struct xdp_rxq_info */
	__u32 ingress_ifindex; /* rxq->dev->ifindex The serial number of the network card, the one displayed by the ip link */
	__u32 rx_queue_index;  /* rxq->queue_index Serial number of network card reception queue */

	__u32 egress_ifindex;  /* txq->dev->ifindex This parameter is not available in older kernels */
};

struct bpf_map

Here I put the definition in libbpf.c:

You can use bpf_object__find_map_by_name get;

struct bpf_map {
	char *name;
	int fd;
	int sec_idx;
	size_t sec_offset;
	int map_ifindex;
	int inner_map_fd;
	struct bpf_map_def def;
	__u32 numa_node;
	__u32 btf_var_idx;
	__u32 btf_key_type_id;
	__u32 btf_value_type_id;
	__u32 btf_vmlinux_value_type_id;
	void *priv;
	bpf_map_clear_priv_t clear_priv;
	enum libbpf_map_type libbpf_type;
	void *mmaped;
	struct bpf_struct_ops *st_ops;
	struct bpf_map *inner_map;
	void **init_slots;
	int init_slots_sz;
	char *pin_path;
	bool pinned;
	bool reused;
};

Then the following is the definition of / include/linux/bpf.h:

struct bpf_map {
	/* The first two cachelines with read-mostly members of which some
	 * are also accessed in fast-path (e.g. ops, max_entries).
	 */
	const struct bpf_map_ops *ops ____cacheline_aligned;
	struct bpf_map *inner_map_meta;
#ifdef CONFIG_SECURITY
	void *security;
#endif
	enum bpf_map_type map_type;
	u32 key_size;
	u32 value_size;
	u32 max_entries;
	u32 map_flags;
	int spin_lock_off; /* >=0 valid offset, <0 error */
	u32 id;
	int numa_node;
	u32 btf_key_type_id;
	u32 btf_value_type_id;
	struct btf *btf;
#ifdef CONFIG_MEMCG_KMEM
	struct mem_cgroup *memcg;
#endif
	char name[BPF_OBJ_NAME_LEN];
	u32 btf_vmlinux_value_type_id;
	bool bypass_spec_v1;
	bool frozen; /* write-once; write-protected by freeze_mutex */
	/* 22 bytes hole */

	/* The 3rd and 4th cacheline with misc members to avoid false sharing
	 * particularly with refcounting.
	 */
	atomic64_t refcnt ____cacheline_aligned;
	atomic64_t usercnt;
	struct work_struct work;
	struct mutex freeze_mutex;
	u64 writecnt; /* writable mmap cnt; protected by freeze_mutex */
};

struct bpf_object

This structure is obtained by reading the compiled. o file, which contains the contents of the whole BPF program.

struct bpf_object {
	char name[BPF_OBJ_NAME_LEN];
	char license[64];
	__u32 kern_version;

	struct bpf_program *programs;
	size_t nr_programs;
	struct bpf_map *maps;
	size_t nr_maps;
	size_t maps_cap;

	char *kconfig;
	struct extern_desc *externs;
	int nr_extern;
	int kconfig_map_idx;
	int rodata_map_idx;

	bool loaded;
	bool has_subcalls;

	struct bpf_gen *gen_loader;

	/*
	 * Information when doing elf related work. Only valid if fd
	 * is valid.
	 */
	struct {
		int fd;
		const void *obj_buf;
		size_t obj_buf_sz;
		Elf *elf;
		GElf_Ehdr ehdr;
		Elf_Data *symbols;
		Elf_Data *data;
		Elf_Data *rodata;
		Elf_Data *bss;
		Elf_Data *st_ops_data;
		size_t shstrndx; /* section index for section name strings */
		size_t strtabidx;
		struct {
			GElf_Shdr shdr;
			Elf_Data *data;
		} *reloc_sects;
		int nr_reloc_sects;
		int maps_shndx;
		int btf_maps_shndx;
		__u32 btf_maps_sec_btf_id;
		int text_shndx;
		int symbols_shndx;
		int data_shndx;
		int rodata_shndx;
		int bss_shndx;
		int st_ops_shndx;
	} efile;
	/*
	 * All loaded bpf_object is linked in a list, which is
	 * hidden to caller. bpf_objects__<func> handlers deal with
	 * all objects.
	 */
	struct list_head list;

	struct btf *btf;
	struct btf_ext *btf_ext;

	/* Parse and load BTF vmlinux if any of the programs in the object need
	 * it at load time.
	 */
	struct btf *btf_vmlinux;
	/* vmlinux BTF override for CO-RE relocations */
	struct btf *btf_vmlinux_override;
	/* Lazily initialized kernel module BTFs */
	struct module_btf *btf_modules;
	bool btf_modules_loaded;
	size_t btf_module_cnt;
	size_t btf_module_cap;

	void *priv;
	bpf_object_clear_priv_t clear_priv;

	char path[];
};

Functions (in libbpc)

bpf_object__find_map_by_name

Function: BPF by specifying structure_ Object pointer and mapping name, return mapping structure bpf_map´╝Ť

struct bpf_map *bpf_object__find_map_by_name(const struct bpf_object *obj, const char *name);

bpf_map__***

bpf_map__name

Function: input structure bpf_map pointer, which returns the mapping name. It will check whether the pointer is empty. If it is empty, it will return a null pointer;

const char *bpf_map__name(const struct bpf_map *map)
{
	return map ? map->name : NULL;
}

Note: NULL and 0 are the same thing, but it is common to use NULL to refer to NULL pointer;

bpf_map__fd

Function: input structure BPF_ The map pointer returns the mapping fd. It will check whether the pointer is null. If it is null, it will return - EINVAL (i.e. - 22, generally defined as invalid argument);

int bpf_map__fd(const struct bpf_map *map)
{
	return map ? map->fd : -EINVAL;
}

Other related functions / structures

setrlimit/getlimit

Full name: SET/GET Resource LIMIT;

Function: set or obtain resource usage restrictions. Enter the resource parameter and rlimit structure. 0 will be returned for success, and a negative number corresponding to the failure code will be returned for failure; The current process and its subsequent fork child processes will follow this restriction, while other processes are not affected by the current process conditions.

Resource has several fixed values, which are defined in sys/resource.h; I'll just introduce what I use:

RLIMIT_MEMLOCK: the maximum amount of data that the adjustment process can lock in memory, in bytes;

#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim); // The return method is to directly assign a value to the structure pointed to by the incoming pointer;
int setrlimit(int resource, const struct rlimit *rlim); // The meaning of const constant modifier is that the value remains fixed throughout the scope (here in the setrlimit function); (does it also stipulate that the pointer should not be modified in this scope in future modifications?)

struct rlimit {
	__kernel_ulong_t	rlim_cur; // Resource LIMit_CURrent current setting
	__kernel_ulong_t	rlim_max; // Resource LIMit_MAX set maximum
}; // Here__ kernel_ulong_t is another macro definition of unsigned long. I know it is to distinguish, but I still can't understand why I have to distinguish;

Example:

struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY}; // The current setting and maximum value are set to infinite, which is the macro definition in sys/resource.h, as shown below

if (setrlimit(RLIMIT_MEMLOCK, &rlim)) {
    fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n",
            strerror(errno));
    exit(EXIT_FAILURE);
}
-----------------------
/* This is a comment in sys/resource.h
 * SuS says limits have to be unsigned.
 * Which makes a ton more sense anyway.
 *
 * Some architectures override this (for compatibility reasons):
 */
#ifndef RLIM_INFINITY
# define RLIM_INFINITY 		 (~ 0UL) / / note that 0UL means unsigned long, and the reverse is naturally 2 ^ 64-1 (all binary 64 bits are 1)
#endif

Say more about this resource limitation

Mainly to understand the background;

I'm grateful to all kinds of blogs for opening my mind, but the online materials are mixed, so I have to try it myself.

Under linux, each process has resource limits, such as the maximum number of files that can be opened, the maximum lockable memory, etc. the built-in command ulimit in the shell can be used to view or modify the resource limits of the shell itself. In fact, it also calls its own setrlimit()/getrlimit() function, and other processes can also call these two functions directly;

shell How to view hardware and software resource limits in:

ulimit -aS # View the soft resource limit without S. The soft limit is displayed by default
ulimit -aH # View hard resource limits,

Note: your shell terminal, bash, is also a process and has its own resource constraints; PAM at system startup_ Limits is set. After the user logs in, pam_limits will set the user's shell to the value defined in / etc/security/limits.conf (just know that it will be set when the system starts...)

Note: after understanding, you will know that ulimit setting is only valid for this shell process and its child processes, and it is useless in rc.local startup item;

Tags: Linux

Posted on Fri, 19 Nov 2021 14:47:33 -0500 by louisA2A