From owner-freebsd-amd64@FreeBSD.ORG Tue Feb 5 01:20:00 2013 Return-Path: Delivered-To: freebsd-amd64@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id E44CE89E for ; Tue, 5 Feb 2013 01:20:00 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 8A1C8D4E for ; Tue, 5 Feb 2013 01:20:00 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r151K0Xc000878 for ; Tue, 5 Feb 2013 01:20:00 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r151K06J000877; Tue, 5 Feb 2013 01:20:00 GMT (envelope-from gnats) Resent-Date: Tue, 5 Feb 2013 01:20:00 GMT Resent-Message-Id: <201302050120.r151K06J000877@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-amd64@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Karim Fodil-Lemelin Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 7D812877 for ; Tue, 5 Feb 2013 01:15:16 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 5634FD2F for ; Tue, 5 Feb 2013 01:15:16 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.5/8.14.5) with ESMTP id r151FGVn097916 for ; Tue, 5 Feb 2013 01:15:16 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.5/8.14.5/Submit) id r151FGj5097915; Tue, 5 Feb 2013 01:15:16 GMT (envelope-from nobody) Message-Id: <201302050115.r151FGj5097915@red.freebsd.org> Date: Tue, 5 Feb 2013 01:15:16 GMT From: Karim Fodil-Lemelin To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Subject: amd64/175852: in_cksum_hdr() behaves differently on amd64 vs i386 with unaligned data X-Mailman-Approved-At: Tue, 05 Feb 2013 03:20:56 +0000 X-BeenThere: freebsd-amd64@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Porting FreeBSD to the AMD64 platform List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Feb 2013 01:20:01 -0000 >Number: 175852 >Category: amd64 >Synopsis: in_cksum_hdr() behaves differently on amd64 vs i386 with unaligned data >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-amd64 >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Feb 05 01:20:00 UTC 2013 >Closed-Date: >Last-Modified: >Originator: Karim Fodil-Lemelin >Release: FreeBSD 7.x but also in 9.x >Organization: >Environment: FreeBSD pluto 7.4-RELEASE FreeBSD 7.4-RELEASE #0: Fri Feb 18 01:55:22 UTC 2011 root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64 >Description: TLDR: If the IP header is not aligned on an even address then the amd64 version of in_cksum_hdr() will not work while the i386 version of it will. I came across this problem while working on custom software using the FreeBSD bridge. Our code sometimes decapsulate packets with the resulting header starting on an odd address and we need to send it through the FreeBSD bridge where we hit in_cksum_hdr() in bridge_pfil(). While this always worked on i386 we started seeing 'reversed' checksums on amd64: 21:47:29.178620 IP (tos 0x0, ttl 63, id 3819, offset 0, flags [none], proto ICMP (1), length 84) 192.168.76.100 > 192.168.73.200: ICMP echo request, id 44019, seq 2, length 64 21:47:29.179972 IP (tos 0x0, ttl 62, id 1701, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 875e (->5e87)!) 192.168.73.200 > 192.168.76.100: ICMP echo reply, id 44019, seq 2, length 64 Please note the reversed checksum on the ICMP reply (as if someone had called htons on ip_sum ...). Needless to say this caused a lot of head scratching over here. Now it looks like the i386 version of in_cksum_hdr() is totally different then the amd64 one. The FreeBSD source uses in_cksum_hdr() in many other places then if_bridge.c and while the i386 version of it is capable of dealing with unaligned addresses the amd64 one is not (we haven't checked other architectures). My question(s) to the list is what is the proper way to fix this? Should we replace all occurrence of in_cksum_hdr() with in_cksum()? Should we write another inline assembly of the in_cksum_hdr function for 64bit? Should in_cksum_hdr() in amd64 changed to deal with misaligned addresses? Other solutions? >How-To-Repeat: >Fix: diff --git a/freebsd/sys/amd64/amd64/in_cksum.c b/freebsd/sys/amd64/amd64/in_cksum.c index ae02e91..71749e1 100644 --- a/freebsd/sys/amd64/amd64/in_cksum.c +++ b/freebsd/sys/amd64/amd64/in_cksum.c @@ -233,9 +233,13 @@ skip_start: u_int in_cksum_hdr(const struct ip *ip) { - u_int64_t sum = in_cksumdata(ip, sizeof(struct ip)); - union q_util q_util; - union l_util l_util; - REDUCE16; - return (~sum & 0xffff); + u_int64_t sum; + union q_util q_util; + union l_util l_util; + if ((uintptr_t)ip & 1) + sum = in_cksumdata(ip, sizeof(struct ip)) << 8; + else + sum = in_cksumdata(ip, sizeof(struct ip)); + REDUCE16; + return (~sum & 0xffff); } >Release-Note: >Audit-Trail: >Unformatted: