Commit 6a5f9f40 authored by Tom Barbette's avatar Tom Barbette

Make KernelTun batch-compatible

parent 7b9d62ff
Pipeline #1815 passed with stage
in 11 minutes and 28 seconds
...@@ -72,6 +72,9 @@ KernelTun::KernelTun() ...@@ -72,6 +72,9 @@ KernelTun::KernelTun()
_printed_write_err(false), _printed_read_err(false), _printed_write_err(false), _printed_read_err(false),
_selected_calls(0), _packets(0) _selected_calls(0), _packets(0)
{ {
#if HAVE_BATCH
in_batch_mode = BATCH_MODE_YES;
#endif
} }
KernelTun::~KernelTun() KernelTun::~KernelTun()
...@@ -498,94 +501,134 @@ KernelTun::selected(int fd, int) ...@@ -498,94 +501,134 @@ KernelTun::selected(int fd, int)
return; return;
++_selected_calls; ++_selected_calls;
unsigned n = _burst; unsigned n = _burst;
while (n > 0 && one_selected(now)) #if HAVE_BATCH
--n; BATCH_CREATE_INIT(batch);
#endif
while (n > 0) {
WritablePacket* p = 0;
int o = one_selected(now, p);
if (likely(o == 0)) {
#if HAVE_BATCH
BATCH_CREATE_APPEND(batch,p);
#else
output(0).push(p);
#endif
} else if (o == 2) {
break;
} else if (o == 1) {
#if HAVE_BATCH
checked_output_push_batch(1, PacketBatch::make_from_packet(p));
#else
checked_output_push(1, p);
#endif
}
--n;
}
#if HAVE_BATCH
BATCH_CREATE_FINISH(batch);
if (batch)
output(0).push_batch(batch);
#endif
} }
bool bool
KernelTun::one_selected(const Timestamp &now) KernelTun::one_selected(const Timestamp &now, WritablePacket* &p)
{ {
WritablePacket *p = Packet::make(_headroom, 0, _mtu_in, 0); p = Packet::make(_headroom, 0, _mtu_in, 0);
if (!p) { if (!p) {
click_chatter("out of memory!"); click_chatter("out of memory!");
return false; return 2;
} }
int cc = read(_fd, p->data(), _mtu_in); int cc = read(_fd, p->data(), _mtu_in);
if (cc > 0) { if (cc > 0) {
++_packets; ++_packets;
p->take(_mtu_in - cc); p->take(_mtu_in - cc);
bool ok = false; bool ok = false;
if (_tap) { if (_tap) {
if (_type == LINUX_UNIVERSAL) if (_type == LINUX_UNIVERSAL)
// 2-byte padding, 2-byte Ethernet type, then Ethernet header // 2-byte padding, 2-byte Ethernet type, then Ethernet header
p->pull(4); p->pull(4);
else if (_type == LINUX_ETHERTAP) else if (_type == LINUX_ETHERTAP)
// 2-byte padding, then Ethernet header // 2-byte padding, then Ethernet header
p->pull(2); p->pull(2);
ok = true; ok = true;
} else if (_type == LINUX_UNIVERSAL) { } else if (_type == LINUX_UNIVERSAL) {
// 2-byte padding followed by an Ethernet type // 2-byte padding followed by an Ethernet type
uint16_t etype = *(uint16_t *)(p->data() + 2); uint16_t etype = *(uint16_t *)(p->data() + 2);
p->pull(4); p->pull(4);
if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6)) if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6)) {
checked_output_push(1, p->clone()); #if HAVE_BATCH
else checked_output_push(1, p->clone());
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW); #else
} else if (_type == BSD_TUN) { checked_output_push_batch(1, PacketBatch::make_from_packet(p->clone()));
// 4-byte address family followed by IP header #endif
int af = ntohl(*(unsigned *)p->data()); } else
p->pull(4); ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
if (af != AF_INET && af != AF_INET6) { } else if (_type == BSD_TUN) {
click_chatter("KernelTun(%s): don't know AF %d", _dev_name.c_str(), af); // 4-byte address family followed by IP header
checked_output_push(1, p->clone()); int af = ntohl(*(unsigned *)p->data());
} else p->pull(4);
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW); if (af != AF_INET && af != AF_INET6) {
} else if (_type == OSX_TUN || _type == NETBSD_TUN) { click_chatter("KernelTun(%s): don't know AF %d", _dev_name.c_str(), af);
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW); #if HAVE_BATCH
} else { /* _type == LINUX_ETHERTAP */ checked_output_push(1, p->clone());
// 2-byte padding followed by a mostly-useless Ethernet header #else
uint16_t etype = *(uint16_t *)(p->data() + 14); checked_output_push_batch(1, PacketBatch::make_from_packet(p->clone()));
p->pull(16); #endif
if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6)) } else
checked_output_push(1, p->clone()); ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
else } else if (_type == OSX_TUN || _type == NETBSD_TUN) {
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW); ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} } else { /* _type == LINUX_ETHERTAP */
// 2-byte padding followed by a mostly-useless Ethernet header
if (ok) { uint16_t etype = *(uint16_t *)(p->data() + 14);
p->set_timestamp_anno(now); p->pull(16);
output(0).push(p); if (etype != htons(ETHERTYPE_IP) && etype != htons(ETHERTYPE_IP6))
} else return 1;
checked_output_push(1, p); else
return true; ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
}
if (ok) {
p->set_timestamp_anno(now);
return 0;
} else {
return 1;
}
} else { } else {
p->kill(); p->kill();
if (errno != EAGAIN && errno != EWOULDBLOCK if (errno != EAGAIN && errno != EWOULDBLOCK
&& (!_ignore_q_errs || !_printed_read_err || errno != ENOBUFS)) { && (!_ignore_q_errs || !_printed_read_err || errno != ENOBUFS)) {
_printed_read_err = true; _printed_read_err = true;
perror("KernelTun read"); perror("KernelTun read");
} }
return false; return 2;
} }
} }
bool bool
KernelTun::run_task(Task *) KernelTun::run_task(Task *)
{ {
#if HAVE_BATCH
PacketBatch *p = input(0).pull_batch(_burst);
if (p)
push_batch(0, p);
#else
Packet *p = input(0).pull(); Packet *p = input(0).pull();
if (p) if (p)
push(0, p); push(0, p);
#endif
else if (!_signal) else if (!_signal)
return false; return false;
_task.fast_reschedule(); _task.fast_reschedule();
return p != 0; return p != 0;
} }
void void
KernelTun::push(int, Packet *p) KernelTun::process(Packet* p) {
{
const click_ip *iph = 0; const click_ip *iph = 0;
int check_length; int check_length;
...@@ -673,6 +716,20 @@ KernelTun::push(int, Packet *p) ...@@ -673,6 +716,20 @@ KernelTun::push(int, Packet *p)
click_chatter("%s(%s): out of memory", class_name(), _dev_name.c_str()); click_chatter("%s(%s): out of memory", class_name(), _dev_name.c_str());
} }
void
KernelTun::push(int, Packet *p)
{
process(p);
}
#if HAVE_BATCH
void
KernelTun::push_batch(int, PacketBatch *batch) {
FOR_EACH_PACKET_SAFE(batch, p)
process(p);
}
#endif
void void
KernelTun::add_handlers() KernelTun::add_handlers()
{ {
......
// -*- c-basic-offset: 4 -*- // -*- c-basic-offset: 4 -*-
#ifndef CLICK_KERNELTUN_HH #ifndef CLICK_KERNELTUN_HH
#define CLICK_KERNELTUN_HH #define CLICK_KERNELTUN_HH
#include <click/element.hh> #include <click/batchelement.hh>
#include <click/etheraddress.hh> #include <click/etheraddress.hh>
#include <click/task.hh> #include <click/task.hh>
#include <click/notifier.hh> #include <click/notifier.hh>
...@@ -104,30 +104,33 @@ packets, not IP-in-Ethernet packets. ...@@ -104,30 +104,33 @@ packets, not IP-in-Ethernet packets.
FromDevice.u, ToDevice.u, KernelTap, ifconfig(8) */ FromDevice.u, ToDevice.u, KernelTap, ifconfig(8) */
class KernelTun : public Element { public: class KernelTun : public BatchElement { public:
KernelTun() CLICK_COLD; KernelTun() CLICK_COLD;
~KernelTun() CLICK_COLD; ~KernelTun() CLICK_COLD;
const char *class_name() const { return "KernelTun"; } const char *class_name() const override { return "KernelTun"; }
const char *port_count() const { return "0-1/1-2"; } const char *port_count() const override { return "0-1/1-2"; }
const char *processing() const { return "a/h"; } const char *processing() const override { return "a/h"; }
const char *flow_code() const { return "x/y"; } const char *flow_code() const override { return "x/y"; }
const char *flags() const { return "S3"; } const char *flags() const override { return "S3"; }
void *cast(const char *); void *cast(const char *) override;
int configure_phase() const { return CONFIGURE_PHASE_PRIVILEGED - 1; } int configure_phase() const override { return CONFIGURE_PHASE_PRIVILEGED - 1; }
int configure(Vector<String> &, ErrorHandler *) CLICK_COLD; int configure(Vector<String> &, ErrorHandler *) override CLICK_COLD;
int initialize(ErrorHandler *) CLICK_COLD; int initialize(ErrorHandler *) override CLICK_COLD;
void cleanup(CleanupStage) CLICK_COLD; void cleanup(CleanupStage) override CLICK_COLD;
void add_handlers() CLICK_COLD; void add_handlers() override CLICK_COLD;
bool get_spawning_threads(Bitvector &, bool) override; bool get_spawning_threads(Bitvector &, bool) override;
void selected(int fd, int mask); void selected(int fd, int mask) override;
void push(int port, Packet *); void push(int port, Packet *) override;
bool run_task(Task *); #if HAVE_BATCH
void push_batch(int port, PacketBatch *) override;
#endif
bool run_task(Task *) override;
private: private:
...@@ -165,7 +168,8 @@ class KernelTun : public Element { public: ...@@ -165,7 +168,8 @@ class KernelTun : public Element { public:
int alloc_tun(ErrorHandler *); int alloc_tun(ErrorHandler *);
int setup_tun(ErrorHandler *); int setup_tun(ErrorHandler *);
int updown(IPAddress, IPAddress, ErrorHandler *); int updown(IPAddress, IPAddress, ErrorHandler *);
bool one_selected(const Timestamp &now); bool one_selected(const Timestamp &now, WritablePacket* &p);
void process(Packet* p);
friend class KernelTap; friend class KernelTap;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment