Русский
Русский
English
Статистика
Реклама

NAPI в сетевых драйверах Linux

Привет, Хабр!
Поговорим о драйверах сетевых устройств Linux, механизме NAPI и его изменениях в ядре 5.12.

Сетевая подсистема Linux (рисунок) построена по примеру стека BSD, в ней прием и передача данных на транспортном и сетевом уровнях происходит с помощью интерфейса сокетов. В отличие от unix-сокетов для межпроцессного взаимодействия, TCP/IP сокеты используют для работы сетевой протокол и при создании (sys_socket) принимают параметры домен, тип, локальные и удаленные IP-адрес и порт. Буфер сокета (sk_buff) - фактически, пакет. Связный список экземпляров таких структур составляет очередь сетевого интерфейса (tx_queue, rx_queue).

Упрощенно некоторые важные поля sk_buff:

struct sk_buff {union {struct {    /* Двусвязный список */struct sk_buff*next;struct sk_buff*prev;struct net_device*dev;};struct list_headlist;};struct sock*sk;unsigned intlen,data_len;__u16mac_len,hdr_len;/* Часть NAPI-интерфейса */#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)union {unsigned intnapi_id;unsigned intsender_cpu;};#endif__u8inner_ipproto;__u16inner_transport_header;__u16inner_network_header;__u16inner_mac_header;__be16protocol;__u16transport_header;__u16network_header;__u16mac_header;sk_buff_data_ttail;sk_buff_data_tend;unsigned char*head,*data;unsigned inttruesize;};

Драйвера отвечают за реализацию канального уровня (разрешение MAC-адресов) и предоставление интерфейса между системными вызовами ядра и сетевой картой. Обработка входящих и исходящих пакетов происходят с помощью функций xmit и rx, от одновременного доступа они защищены спин блокировками, как и обновление статистики stats и изменение параметров передачи. Сам интерфейс определяется структурой net_device, для создания и регистрации вызываются функции alloc_netdev и register_netdev.

Важные поля net_device:

struct net_device {charname[IFNAMSIZ];    // Строка в стиле printfunsigned longmem_end;unsigned longmem_start;unsigned longbase_addr;unsigned longstate;struct list_headdev_list;struct list_headnapi_list;unsigned intflags;unsigned intpriv_flags;const struct net_device_ops *netdev_ops;unsigned shorthard_header_len;unsigned intmtu;struct net_device_statsstats; atomic_long_trx_dropped;atomic_long_ttx_dropped;atomic_long_trx_nohandler;const struct ethtool_ops *ethtool_ops;const struct header_ops *header_ops;unsigned charif_port;unsigned chardma;/* Interface address info. */unsigned charperm_addr[MAX_ADDR_LEN];unsigned short          dev_id;unsigned short          dev_port;spinlock_taddr_list_lock;intirq;unsigned char*dev_addr;struct netdev_rx_queue*_rx;unsigned intnum_rx_queues;struct netdev_queue*_tx ____cacheline_aligned_in_smp;unsigned intnum_tx_queues;struct timer_listwatchdog_timer;intwatchdog_timeo;};

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

Схематичные действия в обработчике прерываний для очистки очереди входящих пакетов: (драйвер intel Ethernet e1000):

static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,  // Сетевое устройство       struct e1000_rx_ring *rx_ring, // Очередь входящих пакетов       int *work_done, int work_to_do){while (rx_desc->status & E1000_RXD_STAT_DD) {struct sk_buff *skb;u8 *data;u8 status;        if (netdev->features & NETIF_F_RXALL) {    total_rx_bytes += (length - 4);     total_rx_packets++;    e1000_receive_skb(adapter, status, rx_desc->special, skb);}     }if (cleaned_count)    // Создание нового буфераadapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);    // Обновление статистикиadapter->total_rx_packets += total_rx_packets;adapter->total_rx_bytes += total_rx_bytes;netdev->stats.rx_bytes += total_rx_bytes;netdev->stats.rx_packets += total_rx_packets;return cleaned;}

До ядер версии 2.3 после самого обработчика прерывания (top half) для выполнения основных задач использовались нижние половины (bottom half) и очереди задач (task queue). Начиная с версии 2.3 на замену интерфейсу BH пришли отложенные прерывания (softirq), тасклеты (tasklet) и очереди отложенных действий (work queue). Преимущество softirq в том, что они могут одновременно выполняться на разных процессорах. Они напрямую используются в сетевой подсистеме.

Немного о NAPI

Пока сетевой трафик был умеренным, механизм прерываний при получении пакета эффективно справлялся со своей задачей. С ростом трафика и появлением высоконагруженных систем постоянная обработка прерываний стала приводить к нехватке процессорного времени для пользовательских программ и потере пакетов. Решение проблемы было предложено в 2001 году и появилось в виде интерфейса New API в ядрах серии 2.4. (В оригинальной статье результаты тестирования для SMP-системы, генератор трафика наподобие pktgen).

Основная цель NAPI - сократить количество прерываний, генерируемых при получении пакетов. В NAPI механизм прерываний сочетается с механизмом опроса. Чаще всего в разработке избегают использования поллинга, так как могут тратится лишние ресурсы, когда оборудование молчит. У выоконагруженных интерфейсов такой проблемы не возникает.

В NAPI-совместимых драйверах прерывания отключаются, когда на интерфейс приходит пакет. Обработчик в этом случае только вызывает rx_schedule, гарантирующий, что обработка пакетов произойдет в дальнейшем. Когда приходящие пакеты заполняют буфер (предельное количество budget), для обработки вызывается метод dev->poll. Метод poll будет вызываться одновременно не более, чем на одном процессоре, что упрощает синхронизацию. Если нагрузка падает, снова разрешаются прерывания. Это позволяет динамически регулировать производительность в зависимости от нагрузки интерфейса. Метод poll может использоваться также и для передачи пакетов.

Пример poll из драйвера e1000:

static void e1000_netpoll(struct net_device *netdev){struct e1000_adapter *adapter = netdev_priv(netdev);if (disable_hardirq(adapter->pdev->irq))e1000_intr(adapter->pdev->irq, netdev);enable_irq(adapter->pdev->irq);}

При реализации NAPI-совместимого драйвера должны быть выполнены некоторые требования:

