Skip to content

Commit

Permalink
Replace GFSM calls with direct calls to TLS and HTTP handlers on
Browse files Browse the repository at this point in the history
low level networking layers.

GFSM was designed to build graphs of network protocols FSMs (this
design was inspired by FreeBSD netgraph). However, during the years
neither we nor external users have any requirements to introduce
any modules which use GFSM to hook TLS or HTTP entry code. There
are only 2 users of the mechanism for TLS and HTTP for now:
1. TLS -> HTTP protocols handling
2. HTTP limits (the frang module)

This patch replaces GFSM calls with direct calls to
tfw_http_req_process(), tfw_tls_msg_process() and frang_tls_handler()
in following paths:
1. sync sockets -> TLS
2. sync sockets -> HTTP
3. TLS -> HTTP
4. TLS -> Frang

As the result the function tfw_connection_recv() was eliminated.
Now the code is simpler and has lower overhead.

We still might need GFSM for the user-space requests handling (#77)
and Tempesta Language (#102).
  • Loading branch information
krizhanovsky committed Nov 14, 2021
1 parent 27e65ef commit 2eae1da
Show file tree
Hide file tree
Showing 13 changed files with 79 additions and 157 deletions.
11 changes: 0 additions & 11 deletions fw/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,6 @@ tfw_connection_send(TfwConn *conn, TfwMsg *msg)
return TFW_CONN_HOOK_CALL(conn, conn_send, msg);
}

int
tfw_connection_recv(void *cdata, struct sk_buff *skb)
{
TfwConn *conn = cdata;
TfwFsmData fsm_data = {
.skb = skb,
};

return tfw_gfsm_dispatch(&conn->state, conn, &fsm_data);
}

void
tfw_connection_hooks_register(TfwConnHooks *hooks, int type)
{
Expand Down
2 changes: 0 additions & 2 deletions fw/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,4 @@ int tfw_connection_close(TfwConn *conn, bool sync);
void tfw_connection_drop(TfwConn *conn);
void tfw_connection_release(TfwConn *conn);

int tfw_connection_recv(void *cdata, struct sk_buff *skb);

#endif /* __TFW_CONNECTION_H__ */
3 changes: 1 addition & 2 deletions fw/gfsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2018 Tempesta Technologies, Inc.
* Copyright (C) 2015-2021 Tempesta Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -88,7 +88,6 @@ enum {
/* Security rules enforcement. */
TFW_FSM_FRANG_REQ,
TFW_FSM_FRANG_RESP,
TFW_FSM_FRANG_TLS,

TFW_FSM_NUM /* Must be <= TFW_GFSM_FSM_N */
};
Expand Down
65 changes: 24 additions & 41 deletions fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@
#define RESP_BUF_LEN 128

static DEFINE_PER_CPU(char[RESP_BUF_LEN], g_buf);
int ghprio; /* GFSM hook priority. */

#define TFW_CFG_BLK_DEF (TFW_BLK_ERR_REPLY)
unsigned short tfw_blk_flags = TFW_CFG_BLK_DEF;
Expand Down Expand Up @@ -5132,12 +5131,11 @@ tfw_h1_req_process(TfwStream *stream, struct sk_buff *skb)
* TODO enter the function depending on current GFSM state.
*/
static int
tfw_http_req_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb)
{
bool block;
ss_skb_actor_t *actor;
unsigned int parsed;
struct sk_buff *skb = data->skb;
TfwHttpReq *req;
TfwHttpMsg *hmsib;
TfwFsmData data_up;
Expand Down Expand Up @@ -5168,7 +5166,7 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
skb->len, skb->next, parsed, req->msg.len, req->version, r);

/*
* We have to keep @data the same to pass it as is to FSMs
* We have to keep @skb the same to pass it as is to FSMs
* registered with lower priorities after us, but we must
* feed the new data version to FSMs registered on our states.
*/
Expand Down Expand Up @@ -5339,8 +5337,7 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
* the quickest way to obtain target VHost and target backend server
* connection since it allows to avoid expensive tables lookups.
*/
switch (tfw_http_sess_obtain(req))
{
switch (tfw_http_sess_obtain(req)) {
case TFW_HTTP_SESS_SUCCESS:
break;

Expand Down Expand Up @@ -5710,11 +5707,10 @@ tfw_http_resp_terminate(TfwHttpMsg *hm)
* TODO enter the function depending on current GFSM state.
*/
static int
tfw_http_resp_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
tfw_http_resp_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb)
{
int r = TFW_BLOCK;
unsigned int chunks_unused, parsed;
struct sk_buff *skb = data->skb;
TfwHttpReq *bad_req;
TfwHttpMsg *hmresp, *hmsib;
TfwFsmData data_up;
Expand Down Expand Up @@ -5749,7 +5745,7 @@ tfw_http_resp_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
skb->len, parsed, hmresp->msg.len, hmresp->version, r);

/*
* We have to keep @data the same to pass it as is to FSMs
* We have to keep @skb the same to pass it as is to FSMs
* registered with lower priorities after us, but we must
* feed the new data version to FSMs registered on our states.
*/
Expand Down Expand Up @@ -5934,28 +5930,28 @@ tfw_http_resp_process(TfwConn *conn, TfwStream *stream, const TfwFsmData *data)
* @return status (application logic decision) of the message processing.
*/
int
tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream, TfwFsmData *data)
tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream,
struct sk_buff *skb)
{
if (WARN_ON_ONCE(!stream))
return -EINVAL;
if (unlikely(!stream->msg)) {
stream->msg = tfw_http_conn_msg_alloc(conn, stream);
if (!stream->msg) {
__kfree_skb(data->skb);
__kfree_skb(skb);
return TFW_BLOCK;
}
tfw_http_mark_wl_new_msg(conn, (TfwHttpMsg *)stream->msg,
data->skb);
tfw_http_mark_wl_new_msg(conn, (TfwHttpMsg *)stream->msg, skb);
T_DBG2("Link new msg %p with connection %p\n",
stream->msg, conn);
}

T_DBG2("Add skb %p to message %p\n", data->skb, stream->msg);
ss_skb_queue_tail(&stream->msg->skb_head, data->skb);
T_DBG2("Add skb %p to message %p\n", skb, stream->msg);
ss_skb_queue_tail(&stream->msg->skb_head, skb);

return (TFW_CONN_TYPE(conn) & Conn_Clnt)
? tfw_http_req_process(conn, stream, data)
: tfw_http_resp_process(conn, stream, data);
? tfw_http_req_process(conn, stream, skb)
: tfw_http_resp_process(conn, stream, skb);
}

