/* Probe whether kernel switched from memlock-based (RLIMIT_MEMLOCK) to * memcg-based memory accounting for BPF maps and programs. This was done in * commit 97306be45fbe ("Merge branch 'switch to memcg-based memory * accounting'"), in Linux 5.11. * * Libbpf also offers to probe for memcg-based accounting vs rlimit, but does * so by checking for the availability of a given BPF helper and this has * failed on some kernels with backports in the past, see commit 6b4384ff1088 * ("Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK""). * Instead, we can probe by lowering the process-based rlimit to 0, trying to * load a BPF object, and resetting the rlimit. If the load succeeds then * memcg-based accounting is supported. * * This would be too dangerous to do in the library, because multithreaded * applications might attempt to load items while the rlimit is at 0. Given * that bpftool is single-threaded, this is fine to do here.
*/ staticbool known_to_need_rlimit(void)
{ struct rlimit rlim_init, rlim_cur_zero = {}; struct bpf_insn insns[] = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};
size_t insn_cnt = ARRAY_SIZE(insns); union bpf_attr attr; int prog_fd, err;
if (getrlimit(RLIMIT_MEMLOCK, &rlim_init)) returnfalse;
/* Drop the soft limit to zero. We maintain the hard limit to its * current value, because lowering it would be a permanent operation * for unprivileged users.
*/
rlim_cur_zero.rlim_max = rlim_init.rlim_max; if (setrlimit(RLIMIT_MEMLOCK, &rlim_cur_zero)) returnfalse;
/* Do not use bpf_prog_load() from libbpf here, because it calls * bump_rlimit_memlock(), interfering with the current probe.
*/
prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
err = errno;
/* reset soft rlimit to its initial value */
setrlimit(RLIMIT_MEMLOCK, &rlim_init);
if (is_bpffs(parent_name)) { /* nothing to do if already mounted */
free(temp_name); return err;
}
if (access(parent_name, F_OK) == -1) {
p_err("can't create dir '%s' to pin BPF object: parent dir '%s' doesn't exist",
dir_name, parent_name);
free(temp_name); return -1;
}
free(temp_name);
}
if (block_mount) {
p_err("no BPF file system found, not mounting it due to --nomount option"); return -1;
}
if (!dir_exists) {
err = mkdir(dir_name, S_IRWXU); if (err) {
p_err("failed to create dir '%s': %s", dir_name, strerror(errno)); return err;
}
}
err = mnt_fs(dir_name, "bpf", err_str, ERR_MAX_LEN); if (err) {
err_str[ERR_MAX_LEN - 1] = '\0';
p_err("can't mount BPF file system on given dir '%s': %s",
dir_name, err_str);
if (!dir_exists)
rmdir(dir_name);
}
return err;
}
int mount_bpffs_for_file(constchar *file_name)
{ char err_str[ERR_MAX_LEN]; char *temp_name; char *dir; int err = 0;
constchar *
ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, constchar **opt)
{
__maybe_unused int device_id; char devname[IF_NAMESIZE]; int vendor_id;
if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
p_err("Can't get net device name for ifindex %u: %s", ifindex,
strerror(errno)); return NULL;
}
vendor_id = read_sysfs_netdev_hex_int(devname, "vendor"); if (vendor_id < 0) {
p_err("Can't get device vendor id for %s", devname); return NULL;
}
switch (vendor_id) { #ifdef HAVE_LIBBFD_SUPPORT case 0x19ee:
device_id = read_sysfs_netdev_hex_int(devname, "device"); if (device_id != 0x4000 &&
device_id != 0x6000 &&
device_id != 0x6003)
p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
*opt = "ctx4"; return"NFP-6xxx"; #endif/* HAVE_LIBBFD_SUPPORT */ /* No NFP support in LLVM, we have no valid triple to return. */ default:
p_err("Can't get arch name for device vendor id 0x%04x",
(unsignedint)vendor_id); return NULL;
}
}
int prog_parse_fds(int *argc, char ***argv, int **fds)
{ if (is_prefix(**argv, "id")) { unsignedint id; char *endptr;
NEXT_ARGP();
id = strtoul(**argv, &endptr, 0); if (*endptr) {
p_err("can't parse %s as ID", **argv); return -1;
}
NEXT_ARGP();
(*fds)[0] = bpf_prog_get_fd_by_id(id); if ((*fds)[0] < 0) {
p_err("get by id (%u): %s", id, strerror(errno)); return -1;
} return 1;
} elseif (is_prefix(**argv, "tag")) { unsignedchar tag[BPF_TAG_SIZE];
NEXT_ARGP();
if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
!= BPF_TAG_SIZE) {
p_err("can't parse tag"); return -1;
}
NEXT_ARGP();
int prog_parse_fd(int *argc, char ***argv)
{ int *fds = NULL; int nb_fds, fd;
fds = malloc(sizeof(int)); if (!fds) {
p_err("mem alloc failed"); return -1;
}
nb_fds = prog_parse_fds(argc, argv, &fds); if (nb_fds != 1) { if (nb_fds > 1) {
p_err("several programs match this handle"); while (nb_fds--)
close(fds[nb_fds]);
}
fd = -1; goto exit_free;
}
fd = fds[0];
exit_free:
free(fds); return fd;
}
staticint map_fd_by_name(char *name, int **fds, conststruct bpf_get_fd_by_id_opts *opts)
{ unsignedint id = 0; int fd, nb_fds = 0; void *tmp; int err;
while (true) {
LIBBPF_OPTS(bpf_get_fd_by_id_opts, opts_ro); struct bpf_map_info info = {};
__u32 len = sizeof(info);
err = bpf_map_get_next_id(id, &id); if (err) { if (errno != ENOENT) {
p_err("%s", strerror(errno)); goto err_close_fds;
} return nb_fds;
}
/* Request a read-only fd to query the map info */
opts_ro.open_flags = BPF_F_RDONLY;
fd = bpf_map_get_fd_by_id_opts(id, &opts_ro); if (fd < 0) {
p_err("can't get map by id (%u): %s",
id, strerror(errno)); goto err_close_fds;
}
err = bpf_map_get_info_by_fd(fd, &info, &len); if (err) {
p_err("can't get map info (%u): %s",
id, strerror(errno)); goto err_close_fd;
}
if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
close(fd); continue;
}
/* Get an fd with the requested options, if they differ * from the read-only options used to get the fd above.
*/ if (memcmp(opts, &opts_ro, sizeof(opts_ro))) {
close(fd);
fd = bpf_map_get_fd_by_id_opts(id, opts); if (fd < 0) {
p_err("can't get map by id (%u): %s", id,
strerror(errno)); goto err_close_fds;
}
}
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); if (!tmp) {
p_err("failed to realloc"); goto err_close_fd;
}
*fds = tmp;
}
(*fds)[nb_fds++] = fd;
}
constchar *bpf_attach_type_input_str(enum bpf_attach_type t)
{ switch (t) { case BPF_CGROUP_INET_INGRESS: return"ingress"; case BPF_CGROUP_INET_EGRESS: return"egress"; case BPF_CGROUP_INET_SOCK_CREATE: return"sock_create"; case BPF_CGROUP_INET_SOCK_RELEASE: return"sock_release"; case BPF_CGROUP_SOCK_OPS: return"sock_ops"; case BPF_CGROUP_DEVICE: return"device"; case BPF_CGROUP_INET4_BIND: return"bind4"; case BPF_CGROUP_INET6_BIND: return"bind6"; case BPF_CGROUP_INET4_CONNECT: return"connect4"; case BPF_CGROUP_INET6_CONNECT: return"connect6"; case BPF_CGROUP_INET4_POST_BIND: return"post_bind4"; case BPF_CGROUP_INET6_POST_BIND: return"post_bind6"; case BPF_CGROUP_INET4_GETPEERNAME: return"getpeername4"; case BPF_CGROUP_INET6_GETPEERNAME: return"getpeername6"; case BPF_CGROUP_INET4_GETSOCKNAME: return"getsockname4"; case BPF_CGROUP_INET6_GETSOCKNAME: return"getsockname6"; case BPF_CGROUP_UDP4_SENDMSG: return"sendmsg4"; case BPF_CGROUP_UDP6_SENDMSG: return"sendmsg6"; case BPF_CGROUP_SYSCTL: return"sysctl"; case BPF_CGROUP_UDP4_RECVMSG: return"recvmsg4"; case BPF_CGROUP_UDP6_RECVMSG: return"recvmsg6"; case BPF_CGROUP_GETSOCKOPT: return"getsockopt"; case BPF_CGROUP_SETSOCKOPT: return"setsockopt"; case BPF_TRACE_RAW_TP: return"raw_tp"; case BPF_TRACE_FENTRY: return"fentry"; case BPF_TRACE_FEXIT: return"fexit"; case BPF_MODIFY_RETURN: return"mod_ret"; case BPF_SK_REUSEPORT_SELECT: return"sk_skb_reuseport_select"; case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return"sk_skb_reuseport_select_or_migrate"; default: return libbpf_bpf_attach_type_str(t);
}
}
int pathname_concat(char *buf, int buf_sz, constchar *path, constchar *name)
{ int len;
len = snprintf(buf, buf_sz, "%s/%s", path, name); if (len < 0) return -EINVAL; if (len >= buf_sz) return -ENAMETOOLONG;
return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.