Skip to content

Commit b8e1426

Browse files
author
Herton R. Krzesinski
committed
Merge: net: add helper support in tc act_ct for ovs offloading
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/1967 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2106859 Tested: bz reproducer I didn't backport the cleanups in upstream patchset of: "net: eliminate the duplicate code in the ct nat functions of ovs and tc" as some of the patches have been already in: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/1932 I may do the rest backport for the cleanups when that MR is merged. Signed-off-by: Xin Long <lxin@redhat.com> Approved-by: Aaron Conole <aconole@redhat.com> Approved-by: Marcelo Ricardo Leitner <mleitner@redhat.com> Approved-by: Andrea Claudi <aclaudi@redhat.com> Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
2 parents c8cedca + a1435b6 commit b8e1426

File tree

6 files changed

+214
-124
lines changed

6 files changed

+214
-124
lines changed

include/net/netfilter/nf_conntrack_helper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
115115
int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
116116
gfp_t flags);
117117

118+
int nf_ct_helper(struct sk_buff *skb, struct nf_conn *ct,
119+
enum ip_conntrack_info ctinfo, u16 proto);
120+
int nf_ct_add_helper(struct nf_conn *ct, const char *name, u8 family,
121+
u8 proto, bool nat, struct nf_conntrack_helper **hp);
122+
118123
void nf_ct_helper_destroy(struct nf_conn *ct);
119124

120125
static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)

include/net/tc_act/tc_ct.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <net/netfilter/nf_conntrack_labels.h>
1111

1212
struct tcf_ct_params {
13+
struct nf_conntrack_helper *helper;
1314
struct nf_conn *tmpl;
1415
u16 zone;
1516

include/uapi/linux/tc_act/tc_ct.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ enum {
2222
TCA_CT_NAT_PORT_MIN, /* be16 */
2323
TCA_CT_NAT_PORT_MAX, /* be16 */
2424
TCA_CT_PAD,
25+
TCA_CT_HELPER_NAME, /* string */
26+
TCA_CT_HELPER_FAMILY, /* u8 */
27+
TCA_CT_HELPER_PROTO, /* u8 */
2528
__TCA_CT_MAX
2629
};
2730

net/netfilter/nf_conntrack_helper.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
#include <net/netfilter/nf_conntrack_extend.h>
2727
#include <net/netfilter/nf_conntrack_helper.h>
2828
#include <net/netfilter/nf_conntrack_l4proto.h>
29+
#include <net/netfilter/nf_conntrack_seqadj.h>
2930
#include <net/netfilter/nf_log.h>
31+
#include <net/ip.h>
3032

3133
static DEFINE_MUTEX(nf_ct_helper_mutex);
3234
struct hlist_head *nf_ct_helper_hash __read_mostly;
@@ -287,6 +289,104 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
287289
}
288290
EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
289291

