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