Skip to content

Commit eac58dd

Browse files
committed
Upgrade connection to websocket and provision new connection
Signed-off-by: Aleksey Mikhaylov <[email protected]>
1 parent 94be89e commit eac58dd

12 files changed

+197
-29
lines changed

fw/connection.h

+21-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ enum {
5151
/* HTTPS */
5252
Conn_HttpsClnt = Conn_Clnt | TFW_FSM_HTTPS,
5353
Conn_HttpsSrv = Conn_Srv | TFW_FSM_HTTPS,
54+
55+
/* Websocket plain */
56+
Conn_WsClnt = Conn_HttpClnt | TFW_FSM_WS,
57+
Conn_WsSrv = Conn_HttpSrv | TFW_FSM_WS,
58+
59+
/* Websocket secure */
60+
Conn_WssClnt = Conn_HttpsClnt | TFW_FSM_WS,
61+
Conn_WssSrv = Conn_HttpsSrv | TFW_FSM_WS,
5462
};
5563

5664
#define TFW_CONN_TYPE2IDX(t) TFW_FSM_TYPE(t)
@@ -100,7 +108,7 @@ enum {
100108
struct sock *sk; \
101109
void (*destructor)(void *);
102110

103-
typedef struct TfwConn {
111+
typedef struct tfw_conn_t {
104112
TFW_CONN_COMMON;
105113
} TfwConn;
106114

@@ -199,7 +207,9 @@ enum {
199207
/* Connection is in use or at least scheduled to be established. */
200208
TFW_CONN_B_ACTIVE,
201209
/* Connection is disconnected and stopped. */
202-
TFW_CONN_B_STOPPED
210+
TFW_CONN_B_STOPPED,
211+
/* Mark connection as unavailable to schedulers */
212+
TFW_CONN_B_UNSCHED
203213
};
204214

205215
/**
@@ -297,6 +307,15 @@ tfw_srv_conn_restricted(TfwSrvConn *srv_conn)
297307
return test_bit(TFW_CONN_B_RESEND, &srv_conn->flags);
298308
}
299309

310+
/*
311+
* Connection is unavailable to scheduler and may be removed from it
312+
*/
313+
static inline bool
314+
tfw_srv_conn_unscheduled(TfwSrvConn *srv_conn)
315+
{
316+
return test_bit(TFW_CONN_B_UNSCHED, &srv_conn->flags);
317+
}
318+
300319
/*
301320
* Tell if a connection has non-idempotent requests.
302321
*/

fw/gfsm.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ enum {
8484
/* Protocols */
8585
TFW_FSM_HTTP,
8686
TFW_FSM_HTTPS,
87+
/* Not really a FSM */
88+
TFW_FSM_WS,
8789

8890
/* Security rules enforcement. */
8991
TFW_FSM_FRANG_REQ,
@@ -181,7 +183,7 @@ typedef struct {
181183
& ((TFW_GFSM_FSM_MASK << TFW_GFSM_FSM_SHIFT) \
182184
| TFW_GFSM_STATE_MASK))
183185

184-
typedef struct TfwConn TfwConn;
186+
typedef struct tfw_conn_t TfwConn;
185187
typedef int (*tfw_gfsm_handler_t)(TfwConn *conn, TfwFsmData *data);
186188

187189
void tfw_gfsm_state_init(TfwGState *st, void *obj, int st0);

fw/http.c

+40-1
Original file line numberDiff line numberDiff line change
@@ -2339,7 +2339,6 @@ static int
23392339
tfw_http_conn_init(TfwConn *conn)
23402340
{
23412341
T_DBG2("%s: conn=[%p]\n", __func__, conn);
2342-
23432342
if (TFW_CONN_TYPE(conn) & Conn_Srv) {
23442343
TfwSrvConn *srv_conn = (TfwSrvConn *)conn;
23452344
if (!list_empty(&srv_conn->fwd_queue)) {
@@ -5931,6 +5930,7 @@ tfw_http_resp_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb)
59315930
unsigned int chunks_unused, parsed;
59325931
TfwHttpReq *bad_req;
59335932
TfwHttpMsg *hmresp, *hmsib;
5933+
TfwHttpResp *resp;
59345934
TfwFsmData data_up;
59355935
bool conn_stop, filtout = false;
59365936

@@ -5953,6 +5953,7 @@ tfw_http_resp_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb)
59535953
parsed = 0;
59545954
hmsib = NULL;
59555955
hmresp = (TfwHttpMsg *)stream->msg;
5956+
resp = (TfwHttpResp *)hmresp;
59565957

59575958
r = ss_skb_process(skb, tfw_http_parse_resp, hmresp, &chunks_unused,
59585959
&parsed);
@@ -6098,6 +6099,44 @@ tfw_http_resp_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb)
60986099
r = TFW_PASS;
60996100
goto next_resp;
61006101
}
6102+
6103+
/*
6104+
* Upgrade client and server connection to websocket, remove it
6105+
* from scheduler and provision new connection.
6106+
*
6107+
* TODO #755: set existent client and server connection to Conn_Ws*
6108+
* when websocket proxing protocol will be implemented
6109+
*/
6110+
if (unlikely(test_bit(TFW_HTTP_B_CONN_UPGRADE, hmresp->flags)
6111+
&& test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hmresp->flags)
6112+
&& resp->status == 101))
6113+
{
6114+
TfwServer *srv = (TfwServer *)resp->conn->peer;
6115+
TfwSrvConn *srv_conn;
6116+
6117+
/* Cannot proceed with upgrade websocket due to error
6118+
* in creation of new http connection. While it will not be
6119+
* inherently erroneous to upgrade existing connection, but
6120+
* we would pay for it with essentially dropping connection with
6121+
* server. Better just drop upgrade request and
6122+
* reestablish connection.
6123+
*/
6124+
if (!(srv_conn = tfw_sock_srv_new_conn(srv))) {
6125+
tfw_http_conn_error_log(conn, "Can't create new "
6126+
"connection for websocket"
6127+
" upgrade response");
6128+
return TFW_BLOCK;
6129+
}
6130+
6131+
set_bit(TFW_CONN_B_UNSCHED,
6132+
&((TfwSrvConn *)hmresp->conn)->flags);
6133+
6134+
tfw_sock_srv_conn_activate(srv, srv_conn);
6135+
tfw_sock_srv_connect_try(srv_conn);
6136+
6137+
srv->sg->sched->upd_srv(srv);
6138+
}
6139+
61016140
/*
61026141
* Pass the response to cache for further processing.
61036142
* In the end, the response is sent on to the client.

fw/http_frame.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ typedef struct {
200200
unsigned char data_off;
201201
} TfwH2Ctx;
202202

203-
typedef struct TfwConn TfwConn;
203+
typedef struct tfw_conn_t TfwConn;
204204

205205
int tfw_h2_init(void);
206206
void tfw_h2_cleanup(void);

fw/http_sched_hash.c

+28
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ __is_conn_suitable(TfwSrvConn *conn, bool hmonitor)
129129
{
130130
return (hmonitor || !tfw_srv_suspended((TfwServer *)conn->peer))
131131
&& !tfw_srv_conn_restricted(conn)
132+
&& !tfw_srv_conn_unscheduled(conn)
132133
&& !tfw_srv_conn_busy(conn)
133134
&& !tfw_srv_conn_queue_full(conn)
134135
&& tfw_srv_conn_get_if_live(conn);
@@ -333,6 +334,8 @@ tfw_sched_hash_add_conns(TfwServer *srv, TfwHashConnList *cl, size_t *seed,
333334

334335
list_for_each_entry(conn, &srv->conn_list, list) {
335336
unsigned long hash;
337+
if (tfw_srv_conn_unscheduled(conn))
338+
continue;
336339
do {
337340
hash = __hash_64(srv_hash ^ *seed);
338341
*seed += seed_inc;
@@ -432,13 +435,38 @@ tfw_sched_hash_del_srv(TfwServer *srv)
432435
call_rcu(&cl->rcu, tfw_sched_hash_put_srv_data);
433436
}
434437

438+
static int
439+
tfw_sched_hash_upd_srv(TfwServer *srv)
440+
{
441+
size_t size, seed, seed_inc = 0;
442+
TfwHashConnList *cl = rcu_dereference_bh_check(srv->sched_data, 1);
443+
TfwHashConnList *cl_copy;
444+
445+
seed = get_random_long();
446+
seed_inc = get_random_int();
447+
448+
size = sizeof(TfwHashConnList) + srv->conn_n * sizeof(TfwHashConn);
449+
if (!(cl_copy = kzalloc(size, GFP_ATOMIC)))
450+
return -ENOMEM;
451+
452+
tfw_sched_hash_add_conns(srv, cl_copy, &seed, seed_inc);
453+
454+
rcu_assign_pointer(srv->sched_data, cl_copy);
455+
456+
if (cl)
457+
call_rcu(&cl->rcu, tfw_sched_hash_put_srv_data);
458+
459+
return 0;
460+
}
461+
435462
static TfwScheduler tfw_sched_hash = {
436463
.name = "hash",
437464
.list = LIST_HEAD_INIT(tfw_sched_hash.list),
438465
.add_grp = tfw_sched_hash_add_grp,
439466
.del_grp = tfw_sched_hash_del_grp,
440467
.add_srv = tfw_sched_hash_add_srv,
441468
.del_srv = tfw_sched_hash_del_srv,
469+
.upd_srv = tfw_sched_hash_upd_srv,
442470
.sched_sg_conn = tfw_sched_hash_get_sg_conn,
443471
.sched_srv_conn = tfw_sched_hash_get_srv_conn,
444472
};

fw/http_sched_ratio.c

+73-17
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030

3131
#define TFW_SCHED_RATIO_INTVL (HZ / 20) /* The timer periodicity. */
3232

33+
typedef struct {
34+
struct rcu_head rcu;
35+
size_t conn_n;
36+
TfwSrvConn *conns[0];
37+
} TfwRatioSrvConnList;
38+
3339
/**
3440
* Individual upstream server descriptor.
3541
*
@@ -38,17 +44,15 @@
3844
*
3945
* @rcu - RCU control structure.
4046
* @srv - pointer to server structure.
41-
* @conn - list of pointers to server connection structures.
47+
* @cl - pointer to list of pointers to server connection structures.
4248
* @counter - monotonic counter for choosing the next connection.
43-
* @conn_n - number of connections to server.
4449
* @seq - current sequence number for APM stats.
4550
*/
4651
typedef struct {
4752
struct rcu_head rcu;
4853
TfwServer *srv;
49-
TfwSrvConn **conn;
54+
TfwRatioSrvConnList *cl;
5055
atomic64_t counter;
51-
size_t conn_n;
5256
unsigned int seq;
5357
} TfwRatioSrvDesc;
5458

@@ -827,12 +831,15 @@ static inline TfwSrvConn *
827831
__sched_srv(TfwRatioSrvDesc *srvdesc, int skipnip, int *nipconn)
828832
{
829833
size_t ci;
834+
TfwRatioSrvConnList *cl = rcu_dereference_bh_check(srvdesc->cl, 1);
830835

831-
for (ci = 0; ci < srvdesc->conn_n; ++ci) {
836+
rcu_read_lock_bh();
837+
for (ci = 0; ci < cl->conn_n; ++ci) {
832838
unsigned long idxval = atomic64_inc_return(&srvdesc->counter);
833-
TfwSrvConn *srv_conn = srvdesc->conn[idxval % srvdesc->conn_n];
839+
TfwSrvConn *srv_conn = cl->conns[idxval % cl->conn_n];
834840

835841
if (unlikely(tfw_srv_conn_restricted(srv_conn)
842+
|| tfw_srv_conn_unscheduled(srv_conn)
836843
|| tfw_srv_conn_busy(srv_conn)
837844
|| tfw_srv_conn_queue_full(srv_conn)))
838845
continue;
@@ -841,9 +848,12 @@ __sched_srv(TfwRatioSrvDesc *srvdesc, int skipnip, int *nipconn)
841848
++(*nipconn);
842849
continue;
843850
}
844-
if (likely(tfw_srv_conn_get_if_live(srv_conn)))
851+
if (likely(tfw_srv_conn_get_if_live(srv_conn))) {
852+
rcu_read_unlock_bh();
845853
return srv_conn;
854+
}
846855
}
856+
rcu_read_unlock_bh();
847857

848858
return NULL;
849859
}
@@ -981,7 +991,7 @@ tfw_sched_ratio_cleanup(TfwRatio *ratio)
981991

982992
/* Data that is shared between pool entries. */
983993
for (si = 0; si < ratio->srv_n; ++si)
984-
kfree(ratio->srvdesc[si].conn);
994+
kfree(ratio->srvdesc[si].cl);
985995

986996
kfree(ratio->hstdata);
987997
kfree(ratio->rtodata);
@@ -1039,28 +1049,32 @@ static int
10391049
tfw_sched_ratio_srvdesc_setup_srv(TfwServer *srv, TfwRatioSrvDesc *srvdesc)
10401050
{
10411051
size_t size, ci = 0;
1042-
TfwSrvConn **conn, *srv_conn;
1052+
TfwSrvConn *srv_conn;
1053+
TfwRatioSrvConnList *cl;
10431054

1044-
size = sizeof(TfwSrvConn *) * srv->conn_n;
1045-
if (!(srvdesc->conn = kzalloc(size, GFP_KERNEL)))
1055+
size = sizeof(TfwRatioSrvConnList) + sizeof(TfwSrvConn *) * srv->conn_n;
1056+
if (!(cl = kzalloc(size, GFP_KERNEL)))
10461057
return -ENOMEM;
10471058

1048-
conn = srvdesc->conn;
10491059
list_for_each_entry(srv_conn, &srv->conn_list, list) {
1060+
if (tfw_srv_conn_unscheduled(srv_conn))
1061+
continue;
10501062
if (unlikely(ci++ == srv->conn_n))
10511063
goto err;
1052-
*conn++ = srv_conn;
1064+
1065+
cl->conns[ci-1] = srv_conn;
10531066
}
10541067
if (unlikely(ci != srv->conn_n))
10551068
goto err;
10561069

1057-
srvdesc->conn_n = srv->conn_n;
1070+
cl->conn_n = ci;
10581071
srvdesc->srv = srv;
10591072
atomic64_set(&srvdesc->counter, 0);
10601073

1074+
rcu_assign_pointer(srvdesc->cl, cl);
10611075
return 0;
10621076
err:
1063-
kfree(srvdesc->conn);
1077+
kfree(srvdesc->cl);
10641078
return -EINVAL;
10651079
}
10661080

@@ -1081,7 +1095,7 @@ tfw_sched_ratio_srvdesc_setup(TfwSrvGroup *sg, TfwRatio *ratio)
10811095
int r;
10821096
size_t si = 0;
10831097
TfwServer *srv;
1084-
TfwRatioSrvDesc *srvdesc = ratio->srvdesc;
1098+
TfwRatioSrvDesc *srvdesc = rcu_dereference_bh_check(ratio->srvdesc, 1);
10851099

10861100
list_for_each_entry(srv, &sg->srv_list, list) {
10871101
if (unlikely((si++ == sg->srv_n) || !srv->conn_n
@@ -1277,10 +1291,17 @@ static void
12771291
tfw_sched_ratio_put_srv_data(struct rcu_head *rcu)
12781292
{
12791293
TfwRatioSrvDesc *srvdesc = container_of(rcu, TfwRatioSrvDesc, rcu);
1280-
kfree(srvdesc->conn);
1294+
kfree(srvdesc->cl);
12811295
kfree(srvdesc);
12821296
}
12831297

1298+
static void
1299+
tfw_sched_ratio_put_conn_data(struct rcu_head *rcu)
1300+
{
1301+
TfwRatioSrvConnList *cl = container_of(rcu, TfwRatioSrvConnList, rcu);
1302+
kfree(cl);
1303+
}
1304+
12841305
static void
12851306
tfw_sched_ratio_del_srv(TfwServer *srv)
12861307
{
@@ -1291,13 +1312,48 @@ tfw_sched_ratio_del_srv(TfwServer *srv)
12911312
call_rcu(&srvdesc->rcu, tfw_sched_ratio_put_srv_data);
12921313
}
12931314

1315+
static int
1316+
tfw_sched_ratio_upd_srv(TfwServer *srv)
1317+
{
1318+
TfwRatioSrvDesc *srvdesc = rcu_dereference_bh_check(srv->sched_data, 1);
1319+
size_t size, ci = 0;
1320+
TfwRatioSrvConnList *cl_copy;
1321+
TfwRatioSrvConnList *cl = rcu_dereference_bh_check(srvdesc->cl, 1);
1322+
TfwSrvConn *srv_conn;
1323+
1324+
size = sizeof(TfwRatioSrvConnList) + sizeof(TfwSrvConn *) * srv->conn_n;
1325+
if (!(cl_copy = kzalloc(size, GFP_ATOMIC)))
1326+
return -ENOMEM;
1327+
1328+
list_for_each_entry(srv_conn, &srv->conn_list, list) {
1329+
if (tfw_srv_conn_unscheduled(srv_conn))
1330+
continue;
1331+
if (unlikely(ci++ == srv->conn_n))
1332+
goto err;
1333+
cl_copy->conns[ci-1] = srv_conn;
1334+
}
1335+
if (unlikely(ci != srv->conn_n))
1336+
goto err;
1337+
cl->conn_n = ci;
1338+
rcu_assign_pointer(srvdesc->cl, cl_copy);
1339+
1340+
if (srvdesc)
1341+
call_rcu(&cl->rcu, tfw_sched_ratio_put_conn_data);
1342+
1343+
return 0;
1344+
err:
1345+
kfree(cl_copy);
1346+
return -EINVAL;
1347+
}
1348+
12941349
static TfwScheduler tfw_sched_ratio = {
12951350
.name = "ratio",
12961351
.list = LIST_HEAD_INIT(tfw_sched_ratio.list),
12971352
.add_grp = tfw_sched_ratio_add_grp,
12981353
.del_grp = tfw_sched_ratio_del_grp,
12991354
.add_srv = tfw_sched_ratio_add_srv,
13001355
.del_srv = tfw_sched_ratio_del_srv,
1356+
.upd_srv = tfw_sched_ratio_upd_srv,
13011357
.sched_sg_conn = tfw_sched_ratio_sched_sg_conn,
13021358
.sched_srv_conn = tfw_sched_ratio_sched_srv_conn,
13031359
};

0 commit comments

Comments
 (0)