Bug 152853 - [em] tftpd (and likely other udp traffic) fails over em(4) unless rxcsum/txcsum disabled [regression]
Summary: [em] tftpd (and likely other udp traffic) fails over em(4) unless rxcsum/txcs...
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 8.2-PRERELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-net (Nobody)
URL:
Keywords: IntelNetworking
Depends on:
Blocks:
 
Reported: 2010-12-05 21:30 UTC by Mike Andrews
Modified: 2015-06-30 18:28 UTC (History)
1 user (show)

See Also:


Attachments
if_em.patch (1.31 KB, patch)
2011-01-18 15:15 UTC, lampa
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Andrews 2010-12-05 21:30:08 UTC
	The tftp server in FreeBSD fails to send any packets -- when a write
	request comes in (in this example, from a Cisco IOS router), tcpdump
	shows that FreeBSD receives the write reqeust but then its tftp server
	never sends a single packet out in response, and the transfer never
	starts:

	Dec  5 14:22:29 <ftp.info> bat tftpd[453]: Filename: 'moat-confg'
	Dec  5 14:22:29 <ftp.info> bat tftpd[453]: Mode: 'octet'
	Dec  5 14:22:29 <ftp.info> bat tftpd[453]: 172.27.0.1: write request for //moat-confg: success
	Dec  5 14:22:34 <ftp.warn> bat tftpd[453]: Timeout #0 on DATA block 1
	Dec  5 14:22:39 <ftp.warn> bat tftpd[453]: Timeout #1 on DATA block 1
	Dec  5 14:22:44 <ftp.warn> bat tftpd[453]: Timeout #2 on DATA block 1
	Dec  5 14:22:49 <ftp.warn> bat tftpd[453]: Timeout #3 on DATA block 1
	Dec  5 14:22:54 <ftp.warn> bat tftpd[453]: Timeout #4 on DATA block 1
	Dec  5 14:22:59 <ftp.err> bat tftpd[453]: Timeout #5 on DATA block 1, giving up

	On a complete whim, I tried disabling TSO4, TXCSUM, and RXCSUM on the
	NIC, and to my surprise I found that disabling the latter two made the
	problem disappear.  TSO had no effect -- as you'd expect since tftp is
	UDP based :)

	I have not checked to see if this is em(4) specific or what other UDP
	based services it might affect.  It appears that DNS on the same system
	works fine...

Fix: 

ifconfig em0 -rxcsum -txcsum

	(It doesn't appear you can turn just one or the other off.)
How-To-Repeat: 	On a system with an Intel gigabit NIC, start a tftp server (via inetd)
	and try to write a file to it.
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2010-12-06 10:57:32 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 2 lampa 2011-01-18 15:15:12 UTC
Some folowup for kern/152853 with a patch.

It seems that the current version of if_em.c (both CURRENT and STABLE8)
with txcsum/rxcsum cannot send any UDP packet shorter then TCP header size. 
The reason is suspicious m_pullup(m_head, poff + sizeof(struct tcphdr)) in 
common packet em_xmit handling. I've moved this m_pullupi() call to required 
branches further down and this fixed the issue (UDP ack from tftpd daemon 
now ok). The code however needs some audit, repeated m_pullups are strange.

Sincerely,
Petr Lampa

*** if_em.c.old	2011-01-18 15:52:21.000000000 +0100
--- if_em.c	2011-01-18 15:58:11.000000000 +0100
***************
*** 1820,1831 ****
  		}
  		ip = (struct ip *)(mtod(m_head, char *) + ip_off);
  		poff = ip_off + (ip->ip_hl << 2);
- 		m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
- 		if (m_head == NULL) {
- 			*m_headp = NULL;
- 			return (ENOBUFS);
- 		}
  		if (do_tso) {
  			tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
  			/*
  			 * TSO workaround:
--- 1820,1831 ----
  		}
  		ip = (struct ip *)(mtod(m_head, char *) + ip_off);
  		poff = ip_off + (ip->ip_hl << 2);
  		if (do_tso) {
+ 			m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
+ 			if (m_head == NULL) {
+ 				*m_headp = NULL;
+ 				return (ENOBUFS);
+ 			}
  			tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
  			/*
  			 * TSO workaround:
***************
*** 1849,1854 ****
--- 1849,1859 ----
  			tp->th_sum = in_pseudo(ip->ip_src.s_addr,
  			    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
  		} else if (m_head->m_pkthdr.csum_flags & CSUM_TCP) {
+ 			m_head = m_pullup(m_head, poff + sizeof(struct tcphdr));
+ 			if (m_head == NULL) {
+ 				*m_headp = NULL;
+ 				return (ENOBUFS);
+ 			}
  			tp = (struct tcphdr *)(mtod(m_head, char *) + poff);
  			m_head = m_pullup(m_head, poff + (tp->th_off << 2));
  			if (m_head == NULL) {

-- 
Computer Centre                             E-mail: lampa@fit.vutbr.cz
Faculty of Information Technology           Web: http://www.fit.vutbr.cz/
Brno University of Technology               Fax:  +420 54114-1270
Bozetechova 2, 612 66 Brno, Czech Republic  Phone: +420 54114-1225
Comment 3 Eugene Grosbein 2011-01-18 16:00:54 UTC
Hi!

7.4-PRERELEASE is affected too. In short, tftp is broken in recent em(4) driver in all branches due to this bug. 8.1-RELEASE is not affected, 7.3 is fine too.

Eugene Grosbein
Comment 4 Sean Bruno freebsd_committer freebsd_triage 2015-06-30 18:28:59 UTC
This appears to be applied to if_em.c ... if this is not the case, please correctly reopen this ticket.