Skip to content

Commit

Permalink
Move applying of new settings to ss_do_send
Browse files Browse the repository at this point in the history
New settings should be applyed just before ack to
this settings is pushed to the socket write queue,
because otherwise new settings can be applyed and
some frames with this new settings will be sent
before ack to this settings.
  • Loading branch information
EvgeniiMekhanik committed Sep 14, 2023
1 parent 4c7bf82 commit a97b4fa
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 40 deletions.
2 changes: 0 additions & 2 deletions fw/hpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ typedef struct {
* @window - maximum pseudo-length of the dynamic table (in bytes); this
* value used as threshold to flushing old entries;
* @wnd_changed - flag indicates, that window was changed by settings update;
* @ack_sent - flag indicates, that ack for window change was sent;
* @rbuf - pointer to the ring buffer;
* @root - pointer to the root node of binary tree;
* @pool - memory pool for dynamic table;
Expand All @@ -102,7 +101,6 @@ typedef struct {
TFW_HPACK_ETBL_COMMON;
unsigned short window;
bool wnd_changed;
bool ack_sent;
char *rbuf;
TfwHPackNode *root;
TfwPool *pool;
Expand Down
121 changes: 94 additions & 27 deletions fw/http_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,6 @@ typedef enum {
HTTP2_RECV_APP_DATA_POST
} TfwFrameState;

/**
* IDs for SETTINGS parameters of HTTP/2 connection (RFC 7540
* section 6.5.2).
*/
typedef enum {
HTTP2_SETTINGS_TABLE_SIZE = 0x01,
HTTP2_SETTINGS_ENABLE_PUSH,
HTTP2_SETTINGS_MAX_STREAMS,
HTTP2_SETTINGS_INIT_WND_SIZE,
HTTP2_SETTINGS_MAX_FRAME_SIZE,
HTTP2_SETTINGS_MAX_HDR_LIST_SIZE
} TfwSettingsId;

#define __FRAME_FSM_EXIT() \
do { \
ctx->rlen = 0; \
Expand Down Expand Up @@ -1211,25 +1198,22 @@ tfw_h2_apply_wnd_sz_change(TfwH2Ctx *ctx, long int delta)
}
}

static int
static void
tfw_h2_apply_settings_entry(TfwH2Ctx *ctx, unsigned short id,
unsigned int val)
{
TfwH2Conn *conn = container_of(ctx, TfwH2Conn, h2);
TfwSettings *dest = &ctx->rsettings;
long int delta;

switch (id) {
case HTTP2_SETTINGS_TABLE_SIZE:
assert_spin_locked(&((TfwConn *)conn)->sk->sk_lock.slock);
dest->hdr_tbl_sz = min_t(unsigned int,
val, HPACK_ENC_TABLE_MAX_SIZE);
tfw_hpack_set_rbuf_size(&ctx->hpack.enc_tbl, dest->hdr_tbl_sz);
break;

case HTTP2_SETTINGS_ENABLE_PUSH:
if (val > 1)
return -EINVAL;
BUG_ON(val > 1);
dest->push = val;
break;

Expand All @@ -1238,17 +1222,14 @@ tfw_h2_apply_settings_entry(TfwH2Ctx *ctx, unsigned short id,
break;

case HTTP2_SETTINGS_INIT_WND_SIZE:
if (val > MAX_WND_SIZE)
return -EINVAL;

BUG_ON(val > MAX_WND_SIZE);
delta = (long int)val - (long int)dest->wnd_sz;
tfw_h2_apply_wnd_sz_change(ctx, delta);
dest->wnd_sz = val;
break;

case HTTP2_SETTINGS_MAX_FRAME_SIZE:
if (val < FRAME_DEF_LENGTH || val > FRAME_MAX_LENGTH)
return -EINVAL;
BUG_ON(val < FRAME_DEF_LENGTH || val > FRAME_MAX_LENGTH);
dest->max_frame_sz = val;
break;

Expand All @@ -1261,12 +1242,97 @@ tfw_h2_apply_settings_entry(TfwH2Ctx *ctx, unsigned short id,
* We should silently ignore unknown identifiers (see
* RFC 7540 section 6.5.2)
*/
return 0;
break;
}
}

static int
tfw_h2_check_settings_entry(TfwH2Ctx *ctx, unsigned short id, unsigned int val)
{
TfwH2Conn *conn = container_of(ctx, TfwH2Conn, h2);

assert_spin_locked(&((TfwConn *)conn)->sk->sk_lock.slock);

switch (id) {
case HTTP2_SETTINGS_TABLE_SIZE:
break;

case HTTP2_SETTINGS_ENABLE_PUSH:
if (val > 1)
return -EINVAL;
break;

case HTTP2_SETTINGS_MAX_STREAMS:
break;

case HTTP2_SETTINGS_INIT_WND_SIZE:
if (val > MAX_WND_SIZE)
return -EINVAL;
break;

case HTTP2_SETTINGS_MAX_FRAME_SIZE:
if (val < FRAME_DEF_LENGTH || val > FRAME_MAX_LENGTH)
return -EINVAL;
break;

case HTTP2_SETTINGS_MAX_HDR_LIST_SIZE:
break;

default:
/*
* We should silently ignore unknown identifiers (see
* RFC 7540 section 6.5.2)
*/
break;
}

return 0;
}

/**
* Flags indicates that appropriate SETTINGS parameter is waited for
* update.
*/
static const unsigned char
ctx_new_settings_flags[] = {
[HTTP2_SETTINGS_TABLE_SIZE] = 0x01,
[HTTP2_SETTINGS_ENABLE_PUSH] = 0x02,
[HTTP2_SETTINGS_MAX_STREAMS] = 0x04,
[HTTP2_SETTINGS_INIT_WND_SIZE] = 0x08,
[HTTP2_SETTINGS_MAX_FRAME_SIZE] = 0x10,
[HTTP2_SETTINGS_MAX_HDR_LIST_SIZE] = 0x20
};

static void
tfw_h2_save_settings_entry(TfwH2Ctx *ctx, unsigned short id, unsigned int val)
{
TfwH2Conn *conn = container_of(ctx, TfwH2Conn, h2);

assert_spin_locked(&((TfwConn *)conn)->sk->sk_lock.slock);

if (id < _HTTP2_SETTINGS_MAX) {
ctx->new_settings.settings[id] = val;
ctx->new_settings.flags |= ctx_new_settings_flags[id];
}
}

void
tfw_h2_apply_new_settings(TfwH2Ctx *ctx)
{
TfwH2Conn *conn = container_of(ctx, TfwH2Conn, h2);
unsigned int id;

assert_spin_locked(&((TfwConn *)conn)->sk->sk_lock.slock);

for (id = HTTP2_SETTINGS_TABLE_SIZE; id < _HTTP2_SETTINGS_MAX; id++) {
if (ctx->new_settings.flags & ctx_new_settings_flags[id]) {
unsigned int val = ctx->new_settings.settings[id];
tfw_h2_apply_settings_entry(ctx, id, val);
}
}
ctx->new_settings.flags = 0;
}

static void
tfw_h2_settings_ack_process(TfwH2Ctx *ctx)
{
Expand All @@ -1289,9 +1355,11 @@ tfw_h2_settings_process(TfwH2Ctx *ctx)

T_DBG3("%s: entry parsed, id=%hu, val=%u\n", __func__, id, val);

if ((r = tfw_h2_apply_settings_entry(ctx, id, val)))
if ((r = tfw_h2_check_settings_entry(ctx, id, val)))
return r;

tfw_h2_save_settings_entry(ctx, id, val);

ctx->to_read = hdr->length ? FRAME_SETTINGS_ENTRY_SIZE : 0;
hdr->length -= ctx->to_read;

Expand Down Expand Up @@ -2515,15 +2583,14 @@ do { \

T_FSM_STATE(HTTP2_MAKE_HEADERS_FRAMES) {
ADJUST_AVAILABLE_CWND(tmp_cwnd_awail, HTTP2_HEADERS);
if (unlikely(ctx->hpack.enc_tbl.ack_sent)) {
if (unlikely(ctx->hpack.enc_tbl.wnd_changed)) {
r = tfw_hpack_enc_tbl_write_sz(&ctx->hpack.enc_tbl,
stream);
if (unlikely(r < 0)) {
T_WARN("Failed to encode hpack dynamic"
"table size %d", r);
return r;
}
ctx->hpack.enc_tbl.ack_sent = false;
}

r = tfw_h2_insert_frame_header_and_send(ctx, stream, frame_type,
Expand Down
21 changes: 21 additions & 0 deletions fw/http_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ typedef enum {
_HTTP2_UNDEFINED
} TfwFrameType;

/**
* IDs for SETTINGS parameters of HTTP/2 connection (RFC 7540
* section 6.5.2).
*/
typedef enum {
HTTP2_SETTINGS_TABLE_SIZE = 0x01,
HTTP2_SETTINGS_ENABLE_PUSH,
HTTP2_SETTINGS_MAX_STREAMS,
HTTP2_SETTINGS_INIT_WND_SIZE,
HTTP2_SETTINGS_MAX_FRAME_SIZE,
HTTP2_SETTINGS_MAX_HDR_LIST_SIZE,
_HTTP2_SETTINGS_MAX,
} TfwSettingsId;

static const char *__tfw_h2_frm_names[] = {
[HTTP2_DATA] = "DATA",
[HTTP2_HEADERS] = "HEADERS",
Expand Down Expand Up @@ -156,6 +170,8 @@ typedef struct {
* @rem_wnd - remote peer current flow controlled window;
* @hpack - HPACK context, used in processing of
* HEADERS/CONTINUATION frames;
* @new_settings - new settings to apply when ack is pushed to socket
* write queue;
* @__off - offset to reinitialize processing context;
* @skb_head - collected list of processed skbs containing HTTP/2
* frames;
Expand Down Expand Up @@ -195,6 +211,10 @@ typedef struct {
long int loc_wnd;
long int rem_wnd;
TfwHPack hpack;
struct {
unsigned int settings[_HTTP2_SETTINGS_MAX];
unsigned char flags;
} new_settings;
char __off[0];
struct sk_buff *skb_head;
TfwStream *cur_stream;
Expand All @@ -217,6 +237,7 @@ int tfw_h2_context_init(TfwH2Ctx *ctx);
void tfw_h2_context_clear(TfwH2Ctx *ctx);
int tfw_h2_frame_process(TfwConn *c, struct sk_buff *skb,
struct sk_buff **next);
void tfw_h2_apply_new_settings(TfwH2Ctx *ctx);
void tfw_h2_conn_streams_cleanup(TfwH2Ctx *ctx);
TfwStream *tfw_h2_find_not_closed_stream(TfwH2Ctx *ctx, unsigned int id,
bool recv);
Expand Down
13 changes: 2 additions & 11 deletions fw/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,17 +445,8 @@ ss_do_send(struct sock *sk, struct sk_buff **skb_head, int flags)
}

if (!stream) {
if (h2 && unlikely(h2->hpack.enc_tbl.wnd_changed &&
!h2->hpack.enc_tbl.ack_sent))
{
TfwFrameHdr hdr;
char *data = ss_skb_data_ptr_by_offset(skb, 0);

tfw_h2_unpack_frame_header(&hdr, data);
if (hdr.type == HTTP2_SETTINGS &&
hdr.flags == HTTP2_F_ACK)
h2->hpack.enc_tbl.ack_sent = true;
}
if (h2 && unlikely(h2->new_settings.flags))
tfw_h2_apply_new_settings(h2);
ss_skb_entail(sk, skb, mark, tls_type);
} else {
ss_skb_queue_tail(&stream->xmit.skb_head, skb);
Expand Down

0 comments on commit a97b4fa

Please sign in to comment.