Какой аналог фильтра NDIS в linux?

Я работаю над системой as close to real-time, насколько это возможно в Linux, и мне нужно отправить около 600-800 байт в TCP-пакете, как только я получу определенный пакет.

Для наилучших возможных задержек я хочу, чтобы этот пакет был отправлен непосредственно из ядра, вместо того, чтобы полученный пакет проходил весь путь до пользовательского пространства и приложения, а затем возвращался обратно.

Если бы я был в Windows, я бы написал фильтр NDIS, который кэшировал бы пакет для отправки и соответствующие параметры, чтобы он проверял полученный пакет и при совпадении запускал предварительно кэшированный пакет в сеть без передачи принятый пакет до более высоких уровней.

Итак, мой вопрос: какой ближайший аналог фильтра NDIS в Linux?

Я читал о netfilter и, возможно, я бы использовал его, но я не знаю, лучший ли это из возможных способов.

Что еще я мог бы сделать, чтобы добиться минимально возможных задержек?

Мой текущий чисто пользовательский код дает мне около 80-100 микросекунд на процессоре Intel Xeon 3,7 ГГц под управлением Ubuntu 10.04 на ядре 2.6.3x.


person Surojit    schedule 10.10.2012    source источник


Ответы (2)


Вы можете использовать iptables target NFLOG для копирования пакетов в пользовательское пространство или NFQUEUE, чтобы позволить пользовательскому пространству изменять их. Это взаимодействие происходит через netlink, но вы можете использовать такие библиотеки, как libnetfilter_log и libnetfilter_queue, которые обертывают его.

person ephemient    schedule 12.10.2012

В ядре Linux есть аналогичный механизм, который называется BPF (пакетный фильтр Berkeley). Зарегистрируйте фильтр BPF в ядре из вашего приложения. Пакеты, соответствующие фильтру, будут перехватываться и пересылаться в зарегистрированную функцию ловушки.

Ниже приведен код exmpale, который я нашел в Интернете. ( https://gist.github.com/939154 ) В основном вам нужно было создать открытый, привязав его с фильтром BPF, а затем выбрать этот FD для приема пакетов: ; set_filter(int fd) { struct bpf_program fcode = {0};

/* dump ssh packets only */
struct bpf_insn insns[] = {
    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 10),
    BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23),
    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 8),
    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),
    BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0),
    BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14),
    BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14),
    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 22, 2, 0),
    BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16),
    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 22, 0, 1),
    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
    BPF_STMT(BPF_RET+BPF_K, 0),
};


/* Set the filter */
fcode.bf_len = sizeof(insns) / sizeof(struct bpf_insn);
fcode.bf_insns = &insns[0];

if(ioctl(fd, BIOCSETF, &fcode) < 0)
    return -1;

return 0;

}

Bpf_inst выглядит ужасно. Тем не менее, нет необходимости писать его вручную. Вы можете использовать tcp-dump для автоматической генерации этих скриптов.

Например:

sudo tcpdump 'tcp[13]=18'  -i eth0 -dd
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000006 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 4, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x50, 0, 0, 0x0000001b },
{ 0x15, 0, 1, 0x00000012 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
person Houcheng    schedule 12.10.2012
comment
Обратите внимание, что это по-прежнему переходит в пространство пользователя и обратно, так как вы должны прочитать устройство bpf и записать на него пакет. Однако, прежде чем это отключит вас от теста. Системные вызовы Linux часто быстрее, чем эквиваленты Windows. - person Zan Lynx; 12.10.2012