Skip to content

Commit 6a9bad0

Browse files
w1ldptrdavem330
authored andcommitted
net/sched: act_ct: offload UDP NEW connections
Modify the offload algorithm of UDP connections to the following: - Offload NEW connection as unidirectional. - When connection state changes to ESTABLISHED also update the hardware flow. However, in order to prevent act_ct from spamming offload add wq for every packet coming in reply direction in this state verify whether connection has already been updated to ESTABLISHED in the drivers. If that it the case, then skip flow_table and let conntrack handle such packets which will also allow conntrack to potentially promote the connection to ASSURED. - When connection state changes to ASSURED set the flow_table flow NF_FLOW_HW_BIDIRECTIONAL flag which will cause refresh mechanism to offload the reply direction. All other protocols have their offload algorithm preserved and are always offloaded as bidirectional. Note that this change tries to minimize the load on flow_table add workqueue. First, it tracks the last ctinfo that was offloaded by using new flow 'NF_FLOW_HW_ESTABLISHED' flag and doesn't schedule the refresh for reply direction packets when the offloads have already been updated with current ctinfo. Second, when 'add' task executes on workqueue it always update the offload with current flow state (by checking 'bidirectional' flow flag and obtaining actual ctinfo/cookie through meta action instead of caching any of these from the moment of scheduling the 'add' work) preventing the need from scheduling more updates if state changed concurrently while the 'add' work was pending on workqueue. Signed-off-by: Vlad Buslov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d5774cb commit 6a9bad0

File tree

1 file changed

+39
-12
lines changed

1 file changed

+39
-12
lines changed

net/sched/act_ct.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ static void tcf_ct_flow_tc_ifidx(struct flow_offload *entry,
369369

370370
static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
371371
struct nf_conn *ct,
372-
bool tcp)
372+
bool tcp, bool bidirectional)
373373
{
374374
struct nf_conn_act_ct_ext *act_ct_ext;
375375
struct flow_offload *entry;
@@ -388,6 +388,8 @@ static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
388388
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
389389
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
390390
}
391+
if (bidirectional)
392+
__set_bit(NF_FLOW_HW_BIDIRECTIONAL, &entry->flags);
391393

392394
act_ct_ext = nf_conn_act_ct_ext_find(ct);
393395
if (act_ct_ext) {
@@ -411,26 +413,34 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
411413
struct nf_conn *ct,
412414
enum ip_conntrack_info ctinfo)
413415
{
414-
bool tcp = false;
415-
416-
if ((ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY) ||
417-
!test_bit(IPS_ASSURED_BIT, &ct->status))
418-
return;
416+
bool tcp = false, bidirectional = true;
419417

420418
switch (nf_ct_protonum(ct)) {
421419
case IPPROTO_TCP:
422-
tcp = true;
423-
if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
420+
if ((ctinfo != IP_CT_ESTABLISHED &&
421+
ctinfo != IP_CT_ESTABLISHED_REPLY) ||
422+
!test_bit(IPS_ASSURED_BIT, &ct->status) ||
423+
ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
424424
return;
425+
426+
tcp = true;
425427
break;
426428
case IPPROTO_UDP:
429+
if (!nf_ct_is_confirmed(ct))
430+
return;
431+
if (!test_bit(IPS_ASSURED_BIT, &ct->status))
432+
bidirectional = false;
427433
break;
428434
#ifdef CONFIG_NF_CT_PROTO_GRE
429435
case IPPROTO_GRE: {
430436
struct nf_conntrack_tuple *tuple;
431437

432-
if (ct->status & IPS_NAT_MASK)
438+
if ((ctinfo != IP_CT_ESTABLISHED &&
439+
ctinfo != IP_CT_ESTABLISHED_REPLY) ||
440+
!test_bit(IPS_ASSURED_BIT, &ct->status) ||
441+
ct->status & IPS_NAT_MASK)
433442
return;
443+
434444
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
435445
/* No support for GRE v1 */
436446
if (tuple->src.u.gre.key || tuple->dst.u.gre.key)
@@ -446,7 +456,7 @@ static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
446456
ct->status & IPS_SEQ_ADJUST)
447457
return;
448458

449-
tcf_ct_flow_table_add(ct_ft, ct, tcp);
459+
tcf_ct_flow_table_add(ct_ft, ct, tcp, bidirectional);
450460
}
451461

452462
static bool
@@ -625,13 +635,30 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
625635
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
626636
ct = flow->ct;
627637

638+
if (dir == FLOW_OFFLOAD_DIR_REPLY &&
639+
!test_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags)) {
640+
/* Only offload reply direction after connection became
641+
* assured.
642+
*/
643+
if (test_bit(IPS_ASSURED_BIT, &ct->status))
644+
set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
645+
else if (test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags))
646+
/* If flow_table flow has already been updated to the
647+
* established state, then don't refresh.
648+
*/
649+
return false;
650+
}
651+
628652
if (tcph && (unlikely(tcph->fin || tcph->rst))) {
629653
flow_offload_teardown(flow);
630654
return false;
631655
}
632656

633-
ctinfo = dir == FLOW_OFFLOAD_DIR_ORIGINAL ? IP_CT_ESTABLISHED :
634-
IP_CT_ESTABLISHED_REPLY;
657+
if (dir == FLOW_OFFLOAD_DIR_ORIGINAL)
658+
ctinfo = test_bit(IPS_SEEN_REPLY_BIT, &ct->status) ?
659+
IP_CT_ESTABLISHED : IP_CT_NEW;
660+
else
661+
ctinfo = IP_CT_ESTABLISHED_REPLY;
635662

636663
flow_offload_refresh(nf_ft, flow);
637664
nf_conntrack_get(&ct->ct_general);

0 commit comments

Comments
 (0)