Назад | Перейти на главную страницу

Ядро Linux не проходит через многоадресные UDP-пакеты

Недавно я установил новый сервер Ubuntu 10.04 и заметил, что мой UDP-сервер больше не может видеть какие-либо данные многоадресной рассылки, отправленные на интерфейс, даже после присоединения к группе многоадресной рассылки. У меня точно такая же настройка на двух других машинах Ubuntu 8.04.4 LTS, и нет проблем с получением данных после присоединения к той же группе многоадресной рассылки.

Карта Ethernet - это Broadcom netXtreme II BCM5709, и используемый драйвер:

b $ ethtool -i eth1
driver: bnx2
version: 2.0.2
firmware-version: 5.0.11 NCSI 2.0.5
bus-info: 0000:01:00.1

Я использую smcroute для управления своими многоадресными регистрациями.

b$ smcroute -d
b$ smcroute -j eth1 233.37.54.71

После присоединения к группе ip maddr показывает добавленную регистрацию.

b$ ip maddr

    1:  lo
        inet  224.0.0.1
        inet6 ff02::1
    2:  eth0
        link  33:33:ff:40:c6:ad
        link  01:00:5e:00:00:01
        link  33:33:00:00:00:01
        inet  224.0.0.1
        inet6 ff02::1:ff40:c6ad
        inet6 ff02::1
    3:  eth1
        link  01:00:5e:25:36:47
        link  01:00:5e:25:36:3e
        link  01:00:5e:25:36:3d
        link  33:33:ff:40:c6:af
        link  01:00:5e:00:00:01
        link  33:33:00:00:00:01
        inet  233.37.54.71 <------- McastGroup.
        inet  224.0.0.1
        inet6 ff02::1:ff40:c6af
        inet6 ff02::1

Пока все хорошо, я вижу, что получаю данные для этой группы многоадресной рассылки.

b$ sudo tcpdump -i eth1 -s 65534 host 233.37.54.71
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65534 bytes
09:30:09.924337 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
09:30:09.947547 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
09:30:10.108378 IP 192.164.1.120.58866 > 233.37.54.71.15574: UDP, length 268
09:30:10.196841 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
...

Я также могу подтвердить, что интерфейс принимает пакеты mcast.

b $ ethtool -S eth1 | grep mcast_pack
rx_mcast_packets: 103998
tx_mcast_packets: 33

Теперь вот в чем проблема. Когда я пытаюсь захватить трафик с помощью простого UDP-сервера ruby, я получаю нулевые данные! Вот простой сервер, который считывает данные, отправленные через порт 15572, и печатает первые два символа. Это работает на двух серверах Ubuntu 8.04.4, но не на сервере 10.04.

require 'socket'
s = UDPSocket.new
s.bind("", 15572)
5.times do
  text, sender = s.recvfrom(2)
  puts text
end

Если я отправлю UDP-пакет, созданный на ruby, на localhost, сервер получит его и распечатает первые два символа. Итак, я знаю, что указанный выше сервер работает правильно.

irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UDPSocket.new
=> #<UDPSocket:0x7f3ccd6615f0>
irb(main):003:0> s.send("I2 XXX", 0, 'localhost', 15572)

Когда я проверяю статистику протокола, я вижу, что InMcastPkts не увеличивается. В то время как на других серверах 8.04 в той же сети было получено несколько тысяч пакетов за 10 секунд.

b $ netstat -sgu ; sleep 10 ; netstat -sgu
IcmpMsg:
    InType3: 11
    OutType3: 11
Udp:
    446 packets received
    4 packets to unknown port received.
    0 packet receive errors
    461 packets sent
UdpLite:
IpExt:
    InMcastPkts: 4654 <--------- Same as below
    OutMcastPkts: 3426
    InBcastPkts: 9854
    InOctets: -1691733021
    OutOctets: 51187936
    InMcastOctets: 145207
    OutMcastOctets: 109680
    InBcastOctets: 1246341
