From bc6f42128dffd41076a6fb6630e15bd55e6930ed Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 29 Nov 2017 16:56:04 -0600 Subject: [PATCH 01/15] Divide timer into session and global timer Due to a possible bottleneck scenario, the session timer needed to be sepparated from the other timers in order to have control on the execution time of such timer. The scenario is this: while the sessions are being removed, the package translation could be delayed by the execution of the sessions removal task. This is a massive trafic scenario that could happen when there's a huge amount of expired sessions to remove. --- include/nat64/mod/stateful/bib/db.h | 3 +- include/nat64/mod/stateful/bib/pkt_queue.h | 3 +- include/nat64/mod/stateful/global_timer.h | 13 ++++ include/nat64/mod/stateful/session_timer.h | 13 ++++ include/nat64/mod/stateful/timer.h | 17 ------ mod/stateful/Kbuild | 3 +- mod/stateful/bib/db.c | 56 +++++++++++++---- mod/stateful/bib/pkt_queue.c | 11 +++- mod/stateful/{timer.c => global_timer.c} | 7 +-- mod/stateful/nf_hook.c | 19 ++++-- mod/stateful/session_timer.c | 71 ++++++++++++++++++++++ 11 files changed, 172 insertions(+), 44 deletions(-) create mode 100644 include/nat64/mod/stateful/global_timer.h create mode 100644 include/nat64/mod/stateful/session_timer.h delete mode 100644 include/nat64/mod/stateful/timer.h rename mod/stateful/{timer.c => global_timer.c} (87%) create mode 100644 mod/stateful/session_timer.c diff --git a/include/nat64/mod/stateful/bib/db.h b/include/nat64/mod/stateful/bib/db.h index 4d26d5c2c..fae8f569c 100644 --- a/include/nat64/mod/stateful/bib/db.h +++ b/include/nat64/mod/stateful/bib/db.h @@ -96,7 +96,8 @@ 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); +void bib_clean(struct bib *db, struct net *ns, u64 *max_session_rm, + bool *pending_rm); /* These are used by userspace request handling. */ diff --git a/include/nat64/mod/stateful/bib/pkt_queue.h b/include/nat64/mod/stateful/bib/pkt_queue.h index eed671562..a45d00610 100644 --- a/include/nat64/mod/stateful/bib/pkt_queue.h +++ b/include/nat64/mod/stateful/bib/pkt_queue.h @@ -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. */ diff --git a/include/nat64/mod/stateful/global_timer.h b/include/nat64/mod/stateful/global_timer.h new file mode 100644 index 000000000..7f1ead025 --- /dev/null +++ b/include/nat64/mod/stateful/global_timer.h @@ -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 */ diff --git a/include/nat64/mod/stateful/session_timer.h b/include/nat64/mod/stateful/session_timer.h new file mode 100644 index 000000000..e48ad56d4 --- /dev/null +++ b/include/nat64/mod/stateful/session_timer.h @@ -0,0 +1,13 @@ +#ifndef _JOOL_MOD_SESSION_TIMER_H +#define _JOOL_MOD_SESSION_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 session expiration. + */ + +int session_timer_init(void); +void session_timer_destroy(void); + +#endif /* _JOOL_MOD_SESSION_TIMER_H */ diff --git a/include/nat64/mod/stateful/timer.h b/include/nat64/mod/stateful/timer.h deleted file mode 100644 index 7047a9143..000000000 --- a/include/nat64/mod/stateful/timer.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _JOOL_MOD_TIMER_H -#define _JOOL_MOD_TIMER_H - -/** - * @file - * An all-purpose timer used to trigger some of Jool's events. Always runs, as - * long as Jool is modprobed. At time of writing, this induces session and - * fragment expiration. - * - * Why don't the session and fragment code manage their own timers? - * Because that's more code and I don't see how it would improve anything. - */ - -int timer_init(void); -void timer_destroy(void); - -#endif /* _JOOL_MOD_TIMER_H */ diff --git a/mod/stateful/Kbuild b/mod/stateful/Kbuild index 7c6e97853..f11610036 100644 --- a/mod/stateful/Kbuild +++ b/mod/stateful/Kbuild @@ -56,7 +56,8 @@ jool += bib/db.o jool += bib/entry.o jool += bib/pkt_queue.o -jool += timer.o +jool += global_timer.o +jool += session_timer.o jool += fragment_db.o jool += determine_incoming_tuple.o jool += filtering_and_updating.o diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index ea554d50f..437316108 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -1972,15 +1972,21 @@ 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 *max_session_rm, + u64 *sessions_rm, + bool *pending_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; + log_debug("++ TOTAL Session count = %llu", table->session_count); + list_for_each_entry_safe(session, tmp, &expirer->sessions, list_hook) { /* * "list" is sorted by expiration date, @@ -1988,22 +1994,41 @@ static void __clean(struct expire_timer *expirer, */ if (time_before(jiffies, session->update_time + expirer->timeout)) break; + + if (*pending_rm || *sessions_rm >= *max_session_rm) { + *pending_rm = 1; + log_debug("++ Session pending to rem"); + 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) +static void clean_table(struct bib_table *table, + struct net *ns, + u64 *max_session_rm, + u64 *sessions_rm, + bool *pending_rm) { LIST_HEAD(probes); LIST_HEAD(icmps); + if (*pending_rm) + return; + 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, max_session_rm, sessions_rm, + pending_rm); + __clean(&table->trans_timer, table, &probes, max_session_rm, sessions_rm, + pending_rm); + __clean(&table->syn4_timer, table, &probes, max_session_rm, sessions_rm, + pending_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, + max_session_rm, sessions_rm, pending_rm); } spin_unlock_bh(&table->lock); @@ -2014,11 +2039,16 @@ static void clean_table(struct bib_table *table, struct net *ns) /** * Forgets or downgrades (from EST to TRANS) old sessions. */ -void bib_clean(struct bib *db, struct net *ns) -{ - clean_table(&db->udp, ns); - clean_table(&db->tcp, ns); - clean_table(&db->icmp, ns); +void bib_clean(struct bib *db, + struct net *ns, + u64 *max_session_rm, + bool *pending_rm) +{ + u64 sessions_rm = 0; + clean_table(&db->udp, ns, max_session_rm, &sessions_rm, pending_rm); + clean_table(&db->tcp, ns, max_session_rm, &sessions_rm, pending_rm); + clean_table(&db->icmp, ns, max_session_rm, &sessions_rm, pending_rm); + log_debug("+ Session total removed: %llu", sessions_rm); } static struct rb_node *find_starting_point(struct bib_table *table, diff --git a/mod/stateful/bib/pkt_queue.c b/mod/stateful/bib/pkt_queue.c index e62df10a7..df91c359e 100644 --- a/mod/stateful/bib/pkt_queue.c +++ b/mod/stateful/bib/pkt_queue.c @@ -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(); @@ -211,9 +214,15 @@ 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 = 1; + log_debug("++ Session pending to rem in pktqueue"); + break; + } rm(queue, node); list_add(&node->list_hook, probes); removed++; + (*sessions_rm)++; } return removed; diff --git a/mod/stateful/timer.c b/mod/stateful/global_timer.c similarity index 87% rename from mod/stateful/timer.c rename to mod/stateful/global_timer.c index 51b6cd244..56eb17277 100644 --- a/mod/stateful/timer.c +++ b/mod/stateful/global_timer.c @@ -1,4 +1,4 @@ -#include "nat64/mod/stateful/timer.h" +#include "nat64/mod/stateful/global_timer.h" #include "nat64/mod/common/xlator.h" #include "nat64/mod/stateful/fragment_db.h" @@ -12,7 +12,6 @@ static struct timer_list timer; static int clean_state(struct xlator *jool, void *args) { fragdb_clean(jool->nat64.frag); - bib_clean(jool->nat64.bib, jool->ns); joold_clean(jool->nat64.joold, jool->nat64.bib); return 0; } @@ -26,7 +25,7 @@ static void timer_function(unsigned long arg) /** * This function should be always called *after* other init()s. */ -int timer_init(void) +int global_timer_init(void) { init_timer(&timer); timer.function = timer_function; @@ -39,7 +38,7 @@ int timer_init(void) /** * This function should be always called *before* other destroy()s. */ -void timer_destroy(void) +void global_timer_destroy(void) { del_timer_sync(&timer); } diff --git a/mod/stateful/nf_hook.c b/mod/stateful/nf_hook.c index a7f7344f6..ef67f673d 100644 --- a/mod/stateful/nf_hook.c +++ b/mod/stateful/nf_hook.c @@ -12,8 +12,9 @@ #include "nat64/mod/common/xlator.h" #include "nat64/mod/common/nl/nl_handler.h" #include "nat64/mod/stateful/fragment_db.h" +#include "nat64/mod/stateful/global_timer.h" #include "nat64/mod/stateful/joold.h" -#include "nat64/mod/stateful/timer.h" +#include "nat64/mod/stateful/session_timer.h" #include "nat64/mod/stateful/pool4/db.h" #include "nat64/mod/stateful/pool4/rfc6056.h" #include "nat64/mod/stateful/bib/db.h" @@ -135,9 +136,12 @@ static int __init jool_init(void) error = nlhandler_init(); if (error) goto nlhandler_fail; - error = timer_init(); + error = global_timer_init(); if (error) - goto timer_fail; + goto global_timer_fail; + error = session_timer_init(); + if (error) + goto session_timer_fail; error = logtime_init(); if (error) goto logtime_fail; @@ -161,8 +165,10 @@ static int __init jool_init(void) instance_fail: logtime_destroy(); logtime_fail: - timer_destroy(); -timer_fail: + session_timer_destroy(); +session_timer_fail: + global_timer_destroy(); +global_timer_fail: nlhandler_destroy(); nlhandler_fail: xlator_destroy(); @@ -183,7 +189,8 @@ static void __exit jool_exit(void) nf_unregister_hooks(nfho, ARRAY_SIZE(nfho)); logtime_destroy(); - timer_destroy(); + session_timer_destroy(); + global_timer_destroy(); nlhandler_destroy(); xlator_destroy(); rfc6056_destroy(); diff --git a/mod/stateful/session_timer.c b/mod/stateful/session_timer.c new file mode 100644 index 000000000..86dcf3940 --- /dev/null +++ b/mod/stateful/session_timer.c @@ -0,0 +1,71 @@ +#include "nat64/mod/stateful/session_timer.h" + +#include "nat64/mod/common/xlator.h" +#include "nat64/mod/stateful/bib/db.h" + +#define INITIAL_TIMER_PERIOD msecs_to_jiffies(2000) +#define MAX_SESSIONS_RM 1024 + +static struct timer_list timer; + +struct clean_params { + bool pend_rm; + u64 max_session_rm; +}; + +static struct clean_params sess_params; + +static int clean_state(struct xlator *jool, void *args) +{ + struct clean_params *params = args; + bib_clean(jool->nat64.bib, jool->ns, ¶ms->max_session_rm, + ¶ms->pend_rm); + return 0; +} + +static void update_params(unsigned long arg) +{ + if (sess_params.pend_rm) { + timer.data = msecs_to_jiffies(jiffies_to_msecs(arg) / 2); + sess_params.max_session_rm <<= 1; + log_debug("+ Session timer NEW msecs and max_sess_rm: %u - %llu", + (jiffies_to_msecs(arg) / 2), sess_params.max_session_rm); + } else { + timer.data = INITIAL_TIMER_PERIOD; + sess_params.max_session_rm = MAX_SESSIONS_RM; + log_debug("+ Session timer RESET msecs and max_sess_rm: %u - %llu", + jiffies_to_msecs(INITIAL_TIMER_PERIOD), + sess_params.max_session_rm); + } + sess_params.pend_rm = 0; +} + +static void timer_function(unsigned long arg) +{ + xlator_foreach(clean_state, &sess_params); + update_params(arg); + mod_timer(&timer, jiffies + timer.data); +} + +/** + * This function should be always called *after* other init()s. + */ +int session_timer_init(void) +{ + init_timer(&timer); + timer.function = timer_function; + timer.expires = 0; + timer.data = 0; + sess_params.pend_rm = 0; + sess_params.max_session_rm = MAX_SESSIONS_RM; + mod_timer(&timer, jiffies + INITIAL_TIMER_PERIOD); + return 0; +} + +/** + * This function should be always called *before* other destroy()s. + */ +void session_timer_destroy(void) +{ + del_timer_sync(&timer); +} From 75df0d1abb9ce7fcec5dbe03e3eb042b6a9abd74 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Fri, 1 Dec 2017 06:18:47 -0600 Subject: [PATCH 02/15] Remove debug logs --- mod/stateful/bib/db.c | 4 ---- mod/stateful/bib/pkt_queue.c | 1 - mod/stateful/session_timer.c | 5 ----- 3 files changed, 10 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 437316108..5ebf85768 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -1985,8 +1985,6 @@ static void __clean(struct expire_timer *expirer, cb.cb = expirer->decide_fate_cb; cb.arg = NULL; - log_debug("++ TOTAL Session count = %llu", table->session_count); - list_for_each_entry_safe(session, tmp, &expirer->sessions, list_hook) { /* * "list" is sorted by expiration date, @@ -1997,7 +1995,6 @@ static void __clean(struct expire_timer *expirer, if (*pending_rm || *sessions_rm >= *max_session_rm) { *pending_rm = 1; - log_debug("++ Session pending to rem"); break; } session_cnt = table->session_count; @@ -2048,7 +2045,6 @@ void bib_clean(struct bib *db, clean_table(&db->udp, ns, max_session_rm, &sessions_rm, pending_rm); clean_table(&db->tcp, ns, max_session_rm, &sessions_rm, pending_rm); clean_table(&db->icmp, ns, max_session_rm, &sessions_rm, pending_rm); - log_debug("+ Session total removed: %llu", sessions_rm); } static struct rb_node *find_starting_point(struct bib_table *table, diff --git a/mod/stateful/bib/pkt_queue.c b/mod/stateful/bib/pkt_queue.c index df91c359e..2f2a1d11f 100644 --- a/mod/stateful/bib/pkt_queue.c +++ b/mod/stateful/bib/pkt_queue.c @@ -216,7 +216,6 @@ unsigned int pktqueue_prepare_clean(struct pktqueue *queue, if (*pending_rm || *sessions_rm >= *max_session_rm) { *pending_rm = 1; - log_debug("++ Session pending to rem in pktqueue"); break; } rm(queue, node); diff --git a/mod/stateful/session_timer.c b/mod/stateful/session_timer.c index 86dcf3940..14095342c 100644 --- a/mod/stateful/session_timer.c +++ b/mod/stateful/session_timer.c @@ -28,14 +28,9 @@ static void update_params(unsigned long arg) if (sess_params.pend_rm) { timer.data = msecs_to_jiffies(jiffies_to_msecs(arg) / 2); sess_params.max_session_rm <<= 1; - log_debug("+ Session timer NEW msecs and max_sess_rm: %u - %llu", - (jiffies_to_msecs(arg) / 2), sess_params.max_session_rm); } else { timer.data = INITIAL_TIMER_PERIOD; sess_params.max_session_rm = MAX_SESSIONS_RM; - log_debug("+ Session timer RESET msecs and max_sess_rm: %u - %llu", - jiffies_to_msecs(INITIAL_TIMER_PERIOD), - sess_params.max_session_rm); } sess_params.pend_rm = 0; } From 73bc6ae8d3c582f19d92c681fc244ad0880fe526 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Thu, 7 Dec 2017 15:28:20 -0600 Subject: [PATCH 03/15] Use boolean labels instead of digits --- mod/stateful/bib/db.c | 2 +- mod/stateful/bib/pkt_queue.c | 2 +- mod/stateful/session_timer.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 5ebf85768..200fc1899 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -1994,7 +1994,7 @@ static void __clean(struct expire_timer *expirer, break; if (*pending_rm || *sessions_rm >= *max_session_rm) { - *pending_rm = 1; + *pending_rm = true; break; } session_cnt = table->session_count; diff --git a/mod/stateful/bib/pkt_queue.c b/mod/stateful/bib/pkt_queue.c index 2f2a1d11f..d41b885cd 100644 --- a/mod/stateful/bib/pkt_queue.c +++ b/mod/stateful/bib/pkt_queue.c @@ -215,7 +215,7 @@ unsigned int pktqueue_prepare_clean(struct pktqueue *queue, break; if (*pending_rm || *sessions_rm >= *max_session_rm) { - *pending_rm = 1; + *pending_rm = true; break; } rm(queue, node); diff --git a/mod/stateful/session_timer.c b/mod/stateful/session_timer.c index 14095342c..b80246f33 100644 --- a/mod/stateful/session_timer.c +++ b/mod/stateful/session_timer.c @@ -32,7 +32,7 @@ static void update_params(unsigned long arg) timer.data = INITIAL_TIMER_PERIOD; sess_params.max_session_rm = MAX_SESSIONS_RM; } - sess_params.pend_rm = 0; + sess_params.pend_rm = false; } static void timer_function(unsigned long arg) @@ -51,7 +51,7 @@ int session_timer_init(void) timer.function = timer_function; timer.expires = 0; timer.data = 0; - sess_params.pend_rm = 0; + sess_params.pend_rm = false; sess_params.max_session_rm = MAX_SESSIONS_RM; mod_timer(&timer, jiffies + INITIAL_TIMER_PERIOD); return 0; From e9ca0eefff5c43e4aed84782a58354379de87c85 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Tue, 19 Dec 2017 16:14:17 -0600 Subject: [PATCH 04/15] Delete session timer to relocate it --- include/nat64/mod/stateful/session_timer.h | 13 ----- mod/stateful/Kbuild | 1 - mod/stateful/nf_hook.c | 7 --- mod/stateful/session_timer.c | 66 ---------------------- 4 files changed, 87 deletions(-) delete mode 100644 include/nat64/mod/stateful/session_timer.h delete mode 100644 mod/stateful/session_timer.c diff --git a/include/nat64/mod/stateful/session_timer.h b/include/nat64/mod/stateful/session_timer.h deleted file mode 100644 index e48ad56d4..000000000 --- a/include/nat64/mod/stateful/session_timer.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _JOOL_MOD_SESSION_TIMER_H -#define _JOOL_MOD_SESSION_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 session expiration. - */ - -int session_timer_init(void); -void session_timer_destroy(void); - -#endif /* _JOOL_MOD_SESSION_TIMER_H */ diff --git a/mod/stateful/Kbuild b/mod/stateful/Kbuild index f11610036..acca7c6fe 100644 --- a/mod/stateful/Kbuild +++ b/mod/stateful/Kbuild @@ -57,7 +57,6 @@ jool += bib/entry.o jool += bib/pkt_queue.o jool += global_timer.o -jool += session_timer.o jool += fragment_db.o jool += determine_incoming_tuple.o jool += filtering_and_updating.o diff --git a/mod/stateful/nf_hook.c b/mod/stateful/nf_hook.c index ef67f673d..da67d82c3 100644 --- a/mod/stateful/nf_hook.c +++ b/mod/stateful/nf_hook.c @@ -14,7 +14,6 @@ #include "nat64/mod/stateful/fragment_db.h" #include "nat64/mod/stateful/global_timer.h" #include "nat64/mod/stateful/joold.h" -#include "nat64/mod/stateful/session_timer.h" #include "nat64/mod/stateful/pool4/db.h" #include "nat64/mod/stateful/pool4/rfc6056.h" #include "nat64/mod/stateful/bib/db.h" @@ -139,9 +138,6 @@ static int __init jool_init(void) error = global_timer_init(); if (error) goto global_timer_fail; - error = session_timer_init(); - if (error) - goto session_timer_fail; error = logtime_init(); if (error) goto logtime_fail; @@ -165,8 +161,6 @@ static int __init jool_init(void) instance_fail: logtime_destroy(); logtime_fail: - session_timer_destroy(); -session_timer_fail: global_timer_destroy(); global_timer_fail: nlhandler_destroy(); @@ -189,7 +183,6 @@ static void __exit jool_exit(void) nf_unregister_hooks(nfho, ARRAY_SIZE(nfho)); logtime_destroy(); - session_timer_destroy(); global_timer_destroy(); nlhandler_destroy(); xlator_destroy(); diff --git a/mod/stateful/session_timer.c b/mod/stateful/session_timer.c deleted file mode 100644 index b80246f33..000000000 --- a/mod/stateful/session_timer.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "nat64/mod/stateful/session_timer.h" - -#include "nat64/mod/common/xlator.h" -#include "nat64/mod/stateful/bib/db.h" - -#define INITIAL_TIMER_PERIOD msecs_to_jiffies(2000) -#define MAX_SESSIONS_RM 1024 - -static struct timer_list timer; - -struct clean_params { - bool pend_rm; - u64 max_session_rm; -}; - -static struct clean_params sess_params; - -static int clean_state(struct xlator *jool, void *args) -{ - struct clean_params *params = args; - bib_clean(jool->nat64.bib, jool->ns, ¶ms->max_session_rm, - ¶ms->pend_rm); - return 0; -} - -static void update_params(unsigned long arg) -{ - if (sess_params.pend_rm) { - timer.data = msecs_to_jiffies(jiffies_to_msecs(arg) / 2); - sess_params.max_session_rm <<= 1; - } else { - timer.data = INITIAL_TIMER_PERIOD; - sess_params.max_session_rm = MAX_SESSIONS_RM; - } - sess_params.pend_rm = false; -} - -static void timer_function(unsigned long arg) -{ - xlator_foreach(clean_state, &sess_params); - update_params(arg); - mod_timer(&timer, jiffies + timer.data); -} - -/** - * This function should be always called *after* other init()s. - */ -int session_timer_init(void) -{ - init_timer(&timer); - timer.function = timer_function; - timer.expires = 0; - timer.data = 0; - sess_params.pend_rm = false; - sess_params.max_session_rm = MAX_SESSIONS_RM; - mod_timer(&timer, jiffies + INITIAL_TIMER_PERIOD); - return 0; -} - -/** - * This function should be always called *before* other destroy()s. - */ -void session_timer_destroy(void) -{ - del_timer_sync(&timer); -} From 19ff3e43a7495ccc584ba26e8e54c56d00037b2f Mon Sep 17 00:00:00 2001 From: fmoreno Date: Tue, 19 Dec 2017 17:08:58 -0600 Subject: [PATCH 05/15] Add a session timer to each BIB table Now the timer is related to each table, therefore it doesn't affect other instances. The code is still a work in progress, some parameters at some functions can be removed. --- include/nat64/mod/stateful/bib/db.h | 7 +- mod/common/xlator.c | 2 +- mod/stateful/bib/db.c | 104 ++++++++++++++++++++++++++-- mod/stateful/nf_hook.c | 1 + 4 files changed, 106 insertions(+), 8 deletions(-) diff --git a/include/nat64/mod/stateful/bib/db.h b/include/nat64/mod/stateful/bib/db.h index fae8f569c..caead5e98 100644 --- a/include/nat64/mod/stateful/bib/db.h +++ b/include/nat64/mod/stateful/bib/db.h @@ -57,8 +57,9 @@ enum session_fate { int bib_init(void); void bib_destroy(void); +void bib_timers_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); @@ -96,8 +97,8 @@ 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, u64 *max_session_rm, - bool *pending_rm); +void bib_clean(struct bib *db, l4_protocol proto, struct net *ns, + u64 *max_session_rm, bool *pending_rm); /* These are used by userspace request handling. */ diff --git a/mod/common/xlator.c b/mod/common/xlator.c index 3006c86dc..520d98af3 100644 --- a/mod/common/xlator.c +++ b/mod/common/xlator.c @@ -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; diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 200fc1899..1d3a3910c 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -9,6 +9,7 @@ #include "nat64/mod/common/rbtree.h" #include "nat64/mod/common/route.h" #include "nat64/mod/common/wkmalloc.h" +#include "nat64/mod/common/xlator.h" #include "nat64/mod/stateful/bib/pkt_queue.h" /* @@ -105,6 +106,20 @@ struct expire_timer { fate_cb decide_fate_cb; }; +struct curr_inst { + struct bib *db; + struct net *ns; +}; + +struct session_timer { + struct timer_list timer; + struct curr_inst instance_ref; + unsigned long run_period_jiff; + bool pend_rm; + u64 max_session_rm; + l4_protocol proto; +}; + struct bib_table { /** Indexes the entries using their IPv6 identifiers. */ struct rb_root tree6; @@ -164,6 +179,9 @@ struct bib_table { * This is NULL in UDP/ICMP. */ struct pktqueue *pkt_queue; + + /** Drops expired sessions */ + struct session_timer sess_timer; }; struct bib { @@ -185,6 +203,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; @@ -290,6 +311,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", @@ -315,6 +341,19 @@ void bib_destroy(void) kmem_cache_destroy(session_cache); } +void bib_timers_destroy(void) +{ + struct xlator jool; + int error; + error = xlator_find_current(&jool); + if (!error) { + destroy_session_timer(&jool.nat64.bib->udp.sess_timer.timer); + destroy_session_timer(&jool.nat64.bib->tcp.sess_timer.timer); + destroy_session_timer(&jool.nat64.bib->icmp.sess_timer.timer); + xlator_put(&jool); + } +} + static enum session_fate just_die(struct session_entry *session, void *arg) { return FATE_RM; @@ -331,6 +370,59 @@ static void init_expirer(struct expire_timer *expirer, expirer->decide_fate_cb = fate_cb; } +static void clean_state(struct session_timer *sess_timer) +{ + bib_clean(sess_timer->instance_ref.db, sess_timer->proto, + sess_timer->instance_ref.ns, &sess_timer->max_session_rm, + &sess_timer->pend_rm); +} + +static void update_timer(struct session_timer *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)(sess_timer); +} + +static void timer_function(unsigned long arg) +{ + struct session_timer *sess_timer = (struct session_timer *)arg; + clean_state(sess_timer); + update_timer(sess_timer); + mod_timer(&sess_timer->timer, jiffies + sess_timer->run_period_jiff); +} + +static void init_session_timer(struct bib *db, + struct net *ns, + struct bib_table *table, + l4_protocol proto) +{ + struct session_timer *sess_timer = &table->sess_timer; + struct timer_list *timer = &sess_timer->timer; + struct curr_inst inst_data; + inst_data.db = db; + inst_data.ns = ns; + + init_timer(timer); + timer->function = timer_function; + timer->expires = 0; + timer->data = (unsigned long)(sess_timer); + + 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->proto = proto; + sess_timer->instance_ref = inst_data; + mod_timer(timer, jiffies + RM_SESSION_TIMER_INIT); +} + static void init_table(struct bib_table *table, unsigned long est_timeout, unsigned long trans_timeout, @@ -357,7 +449,7 @@ static void init_table(struct bib_table *table, table->pkt_queue = NULL; } -struct bib *bib_create(void) +struct bib *bib_create(struct net *ns) { struct bib *db; @@ -381,6 +473,10 @@ struct bib *bib_create(void) */ db->icmp.drop_by_addr = false; + init_session_timer(db, ns, &db->udp, L4PROTO_UDP); + init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); + init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); + kref_init(&db->refs); return db; @@ -2037,14 +2133,14 @@ static void clean_table(struct bib_table *table, * Forgets or downgrades (from EST to TRANS) old sessions. */ void bib_clean(struct bib *db, + l4_protocol proto, struct net *ns, u64 *max_session_rm, bool *pending_rm) { u64 sessions_rm = 0; - clean_table(&db->udp, ns, max_session_rm, &sessions_rm, pending_rm); - clean_table(&db->tcp, ns, max_session_rm, &sessions_rm, pending_rm); - clean_table(&db->icmp, ns, max_session_rm, &sessions_rm, pending_rm); + struct bib_table *table = get_table(db, proto); + clean_table(table, ns, max_session_rm, &sessions_rm, pending_rm); } static struct rb_node *find_starting_point(struct bib_table *table, diff --git a/mod/stateful/nf_hook.c b/mod/stateful/nf_hook.c index da67d82c3..ee4f2650a 100644 --- a/mod/stateful/nf_hook.c +++ b/mod/stateful/nf_hook.c @@ -183,6 +183,7 @@ static void __exit jool_exit(void) nf_unregister_hooks(nfho, ARRAY_SIZE(nfho)); logtime_destroy(); + bib_timers_destroy(); global_timer_destroy(); nlhandler_destroy(); xlator_destroy(); From 3c7ab57cbd1fb68c3c61d26d9601e548bbf23898 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Tue, 19 Dec 2017 17:58:25 -0600 Subject: [PATCH 06/15] Remove useless parameters --- include/nat64/mod/stateful/bib/db.h | 3 +-- mod/stateful/bib/db.c | 41 ++++++++++------------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/include/nat64/mod/stateful/bib/db.h b/include/nat64/mod/stateful/bib/db.h index caead5e98..27e38fb1a 100644 --- a/include/nat64/mod/stateful/bib/db.h +++ b/include/nat64/mod/stateful/bib/db.h @@ -97,8 +97,7 @@ 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, l4_protocol proto, struct net *ns, - u64 *max_session_rm, bool *pending_rm); +void bib_clean(struct bib *db, l4_protocol proto, struct net *ns); /* These are used by userspace request handling. */ diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 1d3a3910c..d199cc9a7 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -373,8 +373,7 @@ static void init_expirer(struct expire_timer *expirer, static void clean_state(struct session_timer *sess_timer) { bib_clean(sess_timer->instance_ref.db, sess_timer->proto, - sess_timer->instance_ref.ns, &sess_timer->max_session_rm, - &sess_timer->pend_rm); + sess_timer->instance_ref.ns); } static void update_timer(struct session_timer *sess_timer) @@ -2069,9 +2068,7 @@ int bib_add_session(struct bib *db, static void __clean(struct expire_timer *expirer, struct bib_table *table, struct list_head *probes, - u64 *max_session_rm, - u64 *sessions_rm, - bool *pending_rm) + u64 *sessions_rm) { struct tabled_session *session; struct tabled_session *tmp; @@ -2089,8 +2086,9 @@ static void __clean(struct expire_timer *expirer, if (time_before(jiffies, session->update_time + expirer->timeout)) break; - if (*pending_rm || *sessions_rm >= *max_session_rm) { - *pending_rm = true; + 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; @@ -2099,29 +2097,21 @@ static void __clean(struct expire_timer *expirer, }; } -static void clean_table(struct bib_table *table, - struct net *ns, - u64 *max_session_rm, - u64 *sessions_rm, - bool *pending_rm) +static void clean_table(struct bib_table *table, struct net *ns) { LIST_HEAD(probes); LIST_HEAD(icmps); - - if (*pending_rm) - return; + u64 sessions_rm = 0; spin_lock_bh(&table->lock); - __clean(&table->est_timer, table, &probes, max_session_rm, sessions_rm, - pending_rm); - __clean(&table->trans_timer, table, &probes, max_session_rm, sessions_rm, - pending_rm); - __clean(&table->syn4_timer, table, &probes, max_session_rm, sessions_rm, - pending_rm); + __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, - max_session_rm, sessions_rm, pending_rm); + &table->sess_timer.max_session_rm, &sessions_rm, + &table->sess_timer.pend_rm); } spin_unlock_bh(&table->lock); @@ -2134,13 +2124,10 @@ static void clean_table(struct bib_table *table, */ void bib_clean(struct bib *db, l4_protocol proto, - struct net *ns, - u64 *max_session_rm, - bool *pending_rm) + struct net *ns) { - u64 sessions_rm = 0; struct bib_table *table = get_table(db, proto); - clean_table(table, ns, max_session_rm, &sessions_rm, pending_rm); + clean_table(table, ns); } static struct rb_node *find_starting_point(struct bib_table *table, From 8c4e5b3929aa4b75e71048041c314cebf8c95e72 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 20 Dec 2017 10:47:36 -0600 Subject: [PATCH 07/15] Receive timer's initial config as parameter --- mod/stateful/bib/db.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index d199cc9a7..bf6b6d62b 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -401,7 +401,9 @@ static void timer_function(unsigned long arg) static void init_session_timer(struct bib *db, struct net *ns, struct bib_table *table, - l4_protocol proto) + l4_protocol proto, + u64 max_sessions_rm, + unsigned long run_period_jiffies) { struct session_timer *sess_timer = &table->sess_timer; struct timer_list *timer = &sess_timer->timer; @@ -415,11 +417,11 @@ static void init_session_timer(struct bib *db, timer->data = (unsigned long)(sess_timer); 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->max_session_rm = max_sessions_rm; + sess_timer->run_period_jiff = run_period_jiffies; sess_timer->proto = proto; sess_timer->instance_ref = inst_data; - mod_timer(timer, jiffies + RM_SESSION_TIMER_INIT); + mod_timer(timer, jiffies + run_period_jiffies); } static void init_table(struct bib_table *table, @@ -472,9 +474,12 @@ struct bib *bib_create(struct net *ns) */ db->icmp.drop_by_addr = false; - init_session_timer(db, ns, &db->udp, L4PROTO_UDP); - init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); - init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); + init_session_timer(db, ns, &db->udp, L4PROTO_UDP, RM_SESSION_MAX_INIT, + RM_SESSION_TIMER_INIT); + init_session_timer(db, ns, &db->tcp, L4PROTO_TCP, RM_SESSION_MAX_INIT, + RM_SESSION_TIMER_INIT); + init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP, RM_SESSION_MAX_INIT, + RM_SESSION_TIMER_INIT); kref_init(&db->refs); From 4685e69d5f8db9594b30d1010964051f76334bb4 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 20 Dec 2017 12:48:34 -0600 Subject: [PATCH 08/15] Fix wrong calls to "bib_create" --- mod/stateless/impersonator.c | 2 +- test/unit/bibdb/bibdb_test.c | 2 +- test/unit/bibtable/bibtable_test.c | 2 +- test/unit/sessiondb/sessiondb_test.c | 2 +- test/unit/sessiontable/sessiontable_test.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/stateless/impersonator.c b/mod/stateless/impersonator.c index b2585a56a..71bc08cb0 100644 --- a/mod/stateless/impersonator.c +++ b/mod/stateless/impersonator.c @@ -160,7 +160,7 @@ bool pool4db_contains(struct pool4 *pool, struct net *ns, return false; } -struct bib *bib_create(void) +struct bib *bib_create(struct net *ns) { fail(__func__); return NULL; diff --git a/test/unit/bibdb/bibdb_test.c b/test/unit/bibdb/bibdb_test.c index 0ed58a1c8..a63ad74ef 100644 --- a/test/unit/bibdb/bibdb_test.c +++ b/test/unit/bibdb/bibdb_test.c @@ -210,7 +210,7 @@ static bool init(void) { if (bib_init()) return false; - db = bib_create(); + db = bib_create(NULL); if (!db) bib_destroy(); return db; diff --git a/test/unit/bibtable/bibtable_test.c b/test/unit/bibtable/bibtable_test.c index e76d585a4..933c2b821 100644 --- a/test/unit/bibtable/bibtable_test.c +++ b/test/unit/bibtable/bibtable_test.c @@ -161,7 +161,7 @@ static bool init(void) { if (bib_init()) return false; - db = bib_create(); + db = bib_create(NULL); if (!db) bib_destroy(); return db; diff --git a/test/unit/sessiondb/sessiondb_test.c b/test/unit/sessiondb/sessiondb_test.c index 0c8ab7a28..680ec2a39 100644 --- a/test/unit/sessiondb/sessiondb_test.c +++ b/test/unit/sessiondb/sessiondb_test.c @@ -263,7 +263,7 @@ static bool init(void) { if (bib_init()) return false; - db = bib_create(); + db = bib_create(NULL); if (!db) bib_destroy(); return db; diff --git a/test/unit/sessiontable/sessiontable_test.c b/test/unit/sessiontable/sessiontable_test.c index 5fb9eeafc..8c91d10fe 100644 --- a/test/unit/sessiontable/sessiontable_test.c +++ b/test/unit/sessiontable/sessiontable_test.c @@ -280,7 +280,7 @@ static bool init(void) { if (bib_init()) return false; - db = bib_create(); + db = bib_create(NULL); if (!db) bib_destroy(); return db; From 9ffc57a0d4c9ba5bef025945b58a21030c6d597e Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 20 Dec 2017 18:05:48 -0600 Subject: [PATCH 09/15] Fix more broken tests There are still some tests with warnings due to the "xlator" calls when the session timers are removed; I've taken this as a general warning: probably the BIB shouldn't be getting the "xlator". I'm analizing what to do, since this is probably not the best solution (to get the "xlator" from the BIB scope). --- test/unit/filtering/filtering_and_updating_test.c | 1 + test/unit/impersonator/bib.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/filtering/filtering_and_updating_test.c b/test/unit/filtering/filtering_and_updating_test.c index 6055fa91c..3f9b78d7d 100644 --- a/test/unit/filtering/filtering_and_updating_test.c +++ b/test/unit/filtering/filtering_and_updating_test.c @@ -574,6 +574,7 @@ static void end(void) { icmp64_pop(); xlator_put(&jool); + bib_timers_destroy(); xlator_destroy(); rfc6056_destroy(); bib_destroy(); diff --git a/test/unit/impersonator/bib.c b/test/unit/impersonator/bib.c index 541df5ac1..94eb7530e 100644 --- a/test/unit/impersonator/bib.c +++ b/test/unit/impersonator/bib.c @@ -65,7 +65,8 @@ void pktqueue_put_node(struct pktqueue_session *node) } 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) { return broken_unit_call(__func__); } From 1bbb13a6e0957b298e1fdcace99bb165c8196871 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 20 Dec 2017 22:16:02 -0600 Subject: [PATCH 10/15] Remove useless parameters, use constants instead --- mod/stateful/bib/db.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index bf6b6d62b..d199cc9a7 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -401,9 +401,7 @@ static void timer_function(unsigned long arg) static void init_session_timer(struct bib *db, struct net *ns, struct bib_table *table, - l4_protocol proto, - u64 max_sessions_rm, - unsigned long run_period_jiffies) + l4_protocol proto) { struct session_timer *sess_timer = &table->sess_timer; struct timer_list *timer = &sess_timer->timer; @@ -417,11 +415,11 @@ static void init_session_timer(struct bib *db, timer->data = (unsigned long)(sess_timer); sess_timer->pend_rm = false; - sess_timer->max_session_rm = max_sessions_rm; - sess_timer->run_period_jiff = run_period_jiffies; + sess_timer->max_session_rm = RM_SESSION_MAX_INIT; + sess_timer->run_period_jiff = RM_SESSION_TIMER_INIT; sess_timer->proto = proto; sess_timer->instance_ref = inst_data; - mod_timer(timer, jiffies + run_period_jiffies); + mod_timer(timer, jiffies + RM_SESSION_TIMER_INIT); } static void init_table(struct bib_table *table, @@ -474,12 +472,9 @@ struct bib *bib_create(struct net *ns) */ db->icmp.drop_by_addr = false; - init_session_timer(db, ns, &db->udp, L4PROTO_UDP, RM_SESSION_MAX_INIT, - RM_SESSION_TIMER_INIT); - init_session_timer(db, ns, &db->tcp, L4PROTO_TCP, RM_SESSION_MAX_INIT, - RM_SESSION_TIMER_INIT); - init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP, RM_SESSION_MAX_INIT, - RM_SESSION_TIMER_INIT); + init_session_timer(db, ns, &db->udp, L4PROTO_UDP); + init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); + init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); kref_init(&db->refs); From 6fdca2cfa1be832b287946988d99fe8684ff2db9 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 20 Dec 2017 23:04:32 -0600 Subject: [PATCH 11/15] Declare bib_clean as static function and relocate code to use it --- include/nat64/mod/stateful/bib/db.h | 1 - mod/stateful/bib/db.c | 219 ++++++++++++++-------------- 2 files changed, 107 insertions(+), 113 deletions(-) diff --git a/include/nat64/mod/stateful/bib/db.h b/include/nat64/mod/stateful/bib/db.h index 27e38fb1a..03c125b1a 100644 --- a/include/nat64/mod/stateful/bib/db.h +++ b/include/nat64/mod/stateful/bib/db.h @@ -97,7 +97,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, l4_protocol proto, struct net *ns); /* These are used by userspace request handling. */ diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index d199cc9a7..3a9efa475 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -370,117 +370,6 @@ static void init_expirer(struct expire_timer *expirer, expirer->decide_fate_cb = fate_cb; } -static void clean_state(struct session_timer *sess_timer) -{ - bib_clean(sess_timer->instance_ref.db, sess_timer->proto, - sess_timer->instance_ref.ns); -} - -static void update_timer(struct session_timer *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)(sess_timer); -} - -static void timer_function(unsigned long arg) -{ - struct session_timer *sess_timer = (struct session_timer *)arg; - clean_state(sess_timer); - update_timer(sess_timer); - mod_timer(&sess_timer->timer, jiffies + sess_timer->run_period_jiff); -} - -static void init_session_timer(struct bib *db, - struct net *ns, - struct bib_table *table, - l4_protocol proto) -{ - struct session_timer *sess_timer = &table->sess_timer; - struct timer_list *timer = &sess_timer->timer; - struct curr_inst inst_data; - inst_data.db = db; - inst_data.ns = ns; - - init_timer(timer); - timer->function = timer_function; - timer->expires = 0; - timer->data = (unsigned long)(sess_timer); - - 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->proto = proto; - sess_timer->instance_ref = inst_data; - 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) -{ - 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(db, ns, &db->udp, L4PROTO_UDP); - init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); - init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); - - kref_init(&db->refs); - - return db; -} - void bib_get(struct bib *db) { kref_get(&db->refs); @@ -2122,7 +2011,7 @@ static void clean_table(struct bib_table *table, struct net *ns) /** * Forgets or downgrades (from EST to TRANS) old sessions. */ -void bib_clean(struct bib *db, +static void bib_clean(struct bib *db, l4_protocol proto, struct net *ns) { @@ -2130,6 +2019,112 @@ void bib_clean(struct bib *db, clean_table(table, ns); } +static void update_timer(struct session_timer *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)(sess_timer); +} + +static void timer_function(unsigned long arg) +{ + struct session_timer *sess_timer = (struct session_timer *)arg; + bib_clean(sess_timer->instance_ref.db, sess_timer->proto, + sess_timer->instance_ref.ns); + update_timer(sess_timer); + mod_timer(&sess_timer->timer, jiffies + sess_timer->run_period_jiff); +} + +static void init_session_timer(struct bib *db, + struct net *ns, + struct bib_table *table, + l4_protocol proto) +{ + struct session_timer *sess_timer = &table->sess_timer; + struct timer_list *timer = &sess_timer->timer; + struct curr_inst inst_data; + inst_data.db = db; + inst_data.ns = ns; + + init_timer(timer); + timer->function = timer_function; + timer->expires = 0; + timer->data = (unsigned long)(sess_timer); + + 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->proto = proto; + sess_timer->instance_ref = inst_data; + 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) +{ + 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(db, ns, &db->udp, L4PROTO_UDP); + init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); + init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); + + kref_init(&db->refs); + + return db; +} + static struct rb_node *find_starting_point(struct bib_table *table, const struct ipv4_transport_addr *offset, bool include_offset) From 12ccf87d1f9987b1913dcaa2ad604944c9d7cad7 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 3 Jan 2018 16:06:39 -0600 Subject: [PATCH 12/15] Destroy session timers when releasing BIB --- include/nat64/mod/stateful/bib/db.h | 1 - mod/stateful/bib/db.c | 18 ++++-------------- mod/stateful/nf_hook.c | 1 - .../filtering/filtering_and_updating_test.c | 1 - 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/include/nat64/mod/stateful/bib/db.h b/include/nat64/mod/stateful/bib/db.h index 03c125b1a..59066017d 100644 --- a/include/nat64/mod/stateful/bib/db.h +++ b/include/nat64/mod/stateful/bib/db.h @@ -57,7 +57,6 @@ enum session_fate { int bib_init(void); void bib_destroy(void); -void bib_timers_destroy(void); struct bib *bib_create(struct net *ns); void bib_get(struct bib *db); diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 3a9efa475..87f657ab2 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -9,7 +9,6 @@ #include "nat64/mod/common/rbtree.h" #include "nat64/mod/common/route.h" #include "nat64/mod/common/wkmalloc.h" -#include "nat64/mod/common/xlator.h" #include "nat64/mod/stateful/bib/pkt_queue.h" /* @@ -341,19 +340,6 @@ void bib_destroy(void) kmem_cache_destroy(session_cache); } -void bib_timers_destroy(void) -{ - struct xlator jool; - int error; - error = xlator_find_current(&jool); - if (!error) { - destroy_session_timer(&jool.nat64.bib->udp.sess_timer.timer); - destroy_session_timer(&jool.nat64.bib->tcp.sess_timer.timer); - destroy_session_timer(&jool.nat64.bib->icmp.sess_timer.timer); - xlator_put(&jool); - } -} - static enum session_fate just_die(struct session_entry *session, void *arg) { return FATE_RM; @@ -417,6 +403,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); } diff --git a/mod/stateful/nf_hook.c b/mod/stateful/nf_hook.c index ee4f2650a..da67d82c3 100644 --- a/mod/stateful/nf_hook.c +++ b/mod/stateful/nf_hook.c @@ -183,7 +183,6 @@ static void __exit jool_exit(void) nf_unregister_hooks(nfho, ARRAY_SIZE(nfho)); logtime_destroy(); - bib_timers_destroy(); global_timer_destroy(); nlhandler_destroy(); xlator_destroy(); diff --git a/test/unit/filtering/filtering_and_updating_test.c b/test/unit/filtering/filtering_and_updating_test.c index 3f9b78d7d..6055fa91c 100644 --- a/test/unit/filtering/filtering_and_updating_test.c +++ b/test/unit/filtering/filtering_and_updating_test.c @@ -574,7 +574,6 @@ static void end(void) { icmp64_pop(); xlator_put(&jool); - bib_timers_destroy(); xlator_destroy(); rfc6056_destroy(); bib_destroy(); From 9e214c67816e90d5348a317a7d39c3f4a1296411 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Wed, 3 Jan 2018 19:51:24 -0600 Subject: [PATCH 13/15] Remove reference from timer to DB, use the BIB table instead --- mod/stateful/bib/db.c | 53 ++++++++++++------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 87f657ab2..53c2c586e 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -105,18 +105,12 @@ struct expire_timer { fate_cb decide_fate_cb; }; -struct curr_inst { - struct bib *db; - struct net *ns; -}; - struct session_timer { struct timer_list timer; - struct curr_inst instance_ref; + struct net *ns; unsigned long run_period_jiff; bool pend_rm; u64 max_session_rm; - l4_protocol proto; }; struct bib_table { @@ -1998,19 +1992,9 @@ static void clean_table(struct bib_table *table, struct net *ns) pktqueue_clean(&icmps); } -/** - * Forgets or downgrades (from EST to TRANS) old sessions. - */ -static void bib_clean(struct bib *db, - l4_protocol proto, - struct net *ns) -{ - struct bib_table *table = get_table(db, proto); - clean_table(table, ns); -} - -static void update_timer(struct session_timer *sess_timer) +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); @@ -2020,39 +2004,32 @@ static void update_timer(struct session_timer *sess_timer) sess_timer->max_session_rm = RM_SESSION_MAX_INIT; } sess_timer->pend_rm = false; - sess_timer->timer.data = (unsigned long)(sess_timer); + sess_timer->timer.data = (unsigned long)(table); } static void timer_function(unsigned long arg) { - struct session_timer *sess_timer = (struct session_timer *)arg; - bib_clean(sess_timer->instance_ref.db, sess_timer->proto, - sess_timer->instance_ref.ns); - update_timer(sess_timer); - mod_timer(&sess_timer->timer, jiffies + sess_timer->run_period_jiff); + 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 bib *db, - struct net *ns, - struct bib_table *table, - l4_protocol proto) +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; - struct curr_inst inst_data; - inst_data.db = db; - inst_data.ns = ns; init_timer(timer); timer->function = timer_function; timer->expires = 0; - timer->data = (unsigned long)(sess_timer); + 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->proto = proto; - sess_timer->instance_ref = inst_data; + sess_timer->ns = ns; mod_timer(timer, jiffies + RM_SESSION_TIMER_INIT); } @@ -2106,9 +2083,9 @@ struct bib *bib_create(struct net *ns) */ db->icmp.drop_by_addr = false; - init_session_timer(db, ns, &db->udp, L4PROTO_UDP); - init_session_timer(db, ns, &db->tcp, L4PROTO_TCP); - init_session_timer(db, ns, &db->icmp, L4PROTO_ICMP); + init_session_timer(ns, &db->udp); + init_session_timer(ns, &db->tcp); + init_session_timer(ns, &db->icmp); kref_init(&db->refs); From fb8369ce909a9ad6205c61ea2d764f1f0946eb15 Mon Sep 17 00:00:00 2001 From: fmoreno Date: Mon, 8 Jan 2018 14:24:27 -0600 Subject: [PATCH 14/15] Kill timers before the trees --- mod/stateful/bib/db.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 53c2c586e..9f5e6641e 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -387,6 +387,10 @@ static void release_bib(struct kref *refs) struct bib *db; db = container_of(refs, struct bib, refs); + destroy_session_timer(&db->udp.sess_timer.timer); + destroy_session_timer(&db->tcp.sess_timer.timer); + destroy_session_timer(&db->icmp.sess_timer.timer); + /* * The trees share the entries, so only one tree of each protocol * needs to be emptied. @@ -397,10 +401,6 @@ 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); } From 330d689e09c4b978eec440f65acbf15729daf25f Mon Sep 17 00:00:00 2001 From: jool Date: Wed, 24 Jan 2018 09:25:32 -0600 Subject: [PATCH 15/15] Merge with fake-nat64 measurement tool --- include/nat64/common/config.h | 56 ++++- include/nat64/common/xlat.h | 2 +- include/nat64/mod/common/nl/timestamp.h | 8 + include/nat64/mod/common/timestamp.h | 51 +++++ include/nat64/usr/argp/options.h | 1 + include/nat64/usr/timestamp.h | 6 + mod/common/core.c | 71 ++++-- mod/common/icmp_wrapper.c | 8 + mod/common/nl/nl_handler2.c | 4 + mod/common/nl/timestamp.c | 63 +++++ mod/common/timestamp.c | 291 ++++++++++++++++++++++++ mod/stateful/Kbuild | 2 + mod/stateful/bib/db.c | 42 +++- mod/stateful/filtering_and_updating.c | 23 +- usr/common/argp/options.c | 11 + usr/common/jool.c | 16 ++ usr/common/target/timestamp.c | 96 ++++++++ usr/stateful/Makefile.am | 3 +- usr/stateless/Makefile.am | 3 +- 19 files changed, 728 insertions(+), 29 deletions(-) create mode 100644 include/nat64/mod/common/nl/timestamp.h create mode 100644 include/nat64/mod/common/timestamp.h create mode 100644 include/nat64/usr/timestamp.h create mode 100644 mod/common/nl/timestamp.c create mode 100644 mod/common/timestamp.c create mode 100644 usr/common/target/timestamp.c diff --git a/include/nat64/common/config.h b/include/nat64/common/config.h index 194a5b6dd..cbab5c1c8 100644 --- a/include/nat64/common/config.h +++ b/include/nat64/common/config.h @@ -57,6 +57,8 @@ enum config_mode { MODE_SESSION = (1 << 4), /** The current message is talking about log times for benchmark. */ MODE_LOGTIME = (1 << 5), + /** The user requested performance status. */ + MODE_TIMESTAMPS = (1 << 12), /** The current message is talking about the JSON configuration file */ MODE_PARSE_FILE = (1 << 9), /** The current message is talking about synchronization entries.*/ @@ -85,6 +87,7 @@ char *configmode_to_string(enum config_mode mode); #define SESSION_OPS (OP_DISPLAY | OP_COUNT) #define JOOLD_OPS (OP_ADVERTISE | OP_TEST) #define LOGTIME_OPS (OP_DISPLAY) +#define TIMESTAMPS_OPS (OP_DISPLAY) #define INSTANCE_OPS (OP_ADD | OP_REMOVE) /** * @} @@ -151,10 +154,11 @@ enum parse_section { #define UPDATE_MODES (MODE_GLOBAL | MODE_POOL4 | MODE_PARSE_FILE) #define SIIT_MODES (MODE_GLOBAL | MODE_POOL6 | MODE_BLACKLIST | MODE_RFC6791 \ - | MODE_EAMT | MODE_LOGTIME | MODE_PARSE_FILE | MODE_INSTANCE) + | MODE_EAMT | MODE_LOGTIME | MODE_PARSE_FILE | MODE_INSTANCE \ + | MODE_TIMESTAMPS) #define NAT64_MODES (MODE_GLOBAL | MODE_POOL6 | MODE_POOL4 | MODE_BIB \ | MODE_SESSION | MODE_LOGTIME | MODE_PARSE_FILE \ - | MODE_INSTANCE | MODE_JOOLD) + | MODE_INSTANCE | MODE_JOOLD | MODE_TIMESTAMPS) /** * @} */ @@ -467,6 +471,54 @@ struct logtime_entry_usr { #endif +typedef enum timestamp_type { + TST64_FULL_TRANSLATION, + TST_PKT6_INIT, + + TST46_FULL_TRANSLATION, + TST_PKT4_INIT, + + TST_DIT, /* determine incoming tuple */ + TST_FAU, /* filtering and updating */ + TST_COT, /* compute outgoing tuple */ + TST_TTP, /* translating the packet */ + TST_HH, /* handling hairpinning */ + TST_SP, /* send packet */ + + TST_FAU64_VALIDATIONS, + TST_FAU46_VALIDATIONS, + TST_FAU64_MDS, /* Mask domain search */ + + TST64_SESSION_GENERIC_OLD, + TST64_SESSION_GENERIC_NEW, + TST46_SESSION_GENERIC, + TST64_SESSION_TCP_OLD, + TST64_SESSION_TCP_NEW, + TST46_SESSION_TCP, + TST_SESSION_OLD, + TST_SESSION_NEW, + TST_SESSION_TIMER, + TST_SESSION_PROBE, + TST_SESSION_MASK, + + TST_ICMP6, + TST_ICMP4, + + TST_LENGTH, +} timestamp_type; + +struct timestamps_entry_usr { + __u32 success_count; + __u32 success_min; + __u32 success_avg; + __u32 success_max; + + __u32 failure_count; + __u32 failure_min; + __u32 failure_avg; + __u32 failure_max; +}; + /** * A BIB entry, from the eyes of userspace. * diff --git a/include/nat64/common/xlat.h b/include/nat64/common/xlat.h index a80c39fc0..d1c6e299d 100644 --- a/include/nat64/common/xlat.h +++ b/include/nat64/common/xlat.h @@ -13,7 +13,7 @@ #define JOOL_VERSION_MAJOR 3 #define JOOL_VERSION_MINOR 5 #define JOOL_VERSION_REV 5 -#define JOOL_VERSION_DEV 0 +#define JOOL_VERSION_DEV 1 /** See http://stackoverflow.com/questions/195975 */ #define STR_VALUE(arg) #arg diff --git a/include/nat64/mod/common/nl/timestamp.h b/include/nat64/mod/common/nl/timestamp.h new file mode 100644 index 000000000..d6a226eb5 --- /dev/null +++ b/include/nat64/mod/common/nl/timestamp.h @@ -0,0 +1,8 @@ +#ifndef MOD_COMMON_NL_TIMESTAMP_H_ +#define MOD_COMMON_NL_TIMESTAMP_H_ + +#include + +int handle_timestamp(struct genl_info *info); + +#endif /* MOD_COMMON_NL_TIMESTAMPS_H_ */ diff --git a/include/nat64/mod/common/timestamp.h b/include/nat64/mod/common/timestamp.h new file mode 100644 index 000000000..c37cf0871 --- /dev/null +++ b/include/nat64/mod/common/timestamp.h @@ -0,0 +1,51 @@ +#ifndef INCLUDE_NAT64_MOD_COMMON_TIMESTAMP_H_ +#define INCLUDE_NAT64_MOD_COMMON_TIMESTAMP_H_ + +#include "nat64/common/config.h" + +/* + * Ehh... this should be private. Feel free to ignore it if you're reading the + * API... --U + */ +#define TS_BATCH_COUNT 1 + +#if defined(TIMESTAMP_JIFFIES) + +typedef unsigned long timestamp; +#define TIMESTAMP_DECLARE_START(name) timestamp name = jiffies +#define TIMESTAMP_DECLARE(name) timestamp name +#define TIMESTAMP_START(name) name = jiffies +#define TIMESTAMP_STOP(a, b, c) timestamp_stop(a, b, c) + +#elif defined(TIMESTAMP_TIMESPEC) + +#include +#include +#include +#include +typedef struct timespec64 timestamp; +#define TIMESTAMP_DECLARE_START(name) timestamp name; getnstimeofday64(&name) +#define TIMESTAMP_DECLARE(name) timestamp name +#define TIMESTAMP_START(name) getnstimeofday64(&name) +#define TIMESTAMP_STOP(a, b, c) timestamp_stop(a, b, c) + +#else + +#define timestamp int /* Whatevs */ +#define TIMESTAMP_DECLARE_START(name) /* Empty */ +#define TIMESTAMP_DECLARE(name) /* Empty */ +#define TIMESTAMP_START(name) /* Empty */ +#define TIMESTAMP_STOP(a, b, c) /* Empty */ + +#endif + +void timestamp_stop(timestamp ts, timestamp_type type, bool success); + +struct timestamp_foreach_func { + int (*cb)(struct timestamps_entry_usr *, void *); + void *arg; +}; + +int timestamp_foreach(struct timestamp_foreach_func *func, void *args); + +#endif /* INCLUDE_NAT64_MOD_COMMON_TIMESTAMP_H_ */ diff --git a/include/nat64/usr/argp/options.h b/include/nat64/usr/argp/options.h index 2fc6ed122..dec9542df 100644 --- a/include/nat64/usr/argp/options.h +++ b/include/nat64/usr/argp/options.h @@ -27,6 +27,7 @@ enum argp_flags { ARGP_BLACKLIST = 7000, ARGP_RFC6791 = 6791, ARGP_LOGTIME = 'l', + ARGP_TIMESTAMPS = 7003, ARGP_GLOBAL = 'g', ARGP_PARSE_FILE = 'p', ARGP_INSTANCE = 7001, diff --git a/include/nat64/usr/timestamp.h b/include/nat64/usr/timestamp.h new file mode 100644 index 000000000..20aed60b9 --- /dev/null +++ b/include/nat64/usr/timestamp.h @@ -0,0 +1,6 @@ +#ifndef INCLUDE_NAT64_USR_TIMESTAMP_H_ +#define INCLUDE_NAT64_USR_TIMESTAMP_H_ + +int timestamp_display(void); + +#endif /* INCLUDE_NAT64_USR_TIMESTAMP_H_ */ diff --git a/mod/common/core.c b/mod/common/core.c index 113a95224..4841cadfa 100644 --- a/mod/common/core.c +++ b/mod/common/core.c @@ -3,6 +3,7 @@ #include "nat64/mod/common/config.h" #include "nat64/mod/common/handling_hairpinning.h" #include "nat64/mod/common/xlator.h" +#include "nat64/mod/common/timestamp.h" #include "nat64/mod/common/translation_state.h" #include "nat64/mod/common/rfc6145/core.h" #include "nat64/mod/stateful/compute_outgoing_tuple.h" @@ -14,31 +15,40 @@ #include #include +#define EXECUTE(action, tst) ({\ + TIMESTAMP_START(timer); \ + result = action; \ + TIMESTAMP_STOP(timer, tst, result == VERDICT_CONTINUE); \ + result; \ + }) -static verdict core_common(struct xlation *state) + +static verdict core_common(struct xlation *state, bool *success) { verdict result; + TIMESTAMP_DECLARE(timer); if (xlat_is_nat64()) { - result = determine_in_tuple(state); + result = EXECUTE(determine_in_tuple(state), TST_DIT); if (result != VERDICT_CONTINUE) goto end; - result = filtering_and_updating(state); + result = EXECUTE(filtering_and_updating(state), TST_FAU); if (result != VERDICT_CONTINUE) goto end; - result = compute_out_tuple(state); + result = EXECUTE(compute_out_tuple(state), TST_COT); if (result != VERDICT_CONTINUE) goto end; } - result = translating_the_packet(state); + + result = EXECUTE(translating_the_packet(state), TST_TTP); if (result != VERDICT_CONTINUE) goto end; if (is_hairpin(state)) { - result = handling_hairpinning(state); + result = EXECUTE(handling_hairpinning(state), TST_HH); kfree_skb(state->out.skb); /* Put this inside of hh()? */ } else { - result = sendpkt_send(state); + result = EXECUTE(sendpkt_send(state), TST_SP); /* sendpkt_send() releases out's skb regardless of verdict. */ } @@ -56,6 +66,7 @@ static verdict core_common(struct xlation *state) */ kfree_skb(state->in.skb); result = VERDICT_STOLEN; + *success = true; /* Fall through. */ end: @@ -64,11 +75,24 @@ static verdict core_common(struct xlation *state) return result; } +static int init_pkt4(struct packet *pkt, struct sk_buff *skb) +{ + int error; + TIMESTAMP_DECLARE_START(timer); + + error = pkt_init_ipv4(pkt, skb); + + TIMESTAMP_STOP(timer, TST_PKT4_INIT, !error); + return error; +} + unsigned int core_4to6(struct sk_buff *skb, const struct net_device *dev) { struct xlation state; struct iphdr *hdr = ip_hdr(skb); + bool success = false; verdict result; + TIMESTAMP_DECLARE_START(timer); xlation_init(&state); @@ -83,21 +107,36 @@ unsigned int core_4to6(struct sk_buff *skb, const struct net_device *dev) log_debug("Catching IPv4 packet: %pI4->%pI4", &hdr->saddr, &hdr->daddr); /* Reminder: This function might change pointers. */ - if (pkt_init_ipv4(&state.in, skb) != 0) { + if (init_pkt4(&state.in, skb)) { xlation_put(&state); return NF_DROP; } - result = core_common(&state); + result = core_common(&state, &success); + xlation_put(&state); + TIMESTAMP_STOP(timer, TST46_FULL_TRANSLATION, success); return result; } +static int init_pkt6(struct packet *pkt, struct sk_buff *skb) +{ + int error; + TIMESTAMP_DECLARE_START(timer); + + error = pkt_init_ipv6(pkt, skb); + + TIMESTAMP_STOP(timer, TST_PKT6_INIT, !error); + return error; +} + unsigned int core_6to4(struct sk_buff *skb, const struct net_device *dev) { struct xlation state; struct ipv6hdr *hdr = ipv6_hdr(skb); + bool success = false; verdict result; + TIMESTAMP_DECLARE_START(timer); xlation_init(&state); @@ -115,7 +154,7 @@ unsigned int core_6to4(struct sk_buff *skb, const struct net_device *dev) &hdr->daddr); /* Reminder: This function might change pointers. */ - if (pkt_init_ipv6(&state.in, skb) != 0) { + if (init_pkt6(&state.in, skb)) { xlation_put(&state); return NF_DROP; } @@ -124,13 +163,15 @@ unsigned int core_6to4(struct sk_buff *skb, const struct net_device *dev) if (xlat_is_nat64()) { result = fragdb_handle(state.jool.nat64.frag, &state.in); - if (result != VERDICT_CONTINUE) - goto end; + if (result != VERDICT_CONTINUE) { + xlation_put(&state); + return result; + } } - result = core_common(&state); - /* Fall through. */ -end: + result = core_common(&state, &success); + xlation_put(&state); + TIMESTAMP_STOP(timer, TST64_FULL_TRANSLATION, success); return result; } diff --git a/mod/common/icmp_wrapper.c b/mod/common/icmp_wrapper.c index ac588f4df..8899c9b19 100644 --- a/mod/common/icmp_wrapper.c +++ b/mod/common/icmp_wrapper.c @@ -5,6 +5,7 @@ #include #include "nat64/common/types.h" #include "nat64/mod/common/route.h" +#include "nat64/mod/common/timestamp.h" static char *icmp_error_to_string(icmp_error_code error) { @@ -36,6 +37,7 @@ static void icmp64_send4(struct sk_buff *skb, icmp_error_code error, __u32 info) { int type, code; int err; + TIMESTAMP_DECLARE_START(timer); /* * I don't know why the kernel needs this nonsense, @@ -44,6 +46,7 @@ static void icmp64_send4(struct sk_buff *skb, icmp_error_code error, __u32 info) err = route4_input(skb); if (err) { log_debug("Can't send an ICMPv4 Error: %d", err); + TIMESTAMP_STOP(timer, TST_ICMP4, false); return; } @@ -77,17 +80,20 @@ static void icmp64_send4(struct sk_buff *skb, icmp_error_code error, __u32 info) code = ICMP_SR_FAILED; break; default: + TIMESTAMP_STOP(timer, TST_ICMP4, false); return; /* Not supported or needed. */ } log_debug("Sending ICMPv4 error: %s, type: %d, code: %d.", icmp_error_to_string(error), type, code); icmp_send(skb, type, code, cpu_to_be32(info)); + TIMESTAMP_STOP(timer, TST_ICMP4, true); } static void icmp64_send6(struct sk_buff *skb, icmp_error_code error, __u32 info) { int type, code; + TIMESTAMP_DECLARE_START(timer); switch (error) { case ICMPERR_ADDR_UNREACHABLE: @@ -117,6 +123,7 @@ static void icmp64_send6(struct sk_buff *skb, icmp_error_code error, __u32 info) code = 0; /* No code. */ break; default: + TIMESTAMP_STOP(timer, TST_ICMP6, false); return; /* Not supported or needed. */ } @@ -133,6 +140,7 @@ static void icmp64_send6(struct sk_buff *skb, icmp_error_code error, __u32 info) #else #warning "You're compiling in kernel 3.12. See https://github.com/NICMx/Jool/issues/90" #endif + TIMESTAMP_STOP(timer, TST_ICMP6, true); } void icmp64_send(struct packet *pkt, icmp_error_code error, __u32 info) diff --git a/mod/common/nl/nl_handler2.c b/mod/common/nl/nl_handler2.c index ebb32790a..4d76781ce 100644 --- a/mod/common/nl/nl_handler2.c +++ b/mod/common/nl/nl_handler2.c @@ -3,6 +3,7 @@ #include #include #include + #include "nat64/common/types.h" #include "nat64/mod/common/config.h" #include "nat64/mod/common/linux_version.h" @@ -20,6 +21,7 @@ #include "nat64/mod/common/nl/pool4.h" #include "nat64/mod/common/nl/pool6.h" #include "nat64/mod/common/nl/session.h" +#include "nat64/mod/common/nl/timestamp.h" static struct genl_multicast_group mc_groups[1] = { { @@ -110,6 +112,8 @@ static int multiplex_request(struct xlator *jool, struct genl_info *info) return handle_blacklist_config(jool, info); case MODE_LOGTIME: return handle_logtime_config(info); + case MODE_TIMESTAMPS: + return handle_timestamp(info); case MODE_GLOBAL: return handle_global_config(jool, info); case MODE_PARSE_FILE: diff --git a/mod/common/nl/timestamp.c b/mod/common/nl/timestamp.c new file mode 100644 index 000000000..48f6e32a3 --- /dev/null +++ b/mod/common/nl/timestamp.c @@ -0,0 +1,63 @@ +#include "nat64/mod/common/nl/timestamp.h" + +#include "nat64/common/config.h" +#include "nat64/mod/common/timestamp.h" +#include "nat64/mod/common/nl/nl_common.h" +#include "nat64/mod/common/nl/nl_core2.h" + +static int timestamp_to_userspace(struct timestamps_entry_usr *entry, void *arg) +{ + return nlbuffer_write(arg, entry, sizeof(*entry)); +} + +static int handle_global_display(struct genl_info *info) +{ + struct nlcore_buffer buffer; + struct timestamp_foreach_func func = { + .cb = timestamp_to_userspace, + .arg = &buffer, + }; + size_t msg_size; + int error; + + if (verify_superpriv()) + return nlcore_respond(info, -EPERM); + + log_debug("Sending timestamps to userspace."); + + log_info("Note: Our maximum NL message size is %zu bytes.", + nlbuffer_response_max_size()); + log_info("Each timestamp group is %zu bytes long.", + TST_LENGTH * sizeof(struct timestamps_entry_usr)); + + msg_size = TS_BATCH_COUNT * TST_LENGTH * sizeof(struct timestamps_entry_usr); + if (msg_size > nlbuffer_response_max_size()) { + log_err("The timestamps do not fit in a netlink message. More programming is required."); + return nlcore_respond(info, -EINVAL); + } + + error = nlbuffer_init_response(&buffer, info, msg_size); + if (error) + return nlcore_respond(info, error); + + error = timestamp_foreach(&func, &buffer); + error = (error >= 0) + ? nlbuffer_send(info, &buffer) + : nlcore_respond(info, error); + + nlbuffer_free(&buffer); + return error; +} + +int handle_timestamp(struct genl_info *info) +{ + struct request_hdr *hdr = get_jool_hdr(info); + + switch (be16_to_cpu(hdr->operation)) { + case OP_DISPLAY: + return handle_global_display(info); + } + + log_err("Unknown operation: %u", be16_to_cpu(hdr->operation)); + return nlcore_respond(info, -EINVAL); +} diff --git a/mod/common/timestamp.c b/mod/common/timestamp.c new file mode 100644 index 000000000..abd00b882 --- /dev/null +++ b/mod/common/timestamp.c @@ -0,0 +1,291 @@ +#include "nat64/mod/common/timestamp.h" + +#include +#include + +/* + * Note: In this context, "wrap" means as in the sense of returning to the + * beginning of a circular data structure. + */ + +struct timestamp_stats { + timestamp min; + timestamp max; + + /* These two are intended for the computation of the average later. */ + timestamp total; + unsigned int count; + + bool initialized; +}; + +struct timestamp_stat_group { + struct timestamp_stats successes; + struct timestamp_stats failures; +}; + + +#define BATCH_PERIOD (1) /* In seconds. */ + +/** + * Keep in mind that this whole thing needs to fit in a single netlink message, + * because the copy to userspace doesn't currently bother with fragmenting it. + * + * Only BATCH_COUNT batches are kept in memory. Older batches get overriden, as + * the first dimension of this is meant to be a circular array. + * (This is fine because the userspace app is meant to request this information + * often enough.) + */ +static struct timestamp_stat_group stats[TS_BATCH_COUNT][TST_LENGTH]; +/** + * Batch counter. It is the absolute total number of batches we've processed. + * (Excluding the one we're currently at.) + * + * -1 stands for "we haven't even initialized this module". + */ +static int b = -1; +/** Jiffy at which the current batch's period started. */ +static unsigned long epoch; + +static DEFINE_SPINLOCK(lock); + + +static bool timestamps_enabled(void) +{ +#if defined(TIMESTAMP_JIFFIES) || defined(TIMESTAMP_TIMESPEC) + return true; +#else + return false; +#endif +} + +static bool need_new_batch(void) +{ + if (b == -1) + return true; + + return time_after(jiffies, + epoch + msecs_to_jiffies(BATCH_PERIOD * 1000)); +} + +static int wrap(int batch) +{ + /* + * I know this could be "& 3", but I might need to tweak BATCH_COUNT + * in the future. I'm hoping gcc will realize it can optimize this. + */ + return batch % TS_BATCH_COUNT; +} + +#if defined(TIMESTAMP_JIFFIES) + +/** + * Returns the time difference between now and beginning. + */ +static timestamp compute_delta(timestamp beginning) +{ + return jiffies - beginning; +} + +/* + * lhs < rhs: return <0 + * lhs == rhs: return 0 + * lhs > rhs: return >0 + */ +static int timestamp_compare(timestamp *lhs, timestamp *rhs) +{ + return (*lhs) - (*rhs); +} + +static timestamp timestamp_add(timestamp t1, timestamp t2) +{ + return t1 + t2; +} + +#elif defined(TIMESTAMP_TIMESPEC) + +static timestamp compute_delta(timestamp beginning) +{ + timestamp now; + getnstimeofday64(&now); + return timespec64_sub(now, beginning); +} + +static int timestamp_compare(timestamp *lhs, timestamp *rhs) +{ + return timespec_compare(lhs, rhs); +} + +static timestamp timestamp_add(timestamp lhs, timestamp rhs) +{ + return timespec_add(lhs, rhs); +} + +#else + +#define compute_delta(a) 0 +#define timestamp_compare(a, b) 0 +#define timestamp_add(a, b) 0 + +#endif + +/** + * The reason why the first argument is a struct and not a pointer is because + * I'm following along with the timespec's API's idiosyncrasies. It's weird. + */ +void timestamp_stop(timestamp beginning, timestamp_type type, bool success) +{ + struct timestamp_stats *stat; + timestamp delta; + int wb; + + if (WARN(!timestamps_enabled(), "Timestamps feature disabled but someone called a timestamps function.")) + return; + + delta = compute_delta(beginning); + wb = wrap(b); + + spin_lock_bh(&lock); + + if (need_new_batch()) { + b++; + wb = wrap(b); + memset(&stats[wb], 0, sizeof(stats[wb])); + epoch = jiffies; + } + + stat = success ? &stats[wb][type].successes : &stats[wb][type].failures; + + if (!stat->initialized) { + stat->min = delta; + stat->max = delta; + stat->total = delta; + stat->count = 1; + stat->initialized = true; + spin_unlock_bh(&lock); + return; + } + + if (timestamp_compare(&delta, &stat->min) < 0) + stat->min = delta; + else if (timestamp_compare(&delta, &stat->max) > 0) + stat->max = delta; + stat->total = timestamp_add(stat->total, delta); + stat->count++; + spin_unlock_bh(&lock); +} + +#if defined(TIMESTAMP_JIFFIES) + +/** + * Not sure if this name is self-explanatory. Think of "cap" as in like a Fire + * Emblem stat "cap". + */ +static __u32 cap_u32(unsigned int number) +{ + return (number > U32_MAX) ? U32_MAX : number; +} + +static __u32 tstou32(timestamp *ts) +{ + return cap_u32(jiffies_to_msecs(*ts)); +} + +static __u32 compute_avg(struct timestamp_stats *stat) +{ + if (stat->count == 0) + return 0; + return cap_u32(jiffies_to_msecs(stat->total / stat->count)); +} + +#elif defined(TIMESTAMP_TIMESPEC) + +static __u32 cap_u32(__u64 number) +{ + return (number > U32_MAX) ? U32_MAX : number; +} + +static __u64 get_total_microseconds(timestamp *ts) +{ + __u64 micros = 0; + + micros += ((__u64)1000000) * (__u64)ts->tv_sec; + micros += ts->tv_nsec / 1000; + + return micros; +} + +/** + * AFAIK, even though timespecs have a nanosecond field, the precision is far + * lower than that due to both hardware and software constraints. + * Also, we don't have all that much room in a __u32, so I'm going to convert + * them to microseconds. + */ +static __u32 tstou32(timestamp *ts) +{ + return cap_u32(get_total_microseconds(ts)); +} + +static __u32 compute_avg(struct timestamp_stats *stat) +{ + if (stat->count == 0) + return 0; + return cap_u32(get_total_microseconds(&stat->total) / stat->count); +} + +#else + +#define tstou32(a) 0 +#define compute_avg(a) 0 + +#endif + +int timestamp_foreach(struct timestamp_foreach_func *func, void *args) +{ + struct timestamp_stats *stat; + struct timestamps_entry_usr usr; + /* + * I literally have no clue what to call these variables. + * bb is a local batch counter (on top of the global batch counter, "b") + * and the latter is just the wrapped version of bb to prevent so many + * modulos. + */ + int bb, wbb; + unsigned int s; /* Stat group counter. */ + int result = 0; + + if (!timestamps_enabled()) { + log_err("This binary was not compiled to support timestamps."); + return -EINVAL; + } + + /* + * Rrrrg. This sucks pretty hard. It risks increasing the experiment's + * averages and max's. I dunno. Try not requesting the stats too often. + */ + spin_lock_bh(&lock); + + for (bb = b; bb > b - TS_BATCH_COUNT && bb >= 0; bb--) { + wbb = wrap(bb); + for (s = 0; s < TST_LENGTH; s++) { + stat = &stats[wbb][s].successes; + usr.success_count = stat->count; + usr.success_min = tstou32(&stat->min); + usr.success_avg = compute_avg(stat); + usr.success_max = tstou32(&stat->max); + stat = &stats[wbb][s].failures; + usr.failure_count = stat->count; + usr.failure_min = tstou32(&stat->min); + usr.failure_avg = compute_avg(stat); + usr.failure_max = tstou32(&stat->max); + + result = func->cb(&usr, args); + if (result) + goto end; + } + } + +end: + spin_unlock_bh(&lock); + return result; +} diff --git a/mod/stateful/Kbuild b/mod/stateful/Kbuild index acca7c6fe..63e3b0f03 100644 --- a/mod/stateful/Kbuild +++ b/mod/stateful/Kbuild @@ -32,6 +32,7 @@ jool_common += ../common/send_packet.o jool_common += ../common/core.o jool_common += ../common/error_pool.o jool_common += ../common/wkmalloc.o +jool_common += ../common/timestamp.o jool_common += ../common/xlator.o jool_common += ../common/nl/atomic_config.o jool_common += ../common/nl/nl_handler2.o @@ -47,6 +48,7 @@ jool_common += ../common/nl/nl_common.o jool_common += ../common/nl/pool4.o jool_common += ../common/nl/pool6.o jool_common += ../common/nl/session.o +jool_common += ../common/nl/timestamp.o jool += pool4/empty.o jool += pool4/db.o diff --git a/mod/stateful/bib/db.c b/mod/stateful/bib/db.c index 9f5e6641e..d420db24f 100644 --- a/mod/stateful/bib/db.c +++ b/mod/stateful/bib/db.c @@ -8,6 +8,7 @@ #include "nat64/mod/common/linux_version.h" #include "nat64/mod/common/rbtree.h" #include "nat64/mod/common/route.h" +#include "nat64/mod/common/timestamp.h" #include "nat64/mod/common/wkmalloc.h" #include "nat64/mod/stateful/bib/pkt_queue.h" @@ -715,6 +716,8 @@ static void send_probe_packet(struct net *ns, struct session_entry *session) unsigned int l3_hdr_len = sizeof(*iph); unsigned int l4_hdr_len = sizeof(*th); + TIMESTAMP_DECLARE_START(timer); + skb = alloc_skb(LL_MAX_HEADER + l3_hdr_len + l4_hdr_len, GFP_ATOMIC); if (!skb) { log_debug("Could now allocate a probe packet."); @@ -781,9 +784,11 @@ static void send_probe_packet(struct net *ns, struct session_entry *session) goto fail; } + TIMESTAMP_STOP(timer, TST_SESSION_PROBE, true); return; fail: + TIMESTAMP_STOP(timer, TST_SESSION_PROBE, false); log_debug("A TCP connection will probably break."); } @@ -1554,6 +1559,7 @@ int bib_add6(struct bib *db, struct slot_group slots; struct bib_delete_list rm_list = { NULL }; int error; + TIMESTAMP_DECLARE_START(timer); table = get_table(db, tuple6->l4_proto); if (!table) @@ -1595,10 +1601,14 @@ int bib_add6(struct bib *db, end: spin_unlock_bh(&table->lock); - if (new.bib) + if (new.bib) { free_bib(new.bib); - if (new.session) + TIMESTAMP_STOP(timer, TST64_SESSION_GENERIC_OLD, !error); + } + if (new.session) { free_session(new.session); + TIMESTAMP_STOP(timer, TST64_SESSION_GENERIC_NEW, !error); + } commit_delete_list(&rm_list); return error; @@ -1631,6 +1641,7 @@ int bib_add4(struct bib *db, struct tree_slot session_slot; bool allow; int error = 0; + TIMESTAMP_DECLARE_START(timer); table = get_table(db, tuple4->l4_proto); if (!table) @@ -1669,6 +1680,7 @@ int bib_add4(struct bib *db, spin_unlock_bh(&table->lock); if (new) free_session(new); + TIMESTAMP_STOP(timer, TST46_SESSION_GENERIC, !error); return error; } @@ -1689,6 +1701,7 @@ verdict bib_add_tcp6(struct bib *db, struct slot_group slots; struct bib_delete_list rm_list = { NULL }; verdict verdict; + TIMESTAMP_DECLARE_START(timer); if (WARN(pkt->tuple.l4_proto != L4PROTO_TCP, "Incorrect l4 proto in TCP handler.")) return VERDICT_DROP; @@ -1734,10 +1747,16 @@ verdict bib_add_tcp6(struct bib *db, end: spin_unlock_bh(&table->lock); - if (new.bib) + if (new.bib) { free_bib(new.bib); - if (new.session) + TIMESTAMP_STOP(timer, TST64_SESSION_TCP_OLD, + verdict == VERDICT_CONTINUE); + } + if (new.session) { free_session(new.session); + TIMESTAMP_STOP(timer, TST64_SESSION_TCP_NEW, + verdict == VERDICT_CONTINUE); + } commit_delete_list(&rm_list); return verdict; @@ -1759,6 +1778,7 @@ verdict bib_add_tcp4(struct bib *db, struct tree_slot session_slot; verdict verdict; int error; + TIMESTAMP_DECLARE_START(timer); if (WARN(pkt->tuple.l4_proto != L4PROTO_TCP, "Incorrect l4 proto in TCP handler.")) return VERDICT_DROP; @@ -1853,7 +1873,7 @@ verdict bib_add_tcp4(struct bib *db, if (new) free_session(new); - + TIMESTAMP_STOP(timer, TST46_SESSION_TCP, verdict == VERDICT_CONTINUE); return verdict; too_many_pkts: @@ -1902,6 +1922,7 @@ int bib_add_session(struct bib *db, struct slot_group slots; struct bib_delete_list rm_list = { NULL }; int error; + TIMESTAMP_DECLARE_START(timer); table = get_table(db, session->proto); if (!table) @@ -1929,10 +1950,14 @@ int bib_add_session(struct bib *db, end: spin_unlock_bh(&table->lock); - if (new.bib) + if (new.bib) { free_bib(new.bib); - if (new.session) + TIMESTAMP_STOP(timer, TST_SESSION_OLD, !error); + } + if (new.session) { free_session(new.session); + TIMESTAMP_STOP(timer, TST_SESSION_NEW, !error); + } commit_delete_list(&rm_list); return error; @@ -1975,6 +2000,7 @@ static void clean_table(struct bib_table *table, struct net *ns) LIST_HEAD(probes); LIST_HEAD(icmps); u64 sessions_rm = 0; + TIMESTAMP_DECLARE_START(timer); spin_lock_bh(&table->lock); __clean(&table->est_timer, table, &probes, &sessions_rm); @@ -1990,6 +2016,8 @@ static void clean_table(struct bib_table *table, struct net *ns) post_fate(ns, &probes); pktqueue_clean(&icmps); + + TIMESTAMP_STOP(timer, TST_SESSION_TIMER, true); } static void update_timer(struct bib_table *table) diff --git a/mod/stateful/filtering_and_updating.c b/mod/stateful/filtering_and_updating.c index 3379ec08d..51c06faeb 100644 --- a/mod/stateful/filtering_and_updating.c +++ b/mod/stateful/filtering_and_updating.c @@ -7,6 +7,7 @@ #include "nat64/mod/common/rfc6052.h" #include "nat64/mod/common/stats.h" #include "nat64/mod/common/rfc6145/6to4.h" +#include "nat64/mod/common/timestamp.h" #include "nat64/mod/stateful/joold.h" #include "nat64/mod/stateful/pool4/db.h" #include "nat64/mod/stateful/bib/db.h" @@ -49,6 +50,7 @@ static void log_entries(struct bib_session *entries) { struct session_entry *session = &entries->session; + /* if (entries->bib_set) { log_debug("BIB entry: %pI6c#%u - %pI4#%u (%s)", &session->src6.l3, session->src6.l4, @@ -57,11 +59,11 @@ static void log_entries(struct bib_session *entries) } else { log_debug("BIB entry: None"); } + */ if (entries->session_set) { - log_debug("Session entry: %pI6c#%u - %pI6c#%u | %pI4#%u - %pI4#%u (%s)", + log_debug("Session entry: %pI6c#%u | %pI4#%u | %pI4#%u (%s)", &session->src6.l3, session->src6.l4, - &session->dst6.l3, session->dst6.l4, &session->src4.l3, session->src4.l4, &session->dst4.l3, session->dst4.l4, l4proto_to_string(session->proto)); @@ -136,8 +138,11 @@ static int find_mask_domain(struct xlation *state, .mark = state->in.skb->mark, }; + TIMESTAMP_DECLARE_START(timer); *masks = mask_domain_find(state->jool.nat64.pool4, &state->in.tuple, state->jool.global->cfg.nat64.f_args, &args); + TIMESTAMP_STOP(timer, TST_FAU64_MDS, masks); + if (*masks) return 0; @@ -546,42 +551,56 @@ verdict filtering_and_updating(struct xlation *state) struct packet *in = &state->in; struct ipv6hdr *hdr_ip6; verdict result = VERDICT_CONTINUE; + TIMESTAMP_DECLARE(timer); log_debug("Step 2: Filtering and Updating"); switch (pkt_l3_proto(in)) { case L3PROTO_IPV6: + TIMESTAMP_START(timer); + /* Get rid of hairpinning loops and unwanted packets. */ hdr_ip6 = pkt_ip6_hdr(in); if (pool6_contains(state->jool.pool6, &hdr_ip6->saddr)) { log_debug("Hairpinning loop. Dropping..."); inc_stats(in, IPSTATS_MIB_INADDRERRORS); + TIMESTAMP_STOP(timer, TST_FAU64_VALIDATIONS, false); return VERDICT_DROP; } if (!pool6_contains(state->jool.pool6, &hdr_ip6->daddr)) { log_debug("Packet does not belong to pool6."); + TIMESTAMP_STOP(timer, TST_FAU64_VALIDATIONS, false); return VERDICT_ACCEPT; } /* ICMP errors should not be filtered or affect the tables. */ if (pkt_is_icmp6_error(in)) { log_debug("Packet is ICMPv6 error; skipping step..."); + TIMESTAMP_STOP(timer, TST_FAU64_VALIDATIONS, true); return VERDICT_CONTINUE; } + + TIMESTAMP_STOP(timer, TST_FAU64_VALIDATIONS, true); break; case L3PROTO_IPV4: + TIMESTAMP_START(timer); + /* Get rid of unexpected packets */ if (!pool4db_contains(state->jool.nat64.pool4, state->jool.ns, in->tuple.l4_proto, &in->tuple.dst.addr4)) { log_debug("Packet does not belong to pool4."); + TIMESTAMP_STOP(timer, TST_FAU46_VALIDATIONS, false); return VERDICT_ACCEPT; } /* ICMP errors should not be filtered or affect the tables. */ if (pkt_is_icmp4_error(in)) { log_debug("Packet is ICMPv4 error; skipping step..."); + TIMESTAMP_STOP(timer, TST_FAU46_VALIDATIONS, true); return VERDICT_CONTINUE; } + + TIMESTAMP_STOP(timer, TST_FAU46_VALIDATIONS, true); break; } diff --git a/usr/common/argp/options.c b/usr/common/argp/options.c index af611d11b..3fc0d9793 100644 --- a/usr/common/argp/options.c +++ b/usr/common/argp/options.c @@ -93,6 +93,15 @@ static const struct argp_option benchmark_opt = { }; #endif +static const struct argp_option timestamps_opt = { + .name = "timestamps", + .key = ARGP_TIMESTAMPS, + .arg = NULL, + .flags = 0, + .doc = "Report performance numbers.", + .group = 0, +}; + static const struct argp_option global_opt = { .name = OPTNAME_GLOBAL, .key = ARGP_GLOBAL, @@ -601,6 +610,7 @@ static const struct argp_option *opts_siit[] = { &blacklist_opt, &pool6791_opt, &global_opt, + ×tamps_opt, #ifdef BENCHMARK &benchmark_opt, #endif @@ -644,6 +654,7 @@ static const struct argp_option *opts_nat64[] = { #ifdef BENCHMARK &benchmark_opt, #endif + ×tamps_opt, &parse_file_opt, &instance_opt, diff --git a/usr/common/jool.c b/usr/common/jool.c index b19f71690..f3d49bbaf 100644 --- a/usr/common/jool.c +++ b/usr/common/jool.c @@ -26,6 +26,7 @@ #include "nat64/usr/pool4.h" #include "nat64/usr/bib.h" #include "nat64/usr/session.h" +#include "nat64/usr/timestamp.h" #include "nat64/usr/eam.h" #include "nat64/usr/global.h" #include "nat64/usr/log_time.h" @@ -417,6 +418,9 @@ static int parse_opt(int key, char *str, struct argp_state *state) case ARGP_LOGTIME: error = update_state(args, MODE_LOGTIME, LOGTIME_OPS); break; + case ARGP_TIMESTAMPS: + error = update_state(args, MODE_TIMESTAMPS, TIMESTAMPS_OPS); + break; case ARGP_INSTANCE: error = update_state(args, MODE_INSTANCE, INSTANCE_OPS); break; @@ -994,6 +998,16 @@ static int handle_instance(struct arguments *args) } } +static int handle_timestamps(struct arguments *args) +{ + switch (args->op) { + case OP_DISPLAY: + return timestamp_display(); + default: + return unknown_op("timestamps", args->op); + } +} + static int main_wrapped(struct arguments *args) { switch (args->mode) { @@ -1020,6 +1034,8 @@ static int main_wrapped(struct arguments *args) return handle_joold(args); case MODE_INSTANCE: return handle_instance(args); + case MODE_TIMESTAMPS: + return handle_timestamps(args); } log_err("Unknown configuration mode: %u", args->mode); diff --git a/usr/common/target/timestamp.c b/usr/common/target/timestamp.c new file mode 100644 index 000000000..02bbdd4dc --- /dev/null +++ b/usr/common/target/timestamp.c @@ -0,0 +1,96 @@ +#include + +#include "nat64/usr/timestamp.h" +#include "nat64/common/config.h" +#include "nat64/usr/netlink.h" + +static void print_entry(struct timestamps_entry_usr *entries, char *prefix) +{ + if (entries->success_count == 0 && entries->failure_count == 0) + return; + + printf("%s\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\n", prefix, + entries->success_count, entries->success_min, + entries->success_avg, entries->success_max, + entries->failure_count, entries->failure_min, + entries->failure_avg, entries->failure_max); + + /* + printf("Success count: %u\n", ); + printf("Success minimum: %u\n", ); + printf("Success average: %u\n", ); + printf("Success maximum: %u\n", ); + printf("Failure count: %u\n", ); + printf("Failure minimum: %u\n", ); + printf("Failure average: %u\n", ); + printf("Failure maximum: %u\n", ); + printf("\n"); + */ +} + +static void print_batch(unsigned int index, struct timestamps_entry_usr *entry) +{ + printf("\tBatch %u\n", index); + + print_entry(entry++, "6->4: Full translations"); + print_entry(entry++, "6->4: Incoming packet validations"); + print_entry(entry++, "4->6: Full translations"); + print_entry(entry++, "4->6: Incoming packet validations"); + + print_entry(entry++, "'Determine Incoming Tuple' step"); + print_entry(entry++, "'Filtering and Updating' step"); + print_entry(entry++, "'Compute Outgoing Tuple' step"); + print_entry(entry++, "'Translating the Packet' step"); + print_entry(entry++, "'Handling Hairpinning' step"); + print_entry(entry++, "'Send packet' step"); + + print_entry(entry++, "6->4 Filtering and Updating validations"); + print_entry(entry++, "4->6 Filtering and Updating validations"); + print_entry(entry++, "Mask Domain searches"); + + print_entry(entry++, "6->4 UDP/ICMP session lookup - Found"); + print_entry(entry++, "6->4 UDP/ICMP session lookup - Created"); + print_entry(entry++, "4->6 UDP/ICMP session lookup - Found"); + print_entry(entry++, "6->4 TCP session lookup - Found"); + print_entry(entry++, "6->4 TCP session lookup - Created"); + print_entry(entry++, "4->6 TCP session lookup - Found"); + print_entry(entry++, "Generic session lookup - Found"); + print_entry(entry++, "Generic session lookup - Created"); + print_entry(entry++, "Session expiration timer"); + print_entry(entry++, "Session probing"); + print_entry(entry++, "Session mask allocation"); + + print_entry(entry++, "ICMPv6 error"); + print_entry(entry++, "ICMPv4 error"); + + printf("\n"); +} + +static int handle_display(struct jool_response *response, void *arg) +{ + struct timestamps_entry_usr *entries = response->payload; + unsigned int b, batch_count; + size_t batch_size; + + batch_size = TST_LENGTH * sizeof(*entries); + + if (response->payload_len % batch_size != 0) { + printf("Error: The kernel module responded %zu bytes, multiple of %zu expected.\n", + response->payload_len, + TST_LENGTH * sizeof(*entries)); + return -EINVAL; + } + + batch_count = response->payload_len / batch_size; + for (b = 0; b < batch_count; b++) + print_batch(b + 1, &entries[TST_LENGTH * b]); + + return 0; +} + +int timestamp_display(void) +{ + struct request_hdr hdr; + init_request_hdr(&hdr, MODE_TIMESTAMPS, OP_DISPLAY); + return netlink_request(&hdr, sizeof(hdr), handle_display, NULL); +} diff --git a/usr/stateful/Makefile.am b/usr/stateful/Makefile.am index 9f3ce9c4d..93bb13c85 100644 --- a/usr/stateful/Makefile.am +++ b/usr/stateful/Makefile.am @@ -23,7 +23,8 @@ jool_SOURCES = \ ../common/target/pool.c \ ../common/target/pool4.c \ ../common/target/pool6.c \ - ../common/target/session.c + ../common/target/session.c \ + ../common/target/timestamp.c jool_LDADD = ${LIBNLGENL3_LIBS} jool_CFLAGS = -Wall -O2 diff --git a/usr/stateless/Makefile.am b/usr/stateless/Makefile.am index 8d8ec8be4..071889f31 100644 --- a/usr/stateless/Makefile.am +++ b/usr/stateless/Makefile.am @@ -23,7 +23,8 @@ jool_siit_SOURCES = \ ../common/target/pool.c \ ../common/target/pool4.c \ ../common/target/pool6.c \ - ../common/target/session.c + ../common/target/session.c \ + ../common/target/timestamp.c jool_siit_LDADD = ${LIBNLGENL3_LIBS} jool_siit_CFLAGS = -Wall -O2