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

Session timer enhancement #257

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
3 changes: 1 addition & 2 deletions include/nat64/mod/stateful/bib/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ enum session_fate {
int bib_init(void);
void bib_destroy(void);

struct bib *bib_create(void);
struct bib *bib_create(struct net *ns);
void bib_get(struct bib *db);
void bib_put(struct bib *db);

Expand Down Expand Up @@ -96,7 +96,6 @@ int bib_find(struct bib *db, struct tuple *tuple,
struct bib_session *result);
int bib_add_session(struct bib *db, struct session_entry *new,
struct collision_cb *cb);
void bib_clean(struct bib *db, struct net *ns);

/* These are used by userspace request handling. */

Expand Down
3 changes: 2 additions & 1 deletion include/nat64/mod/stateful/bib/pkt_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ void pktqueue_put_node(struct pktqueue_session *node);
* outside.
*/
unsigned int pktqueue_prepare_clean(struct pktqueue *queue,
struct list_head *probes);
struct list_head *probes, u64 *max_session_rm, u64 *sessions_rm,
bool *pending_rm);
/**
* Sends the ICMP errors contained in the @probe list.
*/
Expand Down
13 changes: 13 additions & 0 deletions include/nat64/mod/stateful/global_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef _JOOL_MOD_GLOBAL_TIMER_H
#define _JOOL_MOD_GLOBAL_TIMER_H

/**
* @file
* Timer used to trigger some of Jool's events. Always runs, as long as Jool
* is modprobed. At time of writing, this induces fragment expiration.
*/

int global_timer_init(void);
void global_timer_destroy(void);

#endif /* _JOOL_MOD_GLOBAL_TIMER_H */
17 changes: 0 additions & 17 deletions include/nat64/mod/stateful/timer.h

This file was deleted.

