In Fall 1998, we noticed that some of the 3Com509B cards were generating duplicate hardware packets under FreeBSD 2.2.7 and 2.2.8. These cards came on the motherboards of the Intel boxes as device xl0. We found information that pointed to a faulty shipment from 3Com. Look at the card and if there is an assembly number of 03-172 written on the GREEN part of the FAB (NOT in the YELLOW perimeter), then the card is faulty. (It could also be that the FreeBSD driver is bad. I don't think anyone's checked this with FreeBSD 3.x.)
Last time I checked, our cards were in this batch. We switched to using mainly Intel cards because of this. If you need to use the 3Com cards, be careful. An easy way to check for duplicates is to take a tcpdump where the 3Com card is the sender, and run it through tcptrace, which will alert you if there are hardware duplicates found.
This problem is fixed in a newer version of the xl driver, which is available from http://www.freebsd.org/~wpaul/ Our friends in Denmark have used the new driver and see no more duplicate packets.
Note: If you change the driver on an ALTQ kernel, you need to re-apply the ALTQ patch because ALTQ makes changes to the xl driver. Also, in the new xl driver, a new routine, xl_start_90xB, has been added. This routine is not patched by the ALTQ 2.0 patch, so this needs to be done by hand. Look at Step 2 of [your favorite ALTQ distribution]/docs/howto-modify-drivers.txt (see below) for info on how to perform the manual patch.
Thanks to Jan Justensen (firstname.lastname@example.org) and Jesper Krogh (email@example.com) for finding this.
[my ALTQ distribution]/docs/howto-modify-drivers.txt
Currently supported drivers are very limited. If you want to use unsupported drivers, you have to make modifications by yourself. If you successfully made modifications, please send diffs to (firstname.lastname@example.org). I'll include the support in the next release. (1) ethernet drivers Step 1: attach routine (e.g. vxattach) When a driver supports ALTQ, it should set the ALTQF_READY flag in the driver's attach routine. #ifdef ALTQ /* * set ALTQF_READY to show this driver supports * alternate queueing. */ ifp->if_altqflags |= ALTQF_READY; #endif if_attach(ifp); Step 2: if_start routine. (e.g. vxstart) This is an example of how to put the alternate dequeue operation in the if_start routine. #ifdef ALTQ if (IS_ALTQ_ON(ifp)) m0 = (*ifp->if_altqdequeue)(ifp, ALTDQ_DEQUEUE); else #endif IF_DEQUEUE(&ifp->if_snd, m0); Also, many drivers peek the next packet in the queue to see they have enough buffer space. Those should be modified like this. /* Sneak a peek at the next packet */ #ifdef ALTQ if (IS_ALTQ_ON(ifp)) m0 = (*ifp->if_altqdequeue)(ifp, ALTDQ_PEEK); else #endif m0 = ifp->if_snd.ifq_head; A queueing scheme guarantees that if a driver peeks the next packet and then dequeues the packet, the same peeked packet is returned. Because if_start is assumed to be called in splimp, if_start can safely dequeue the same packet. The last variation is flushing the queue. This is necessary for non-work conserving queueing schemes, since just dequeueing until NULL returned doesn't drain those queues. (*ifp->if_altqdequeue)(ifp, ALTDQ_FLUSH); See the altq document for more details. Also, vxstart in if_vx.c is a good reference.