Отправка сообщения Netlink Taskstats с использованием libnl-3
Я хочу прочитать статистику ядра Linux за один поток, используя сокет netlink и задачи.
Я мог бы заставить задачи работать с помощью оболочки Python ( https://github.com/facebook/gnlpy), но я хочу сделать реализацию C.
После настройки сокета, параметров сообщения и отправки, получения
nl_recvmsgs_default(sock)
всегда возвращает код ошибки -7 ("Неверные входные данные или параметр") или -12 ("Объект не найден") в зависимости от того, как я создаю сообщение для отправки.
Я проверил все вызовы методов до nl_recvmsgs_default (sock), но не получаю никаких ошибок назад. Я предполагаю, что пропускаю часть в настройке сообщения или сокета, но не знаю, какая это часть.
#include <stdlib.h>
#include <unistd.h>
#include <linux/taskstats.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
int callback_message(struct nl_msg *, void *);
int main(int argc, char ** argv) {
struct nl_sock * sock;
struct nl_msg * msg;
int family;
sock = nl_socket_alloc();
// Connect to generic netlink socket on kernel side
genl_connect(sock);
// get the id for the TASKSTATS generic family
family = genl_ctrl_resolve(sock, "TASKSTATS");
// Allocate a new netlink message and inherit netlink message header.
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION))
//error code: -7 NLE_INVAL "Invalid input data or parameter",
nla_put_string(msg, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, "0");
//error code: -12 NLE_OBJ_NOTFOUND "Obj not found"
//nla_put_string(msg, TASKSTATS_CMD_ATTR_PID, "583");
nl_send_auto(sock, msg);
nlmsg_free(msg);
// specify a callback for inbound messages
nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, callback_message, NULL);
// gives error code -7 or -12 depending on the two nla_put_string alternatives above
printf("recv code (0 = success): %d", nl_recvmsgs_default(sock));
}
int callback_message(struct nl_msg * nlmsg, void * arg) {
struct nlmsghdr * nlhdr;
struct nlattr * nlattrs[TASKSTATS_TYPE_MAX + 1];
struct nlattr * nlattr;
struct taskstats * stats;
int rem;
nlhdr = nlmsg_hdr(nlmsg);
int answer;
if ((answer = genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL))
< 0) {
printf("error parsing msg\n");
}
if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_TGID]) || (nlattr =
nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr =
nlattrs[TASKSTATS_TYPE_NULL])) {
stats = nla_data(nla_next(nla_data(nlattr), &rem));
printf("---\n");
printf("pid: %u\n", stats->ac_pid);
printf("command: %s\n", stats->ac_comm);
printf("status: %u\n", stats->ac_exitcode);
printf("time:\n");
printf(" start: %u\n", stats->ac_btime);
printf(" elapsed: %llu\n", stats->ac_etime);
printf(" user: %llu\n", stats->ac_utime);
printf(" system: %llu\n", stats->ac_stime);
printf("memory:\n");
printf(" bytetime:\n");
printf(" rss: %llu\n", stats->coremem);
printf(" vsz: %llu\n", stats->virtmem);
printf(" peak:\n");
printf(" rss: %llu\n", stats->hiwater_rss);
printf(" vsz: %llu\n", stats->hiwater_vm);
printf("io:\n");
printf(" bytes:\n");
printf(" read: %llu\n", stats->read_char);
printf(" write: %llu\n", stats->write_char);
printf(" syscalls:\n");
printf(" read: %llu\n", stats->read_syscalls);
printf(" write: %llu\n", stats->write_syscalls);
} else {
printf("unknown attribute format received\n");
}
return 0;
}
1 ответ
Код, который вы предоставили, прекрасно работает для меня, за исключением синтаксической ошибки в строке 26. Убедитесь, что вы запускаете программу от имени пользователя root. Обратите внимание, что вы создаете прослушиватель для выхода из задач, но при этом читаете одно сообщение, которое, насколько я понимаю, ACK. Чтение из сокета в цикле while(1) показывает проанализированные сообщения всякий раз, когда задача выходит из CPU 0.
РЕДАКТИРОВАТЬ: В случае, когда вы получаете статистику для одного PID, вы должны использовать вместо этого nla_put_u32:
nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 583);
где 583 - это идентификатор существующего процесса.