-
Notifications
You must be signed in to change notification settings - Fork 104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tls: encrypting in new sk_buff pages, if sendfile()
is used or response from cache
#1264
Conversation
sendfile ()
is usedsendfile ()
is used
sendfile ()
is usedsendfile()
is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current version of PR introduces redundant data copying, which could be avoided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several issues with the code. Also @i-rinat proposed much better design - this is the right way to go.
tempesta_fw/ss_skb.c
Outdated
__copy_ip_header(*skb_head, skb); | ||
skb_shinfo(*skb_head)->tx_flags = skb_shinfo(skb)->tx_flags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Socket buffer unrolling is supposed to receive list of skbs on GRO and unroll it to separate skbs, which will be processed separately in Tempesta and the TCP/IP stack aftewards. The sense of GROed lists of skbs is that the only head skb is processed in control flow and the rest of skbs are processed only when some data is needed, so all the control information is kept in head skb only.
It seems this is a wrong place for the flags copying - you set the flags only for the first skb, bu all the skbs must have the flag. You should do very similar things as we propagate skb->mark
: the first newly allocated skb gets mark
from the original skb at the first ss_skb_queue_coalesce_tail()
call in ss_skb_unroll_slow()
. Next, we copy the mark
to all frags f_skb
and they pass the mark
to any newly allocated skb if necessary.
tempesta_fw/tls.c
Outdated
int r; | ||
TlsCtx *tls = tfw_tls_context(c); | ||
TlsIOCtx *io = &tls->io_out; | ||
|
||
while ((skb = ss_skb_dequeue(&msg->skb_head))) { | ||
if (skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, lovely to see that splice()
sets the flag. Please also investigate MSG_ZEROCOPY
usage in modern kernels (see comment #1217 (comment)) . Please explore the latest kernel for the flag and at least write a comment what should we do if a application server uses it for sending us the data. The comment will be very helpful for further migration to newer kernel and we won't forget about the problem.
BTW @ikoveshnikov is right in #1217 (comment) : we should copy only response body for cached responses, headers are copied anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, SKBTX_DEV_ZEROCOPY
is set when MSG_ZEROCOPY is used:
static inline struct ubuf_info *skb_zcopy(struct sk_buff *skb)
{
bool is_zcopy = skb && skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY;
return is_zcopy ? skb_uarg(skb) : NULL;
}
#define SKBTX_ZEROCOPY_FRAG (SKBTX_DEV_ZEROCOPY | SKBTX_SHARED_FRAG)
So, maybe we should check for SKBTX_ZEROCOPY_FRAG
rather than only for SKBTX_SHARED_FRAG
?
tempesta_fw/tls.c
Outdated
{ | ||
int i; | ||
struct sk_buff *frag_iter; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a comment why don't we need to copy skb head.
tempesta_fw/tls.c
Outdated
|
||
p = skb_frag_page(f); | ||
order = get_order(frag_size); | ||
p2 = alloc_pages(__GFP_MEMALLOC, order); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're in softirq, so GFP_ATOMIC
must be used instead
tempesta_fw/tls.c
Outdated
goto err; | ||
vaddr = kmap_atomic(p); | ||
vaddr2 = kmap_atomic(p2); | ||
memcpy(vaddr2, vaddr + f->page_offset, frag_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memcpy()
sucks, we can and should use memcpy_fast()
tempesta_fw/tls.c
Outdated
vaddr2 = kmap_atomic(p2); | ||
memcpy(vaddr2, vaddr + f->page_offset, frag_size); | ||
kunmap_atomic(vaddr2); | ||
kunmap_atomic(vaddr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're in softirq, so there is no preemtion or page faults, so it's safe just to use page_address()
.
491f99c
to
7b8806e
Compare
sendfile()
is usedsendfile()
is used or response from cache
sendfile()
is used or response from cachesendfile()
is used or response from cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some comments about the code. See below.
GFP_ATOMIC); | ||
if (!pages) { | ||
T_WARN("cannot alloc memory.\n"); | ||
return -ENOMEM; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memory leak happens here. In case of the error, the out_sgt.sgl
wouldn't be freed.
33089bf
to
3de5b27
Compare
sendfile()
is used or response from cachesendfile()
or MSG_ZEROCOPY
is used or response from cache
DONE |
tempesta_fw/cache.c
Outdated
@@ -1579,6 +1579,9 @@ tfw_cache_build_resp(TfwHttpReq *req, TfwCacheEntry *ce) | |||
if (tfw_cache_build_resp_body(db, resp, trec, &it, p)) | |||
goto err; | |||
|
|||
if (TFW_CONN_TLS(req->conn)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should happen right after the response object is allocated in tfw_cache_build_resp()
function, i.e. after tfw_http_msg_setup()
. Please add a comment here, why the flag is added and which problem it solves.
And we have problem here, only very first skb is marked with the flag, all the following skbs in the message won't have the flag. Bit in the same time huge responses may require more than one skb. Seems like we should care of this case in tfw_msg_iter_append_skb()
function.
7fa1ce8
to
284a8d0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to revert to SKBTX_SHARED_FRAG
, since we don't handle working with user pages yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
All comments from the review were addressed.
sendfile()
or MSG_ZEROCOPY
is used or response from cachesendfile()
is used or response from cache
d55621e
to
2ce2672
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tempesta_fw/tls.c
Outdated
if (!pages) { | ||
T_WARN("cannot alloc memory.\n"); | ||
r = -ENOMEM; | ||
goto err_pages_alloc; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic allocation is relatively heavy operation and I see no reason to call kmalloc()
3 times - you free all the allocations at the same time.
tempesta_fw/tls.c
Outdated
if (r <= 0) | ||
goto out; | ||
out_frags += r; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tfw_tls_encrypt()
is already overloaded function and the code just prepares memory for encrypted data, so it could make sense to move it to separate function in ss_skb
. However, I'm not sure how many local variables are used - if the function must accept more than standard 6 arguments, them let's leave with the current code.
tempesta_fw/tls.c
Outdated
ttls_aad2hdriv(xfrm, skb->data); | ||
|
||
spin_unlock(&tls->lock); | ||
|
||
for (i = 0; i < elt; ++i) { | ||
put_page(pages[i]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not need braces for single line code blocks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
backport tls encrypting in new sk_buff pages, if `sendfile()` is used or response from cache, from #1264 to release 0.6 branch
#1217
Transfer the
tx_flags
to the newskb_buff
and encrypt in the newsk_buff
pages if SKBTX_SHARED_FRAG is set or response from cache when send response via https.