Skip to content

Commit

Permalink
Remove bpf_ktime from simplebridge and use custom thread
Browse files Browse the repository at this point in the history
This commit removes the bpf_ktime() helper from the Simplebridge
used to remove old entries from the filtering database.
This helper introduces a performance degradation that could be removed
by using a custom thread that updates a percpu map with the timestamp
at the same way it is done in the Iptables service.

Signed-off-by: Sebastiano Miano <mianosebastiano@gmail.com>
  • Loading branch information
sebymiano authored and mauriciovasquezbernal committed Feb 6, 2019
1 parent 5a8c2c9 commit 9a58dd3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 27 deletions.
17 changes: 7 additions & 10 deletions src/services/pcn-simplebridge/src/FdbEntry.cpp
Expand Up @@ -28,7 +28,7 @@ FdbEntry::FdbEntry(Fdb &parent, const FdbEntryJsonObject &conf): parent_(parent)
logger()->info("Creating FdbEntry instance");
}

FdbEntry::FdbEntry(Fdb &parent, const std::string &address, uint64_t entry_age, uint32_t out_port) :
FdbEntry::FdbEntry(Fdb &parent, const std::string &address, uint32_t entry_age, uint32_t out_port) :
parent_(parent), address_(address), entry_age_(entry_age), port_no_(out_port)
{
auto port = parent.parent_.get_port(port_no_);
Expand Down Expand Up @@ -74,12 +74,10 @@ void FdbEntry::create(Fdb &parent, const std::string &address, const FdbEntryJso

struct timespec now_timespec;
clock_gettime(CLOCK_MONOTONIC, &now_timespec);
const uint64_t SEC2NANOSEC = 1000000000ULL;
uint64_t now = now_timespec.tv_sec*SEC2NANOSEC + now_timespec.tv_nsec;

uint64_t key = utils::mac_string_to_be_uint(address);
fwd_entry value {
.timestamp = now,
.timestamp = (uint32_t) now_timespec.tv_sec,
.port = port_index,
};

Expand All @@ -97,22 +95,21 @@ std::shared_ptr<FdbEntry> FdbEntry::constructFromMap(Fdb &parent, const std::str
const fwd_entry &value) {
struct timespec now_timespec;
clock_gettime(CLOCK_MONOTONIC, &now_timespec);
const uint64_t SEC2NANOSEC = 1000000000ULL;
uint64_t now = now_timespec.tv_sec*SEC2NANOSEC + now_timespec.tv_nsec;
uint32_t now = now_timespec.tv_sec;

uint64_t key = utils::mac_string_to_be_uint(address);
uint64_t timestamp = value.timestamp;
uint32_t timestamp = value.timestamp;

//Here I'm going to check if the entry in the filtering database is too old.\
//In this case, I'll not show the entry
if ((now - timestamp) > parent.getAgingTime()*SEC2NANOSEC) {
if ((now - timestamp) > parent.getAgingTime()) {
parent.logger()->debug("Ignoring old entry: now {0}, last_seen: {1}",
now/SEC2NANOSEC, timestamp/SEC2NANOSEC);
now, timestamp);
auto fwdtable = parent.parent_.get_hash_table<uint64_t, fwd_entry>("fwdtable");
fwdtable.remove(key);
return nullptr;
}
uint64_t entry_age = (now - timestamp)/SEC2NANOSEC;
uint32_t entry_age = now - timestamp;
uint32_t port_no = value.port;
return std::make_shared<FdbEntry>(parent, address, entry_age, port_no);
}
Expand Down
6 changes: 3 additions & 3 deletions src/services/pcn-simplebridge/src/FdbEntry.h
Expand Up @@ -27,7 +27,7 @@ class Fdb;

/* definitions copied from datapath */
struct fwd_entry {
uint64_t timestamp;
uint32_t timestamp;
uint32_t port;
} __attribute__((packed));

Expand All @@ -36,7 +36,7 @@ using namespace io::swagger::server::model;
class FdbEntry : public FdbEntryInterface {
public:
FdbEntry(Fdb &parent, const FdbEntryJsonObject &conf);
FdbEntry(Fdb &parent, const std::string &address, uint64_t entry_age, uint32_t out_port);
FdbEntry(Fdb &parent, const std::string &address, uint32_t entry_age, uint32_t out_port);
virtual ~FdbEntry();

static void create(Fdb &parent, const std::string &address, const FdbEntryJsonObject &conf);
Expand Down Expand Up @@ -77,7 +77,7 @@ class FdbEntry : public FdbEntryInterface {

std::string address_;
std::string port_name_;
uint64_t entry_age_;
uint32_t entry_age_;
uint32_t port_no_;
};

37 changes: 35 additions & 2 deletions src/services/pcn-simplebridge/src/Simplebridge.cpp
Expand Up @@ -23,23 +23,57 @@

#include <tins/ethernetII.h>
#include <tins/tins.h>
#include <thread>

using namespace Tins;

Simplebridge::Simplebridge(const std::string name, const SimplebridgeJsonObject &conf, CubeType type)
: Cube(name, {generate_code()}, {}, type, conf.getPolycubeLoglevel()) {
: Cube(name, {generate_code()}, {}, type, conf.getPolycubeLoglevel()),
quit_thread_(false) {
logger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Simplebridge] [%n] [%l] %v");
logger()->info("Creating Simplebridge instance");

addFdb(conf.getFdb());
addPortsList(conf.getPorts());

timestamp_update_thread_ = std::thread(&Simplebridge::updateTimestampTimer, this);
}

Simplebridge::~Simplebridge() {
// we are destroying this service, prepare for it.
quitAndJoin();
Cube::dismount();
}

void Simplebridge::quitAndJoin() {
quit_thread_ = true;
timestamp_update_thread_.join();
}

void Simplebridge::updateTimestampTimer() {
do {
sleep(1);
updateTimestamp();
} while (!quit_thread_);
}

/*
* This method is in charge of updating the timestamp table
* that is used in the dataplane to avoid calling the bpf_ktime helper
* that introduces a non-negligible overhead to the eBPF program.
*/
void Simplebridge::updateTimestamp() {
try {
// get timestamp from system
struct timespec now_timespec;
clock_gettime(CLOCK_MONOTONIC, &now_timespec);
auto timestamp_table = get_array_table<uint32_t>("timestamp");
timestamp_table.set(0, now_timespec.tv_sec);
} catch (...) {
logger()->error("Error while updating the timestamp table");
}
}

void Simplebridge::update(const SimplebridgeJsonObject &conf) {
//This method updates all the object/parameter in Simplebridge object specified in the conf JsonObject.
//You can modify this implementation.
Expand Down Expand Up @@ -141,4 +175,3 @@ void Simplebridge::reloadCodeWithAgingtime(uint32_t aging_time) {




8 changes: 8 additions & 0 deletions src/services/pcn-simplebridge/src/Simplebridge.h
Expand Up @@ -25,6 +25,7 @@
#include "polycube/services/utils.h"

#include <spdlog/spdlog.h>
#include <thread>

#include "Fdb.h"
#include "Ports.h"
Expand Down Expand Up @@ -96,6 +97,13 @@ class Simplebridge : public polycube::service::Cube<Ports>, public SimplebridgeI
std::unordered_map<std::string, Ports> ports_;
std::shared_ptr<Fdb> fdb_ = nullptr;

void updateTimestamp();
void updateTimestampTimer();
void quitAndJoin();

std::thread timestamp_update_thread_;
std::atomic<bool> quit_thread_;

void flood_packet(Port &port, PacketInMetadata &md, const std::vector<uint8_t> &packet);
std::mutex ports_mutex_;
};
Expand Down
26 changes: 14 additions & 12 deletions src/services/pcn-simplebridge/src/Simplebridge_dp.c
Expand Up @@ -32,18 +32,28 @@
#define REASON_FLOODING 0x01

struct fwd_entry {
u64 timestamp;
u32 timestamp;
u32 port;
} __attribute__((packed));
} __attribute__((packed, aligned(8)));

BPF_TABLE("hash", __be64, struct fwd_entry, fwdtable, 1024);
BPF_TABLE("array", int, uint32_t, timestamp, 1);

struct eth_hdr {
__be64 dst:48;
__be64 src:48;
__be16 proto;
} __attribute__((packed));

static __always_inline u32 time_get_sec() {
int key = 0;
u32 *ts = timestamp.lookup(&key);
if (ts)
return *ts;

return 0;
}

static __always_inline
int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
void *data = (void *)(long)ctx->data;
Expand All @@ -60,7 +70,7 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {

// LEARNING PHASE
__be64 src_key = eth->src;
u64 now = bpf_ktime_get_ns();
u32 now = time_get_sec();

struct fwd_entry e; // used to update the entry in the fdb

Expand All @@ -84,15 +94,7 @@ int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
u64 timestamp = entry->timestamp;

// Check if the entry is still valid (not too old)
// Warning: the bpf_ktime_get_ns() used before is not monotonic and it may return
// a value that is older than a previously returned value. So, we have to add
// the very strange check 'now < timestamp' to handle this special case
if (now < timestamp) {
pcn_log(ctx, LOG_TRACE, "Entry is valid (but 'now < timestamp'). FORWARDING");
goto FORWARD;
}

if ((now - timestamp) > FDB_TIMEOUT*1000000000ULL) {
if ((now - timestamp) > FDB_TIMEOUT) {
pcn_log(ctx, LOG_TRACE, "Entry is too old. FLOODING");
fwdtable.delete(&dst_mac);
goto DO_FLOODING;
Expand Down

0 comments on commit 9a58dd3

Please sign in to comment.