文章目录
前言
作为自己学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开机启动项里面也没用;