292+
/* 'skb' should already be pulled to nh_ofs. */
293+
int nf_ct_helper(struct sk_buff *skb, struct nf_conn *ct,
294+
enum ip_conntrack_info ctinfo, u16 proto)
295+
{
296+
const struct nf_conntrack_helper *helper;
297+
const struct nf_conn_help *help;
298+
unsigned int protoff;
299+
int err;
300+
301+
if (ctinfo == IP_CT_RELATED_REPLY)
302+
return NF_ACCEPT;
303+
304+
help = nfct_help(ct);
305+
if (!help)
306+
return NF_ACCEPT;
307+
308+
helper = rcu_dereference(help->helper);
309+
if (!helper)
310+
return NF_ACCEPT;
311+
312+
if (helper->tuple.src.l3num != NFPROTO_UNSPEC &&
313+
helper->tuple.src.l3num != proto)
314+
return NF_ACCEPT;
315+
316+
switch (proto) {
317+
case NFPROTO_IPV4:
318+
protoff = ip_hdrlen(skb);
319+
proto = ip_hdr(skb)->protocol;
320+
break;
321+
case NFPROTO_IPV6: {
322+
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
323+
__be16 frag_off;
324+
int ofs;
325+
326+
ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
327+
&frag_off);
328+
if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
329+
pr_debug("proto header not found\n");
330+
return NF_ACCEPT;
331+
}
332+
protoff = ofs;
333+
proto = nexthdr;
334+
break;
335+
}
336+
default:
337+
WARN_ONCE(1, "helper invoked on non-IP family!");
338+
return NF_DROP;
339+
}
340+
341+
if (helper->tuple.dst.protonum != proto)
342+
return NF_ACCEPT;
343+
344+
err = helper->help(skb, protoff, ct, ctinfo);
345+
if (err != NF_ACCEPT)
346+
return err;
347+
348+
/* Adjust seqs after helper. This is needed due to some helpers (e.g.,
349+
* FTP with NAT) adusting the TCP payload size when mangling IP
350+
* addresses and/or port numbers in the text-based control connection.
351+
*/
352+
if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
353+
!nf_ct_seq_adjust(skb, ct, ctinfo, protoff))
354+
return NF_DROP;
355+
return NF_ACCEPT;
356+
}
357+
EXPORT_SYMBOL_GPL(nf_ct_helper);
358+
359+
int nf_ct_add_helper(struct nf_conn *ct, const char *name, u8 family,
360+
u8 proto, bool nat, struct nf_conntrack_helper **hp)
361+
{
362+
struct nf_conntrack_helper *helper;
363+
struct nf_conn_help *help;
364+
int ret = 0;
365+
366+
helper = nf_conntrack_helper_try_module_get(name, family, proto);
367+
if (!helper)
368+
return -EINVAL;
369+
370+
help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
371+
if (!help) {
372+
nf_conntrack_helper_put(helper);
373+
return -ENOMEM;
374+
}
375+
#if IS_ENABLED(CONFIG_NF_NAT)
376+
if (nat) {
377+
ret = nf_nat_helper_try_module_get(name, family, proto);
378+
if (ret) {
379+
nf_conntrack_helper_put(helper);
380+
return ret;
381+
}
382+
}
383+
#endif
384+
rcu_assign_pointer(help->helper, helper);
385+
*hp = helper;
386+
return ret;
387+
}
388+
EXPORT_SYMBOL_GPL(nf_ct_add_helper);
389+
290390
/* appropriate ct lock protecting must be taken by caller */
291391
static int unhelp(struct nf_conn *ct, void *me)
292392
{

net/openvswitch/conntrack.c

Lines changed: 6 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -434,65 +434,6 @@ static int ovs_ct_set_labels(struct nf_conn *ct, struct sw_flow_key *key,
434434
return 0;
435435
}
436436

437-
/* 'skb' should already be pulled to nh_ofs. */
438-
static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
439-
{
440-
const struct nf_conntrack_helper *helper;
441-
const struct nf_conn_help *help;
442-
enum ip_conntrack_info ctinfo;
443-
unsigned int protoff;
444-
struct nf_conn *ct;
445-
int err;
446-
447-
ct = nf_ct_get(skb, &ctinfo);
448-
if (!ct || ctinfo == IP_CT_RELATED_REPLY)
449-
return NF_ACCEPT;
450-
451-
help = nfct_help(ct);
452-
if (!help)
453-
return NF_ACCEPT;
454-
455-
helper = rcu_dereference(help->helper);
456-
if (!helper)
457-
return NF_ACCEPT;
458-
459-
switch (proto) {
460-
case NFPROTO_IPV4:
461-
protoff = ip_hdrlen(skb);
462-
break;
463-
case NFPROTO_IPV6: {
464-
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
465-
__be16 frag_off;
466-
int ofs;
467-
468-
ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
469-
&frag_off);
470-
if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
471-
pr_debug("proto header not found\n");
472-
return NF_ACCEPT;
473-
}
474-
protoff = ofs;
475-
break;
476-
}
477-
default:
478-
WARN_ONCE(1, "helper invoked on non-IP family!");
479-
return NF_DROP;
480-
}
481-
482-
err = helper->help(skb, protoff, ct, ctinfo);
483-
if (err != NF_ACCEPT)
484-
return err;
485-
486-
/* Adjust seqs after helper. This is needed due to some helpers (e.g.,
487-
* FTP with NAT) adusting the TCP payload size when mangling IP
488-
* addresses and/or port numbers in the text-based control connection.
489-
*/
490-
if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
491-
!nf_ct_seq_adjust(skb, ct, ctinfo, protoff))
492-
return NF_DROP;
493-
return NF_ACCEPT;
494-
}
495-
496437
/* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
497438
* value if 'skb' is freed.
498439
*/
@@ -1035,7 +976,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
1035976
*/
1036977
if ((nf_ct_is_confirmed(ct) ? !cached || add_helper :
1037978
info->commit) &&
1038-
ovs_ct_helper(skb, info->family) != NF_ACCEPT) {
979+
nf_ct_helper(skb, ct, ctinfo, info->family) != NF_ACCEPT) {
1039980
return -EINVAL;
1040981
}
1041982

@@ -1347,43 +1288,6 @@ int ovs_ct_clear(struct sk_buff *skb, struct sw_flow_key *key)
13471288
return 0;
13481289
}
13491290

1350-
static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name,
1351-
const struct sw_flow_key *key, bool log)
1352-
{
1353-
struct nf_conntrack_helper *helper;
1354-
struct nf_conn_help *help;
1355-
int ret = 0;
1356-
1357-
helper = nf_conntrack_helper_try_module_get(name, info->family,
1358-
key->ip.proto);
1359-
if (!helper) {
1360-
OVS_NLERR(log, "Unknown helper \"%s\"", name);
1361-
return -EINVAL;
1362-
}
1363-
1364-
help = nf_ct_helper_ext_add(info->ct, GFP_KERNEL);
1365-
if (!help) {
1366-
nf_conntrack_helper_put(helper);
1367-
return -ENOMEM;
1368-
}
1369-
1370-
#if IS_ENABLED(CONFIG_NF_NAT)
1371-
if (info->nat) {
1372-
ret = nf_nat_helper_try_module_get(name, info->family,
1373-
key->ip.proto);
1374-
if (ret) {
1375-
nf_conntrack_helper_put(helper);
1376-
OVS_NLERR(log, "Failed to load \"%s\" NAT helper, error: %d",
1377-
name, ret);
1378-
return ret;
1379-
}
1380-
}
1381-
#endif
1382-
rcu_assign_pointer(help->helper, helper);
1383-
info->helper = helper;
1384-
return ret;
1385-
}
1386-
13871291
#if IS_ENABLED(CONFIG_NF_NAT)
13881292
static int parse_nat(const struct nlattr *attr,
13891293
struct ovs_conntrack_info *info, bool log)
@@ -1717,9 +1621,12 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
17171621
}
17181622

17191623
if (helper) {
1720-
err = ovs_ct_add_helper(&ct_info, helper, key, log);
1721-
if (err)
1624+
err = nf_ct_add_helper(ct_info.ct, helper, ct_info.family,
1625+
key->ip.proto, ct_info.nat, &ct_info.helper);
1626+
if (err) {
1627+
OVS_NLERR(log, "Failed to add %s helper %d", helper, err);
17221628
goto err_free_ct;
1629+
}
17231630
}
17241631

17251632
err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info,

0 commit comments

Comments
 (0)