re0 device txcsum issue

John-Mark Gurney gurney_j at resnet.uoregon.edu
Thu Sep 23 15:52:38 PDT 2004


Sean McNeil wrote this message on Thu, Sep 23, 2004 at 15:20 -0700:
> Is anyone willing to work with me to help trace down this problem?  It
> has been outstanding for a long time and I would dearly like it fixed. 
> I'm willing to help in any capacity to trace down the culprit.
> 
> To recap, on the re0 device (possibly others) running -current on an
> amd64 processor there are times when udp packets get improper checksum
> calculations with txcsum set for the interface.  This causes a deadlock
> in nfs as the client just contunuously requests this packet and it is
> rejected because of the checksum being bad.

I have recently been working with the re driver, so I'm somewhat familar
with the driver.  I haven't seen any issues, but I also don't have an
AMD64 system to test with.

Have you tried to find out if it is packet size related?  are you
trying to use jumbo frames?  rwatson committed netsend to the src/tools
tree that could help this, and I have attached udpcheck.py which is
a client/server script to test/verify packet sizes of difference
sizes.

-- 
  John-Mark Gurney				Voice: +1 415 225 5579

     "All that I will do, has been done, All that I have, has not."
-------------- next part --------------
#!/usr/bin/env python

import getopt
import time
import socket
import struct
import sys

def debug(cmd):
	if verbose:
		sys.stdout.write(cmd + '\n')
		sys.stdout.flush()

def genmaxpacket():
	pkt = []
	for i in range(256):
		pkt.append(chr(i))
	for i in range(8192):
		pkt.append(chr(i / 256) + chr(i % 256))
	return ''.join(pkt)

def usage():
	print 'Usage:	udpcheck.py [ -v ] -s <port>'
	print '	udpcheck.py [ -v ] <host> <port> [ -s <lenstart> ] [ -e <lenend> ]'
	sys.exit(2)

def main():
	try:
		opts, args = getopt.getopt(sys.argv[1:], "sv")
	except getopt.GetoptError:
		usage()
	global verbose
	verbose = False
	server = False
	for o, a in opts:
		if o == '-v':
			verbose = True
		elif o == '-s':
			server = True

	if (server and len(args) != 1) or (not server and len(args) < 2):
		usage()

	if server:
		doserver(args[0])
	else:
		doclient(args[0], args[1], args[2:])

def doserver(port):
	'''I guess I had better start documenting the protocol.  Single caracter is the command:
	e:	exit server
	q:	quit connection
	s:	send client a udp packet of !H length from maxpacket
	r:	receive udp packet from client of length, response will be
			!H length of received packet followed by length.'''

	maxpacket = genmaxpacket()

	# Start up sockets for server
	udpout = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	cn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	cn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
	cn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
	try:
		port = int(port)
	except ValueError:
		port = socket.getservbyname(port, 'tcp')
	cn.bind(('', port))
	udpout.bind(('', port))
	cn.listen(-1)

	# Start processing commands from a client
	exit = False
	while not exit:
		cli, remote = cn.accept()
		debug("connection from: " + str(remote))

		#Handle client
		cmd = cli.recv(1)
		while cmd:
			debug("command: " + cmd)
			if cmd == 'e':
				exit = True
				break
			elif cmd == 'q':
				break
			elif cmd == 's':
				rlen = struct.unpack("!H", cli.recv(2))[0]
				debug("len: %d" % rlen)
				udpout.sendto(maxpacket[:rlen], remote)
			elif cmd == 'r':
				rlen = struct.unpack("!H", cli.recv(2))[0]
				debug("len: %d" % rlen)
				rdata = udpout.recv(rlen)
				cli.send(struct.pack("!H", len(rdata)))
				cli.send(rdata)
			cmd = cli.recv(1)

		del cli

def doclient(host, port, args):
	error = False
	errors = []
	maxpacket = genmaxpacket()

	lenstart = 1
	lenend = 2048
	dosend = True
	dorecv = True

	try:
		opts, args = getopt.getopt(args, "s:e:")
	except getopt.GetoptError:
		usage()

	for o, a in opts:
		if o == '-s':
			lenstart = int(a)
		elif o == '-e':
			lenend = int(a)

	if lenstart <= 0 or lenend <= 0:
		usage()

	# Establish connection to server
	inf = socket.getaddrinfo(host, port, socket.AF_INET, socket.SOCK_STREAM)[0]
	serv = socket.socket(inf[0], inf[1])
	serv.connect(inf[4])
	serv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
	udprecv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	udprecv.bind(serv.getsockname())

	# Start work
	# Receive/Send is viewed from server, so local client is doing opposite
	for i in range(lenstart, lenend):
		if dosend:
			debug("sending len: %d" % i)
			serv.send('s' + struct.pack("!H", i))
			data = udprecv.recv(i * 2)
			debug("recv len: %d" % len(data))
			if data != maxpacket[:i]:
				print 'packet recv mismatch at:', i
				errors.append(('s', i))
				error = True

		if dorecv:
			debug("recving len: %d" % i)
			serv.send('r' + struct.pack("!H", i * 2))
			udprecv.sendto(maxpacket[:i], inf[4])
			rlen = struct.unpack("!H", serv.recv(2))[0]
			debug('rlen: %d' % rlen)
			rdata = serv.recv(rlen)
			if rdata != maxpacket[:rlen] or rlen != i:
				print 'packet send mismatch at:', i
				errors.append(('r', i))
				error = True

	serv.send('q')
	if error:
		print errors
		sys.exit(1)

if __name__ == '__main__':
	main()


More information about the freebsd-current mailing list