Como faço para criar um “netlink” entre o kernel e userspace?
-
03-07-2019 - |
Pergunta
Eu quero usar netlink para se comunicar entre um aplicativo e espaço do kernel. Minha versão do kernel Linux é 2.6.28, eo seguinte é o meu código errado:
nf_sock=netlink_kernel_create(NL_PROTO,0,nl_user_skb,THIS_MODULE);
A mensagem de erro abreviado é:
error: too few arguments to function 'netlink_kernel_create'
No <linux/netlink.h>
arquivo, o netlink_kernel_create()
função é definida como
extern struct sock *netlink_kernel_create(struct net *net,int unit,unsigned int groups,void (*input)(struct sk_buff *skb),struct mutex *cb_mutex,struct module *module)
Eu não entendo o que usar para o primeiro argumento, net
. Alguém pode explicar o que devo usar aqui?
Solução
A struct net
contém informações sobre o namespace de rede, um conjunto de recursos de rede disponível para processos. Note-se que poderia haver vários espaços de nomes de rede (ou seja, várias instâncias da pilha de rede), mas a maioria dos motoristas usar o namespace init_net.
A sua chamada deve provavelmente algo parecido com o seguinte
nf_sock = netlink_kernel_create(&init_net,
NETLINK_USERSOCK,
0,
nl_rcv_func,
NULL,
THIS_MODULE);
onde nl_rcv_func
é um struct sk_buff *skb
função tomada como único argumento e processa a mensagem netlink recebido.
Outras dicas
Você parece ter vindo a seguir um guia, como esta , que ( sendo de 2005) bem poderia ter sido superado pelo desenvolvimento do kernel. Parece que a API interna para criar um netlink do lado do kernel mudou.
De qualquer verifique a / pasta Documentação na árvore do kernel local para alguma documentação (espero mais fresco), ou ler o código em si. Você poderia também arrasto as Linux Kernel mailing list arquivos para qualquer menção às mudanças que parece ter acontecido.
Aqui é o implemntation real a partir de 2.6.29, se você preferir quebra-lo para trás (e ainda não tiver verificado este na sua própria árvore, é claro).
Sim, struct net é certamente para namespace net, mas não é adequado para usar sempre init_net, você deve registrar seus próprios pernet_operations, como este:
static struct pernet_operations fib_net_ops = {
.init = fib_net_init,
.exit = fib_net_exit,
};
static int __net_init fib_net_init(struct net *net)
{
int error;
#ifdef CONFIG_IP_ROUTE_CLASSID
net->ipv4.fib_num_tclassid_users = 0;
#endif
error = ip_fib_net_init(net);
if (error < 0)
goto out;
error = nl_fib_lookup_init(net);
if (error < 0)
goto out_nlfl;
error = fib_proc_init(net);
if (error < 0)
goto out_proc;
out:
return error;
out_proc:
nl_fib_lookup_exit(net);
out_nlfl:
ip_fib_net_exit(net);
goto out;
}
static int __net_init nl_fib_lookup_init(struct net *net)
{
struct sock *sk;
struct netlink_kernel_cfg cfg = {
.input = nl_fib_input,
};
sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg);
if (sk == NULL)
return -EAFNOSUPPORT;
net->ipv4.fibnl = sk;
return 0;
}
e, finalmente:
register_pernet_subsys(&fib_net_ops);
Eu sugeriria ioctl para comunicação kernel / user. A interface ioctl é padrão e a chance de foi atualizado entre kernels é pequena.