vop Опубликовано 14 сентября, 2017 · Жалоба 1 час назад, oleg_n сказал: - добавлено удаление .... и финальных '/' в http uri.... А это зачем? > curl -D- http://forum.nag.ru/uploads HTTP/1.1 301 Moved Permanently Server: nginx/1.10.1 Date: Thu, 14 Sep 2017 16:52:10 GMT Content-Type: text/html; charset=iso-8859-1 Content-Length: 236 Connection: keep-alive Location: http://forum.nag.ru/uploads/ Cache-Control: max-age=86400 Expires: Fri, 15 Sep 2017 16:52:10 GMT .... Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 15 сентября, 2017 · Жалоба 16 часов назад, vop сказал: А это зачем? > curl -D- http://forum.nag.ru/uploads HTTP/1.1 301 Moved Permanently Server: nginx/1.10.1 Date: Thu, 14 Sep 2017 16:52:10 GMT Content-Type: text/html; charset=iso-8859-1 Content-Length: 236 Connection: keep-alive Location: http://forum.nag.ru/uploads/ Cache-Control: max-age=86400 Expires: Fri, 15 Sep 2017 16:52:10 GMT .... Вот именно за этим. В реестре были замечены записи, которые отличаются только финальным '/'. Т.о. уменьшаем дублирующие записи. Плюс, если в блоке есть http://some.domain, а пользователь вводит http://some.domain/, то, благодаря приведению к виду http://some.domain, мы блокируем этот запрос. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 19 сентября, 2017 · Жалоба Надо данные нагрузочного тестирования. Так как libnfqueue копирует данные в пространство пользователя, сдается мне 10G там смысла не имеет даже трогать. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 20 сентября, 2017 · Жалоба 20 часов назад, StSphinx сказал: Надо данные нагрузочного тестирования. Пока точных данных не могу получить. Но примерные такие: - xeon E5-2603, 8 ядер - ~700Mb/s - 6 очередей nfq - LA ~1.5 Цитата Так как libnfqueue копирует данные в пространство пользователя, сдается мне 10G там смысла не имеет даже трогать. Это да, это печально. Но потрогать, если есть в наличии 10G всё таки можно. Если же не для теста, а для полноценной работы, то, думаю, лучше применять комбинированные схемы работы. Допустим, ipset'ом фильтровать ip'шники, потом оставшийся трафик ipset'ом направлять выборочно на фильтр. Если будет время, хотел попробовать комбинированную схему такую: - ipset'ом фильтровать ip - domainset'ом(модуль, который надо сделать на основе ipset, который будет фильтовать чисто dns-запросы) фильтровать домены - оставшийся трафик(остаётся http) выборочно по портам или по ip(ipset'ом) отправлять на фильтр уже Это должна быть достаточно эффективная схема. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 20 сентября, 2017 · Жалоба 1 минуту назад, oleg_n сказал: Пока точных данных не могу получить. Но примерные такие: - xeon E5-2603, 8 ядер - ~700Mb/s - 6 очередей nfq - LA ~1.5 Это да, это печально. Но потрогать, если есть в наличии 10G всё таки можно. Если же не для теста, а для полноценной работы, то, думаю, лучше применять комбинированные схемы работы. Допустим, ipset'ом фильтровать ip'шники, потом оставшийся трафик ipset'ом направлять выборочно на фильтр. Если будет время, хотел попробовать комбинированную схему такую: - ipset'ом фильтровать ip - domainset'ом(модуль, который надо сделать на основе ipset, который будет фильтовать чисто dns-запросы) фильтровать домены - оставшийся трафик(остаётся http) выборочно по портам или по ip(ipset'ом) отправлять на фильтр уже Это должна быть достаточно эффективная схема. Может проще было решить проблему кардинально - сменить engine обработки трафика на что-то типа dpdk/netmap ? Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 20 сентября, 2017 (изменено) · Жалоба 52 минуты назад, StSphinx сказал: Может проще было решить проблему кардинально - сменить engine обработки трафика на что-то типа dpdk/netmap ? ПО изначально делалось под требования заказчика в 1-2Gb/s. С этим оно справляется с запасом, свою задачу выполняет. Зачем сейчас, когда уже всё отлажено, что-то менять? Насчёт простоты. По требуемому времени проще как раз реализовать комбинированную схему. Даже если вкладываться в написание аналога ipset для dns-фильтрации. Единственный момент - перечитывание конфига. trfl фильтрует трафик по текущему конфигу, перечитывая новый, и в конце этого процесса переключается на новый; т.о. нет моментов работы по неполному списку из-за этого(всегда в работе полный список - либо старый, либо новый). С ipset возможны пропуски в момент обновления конфига, даже при использовании rename(их будет, конечно, ничтожное кол-во, но всё же). Насчёт кардинального. Мне как раз более кардинальным видится уход полностью в пространство ядра, что бы избежать копирования пакетов. Если делать красиво, то надо просто сделать недостающие модули для netfilter, что бы можно было использовать iptables/nftables. Для фильтрации ip есть ipset; для фильтрации доменов сделать на основе ipset модуль; для фильтрации tls сделать модуль; и для фильтрации http тоже придётся модуль сделать. Т.о. получим гибкую систему в связке с iptables/nftables, где админ правила создал, а rknr_get.pl какой-нибудь просто обновляет списки. Это был бы самый лучший вариант с точки зрения производительности(немного медленней dpdk/netmap, но с возможностью ставить в разрыв, интергацией с iptables и не зависимостью от сетевого оборудования). И не надо тащить trfl полностью монолитом в ядро. По поводу dpdk. Я лично с ним не работал, поэтому такие манёвры достаточно затратны по времени. И есть же уже extfilter, если хочется dpdk. Люди пользуются. Работает хорошо, судя по отзывам. Про netmap только услышал. Мне лично что не оч. нравится в dpdk(у netmap, насколько успел понять, такая же особенность), что не все сетёвки поддерживаются. Это наверное не касается каналов в 10Gb/s, т.к. все серьёзные девайсы там поддерживаются, насколько я знаю, но всё же если взять за внимание, что с dpdk я не работал совсем, а модули ядра когда-то какие-то писал, плюс то, что модуль ядра для netfilter будет работать со всеми сетёвками, которые поддерживает linux, то проще замарочиться модулем ядра(при всех его минусах, вроде kernel panic). Изменено 20 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 20 сентября, 2017 · Жалоба Даже в текущем коде ещё есть места, где можно подвыжать производительности: - замутить свой аллокатор памяти для выделения большого куска памяти под разбор пакета, где все внутреннии malloc'и будут копошиться в этом куске; этот кусок не освобождается, а используется повторно для следующего пакета; в итоге будет, грубо, один malloc при старте trfl и ни одного malloc/free потом; - почти тоже самое для конфига(добиваемся одной пары (free, malloc) при перечитывании конфига); - интеграция с conntrack(может снизить существенно нагрузку) Хз насколько результат этого всего можно будет ощутить на 10Gb/s :-). Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
Ivan_83 Опубликовано 20 сентября, 2017 · Жалоба 1 час назад, oleg_n сказал: - замутить свой аллокатор памяти для выделения большого куска памяти под разбор пакета, где все внутреннии malloc'и будут копошиться в этом куске; этот кусок не освобождается, а используется повторно для следующего пакета; в итоге будет, грубо, один malloc при старте trfl и ни одного malloc/free потом; Должен быть такой уже в ядре. Во фре точно есть спец аллокатор для таких вещей. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 20 сентября, 2017 (изменено) · Жалоба 2 минуты назад, Ivan_83 сказал: Должен быть такой уже в ядре. Во фре точно есть спец аллокатор для таких вещей. Да, есть такой - slab. Но оно только для выделения памяти в пространстве ядра. Изменено 20 сентября, 2017 пользователем StSphinx Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 20 сентября, 2017 · Жалоба 51 минуту назад, Ivan_83 сказал: Должен быть такой уже в ядре. Во фре точно есть спец аллокатор для таких вещей. Не скажу, что я сильно упорно искал, но не слышал о таком для пространства пользователя(хотя нужон бывает очень для подобных задач). Может и есть какой заброшенный проект на github, но чем копаться в подобном, если есть, проще свой написать - по моим прикидкам там ничего особенного не будет. Список блоков с большими кусками, внутри которых подобные списки с маленькими кусками(на каждый malloc в коде). Главное, что бы всё это богатство было выравнено правильно для быстрого доступа. Но тут вся надежда на умолчальное выравнивание указателей. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 21 сентября, 2017 · Жалоба 17 часов назад, oleg_n сказал: Не скажу, что я сильно упорно искал, но не слышал о таком для пространства пользователя(хотя нужон бывает очень для подобных задач). Может и есть какой заброшенный проект на github, но чем копаться в подобном, если есть, проще свой написать - по моим прикидкам там ничего особенного не будет. Список блоков с большими кусками, внутри которых подобные списки с маленькими кусками(на каждый malloc в коде). Главное, что бы всё это богатство было выравнено правильно для быстрого доступа. Но тут вся надежда на умолчальное выравнивание указателей. В Glib есть аллокатор, который выделяет память пулами с равными участками. Очень удобная штука. https://developer.gnome.org/glib/2.42/glib-Memory-Slices.html Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 21 сентября, 2017 · Жалоба 1 час назад, StSphinx сказал: В Glib есть аллокатор, который выделяет память пулами с равными участками. Очень удобная штука. https://developer.gnome.org/glib/2.42/glib-Memory-Slices.html О. glib. Давно её не пользовал. Хорошая штука. Конкретно эти функции немного не то, что мне надо. Найду время, покажу о чём я говорю. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
Ivan_83 Опубликовано 21 сентября, 2017 · Жалоба 2 часа назад, StSphinx сказал: В Glib есть аллокатор, который выделяет память пулами с равными участками. ИМХО тот же jmalloc имеет всякие фичи внутри для подобных ситуаций, просто оно отдельно не вынесено. Нужно брать доки и читать. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 21 сентября, 2017 · Жалоба 30 минут назад, Ivan_83 сказал: ИМХО тот же jmalloc имеет всякие фичи внутри для подобных ситуаций, просто оно отдельно не вынесено. Нужно брать доки и читать. jmalloc можно тоже поковырять. Мне нужна достаточно простая вещь и быстрая. glib Memory Slices крутая вещь, но для данной задачи выглядит overkill'ом, плюс бонусом будет зависимость проекта от glib. Хотелось бы без необходимости не добавлять новых зависимостей. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
MATPOC Опубликовано 21 сентября, 2017 · Жалоба 6 часов назад, oleg_n сказал: плюс бонусом будет зависимость проекта от glib Зависимость от glib - это меньшая из забот. Любой мало-мальски сложный проект его использует. Можно воспринимать glib как libc 2.0 :) Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 22 сентября, 2017 (изменено) · Жалоба 15 часов назад, MATPOC сказал: Любой мало-мальски сложный проект его использует. Ну, это не является техническим основанием для использования :-). Мало ли кто там что использует. Я не против glib, более того я за и использовал её в некоторых проектах, но конкретно в этом случае вижу следующие технические моменты: - glib такая штука, что если её использовать, то проще во всём проекте(у неё свои типы и т.п.); - тащить же зависимостью немаленькую glib ради одного функционала как-то не обосновано; - если же очень хочется этот один функционал, то архитектурно правильней, imho, будет в этом случае вырезать нужную её часть(Memory Slices) и вставить в проект(хотя это связано с возможным гемором поддержки данного кода в синхронизированном состоянии с upstream); - кроме всего, как я уже говорил, Memory Slices это overkill(и не совсем то) в данном случае, что делает использование glib только ради этого вообще бессмысленным. Изменено 22 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 22 сентября, 2017 (изменено) · Жалоба Коллеги, появилась новая мысль по поводу путей оптимизации. Думаю, можно обойтись одним ядерным модулем и оставить trfl почти как есть, но при этом увеличить производительность в несколько раз(до 10 раз!). Мысль такая. Нужен модуль, который будет на основе списка соединений выставлять 3 разных метки пакетам(new, accept, drop). Далее по цепочке iptables: - если mark соответствует drop, то пакет отбрасываем(или перенаправляем куда надо); - если mark соответствует accept, то accept; - если mark соответствует new, то пакет уходит в trfl через nfqueue, где, если уже ясно каков вердикт, через какой-нибудь netlink модулю ядра отсылается инфа по данному соединению(accept или drop). Такая схемка: -->МОДУЛЬ--->NFQUEUE----> ^ ^ | |PKT |CONNMARK v +----------------+ | TRFL | +----------------+ Описаные ранее варианты, с выборочным направлением пакетов с помощью ipset в nfqueue тоже можно использовать дополнительно. Изменено 22 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 22 сентября, 2017 · Жалоба Во всем этом мне видится одна фундаментальная проблема - как отделять мух от котлет? То есть, если web ходит не по стандартным портам? Или я что-то упустил? А, нет, даже две:) Вторая это сборка сессий. Кто мешает пользователю выставить MTU для определенного типа трафика по-меньше, со всеми вытекающими. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 22 сентября, 2017 (изменено) · Жалоба 43 минуты назад, StSphinx сказал: Во всем этом мне видится одна фундаментальная проблема - как отделять мух от котлет? То есть, если web ходит не по стандартным портам? Или я что-то упустил? А, нет, даже две:) Вторая это сборка сессий. Кто мешает пользователю выставить MTU для определенного типа трафика по-меньше, со всеми вытекающими. Описаная схема, как и используемая сейчас, подразумевает прохождение _всего_ трафика через фильтр(стандартные порты, нестандартные - не важно). Сборкой сессий будет заниматься trfl с помощью conntrack. Если же в разрезе выборочного отвода трафика с помощью ipset говорить про удовлетворение РКН, то хватит отправления через nfqueue ip/портов, которые фигурируют в реестре. 43 минуты назад, StSphinx сказал: Кто мешает пользователю выставить MTU для определенного типа трафика по-меньше, со всеми вытекающими. Если речь про фрагментацию ip, то тут сборкой целого ip-пакета занимается ядро. Нам этим заморачиваться не надо. Изменено 22 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
max1976 Опубликовано 22 сентября, 2017 · Жалоба 10 минут назад, oleg_n сказал: Если речь про фрагментацию ip, то тут сборкой целого ip-пакета занимается ядро. Нам этим заморачиваться не надо. Скорее имеется в виду сборка TCP сессии. Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 22 сентября, 2017 (изменено) · Жалоба 3 минуты назад, max1976 сказал: Скорее имеется в виду сборка TCP сессии. Ну, тогда как и писал - trfl + conntrack(libnetfilter_conntrack) сессии собирает для вынесения решения, а модуль ядра этим сессиям уже выставляет метки в соответствии с принятыми решениями. Изменено 22 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 22 сентября, 2017 · Жалоба Накидал тут по-быстрому общий вид аллокатора: #ifndef __MEMPILE__H__ #define __MEMPILE__H__ #include "list.h" struct mempile_piece { unsigned int size; }; struct mempile { struct list_item_head list; unsigned int size; unsigned int size_free; void *child_next; }; struct mempile* mempile_make(unsigned int size_def); void* mempile_palloc(struct mempile *mempile, unsigned int size); void mempile_reset(struct mempile *mpile); #endif /* __MEMPILE__H__ */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include "mempile.h" static void* _mempile_padd(struct mempile *mpile, unsigned int size); static unsigned int _sizeof_aligned(unsigned int size) { unsigned int rem; rem = size % sizeof(void*); if (rem) size += sizeof(void*) - rem; return size; } static void* _ptr_aligned(void *ptr) { unsigned int rem; rem = (unsigned long long int)ptr % sizeof(void*); if (rem) ptr += sizeof(void*) - rem; return ptr; } struct mempile* mempile_make(unsigned int size) { struct mempile *mpile; mpile = malloc(size + _sizeof_aligned(sizeof(*mpile))); if (!mpile) return NULL; memset(mpile, 0, sizeof(*mpile)); list_item_head_init(&mpile->list); mpile->size = size; mpile->size_free = size - _sizeof_aligned(sizeof(struct mempile_piece)); mpile->child_next = (void*)mpile + _sizeof_aligned(sizeof(*mpile)); return mpile; } void* mempile_palloc(struct mempile *mempile, unsigned int size) { struct list_item_head *lh; struct mempile *mpile, *mpile_last; list_for_each(lh, &mempile->list) { mpile = list_item(lh, struct mempile, list); if (mpile->size_free >= size) return _mempile_padd(mpile, size); } mpile_last = mpile; if (size > mempile->size) mpile = mempile_make(size + _sizeof_aligned(sizeof(struct mempile_piece))); else mpile = mempile_make(mempile->size); if (!mpile) return NULL; list_add(&mpile->list, &mpile_last->list); return _mempile_padd(mpile, size); } static void* _mempile_padd(struct mempile *mpile, unsigned int size) { struct mempile_piece *mpile_piece; unsigned int s; if (mpile->size_free < size) abort(); mpile_piece = mpile->child_next; memset(mpile_piece, 0, sizeof(*mpile_piece)); list_item_head_init(&mpile_piece->list); mpile_piece->size = size; mpile->child_next = _ptr_aligned(mpile->child_next + _sizeof_aligned(sizeof(*mpile_piece)) + size); s = mpile->child_next - (void*)mpile_piece; if (s < mpile->size_free) mpile->size_free -= s; else mpile->size_free = 0; return mpile_piece + _sizeof_aligned(sizeof(*mpile_piece)); } void mempile_reset(struct mempile *mempile) { struct list_item_head *lh; struct mempile *mpile, *mpile_last; list_for_each(lh, &mempile->list) { mpile = list_item(lh, struct mempile, list); mpile->size_free = mpile->size - _sizeof_aligned(sizeof(struct mempile_piece)); mpile->child_next = (void*)mpile + _sizeof_aligned(sizeof(*mpile)); } } Используется как-то так: struct mempile *mpile; char *str; mpile = mempile_make(4 * 1024 * 1024); if (!mpile) exit(1); str = mempile_palloc(mpile, 1000); if (!str) exit(1); ... /* рабочий цикл закончен, сбрасываем выделенные куски для нового использования */ mempile_reset(mpile); str = mempile_palloc(mpile, 1000); if (!str) exit(1); ... Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
StSphinx Опубликовано 25 сентября, 2017 · Жалоба Извиняюсь, неточно выразился. Имелось ввиду TCP MSS. По поводу кода - само собой каждый C-шник должен написать свой аллокатор, но наверное лучше взять что-то проверенное временем? Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
oleg_n Опубликовано 25 сентября, 2017 (изменено) · Жалоба 2 часа назад, StSphinx сказал: По поводу кода - само собой каждый C-шник должен написать свой аллокатор, но наверное лучше взять что-то проверенное временем? Лучше. Но где? Мне нужен аллокатор для разбора пакета, упрощёно, выделяющий большой кусок памяти сразу и все последующие выделения осуществляющий внутри этого куска. Код, который я выше выложил, несмотря на то, что это эскизный вариант, _уже_ справляется с этой задачей. И он специфичный имено для данного случая, стало быть лишён каких-либо излишеств в функционале, которые будут отрицительно влиять на производтельность, и его намного проще оптимизировать, чем тот же glib Memory Slices. Хотя, при достаточном времени, в идеале, конечно, сделать и так и так и померять производительность. Изменено 25 сентября, 2017 пользователем oleg_n Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...
shamani Опубликовано 26 сентября, 2017 · Жалоба oleg_n, подскажите я по коду так и не понял. Как осуществляется блокировка https? По IP или по server name? Вставить ник Цитата Ответить с цитированием Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах More sharing options...