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

Post on 05-Jul-2015

2.700 views 8 download

Transcript of Netmap (by luigi rizzo) простой и удобный opensource фреймворк для...

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.

БОЛЬШОЕ СПАСИБО ЗА ВНИМАНИЕ !