Date: Thu, 31 Jul 2014 17:46:19 +0100 From: Robert Clipsham <robert@octarineparrot.com> To: freebsd-net@freebsd.org Subject: Using the loopback interface with BPF Message-ID: <CAJ9_%2BXK%2Bib3uei%2Ba-eaGmedpQXLm1dOCO5-Ez3EndFoNDpLwvQ@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
Hi there, I've been using BPF to read and write Ethernet packets from the network, however I have encountered issues while writing a test suite for my code. The tests run on the loopback interface, however when calling write(), I received an EAFNOSUPPORT error (looutput: af=0 unexpected). When investigating further my findings were unexpected. It seems there are three main functions involved with writing packets on the loopback interface using BPF: looutput() from sys/net/if_loop.c; bpfwrite() and bpf_movein() from sys/net/bpf.c. When write()ing, bpf_movein() generates a sockaddr which is later used in looutput(). When using the loopback interface (DLT_NULL), the sa_family field is initialised to AF_UNSPEC, and it specifies a pseudo-header of 4 bytes should exist at the start of the buffer provided to write(). In bpfwrite(), after bpf_movein() has been called, if BIOCSHDRCMPLT has been set, the sa_family field is overwritten with pseudo_AF_HDRCMPLT. After this initial setup, looutput() is called. It handles BPF calls specially, by checking if the sa_family is AF_UNSPEC, and if so treating sa_family as whatever is stored in sa_data. There is then a switch statement, which only handles AF_INET and AF_INET6 packets. This has a number of consequences: * When using BPF on the loopback interface, the first 4 bytes of the buffer being sent are used for a pseudo-header. This pseudo-header remains in-tact when receiving, so the loopback interface must be special-cased for sending/receiving (alternatively a corrupt packet is sent/received, depending on how you look at it). * The need for any kind of pseudo-header is undocumented in the BPF man pages. It is mentioned briefly in the pcap man pages. * When BIOSHDRCMPLT is set, BPF cannot work on the loopback interface (since looutput() checks for AF_UNSPEC, but sa_family is pseudo_AF_HDRCMPLT). So my question is, what is the best way to test data link protocols with BPF offline with FreeBSD? My current ideas: * Special-case the loopback interface to add the pseudo-header and remove the BIOCSHDRCMPLT ioctl() (intresting note here: the ioctl() call does not fail, despite the option being invalid). * Modify the loopback device to support data link protocols properly, without the need for a pseudo-header (of course this would break backwards compatability). * Create an additional type of loopback interface designed to emulate other data link protocols. Your input would be appreciated. Thanks, Robert
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ9_%2BXK%2Bib3uei%2Ba-eaGmedpQXLm1dOCO5-Ez3EndFoNDpLwvQ>