#c #linux #sockets #kernel #netlink
#c #linux #сокеты #ядро #netlink
Вопрос:
У меня есть модуль ядра, который взаимодействует с пользовательским пространством с помощью Netlink, это выглядит так
Модуль ядра
#define NETLINK_USER 31
struct sock *nl_sk = NULL;
int init_module()
{
struct netlink_kernel_cfg cfg = {
.input = nl_recv_msg,
};
nl_sk = netlink_kernel_create(amp;init_net, NETLINK_USER, amp;cfg);
if (!nl_sk) return -1;
return 0;
}
void cleanup_module()
{
netlink_kernel_release(nl_sk);
}
И это приложение пользовательского пространства C , которое взаимодействует с ним
Пользовательский C
#define NETLINK_USER 31
#define APP_PORT 5007
#define TIMEOUT_SEC 3
int sock_fd = 0;
void Listen()
{
nlmsghdr *nlh = NULL;
iovec iov;
msghdr msg;
sockaddr_nl dest_addr, src_addr;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
InitSocketParams(src_addr, dest_addr, nlh, iov, msg, sizeof(LD_EVENT));
timeval timeout;
timeout.tv_sec = TIMEOUT_SEC;
timeout.tv_usec = 0;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)amp;timeout, sizeof(timeout));
while (isrunning)
{
int num_recv = recvmsg(sock_fd, amp;msg, 0);
if (num_recv <= 0)
{
if (errno == EAGAIN) // EAGAIN is a periodic Timeout
continue;
}
void *recv_st = NLMSG_DATA(nlh);
ProcessMsg(recv_st);
}
free(nlh);
close(sock_fd);
}
int Send(void *msg)
{
sockaddr_nl src_addr, dest_addr;
nlmsghdr *nlh = NULL;
iovec iov;
msghdr _msghdr;
int ret = 0;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
InitSocketParams(src_addr, dest_addr, nlh, iov, _msghdr, sizeof(*msg));
memcpy(NLMSG_DATA(nlh), msg, sizeof(*msg));
int bytes_sent = sendmsg(sock_fd, amp;_msghdr, 0);
if (bytes_sent < 0)
ret = errno;
free(nlh);
return ret;
}
void InitSocketParams(sockaddr_nl amp;src_addr, sockaddr_nl amp;dest_addr,
nlmsghdr *amp;nlh, iovec amp;iov, msghdr amp;msg, const int max_payload_size)
{
memset(amp;msg, 0, sizeof(msg));
memset(amp;src_addr, 0, sizeof(src_addr));
memset(amp;dest_addr, 0, sizeof(dest_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = APP_PORT; /* self pid */
bind(sock_fd, (struct sockaddr *)amp;src_addr, sizeof(src_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
if (nlh) free(nlh);
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(max_payload_size));
memset(nlh, 0, NLMSG_SPACE(max_payload_size));
nlh->nlmsg_len = NLMSG_SPACE(max_payload_size);
nlh->nlmsg_pid = DAEMON_PORT;
nlh->nlmsg_flags = 0;
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)amp;dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = amp;iov;
msg.msg_iovlen = 1;
}
Close()
{
if (sock_fd > 0)
close(sock_fd);
}
int StartListener()
{
isrunning = true;
std::thread th(amp;Listen, this);
m_watcherthread = std::move(th);
}
Проблема в том, что когда приложение пользовательского пространства подключено к модулю ядра, я вообще не могу использовать rmmod
модуль ядра. Это показывает rmmod: ERROR: Module my_module is in use
. Я должен сначала закрыть приложение пользовательского пространства, чтобы получить доступ к rmmod
модулю ядра. Есть ли способ сделать это, не закрывая приложение пользовательского пространства?
Комментарии:
1. Почему вы хотите это сделать? Я не эксперт по ядру, но это звучит невероятно странно — вы почти наверняка не хотите, чтобы модуль исчез, пока с вашим приложением связан дескриптор открытого файла. Вероятно, лучше всего либо заставить ваше приложение закрыть соединение, чтобы вы могли перезагрузить модуль и повторно открыть его, либо просто смириться с накладными расходами на перезагрузку вашего приложения.
2. @JohnGraham Мне нужны как модуль ядра, так и приложение пользовательского пространства, чтобы иметь возможность отключаться / закрываться в любое время. Я могу обработать необходимую логику для другой части, когда она обнаружит отключение.
3. Похоже, вы можете просто закрыть дескрипторы файлов из своего пользовательского приложения — тогда вы можете удалить модуль, если хотите