mc_filter on big-endian arch
Subsystems (2)
cover mc_filter on big-endian arch
A.J. from VIA Networking Technologies noticed that via-rhine is using cpu_to_le32() when preparing mc_filter hashes. I confirmed that this breaks Rhine hardware multicast filters on big-endian architectures.
A bunch of other drivers are affected, too. I'll post a patch for 2.6 atp, winbond, and tulip_core (typhoon could be okay at first glance). Those are entirely untested due to lack of hardware.
If the patches are ack'ed by the respective maintainers, we might want to fix up the tulips in 2.4 as well. atp still uses set_bit in 2.4 and is thus okay. Note: Although it's been widely popular, there is no need to use cpu_to_le32 when converting from set_bit.
A generic hash filter calculator might be helpful. Most drivers get it right, but the workings of the hardware mc filters and the bit trickery in all those functions calls for at least one _documented_ version. IMHO, anyway.
Roger
Quoted 3 lines · Roger Luethi
A bunch of other drivers are affected, too. I'll post a patch for 2.6 atp, winbond, and
tulip_core(typhoon could be okay at first glance). Those are entirely untested due to lack of hardware.
I think typhoon's OK -- I calculate the filter on the host, and then do a cpu_to_le32() on the final values, since the processor on the NIC is in little-endian mode.
However, I've never tested it. I'll be happy to do so, if someone will point me to appropriate code -- I've got an Ultra5 as well, so I can test both big and little endian machines. Otherwise, I'll test it when I get around to writing something, or someone reports a bug. :)
Dave
Quoted 8 lines · David Dillow
I think typhoon's OK -- I calculate the filter on the host, and then do a
cpu_to_le32()on the final values, since the processor on the NIC is in little-endian mode.However, I've never tested it. I'll be happy to do so, if someone will point me to appropriate code -- I've got an Ultra5 as well, so I can test both big and little endian machines. Otherwise, I'll test it when I get around to writing something, or someone reports a bug. :)
Warning: This is a very basic functionality test using standard Linux tools. Some existing multicast problems are detected by this (if you screw up the endianness of the filter hash, you will know :-)). Others are not.
Multicast Driver Testing Quick How-To
=====================================
Make sure the host you are testing replies to broadcasts:
target# cat /proc/sys/net/ipv4/icmp_echo_ignore_all 0
target# cat /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 0
Our test packets need to go to the target host, so either have a route or use ping "-r -I <ifname>" option:
tester# route add -net 224.0.0.0 netmask 240.0.0.0 eth0
Since every multicast capable host interface joins 224.0.0.1, you can already ping your target:
tester# ping -r -I eth0 -t 1 -c 2 224.0.0.1
Your target host should answer this (so may your tester, depending on your setup).
We haven't joined the next group yet, so there should be no answer:
tester# ping -r -I eth0 -t 1 -c 2 224.1.1.1
Use packet sniffer to confirm that target is not seeing the request (use -p option for tcpdump or tethereal to prevent promiscuous mode)
Now join the group:
target# ip maddr add 01:00:5e:01:01:01 dev eth0
tester# ping -r -I eth0 -t 1 -c 2 224.1.1.1
Use packet sniffer to confirm that target is seeing the request now.
One thing maybe worth mentioning: If you want to play with different addresses, remember that IP addresses are in decimal notation, ethernet in hex. So if you set
target# ip maddr add 01:00:5e:00:00:25 dev eth0
the test would be
tester# ping -r -I eth0 -t 1 -c 2 224.0.0.37
Roger
[email protected] wrote on 06/07/2004 04:59:21 AM:
Quoted 9 lines
One thing maybe worth mentioning: If you want to play with different addresses, remember that IP addresses are in decimal notation, ethernet in hex. So if you set
target# ip maddr add 01:00:5e:00:00:25 dev eth0
the test would be
tester# ping -r -I eth0 -t 1 -c 2 224.0.0.37
This will add "01:00:5e:00:00:25" to the device multicast address filter, which will mean the host will receive the packet. But because it doesn't join the group at the IP level, it'll be dropped and the ping won't be answered (it isn't for a local address).
If you want the machine to answer, you need to join the group, which will conveniently add the hardware multicast address automatically. :-)
+-DLS
PS - Here's a trivial program that will join a group. If you run this on one side, then a ping to the multicast address will work when it's in the group, and stop answering when it exits. There are more general things that have been around for years for testing-- I just threw this together just now. (I hope it doesn't have any bugs! :-) ) Should be suitable for testing hardware multicast address filters...
+-DLS
#include <stdio.h>
#include <netinet/in.h>
intmain(int argc, char *argv[])
{
struct ip_mreqn mreqn;
int s;
if (argc != 3) {
fprintf(stderr, "usage: %s <dev> <group>\n", argv[0]);
exit(1);
}
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
exit(1);
}
memset(&mreqn, 0, sizeof(mreqn));
mreqn.imr_ifindex = if_nametoindex(argv[1]);
if (!mreqn.imr_ifindex) {
fprintf(stderr, "%s: \"%s\" invalid interface\n", argv[0],
argv[1]);
exit(1);
}
if (inet_pton(AF_INET, argv[2], &mreqn.imr_multiaddr) <= 0) {
fprintf(stderr, "%s: \"%s\" invalid group address\n",
argv[0],
argv[2]);
exit(1);
}
if (setsockopt(s, SOL_IP, IP_ADD_MEMBERSHIP, &mreqn,sizeof mreqn)
< 0) {
perror("IP_ADD_MEMBERSHIP");
exit(1);
}
printf("joined group %s on %s (pausing...)");
fflush(stdout);
pause();
exit(0);
}Quoted 6 lines · David Stevens
PS - Here's a trivial program that will join a group. If you run this on one side, then a ping to the multicast address will work when it's in the group, and stop answering when it exits. There are more general things that have been around for years for testing-- I just threw this together just now. (I hope it doesn't have any bugs! :-) ) Should be suitable for testing hardware multicast address filters...
Thank you for sending this program; it saved me having to write my own, and it helped me to demonstrate that multicast already works properly under typhoon. As it turns out, my copy of tcpdump was turning on ALL_MULTI on the interface, even with "-p", and the NIC was responding appropriately. So the multicast packets I saw coming in were legitimate.
So, summary, typhoon multicast is OK, on both big and little endian machines.
Roger, thanks for spurring me to finally test this.
Dave
Quoted 12 lines · David Stevens
[email protected] wrote on 06/07/2004 04:59:21 AM:
Quoted 9 lines
One thing maybe worth mentioning: If you want to play with different addresses, remember that IP addresses are in decimal notation, ethernet in hex. So if you set
target# ip maddr add 01:00:5e:00:00:25 dev eth0
the test would be
tester# ping -r -I eth0 -t 1 -c 2 224.0.0.37
Quoted 7 lines
This will add "01:00:5e:00:00:25" to the device multicast address filter, which will mean the host will receive the packet. But because it doesn't join the group at the IP level, it'll be dropped and the ping won't be answered (it isn't for a local address).
If you want the machine to answer, you need to join the group, which will conveniently add the hardware multicast address automatically. :-)
Correct. The method I described does the trick using standard tools (iproute2, packet sniffer), though.
Quoted 6 lines
PS - Here's a trivial program that will join a group. If you run this on one side, then a ping to the multicast address will work when it's in the group, and stop answering when it exits. There are more general things that have been around for years for testing-- I just threw this together just now. (I hope it doesn't have any bugs! :-) ) Should be suitable for testing hardware multicast address filters...
Sure, why not? Fixed up and added to the How-To below.
Roger
Multicast Driver Testing Quick How-To (version 0.2)
=====================================
Preparation
-----------
Make sure the host you are testing replies to broadcasts:
target# cat /proc/sys/net/ipv4/icmp_echo_ignore_all 0
target# cat /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 0
Our test packets need to go to the target host, so either have a route or use ping "-r -I <ifname>" option:
tester# route add -net 224.0.0.0 netmask 240.0.0.0 eth0
Test default group
------------------
Since every multicast capable host interface joins 224.0.0.1, you can already ping your target:
tester# ping -r -I eth0 -t 1 -c 2 224.0.0.1
Your target host should answer this (so may your tester, depending on your setup).
Join group on Ethernet level
----------------------------
We haven't joined the next group yet, so there should be no answer:
tester# ping -r -I eth0 -t 1 -c 2 224.1.1.37
Use packet sniffer to confirm that target is not seeing the request (use -p option for tcpdump or tethereal to prevent promiscuous mode)
Now join the group (Ethernet level):
target# ip maddr add 01:00:5e:01:01:25 dev eth0
tester# ping -r -I eth0 -t 1 -c 2 224.1.1.37
Use packet sniffer to confirm that target is seeing the request now.
Join group on IP level
----------------------
The program below will join a multicast group at IP level and thus at Ethernet level as well -- provided driver and hardware work properly. Group membership end with termination of the program.
Remove hardware filter (if any left from previous test):
target# ip maddr del 01:00:5e:01:01:25 dev eth0
Join multicast group:
target# ./mcjoin eth0 224.1.1.37
tester# ping -r -I eth0 -t 1 -c 2 224.1.1.37
No need for packet sniffer this time, the target will answer since the IP layer is aware of our group membership.
--------------------------------------------------------------------------------
/* Purpose: Join a multicast group (for testing) */
/* Author: David Stevens <[email protected]>, 2004 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <net/if.h>
intmain(int argc, char *argv[])
{
struct ip_mreqn mreqn;
int s;
if (argc != 3) {
fprintf(stderr, "usage: %s <dev> <group>\n", argv[0]);
exit(1);
}
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket");
exit(1);
}
memset(&mreqn, 0, sizeof(mreqn));
mreqn.imr_ifindex = if_nametoindex(argv[1]);
if (!mreqn.imr_ifindex) {
fprintf(stderr, "%s: \"%s\" invalid interface\n", argv[0],
argv[1]);
exit(1);
}
if (inet_pton(AF_INET, argv[2], &mreqn.imr_multiaddr) <= 0) {
fprintf(stderr, "%s: \"%s\" invalid group address\n", argv[0],
argv[2]);
exit(1);
}
if (setsockopt(s, SOL_IP, IP_ADD_MEMBERSHIP, &mreqn,sizeof mreqn) < 0) {
perror("IP_ADD_MEMBERSHIP");
exit(1);
}
printf("joined group %s on %s (pausing...)\n", argv[2], argv[1]);
fflush(stdout);
pause();
exit(0);
}--------------------------------------------------------------------------------
Quoted 2 lines · Roger Luethi
Multicast Driver Testing Quick How-To (version 0.2)
=====================================
Thank you guys for all the info. I've done some testing, and sure enough, there are some problems in typhoon, which I'll fix this weekend. But I think the cpu_to_le32() calls are correct -- it would seem that crc32_be() is needed rather than ether_crc() (which does little endian). I'm assuming the results will be different, but I haven't done the math, nor am I very familiar with the properties of the crc.
Even then, I'm not sure that's my real problem -- if it was setting the wrong bits in the hash -- my working hypothesis -- I shouldn't be receiving the 224.0.0.1 frames. I am.
I am also seeing 224.1.1.37 frames come up the stack in tcpdump (with -p), before running "ip maddr ..." so something seems wonky. It seems to be getting into ALL_MULTI mode, but I don't see how in the driver. I'm going to add some printks and see what's going on.
Signature · 1 line
Dave Dillow <[email protected]>
Roger suggested that I bring to "netdev" the comment I made to him in private e-mail about his FAQ, so here it is:
if you add multicast addresses via "ip maddr" in the way described, it won't work for some hardware configurations. In particular, if you have an Ethernet switch that does IGMP snooping, the switch won't replicate multicast packets on ports that haven't had IGMP reports for the multicast address you're testing. In that case, having it in the hardware MAF doesn't
help, and you'll need to do the IP-level join to get them delivered.
+-DLS
Quoted 10 lines · Roger Luethi
Quoted 8 lines · David Dillow
I think typhoon's OK -- I calculate the filter on the host, and then do a
cpu_to_le32()on the final values, since the processor on the NIC is in little-endian mode.However, I've never tested it. I'll be happy to do so, if someone will point me to appropriate code -- I've got an Ultra5 as well, so I can test both big and little endian machines. Otherwise, I'll test it when I get around to writing something, or someone reports a bug. :)
Quoted 4 lines
Warning: This is a very basic functionality test using standard Linux tools. Some existing multicast problems are detected by this (if you screw up the endianness of the filter hash, you will know :-)). Others are not.
Thanks for the info; it seems typhoon may have some problems -- I see the 224.1.1.1 packets before I join the group, so I'll need to see what's up. I'll check big endian tonight, if possible.
Dave
you would be kind enough to resend the non-via-rhine patches WRT mc_filter?