/*
* virbpf.c: methods for eBPF
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include "virlog.h"
#include "virerror.h"
#include "virbpf.h"
VIR_LOG_INIT("util.bpf");
#define VIR_FROM_THIS VIR_FROM_BPF
#if HAVE_SYS_SYSCALL_H && HAVE_DECL_BPF_PROG_QUERY
# include
# include
int
virBPFCreateMap(unsigned int mapType,
unsigned int keySize,
unsigned int valSize,
unsigned int maxEntries)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_type = mapType;
attr.key_size = keySize;
attr.value_size = valSize;
attr.max_entries = maxEntries;
return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}
# define LOG_BUF_SIZE (256 * 1024)
int
virBPFLoadProg(struct bpf_insn *insns,
int progType,
unsigned int insnCnt)
{
g_autofree char *logbuf = NULL;
int progfd = -1;
union bpf_attr attr;
logbuf = g_new0(char, LOG_BUF_SIZE);
memset(&attr, 0, sizeof(attr));
attr.prog_type = progType;
attr.insn_cnt = insnCnt;
attr.insns = (uintptr_t)insns;
attr.license = (uintptr_t)"GPL";
attr.log_buf = (uintptr_t)logbuf;
attr.log_size = LOG_BUF_SIZE;
attr.log_level = 1;
progfd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (progfd < 0)
VIR_DEBUG("%s", logbuf);
return progfd;
}
int
virBPFAttachProg(int progfd,
int targetfd,
int attachType)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.target_fd = targetfd;
attr.attach_bpf_fd = progfd;
attr.attach_type = attachType;
return syscall(SYS_bpf, BPF_PROG_ATTACH, &attr, sizeof(attr));
}
int
virBPFDetachProg(int progfd,
int targetfd,
int attachType)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.target_fd = targetfd;
attr.attach_bpf_fd = progfd;
attr.attach_type = attachType;
return syscall(SYS_bpf, BPF_PROG_DETACH, &attr, sizeof(attr));
}
int
virBPFQueryProg(int targetfd,
unsigned int maxprogids,
int attachType,
unsigned int *progcnt,
void *progids)
{
union bpf_attr attr;
int rc;
memset(&attr, 0, sizeof(attr));
attr.query.target_fd = targetfd;
attr.query.attach_type = attachType;
attr.query.prog_cnt = maxprogids;
attr.query.prog_ids = (uintptr_t)progids;
rc = syscall(SYS_bpf, BPF_PROG_QUERY, &attr, sizeof(attr));
if (rc >= 0)
*progcnt = attr.query.prog_cnt;
return rc;
}
int
virBPFGetProg(unsigned int id)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.prog_id = id;
return syscall(SYS_bpf, BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
}
int
virBPFGetProgInfo(int progfd,
struct bpf_prog_info *info,
unsigned int **mapIDs)
{
union bpf_attr attr;
int rc;
memset(&attr, 0, sizeof(attr));
attr.info.bpf_fd = progfd;
attr.info.info_len = sizeof(struct bpf_prog_info);
attr.info.info = (uintptr_t)info;
rc = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
if (rc < 0)
return rc;
if (mapIDs && info->nr_map_ids > 0) {
unsigned int maplen = info->nr_map_ids;
g_autofree unsigned int *retmapIDs = NULL;
retmapIDs = g_new0(unsigned int, maplen);
memset(info, 0, sizeof(struct bpf_prog_info));
info->nr_map_ids = maplen;
info->map_ids = (uintptr_t)retmapIDs;
memset(&attr, 0, sizeof(attr));
attr.info.bpf_fd = progfd;
attr.info.info_len = sizeof(struct bpf_prog_info);
attr.info.info = (uintptr_t)info;
rc = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
if (rc < 0)
return rc;
*mapIDs = g_steal_pointer(&retmapIDs);
}
return rc;
}
int
virBPFGetMap(unsigned int id)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_id = id;
return syscall(SYS_bpf, BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
}
int
virBPFGetMapInfo(int mapfd,
struct bpf_map_info *info)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.info.bpf_fd = mapfd;
attr.info.info_len = sizeof(struct bpf_map_info);
attr.info.info = (uintptr_t)info;
return syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
}
int
virBPFLookupElem(int mapfd,
void *key,
void *val)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = mapfd;
attr.key = (uintptr_t)key;
attr.value = (uintptr_t)val;
return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
int
virBPFGetNextElem(int mapfd,
void *key,
void *nextKey)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = mapfd;
attr.key = (uintptr_t)key;
attr.next_key = (uintptr_t)nextKey;
return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
}
int
virBPFUpdateElem(int mapfd,
void *key,
void *val)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = mapfd;
attr.key = (uintptr_t)key;
attr.value = (uintptr_t)val;
return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
int
virBPFDeleteElem(int mapfd,
void *key)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = mapfd;
attr.key = (uintptr_t)key;
return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
#else /* !HAVE_SYS_SYSCALL_H || !HAVE_DECL_BPF_PROG_QUERY */
int
virBPFCreateMap(unsigned int mapType G_GNUC_UNUSED,
unsigned int keySize G_GNUC_UNUSED,
unsigned int valSize G_GNUC_UNUSED,
unsigned int maxEntries G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFLoadProg(struct bpf_insn *insns G_GNUC_UNUSED,
int progType G_GNUC_UNUSED,
unsigned int insnCnt G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFAttachProg(int progfd G_GNUC_UNUSED,
int targetfd G_GNUC_UNUSED,
int attachType G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFDetachProg(int progfd G_GNUC_UNUSED,
int targetfd G_GNUC_UNUSED,
int attachType G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFQueryProg(int targetfd G_GNUC_UNUSED,
unsigned int maxprogids G_GNUC_UNUSED,
int attachType G_GNUC_UNUSED,
unsigned int *progcnt G_GNUC_UNUSED,
void *progids G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFGetProg(unsigned int id G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFGetProgInfo(int progfd G_GNUC_UNUSED,
struct bpf_prog_info *info G_GNUC_UNUSED,
unsigned int **mapIDs G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFGetMap(unsigned int id G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFGetMapInfo(int mapfd G_GNUC_UNUSED,
struct bpf_map_info *info G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFLookupElem(int mapfd G_GNUC_UNUSED,
void *key G_GNUC_UNUSED,
void *val G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFGetNextElem(int mapfd G_GNUC_UNUSED,
void *key G_GNUC_UNUSED,
void *nextKey G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFUpdateElem(int mapfd G_GNUC_UNUSED,
void *key G_GNUC_UNUSED,
void *val G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
int
virBPFDeleteElem(int mapfd G_GNUC_UNUSED,
void *key G_GNUC_UNUSED)
{
errno = ENOSYS;
return -1;
}
#endif /* !HAVE_SYS_SYSCALL_H || !HAVE_DECL_BPF_PROG_QUERY */