/**
Expand All @@ -5967,24 +5963,25 @@ tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream, TfwFsmData *data)
* returned an error code on. The rest of skbs are freed by us.
*/
int
tfw_http_msg_process(void *conn, TfwFsmData *data)
tfw_http_msg_process(void *conn, struct sk_buff *skb)
{
int r = T_OK;
TfwStream *stream = &((TfwConn *)conn)->stream;
struct sk_buff *next;

if (data->skb->prev)
data->skb->prev->next = NULL;
for (next = data->skb->next; data->skb;
data->skb = next, next = next ? next->next : NULL)
if (skb->prev)
skb->prev->next = NULL;
for (next = skb->next; skb;
skb = next, next = next ? next->next : NULL)
{
if (likely(r == T_OK || r == T_POSTPONE)) {
data->skb->next = data->skb->prev = NULL;
skb->next = skb->prev = NULL;
r = TFW_CONN_H2(conn)
? tfw_h2_frame_process(conn, data)
: tfw_http_msg_process_generic(conn, stream, data);
? tfw_h2_frame_process(conn, skb)
: tfw_http_msg_process_generic(conn, stream,
skb);
} else {
__kfree_skb(data->skb);
__kfree_skb(skb);
}
}

Expand Down Expand Up @@ -6737,28 +6734,15 @@ TfwMod tfw_http_mod = {
* init/exit
* ------------------------------------------------------------------------
*/

int __init
tfw_http_init(void)
{
int r;

r = tfw_gfsm_register_fsm(TFW_FSM_HTTP, tfw_http_msg_process);
if (r)
if ((r = tfw_gfsm_register_fsm(TFW_FSM_HTTP, tfw_http_msg_process)))
return r;

tfw_connection_hooks_register(&http_conn_hooks, TFW_FSM_HTTP);

ghprio = tfw_gfsm_register_hook(TFW_FSM_TLS,
TFW_GFSM_HOOK_PRIORITY_ANY,
TFW_TLS_FSM_DATA_READY,
TFW_FSM_HTTP, TFW_HTTP_FSM_INIT);
if (ghprio < 0) {
tfw_connection_hooks_unregister(TFW_FSM_HTTP);
tfw_gfsm_unregister_fsm(TFW_FSM_HTTP);
return ghprio;
}

tfw_mod_register(&tfw_http_mod);

return 0;
Expand All @@ -6768,7 +6752,6 @@ void
tfw_http_exit(void)
{
tfw_mod_unregister(&tfw_http_mod);
tfw_gfsm_unregister_hook(TFW_FSM_TLS, ghprio, TFW_TLS_FSM_DATA_READY);
tfw_connection_hooks_unregister(TFW_FSM_HTTP);
tfw_gfsm_unregister_fsm(TFW_FSM_HTTP);
}
2 changes: 1 addition & 1 deletion fw/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ tfw_h2_pseudo_index(unsigned short status)
typedef void (*tfw_http_cache_cb_t)(TfwHttpMsg *);

/* External HTTP functions. */
int tfw_http_msg_process(void *conn, TfwFsmData *data);
int tfw_http_msg_process(TfwConn *conn, TfwFsmData *data);
int tfw_http_msg_process_generic(TfwConn *conn, TfwStream *stream,
TfwFsmData *data);
unsigned long tfw_http_req_key_calc(TfwHttpReq *req);
Expand Down
4 changes: 2 additions & 2 deletions fw/http_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -1698,14 +1698,14 @@ tfw_h2_context_reinit(TfwH2Ctx *ctx, bool postponed)
}

int
tfw_h2_frame_process(void *c, TfwFsmData *data)
tfw_h2_frame_process(TfwConn *c, struct sk_buff *skb)
{
int r;
bool postponed;
unsigned int parsed, unused;
TfwFsmData data_up = {};
TfwH2Ctx *h2 = tfw_h2_context(c);
struct sk_buff *nskb = NULL, *skb = data->skb;
struct sk_buff *nskb = NULL;

next_msg:
postponed = false;
Expand Down
40 changes: 7 additions & 33 deletions fw/http_limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -856,13 +856,6 @@ enum {
TFW_FRANG_RESP_FSM_DONE = TFW_GFSM_FRANG_RESP_STATE(TFW_GFSM_STATE_LAST)
};

#define TFW_GFSM_FRANG_TLS_STATE(s) \
((TFW_FSM_FRANG_TLS << TFW_GFSM_FSM_SHIFT) | (s))
enum {
TFW_FRANG_TLS_FSM_INIT = TFW_GFSM_FRANG_TLS_STATE(0),
TFW_FRANG_TLS_FSM_DONE = TFW_GFSM_FRANG_TLS_STATE(TFW_GFSM_STATE_LAST)
};

#define __FRANG_FSM_MOVE(st) T_FSM_MOVE(st, if (r) T_FSM_EXIT(); )

#define __FRANG_FSM_JUMP_EXIT(st) \
Expand Down Expand Up @@ -1451,8 +1444,7 @@ frang_tls_conn_limit(FrangAcc *ra, FrangGlobCfg *conf, int hs_state)
ra->history[i].ts = ts;
}

switch (hs_state)
{
switch (hs_state) {
case TTLS_HS_CB_FINISHED_NEW:
ra->history[i].tls_sess_new++;
break;
Expand All @@ -1473,8 +1465,7 @@ frang_tls_conn_limit(FrangAcc *ra, FrangGlobCfg *conf, int hs_state)
sum_incomplete += ra->history[i].tls_sess_incomplete;
}

switch (hs_state)
{
switch (hs_state) {
case TTLS_HS_CB_FINISHED_NEW:
if (conf->tls_new_conn_rate
&& sum_new > conf->tls_new_conn_rate)
Expand Down Expand Up @@ -1511,12 +1502,11 @@ frang_tls_conn_limit(FrangAcc *ra, FrangGlobCfg *conf, int hs_state)
return TFW_PASS;
}

static int
frang_tls_handler(void *obj, TfwFsmData *data)
int
frang_tls_handler(TlsCtx *tls, int state)
{
TfwCliConn *conn = (TfwCliConn *)obj;
FrangAcc *ra = conn->sk->sk_security;
int hs_state = -PTR_ERR(data->req);
TfwTlsConn *conn = container_of(tls, TfwTlsConn, tls);
FrangAcc *ra = conn->cli_conn.sk->sk_security;
TfwVhost *dflt_vh = tfw_vhost_lookup_default();
int r;

Expand All @@ -1525,7 +1515,7 @@ frang_tls_handler(void *obj, TfwFsmData *data)

spin_lock(&ra->lock);

r = frang_tls_conn_limit(ra, dflt_vh->frang_gconf, hs_state);
r = frang_tls_conn_limit(ra, dflt_vh->frang_gconf, state);
if (r == TFW_BLOCK && dflt_vh->frang_gconf->ip_block)
tfw_filter_block_ip(&FRANG_ACC2CLI(ra)->addr);

Expand Down Expand Up @@ -1596,14 +1586,6 @@ static FrangGfsmHook frang_gfsm_hooks[] = {
.st0 = TFW_FRANG_RESP_FSM_FWD,
.name = "response_fwd",
},
{
.prio = -1,
.hook_fsm = TFW_FSM_HTTPS,
.hook_state = TFW_TLS_FSM_HS_DONE,
.fsm_id = TFW_FSM_FRANG_TLS,
.st0 = TFW_FRANG_TLS_FSM_INIT,
.name = "tls_hs_done",
},
};

void
Expand Down Expand Up @@ -1664,20 +1646,13 @@ tfw_http_limits_init(void)
goto err_fsm_resp;
}

r = tfw_gfsm_register_fsm(TFW_FSM_FRANG_TLS, frang_tls_handler);
if (r) {
T_ERR_NL("frang: can't register frang tls fsm\n");
goto err_fsm_tls;
}

r = tfw_http_limits_hooks_register();
if (r)
goto err_hooks;

return 0;
err_hooks:
tfw_http_limits_hooks_remove();
tfw_gfsm_unregister_fsm(TFW_FSM_FRANG_TLS);
err_fsm_tls:
tfw_gfsm_unregister_fsm(TFW_FSM_FRANG_RESP);
err_fsm_resp:
Expand All @@ -1694,7 +1669,6 @@ tfw_http_limits_exit(void)
T_DBG("frang exit\n");

tfw_http_limits_hooks_remove();
tfw_gfsm_unregister_fsm(TFW_FSM_FRANG_TLS);
tfw_gfsm_unregister_fsm(TFW_FSM_FRANG_RESP);
tfw_gfsm_unregister_fsm(TFW_FSM_FRANG_REQ);
tfw_classifier_unregister();
Expand Down
5 changes: 4 additions & 1 deletion fw/http_limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2020 Tempesta Technologies, Inc.
* Copyright (C) 2015-2021 Tempesta Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
Expand All @@ -24,6 +24,7 @@
#include <linux/in6.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/tls_hs.h>

#include "tempesta_fw.h"
#include "connection.h"
Expand Down Expand Up @@ -238,4 +239,6 @@ struct frang_vhost_cfg_t {
bool http_method_override;
};

int frang_tls_handler(TlsCtx *tls, int state);

#endif /* __HTTP_LIMITS__ */
Loading

0 comments on commit 2eae1da

Please sign in to comment.