NETMAP (от Luigi Rizzo)
Простой и удобный открытый фреймворк для
обработки трафика на скоростях 10Gbit/s или
                 14 Mpps
              Евгений Ёрхов
               Компания IXI
Структура доклада
• Анализ проблемы производительности стеков
  TCP/IP в OS общего назначения
• Краткий обзор известных подходов по
  увеличению производительности на больших
  скоростях
• Быстрое введение в Netmap, архитектура,
  основные операции
• Примеры: генератор трафика, компонент
  подсистемы DDOS защиты
• Обзор производительности
Анализ overhead’ов в стеках OS общего назначения

ОСНОВНЫЕ ПРОБЛЕМЫ ПРИ
СКОРОСТНОЙ ОБРАБОТКЕ ПАКЕТОВ
Структуры данных NIC и их взаимосвязь со
         структурами данных OS
Вычисляем наносекунды
KERNEL SPACE                   USER SPACE
#define D(format, ...)         #define D(format, ...)
do {                           do {
 struct timespec __xxts;         if (!verbose) break;
 nanotime(&__xxts);               struct timespec _xxts;
 printf("%03d.%09d %s [%d]      clock_gettime(CLOCK_REALTIME,
  "format "n",                   &_xxts)
  (int)__xxts.tv_sec %          fprintf(stderr, "%03d.%09d %s
                                  [%d] " format
  1000, (int)__xxts.tv_nsec,
                                   "n”,(int)_xxts.tv_sec
  __FUNCTION__, __LINE__,
                                  %1000,  (int)_xxts.tv_nsec,
   ##__VA_ARGS__);
                                  __FUNCTION__, __LINE__,
} while (0)
                                  ##__VA_ARGS__);
                               } while (0)
Путешествие к центру ядра через API
File              Function / description                      Time ns   Delta ns
user_program      sendto() system call                        8         96
uipc_syscalls.c   sys_sendto()                                104
uipc_socket.c     sendit()                                    111       137
                  kern_sendit()                               118
                  sosend()                                    ---
                  sosend_dgram()                              146
                  sockbuf locking, mbuf allocation, copying
udp_usrreq.c      udp_send()
                  udp_output()                                273       57
ip_output.c       Ip_output()                                 330       198
                  Route lookup, ip header setup
if_ethersubr.c    Ether_output                                528       162
                  MAC header lookup and copy, loopback        690
                  ether_output_frame
ixgbe.c           ixgbe_mq_start()                            698
                  ixgbe_mq_start_locked()                     720       220
                  ixgbe_xmit                                  730
-                 On wire                                     950
Современные техники увеличения
       производительности
• Socket API: BPF (FreeBSD), AF_PACKET (Linux)
• Packet filter hooks: Netgraph (FreeBSD),
  Netfilter (Linux), Ndis miniport drivers (MS
  Windows)
• Direct buffer access: PF_RING_DNA (Linux),
  PACKET_MMAP (Linux), UIO-IXGBE (Linux)
Структуры данных, основные операции, примитивы и особенности

АРХИТЕКТУРА NETMAP
Подход NETMAP к обработке
   пакетов на больших скоростях
• Доступ к NIC в обход стека OS
• Защита памяти в хрупком kernel space
• Zero copy операции при форвардинге
  пакетов
• Линейные, лёгкие структуры данных
• pre-alloceted буферы для пакетов и
  метаданных
• Поддержка множественных очередей NIC
Схема взаимодействия NETMAP, NIC и OS

NIC пересылает данные между
сетью и оперативной памятью


ядро OS выполняет защиту
памяти

ядро OS обеспечивает
многозадачность и
синхронизацию

NETMAP обеспечивает
механизмы управления и доступа
к данным для приложения
Структуры данных NETMAP экспортируемые в
user space

Пакетные буферы
( packet buffers )

Кольцевые
буферы-очереди
( netmap rings )

Дескриптор
интерфейса
( netmap_if )
Разделение ответственности
Приложение user space         Ядерная часть
• Управляет слотами в         • NETMAP управляет
  «netmap_ring»                 границами в netmap_rings
• Управляет текущей           • NIC DMA engine
  позицией (номер слота) в      заполняет/читает пакетные
  «netmap_ring»                 буферы в позициях кроме
• Заполняет/читает              как начиная с
  пакетные буферы,              «cur» по «cur + avail»
  начиная с позиции           • NETMAP управляет
  «cur» по «cur + avail -1»     синхронизацией метаданных
• Управляет полем               в «netmap_rings» и структур
  «netmap_ring->avail»          NIC
NETMAP API Основные операции
• /dev/netmap
• ioctl(…, NIOCREGIF, arg)
• ioctl (…, NIOCTXSYNC) – синхронизация очередей
  (netmap rings) для отправки с соответствующими
  очередями сетевой карты, что эквивалентно
  отправке пакетов в сеть, синхронизация начинается
  с позиции cur
• ioctl (…, NIOCRXSYNC) – синхронизация очередей
  сетевой карты с соответствующими очередями
  netmap rings, для получения пакетов, поступивших
  из сети. Запись осуществляется начиная с позиции
  cur
Примитивы блокирования
Используются стандартные механизмы OS
• select()
• poll()

Результат:
• Отсутствие нагрузки на CPU
• Обработка несколько пакетов за
  проход
Дополнительные особенности

Поддержка множественных очередей NIC

Передача/приём пакетов в/из host stack

Защита памяти

Zero copy packet forwarding
Zero copy packet forwarding
...
ns_src = &src_nr_rx->slot[i]; /* locate src and dst slots */
ns_dst = &dst_nr_tx->slot[j];

/* swap the buffers */
tmp = ns_dst->buf_index;
ns_dst->buf_index = ns_src->buf_index;
ns_src->buf_index = tmp;

/* update length and flags */
ns_dst->len = ns_src->len;
ns_src->len = 0;

/* tell kernel to update addresses in the NIC rings */
ns_dst->flags = ns_src->flags = BUF_CHANGED;
dst_nr_tx->avail--; // Для большей ясности кода проверка
src_nr_rx->avail--; // avail > 0 не сделана
...
Прототипы: генератор трафика, компонент подсистемы очистки
трафика в системе DDOS защиты

NETMAP ПРИМЕРЫ
Прототип генератора трафика
fds.fd = open("/dev/netmap", O_RDWR);
strcpy(nmr.nm_name, "ix0");
ioctl(fds.fd, NIOCREG, &nmr);
p = mmap(0, nmr.memsize, fds.fd);
nifp = NETMAP_IF(p, nmr.offset);
fds.events = POLLOUT;
for (;;) {
   poll(fds, 1, -1);
   for (r = 0; r < nmr.num_queues; r++) {
      ring = NETMAP_TXRING(nifp, r);
      while (ring->avail-- > 0) {
         i = ring->cur;
         buf = NETMAP_BUF(ring, ring->slot[i].buf_index);
         //... store the payload into buf ...
         ring->slot[i].len = ... // set packet length
         ring->cur = NETMAP_NEXT(ring, i);
       }
   }
}
NETMAP API в подсистеме очистки
         трафика DDOS
  Основными требованиями к подсистеме
  очистки трафика выбраны
• возможность фильтрации пакетов на предельных
  скоростях
• возможности по обработке пакетов в системе
  фильтров, реализующие различные, известные на
  сегодняшний день техники противодействия
  DDOS атакам
Подготовка и включение режима
           NETMAP
struct nmreq nmr;
…
for (i=0, i < MAX_THREADS, i++) {
 …
 targ[i]->nmr.ringid = i | NETMAP_HW_RING;
 …
 ioctl(targ[i].fd, NIOCREGIF, &targ[i]->nmr);
 …
 targ[i]->mem = mmap(0, targ[i]->nmr.nr_memsize,
                 PROT_WRITE | PROT_READ, MAP_SHARED, targ[i].fd, 0);

 targ[i]->nifp = NETMAP_IF(targ[i]->mem, targ[i]->nmr.nr_offset);
 targ[i]->nr_tx = NETMAP_TXRING(targ[i]->nifp, i);
 targ[i]->nr_rx = NETMAP_RXRING(targ[i]->nifp, i);
 …
}
Открываем очереди для обмена с
           host stack
struct nmreq nmr;
…
  /* NETMAP ассоциирует   netmap   ring   с   наибольшим   ringid   с
сетевым стеком */

targ->nmr.ringid = stack_ring_id | NETMAP_SW_RING;
…
ioctl(targ.fd, NIOCREGIF, &targ->nmr);
…
Стартуем thread’ы каждая из которых
       работает со своей очередью
for ( i = 0; i < MAX_THREADS; i++ ) {
    /* start first rx thread */
    targs[i].used = 1;
    if (pthread_create(&targs[i].thread, NULL, rx_thread, &targs[i]) == -1) {

       D("Unable to create thread %d", i);
       exit(-1);
   }
}
…
/* Wait until threads will finish their loops */
for ( i = 0; i < MAX_THREAD; i++ ) {
    if( pthread_join(targs[i].thread, NULL) ) {
      ioctl(targs[i].fd, NIOCUNREGIF, &targs[i].nmr);
      close(targs[i].fd);
    }
    …
}
Ожидание пакетов в rx_thread()
while(targ->used) {
    ret = poll(fds, 2, 1 * 100);
    if (ret <= 0)
      continue;
  …
  /* run rings processing */
  for ( i = targ->begin; i < targ->end; i++) {
      ioctl(targ->fd, NIOCTXSYNC, 0);
      ioctl(targ->fd_stack, NIOCTXSYNC, 0);
      targ->rx = NETMAP_RXRING(targ->nifp, i);
      targ->tx = NETMAP_TXRING(targ->nifp, i);
      if (targ->rx->avail > 0)
      {
        …
      /* process ring */
      cnt = process_incoming(targ->id, targ->rx, targ->tx,
                              targ->stack_rx, targ->stack_tx);
       …
   }
}
Получение доступа к raw пакетам
           process_incoming()
limit = nic_rx->avail;
while ( limit-- > 0 ) {
    struct netmap_slot *rs = &nic_rx->slot[j]; // rx slot
    struct netmap_slot *ts = &nic_tx->slot[k]; // tx slot
    eth = (struct ether_header *)NETMAP_BUF(nic_rx,
             rs->buf_idx);
    if (eth->ether_type != htons(ETHERTYPE_IP)) {
      goto next_packet; // pass non-ip packet
    }
    /* get ip header of the packet */
    iph = (struct ip *)(eth + 1);
    …
}
ПРОИЗВОДИТЕЛЬНОСТЬ
Метрики
Per-bytes                    Per-packets
• Измерение                  • Измерение
  осуществляется на основе     осуществляется на основе
  отношения показателей к      отношения показателей к
  передаваемым полезным        количеству
  данным (payload)             обрабатываемых пакетов
• Поскольку NETMAP           • Интересно измерить
  использует zero copy         загрузку CPU в отношении
  forwarding – результат       к количеству
  очевиден                     обрабатываемых 64-
                               байтовых пакетов
Тестовое железо и OS

i7-870 4-core 2.93GHz CPU (3.2 GHz в режиме
turbo-boost), оперативная память на частоте
1.33GHz, в систему установлена двухпортовая
сетевая карта на базе чипсета Intel 82599



FreeBSD HEAD/amd64, Апрель 2012 г.
Скорость в зависимости от частоты
     процессора, ядер и т.п.
Загрузка процессора на одном ядре

      Частота   Средняя загрузка CPU
      900 MHz   100%
      1.2 GHz   80%
      3GHz      55%
Скорость передачи/приёма, в
зависимости от размера пакета
Скорость в зависимости от количества
  пакетов за один системный вызов
Скорости фильтрации flood-атак
   сервером очистки трафика RUSCREEN
Наименование атаки        Способ противодействия        Скорости обработки
(на случайном
распределении src_addr)
Synflood                  SYNCOOKIE                     12 883 408 pps
UDP flood                 PPS limiting, blacklisting,   13 854 096 pps
                          greylisting
ICMP flood                PPS limiting, blacklisting,   13 780 314 pps
                          greylisting
Смешанный flood           SYNCOOKIE, stateful           11 083 147 pps
                          inspection, PPS limiting,
                          blacklisting, greylisting
Заключение
• В докладе рассмотрены основные возможности NETMAP по
  обработке трафика на скоростях 10Gbit/s
• Сделан сравнительный анализ NETMAP с другими системами
  скоростной обработки пакетов
• Подтверждены тесты производительности, сделанные автором
  NETMAP – Luigi Rizzo
• Продемонстрированы основные приёмы использования
  NETMAP на примерах прототипов генератора трафика и
  подсистемы очистки трафика.

  Благодаря подходу, реализованному в NETMAP, автору доклада
  удалось добиться нужно производительности при фильтрации
  трафика в проекте DDOS-защиты RUSCREEN, позволяющей
  работать на скоростях 14Mpps.
БОЛЬШОЕ СПАСИБО ЗА ВНИМАНИЕ !

Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработки трафика.(Евгений Ёрхов)

  • 1.
    NETMAP (от LuigiRizzo) Простой и удобный открытый фреймворк для обработки трафика на скоростях 10Gbit/s или 14 Mpps Евгений Ёрхов Компания IXI
  • 2.
    Структура доклада • Анализпроблемы производительности стеков TCP/IP в OS общего назначения • Краткий обзор известных подходов по увеличению производительности на больших скоростях • Быстрое введение в Netmap, архитектура, основные операции • Примеры: генератор трафика, компонент подсистемы DDOS защиты • Обзор производительности
  • 3.
    Анализ overhead’ов встеках OS общего назначения ОСНОВНЫЕ ПРОБЛЕМЫ ПРИ СКОРОСТНОЙ ОБРАБОТКЕ ПАКЕТОВ
  • 4.
    Структуры данных NICи их взаимосвязь со структурами данных OS
  • 5.
    Вычисляем наносекунды KERNEL SPACE USER SPACE #define D(format, ...) #define D(format, ...) do { do { struct timespec __xxts; if (!verbose) break; nanotime(&__xxts); struct timespec _xxts; printf("%03d.%09d %s [%d] clock_gettime(CLOCK_REALTIME, "format "n", &_xxts) (int)__xxts.tv_sec % fprintf(stderr, "%03d.%09d %s [%d] " format 1000, (int)__xxts.tv_nsec, "n”,(int)_xxts.tv_sec __FUNCTION__, __LINE__, %1000, (int)_xxts.tv_nsec, ##__VA_ARGS__); __FUNCTION__, __LINE__, } while (0) ##__VA_ARGS__); } while (0)
  • 6.
    Путешествие к центруядра через API File Function / description Time ns Delta ns user_program sendto() system call 8 96 uipc_syscalls.c sys_sendto() 104 uipc_socket.c sendit() 111 137 kern_sendit() 118 sosend() --- sosend_dgram() 146 sockbuf locking, mbuf allocation, copying udp_usrreq.c udp_send() udp_output() 273 57 ip_output.c Ip_output() 330 198 Route lookup, ip header setup if_ethersubr.c Ether_output 528 162 MAC header lookup and copy, loopback 690 ether_output_frame ixgbe.c ixgbe_mq_start() 698 ixgbe_mq_start_locked() 720 220 ixgbe_xmit 730 - On wire 950
  • 7.
    Современные техники увеличения производительности • Socket API: BPF (FreeBSD), AF_PACKET (Linux) • Packet filter hooks: Netgraph (FreeBSD), Netfilter (Linux), Ndis miniport drivers (MS Windows) • Direct buffer access: PF_RING_DNA (Linux), PACKET_MMAP (Linux), UIO-IXGBE (Linux)
  • 8.
    Структуры данных, основныеоперации, примитивы и особенности АРХИТЕКТУРА NETMAP
  • 9.
    Подход NETMAP кобработке пакетов на больших скоростях • Доступ к NIC в обход стека OS • Защита памяти в хрупком kernel space • Zero copy операции при форвардинге пакетов • Линейные, лёгкие структуры данных • pre-alloceted буферы для пакетов и метаданных • Поддержка множественных очередей NIC
  • 10.
    Схема взаимодействия NETMAP,NIC и OS NIC пересылает данные между сетью и оперативной памятью ядро OS выполняет защиту памяти ядро OS обеспечивает многозадачность и синхронизацию NETMAP обеспечивает механизмы управления и доступа к данным для приложения
  • 11.
    Структуры данных NETMAPэкспортируемые в user space Пакетные буферы ( packet buffers ) Кольцевые буферы-очереди ( netmap rings ) Дескриптор интерфейса ( netmap_if )
  • 12.
    Разделение ответственности Приложение userspace Ядерная часть • Управляет слотами в • NETMAP управляет «netmap_ring» границами в netmap_rings • Управляет текущей • NIC DMA engine позицией (номер слота) в заполняет/читает пакетные «netmap_ring» буферы в позициях кроме • Заполняет/читает как начиная с пакетные буферы, «cur» по «cur + avail» начиная с позиции • NETMAP управляет «cur» по «cur + avail -1» синхронизацией метаданных • Управляет полем в «netmap_rings» и структур «netmap_ring->avail» NIC
  • 13.
    NETMAP API Основныеоперации • /dev/netmap • ioctl(…, NIOCREGIF, arg) • ioctl (…, NIOCTXSYNC) – синхронизация очередей (netmap rings) для отправки с соответствующими очередями сетевой карты, что эквивалентно отправке пакетов в сеть, синхронизация начинается с позиции cur • ioctl (…, NIOCRXSYNC) – синхронизация очередей сетевой карты с соответствующими очередями netmap rings, для получения пакетов, поступивших из сети. Запись осуществляется начиная с позиции cur
  • 14.
    Примитивы блокирования Используются стандартныемеханизмы OS • select() • poll() Результат: • Отсутствие нагрузки на CPU • Обработка несколько пакетов за проход
  • 15.
    Дополнительные особенности Поддержка множественныхочередей NIC Передача/приём пакетов в/из host stack Защита памяти Zero copy packet forwarding
  • 16.
    Zero copy packetforwarding ... ns_src = &src_nr_rx->slot[i]; /* locate src and dst slots */ ns_dst = &dst_nr_tx->slot[j]; /* swap the buffers */ tmp = ns_dst->buf_index; ns_dst->buf_index = ns_src->buf_index; ns_src->buf_index = tmp; /* update length and flags */ ns_dst->len = ns_src->len; ns_src->len = 0; /* tell kernel to update addresses in the NIC rings */ ns_dst->flags = ns_src->flags = BUF_CHANGED; dst_nr_tx->avail--; // Для большей ясности кода проверка src_nr_rx->avail--; // avail > 0 не сделана ...
  • 17.
    Прототипы: генератор трафика,компонент подсистемы очистки трафика в системе DDOS защиты NETMAP ПРИМЕРЫ
  • 18.
    Прототип генератора трафика fds.fd= open("/dev/netmap", O_RDWR); strcpy(nmr.nm_name, "ix0"); ioctl(fds.fd, NIOCREG, &nmr); p = mmap(0, nmr.memsize, fds.fd); nifp = NETMAP_IF(p, nmr.offset); fds.events = POLLOUT; for (;;) { poll(fds, 1, -1); for (r = 0; r < nmr.num_queues; r++) { ring = NETMAP_TXRING(nifp, r); while (ring->avail-- > 0) { i = ring->cur; buf = NETMAP_BUF(ring, ring->slot[i].buf_index); //... store the payload into buf ... ring->slot[i].len = ... // set packet length ring->cur = NETMAP_NEXT(ring, i); } } }
  • 19.
    NETMAP API вподсистеме очистки трафика DDOS Основными требованиями к подсистеме очистки трафика выбраны • возможность фильтрации пакетов на предельных скоростях • возможности по обработке пакетов в системе фильтров, реализующие различные, известные на сегодняшний день техники противодействия DDOS атакам
  • 20.
    Подготовка и включениережима NETMAP struct nmreq nmr; … for (i=0, i < MAX_THREADS, i++) { … targ[i]->nmr.ringid = i | NETMAP_HW_RING; … ioctl(targ[i].fd, NIOCREGIF, &targ[i]->nmr); … targ[i]->mem = mmap(0, targ[i]->nmr.nr_memsize, PROT_WRITE | PROT_READ, MAP_SHARED, targ[i].fd, 0); targ[i]->nifp = NETMAP_IF(targ[i]->mem, targ[i]->nmr.nr_offset); targ[i]->nr_tx = NETMAP_TXRING(targ[i]->nifp, i); targ[i]->nr_rx = NETMAP_RXRING(targ[i]->nifp, i); … }
  • 21.
    Открываем очереди дляобмена с host stack struct nmreq nmr; … /* NETMAP ассоциирует netmap ring с наибольшим ringid с сетевым стеком */ targ->nmr.ringid = stack_ring_id | NETMAP_SW_RING; … ioctl(targ.fd, NIOCREGIF, &targ->nmr); …
  • 22.
    Стартуем thread’ы каждаяиз которых работает со своей очередью for ( i = 0; i < MAX_THREADS; i++ ) { /* start first rx thread */ targs[i].used = 1; if (pthread_create(&targs[i].thread, NULL, rx_thread, &targs[i]) == -1) { D("Unable to create thread %d", i); exit(-1); } } … /* Wait until threads will finish their loops */ for ( i = 0; i < MAX_THREAD; i++ ) { if( pthread_join(targs[i].thread, NULL) ) { ioctl(targs[i].fd, NIOCUNREGIF, &targs[i].nmr); close(targs[i].fd); } … }
  • 23.
    Ожидание пакетов вrx_thread() while(targ->used) { ret = poll(fds, 2, 1 * 100); if (ret <= 0) continue; … /* run rings processing */ for ( i = targ->begin; i < targ->end; i++) { ioctl(targ->fd, NIOCTXSYNC, 0); ioctl(targ->fd_stack, NIOCTXSYNC, 0); targ->rx = NETMAP_RXRING(targ->nifp, i); targ->tx = NETMAP_TXRING(targ->nifp, i); if (targ->rx->avail > 0) { … /* process ring */ cnt = process_incoming(targ->id, targ->rx, targ->tx, targ->stack_rx, targ->stack_tx); … } }
  • 24.
    Получение доступа кraw пакетам process_incoming() limit = nic_rx->avail; while ( limit-- > 0 ) { struct netmap_slot *rs = &nic_rx->slot[j]; // rx slot struct netmap_slot *ts = &nic_tx->slot[k]; // tx slot eth = (struct ether_header *)NETMAP_BUF(nic_rx, rs->buf_idx); if (eth->ether_type != htons(ETHERTYPE_IP)) { goto next_packet; // pass non-ip packet } /* get ip header of the packet */ iph = (struct ip *)(eth + 1); … }
  • 25.
  • 26.
    Метрики Per-bytes Per-packets • Измерение • Измерение осуществляется на основе осуществляется на основе отношения показателей к отношения показателей к передаваемым полезным количеству данным (payload) обрабатываемых пакетов • Поскольку NETMAP • Интересно измерить использует zero copy загрузку CPU в отношении forwarding – результат к количеству очевиден обрабатываемых 64- байтовых пакетов
  • 27.
    Тестовое железо иOS i7-870 4-core 2.93GHz CPU (3.2 GHz в режиме turbo-boost), оперативная память на частоте 1.33GHz, в систему установлена двухпортовая сетевая карта на базе чипсета Intel 82599 FreeBSD HEAD/amd64, Апрель 2012 г.
  • 28.
    Скорость в зависимостиот частоты процессора, ядер и т.п.
  • 29.
    Загрузка процессора наодном ядре Частота Средняя загрузка CPU 900 MHz 100% 1.2 GHz 80% 3GHz 55%
  • 30.
  • 31.
    Скорость в зависимостиот количества пакетов за один системный вызов
  • 32.
    Скорости фильтрации flood-атак сервером очистки трафика RUSCREEN Наименование атаки Способ противодействия Скорости обработки (на случайном распределении src_addr) Synflood SYNCOOKIE 12 883 408 pps UDP flood PPS limiting, blacklisting, 13 854 096 pps greylisting ICMP flood PPS limiting, blacklisting, 13 780 314 pps greylisting Смешанный flood SYNCOOKIE, stateful 11 083 147 pps inspection, PPS limiting, blacklisting, greylisting
  • 33.
    Заключение • В докладерассмотрены основные возможности NETMAP по обработке трафика на скоростях 10Gbit/s • Сделан сравнительный анализ NETMAP с другими системами скоростной обработки пакетов • Подтверждены тесты производительности, сделанные автором NETMAP – Luigi Rizzo • Продемонстрированы основные приёмы использования NETMAP на примерах прототипов генератора трафика и подсистемы очистки трафика. Благодаря подходу, реализованному в NETMAP, автору доклада удалось добиться нужно производительности при фильтрации трафика в проекте DDOS-защиты RUSCREEN, позволяющей работать на скоростях 14Mpps.
  • 34.