OvS ct action has this 'force' flag, which basically forces ConnTrack to consider that this packet, this specific direction, is the original one.
Implement that similarly: if the ct entry is there and the direction is not the expected one, destroy it and create a new one. Signed-off-by: Marcelo Ricardo Leitner <mleit...@redhat.com> --- include/uapi/linux/tc_act/tc_ct.h | 1 + net/sched/act_ct.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/tc_act/tc_ct.h b/include/uapi/linux/tc_act/tc_ct.h index 37b95cda1dedd283b0244a03a20860ba22966dfa..009e53ee83fb3125bc5c4ca86954af3bf6a0287a 100644 --- a/include/uapi/linux/tc_act/tc_ct.h +++ b/include/uapi/linux/tc_act/tc_ct.h @@ -25,6 +25,7 @@ enum { enum { TC_CT_COMMIT, + TC_CT_FORCE, __TC_CT_MAX }; #define TC_CT_MAX (__TC_CT_MAX - 1) diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index f69509954149a0c8be710916a5289a4448049b5d..8a1b5d6a7cd8360c50011d992368464db213a020 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -165,6 +165,7 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_ct *p = to_tcf_ct(a); + enum ip_conntrack_info ctinfo; struct nf_hook_state state = { .hook = NF_INET_PRE_ROUTING, }; @@ -173,6 +174,8 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a, int action, err; int nh_ofs; + /* Again needs to be here because we need a new ref on the ct. */ +again: spin_lock(&p->tcf_lock); tcf_lastuse_update(&p->tcf_tm); @@ -218,8 +221,19 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a, if (err != NF_ACCEPT) goto drop; - new_ct = (struct nf_conn *)skb_nfct(skb); + new_ct = nf_ct_get(skb, &ctinfo); if (new_ct) { + /* Force conntrack entry direction. */ + if (flags & BIT(TC_CT_FORCE) && + CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) { + if (nf_ct_is_confirmed(new_ct)) + nf_ct_delete(new_ct, 0, 0); + + nf_conntrack_put(&new_ct->ct_general); + nf_ct_set(skb, NULL, 0); + goto again; + } + if (mark_mask) { new_ct->mark = (new_ct->mark &~ mark_mask) | (mark & mark_mask); if (nf_ct_is_confirmed(new_ct)) -- 2.20.1