IcmpMsg:
    InType3: 11
    OutType3: 11
Udp:
    446 packets received
    4 packets to unknown port received.
    0 packet receive errors
    461 packets sent
UdpLite:
IpExt:
    InMcastPkts: 4656  <-------------- Same as above
    OutMcastPkts: 3427
    InBcastPkts: 9854
    InOctets: -1690886265
    OutOctets: 51188788
    InMcastOctets: 145267
    OutMcastOctets: 109712
    InBcastOctets: 1246341

Если я попытаюсь принудительно переключить интерфейс в режим promisc, ничего не изменится.

На этом я застрял. Я подтвердил, что в конфигурации ядра включена многоадресная рассылка. Возможно, мне стоит проверить другие параметры конфигурации?

b $ grep CONFIG_IP_MULTICAST /boot/config-2.6.32-23-server
CONFIG_IP_MULTICAST=y

Есть мысли о том, куда идти дальше?

В нашем случае наша проблема была решена с помощью параметров sysctl, отличных от Maciej.

Обратите внимание, что я не говорю о OP (buecking), я пришел к этому сообщению из-за проблемы, связанной с основными деталями (отсутствие многоадресного трафика в пользовательском пространстве).

У нас есть приложение, которое считывает данные, отправленные на четыре адреса многоадресной рассылки и уникальный порт для каждого адреса многоадресной рассылки, с устройства, которое (обычно) подключено непосредственно к интерфейсу на принимающем сервере.

Мы пытались развернуть это программное обеспечение на сайте клиента, но при загадочном сбое по неизвестной причине. Попытки отладки этого программного обеспечения привели к проверке каждого системного вызова, и в конечном итоге все они сказали нам одно и то же:

Наше программное обеспечение запрашивает данные, а ОС их никогда не предоставляет.

Счетчик многоадресных пакетов увеличился, tcpdump показал, что трафик достигает интерфейса / бокса, но мы ничего не могли с этим поделать. SELinux был отключен, iptables работал, но не имел правил ни в одной из таблиц.

Мы были в тупике.

Случайно ковыряясь, мы начали думать о параметрах ядра, которые обрабатывает sysctl, но ни одна из задокументированных функций не была особенно актуальной, или, если они имели отношение к многоадресному трафику, они были включены. Да, и ifconfig действительно перечислил "MULTICAST" в строке функций (up, broadcast, running, multicast). Мы из любопытства посмотрели /etc/sysctl.conf. И вот, к базовому изображению этого клиента добавлено несколько дополнительных строк внизу.

В нашем случае заказчик установил net.ipv4.all.rp_filter = 1. rp_filter - это фильтр Route Path, который (насколько я понимаю) отклоняет весь трафик, который не мог достичь этого поля. Переключение между подсетями в сети с мыслью, что исходный IP-адрес подделывается.

Итак, этот сервер находился в подсети 192.168.1 / 24, а исходный IP-адрес устройства для многоадресного трафика находился где-то в сети 10. *. Таким образом, фильтр не позволял серверу делать что-либо значимое с трафиком.

Пару настроек, одобренных заказчиком; net.ipv4.eth0.rp_filter = 1 и net.ipv4.eth1.rp_filter = 0 и мы счастливо бежали.

TL / DR Также убедитесь, что ваша мультикастинг не исходит от vlan. tcpdump -e поможет определить, есть ли у них.

Честно говоря, кто-то должен создать страницу с контрольным списком вещей, которые могут предотвратить попадание многоадресной рассылки в пользовательское пространство. Я боролся с этим пару дней, и, естественно, ничего, что я не мог найти в Интернете, не помогло.

Не только я мог видеть пакеты в tcpdump, Я действительно мог бы получать другие многоадресные пакеты для других производителей только на другом интерфейсе. Команда, которую я использовал для проверки, могу ли я принимать многоадресную рассылку, была:

$ GRP=224.x.x.x # set me to the group
$ PORT=yyyy # set me to the receiving port
$ IFACE=mmmm # set me to the name or IP address of the interface
$ strace -f socat -  UDP4-DATAGRAM:$GRP:$PORT,ip-add-membership=$GRP:$IFACE,bind=0.0.0.0:$PORT,multicast-loop=0

Причина для strace вот что я действительно не мог сделать socat распечатать пакеты на стандартный вывод, но в strace вывод вы можете четко увидеть, если socat получает фактические данные из привязанного сокета (в противном случае он будет отключен через пару начальных select звонки)

  • rp_filter sysctl - не применяется, системы находятся в одной IP-сети (я установил для них 0 все равно кажется что 1 сейчас это настройка по умолчанию, по крайней мере, для Ubuntu).
  • firewalls / etc - принимающая система не имеет брандмауэра (я не думаю, что пакеты будут отображаться в tcpdump, если они были защищены брандмауэром, но я думаю, что это возможно, если брандмауэр забавный)
  • IP / Multicast-маршрутизация и несколько интерфейсов - я явно присоединился к группе на правильном интерфейсе
  • Дурацкое сетевое оборудование - это было мое последнее средство, но смена ноутбука на Intel NUC не помогла. Именно здесь я начал грызть локти и постоянно публиковать это в SE.
  • В моем случае проблема заключалась в использовании VLAN специализированным оборудованием, которое создавало эти многоадресные пакеты. Чтобы убедиться, что это ваша проблема, обязательно включите -e флаг tcpdumpи проверьте наличие тегов vlan. Перед тем, как пользовательская среда сможет получать эти пакеты, потребуется настроить интерфейс на правильный vlan. На самом деле отличием для меня было то, что производители многоадресной рассылки не будут пинговать, но даже не попадут в кеш ARP, хотя я мог ясно видеть ответы ARP.

Чтобы запустить его с VLAN эта ссылка может быть полезно для настройки многоадресной маршрутизации. (К сожалению, я новичок в этом, поэтому Репутация не позволяет мне добавить ответ. Отсюда и это изменение.)

Вот что я сделал (при необходимости используйте sudo):

ip link add link eth0 name eth0_100 type vlan id 100
ip addr add 192.168.100.2/24 brd 192.168.100.255 dev eth0_100
ip link set dev eth0_100 up
ip maddr add 01:00:5e:01:01:01 dev eth0_100
route -n add -net 224.0.0.0 netmask 240.0.0.0 dev eth0_100

Таким образом создается дополнительный интерфейс для трафика vlan с идентификатором vlan 100. IP vlan может быть ненужным. Затем для нового интерфейса настраивается многоадресный адрес (01: 00: 5e: 01: 01: 01 - адрес канального уровня для 239.1.1.1), и весь входящий многоадресный трафик привязывается к eth0_100. Я также выполнил все возможные шаги в ответах выше (проверьте iptables, rp_filter и т. Д.).

Вы можете попробовать посмотреть на эти настройки:

proc

echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

sysctl.conf

sed -i -e 's|^net.ipv4.icmp_echo_ignore_broadcasts =.*|net.ipv4.icmp_echo_ignore_broadcasts = 0|g' /etc/sysctl.conf

Они использовались для включения многоадресной рассылки в RHEL.

Возможно, вы захотите убедиться, что ваш брандмауэр разрешает многоадресный трафик; снова с RHEL я включил следующее:

# allow anything in on multicast addresses
-A INPUT -s 224.0.0.0/4 -j ACCEPT
-A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT
# needed for multicast ping responses
-A INPUT -p icmp --icmp-type 0 -j ACCEPT

Вы используете управляемый коммутатор? У некоторых есть опции для предотвращения «широковещательных штормов» или других проблем с многоадресной рассылкой, которые заставляют их блокировать определенные типы пакетов. Я бы посоветовал взглянуть на вашу документацию по коммутатору.

s.bind("", 15572)

Уверен в ""? Почему бы не использовать для привязки IP-адрес многоадресной рассылки?