Jądro Linux nie przechodzi przez pakiety UDP multiemisji

35

Niedawno skonfigurowałem nowy Ubuntu Server 10.04 i zauważyłem, że mój serwer UDP nie widzi już danych multiemisji wysyłanych do interfejsu, nawet po dołączeniu do grupy multiemisji. Mam dokładnie taką samą konfigurację na dwóch innych maszynach Ubuntu 8.04.4 LTS i nie ma problemu z odbieraniem danych po dołączeniu do tej samej grupy multiemisji.

Karta Ethernet to Broadcom netXtreme II BCM5709, a zastosowany sterownik to:

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

Używam smcroute do zarządzania moimi rejestracjami multiemisji.

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

Po dołączeniu do grupy ip maddr pokazuje nowo dodaną rejestrację.

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

Jak dotąd tak dobrze, widzę, że otrzymuję dane dla tej grupy multiemisji.

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
...

Mogę również potwierdzić, że interfejs odbiera pakiety Mcast.

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

Teraz jest problem. Kiedy próbuję przechwycić ruch za pomocą prostego serwera ruby ​​UDP, otrzymuję zero danych! Oto prosty serwer, który odczytuje dane wysyłane przez port 15572 i drukuje pierwsze dwa znaki. Działa to na dwóch serwerach Ubuntu 8.04.4, ale nie na serwerze 10.04.

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

Jeśli wyślę pakiet UDP spreparowany w rubinie do localhost, serwer odbierze go i wydrukuje dwa pierwsze znaki. Wiem więc, że powyższy serwer działa poprawnie.

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)

Kiedy sprawdzam statystyki protokołu, widzę, że InMcastPkts nie rośnie. Podczas gdy na innych serwerach 8.04, w tej samej sieci, otrzymałem kilka tysięcy pakietów w 10 sekund.

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

Jeśli spróbuję zmusić interfejs do trybu promis, nic się nie zmieni.

W tym momencie utknąłem. Potwierdziłem, że konfiguracja jądra ma włączoną multiemisję. Być może istnieją inne opcje konfiguracji, które powinienem sprawdzić?

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

Czy są jakieś przemyślenia na temat tego, gdzie się udać?