2 changes: 1 addition & 1 deletion mod/common/xlator.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ static int init_nat64(struct xlator *jool)
error = pool4db_init(&jool->nat64.pool4);
if (error)
goto pool4_fail;
jool->nat64.bib = bib_create();
jool->nat64.bib = bib_create(jool->ns);
if (!jool->nat64.bib) {
error = -ENOMEM;
goto bib_fail;
Expand Down
2 changes: 1 addition & 1 deletion mod/stateful/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jool += bib/db.o
jool += bib/entry.o
jool += bib/pkt_queue.o

jool += timer.o
jool += global_timer.o
jool += fragment_db.o
jool += determine_incoming_tuple.o
jool += filtering_and_updating.o
Expand Down
209 changes: 140 additions & 69 deletions mod/stateful/bib/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ struct expire_timer {
fate_cb decide_fate_cb;
};

struct session_timer {
struct timer_list timer;
struct net *ns;
unsigned long run_period_jiff;
bool pend_rm;
u64 max_session_rm;
};

struct bib_table {
/** Indexes the entries using their IPv6 identifiers. */
struct rb_root tree6;
Expand Down Expand Up @@ -164,6 +172,9 @@ struct bib_table {
* This is NULL in UDP/ICMP.
*/
struct pktqueue *pkt_queue;

/** Drops expired sessions */
struct session_timer sess_timer;
};

struct bib {
Expand All @@ -185,6 +196,9 @@ static struct kmem_cache *session_cache;
#define free_bib(bib) wkmem_cache_free("bib entry", bib_cache, bib)
#define free_session(session) wkmem_cache_free("session", session_cache, session)

#define RM_SESSION_TIMER_INIT msecs_to_jiffies(2000)
#define RM_SESSION_MAX_INIT 1024

static struct tabled_bib *bib6_entry(const struct rb_node *node)
{
return node ? rb_entry(node, struct tabled_bib, hook6) : NULL;
Expand Down Expand Up @@ -290,6 +304,11 @@ static void kill_stored_pkt(struct bib_table *table,
table->pkt_count--;
}

static void destroy_session_timer(struct timer_list *timer)
{
del_timer_sync(timer);
}

int bib_init(void)
{
bib_cache = kmem_cache_create("bib_nodes",
Expand Down Expand Up @@ -331,61 +350,6 @@ static void init_expirer(struct expire_timer *expirer,
expirer->decide_fate_cb = fate_cb;
}

static void init_table(struct bib_table *table,
unsigned long est_timeout,
unsigned long trans_timeout,
fate_cb est_cb)
{
table->tree6 = RB_ROOT;
table->tree4 = RB_ROOT;
table->log_bibs = DEFAULT_BIB_LOGGING;
table->log_sessions = DEFAULT_SESSION_LOGGING;
table->drop_by_addr = DEFAULT_ADDR_DEPENDENT_FILTERING;
table->bib_count = 0;
table->session_count = 0;
spin_lock_init(&table->lock);
init_expirer(&table->est_timer, est_timeout, SESSION_TIMER_EST, est_cb);

init_expirer(&table->trans_timer, trans_timeout, SESSION_TIMER_TRANS,
just_die);
/* TODO "just_die"? what about the stored packet? */
init_expirer(&table->syn4_timer, TCP_INCOMING_SYN, SESSION_TIMER_SYN4,
just_die);
table->pkt_count = 0;
table->pkt_limit = 0;
table->drop_v4_syn = DEFAULT_DROP_EXTERNAL_CONNECTIONS;
table->pkt_queue = NULL;
}

struct bib *bib_create(void)
{
struct bib *db;

db = wkmalloc(struct bib, GFP_KERNEL);
if (!db)
return NULL;

init_table(&db->udp, UDP_DEFAULT, 0, just_die);
init_table(&db->tcp, TCP_EST, TCP_TRANS, tcp_est_expire_cb);
init_table(&db->icmp, ICMP_DEFAULT, 0, just_die);

db->tcp.pkt_limit = DEFAULT_MAX_STORED_PKTS;
db->tcp.pkt_queue = pktqueue_create();
if (!db->tcp.pkt_queue) {
wkfree(struct bib, db);
return NULL;
}
/*
* Just in case some crazy psycho decides to change the default.
* THERE IS NO ADRESS-DEPENDENT FILTERING ON ICMP; the RFC is wrong.
*/
db->icmp.drop_by_addr = false;

kref_init(&db->refs);

return db;
}

void bib_get(struct bib *db)
{
kref_get(&db->refs);
Expand Down Expand Up @@ -433,6 +397,10 @@ static void release_bib(struct kref *refs)

pktqueue_destroy(db->tcp.pkt_queue);

destroy_session_timer(&db->udp.sess_timer.timer);
destroy_session_timer(&db->tcp.sess_timer.timer);
destroy_session_timer(&db->icmp.sess_timer.timer);

wkfree(struct bib, db);
}

Expand Down Expand Up @@ -1972,11 +1940,13 @@ int bib_add_session(struct bib *db,

static void __clean(struct expire_timer *expirer,
struct bib_table *table,
struct list_head *probes)
struct list_head *probes,
u64 *sessions_rm)
{
struct tabled_session *session;
struct tabled_session *tmp;
struct collision_cb cb;
u64 session_cnt;

cb.cb = expirer->decide_fate_cb;
cb.arg = NULL;
Expand All @@ -1988,37 +1958,138 @@ static void __clean(struct expire_timer *expirer,
*/
if (time_before(jiffies, session->update_time + expirer->timeout))
break;

if (table->sess_timer.pend_rm
|| *sessions_rm >= table->sess_timer.max_session_rm) {
table->sess_timer.pend_rm = true;
break;
}
session_cnt = table->session_count;
decide_fate(&cb, table, session, probes);
}
*sessions_rm += session_cnt - table->session_count;
};
}

static void clean_table(struct bib_table *table, struct net *ns)
{
LIST_HEAD(probes);
LIST_HEAD(icmps);
u64 sessions_rm = 0;

spin_lock_bh(&table->lock);
__clean(&table->est_timer, table, &probes);
__clean(&table->trans_timer, table, &probes);
__clean(&table->syn4_timer, table, &probes);
__clean(&table->est_timer, table, &probes, &sessions_rm);
__clean(&table->trans_timer, table, &probes, &sessions_rm);
__clean(&table->syn4_timer, table, &probes, &sessions_rm);

if (table->pkt_queue) {
table->pkt_count -= pktqueue_prepare_clean(table->pkt_queue,
&icmps);
table->pkt_count -= pktqueue_prepare_clean(table->pkt_queue, &icmps,
&table->sess_timer.max_session_rm, &sessions_rm,
&table->sess_timer.pend_rm);
}
spin_unlock_bh(&table->lock);

post_fate(ns, &probes);
pktqueue_clean(&icmps);
}

/**
* Forgets or downgrades (from EST to TRANS) old sessions.
*/
void bib_clean(struct bib *db, struct net *ns)
static void update_timer(struct bib_table *table)
{
struct session_timer *sess_timer = &table->sess_timer;
if (sess_timer->pend_rm) {
sess_timer->run_period_jiff = msecs_to_jiffies(
jiffies_to_msecs(sess_timer->run_period_jiff) >> 1);
sess_timer->max_session_rm <<= 1;
} else {
sess_timer->run_period_jiff = RM_SESSION_TIMER_INIT;
sess_timer->max_session_rm = RM_SESSION_MAX_INIT;
}
sess_timer->pend_rm = false;
sess_timer->timer.data = (unsigned long)(table);
}

static void timer_function(unsigned long arg)
{
struct bib_table *table = (struct bib_table *)arg;
clean_table(table, table->sess_timer.ns);
update_timer(table);
mod_timer(&table->sess_timer.timer,
jiffies + table->sess_timer.run_period_jiff);
}

static void init_session_timer(struct net *ns, struct bib_table *table)
{
struct session_timer *sess_timer = &table->sess_timer;
struct timer_list *timer = &sess_timer->timer;

init_timer(timer);
timer->function = timer_function;
timer->expires = 0;
timer->data = (unsigned long)(table);

sess_timer->pend_rm = false;
sess_timer->max_session_rm = RM_SESSION_MAX_INIT;
sess_timer->run_period_jiff = RM_SESSION_TIMER_INIT;
sess_timer->ns = ns;
mod_timer(timer, jiffies + RM_SESSION_TIMER_INIT);
}

static void init_table(struct bib_table *table,
unsigned long est_timeout,
unsigned long trans_timeout,
fate_cb est_cb)
{
table->tree6 = RB_ROOT;
table->tree4 = RB_ROOT;
table->log_bibs = DEFAULT_BIB_LOGGING;
table->log_sessions = DEFAULT_SESSION_LOGGING;
table->drop_by_addr = DEFAULT_ADDR_DEPENDENT_FILTERING;
table->bib_count = 0;
table->session_count = 0;
spin_lock_init(&table->lock);
init_expirer(&table->est_timer, est_timeout, SESSION_TIMER_EST, est_cb);

init_expirer(&table->trans_timer, trans_timeout, SESSION_TIMER_TRANS,
just_die);
/* TODO "just_die"? what about the stored packet? */
init_expirer(&table->syn4_timer, TCP_INCOMING_SYN, SESSION_TIMER_SYN4,
just_die);
table->pkt_count = 0;
table->pkt_limit = 0;
table->drop_v4_syn = DEFAULT_DROP_EXTERNAL_CONNECTIONS;
table->pkt_queue = NULL;
}

struct bib *bib_create(struct net *ns)
{
clean_table(&db->udp, ns);
clean_table(&db->tcp, ns);
clean_table(&db->icmp, ns);
struct bib *db;

db = wkmalloc(struct bib, GFP_KERNEL);
if (!db)
return NULL;

init_table(&db->udp, UDP_DEFAULT, 0, just_die);
init_table(&db->tcp, TCP_EST, TCP_TRANS, tcp_est_expire_cb);
init_table(&db->icmp, ICMP_DEFAULT, 0, just_die);

db->tcp.pkt_limit = DEFAULT_MAX_STORED_PKTS;
db->tcp.pkt_queue = pktqueue_create();
if (!db->tcp.pkt_queue) {
wkfree(struct bib, db);
return NULL;
}
/*
* Just in case some crazy psycho decides to change the default.
* THERE IS NO ADRESS-DEPENDENT FILTERING ON ICMP; the RFC is wrong.
*/
db->icmp.drop_by_addr = false;

init_session_timer(ns, &db->udp);
init_session_timer(ns, &db->tcp);
init_session_timer(ns, &db->icmp);

kref_init(&db->refs);

return db;
}

static struct rb_node *find_starting_point(struct bib_table *table,
Expand Down
10 changes: 9 additions & 1 deletion mod/stateful/bib/pkt_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ void pktqueue_put_node(struct pktqueue_session *node)
* @probes.
*/
unsigned int pktqueue_prepare_clean(struct pktqueue *queue,
struct list_head *probes)
struct list_head *probes,
u64 *max_session_rm,
u64 *sessions_rm,
bool *pending_rm)
{
struct pktqueue_session *node, *tmp;
const unsigned long TIMEOUT = get_timeout();
Expand All @@ -211,9 +214,14 @@ unsigned int pktqueue_prepare_clean(struct pktqueue *queue,
if (time_before(jiffies, node->update_time + TIMEOUT))
break;

if (*pending_rm || *sessions_rm >= *max_session_rm) {
*pending_rm = true;
break;
}
rm(queue, node);
list_add(&node->list_hook, probes);
removed++;
(*sessions_rm)++;
}

return removed;
Expand Down
Loading