Skip site navigation (1)Skip section navigation (2)
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>