Skip to content

Commit

Permalink
Implement ability to set stream_id to response skbs
Browse files Browse the repository at this point in the history
Since we decide to move frame making into `xmit`
callback, we need to save stream id in skb private
area and mark skb as skb, which contains headers or
data frame. In `xmit` callback we use this id to find
appropriate stream and use information of skb type to
add appropriate frame header (HEADERS/DATA).

Part of #1394
  • Loading branch information
EvgeniiMekhanik committed Apr 17, 2023
1 parent 07cdefd commit b7a2f68
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 50 deletions.
12 changes: 8 additions & 4 deletions fw/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -840,8 +840,8 @@ tfw_cache_send_304(TfwHttpReq *req, TfwCacheEntry *ce)
if (unlikely(r))
goto err_setup;
} else {
stream_id = tfw_h2_stream_id_close(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
stream_id = tfw_h2_stream_id_send(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
if (unlikely(!stream_id))
goto err_setup;

Expand Down Expand Up @@ -889,6 +889,7 @@ tfw_cache_send_304(TfwHttpReq *req, TfwCacheEntry *ce)
if (tfw_h2_frame_local_resp(resp, stream_id, h_len, NULL))
goto err_setup;

tfw_h2_stream_id_unlink(req, false, true);
tfw_h2_resp_fwd(resp);

return;
Expand Down Expand Up @@ -2520,6 +2521,10 @@ tfw_cache_build_resp_body(TDB *db, TdbVRec *trec, TfwMsgIter *it, char *p,
h2, !body_sz);
if (r)
return r;
if (stream_id) {
skb_set_tfw_flags(it->skb, SS_F_HTTT2_FRAME_DATA);
skb_set_tfw_cb(it->skb, stream_id);
}
}
if (!body_sz || !(trec = tdb_next_rec_chunk(db, trec)))
break;
Expand Down Expand Up @@ -2807,8 +2812,7 @@ cache_req_process_node(TfwHttpReq *req, tfw_http_cache_cb_t action)
* the backend), thus the stream will be finished.
*/
if (resp && TFW_MSG_H2(req)) {
id = tfw_h2_stream_id_close(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
id = tfw_h2_stream_id_unlink(req, false, true);
if (unlikely(!id)) {
tfw_http_msg_free((TfwHttpMsg *)resp);
tfw_http_conn_msg_free((TfwHttpMsg *)req);
Expand Down
26 changes: 23 additions & 3 deletions fw/hpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -3772,6 +3772,7 @@ __tfw_hpack_encode(TfwHttpResp *__restrict resp, TfwStr *__restrict hdr,
TfwHPackETbl *tbl = &ctx->hpack.enc_tbl;
int r = HPACK_IDX_ST_NOT_FOUND;
bool name_indexed = true;
struct sk_buff *prev = resp->mit.iter.skb;

if (WARN_ON_ONCE(!hdr || TFW_STR_EMPTY(hdr)))
return -EINVAL;
Expand Down Expand Up @@ -3808,7 +3809,7 @@ __tfw_hpack_encode(TfwHttpResp *__restrict resp, TfwStr *__restrict hdr,
return r;

resp->mit.acc_len += idx.sz * !use_pool;
return r;
goto set_skb_priv;
}

if (st_index || HPACK_IDX_RES(r) == HPACK_IDX_ST_NM_FOUND) {
Expand Down Expand Up @@ -3838,9 +3839,28 @@ __tfw_hpack_encode(TfwHttpResp *__restrict resp, TfwStr *__restrict hdr,

encode:
if (use_pool)
return tfw_hpack_hdr_add(resp, hdr, &idx, name_indexed, trans);
r = tfw_hpack_hdr_add(resp, hdr, &idx, name_indexed, trans);
else
return tfw_hpack_hdr_expand(resp, hdr, &idx, name_indexed);
r = tfw_hpack_hdr_expand(resp, hdr, &idx, name_indexed);
set_skb_priv:
BUG_ON(!resp->req);
if (likely(!r) && resp->req->stream) {
struct sk_buff *skb = prev;

/*
* Very long headers can be located in several skbs,
* mark them all.
*/
while(skb && skb != resp->mit.iter.skb) {
skb_set_tfw_flags(skb, SS_F_HTTT2_FRAME_HEADERS);
skb_set_tfw_cb(skb, resp->req->stream->id);
skb = skb->next;
}

skb_set_tfw_flags(resp->mit.iter.skb, SS_F_HTTT2_FRAME_HEADERS);
skb_set_tfw_cb(resp->mit.iter.skb, resp->req->stream->id);
}
return r;
}

int
Expand Down
54 changes: 30 additions & 24 deletions fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,19 +572,19 @@ tfw_h2_prep_resp(TfwHttpResp *resp, unsigned short status, TfwStr *msg,
};
TfwStr *body = NULL;

BUG_ON(!resp->req);
if (!stream_id) {
stream_id = tfw_h2_stream_id_close(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
if (unlikely(!stream_id)) {
return -ENOENT;
}
stream_id = tfw_h2_stream_id_send(resp->req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
if (unlikely(!stream_id))
return -EPIPE;
}

/* Set HTTP/2 ':status' pseudo-header. */
mit->start_off = FRAME_HEADER_SIZE;
r = tfw_h2_resp_status_write(resp, status, false, false);
if (unlikely(r))
return r;
goto out;

/*
* Form and write HTTP/2 response headers excluding "\r\n", ':'
Expand All @@ -610,7 +610,7 @@ tfw_h2_prep_resp(TfwHttpResp *resp, unsigned short status, TfwStr *msg,
r = tfw_hpack_encode(resp, __TFW_STR_CH(&hdr, 0),
false, false);
if (unlikely(r))
return r;
goto out;

write_int(val->len, 0x7F, 0, &vlen);
s_vlen.data = vlen.buf;
Expand All @@ -619,11 +619,11 @@ tfw_h2_prep_resp(TfwHttpResp *resp, unsigned short status, TfwStr *msg,
r = tfw_http_msg_expand_data(iter, skb_head, &s_vlen,
NULL);
if (unlikely(r))
return r;
goto out;

r = tfw_http_msg_expand_data(iter, skb_head, val, NULL);
if (unlikely(r))
return r;
goto out;

hdrs_len += s_vlen.len + val->len;
} else {
Expand All @@ -634,7 +634,7 @@ tfw_h2_prep_resp(TfwHttpResp *resp, unsigned short status, TfwStr *msg,
hdr.hpack_idx = name->hpack_idx;

if ((r = tfw_hpack_encode(resp, &hdr, false, true)))
return r;
goto out;
}
}

Expand All @@ -647,7 +647,12 @@ tfw_h2_prep_resp(TfwHttpResp *resp, unsigned short status, TfwStr *msg,
hdrs_len += mit->acc_len;

body = TFW_STR_BODY_CH(msg);
return tfw_h2_frame_local_resp(resp, stream_id, hdrs_len, body);

r = tfw_h2_frame_local_resp(resp, stream_id, hdrs_len, body);

out:
tfw_h2_stream_id_unlink(req, false, true);
return r;
}

/*
Expand Down Expand Up @@ -955,7 +960,7 @@ static inline void
tfw_http_conn_req_clean(TfwHttpReq *req)
{
if (TFW_MSG_H2(req)) {
tfw_h2_stream_id_close(req, _HTTP2_UNDEFINED, 0);
tfw_h2_stream_id_unlink(req, false, true);
} else {
spin_lock_bh(&((TfwCliConn *)req->conn)->seq_qlock);
if (likely(!list_empty(&req->msg.seq_list)))
Expand Down Expand Up @@ -2721,7 +2726,7 @@ tfw_http_conn_release(TfwConn *conn)
list_for_each_entry_safe(req, tmp, &zap_queue, fwd_list) {
list_del_init(&req->fwd_list);
if (TFW_MSG_H2(req)) {
tfw_h2_stream_id_close(req, _HTTP2_UNDEFINED, 0);
tfw_h2_stream_id_unlink(req, false, true);
}
else if (unlikely(!list_empty_careful(&req->msg.seq_list))) {
spin_lock_bh(&((TfwCliConn *)req->conn)->seq_qlock);
Expand Down Expand Up @@ -4796,6 +4801,10 @@ tfw_h2_append_predefined_body(TfwHttpResp *resp, unsigned int stream_id,
copy + FRAME_HEADER_SIZE);
ss_skb_adjust_data_len(it->skb, copy + FRAME_HEADER_SIZE);

BUG_ON(!stream_id);
skb_set_tfw_flags(it->skb, SS_F_HTTT2_FRAME_DATA);
skb_set_tfw_cb(it->skb, stream_id);

if (it->frag + 1 == MAX_SKB_FRAGS
&& (r = tfw_msg_iter_append_skb(it)))
{
Expand Down Expand Up @@ -4935,7 +4944,7 @@ tfw_h2_make_frames(TfwHttpResp *resp, unsigned int stream_id,
/**
* Frame forwarded response.
*/
int
static int
tfw_h2_frame_fwd_resp(TfwHttpResp *resp, unsigned int stream_id,
unsigned long h_len)
{
Expand All @@ -4947,7 +4956,7 @@ tfw_h2_frame_fwd_resp(TfwHttpResp *resp, unsigned int stream_id,
*/
int
tfw_h2_frame_local_resp(TfwHttpResp *resp, unsigned int stream_id,
unsigned long h_len, const TfwStr *body)
unsigned long h_len, const TfwStr *body)
{
int r;

Expand Down Expand Up @@ -5062,9 +5071,9 @@ tfw_h2_error_resp(TfwHttpReq *req, int status, bool reply, bool attack,
* can just send error response, leave the connection alive and
* drop request's corresponding stream; in this case stream either
* is already in locally closed state (switched in
* @tfw_h2_stream_id_close() during failed proxy/internal response
* @tfw_h2_stream_id_send() during failed proxy/internal response
* creation) or will be switched into locally closed state in
* @tfw_h2_send_err_resp() (or in @tfw_h2_stream_id_close() if no error
* @tfw_h2_send_err_resp() (or in @tfw_h2_stream_id_send() if no error
* response is needed) below; remotely (i.e. on client side) stream
* will be closed - due to END_STREAM flag set in the last frame of
* error response; in case of attack we must close entire connection,
Expand All @@ -5085,7 +5094,7 @@ tfw_h2_error_resp(TfwHttpReq *req, int status, bool reply, bool attack,
* remote peer (via RST_STREAM frame), that the stream has entered
* into closed state (RFC 7540 section 6.4).
*/
stream_id = tfw_h2_stream_id_close(req, HTTP2_RST_STREAM, 0);
stream_id = tfw_h2_stream_id_unlink(req, true, true);
if (stream_id && !attack)
tfw_h2_send_rst_stream(ctx, stream_id, HTTP2_ECODE_CANCEL);

Expand Down Expand Up @@ -5287,12 +5296,8 @@ tfw_h2_resp_adjust_fwd(TfwHttpResp *resp)
req->vhost,
TFW_VHOST_HDRMOD_RESP);

/*
* Get ID of corresponding stream to prepare/send HTTP/2 response, and
* unlink request from the stream.
*/
stream_id = tfw_h2_stream_id_close(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
stream_id = tfw_h2_stream_id_send(req, HTTP2_HEADERS,
HTTP2_F_END_STREAM);
if (unlikely(!stream_id))
goto out;

Expand Down Expand Up @@ -5395,6 +5400,7 @@ tfw_h2_resp_adjust_fwd(TfwHttpResp *resp)
req, resp);
SS_SKB_QUEUE_DUMP(&resp->msg.skb_head);

tfw_h2_stream_id_unlink(req, false, true);
tfw_h2_resp_fwd(resp);

__tfw_h2_resp_cleanup(&cleanup);
Expand Down
2 changes: 0 additions & 2 deletions fw/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,6 @@ unsigned long tfw_http_hdr_split(TfwStr *hdr, TfwStr *name_out, TfwStr *val_out,
bool inplace);
unsigned long tfw_h2_hdr_size(unsigned long n_len, unsigned long v_len,
unsigned short st_index);
int tfw_h2_frame_fwd_resp(TfwHttpResp *resp, unsigned int stream_id,
unsigned long h_len);
int tfw_h2_frame_local_resp(TfwHttpResp *resp, unsigned int stream_id,
unsigned long h_len, const TfwStr *body);
int tfw_http_resp_copy_encodings(TfwHttpResp *resp, TfwStr* dst,
Expand Down
58 changes: 43 additions & 15 deletions fw/http_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,15 +741,13 @@ tfw_h2_stream_id(TfwHttpReq *req)
}

/*
* Get stream ID for upper layer to prepare and send frame with response to
* client, and process stream FSM for the frame (of type specified in @type
* and with flags set in @flags). This procedure also unlinks request from
* corresponding stream (if linked) and moves the stream to the queue of
* closed streams (if it is not contained there yet).
* Get stream ID for upper layer to prepare and send frame with response
* to client. This procedure also unlinks request from corresponding
* stream (if linked) and moves the stream to the queue of closed streams
* (if it is not contained there yet and if it is necessary).
*/
unsigned int
tfw_h2_stream_id_close(TfwHttpReq *req, unsigned char type,
unsigned char flags)
tfw_h2_stream_id_unlink(TfwHttpReq *req, bool send_rst, bool move_to_closed)
{
TfwStream *stream;
unsigned int id = 0;
Expand All @@ -763,23 +761,53 @@ tfw_h2_stream_id_close(TfwHttpReq *req, unsigned char type,
return 0;
}

if (type < _HTTP2_UNDEFINED &&
!STREAM_SEND_PROCESS(stream, type, flags))
{
id = stream->id;
}
if (send_rst)
STREAM_SEND_PROCESS(stream, HTTP2_RST_STREAM, 0);

id = stream->id;
req->stream = NULL;
stream->msg = NULL;

T_DBG3("%s: ctx [%p], strm [%p] added to closed streams list\n",
__func__, ctx, stream);
if (move_to_closed) {
T_DBG3("%s: ctx [%p], strm [%p] added to closed streams list\n",
__func__, ctx, stream);
__tfw_h2_stream_add_closed(&ctx->hclosed_streams, stream);
}

__tfw_h2_stream_add_closed(&ctx->hclosed_streams, stream);
spin_unlock(&ctx->lock);

return id;
}

unsigned int
tfw_h2_stream_id_send(TfwHttpReq *req, unsigned char type,
unsigned char flags)
{
TfwStream *stream;
unsigned int id = 0;
TfwH2Ctx *ctx = tfw_h2_context(req->conn);

spin_lock(&ctx->lock);

stream = req->stream;
if (!stream) {
spin_unlock(&ctx->lock);
return 0;
}

if (!STREAM_SEND_PROCESS(stream, type, flags))
id = stream->id;

if (!id) {
req->stream = NULL;
stream->msg = NULL;
__tfw_h2_stream_add_closed(&ctx->hclosed_streams, stream);
}

spin_unlock(&ctx->lock);

return id;

}

/*
Expand Down
6 changes: 4 additions & 2 deletions fw/http_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,10 @@ void tfw_h2_context_clear(TfwH2Ctx *ctx);
int tfw_h2_frame_process(TfwConn *c, struct sk_buff *skb);
void tfw_h2_conn_streams_cleanup(TfwH2Ctx *ctx);
unsigned int tfw_h2_stream_id(TfwHttpReq *req);
unsigned int tfw_h2_stream_id_close(TfwHttpReq *req, unsigned char type,
unsigned char flags);
unsigned int tfw_h2_stream_id_send(TfwHttpReq *req, unsigned char type,
unsigned char flags);
unsigned int tfw_h2_stream_id_unlink(TfwHttpReq *req, bool send_rst,
bool move_to_closed);
void tfw_h2_conn_terminate_close(TfwH2Ctx *ctx, TfwH2Err err_code, bool close);
int tfw_h2_send_rst_stream(TfwH2Ctx *ctx, unsigned int id, TfwH2Err err_code);

Expand Down

0 comments on commit b7a2f68

Please sign in to comment.