Linus Lüssing
2011-Mar-27 03:44 UTC
[Bridge] Checksumming bug in bridge multicast snooping for IPv6?
Hi everyone, Somehow I'm having trouble with the IPv6 bridge snooping again: MLDv2 Reports are dropped by the multicast snooping feature, looks like it has something to do with checksums. Wireshark does not display any weirdness, it at least reports the MLD reports checksum as correct. The setup is the following: The VM is running a current Linux version of torvalds branch with no other additions then the printk-debug patch attached (2.6.38+ #4 SMP PREEMPT Sat Mar 26 22:59:11 GMT 2011 i686 GNU/Linux): http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;h=16c29dafcc86024048f1dbb8349d31cb22c7c55a;hb=16c29dafcc86024048f1dbb8349d31cb22c7c55a The host machine which is joining a multicast group is doing an explicit join on the KVM instances provided tap interface: IPv6: vlc -vvv "udp://@[ff12::124%vmtap1]" (IPv4: vlc -vvv "udp://@224.0.1.123") The host machine is running a kernel from Debian unstable: 2.6.37-2-amd64 #1 SMP Sun Feb 27 12:32:01 UTC 2011 x86_64 GNU/Linux See the attached debug patch and the according output for some more details where it fails (the bridge is basically ignoring the MLDv2 report due to the goto in this line: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=net/bridge/br_multicast.c;h=f61eb2eff3fdd387b83d9fab642bb610dde1ad69;hb=HEAD#l1530) I'm also attaching both a wireshark capture of the ignored IPv6 MLDv2 report and the working IGMPv3 report, which correspond directly to the attached printk debug output. I'm a little bit startled because I definitely had that part working a couple of weeks ago and I'm still trying to figure out what I might have changed in the setup. I definitely have updated the VMs kernel, but the same issue is present for the 2.6.38 and also 2.6.37 release versions with my fixes backported (the latter one was the one I had been using back then). I probably have updated the multicast listener host's kernel, too, I might have been running 2.6.32 or something more earlier... I've also tried having the listener host in another VM with the same 2.6.38+ kernel as the bridge-snooping host, but also that did not make a difference. Anyways, skb_checksum_complete() is calculating the checksum from skb's data to tail pointer, right? RFC3810 for MLDv2, section 5.1.2 says: "The standard ICMPv6 checksum; it covers the entire MLDv2 message, plus a "pseudo-header" of IPv6 header fields [RFC2463]." Could it be that this "pseudo-header" is not included in the checksumming? Is there a function in the kernel which could already provide that? I guess that could also explain why it's working fine for IPv4, there it's just the IGMP message being checksummed according to RFC 3376, section 4.1.2. Cheers, Linus PS: There also seems to be another offset bug in the same function, see comment in debug patch file, though seemingly unrelated to the issue described above. Correcting that len-variable does to help for the above issue. -------------- next part -------------- IPv6: [ 2460.557303] +++ br_multicast_ipv6_rcv() [ 2460.558114] +++ br_multicast_ipv6_rcv() here 0.5 [ 2460.558114] +++ br_multicast_ipv6_rcv() len: 36, offset: 48, skb_network_offset(skb2): 0 [ 2460.558114] +++ br_multicast_ipv6_rcv() new len: -12 [ 2460.558114] +++ br_multicast_ipv6_rcv() skb2->len: 28 len: -12 skb->len: 76 [ 2460.558114] +++ br_multicast_ipv6_rcv() here 1.5 [ 2460.558114] +++ br_multicast_ipv6_rcv() here 1.7, skb2->csum is 0 [ 2460.558114] +++ br_multicast_ipv6_rcv() here 1.8, skb_checksum_complete(skb2): 81e9 (skb): 2e60 [ 2464.981808] +++ br_multicast_ipv6_rcv() [ 2464.982388] +++ br_multicast_ipv6_rcv() here 0.5 [ 2465.062634] +++ br_multicast_ipv6_rcv() len: 36, offset: 48, skb_network_offset(skb2): 0 [ 2465.066698] +++ br_multicast_ipv6_rcv() new len: -12 [ 2465.069183] +++ br_multicast_ipv6_rcv() skb2->len: 28 len: -12 skb->len: 76 [ 2465.072013] +++ br_multicast_ipv6_rcv() here 1.5 [ 2465.074217] +++ br_multicast_ipv6_rcv() here 1.7, skb2->csum is 0 [ 2465.076785] +++ br_multicast_ipv6_rcv() here 1.8, skb_checksum_complete(skb2): 81e9 (skb): 2e60 IPv4: [ 2325.265830] +++ br_multicast_ipv4_rcv() skb2->len: 40 len: 40 skb->len: 40 [ 2325.266567] +++ br_multicast_ipv4_rcv() 2) skb2->len: 16 len: 16 skb->len: 16 [ 2325.266567] +++ br_multicast_ipv4_rcv() here 1.7, skb2->csum is 0 [ 2325.266567] +++ br_multicast_ipv4_rcv() here 1.8, skb_checksum_complete: 0 [ 2325.266567] +++ br_ip4_multicast_add_group() eth1 224.0.1.123 [ 2327.326179] +++ br_multicast_ipv4_rcv() skb2->len: 40 len: 40 skb->len: 40 [ 2327.326674] +++ br_multicast_ipv4_rcv() 2) skb2->len: 16 len: 16 skb->len: 16 [ 2327.326674] +++ br_multicast_ipv4_rcv() here 1.7, skb2->csum is 0 [ 2327.326674] +++ br_multicast_ipv4_rcv() here 1.8, skb_checksum_complete: 0 [ 2327.326674] +++ br_ip4_multicast_add_group() eth1 224.0.1.123 -------------- next part -------------- A non-text attachment was scrubbed... Name: bridge-snoop-debug.patch Type: text/x-diff Size: 4954 bytes Desc: not available Url : http://lists.linux-foundation.org/pipermail/bridge/attachments/20110327/70fd52ca/attachment.patch -------------- next part -------------- A non-text attachment was scrubbed... Name: ipv4-group-join.cap Type: application/cap Size: 164 bytes Desc: not available Url : http://lists.linux-foundation.org/pipermail/bridge/attachments/20110327/70fd52ca/attachment.cap -------------- next part -------------- A non-text attachment was scrubbed... Name: ipv6-group-join.cap Type: application/cap Size: 236 bytes Desc: not available Url : http://lists.linux-foundation.org/pipermail/bridge/attachments/20110327/70fd52ca/attachment-0001.cap
Linus Lüssing
2011-Mar-27 06:27 UTC
[Bridge] bridge: mcast snooping, fixes for IPv6 MLDv1/2 parsing
Hi everyone, The following two patches are fixing two issues, related to the parsing of IPv6 MLD messages. The first one fixes an observed issue which lead to ignored MLD messages. In the tests this patch fixes the issue in my scenario. However I'm not so familiar with the checksumming functions in the kernel, so would be great if someone could double-check whether the new checksum calculations make sense like this. The second patch fixes a potential issue. Bogus values of the 'len' variable had been observed during tests and this patch successfully fixed this here. However this patch is untested for the potential issues named in the patch's description that could have occured without it. Both patches together have been applied and tested and no more issues with the parsing and adding of new IPv6 multicast listeners to the bridge snooping database could be observed (for now ;) ). Cheers, Linus
Linus Lüssing
2011-Mar-27 06:27 UTC
[Bridge] [PATCH] bridge: mcast snooping, fix IPv6 MLD checksum calculation
In contrast to IGMP, the MLDv1/2 message checksum needs to include an IPv6 "pseudo-header" in the calculations (see RFC2710, section 3.3; RFC3810, section 5.1.2). The multicast snooping feature of the bridge code however did not take this "pseudo-header" into consideration for the checksum validation when parsing a snooped IPv6 MLDv1/2 message of another host, leading to possibly ignored, though valid MLDv1/2 messages. This commit shall fix this issue. Signed-off-by: Linus L?ssing <linus.luessing at web.de> --- net/bridge/br_multicast.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index f61eb2e..47fae4f 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1525,7 +1525,10 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, break; /*FALLTHROUGH*/ case CHECKSUM_NONE: - skb2->csum = 0; + skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, + &ip6h->daddr, + skb2->len, + nexthdr, 0)); if (skb_checksum_complete(skb2)) goto out; } -- 1.5.6.5