初学XDP/eBPF常用的一些结构体和函数、概念

前言

作为自己学XDP、eBPF的一个记录和参考,同时包括对一些概念的理解,后续会陆续补充;

结构体(libbpf中的)

疑问:
为什么linux源码里面有些结构体能找到两个定义?

xdp_md

/* user accessible metadata for XDP packet hook
 * new fields must be added to the end of this structure
 * XDP钩子上的eBPF程序可以访问的数据包元数据,md即meta data
 */
struct xdp_md {
	__u32 data; // 指向数据包的起点
	__u32 data_end; // 指向数据包的末尾
	__u32 data_meta; // ...
	/* Below access go through struct xdp_rxq_info */
	__u32 ingress_ifindex; /* rxq->dev->ifindex 网卡的序号,ip link显示的那个 */
	__u32 rx_queue_index;  /* rxq->queue_index 网卡接收队列的序号 */

	__u32 egress_ifindex;  /* txq->dev->ifindex 这个参数旧一些的内核是没有的 */
};

struct bpf_map

这里我放了libbpf.c里面的定义:

可以通过bpf_object__find_map_by_name获取;

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;
};

然后如下是/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

这个结构体是读取编译得来的.o文件得到的,包含了整个BPF程序的内容。

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[];
};

函数(libbpc中的)

bpf_object__find_map_by_name

功能:通过指定结构体bpf_object指针和映射名称name,返回映射结构体bpf_map

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

bpf_map__***

bpf_map__name

功能:输入结构体bpf_map指针,返回映射名称,会检查指针是否为空,若为空返回空指针;

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

注:NULL、0都是一个东西,只是一般习惯用NULL代指空指针;

bpf_map__fd

功能:输入结构体bpf_map指针,返回映射fd,会检查指针是否为空,若为空返回-EINVAL(即-22,一般定义为invalid argument);

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

相关的其他函数/结构体

setrlimit/getlimit

全称即SET/GET Resource LIMIT

功能:设定或获取资源使用限制。输入resource参数和rlimit结构体,成功返回0,失败返回对应失败码的负数;当前进程和其以后fork的子进程会遵循此限制,而其他进程不受当前进程条件的影响。

resource有固定的的几个取值,定义在了sys/resource.h中;我只介绍我用到的:

RLIMIT_MEMLOCK:调整进程可以锁定在内存中的最大数据量,以字节为单位;

#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim); // 返回方式就是直接把传入指针指向的结构体赋值;
int setrlimit(int resource, const struct rlimit *rlim); // const常量修饰符的意义在于,整个作用域内(这里就是在setrlimit函数中),该值都保持固定;(也是规定以后的修改都不要在该作用域对该指针进行修改吗?)

struct rlimit {
	__kernel_ulong_t	rlim_cur; // Resource LIMit_CURrent 当前设定值
	__kernel_ulong_t	rlim_max; // Resource LIMit_MAX 设定最大值
}; // 这里__kernel_ulong_t是unsigned long的又一个宏定义,知道是为了作出区分,但还是理解不了为什么非得区分;

例:

struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY}; // 当前设定和最大值都设为无限,这是sys/resource.h中的宏定义,见下方

if (setrlimit(RLIMIT_MEMLOCK, &rlim)) {
    fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n",
            strerror(errno));
    exit(EXIT_FAILURE);
}
——————————————————————————————————————————————
/* 这是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)   // 注意0UL意味着unsigned long,取反自然就是2^64-1(2进制64位都是1)
#endif

关于这个资源限制再多说两句

主要是了解一下背景;

很感谢各种博客让我打开了思路,但是网上资料鱼龙混杂,还是得自己试一遍。

linux下每个进程都是有资源限制的,如最大可打开的文件数量、最大可锁定的内存等,使用shell中的内置命令ulimit可以查看或修改shell自身的资源限制,其实也是调用了自身的setrlimit()/getrlimit()函数,其他进程也可以直接调用这俩函数;

shell中查看软硬资源限制的方法:

ulimit -aS # 查看软资源限制,不加S默认显示软限制
ulimit -aH # 查看硬资源限制,

注:你的shell终端,也就是bash,也是一个进程,也有自己的资源限制;是在系统启动时pam_limits设定的,用户登录后,pam_limits 会给用户的 shell 设定在/etc/security/limits.conf定义的值(暂时就知道系统启动时会设定就好了…)

再注:了解了以后就知道ulimit设置只针对本shell进程和其子进程有效,用在rc.local开机启动项里面也没用;

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WuPeng_uin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值