buecking
źródło
Domyśl. Idę wprowadzić nowe pytanie, powiązany algorytm z radością pokazuje mi, że to pytanie istnieje, ale nie ma znaczących odpowiedzi. Boo :(.
VxJasonxV
Nie jestem pewien, jak dokładnie zamierzam przyznać nagrodę. Współpracownik znalazł problem, a ja zorientowałem się, DLACZEGO to się stało, jak to się stało. Jestem więcej niż chętny do przedstawienia sugestii dotyczących przyznania nagrody.
VxJasonxV
wciąż jesteś w pobliżu? Mam do ciebie kilka pytań.
VxJasonxV
Też mam ten problem. Droga buicking, czy to rozwiązujesz?
Dla innych, którzy mieli ten problem - przeczytaj wszystkie odpowiedzi na to pytanie, ponieważ istnieją 2-3 ustawienia O / S, które należy naprawić. Rozwiązaliśmy ten problem poprzez zmianę rp_filteri /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts, a następnie rozpoczął pracę.
Sam Goldberg,

Odpowiedzi:

35

W naszym przypadku nasz problem został rozwiązany za pomocą parametrów sysctl, innych niż Maciej.

Pamiętaj, że nie mówię w imieniu OP (buecking), pojawiłem się w tym poście ze względu na problem związany z podstawowymi szczegółami (brak ruchu multiemisji w obszarze użytkownika).

Mamy aplikację, która odczytuje dane wysyłane na cztery adresy multiemisji i unikalny port na adres multiemisji z urządzenia, które jest (zwykle) podłączone bezpośrednio do interfejsu na serwerze odbierającym.

Próbowaliśmy wdrożyć to oprogramowanie w witrynie klienta, gdy w tajemniczy sposób zawiodło bez żadnego znanego powodu. Próby debugowania tego oprogramowania spowodowały sprawdzenie każdego wywołania systemowego, ostatecznie wszyscy powiedzieli nam to samo:

Nasze oprogramowanie prosi o dane, a system operacyjny nigdy ich nie udostępnia.

Zwiększony licznik pakietów multiemisji, tcpdump, pokazał ruch docierający do interfejsu / konkretnego interfejsu, ale nie mogliśmy nic z tym zrobić. SELinux został wyłączony, iptables działało, ale nie miało żadnych reguł w żadnej z tabel.

Zakłopotani, byliśmy.

Podczas losowego przeszukiwania zaczęliśmy myśleć o parametrach jądra, które obsługuje sysctl, ale żadna z udokumentowanych funkcji nie była szczególnie istotna, lub jeśli miały one związek z ruchem multiemisji, były one włączone. Aha, a ifconfig umieścił „MULTICAST” w linii funkcji (up, broadcast, running, multicast). Z ciekawości spojrzeliśmy /etc/sysctl.conf. oto podstawowy obraz tego klienta ma na dole kilka dodatkowych wierszy.

W naszym przypadku klient ustawił net.ipv4.all.rp_filter = 1. rp_filter to filtr Ścieżki trasy, który (jak rozumiem) odrzuca cały ruch, który nie mógłby dotrzeć do tego pola. Przeskakiwanie podsieci sieciowej, myśląc, że źródłowy adres IP jest sfałszowany.

Cóż, ten serwer był w podsieci 192.168.1 / 24, a źródłowy adres IP urządzenia dla ruchu multiemisji znajdował się gdzieś w sieci 10. *. W ten sposób filtr uniemożliwiał serwerowi robienie czegokolwiek znaczącego z ruchem.

Kilka poprawek zatwierdzonych przez klienta; net.ipv4.eth0.rp_filter = 1i net.ipv4.eth1.rp_filter = 0biegliśmy szczęśliwie.

VxJasonxV
źródło
2
To zadziałało! rp_filterDla naszego interfejsu sieciowego 10 Gb dumping wszystkich naszych pakietów UDP multicast. Wyłączenie filtra pozwala na przepływ wszystkiego.
chrisaycock
Mieliśmy problemy z konfiguracją przesyłania strumieniowego przez multiemisję AMT przez urządzenie tun na odbiorniku Ubuntu i mogliśmy zobaczyć pakiety dostarczane do urządzenia przez tcpdump, ale aplikacja po prostu nie chce streamować. Ten post nas ocalił!
inżynier oprogramowania
2
Działając na Ubuntu 14.04, działało to tylko dla mnie po ustawieniu net.ipv4.all.rp_filter = 0. W szczególności, gdy dane multiemisji docierały do ​​eth2, musiałem ustawić zarówno net.ipv4.eth2.rp_filter = 0i net.ipv4.all.rp_filter = 0.
T-Hawk,
4

TL / DR Upewnij się także, że multiemisja nie pochodzi z sieci Vlan. tcpdump -epomogłoby ustalić, czy tak.

Szczerze mówiąc, ktoś powinien zbudować stronę z listą kontrolną rzeczy, które mogą uniemożliwić multicastowi dotarcie do obszaru użytkownika. Walczyłem z tym od kilku dni i oczywiście nic, co mogłem znaleźć w Internecie, nie pomogło.

Nie tylko mogłem zobaczyć pakiety tcpdump, ale mogłem odbierać inne pakiety multiemisji dla innych producentów, tylko na innym interfejsie. Polecenie, którego użyłem do testowania, czy mogę odbierać multiemisję, brzmiało:

$ 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

Powodem stracejest to, że tak naprawdę nie mogłem socatwydrukować pakietów na standardowe wyjście, ale na stracewyjściu możesz wyraźnie zobaczyć, czy socatodbiera rzeczywiste dane z powiązanego gniazda (w przeciwnym razie zostanie wyciszone po kilku początkowych selectwywołaniach)

  • rp_filtersysctl - nie dotyczy, systemy są w tej samej sieci IP (ustawiłem je 0tak samo, wydaje się, że 1jest to ustawienie domyślne, przynajmniej dla Ubuntu).
  • firewalls / etc - system odbierający jest wolny od zapory ogniowej (nie sądzę, aby pakiety były wyświetlane w tcpdump, gdyby były zaporowe, ale myślę, że jest to możliwe, jeśli firewall jest zabawny)
  • Routing IP / Multicast i wiele interfejsów - wyraźnie dołączyłem do grupy na odpowiednim interfejsie
  • Wacky sprzęt sieciowy - to była moja ostatnia deska ratunku, ale zmiana laptopa na Intel NUC nie pomogła. Chodzi o to, gdzie zacząłem przeżuwać łokcie i popychać to, publikując to na SE.
  • Problem w moim przypadku polegał na wykorzystaniu sieci VLAN przez specjalistyczny sprzęt, który produkował te pakiety multiemisji. Aby sprawdzić, czy to jest twój problem, pamiętaj o dołączeniu -eflagi do tcpdumpi sprawdź tagi vlan. Konieczne będzie skonfigurowanie interfejsu w poprawnym vlan, zanim użytkownik będzie mógł uzyskać te pakiety. W gruncie rzeczy dla mnie było to, że producenci rozsyłania grupowego nie pingują, ale nawet nie dostają się do pamięci podręcznej ARP, chociaż wyraźnie widziałem odpowiedzi ARP.

Aby uruchomić go z VLAN, ten link może być pomocny w konfiguracji routingu multiemisji. (Niestety, jestem w tym nowy, więc Reputacja nie pozwala mi dodawać odpowiedzi. Stąd ta edycja).

Oto co zrobiłem (w razie potrzeby użyj 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

W ten sposób dodatkowy interfejs, jeśli zostanie utworzony dla ruchu vlan z vlan id 100. IP vlan może być niepotrzebny. Następnie konfigurowany jest adres multiemisji dla nowego interfejsu (01: 00: 5e: 01: 01: 01 jest adresem warstwy łącza dla 239.1.1.1) i cały przychodzący ruch multiemisji jest powiązany z eth0_100. Zrobiłem także wszystkie możliwe kroki w powyższych odpowiedziach (sprawdź iptables, rp_filter itp.).

Paweł Veselov
źródło
@Gero: Dodanie trasy multiemisji powoduje skonfigurowanie wychodzącej multiemisji, a nie przychodzącej multiemisji. Nie powiąż bezpośrednio adresów IP multiemisji z interfejsami, chyba że robisz coś fajnego, zwykle jest to zadanie aplikacji.
Paweł Veselov,
2

Możesz spróbować spojrzeć na te ustawienia:

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

Zostały one wykorzystane do włączenia multiemisji w RHEL.

Możesz się upewnić, że zapora zezwala na ruch mutlicast; ponownie z RHEL włączyłem następujące:

# 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
użytkownik64259
źródło
Opcje „emisji” dotyczą również „multiemisji”?
Raedwald
0

Czy używasz przełącznika zarządzanego? Niektóre mają opcje zapobiegania „burzom rozgłoszeniowym” lub innym problemom związanym z multiemisją, które uniemożliwiłyby im niektóre typy pakietów. Proponuję zajrzeć do dokumentacji przełącznika.

devicenull
źródło
0
s.bind("", 15572)

Pewny czegos ""? Dlaczego nie skorzystać z adresu IP multiemisji do połączenia?

poige
źródło
puste adresy hostów zwykle oznaczają „wszystkie interfejsy”.
VxJasonxV,