• Архив

    «   Март 2024   »
    Пн Вт Ср Чт Пт Сб Вс
            1 2 3
    4 5 6 7 8 9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 31
                 

Проблема со скоростью сети в виртуальном окружении VMWare ESXi 5.0

Имеем:
  1. VMWare ESXi 5.0.0-469512-standart хост
  2. CentOS 6.2 kernel 2.6.32-220.el6.x86_64 - гостевая система в виртуальной локальной сети (так же есть Windows 7 гость)
  3. CentOS 6.2 kernel 2.6.32-220.el6.x86_64 - гостевая система-маршрутизатор, обеспечивающая выход в глобальную сеть для других гостевых систем
Пусть маршрутизатор = router, а гостевая система = centos_test.
Router одной сетевой картой подключен к виртуальному свитчу 1, который в свою очередь подключен к wan интерфейсу хост системы.
Вторая сетевая карточка подключена к виртуальному свитчу 2, который не подключен к физическому интерфейсу.
Centos_test имеет одну сетевую карту, подключенную к свитчу 2.
В качестве сетвой карточки во всех виртуальных системах используется vmxnet3 (при использовании E1000 проблема так же наблюдается).

Таким образом создается DMZ внутри одного ESXi хоста.

В такой конфигурации мы замечаем очень медленную работу с centos_test по сети.
Скорость передачи падает чуть ли не до 10 килобайт в секунду.
Диагностика с помощью tcpdump обнаруживает следующее:
IP a.b.c.d > x.x.x.x: ICMP y.y.y.y unreachable - need to frag (mtu 1500), length 556
где a.b.c.d - IP router,  x.x.x.x - IP centos_test,  y.y.y.y - IP назначения потока данных из глобальной сети.
Проанализировав трафик, понимаем - centos_test пытается отправить пакет заметно большей длины, чем MTU,
на что и получает ответ о необходимости фрагментации.
По каким-то причинам виртуальная сетевая карточка не заботится о максимальном размере пакета, как указано на интерфейсе.

Как решить проблему? Гугл отправляет искать причины в включенном LRO (large receive offload) в ESXi.
Однако никакие рекомендованные манипуляции с настройками (Configuration->Advanced settings->Net), связанными с LRO (Net.VmxnetSwLROSL,Net.Vmxnet3SwLRO,Net.Vmxnet3HwLRO,Net.Vmxnet2SwLRO,Net.Vmxnet2HwLRO и другие),  
не дали результата.

Поиски решения дали понять, что в ESXi есть какие-то ошибки в реализации функциональности LRO и TSO (tcp segmentation offload),
которые обнаруживаются в специфичных реализациях. Найти решение на стороне ESXi хоста не удалось, поэтому проблему нужно исправлять на стороне виртуальной машины.
Для этого в гостевой системе нужно отключить поддержку tso (в даном конкретном случае этого достаточно)
на сетевой карточке:      
#ethtool -K eth0 tso off
Но в данной конкретной системе (свежая установка Centos 6.2 без апдейта) вместо выключения tso будет ошибка:
Cannot set device tcp segmentation offload settings: Operation not supported
И только после обновления ядра (в моем случае до 2.6.32-220.13.1.el6.x86_64) команда отрабатывает без ошибок.
После этого работа с сетью нормализуется.
Чтобы после перезагрузки tso выключалось без вашего вмешательства, добавьте команду в /etc/rc.local (для CentOS).

В гостевой системе Windows 7 нужно зайти в настройки сетевой карточки и выключить опцию:
“IPv4 - разгрузка большой отправки” для Е1000 и “IPv4 Giant TSO Offload” для vmxnet3.

CentOS и ARP резолвинг

В некоторых сетевых конфигурациях (например при использовании виртуализации, NAT), можно столкнуться с проблемой доступа в глобальную сеть хостов, которые маскируются маршрутизатором.

Допустим у нас есть сервер под управлением CentOS, который предоставляет доступ в глобальную сеть хостам из локальной сети.



На внешнем интерфейсе нашего маршрутизатора прописаны 2 IP. 10.0.0.2 - основной адрес, выданный провайдером.
172.16.0.1 - дополнительный адрес. Сеть 172.16.0.0/29 маршрутизируется провайдером на наш основной адрес 10.0.0.2.
192.168.0.0/24 - локальная сеть на внутреннем интерфейсе. Основной шлюз (default gateway) - 10.0.0.1
Дополнительный адрес мы используем для маскирования локальной сети, а так же для проброса портов на внутренние сервисы.

В такой конфигурации обнаруживается следующая проблема:  если в таблице арп кеша маршрутизатора нет записи для 10.0.0.1, то
при инициировании соединения со стороны локального клиента ARP request посылается от IP адреса, которым мы его маскируем:
arp who-has 10.0.0.1 tell 172.16.0.1
В зависимости от настроек шлюза провайдера, он в большинстве случаев не ответит на такой  запрос, поскольку адрес, анонсированный в запросе, не принадлежит к сети шлюза провайдера.

Не получив ответа, маршрутизатор не знает на какой мак-адрес отправлять пакет и отвечает клиенту о недоступности сети.

Для того, чтобы наш сервер всегда посылал арп запрос от правильного адреса, в CentOS (справедливо для linux систем c версией ядра начиная с 2.6.4 и 2.4.26), существует настройка ядра arp_announce, которая может принимать 3 значения: 0,1,2 (подробнее можно прочитать здесь: http://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt).

По умолчанию на всех интерфейсах стоит 0 - можно использовать любой IP адрес настроенный на интерфейсе для ARP request.
Рекомендуемое значение 2 - в этом случае система будет игнорировать source IP в исходящем пакете и для арп запроса будет всегда использовать "правильный" адрес. Данную опцию можно поменять как для каждого отдельного интерфейса так и для всех сразу.

Для включения без перезагрузки:
#sysctl -w net.ipv4.conf.all.arp_announce=2
Не забудьте добавить в /etc/sysctl.conf