Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KernelTun: Use IFF_NO_PI on Linux, remove LINUX_ETHERTAP mode #397

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 17 additions & 83 deletions elements/userlevel/kerneltun.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ KernelTun::try_linux_universal()

struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = (_tap ? IFF_TAP : IFF_TUN);
ifr.ifr_flags = (_tap ? IFF_TAP : IFF_TUN) | IFF_NO_PI;
if (_dev_name)
// Setting ifr_name allows us to select an arbitrary interface name.
strncpy(ifr.ifr_name, _dev_name.c_str(), sizeof(ifr.ifr_name));
Expand Down Expand Up @@ -189,24 +189,20 @@ KernelTun::alloc_tun(ErrorHandler *errh)
saved_message = "\n(Perhaps you need to enable tun in your kernel or load the 'tun' module.)";
}
tried << "/dev/net/tun, ";
#endif

#else
String dev_prefix;
#ifdef __linux__
_type = LINUX_ETHERTAP;
dev_prefix = "tap";
#elif defined(KERNELTUN_OSX)
# if defined(KERNELTUN_OSX)
_type = OSX_TUN;
dev_prefix = "tun";
#elif defined(__NetBSD__) && !defined(TUNSIFHEAD)
# elif defined(__NetBSD__) && !defined(TUNSIFHEAD)
_type = (_tap ? NETBSD_TAP : NETBSD_TUN);
dev_prefix = (_tap ? "tap" : "tun");
#else
# else
_type = (_tap ? BSD_TAP : BSD_TUN);
dev_prefix = (_tap ? "tap" : "tun");
#endif
# endif

#if defined(__NetBSD__) && !defined(TUNSIFHEAD)
# if defined(__NetBSD__) && !defined(TUNSIFHEAD)
if (_type == NETBSD_TAP) {
// In NetBSD, two ways to create a tap:
// 1. open /dev/tap cloning interface.
Expand All @@ -224,7 +220,7 @@ KernelTun::alloc_tun(ErrorHandler *errh)
tried << "/dev/" << dev_prefix;
goto error_out;
}
#endif
# endif

for (int i = 0; i < 6; i++) {
if ((error = try_tun(dev_prefix + String(i), errh)) >= 0)
Expand All @@ -234,8 +230,10 @@ KernelTun::alloc_tun(ErrorHandler *errh)
tried << "/dev/" << dev_prefix << i << ", ";
}

#if defined(__NetBSD__) && !defined(TUNSIFHEAD)
# if defined(__NetBSD__) && !defined(TUNSIFHEAD)
error_out:
# endif

#endif
if (saved_error == -ENOENT) {
tried.pop_back(2);
Expand Down Expand Up @@ -438,22 +436,11 @@ KernelTun::setup_tun(ErrorHandler *errh)
// calculate maximum packet size needed to receive data from
// tun/tap.
if (_tap) {
if (_type == LINUX_UNIVERSAL)
_mtu_in = _mtu_out + 18;
else if (_type == LINUX_ETHERTAP)
_mtu_in = _mtu_out + 16;
else
_mtu_in = _mtu_out + 14;
} else if (_type == LINUX_UNIVERSAL)
_mtu_in = _mtu_out + 4;
else if (_type == BSD_TUN)
_mtu_in = _mtu_out + 14;
} else if (_type == BSD_TUN)
_mtu_in = _mtu_out + 4;
else if (_type == BSD_TAP || _type == NETBSD_TAP || _type == NETBSD_TUN)
else
_mtu_in = _mtu_out;
else if (_type == OSX_TUN)
_mtu_in = _mtu_out + 4; // + 0?
else /* _type == LINUX_ETHERTAP */
_mtu_in = _mtu_out + 16;

return 0;
}
Expand All @@ -470,10 +457,7 @@ KernelTun::initialize(ErrorHandler *errh)
_signal = Notifier::upstream_empty_signal(this, 0, &_task);
}
if (_adjust_headroom) {
if (_tap && _type == LINUX_UNIVERSAL)
_headroom += (4 - (_headroom + 2) % 4) % 4; // default 4/2 alignment
else
_headroom += (4 - _headroom % 4) % 4; // default 4/0 alignment
_headroom += (4 - _headroom % 4) % 4; // default 4/0 alignment
}
add_select(_fd, SELECT_READ);
return 0;
Expand Down Expand Up @@ -518,21 +502,7 @@ KernelTun::one_selected(const Timestamp &now)
bool ok = false;

if (_tap) {
if (_type == LINUX_UNIVERSAL)
// 2-byte padding, 2-byte Ethernet type, then Ethernet header
p->pull(4);
else if (_type == LINUX_ETHERTAP)
// 2-byte padding, then Ethernet header
p->pull(2);
ok = true;
} else if (_type == LINUX_UNIVERSAL) {
// 2-byte padding followed by an Ethernet type
uint16_t etype = *(uint16_t *)(p->data() + 2);
p->pull(4);
if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6))
checked_output_push(1, p->clone());
else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} else if (_type == BSD_TUN) {
// 4-byte address family followed by IP header
int af = ntohl(*(unsigned *)p->data());
Expand All @@ -542,16 +512,8 @@ KernelTun::one_selected(const Timestamp &now)
checked_output_push(1, p->clone());
} else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} else if (_type == OSX_TUN || _type == NETBSD_TUN) {
} else {
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} else { /* _type == LINUX_ETHERTAP */
// 2-byte padding followed by a mostly-useless Ethernet header
uint16_t etype = *(uint16_t *)(p->data() + 14);
p->pull(16);
if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6))
checked_output_push(1, p->clone());
else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
}

if (ok) {
Expand Down Expand Up @@ -624,40 +586,12 @@ KernelTun::push(int, Packet *p)

WritablePacket *q;
if (_tap) {
if (_type == LINUX_UNIVERSAL) {
// 2-byte padding, 2-byte Ethernet type, then Ethernet header
uint16_t ethertype = ((const click_ether *) p->data())->ether_type;
if ((q = p->push(4)))
((uint16_t *) q->data())[1] = ethertype;
p = q;
} else if (_type == LINUX_ETHERTAP) {
// 2-byte padding, then Ethernet header
p = p->push(2);
} else {
/* existing packet is OK */;
}
} else if (_type == LINUX_UNIVERSAL) {
// 2-byte padding followed by an Ethernet type
uint32_t ethertype = (iph->ip_v == 4 ? htonl(ETHERTYPE_IP) : htonl(ETHERTYPE_IP6));
if ((q = p->push(4)))
*(uint32_t *)(q->data()) = ethertype;
p = q;
/* existing packet is OK */;
} else if (_type == BSD_TUN) {
uint32_t af = (iph->ip_v == 4 ? htonl(AF_INET) : htonl(AF_INET6));
if ((q = p->push(4)))
*(uint32_t *)(q->data()) = af;
p = q;
} else if (_type == LINUX_ETHERTAP) {
uint16_t ethertype = (iph->ip_v == 4 ? htons(ETHERTYPE_IP) : htons(ETHERTYPE_IP6));
if ((q = p->push(16))) {
/* ethertap driver is very picky about what address we use
* here. e.g. if we have the wrong address, linux might ignore
* all the packets, or accept udp or icmp, but ignore tcp.
* aaarrrgh, well this works. -ddc */
memcpy(q->data(), "\x00\x00\xFE\xFD\x00\x00\x00\x00\xFE\xFD\x00\x00\x00\x00", 14);
*(uint16_t *)(q->data() + 14) = ethertype;
}
p = q;
} else {
/* existing packet is OK */;
}
Expand Down