From f9b0492887ab09a5b59e7d8a90622bdf17cec0df Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Thu, 14 Apr 2022 14:43:33 +0300 Subject: [PATCH 1/3] listeners reconfig --- fw/sock_clnt.c | 80 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/fw/sock_clnt.c b/fw/sock_clnt.c index 50c75b6df..05a3f3bf0 100644 --- a/fw/sock_clnt.c +++ b/fw/sock_clnt.c @@ -367,6 +367,7 @@ typedef struct { * stopped, and not changed in between. Therefore, no locking is required. */ static LIST_HEAD(tfw_listen_socks); +static LIST_HEAD(tfw_listen_socks_reconf); /** * Allocate a new TfwListenSock and add it to the global list of sockets. @@ -385,7 +386,7 @@ tfw_listen_sock_add(const TfwAddr *addr, int type) return -EINVAL; /* Is there such an address on the list already? */ - list_for_each_entry(ls, &tfw_listen_socks, list) { + list_for_each_entry(ls, &tfw_listen_socks_reconf, list) { if (tfw_addr_eq(addr, &ls->addr)) { T_LOG_ADDR("Duplicate listener with", addr, TFW_WITH_PORT); @@ -404,11 +405,9 @@ tfw_listen_sock_add(const TfwAddr *addr, int type) ss_proto_init(&ls->proto, &tfw_sock_tls_clnt_ss_hooks, Conn_HttpsClnt); - list_add(&ls->list, &tfw_listen_socks); + list_add(&ls->list, &tfw_listen_socks_reconf); ls->addr = *addr; - tfw_classifier_add_inport(tfw_addr_port(addr)); - return 0; } @@ -490,7 +489,7 @@ tfw_sock_check_lst(TfwServer *srv) TfwListenSock *ls; T_DBG3("Checking server....\n"); - list_for_each_entry(ls, &tfw_listen_socks, list) { + list_for_each_entry(ls, &tfw_listen_socks_reconf, list) { T_DBG3("Iterating listener\n"); if (tfw_addr_ifmatch(&srv->addr, &ls->addr)) return -EINVAL; @@ -627,21 +626,71 @@ tfw_sock_clnt_cfgend(void) static int tfw_sock_clnt_start(void) { - int r; + int r = 0; TfwListenSock *ls; + TfwListenSock *ls_reconf; + TfwListenSock *tmp; - if (tfw_runstate_is_reconfig()) - return 0; + tfw_classifier_cleanup_inport(); + list_for_each_entry(ls_reconf, &tfw_listen_socks_reconf, list) { + bool found = false; + + list_for_each_entry(ls, &tfw_listen_socks, list) { + if (tfw_addr_eq(&ls_reconf->addr, &ls->addr)) { + found = true; + break; + } + } - list_for_each_entry(ls, &tfw_listen_socks, list) { - if ((r = tfw_listen_sock_start(ls))) { - T_ERR_ADDR("can't start listening on", &ls->addr, - TFW_WITH_PORT); - goto err; + if (!found) { + ls = kzalloc(sizeof(*ls), GFP_KERNEL); + if (!ls) { + r = -ENOMEM; + goto err; + } + + ss_proto_init(&ls->proto, ls_reconf->proto.hooks, ls_reconf->proto.type); + + list_add(&ls->list, &tfw_listen_socks); + ls->addr = ls_reconf->addr; + + if ((r = tfw_listen_sock_start(ls))) { + T_ERR_ADDR("can't start listening on", &ls_reconf->addr, + TFW_WITH_PORT); + goto err; + } } + } - return 0; + list_for_each_entry_safe(ls, tmp, &tfw_listen_socks, list) { + bool found = false; + + list_for_each_entry(ls_reconf, &tfw_listen_socks_reconf, list) { + if (tfw_addr_eq(&ls_reconf->addr, &ls->addr)) { + found = true; + break; + } + } + + if (!found) { + list_del(&ls->list); + if (!ls->sk) + continue; + ss_release(ls->sk); + ls->sk = NULL; + kfree(ls); + } else { + tfw_classifier_add_inport(tfw_addr_port(&ls->addr)); + } + } + +done: + list_for_each_entry_safe(ls, tmp, &tfw_listen_socks_reconf, list) + kfree(ls); + + INIT_LIST_HEAD(&tfw_listen_socks_reconf); + return r; err: list_for_each_entry(ls, &tfw_listen_socks, list) { @@ -651,7 +700,7 @@ tfw_sock_clnt_start(void) ls->sk = NULL; } - return r; + goto done; } static void @@ -702,6 +751,7 @@ static TfwCfgSpec tfw_sock_clnt_specs[] = { .handler = tfw_cfgop_listen, .cleanup = tfw_cfgop_cleanup_sock_clnt, .allow_repeat = true, + .allow_reconfig = true, }, { .name = "keepalive_timeout", From beecd92c26056c97e5be3435d5f48f3968b7b42f Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Mon, 25 Apr 2022 19:51:13 +0300 Subject: [PATCH 2/3] binary search of listeners and bitmap of ports for classifier --- fw/http_limits.c | 21 ++++----- fw/http_limits.h | 1 + fw/sock_clnt.c | 113 +++++++++++++++++++++++++++-------------------- 3 files changed, 77 insertions(+), 58 deletions(-) diff --git a/fw/http_limits.c b/fw/http_limits.c index 69f40ade8..2726b4e4c 100644 --- a/fw/http_limits.c +++ b/fw/http_limits.c @@ -25,6 +25,7 @@ */ #include #include +#include #include "lib/fsm.h" #include "tdb.h" @@ -47,10 +48,7 @@ * ------------------------------------------------------------------------ */ -static struct { - __be16 ports[DEF_MAX_PORTS]; - unsigned int count; -} tfw_inports __read_mostly; +DECLARE_BITMAP(tfw_inports, 65536); static TfwClassifier __rcu *classifier = NULL; @@ -103,15 +101,19 @@ tfw_classify_ipv6(struct sk_buff *skb) void tfw_classifier_add_inport(__be16 port) { - BUG_ON(tfw_inports.count == DEF_MAX_PORTS - 1); + set_bit(port, tfw_inports); +} - tfw_inports.ports[tfw_inports.count++] = port; +void +tfw_classifier_remove_inport(__be16 port) +{ + clear_bit(port, tfw_inports); } void tfw_classifier_cleanup_inport(void) { - memset(&tfw_inports, 0, sizeof(tfw_inports)); + bitmap_zero(tfw_inports, 65536); } static int @@ -121,10 +123,9 @@ tfw_classify_conn_estab(struct sock *sk) unsigned short sport = tfw_addr_get_sk_sport(sk); TfwClassifier *clfr; - /* Pass the packet if it's not for us. */ - for (i = 0; i < tfw_inports.count; ++i) - if (sport == tfw_inports.ports[i]) + if (test_bit(sport, tfw_inports)) goto ours; + return TFW_PASS; ours: diff --git a/fw/http_limits.h b/fw/http_limits.h index 58e2baf51..d66d3f0b8 100644 --- a/fw/http_limits.h +++ b/fw/http_limits.h @@ -92,6 +92,7 @@ typedef struct { } TfwClassifier; void tfw_classifier_add_inport(__be16 port); +void tfw_classifier_remove_inport(__be16 port); void tfw_classifier_cleanup_inport(void); void tfw_classify_shrink(void); diff --git a/fw/sock_clnt.c b/fw/sock_clnt.c index 05a3f3bf0..4b230ee0e 100644 --- a/fw/sock_clnt.c +++ b/fw/sock_clnt.c @@ -20,6 +20,9 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include + #include "tempesta_fw.h" #include "cfg.h" #include "client.h" @@ -369,6 +372,8 @@ typedef struct { static LIST_HEAD(tfw_listen_socks); static LIST_HEAD(tfw_listen_socks_reconf); +static size_t tfw_listen_socks_sz = 0; + /** * Allocate a new TfwListenSock and add it to the global list of sockets. * Don't open a socket now, just save the configuration data. @@ -619,6 +624,20 @@ tfw_sock_clnt_cfgend(void) return 0; } +static int +tfw_listen_socks_array_cmp(const void *l, const void *r) +{ + TfwAddr *a = &(*(TfwListenSock **)l)->addr; + TfwAddr *b = &(*(TfwListenSock **)r)->addr; + int cmp = memcmp(&a->sin6_addr, &b->sin6_addr, sizeof(a->sin6_addr)); + + if (cmp) + return cmp; + else + return (a->sin6_port < b->sin6_port) ? -1 : + (a->sin6_port > b->sin6_port); +} + /** * Start listening on all existing sockets (added via "listen" configuration * entries). @@ -630,62 +649,60 @@ tfw_sock_clnt_start(void) TfwListenSock *ls; TfwListenSock *ls_reconf; TfwListenSock *tmp; - - tfw_classifier_cleanup_inport(); - list_for_each_entry(ls_reconf, &tfw_listen_socks_reconf, list) { - bool found = false; - - list_for_each_entry(ls, &tfw_listen_socks, list) { - if (tfw_addr_eq(&ls_reconf->addr, &ls->addr)) { - found = true; - break; - } - } - - if (!found) { - ls = kzalloc(sizeof(*ls), GFP_KERNEL); - if (!ls) { - r = -ENOMEM; - goto err; - } - - ss_proto_init(&ls->proto, ls_reconf->proto.hooks, ls_reconf->proto.type); - - list_add(&ls->list, &tfw_listen_socks); - ls->addr = ls_reconf->addr; - - if ((r = tfw_listen_sock_start(ls))) { - T_ERR_ADDR("can't start listening on", &ls_reconf->addr, - TFW_WITH_PORT); - goto err; - } + size_t i, listen_socks_sz = tfw_listen_socks_sz; + TfwListenSock **listen_socks_array = kmalloc(tfw_listen_socks_sz * + sizeof(listen_socks_array[0]), + GFP_KERNEL); + TfwListenSock **ls_found; + bool *toched = kzalloc(tfw_listen_socks_sz, GFP_KERNEL); + + i = 0; + list_for_each_entry(ls, &tfw_listen_socks, list) + listen_socks_array[i++] = ls; + sort(listen_socks_array, tfw_listen_socks_sz, + sizeof(listen_socks_array[0]), tfw_listen_socks_array_cmp, NULL); + + list_for_each_entry_safe(ls_reconf, tmp, &tfw_listen_socks_reconf, list) { + if (!(ls_found = bsearch(&ls_reconf, listen_socks_array, + tfw_listen_socks_sz, + sizeof(listen_socks_array[0]), + tfw_listen_socks_array_cmp))) { + list_del(&ls_reconf->list); + list_add(&ls_reconf->list, &tfw_listen_socks); + + if ((r = tfw_listen_sock_start(ls_reconf))) { + T_ERR_ADDR("can't start listening on", &ls_reconf->addr, + TFW_WITH_PORT); + goto err; + } + tfw_classifier_add_inport(tfw_addr_port(&ls_reconf->addr)); + listen_socks_sz++; + } else { + toched[ls_found - &listen_socks_array[0]] = true; } - } - list_for_each_entry_safe(ls, tmp, &tfw_listen_socks, list) { - bool found = false; + for (i = 0; i < tfw_listen_socks_sz; ++i) { + if (toched[i]) + continue; - list_for_each_entry(ls_reconf, &tfw_listen_socks_reconf, list) { - if (tfw_addr_eq(&ls_reconf->addr, &ls->addr)) { - found = true; - break; - } - } + ls = listen_socks_array[i]; + list_del(&ls->list); + if (!ls->sk) + continue; + ss_release(ls->sk); + ls->sk = NULL; + kfree(ls); - if (!found) { - list_del(&ls->list); - if (!ls->sk) - continue; - ss_release(ls->sk); - ls->sk = NULL; - kfree(ls); - } else { - tfw_classifier_add_inport(tfw_addr_port(&ls->addr)); - } + tfw_classifier_remove_inport(tfw_addr_port(&ls->addr)); + listen_socks_sz--; } + tfw_listen_socks_sz = listen_socks_sz; + done: + kfree(listen_socks_array); + list_for_each_entry_safe(ls, tmp, &tfw_listen_socks_reconf, list) kfree(ls); From 15faf90420d20ee0153c0ad1954793c86451ad25 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Wed, 27 Apr 2022 21:20:54 +0300 Subject: [PATCH 3/3] fix review comments --- fw/http_limits.c | 4 +- fw/sock_clnt.c | 104 ++++++++++++++++++++++++----------------------- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/fw/http_limits.c b/fw/http_limits.c index 2726b4e4c..2a56c839e 100644 --- a/fw/http_limits.c +++ b/fw/http_limits.c @@ -48,7 +48,7 @@ * ------------------------------------------------------------------------ */ -DECLARE_BITMAP(tfw_inports, 65536); +static DECLARE_BITMAP(tfw_inports, 65536) __read_mostly; static TfwClassifier __rcu *classifier = NULL; @@ -124,7 +124,7 @@ tfw_classify_conn_estab(struct sock *sk) TfwClassifier *clfr; if (test_bit(sport, tfw_inports)) - goto ours; + goto ours; return TFW_PASS; diff --git a/fw/sock_clnt.c b/fw/sock_clnt.c index 4b230ee0e..7d5a7d0bb 100644 --- a/fw/sock_clnt.c +++ b/fw/sock_clnt.c @@ -372,8 +372,6 @@ typedef struct { static LIST_HEAD(tfw_listen_socks); static LIST_HEAD(tfw_listen_socks_reconf); -static size_t tfw_listen_socks_sz = 0; - /** * Allocate a new TfwListenSock and add it to the global list of sockets. * Don't open a socket now, just save the configuration data. @@ -421,12 +419,12 @@ tfw_listen_sock_del_all(void) { TfwListenSock *ls, *tmp; - list_for_each_entry_safe(ls, tmp, &tfw_listen_socks, list) { + list_for_each_entry_safe(ls, tmp, &tfw_listen_socks_reconf, list) { BUG_ON(ls->sk); kfree(ls); } - INIT_LIST_HEAD(&tfw_listen_socks); + INIT_LIST_HEAD(&tfw_listen_socks_reconf); tfw_classifier_cleanup_inport(); } @@ -634,8 +632,7 @@ tfw_listen_socks_array_cmp(const void *l, const void *r) if (cmp) return cmp; else - return (a->sin6_port < b->sin6_port) ? -1 : - (a->sin6_port > b->sin6_port); + return (int)a->sin6_port - (int)b->sin6_port; } /** @@ -645,79 +642,89 @@ tfw_listen_socks_array_cmp(const void *l, const void *r) static int tfw_sock_clnt_start(void) { + static size_t tfw_listen_socks_sz = 0; + int r = 0; - TfwListenSock *ls; - TfwListenSock *ls_reconf; - TfwListenSock *tmp; + TfwListenSock *ls, *tmp; size_t i, listen_socks_sz = tfw_listen_socks_sz; - TfwListenSock **listen_socks_array = kmalloc(tfw_listen_socks_sz * - sizeof(listen_socks_array[0]), - GFP_KERNEL); - TfwListenSock **ls_found; - bool *toched = kzalloc(tfw_listen_socks_sz, GFP_KERNEL); + TfwListenSock **ls_found, **listen_socks_array = NULL; + bool *touched = NULL; + + touched = kzalloc(tfw_listen_socks_sz, GFP_KERNEL); + if (!touched) { + T_ERR("can't allocate memory\n"); + r = -ENOMEM; + goto done; + } + + listen_socks_array = kmalloc(tfw_listen_socks_sz * + sizeof(listen_socks_array[0]), GFP_KERNEL); + if (!listen_socks_array) { + T_ERR("can't allocate memory\n"); + r = -ENOMEM; + goto done; + } i = 0; list_for_each_entry(ls, &tfw_listen_socks, list) listen_socks_array[i++] = ls; sort(listen_socks_array, tfw_listen_socks_sz, - sizeof(listen_socks_array[0]), tfw_listen_socks_array_cmp, NULL); - - list_for_each_entry_safe(ls_reconf, tmp, &tfw_listen_socks_reconf, list) { - if (!(ls_found = bsearch(&ls_reconf, listen_socks_array, - tfw_listen_socks_sz, - sizeof(listen_socks_array[0]), - tfw_listen_socks_array_cmp))) { - list_del(&ls_reconf->list); - list_add(&ls_reconf->list, &tfw_listen_socks); - - if ((r = tfw_listen_sock_start(ls_reconf))) { - T_ERR_ADDR("can't start listening on", &ls_reconf->addr, - TFW_WITH_PORT); - goto err; - } - tfw_classifier_add_inport(tfw_addr_port(&ls_reconf->addr)); - listen_socks_sz++; - } else { - toched[ls_found - &listen_socks_array[0]] = true; + sizeof(listen_socks_array[0]), tfw_listen_socks_array_cmp, NULL); + + list_for_each_entry_safe(ls, tmp, &tfw_listen_socks_reconf, list) { + ls_found = bsearch(&ls, listen_socks_array, tfw_listen_socks_sz, + sizeof(listen_socks_array[0]), + tfw_listen_socks_array_cmp); + if (ls_found) { + touched[ls_found - &listen_socks_array[0]] = true; + continue; } + + list_del(&ls->list); + list_add(&ls->list, &tfw_listen_socks); + + if ((r = tfw_listen_sock_start(ls))) { + T_ERR_ADDR("can't start listening on", &ls->addr, + TFW_WITH_PORT); + goto done; + } + + tfw_classifier_add_inport(tfw_addr_port(&ls->addr)); + listen_socks_sz++; } for (i = 0; i < tfw_listen_socks_sz; ++i) { - if (toched[i]) + if (touched[i]) continue; ls = listen_socks_array[i]; + + tfw_classifier_remove_inport(tfw_addr_port(&ls->addr)); + listen_socks_sz--; + list_del(&ls->list); if (!ls->sk) continue; ss_release(ls->sk); ls->sk = NULL; kfree(ls); - - tfw_classifier_remove_inport(tfw_addr_port(&ls->addr)); - listen_socks_sz--; } tfw_listen_socks_sz = listen_socks_sz; done: kfree(listen_socks_array); + kfree(touched); + /** + * The list contains the intersection of initial tfw_listen_socks_reconf + * and initial tfw_listen_socks + */ list_for_each_entry_safe(ls, tmp, &tfw_listen_socks_reconf, list) kfree(ls); INIT_LIST_HEAD(&tfw_listen_socks_reconf); return r; - -err: - list_for_each_entry(ls, &tfw_listen_socks, list) { - if (!ls->sk) - continue; - ss_release(ls->sk); - ls->sk = NULL; - } - - goto done; } static void @@ -725,9 +732,6 @@ tfw_sock_clnt_stop(void) { TfwListenSock *ls; - if (tfw_runstate_is_reconfig()) - return; - might_sleep(); /* Stop listening sockets. */