web-dev-qa-db-fra.com

Le noyau Linux ne passe pas par les paquets UDP multicast

Récemment, j'ai configuré un nouveau serveur Ubuntu 10.04 et j'ai remarqué que mon serveur UDP n'est plus en mesure de voir les données de multidiffusion envoyées à l'interface, même après avoir rejoint le groupe de multidiffusion. J'ai exactement la même configuration sur deux autres machines Ubuntu 8.04.4 LTS et il n'y a aucun problème à recevoir des données après avoir rejoint le même groupe de multidiffusion.

La carte Ethernet est un Broadcom netXtreme II BCM5709 et le pilote utilisé est:

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

J'utilise smcroute pour gérer mes enregistrements multicast.

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

Après avoir rejoint le groupe, ip maddr affiche l'enregistrement nouvellement ajouté.

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

Jusqu'ici tout va bien, je peux voir que je reçois des données pour ce groupe de multidiffusion.

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

Je peux également confirmer que l'interface reçoit des paquets mcast.

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

Voici maintenant le problème. Lorsque j'essaie de capturer le trafic à l'aide d'un simple serveur Ruby UDP, je ne reçois aucune donnée! Voici un serveur simple qui lit les données envoyées sur le port 15572 et imprime les deux premiers caractères. Cela fonctionne sur les deux 8.04.4 Serveurs Ubuntu, mais pas le serveur 10.04.

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

Si j'envoie un paquet UDP conçu en Ruby à localhost, le serveur le reçoit et imprime les deux premiers caractères. Je sais donc que le serveur ci-dessus fonctionne correctement.

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)

Lorsque je vérifie les statistiques du protocole, je constate que InMcastPkts n'augmente pas. Sur les autres serveurs 8.04, sur le même réseau, a reçu quelques milliers de paquets en 10 secondes.

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

Si j'essaye de forcer l'interface en mode promisc, rien ne change.

À ce stade, je suis coincé. J'ai confirmé que la configuration du noyau a activé la multidiffusion. Peut-être qu'il y a d'autres options de configuration que je devrais vérifier?

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

Des réflexions sur où aller d'ici?

36
buecking

Dans notre exemple, notre problème a été résolu par des paramètres sysctl, différents de Maciej.

Veuillez noter que je ne parle pas pour l'OP (buecking), je suis venu sur ce poste en raison du problème lié au détail de base (pas de trafic multicast dans l'espace utilisateur).

Nous avons une application qui lit les données envoyées à quatre adresses de multidiffusion, et un port unique par adresse de multidiffusion, à partir d'une appliance qui est (généralement) connectée directement à une interface sur le serveur de réception.

Nous tentions de déployer ce logiciel sur un site client lorsqu'il a mystérieusement échoué sans raison connue. Les tentatives de débogage de ce logiciel ont abouti à l'inspection de chaque appel système, finalement ils nous ont tous dit la même chose:

Notre logiciel demande des données et le système d'exploitation n'en fournit jamais.

Le compteur de paquets de multidiffusion incrémenté, tcpdump a montré le trafic atteignant la boîte/interface spécifique, mais nous ne pouvions rien faire avec. SELinux était désactivé, iptables était en cours d'exécution mais n'avait aucune règle dans aucune des tables.

Perplexe, nous étions.

En fouillant au hasard, nous avons commencé à penser aux paramètres du noyau que sysctl gère, mais aucune des fonctionnalités documentées n'était particulièrement pertinente, ou si elles avaient à voir avec le trafic de multidiffusion, elles étaient activées. Oh, et ifconfig a répertorié "MULTICAST" dans la ligne de fonctionnalités (up, broadcast, running, multicast). Par curiosité, nous avons examiné /etc/sysctl.conf. 'Et voilà, l'image de base de ce client avait quelques lignes supplémentaires ajoutées en bas.

Dans notre cas, le client avait défini net.ipv4.all.rp_filter = 1. rp_filter est le filtre Route Path, qui (si je comprends bien) rejette tout le trafic qui n'aurait pas pu atteindre cette case. Saut de sous-réseau, l'idée étant que l'adresse IP source est usurpée.

Eh bien, ce serveur était sur un sous-réseau 192.168.1/24 et l'adresse IP source de l'appliance pour le trafic de multidiffusion était quelque part dans le réseau 10. *. Ainsi, le filtre empêchait le serveur de faire quoi que ce soit de significatif avec le trafic.

