Post on 05-Jul-2015
transcript
NETMAP (от Luigi Rizzo)Простой и удобный открытый фреймворк для обработки трафика на скоростях 10Gbit/s или
14 Mpps
Евгений Ёрхов
Компания IXI
Структура доклада
• Анализ проблемы производительности стеков TCP/IP в OS общего назначения
• Краткий обзор известных подходов по увеличению производительности на больших скоростях
• Быстрое введение в Netmap, архитектура, основные операции
• Примеры: генератор трафика, компонент подсистемы DDOS защиты
• Обзор производительности
ОСНОВНЫЕ ПРОБЛЕМЫ ПРИ СКОРОСТНОЙ ОБРАБОТКЕ ПАКЕТОВ
Анализ overhead’ов в стеках OS общего назначения
Структуры данных NIC и их взаимосвязь со структурами данных OS
Вычисляем наносекунды
KERNEL SPACE#define D(format, ...)
do {
struct timespec __xxts;
nanotime(&__xxts);
printf("%03d.%09d %s [%d]
"format "\n",
(int)__xxts.tv_sec %
1000, (int)__xxts.tv_nsec,
__FUNCTION__, __LINE__,
##__VA_ARGS__);
} while (0)
USER SPACE#define D(format, ...)
do {
if (!verbose) break;
struct timespec _xxts;
clock_gettime(CLOCK_REALTIME,
&_xxts)
fprintf(stderr, "%03d.%09d %s
[%d] " format
"\n”,(int)_xxts.tv_sec
%1000, \ (int)_xxts.tv_nsec,
__FUNCTION__, __LINE__,
##__VA_ARGS__);
} while (0)
Путешествие к центру ядра через API
File Function / description Time ns Delta ns
user_program sendto() system call 8 96
uipc_syscalls.c
uipc_socket.c
sys_sendto()
sendit()
kern_sendit()
sosend()
sosend_dgram()
sockbuf locking, mbuf allocation, copying
104
111
118
---
146
137
udp_usrreq.c udp_send()
udp_output() 273 57
ip_output.c Ip_output()
Route lookup, ip header setup
330 198
if_ethersubr.c Ether_output
MAC header lookup and copy, loopback
ether_output_frame
528
690
162
ixgbe.c ixgbe_mq_start()
ixgbe_mq_start_locked()
ixgbe_xmit
698
720
730
220
- 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_ring»
• Управляет текущей позицией (номер слота) в «netmap_ring»
• Заполняет/читает пакетные буферы, начиная с позиции «cur» по «cur + avail -1»
• Управляет полем «netmap_ring->avail»
Ядерная часть
• NETMAP управляет границами в netmap_rings
• NIC DMA engine заполняет/читает пакетные буферы в позициях кроме как начиная с «cur» по «cur + avail»
• NETMAP управляет синхронизацией метаданных в «netmap_rings» и структур 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 не сделана
...
NETMAP ПРИМЕРЫ
Прототипы: генератор трафика, компонент подсистемы очистки трафика в системе DDOS защиты
Прототип генератора трафика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
• Измерение осуществляется на основе отношения показателей к передаваемым полезным данным (payload)
• Поскольку NETMAP использует zero copy forwarding – результат очевиден
Per-packets
• Измерение осуществляется на основе отношения показателей к количеству обрабатываемых пакетов
• Интересно измерить загрузку CPU в отношении к количеству обрабатываемых 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,greylisting
13 854 096 pps
ICMP flood PPS limiting, blacklisting,greylisting
13 780 314 pps
Смешанный flood SYNCOOKIE, statefulinspection, PPS limiting, blacklisting, greylisting
11 083 147 pps
Заключение
• В докладе рассмотрены основные возможности NETMAP по обработке трафика на скоростях 10Gbit/s
• Сделан сравнительный анализ NETMAP с другими системами скоростной обработки пакетов
• Подтверждены тесты производительности, сделанные автором NETMAP – Luigi Rizzo
• Продемонстрированы основные приёмы использования NETMAP на примерах прототипов генератора трафика и подсистемы очистки трафика.
Благодаря подходу, реализованному в NETMAP, автору доклада удалось добиться нужно производительности при фильтрации трафика в проекте DDOS-защиты RUSCREEN, позволяющей работать на скоростях 14Mpps.
БОЛЬШОЕ СПАСИБО ЗА ВНИМАНИЕ !