net/sched: act_ct: Support restoring conntrack info on skbs

Provide an API to restore the ct state pointer.

This may be used by drivers to restore the ct state if they
miss in tc chain after they already did the hardware connection
tracking action (ct_metadata action).

For example, consider the following rule on chain 0 that is in_hw,
however chain 1 is not_in_hw:

$ tc filter add dev ... chain 0 ... \
  flower ... action ct pipe action goto chain 1

Packets of a flow offloaded (via nf flow table offload) by the driver
hit this rule in hardware, will be marked with the ct metadata action
(mark, label, zone) that does the equivalent of the software ct action,
and when the packet jumps to hardware chain 1, there would be a miss.

CT was already processed in hardware. Therefore, the driver's miss
handling should restore the ct state on the skb, using the provided API,
and continue the packet processing in chain 1.

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Paul Blakey 2020-03-12 12:23:07 +02:00 коммит произвёл David S. Miller
Родитель 9c26ba9b1f
Коммит 30b0cf90c6
3 изменённых файлов: 24 добавлений и 0 удалений

Просмотреть файл

@ -227,6 +227,7 @@ struct flow_action_entry {
u16 zone;
} ct;
struct {
unsigned long cookie;
u32 mark;
u32 labels[4];
} ct_metadata;

Просмотреть файл

@ -55,6 +55,13 @@ static inline uint16_t tcf_ct_zone(const struct tc_action *a) { return 0; }
static inline int tcf_ct_action(const struct tc_action *a) { return 0; }
#endif /* CONFIG_NF_CONNTRACK */
#if IS_ENABLED(CONFIG_NET_ACT_CT)
void tcf_ct_flow_table_restore_skb(struct sk_buff *skb, unsigned long cookie);
#else
static inline void
tcf_ct_flow_table_restore_skb(struct sk_buff *skb, unsigned long cookie) { }
#endif
static inline bool is_tcf_ct(const struct tc_action *a)
{
#if defined(CONFIG_NET_CLS_ACT) && IS_ENABLED(CONFIG_NF_CONNTRACK)

Просмотреть файл

@ -170,6 +170,7 @@ static void tcf_ct_flow_table_add_action_meta(struct nf_conn *ct,
{
struct nf_conn_labels *ct_labels;
struct flow_action_entry *entry;
enum ip_conntrack_info ctinfo;
u32 *act_ct_labels;
entry = tcf_ct_flow_table_flow_action_get_next(action);
@ -177,6 +178,10 @@ static void tcf_ct_flow_table_add_action_meta(struct nf_conn *ct,
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
entry->ct_metadata.mark = ct->mark;
#endif
ctinfo = dir == IP_CT_DIR_ORIGINAL ? IP_CT_ESTABLISHED :
IP_CT_ESTABLISHED_REPLY;
/* aligns with the CT reference on the SKB nf_ct_set */
entry->ct_metadata.cookie = (unsigned long)ct | ctinfo;
act_ct_labels = entry->ct_metadata.labels;
ct_labels = nf_ct_labels_find(ct);
@ -1530,6 +1535,17 @@ static void __exit ct_cleanup_module(void)
destroy_workqueue(act_ct_wq);
}
void tcf_ct_flow_table_restore_skb(struct sk_buff *skb, unsigned long cookie)
{
enum ip_conntrack_info ctinfo = cookie & NFCT_INFOMASK;
struct nf_conn *ct;
ct = (struct nf_conn *)(cookie & NFCT_PTRMASK);
nf_conntrack_get(&ct->ct_general);
nf_ct_set(skb, ct, ctinfo);
}
EXPORT_SYMBOL_GPL(tcf_ct_flow_table_restore_skb);
module_init(ct_init_module);
module_exit(ct_cleanup_module);
MODULE_AUTHOR("Paul Blakey <paulb@mellanox.com>");