net/sched: act_ct: Offload established connections to flow table
authorPaul Blakey <paulb@mellanox.com>
Tue, 3 Mar 2020 13:07:50 +0000 (15:07 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 Mar 2020 23:09:12 +0000 (15:09 -0800)
Add a ft entry when connections enter an established state and delete
the connections when they leave the established state.

The flow table assumes ownership of the connection. In the following
patch act_ct will lookup the ct state from the FT. In future patches,
drivers will register for callbacks for ft add/del events and will be
able to use the information to offload the connections.

Note that connection aging is managed by the FT.

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/act_ct.c

index 3321087..2ab3843 100644 (file)
@@ -125,6 +125,67 @@ static void tcf_ct_flow_table_put(struct tcf_ct_params *params)
        spin_unlock_bh(&zones_lock);
 }
 
+static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
+                                 struct nf_conn *ct,
+                                 bool tcp)
+{
+       struct flow_offload *entry;
+       int err;
+
+       if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
+               return;
+
+       entry = flow_offload_alloc(ct);
+       if (!entry) {
+               WARN_ON_ONCE(1);
+               goto err_alloc;
+       }
+
+       if (tcp) {
+               ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+               ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+       }
+
+       err = flow_offload_add(&ct_ft->nf_ft, entry);
+       if (err)
+               goto err_add;
+
+       return;
+
+err_add:
+       flow_offload_free(entry);
+err_alloc:
+       clear_bit(IPS_OFFLOAD_BIT, &ct->status);
+}
+
+static void tcf_ct_flow_table_process_conn(struct tcf_ct_flow_table *ct_ft,
+                                          struct nf_conn *ct,
+                                          enum ip_conntrack_info ctinfo)
+{
+       bool tcp = false;
+
+       if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
+               return;
+
+       switch (nf_ct_protonum(ct)) {
+       case IPPROTO_TCP:
+               tcp = true;
+               if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
+                       return;
+               break;
+       case IPPROTO_UDP:
+               break;
+       default:
+               return;
+       }
+
+       if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
+           ct->status & IPS_SEQ_ADJUST)
+               return;
+
+       tcf_ct_flow_table_add(ct_ft, ct, tcp);
+}
+
 static int tcf_ct_flow_tables_init(void)
 {
        return rhashtable_init(&zones_ht, &zones_params);
@@ -578,6 +639,8 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
                nf_conntrack_confirm(skb);
        }
 
+       tcf_ct_flow_table_process_conn(p->ct_ft, ct, ctinfo);
+
 out_push:
        skb_push_rcsum(skb, nh_ofs);