Commit a8031d9f authored by Eddie Kohler's avatar Eddie Kohler

User ToDevice: Support sending packets via pcap.

Luigi Rizzo reports this can be significantly faster on FreeBSD.
Specify the send method via a METHOD keyword.

Simultaneously, update FromDevice to support METHOD.
Signed-off-by: default avatarEddie Kohler <ekohler@gmail.com>
parent fb41a74a
...@@ -34,6 +34,14 @@ ...@@ -34,6 +34,14 @@
of 'madvise', and to 0 if you don't. */ of 'madvise', and to 0 if you don't. */
#undef HAVE_DECL_MADVISE #undef HAVE_DECL_MADVISE
/* Define to 1 if you have the declaration
of 'pcap_inject', and to 0 if you don't. */
#undef HAVE_DECL_PCAP_INJECT
/* Define to 1 if you have the declaration
of 'pcap_sendpacket', and to 0 if you don't. */
#undef HAVE_DECL_PCAP_SENDPACKET
/* Define to 1 if you have the declaration /* Define to 1 if you have the declaration
of 'pcap_setnonblock', and to 0 if you don't. */ of 'pcap_setnonblock', and to 0 if you don't. */
#undef HAVE_DECL_PCAP_SETNONBLOCK #undef HAVE_DECL_PCAP_SETNONBLOCK
...@@ -122,6 +130,12 @@ ...@@ -122,6 +130,12 @@
/* Define if you have -lpcap and pcap.h. */ /* Define if you have -lpcap and pcap.h. */
#undef HAVE_PCAP #undef HAVE_PCAP
/* Define if you have the pcap_inject function. */
#undef HAVE_PCAP_INJECT
/* Define if you have the pcap_sendpacket function. */
#undef HAVE_PCAP_SENDPACKET
/* Define if you have the pcap_setnonblock function. */ /* Define if you have the pcap_setnonblock function. */
#undef HAVE_PCAP_SETNONBLOCK #undef HAVE_PCAP_SETNONBLOCK
......
...@@ -9710,7 +9710,29 @@ $as_echo "$ac_cv_bpf_timeval" >&6; } ...@@ -9710,7 +9710,29 @@ $as_echo "$ac_cv_bpf_timeval" >&6; }
$as_echo "#define HAVE_BPF_TIMEVAL 1" >>confdefs.h $as_echo "#define HAVE_BPF_TIMEVAL 1" >>confdefs.h
fi fi
ac_fn_cxx_check_decl "$LINENO" "pcap_setnonblock" "ac_cv_have_decl_pcap_setnonblock" "#include <pcap.h> ac_fn_cxx_check_decl "$LINENO" "pcap_inject" "ac_cv_have_decl_pcap_inject" "#include <pcap.h>
"
if test "x$ac_cv_have_decl_pcap_inject" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_PCAP_INJECT $ac_have_decl
_ACEOF
ac_fn_cxx_check_decl "$LINENO" "pcap_sendpacket" "ac_cv_have_decl_pcap_sendpacket" "#include <pcap.h>
"
if test "x$ac_cv_have_decl_pcap_sendpacket" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_PCAP_SENDPACKET $ac_have_decl
_ACEOF
ac_fn_cxx_check_decl "$LINENO" "pcap_setnonblock" "ac_cv_have_decl_pcap_setnonblock" "#include <pcap.h>
" "
if test "x$ac_cv_have_decl_pcap_setnonblock" = xyes; then : if test "x$ac_cv_have_decl_pcap_setnonblock" = xyes; then :
ac_have_decl=1 ac_have_decl=1
...@@ -9869,12 +9891,13 @@ $as_echo "#define HAVE_PCAP 1" >>confdefs.h ...@@ -9869,12 +9891,13 @@ $as_echo "#define HAVE_PCAP 1" >>confdefs.h
saveflags="$LDFLAGS" saveflags="$LDFLAGS"
LDFLAGS="$saveflags $PCAP_LIBS" LDFLAGS="$saveflags $PCAP_LIBS"
for ac_func in pcap_setnonblock for ac_func in pcap_inject pcap_sendpacket pcap_setnonblock
do : do :
ac_fn_c_check_func "$LINENO" "pcap_setnonblock" "ac_cv_func_pcap_setnonblock" as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
if test "x$ac_cv_func_pcap_setnonblock" = xyes; then : ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_PCAP_SETNONBLOCK 1 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF _ACEOF
fi fi
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2001 International Computer Science Institute * Copyright (c) 2001 International Computer Science Institute
* Copyright (c) 2005-2007 Regents of the University of California * Copyright (c) 2005-2007 Regents of the University of California
* Copyright (c) 2011 Meraki, Inc.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -73,7 +74,7 @@ int ...@@ -73,7 +74,7 @@ int
FromDevice::configure(Vector<String> &conf, ErrorHandler *errh) FromDevice::configure(Vector<String> &conf, ErrorHandler *errh)
{ {
bool promisc = false, outbound = false, sniffer = true; bool promisc = false, outbound = false, sniffer = true;
_snaplen = 2046; _snaplen = default_snaplen;
_headroom = Packet::default_headroom; _headroom = Packet::default_headroom;
_headroom += (4 - (_headroom + 2) % 4) % 4; // default 4/2 alignment _headroom += (4 - (_headroom + 2) % 4) % 4; // default 4/2 alignment
_force_ip = false; _force_ip = false;
...@@ -86,7 +87,8 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh) ...@@ -86,7 +87,8 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh)
.read_p("SNAPLEN", _snaplen) .read_p("SNAPLEN", _snaplen)
.read("SNIFFER", sniffer) .read("SNIFFER", sniffer)
.read("FORCE_IP", _force_ip) .read("FORCE_IP", _force_ip)
.read("CAPTURE", WordArg(), capture) .read("METHOD", WordArg(), capture)
.read("CAPTURE", WordArg(), capture) // deprecated
.read("BPF_FILTER", bpf_filter) .read("BPF_FILTER", bpf_filter)
.read("OUTBOUND", outbound) .read("OUTBOUND", outbound)
.read("HEADROOM", _headroom) .read("HEADROOM", _headroom)
...@@ -119,7 +121,7 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh) ...@@ -119,7 +121,7 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh)
#elif FROMDEVICE_PCAP #elif FROMDEVICE_PCAP
_capture = CAPTURE_PCAP; _capture = CAPTURE_PCAP;
#else #else
return errh->error("this platform does not support any capture method"); return errh->error("cannot receive packets on this platform");
#endif #endif
} }
#if FROMDEVICE_LINUX #if FROMDEVICE_LINUX
...@@ -131,10 +133,10 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh) ...@@ -131,10 +133,10 @@ FromDevice::configure(Vector<String> &conf, ErrorHandler *errh)
_capture = CAPTURE_PCAP; _capture = CAPTURE_PCAP;
#endif #endif
else else
return errh->error("capture method '%s' not supported", capture.c_str()); return errh->error("bad METHOD");
if (bpf_filter && _capture != CAPTURE_PCAP) if (bpf_filter && _capture != CAPTURE_PCAP)
errh->warning("not using PCAP capture method, BPF filter ignored"); errh->warning("not using METHOD PCAP, BPF filter ignored");
_sniffer = sniffer; _sniffer = sniffer;
_promisc = promisc; _promisc = promisc;
...@@ -215,16 +217,46 @@ FromDevice::set_promiscuous(int fd, String ifname, bool promisc) ...@@ -215,16 +217,46 @@ FromDevice::set_promiscuous(int fd, String ifname, bool promisc)
#endif /* FROMDEVICE_LINUX */ #endif /* FROMDEVICE_LINUX */
#if FROMDEVICE_PCAP #if FROMDEVICE_PCAP
String const char *
FromDevice::get_pcap_error(const char *ebuf) FromDevice::pcap_error(pcap_t *pcap, const char *ebuf)
{ {
if ((!ebuf || !ebuf[0]) && _pcap) if ((!ebuf || !ebuf[0]) && pcap)
ebuf = pcap_geterr(_pcap); ebuf = pcap_geterr(pcap);
if (!ebuf || !ebuf[0]) if (!ebuf || !ebuf[0])
return "unknown error"; return "unknown error";
else else
return ebuf; return ebuf;
} }
pcap_t *
FromDevice::open_pcap(String ifname, int snaplen, bool promisc,
ErrorHandler *errh)
{
char ebuf[PCAP_ERRBUF_SIZE];
ebuf[0] = 0;
pcap_t *pcap = pcap_open_live(ifname.mutable_c_str(), snaplen, promisc,
1, /* timeout: don't wait for packets */
ebuf);
// Note: pcap error buffer will contain the interface name
if (!pcap) {
errh->error("%s while opening %s", pcap_error(0, ebuf), ifname.c_str());
return 0;
} else if (ebuf[0])
errh->warning("%s", ebuf);
// nonblocking I/O on the packet socket so we can poll
# if HAVE_PCAP_SETNONBLOCK
ebuf[0] = 0;
if (pcap_setnonblock(pcap, 1, ebuf) < 0 || ebuf[0])
errh->warning("pcap_setnonblock: %s", pcap_error(pcap, ebuf));
# else
if (fcntl(pcap_fileno(pcap), F_SETFL, O_NONBLOCK) < 0)
errh->warning("setting nonblocking: %s", strerror(errno));
# endif
return pcap;
}
#endif #endif
int int
...@@ -236,28 +268,11 @@ FromDevice::initialize(ErrorHandler *errh) ...@@ -236,28 +268,11 @@ FromDevice::initialize(ErrorHandler *errh)
#if FROMDEVICE_PCAP #if FROMDEVICE_PCAP
if (_capture == CAPTURE_PCAP) { if (_capture == CAPTURE_PCAP) {
assert(!_pcap); assert(!_pcap);
char *ifname = _ifname.mutable_c_str(); _pcap = open_pcap(_ifname, _snaplen, _promisc, errh);
char ebuf[PCAP_ERRBUF_SIZE];
ebuf[0] = 0;
_pcap = pcap_open_live(ifname, _snaplen, _promisc,
1, /* timeout: don't wait for packets */
ebuf);
// Note: pcap error buffer will contain the interface name
if (!_pcap) if (!_pcap)
return errh->error("%s while opening %s", get_pcap_error(ebuf).c_str(), ifname); return 0;
else if (ebuf[0]) char *ifname = _ifname.mutable_c_str();
errh->warning("%s", ebuf);
// nonblocking I/O on the packet socket so we can poll
int pcap_fd = fd(); int pcap_fd = fd();
# if HAVE_PCAP_SETNONBLOCK
ebuf[0] = 0;
if (pcap_setnonblock(_pcap, 1, ebuf) < 0 || ebuf[0])
errh->warning("pcap_setnonblock: %s", get_pcap_error(ebuf).c_str());
# else
if (fcntl(pcap_fd, F_SETFL, O_NONBLOCK) < 0)
errh->warning("setting nonblocking: %s", strerror(errno));
# endif
# ifdef BIOCSSEESENT # ifdef BIOCSSEESENT
{ {
...@@ -288,9 +303,10 @@ FromDevice::initialize(ErrorHandler *errh) ...@@ -288,9 +303,10 @@ FromDevice::initialize(ErrorHandler *errh)
bpf_u_int32 netmask; bpf_u_int32 netmask;
bpf_u_int32 localnet; bpf_u_int32 localnet;
char ebuf[PCAP_ERRBUF_SIZE];
ebuf[0] = 0; ebuf[0] = 0;
if (pcap_lookupnet(ifname, &localnet, &netmask, ebuf) < 0 || ebuf[0] != 0) if (pcap_lookupnet(ifname, &localnet, &netmask, ebuf) < 0 || ebuf[0] != 0)
errh->warning("%s", get_pcap_error(ebuf).c_str()); errh->warning("%s", pcap_error(ebuf));
// Later versions of pcap distributed with linux (e.g. the redhat // Later versions of pcap distributed with linux (e.g. the redhat
// linux pcap-0.4-16) want to have a filter installed before they // linux pcap-0.4-16) want to have a filter installed before they
...@@ -299,9 +315,9 @@ FromDevice::initialize(ErrorHandler *errh) ...@@ -299,9 +315,9 @@ FromDevice::initialize(ErrorHandler *errh)
// compile the BPF filter // compile the BPF filter
struct bpf_program fcode; struct bpf_program fcode;
if (pcap_compile(_pcap, &fcode, _bpf_filter.mutable_c_str(), 0, netmask) < 0) if (pcap_compile(_pcap, &fcode, _bpf_filter.mutable_c_str(), 0, netmask) < 0)
return errh->error("%s: %s", ifname, pcap_geterr(_pcap)); return errh->error("%s: %s", ifname, pcap_error(0));
if (pcap_setfilter(_pcap, &fcode) < 0) if (pcap_setfilter(_pcap, &fcode) < 0)
return errh->error("%s: %s", ifname, pcap_geterr(_pcap)); return errh->error("%s: %s", ifname, pcap_error(0));
add_select(pcap_fd, SELECT_READ); add_select(pcap_fd, SELECT_READ);
...@@ -354,10 +370,9 @@ FromDevice::cleanup(CleanupStage stage) ...@@ -354,10 +370,9 @@ FromDevice::cleanup(CleanupStage stage)
} }
#endif #endif
#if FROMDEVICE_PCAP #if FROMDEVICE_PCAP
if (_pcap) { if (_pcap)
pcap_close(_pcap); pcap_close(_pcap);
_pcap = 0; _pcap = 0;
}
#endif #endif
} }
......
...@@ -79,23 +79,22 @@ Defaults to 2046. ...@@ -79,23 +79,22 @@ Defaults to 2046.
Boolean. If true, then output only IP packets. (Any link-level header remains, Boolean. If true, then output only IP packets. (Any link-level header remains,
but the IP header annotation has been set appropriately.) Default is false. but the IP header annotation has been set appropriately.) Default is false.
=item CAPTURE =item METHOD
Word. Defines the capture method FromDevice will use to read packets from the Word. Defines the capture method FromDevice will use to read packets from the
kernel. Linux targets generally support PCAP and LINUX; other targets support device. Linux targets generally support PCAP and LINUX; other targets support
only PCAP. Defaults to LINUX on Linux targets (unless you give a BPF_FILTER), only PCAP. Defaults to PCAP.
and PCAP elsewhere.
=item BPF_FILTER =item BPF_FILTER
String. A BPF filter expression used to select the interesting packets. String. A BPF filter expression used to select the interesting packets.
Default is the empty string, which means all packets. If CAPTURE is not PCAP, Default is the empty string, which means all packets. If METHOD is not PCAP,
then any filter expression is ignored with a warning. then any filter expression is ignored with a warning.
=item ENCAP =item ENCAP
Word. The encapsulation type the interface should use; see FromDump for Word. The encapsulation type the interface should use; see FromDump for
choices. Ignored if CAPTURE is not PCAP. choices. Ignored if METHOD is not PCAP.
=item OUTBOUND =item OUTBOUND
...@@ -153,6 +152,7 @@ class FromDevice : public Element { public: ...@@ -153,6 +152,7 @@ class FromDevice : public Element { public:
const char *port_count() const { return "0/1-2"; } const char *port_count() const { return "0/1-2"; }
const char *processing() const { return PUSH; } const char *processing() const { return PUSH; }
enum { default_snaplen = 2046 };
int configure_phase() const { return KernelFilter::CONFIGURE_PHASE_FROMDEVICE; } int configure_phase() const { return KernelFilter::CONFIGURE_PHASE_FROMDEVICE; }
int configure(Vector<String> &, ErrorHandler *); int configure(Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *); int initialize(ErrorHandler *);
...@@ -164,10 +164,14 @@ class FromDevice : public Element { public: ...@@ -164,10 +164,14 @@ class FromDevice : public Element { public:
void selected(int fd, int mask); void selected(int fd, int mask);
#if FROMDEVICE_PCAP #if FROMDEVICE_PCAP
pcap_t *pcap() const { return _pcap; }
bool run_task(Task *); bool run_task(Task *);
static const char *pcap_error(pcap_t *pcap, const char *ebuf);
static pcap_t *open_pcap(String ifname, int snaplen, bool promisc, ErrorHandler *errh);
#endif #endif
#if FROMDEVICE_LINUX #if FROMDEVICE_LINUX
int linux_fd() const { return _linux_fd; }
static int open_packet_socket(String, ErrorHandler *); static int open_packet_socket(String, ErrorHandler *);
static int set_promiscuous(int, String, bool); static int set_promiscuous(int, String, bool);
#endif #endif
...@@ -181,12 +185,14 @@ class FromDevice : public Element { public: ...@@ -181,12 +185,14 @@ class FromDevice : public Element { public:
unsigned char *_linux_packetbuf; unsigned char *_linux_packetbuf;
#endif #endif
#if FROMDEVICE_PCAP #if FROMDEVICE_PCAP
pcap_t* _pcap; pcap_t *_pcap;
Task _pcap_task; Task _pcap_task;
int _pcap_complaints; int _pcap_complaints;
friend void FromDevice_get_packet(u_char*, const struct pcap_pkthdr*, friend void FromDevice_get_packet(u_char*, const struct pcap_pkthdr*,
const u_char*); const u_char*);
String get_pcap_error(const char *ebuf); const char *pcap_error(const char *ebuf) {
return pcap_error(_pcap, ebuf);
}
#endif #endif
bool _force_ip; bool _force_ip;
int _burst; int _burst;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2005-2008 Regents of the University of California * Copyright (c) 2005-2008 Regents of the University of California
* Copyright (c) 2011 Meraki, Inc.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -34,13 +35,14 @@ ...@@ -34,13 +35,14 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#if TODEVICE_BSD_DEV_BPF #if TODEVICE_ALLOW_DEVBPF
# include <fcntl.h> # include <fcntl.h>
# include <sys/types.h> # include <sys/types.h>
# include <sys/socket.h> # include <sys/socket.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <net/if.h> # include <net/if.h>
#elif TODEVICE_LINUX #endif
#if TODEVICE_ALLOW_LINUX
# include <sys/socket.h> # include <sys/socket.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <net/if.h> # include <net/if.h>
...@@ -56,10 +58,16 @@ ...@@ -56,10 +58,16 @@
CLICK_DECLS CLICK_DECLS
ToDevice::ToDevice() ToDevice::ToDevice()
: _task(this), _timer(&_task), _fd(-1), _my_fd(false), : _task(this), _timer(&_task), _q(0), _pulls(0)
_q(0),
_pulls(0)
{ {
#if TODEVICE_ALLOW_PCAP
_pcap = 0;
_my_pcap = false;
#endif
#if TODEVICE_ALLOW_LINUX || TODEVICE_ALLOW_DEVBPF || TODEVICE_ALLOW_PCAPFD
_fd = -1;
_my_fd = false;
#endif
} }
ToDevice::~ToDevice() ToDevice::~ToDevice()
...@@ -69,90 +77,158 @@ ToDevice::~ToDevice() ...@@ -69,90 +77,158 @@ ToDevice::~ToDevice()
int int
ToDevice::configure(Vector<String> &conf, ErrorHandler *errh) ToDevice::configure(Vector<String> &conf, ErrorHandler *errh)
{ {
String method;
if (Args(conf, this, errh) if (Args(conf, this, errh)
.read_mp("DEVNAME", _ifname) .read_mp("DEVNAME", _ifname)
.read("DEBUG", _debug) .read("DEBUG", _debug)
.read("METHOD", WordArg(), method)
.complete() < 0) .complete() < 0)
return -1; return -1;
if (!_ifname) if (!_ifname)
return errh->error("interface not set"); return errh->error("interface not set");
if (method == "") {
#if TODEVICE_ALLOW_PCAP && TODEVICE_ALLOW_LINUX
_method = method_pcap;
if (FromDevice *fd = find_fromdevice())
if (fd->linux_fd())
_method = method_linux;
#elif TODEVICE_ALLOW_PCAP
_method = method_pcap;
#elif TODEVICE_ALLOW_LINUX
_method = method_linux;
#elif TODEVICE_ALLOW_DEVBPF
_method = method_devbpf;
#elif TODEVICE_ALLOW_PCAPFD
_method = method_pcapfd;
#else
return errh->error("cannot send packets on this platform");
#endif
}
#if TODEVICE_ALLOW_PCAP
else if (method == "PCAP")
_method = method_pcap;
#endif
#if TODEVICE_ALLOW_LINUX
else if (method == "LINUX")
_method = method_linux;
#endif
#if TODEVICE_ALLOW_DEVBPF
else if (method == "DEVBPF")
_method = method_devbpf;
#endif
#if TODEVICE_ALLOW_PCAPFD
else if (method == "PCAPFD")
_method = method_pcapfd;
#endif
else
return errh->error("bad METHOD");
return 0;
}
FromDevice *
ToDevice::find_fromdevice() const
{
Router *r = router();
for (int ei = 0; ei < r->nelements(); ++ei)
if (FromDevice *fd = (FromDevice *) r->element(ei)->cast("FromDevice"))
return fd;
return 0; return 0;
} }
int int
ToDevice::initialize(ErrorHandler *errh) ToDevice::initialize(ErrorHandler *errh)
{ {
_timer.initialize(this); _timer.initialize(this);
_fd = -1;
#if TODEVICE_ALLOW_PCAP
#if TODEVICE_BSD_DEV_BPF if (_method == method_pcap) {
FromDevice *fd = find_fromdevice();
/* pcap_open_live() doesn't open for writing. */ if (fd && fd->pcap())
for (int i = 0; i < 16 && _fd < 0; i++) { _pcap = fd->pcap();
char tmp[64]; else {
sprintf(tmp, "/dev/bpf%d", i); _pcap = FromDevice::open_pcap(_ifname, FromDevice::default_snaplen, false, errh);
_fd = open(tmp, 1); if (!_pcap)
} return -1;
if (_fd < 0) _my_pcap = true;
return(errh->error("open /dev/bpf* for write: %s", strerror(errno))); }
}
struct ifreq ifr; #endif
strncpy(ifr.ifr_name, _ifname.c_str(), sizeof(ifr.ifr_name));
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0; #if TODEVICE_ALLOW_DEVBPF
if (ioctl(_fd, BIOCSETIF, (caddr_t)&ifr) < 0) if (_method == method_devbpf) {
return errh->error("BIOCSETIF %s failed", ifr.ifr_name); /* pcap_open_live() doesn't open for writing. */
for (int i = 0; i < 16 && _fd < 0; i++) {
char tmp[64];
sprintf(tmp, "/dev/bpf%d", i);
_fd = open(tmp, 1);
}
if (_fd < 0)
return(errh->error("open /dev/bpf* for write: %s", strerror(errno)));
_my_fd = true;
struct ifreq ifr;
strncpy(ifr.ifr_name, _ifname.c_str(), sizeof(ifr.ifr_name));
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;
if (ioctl(_fd, BIOCSETIF, (caddr_t)&ifr) < 0)
return errh->error("BIOCSETIF %s failed", ifr.ifr_name);
# ifdef BIOCSHDRCMPLT # ifdef BIOCSHDRCMPLT
int yes = 1; int yes = 1;
if (ioctl(_fd, BIOCSHDRCMPLT, (caddr_t)&yes) < 0) if (ioctl(_fd, BIOCSHDRCMPLT, (caddr_t)&yes) < 0)
errh->warning("BIOCSHDRCMPLT %s failed", ifr.ifr_name); errh->warning("BIOCSHDRCMPLT %s failed", ifr.ifr_name);
# endif # endif
_my_fd = true;
#elif TODEVICE_LINUX || TODEVICE_PCAP
// find a FromDevice and reuse its socket if possible
for (int ei = 0; ei < router()->nelements() && _fd < 0; ei++) {
Element *e = router()->element(ei);
FromDevice *fdev = (FromDevice *)e->cast("FromDevice");
if (fdev && fdev->ifname() == _ifname && fdev->fd() >= 0) {
_fd = fdev->fd();
_my_fd = false;
} }
} #endif
if (_fd < 0) {
# if TODEVICE_LINUX
_fd = FromDevice::open_packet_socket(_ifname, errh);
_my_fd = true;
# else
return errh->error("ToDevice requires an initialized FromDevice on this platform");
# endif
}
if (_fd < 0)
return -1;
#else