Skip to content

Commit 92acaa0

Browse files
committed
#391: schedule socket and cache work to proper CPU
1 parent 7ac9dc4 commit 92acaa0

File tree

12 files changed

+329
-489
lines changed

12 files changed

+329
-489
lines changed

linux-4.1-tfw.patch

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,24 @@ index 0000000..55049bd
553553
+#endif /* __TEMPESTA_H__ */
554554
+
555555
diff --git a/include/net/sock.h b/include/net/sock.h
556-
index ed01a01..2c29541 100644
556+
index ed01a01..5c44cb0 100644
557557
--- a/include/net/sock.h
558558
+++ b/include/net/sock.h
559-
@@ -1697,8 +1697,7 @@ unsigned long sock_i_ino(struct sock *sk);
559+
@@ -851,6 +851,13 @@ static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
560+
561+
static inline void sk_incoming_cpu_update(struct sock *sk)
562+
{
563+
+#ifdef CONFIG_SECURITY_TEMPESTA
564+
+ if (unlikely(sk->sk_incoming_cpu != raw_smp_processor_id()))
565+
+ net_warn_ratelimited("Warning: bad socket cpu locality:"
566+
+ " old_cpu=%d curr_cpu=%d\n",
567+
+ sk->sk_incoming_cpu,
568+
+ raw_smp_processor_id());
569+
+#endif
570+
sk->sk_incoming_cpu = raw_smp_processor_id();
571+
}
572+
573+
@@ -1697,8 +1704,7 @@ unsigned long sock_i_ino(struct sock *sk);
560574
static inline struct dst_entry *
561575
__sk_dst_get(struct sock *sk)
562576
{

tempesta_fw/cache.c

Lines changed: 68 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@
2020
* this program; if not, write to the Free Software Foundation, Inc., 59
2121
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2222
*/
23-
#include <asm/i387.h>
2423
#include <linux/freezer.h>
24+
#include <linux/irq_work.h>
2525
#include <linux/ipv6.h>
2626
#include <linux/kthread.h>
2727
#include <linux/tcp.h>
2828
#include <linux/topology.h>
29-
#include <linux/workqueue.h>
3029

3130
#include "tdb.h"
3231

3332
#include "tempesta_fw.h"
3433
#include "cache.h"
3534
#include "http_msg.h"
3635
#include "ss_skb.h"
36+
#include "work_queue.h"
3737

3838
#if MAX_NUMNODES > ((1 << 16) - 1)
3939
#warning "Please set CONFIG_NODES_SHIFT to less than 16"
@@ -71,14 +71,19 @@ typedef struct {
7171
#define TFW_CSTR_HDRLEN (sizeof(TfwCStr))
7272

7373
/* Work to copy response body to database. */
74-
typedef struct tfw_cache_work_t {
75-
struct work_struct work;
74+
typedef struct {
7675
TfwHttpReq *req;
7776
TfwHttpResp *resp;
7877
tfw_http_cache_cb_t action;
7978
unsigned long key;
8079
} TfwCWork;
8180

81+
typedef struct {
82+
struct tasklet_struct tasklet;
83+
struct irq_work ipi_work;
84+
TfwRBQueue wq;
85+
} TfwWorkTasklet;
86+
8287
static struct {
8388
int cache;
8489
unsigned int db_size;
@@ -114,8 +119,7 @@ static struct {
114119
} c_nodes[MAX_NUMNODES] __read_mostly;
115120

116121
static struct task_struct *cache_mgr_thr;
117-
static struct workqueue_struct *cache_wq;
118-
static struct kmem_cache *c_cache;
122+
static DEFINE_PER_CPU(TfwWorkTasklet, cache_wq);
119123

120124
/* Iterate over request URI and Host header to process request key. */
121125
#define TFW_CACHE_REQ_KEYITER(c, req, u_end, h_start, h_end) \
@@ -137,31 +141,6 @@ static struct kmem_cache *c_cache;
137141
} \
138142
for ( ; c != h_end; ++c, c = (c == u_end) ? h_start : c)
139143

140-
141-
/**
142-
* Calculates search key for the request URI and Host header.
143-
*
144-
* The function can be called from sotrirq as well as from work queue.
145-
* Softirq saves FPU context, so we can execute tfw_http_req_key_calc()
146-
* w/o explicit FPU context saving.
147-
*/
148-
static unsigned long
149-
tfw_cache_key_calc(TfwHttpReq *req)
150-
{
151-
unsigned long h;
152-
153-
if (likely(in_softirq()))
154-
return tfw_http_req_key_calc(req);
155-
156-
kernel_fpu_begin();
157-
158-
h = tfw_http_req_key_calc(req);
159-
160-
kernel_fpu_end();
161-
162-
return h;
163-
}
164-
165144
static bool
166145
tfw_cache_entry_key_eq(TDB *db, TfwHttpReq *req, TfwCacheEntry *ce)
167146
{
@@ -233,9 +212,10 @@ node_db(void)
233212

234213
/**
235214
* Get a CPU identifier from @node to schedule a work.
215+
* TODO do better CPU scheduling
236216
*/
237217
static int
238-
tfw_cache_sched_work_cpu(TfwHttpReq *req)
218+
tfw_cache_sched_cpu(TfwHttpReq *req)
239219
{
240220
return c_nodes[req->node].cpu;
241221
}
@@ -446,7 +426,7 @@ tfw_cache_add(TfwHttpResp *resp, TfwHttpReq *req)
446426
if (!cache_cfg.cache)
447427
return;
448428

449-
key = tfw_cache_key_calc(req);
429+
key = tfw_http_req_key_calc(req);
450430

451431
tot_len = sizeof(TfwCacheEntry)
452432
+ req->uri_path.len + req->h_tbl->tbl[TFW_HTTP_HDR_HOST].len
@@ -467,38 +447,29 @@ tfw_cache_add(TfwHttpResp *resp, TfwHttpReq *req)
467447
}
468448
}
469449

470-
static void
471-
tfw_cache_resp_process_node(struct work_struct *work)
472-
{
473-
TfwCWork *cw = (TfwCWork *)work;
474-
475-
cw->action(cw->req, cw->resp);
476-
477-
kmem_cache_free(c_cache, cw);
478-
}
479-
480-
void
481-
tfw_cache_resp_process(TfwHttpResp *resp, TfwHttpReq *req,
482-
tfw_http_cache_cb_t action)
450+
int
451+
tfw_cache_process(TfwHttpReq *req, TfwHttpResp *resp,
452+
tfw_http_cache_cb_t action)
483453
{
484-
TfwCWork *cw;
454+
int cpu;
455+
TfwWorkTasklet *ct;
456+
TfwCWork cw;
485457

486-
if (cache_cfg.cache != TFW_CACHE_SHARD) {
458+
if (!cache_cfg.cache) {
487459
action(req, resp);
488-
return;
460+
return 0;
489461
}
490462

491-
cw = kmem_cache_alloc(c_cache, GFP_ATOMIC);
492-
if (!cw) {
493-
action(req, resp);
494-
return;
495-
}
496-
INIT_WORK(&cw->work, tfw_cache_resp_process_node);
497-
cw->req = req;
498-
cw->resp = resp;
499-
cw->action = action;
500-
queue_work_on(tfw_cache_sched_work_cpu(req), cache_wq,
501-
(struct work_struct *)cw);
463+
cw.req = req;
464+
cw.resp = resp;
465+
cw.action = action;
466+
cw.key = tfw_http_req_key_calc(req);
467+
req->node = (cache_cfg.cache == TFW_CACHE_SHARD)
468+
? tfw_cache_key_node(cw.key)
469+
: numa_node_id();
470+
cpu = tfw_cache_sched_cpu(req);
471+
ct = &per_cpu(cache_wq, cpu);
472+
return tfw_wq_push(&ct->wq, &cw, cpu, &ct->ipi_work);
502473
}
503474

504475
static int
@@ -689,7 +660,7 @@ tfw_cache_build_resp(TfwCacheEntry *ce)
689660
}
690661

691662
static void
692-
__cache_req_process_node(TfwHttpReq *req, unsigned long key,
663+
cache_req_process_node(TfwHttpReq *req, unsigned long key,
693664
tfw_http_cache_cb_t action)
694665
{
695666
TfwCacheEntry *ce = NULL;
@@ -720,55 +691,25 @@ __cache_req_process_node(TfwHttpReq *req, unsigned long key,
720691
}
721692

722693
static void
723-
tfw_cache_req_process_node(struct work_struct *work)
694+
tfw_wq_tasklet(unsigned long data)
724695
{
725-
TfwCWork *cw = (TfwCWork *)work;
726-
727-
__cache_req_process_node(cw->req, cw->key, cw->action);
728-
729-
kmem_cache_free(c_cache, cw);
696+
TfwWorkTasklet *ct = (TfwWorkTasklet *)data;
697+
TfwCWork cw;
698+
699+
while (!tfw_wq_pop(&ct->wq, &cw)) {
700+
if (!cache_cfg.cache || cw.resp)
701+
cw.action(cw.req, cw.resp);
702+
else
703+
cache_req_process_node(cw.req, cw.key, cw.action);
704+
}
730705
}
731706

732-
/**
733-
* Process @req at node which possesses the cached data required to fulfill
734-
* the request. In worse case the request can be assembled in softirq at
735-
* one node and the cached response can be prepared at the second node.
736-
* Note that RFS + XFS are responsible for processing the same socket only
737-
* at one CPU, so response is always sent through the same CPU where a request
738-
* was received.
739-
*/
740-
void
741-
tfw_cache_req_process(TfwHttpReq *req, tfw_http_cache_cb_t action)
707+
static void
708+
tfw_cache_ipi(struct irq_work *work)
742709
{
743-
unsigned long key;
744-
745-
if (!cache_cfg.cache) {
746-
action(req, NULL);
747-
return;
748-
}
749-
750-
key = tfw_cache_key_calc(req);
751-
req->node = tfw_cache_key_node(key);
752-
753-
if (cache_cfg.cache == TFW_CACHE_REPLICA)
754-
goto process_locally;
755-
756-
if (req->node != numa_node_id()) {
757-
/* Schedule the cache entry to the right node. */
758-
TfwCWork *cw = kmem_cache_alloc(c_cache, GFP_ATOMIC);
759-
if (!cw)
760-
goto process_locally;
761-
INIT_WORK(&cw->work, tfw_cache_req_process_node);
762-
cw->req = req;
763-
cw->action = action;
764-
cw->key = key;
765-
queue_work_on(tfw_cache_sched_work_cpu(req), cache_wq,
766-
(struct work_struct *)cw);
767-
return;
768-
}
710+
TfwWorkTasklet *ct = container_of(work, TfwWorkTasklet, ipi_work);
769711

770-
process_locally:
771-
__cache_req_process_node(req, key, action);
712+
tasklet_schedule(&ct->tasklet);
772713
}
773714

774715
/**
@@ -799,15 +740,15 @@ tfw_cache_mgr(void *arg)
799740
static int
800741
tfw_cache_start(void)
801742
{
802-
int nid, r = 1;
743+
int i, r = 1;
803744

804745
if (!cache_cfg.cache)
805746
return 0;
806747

807-
for_each_node_with_cpus(nid) {
808-
c_nodes[nid].db = tdb_open(cache_cfg.db_path,
809-
cache_cfg.db_size, 0, nid);
810-
if (!c_nodes[nid].db)
748+
for_each_node_with_cpus(i) {
749+
c_nodes[i].db = tdb_open(cache_cfg.db_path,
750+
cache_cfg.db_size, 0, i);
751+
if (!c_nodes[i].db)
811752
goto close_db;
812753
}
813754

@@ -818,52 +759,40 @@ tfw_cache_start(void)
818759
goto close_db;
819760
}
820761

821-
c_cache = KMEM_CACHE(tfw_cache_work_t, 0);
822-
if (!c_cache)
823-
goto err_cache;
824-
825762
tfw_init_node_cpus();
826763

827-
/*
828-
* WQ_MEM_RECLAIM - allow the workers to do progress
829-
* in memory preasure;
830-
* WQ_UNBOUND - schedule work to particular node and
831-
* let the system scheduler to scheduler worker
832-
* among node cpus.
833-
*
834-
* TODO use tasklets and TfwWorkQueue for cache processing
835-
* Probably threading should be at TDB side...
836-
*/
837-
cache_wq = alloc_workqueue("tfw_cache_wq",
838-
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
839-
if (!cache_wq)
840-
goto err_wq;
764+
TFW_WQ_CHECKSZ(TfwCWork);
765+
for_each_online_cpu(i) {
766+
TfwWorkTasklet *ct = &per_cpu(cache_wq, i);
767+
tfw_wq_init(&ct->wq, cpu_to_node(i));
768+
init_irq_work(&ct->ipi_work, tfw_cache_ipi);
769+
tasklet_init(&ct->tasklet, tfw_wq_tasklet, (unsigned long)ct);
770+
}
841771

842772
return 0;
843-
err_wq:
844-
kmem_cache_destroy(c_cache);
845-
err_cache:
846-
kthread_stop(cache_mgr_thr);
847773
close_db:
848-
for_each_node_with_cpus(nid)
849-
tdb_close(c_nodes[nid].db);
774+
for_each_node_with_cpus(i)
775+
tdb_close(c_nodes[i].db);
850776
return r;
851777
}
852778

853779
static void
854780
tfw_cache_stop(void)
855781
{
856-
int nid;
782+
int i;
857783

858784
if (!cache_cfg.cache)
859785
return;
860786

861-
destroy_workqueue(cache_wq);
862-
kmem_cache_destroy(c_cache);
787+
for_each_online_cpu(i) {
788+
TfwWorkTasklet *ct = &per_cpu(cache_wq, i);
789+
tfw_wq_destroy(&ct->wq);
790+
tasklet_kill(&ct->tasklet);
791+
}
863792
kthread_stop(cache_mgr_thr);
864793

865-
for_each_node_with_cpus(nid)
866-
tdb_close(c_nodes[nid].db);
794+
for_each_node_with_cpus(i)
795+
tdb_close(c_nodes[i].db);
867796
}
868797

869798
static TfwCfgSpec tfw_cache_cfg_specs[] = {

tempesta_fw/cache.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
* Tempesta FW
33
*
44
* Copyright (C) 2014 NatSys Lab. ([email protected]).
5-
* Copyright (C) 2015 Tempesta Technologies, Inc.
5+
* Copyright (C) 2015-2016 Tempesta Technologies, Inc.
66
*
77
* This program is free software; you can redistribute it and/or modify it
88
* under the terms of the GNU General Public License as published by
99
* the Free Software Foundation; either version 2 of the License,
1010
* or (at your option) any later version.
1111
*
1212
* This program is distributed in the hope that it will be useful, but WITHOUT
13-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14-
* FOR A PARTICULAR PURPOSE.
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE.
1515
* See the GNU General Public License for more details.
1616
*
1717
* You should have received a copy of the GNU General Public License along with
@@ -24,8 +24,7 @@
2424
#include "http.h"
2525

2626
void tfw_cache_add(TfwHttpResp *resp, TfwHttpReq *req);
27-
void tfw_cache_req_process(TfwHttpReq *req, tfw_http_cache_cb_t action);
28-
void tfw_cache_resp_process(TfwHttpResp *resp, TfwHttpReq *req,
29-
tfw_http_cache_cb_t action);
27+
int tfw_cache_process(TfwHttpReq *req, TfwHttpResp *resp,
28+
tfw_http_cache_cb_t action);
3029

3130
#endif /* __TFW_CACHE_H__ */

0 commit comments

Comments
 (0)