  • Возможность хранения входящих пакетов в кольце DMA или буфере в самой карте

  • Возможность отключить прерывания

  • В методе poll должна быть реализована возможность забрать несколько пакетов за раз

  • Так как метод poll работает в контексте softirq и управляется демоном ksoftirqd, в системах с высокой загрузкой нужно менять приоритет поллинга для обеспечения баланса ресурсов между обработчиком прерываний и пользовательскими программами.

Недостатки NAPI:

  • В некоторых случаях в системе могуть быть задержки, если весь обработчик прерываний помещен в dev->poll

  • Маскировка прерываний может быть медленной

  • Возможно состояние IRQ-гонки, если пакет приходит во время проверки бита наличия новых пакетов и включения прерываний.

Что нового у NAPI в 5.12?

В серии патчей в ядре 5.12 метод poll из softirq контекста перенесен в поток ядра.

Wei Wang в комментарии к патчу рассказывает, что причина такого решения отсутствие возможности отследить программные прерывания в системе. Планировщик не может измерить время, затрачиваемое на обработку softirq. Поток ядра же видим для планировщика задач CPU, это позволит избежать перегрузки процессора, на котором он работает, и сделать планирование userspace-процессов более детерминированным. Его проще контролировать системному администратору. Kthread можно связать с определенной группой CPU, чтобы явно отделить пользовательские потоки от процессоров, опрашивающих сетевые интерфейсы.

Изменения затронули в основном net/core/dev.c. Обновлен метод __napi_poll, вызываемый из контекста napi_poll. Появился новый sysfs атрибут в net_device для включения/выключения поточного режима опроса для всех экземпляров napi данного сетевого устройства без необходимости вызова up/down.

В napi_struct добавлено поле threaded для реализации опроса внутри потока, причем для включения поддержки потоков после создания kthread нужно вызвать napi_set_threaded (флаг NAPI_STATE_THREADED).

Обновленная структура napi_struct:

struct napi_struct {        struct list_head        dev_list;        struct hlist_node       napi_hash_node;        unsigned int            napi_id;        struct task_struct      *thread; };

Создание потока ядра:

static int napi_kthread_create(struct napi_struct *n){       int err = 0;       /* Create and wake up the kthread once to put it in        * TASK_INTERRUPTIBLE mode to avoid the blocked task        * warning and work with loadavg.        */       n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d",                               n->dev->name, n->napi_id);       if (IS_ERR(n->thread)) {               err = PTR_ERR(n->thread);               pr_err("kthread_run failed with err %d\n", err);               n->thread = NULL;       }       return err;}

В связи с добавлением поточности появился новый метод napi_thread_wait.

Wei Wang получил следующие результаты сравнения эффективности softirq, kthread и очередей отложенных действий:

Основные источники - LDD3 и статьи:

NAPI polling in kernel threads
Threadable NAPI polling, softirqs, and proper fixes
Reworking NAPI
Driver porting: Network drivers

Заранее спасибо за уточнения и указания на ошибки!

Источник: habr.com
К списку статей
Опубликовано: 10.05.2021 20:18:52
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Open source

Системное программирование

*nix

Сетевые технологии

C

Linux

Napi

Softirq

Kernel

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru