dev_queue_xmit случайным образом возвращает NET_XMIT_CN с помощью устройства tun / tap

#networking #linux-kernel #kernel-module #netfilter #tun

#сеть #linux-ядро #kernel-module #netfilter #tun

Вопрос:

У меня есть программа пользовательского пространства, которая создает свой собственный пакет (App, UDP, IP) и write() отправляет его на устройство TUN. Пакет перехватывается моим собственным модулем Netfilter, который проверяет, является ли полученный пакет тем, который мы хотим обработать. Затем мой модуль Netfilter skb_clone() преобразует оригинал skb и создает ответный пакет, который я заполняю некоторыми данными для возврата в программу пользовательского пространства. Чтобы отправить ответ, я использую dev_queue_xmit() . Он возвращается случайным NET_XMIT_CN образом, даже если я только что создал новое устройство TUN и через него не проходит другой трафик. Если я продолжу выполнять программу пользовательского пространства (отправляя новые пакеты на устройство TUN), в конечном итоге устройство TUN ответит, но не последовательно. Кажется, я не могу понять, почему он ведет себя так хаотично.

По сути, я использую устройство TUN в качестве механизма для передачи данных из пользовательского пространства в пространство ядра и наоборот.

Вот мое приложение для пользовательского пространства:

 tun_fd = tun_alloc(dev_name);
packet = ... /* Construct request...*/
nwrite = write(tun_fd, packet, packet_len);
...
unsigned recv_buf[1500];
int received = 0;
while (!received) {
    nread = read(tun_fd, recv_buf, 1500);
    ...
}
...
close(tun_fd);
 

Вот мой модуль Netfilter:

 static struct nf_hook_ops nfho;

static int __init my_hook(void)
{
    nfho.hook = hook_func;
    nfho.hooknum = 0;
    nfho.hook = PF_INET;
    nfho.hook = NF_IP_PRI_FIRST;
    nf_register_hook(amp;nfho);
}

unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct sk_buff *clone_skb = skb_clone(skb, GFP_KERNEL):
    ...
    /*
     * Check if packet is for us.
     * Check IP amp; UDP header, etc
     * If so, parse request, put together response clone_skb
     */
    ...

    if ((err = dev_queue_xmit(clone_skb)) != 0) {
        printk(....)
        /* Either it return 0 (success) or 2, meaning NET_XMIT_CN */
    }

    return NF_STOLEN;
}
 

Кажется, я не могу понять это поведение. Я неправильно использую устройство TUN? Есть ли более простой способ, чем этот?

Пожалуйста, дайте мне знать, если я должен предоставить какие-либо дополнительные подробности или что-то уточнить.