Quelques ajustements approuvés par le client; net.ipv4.eth0.rp_filter = 1 et net.ipv4.eth1.rp_filter = 0 et nous courions joyeusement.

36
VxJasonxV

TL/DR Assurez-vous également que votre multidiffusion ne provient pas d'un vlan. tcpdump -e aiderait à déterminer s'ils le font.

En toute honnêteté, quelqu'un devrait créer une page avec une liste de contrôle des choses qui peuvent empêcher la multidiffusion d'atteindre le pays utilisateur. Je me bats avec ça depuis quelques jours, et naturellement rien de ce que je pouvais trouver sur le Web n'a aidé.

Non seulement je pouvais voir les paquets dans le tcpdump, mais je pouvais en fait recevoir d'autres paquets de multidiffusion, pour d'autres producteurs, juste sur une interface différente. La commande que j'ai finalement utilisée pour tester si je peux recevoir la multidiffusion était:

$ 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

La raison de strace ici est que je ne pouvais en fait pas faire socat imprimer les paquets sur la sortie standard, mais dans la sortie strace vous pouvez clairement voir si socat reçoit des données réelles du socket lié (il sera mis en sourdine sinon après quelques appels initiaux de select)

  • rp_filter sysctl - ne s'applique pas, les systèmes sont sur le même réseau IP (je les ai définis sur 0 tout de même, semble que 1 est maintenant un paramètre par défaut, au moins pour Ubuntu).
  • pare-feu/etc - le système de réception est sans pare-feu (je ne pense pas que les paquets apparaîtront dans tcpdump s'ils étaient pare-feu, mais je suppose que c'est possible si le pare-feu est drôle)
  • Routage IP/multidiffusion et plusieurs interfaces - J'ai explicitement rejoint le groupe sur la bonne interface
  • Matériel réseau farfelu - c'était mon dernier recours, mais changer un ordinateur portable en Intel NUC n'a pas aidé. C'est à peu près là que j'ai commencé à mâcher mes coudes et à le publier sur SE.
  • Le problème dans mon cas était l'utilisation de VLAN par le matériel spécialisé qui produisait ces paquets de multidiffusion. Pour voir si c'est votre problème, assurez-vous d'inclure -e drapeau à tcpdump, et vérifiez les balises vlan. Il sera nécessaire de configurer une interface dans le vlan correct avant que l'utilisateur ne puisse obtenir ces paquets. Le cadeau pour moi était en fait que les producteurs de multidiffusion ne cingleraient pas, mais n'entreraient même pas dans le cache ARP, bien que je puisse clairement voir les réponses ARP.

Pour le faire fonctionner avec VLAN ce lien peut être utile pour configurer le routage multicast. (Malheureusement, je suis nouveau dans ce cas, donc la réputation ne me permet pas d'ajouter une réponse) D'où cette modification.)

Voici ce que j'ai fait (utilisez Sudo si nécessaire):

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

De cette façon, une interface supplémentaire si elle est créée pour le trafic vlan avec vlan id 100. L'ip vlan peut être inutile. Ensuite, une adresse de multidiffusion est configurée pour la nouvelle interface (01: 00: 5e: 01: 01: 01 est l'adresse de couche liaison pour 239.1.1.1) et tout le trafic de multidiffusion entrant est lié à eth0_100. J'ai également fait toutes les étapes possibles dans les réponses ci-dessus (vérifiez iptables, rp_filter etc.).

5
Pawel Veselov

Vous voudrez peut-être essayer de regarder ces paramètres:

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

Ils ont été utilisés pour activer la multidiffusion dans RHEL.

Vous voudrez peut-être vous assurer que votre pare-feu autorise le trafic mutlicast; encore une fois avec RHEL, j'ai activé ce qui suit:

# 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
2
user64259
s.bind("", 15572)

Sûr de ""? Pourquoi ne pas utiliser l'adresse IP de multidiffusion pour établir une liaison?

0
poige

Utilisez-vous un commutateur géré? Certains ont des options pour empêcher les "tempêtes de diffusion" ou d'autres problèmes de multidiffusion, ce qui les obligerait à empêcher certains types de paquets. Je vous suggère de consulter la documentation de votre commutateur.

0
devicenull