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()
_printed_write_err(false), _printed_read_err(false),
_selected_calls(0), _packets(0)
{
#if HAVE_BATCH
in_batch_mode = BATCH_MODE_YES;
#endif
}
KernelTun::~KernelTun()
......@@ -498,94 +501,134 @@ KernelTun::selected(int fd, int)
return;
++_selected_calls;
unsigned n = _burst;
while (n > 0 && one_selected(now))
--n;
#if HAVE_BATCH
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
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) {
click_chatter("out of memory!");
return false;
click_chatter("out of memory!");
return 2;
}
int cc = read(_fd, p->data(), _mtu_in);
if (cc > 0) {
++_packets;
p->take(_mtu_in - cc);
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());
p->pull(4);
if (af != AF_INET && af != AF_INET6) {
click_chatter("KernelTun(%s): don't know AF %d", _dev_name.c_str(), af);
checked_output_push(1, p->clone());
} else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} else if (_type == OSX_TUN || _type == NETBSD_TUN) {
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) {
p->set_timestamp_anno(now);
output(0).push(p);
} else
checked_output_push(1, p);
return true;
++_packets;
p->take(_mtu_in - cc);
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)) {
#if HAVE_BATCH
checked_output_push(1, p->clone());
#else
checked_output_push_batch(1, PacketBatch::make_from_packet(p->clone()));
#endif
} 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());
p->pull(4);
if (af != AF_INET && af != AF_INET6) {
click_chatter("KernelTun(%s): don't know AF %d", _dev_name.c_str(), af);
#if HAVE_BATCH
checked_output_push(1, p->clone());
#else
checked_output_push_batch(1, PacketBatch::make_from_packet(p->clone()));
#endif
} else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
} else if (_type == OSX_TUN || _type == NETBSD_TUN) {
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))
return 1;
else
ok = fake_pcap_force_ip(p, FAKE_DLT_RAW);
}
if (ok) {
p->set_timestamp_anno(now);
return 0;
} else {
return 1;
}
} else {
p->kill();
if (errno != EAGAIN && errno != EWOULDBLOCK
&& (!_ignore_q_errs || !_printed_read_err || errno != ENOBUFS)) {
_printed_read_err = true;
perror("KernelTun read");
}
return false;
p->kill();
if (errno != EAGAIN && errno != EWOULDBLOCK
&& (!_ignore_q_errs || !_printed_read_err || errno != ENOBUFS)) {
_printed_read_err = true;
perror("KernelTun read");
}
return 2;
}
}
bool
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();
if (p)
push(0, p);
push(0, p);
#endif
else if (!_signal)
return false;
_task.fast_reschedule();
return p != 0;
}
void
KernelTun::push(int, Packet *p)
{
KernelTun::process(Packet* p) {
const click_ip *iph = 0;
int check_length;
......@@ -673,6 +716,20 @@ KernelTun::push(int, Packet *p)
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
KernelTun::add_handlers()
{
......
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_KERNELTUN_HH
#define CLICK_KERNELTUN_HH
#include <click/element.hh>
#include <click/batchelement.hh>
#include <click/etheraddress.hh>
#include <click/task.hh>
#include <click/notifier.hh>
......@@ -104,30 +104,33 @@ packets, not IP-in-Ethernet packets.
FromDevice.u, ToDevice.u, KernelTap, ifconfig(8) */
class KernelTun : public Element { public:
class KernelTun : public BatchElement { public:
KernelTun() CLICK_COLD;
~KernelTun() CLICK_COLD;
const char *class_name() const { return "KernelTun"; }
const char *port_count() const { return "0-1/1-2"; }
const char *processing() const { return "a/h"; }
const char *flow_code() const { return "x/y"; }
const char *flags() const { return "S3"; }
void *cast(const char *);
int configure_phase() const { return CONFIGURE_PHASE_PRIVILEGED - 1; }
int configure(Vector<String> &, ErrorHandler *) CLICK_COLD;
int initialize(ErrorHandler *) CLICK_COLD;
void cleanup(CleanupStage) CLICK_COLD;
void add_handlers() CLICK_COLD;
const char *class_name() const override { return "KernelTun"; }
const char *port_count() const override { return "0-1/1-2"; }
const char *processing() const override { return "a/h"; }
const char *flow_code() const override { return "x/y"; }
const char *flags() const override { return "S3"; }
void *cast(const char *) override;
int configure_phase() const override { return CONFIGURE_PHASE_PRIVILEGED - 1; }
int configure(Vector<String> &, ErrorHandler *) override CLICK_COLD;
int initialize(ErrorHandler *) override CLICK_COLD;
void cleanup(CleanupStage) override CLICK_COLD;
void add_handlers() override CLICK_COLD;
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 *);
bool run_task(Task *);
void push(int port, Packet *) override;
#if HAVE_BATCH
void push_batch(int port, PacketBatch *) override;
#endif
bool run_task(Task *) override;
private:
......@@ -165,7 +168,8 @@ class KernelTun : public Element { public:
int alloc_tun(ErrorHandler *);
int setup_tun(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;
......
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