]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/openvswitch/conntrack.c
netfilter: replace NF_NAT_NEEDED with IS_ENABLED(CONFIG_NF_NAT)
[linux.git] / net / openvswitch / conntrack.c
index 1b6896896fff35ff8f3640ece128cf5a7e30c0dd..6266299444500a83f31ec16101ef977da484f7a3 100644 (file)
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_labels.h>
 #include <net/netfilter/nf_conntrack_seqadj.h>
+#include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 #include <net/ipv6_frag.h>
 
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
 #include <net/netfilter/nf_nat.h>
 #endif
 
@@ -73,7 +74,8 @@ struct ovs_conntrack_info {
        u32 eventmask;              /* Mask of 1 << IPCT_*. */
        struct md_mark mark;
        struct md_labels labels;
-#ifdef CONFIG_NF_NAT_NEEDED
+       char timeout[CTNL_TIMEOUT_NAME_MAX];
+#if IS_ENABLED(CONFIG_NF_NAT)
        struct nf_nat_range2 range;  /* Only present for SRC NAT and DST NAT. */
 #endif
 };
@@ -719,7 +721,7 @@ static bool skb_nfct_cached(struct net *net,
        return ct_executed;
 }
 
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
 /* Modelled after nf_nat_ipv[46]_fn().
  * range is only used for new, uninitialized NAT state.
  * Returns either NF_ACCEPT or NF_DROP.
@@ -901,7 +903,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
 
        return err;
 }
-#else /* !CONFIG_NF_NAT_NEEDED */
+#else /* !CONFIG_NF_NAT */
 static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
                      const struct ovs_conntrack_info *info,
                      struct sk_buff *skb, struct nf_conn *ct,
@@ -990,6 +992,12 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
                                                            GFP_ATOMIC);
                        if (err)
                                return err;
+
+                       /* helper installed, add seqadj if NAT is required */
+                       if (info->nat && !nfct_seqadj(ct)) {
+                               if (!nfct_seqadj_ext_add(ct))
+                                       return -EINVAL;
+                       }
                }
 
                /* Call the helper only if:
@@ -1322,7 +1330,7 @@ static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name,
        return 0;
 }
 
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
 static int parse_nat(const struct nlattr *attr,
                     struct ovs_conntrack_info *info, bool log)
 {
@@ -1459,12 +1467,14 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
                                    .maxlen = sizeof(struct md_labels) },
        [OVS_CT_ATTR_HELPER]    = { .minlen = 1,
                                    .maxlen = NF_CT_HELPER_NAME_LEN },
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
        /* NAT length is checked when parsing the nested attributes. */
        [OVS_CT_ATTR_NAT]       = { .minlen = 0, .maxlen = INT_MAX },
 #endif
        [OVS_CT_ATTR_EVENTMASK] = { .minlen = sizeof(u32),
                                    .maxlen = sizeof(u32) },
+       [OVS_CT_ATTR_TIMEOUT] = { .minlen = 1,
+                                 .maxlen = CTNL_TIMEOUT_NAME_MAX },
 };
 
 static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
@@ -1537,7 +1547,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                                return -EINVAL;
                        }
                        break;
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
                case OVS_CT_ATTR_NAT: {
                        int err = parse_nat(a, info, log);
 
@@ -1550,6 +1560,15 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                        info->have_eventmask = true;
                        info->eventmask = nla_get_u32(a);
                        break;
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+               case OVS_CT_ATTR_TIMEOUT:
+                       memcpy(info->timeout, nla_data(a), nla_len(a));
+                       if (!memchr(info->timeout, '\0', nla_len(a))) {
+                               OVS_NLERR(log, "Invalid conntrack helper");
+                               return -EINVAL;
+                       }
+                       break;
+#endif
 
                default:
                        OVS_NLERR(log, "Unknown conntrack attr (%d)",
@@ -1631,6 +1650,14 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
                OVS_NLERR(log, "Failed to allocate conntrack template");
                return -ENOMEM;
        }
+
+       if (ct_info.timeout[0]) {
+               if (nf_ct_set_timeout(net, ct_info.ct, family, key->ip.proto,
+                                     ct_info.timeout))
+                       pr_info_ratelimited("Failed to associated timeout "
+                                           "policy `%s'\n", ct_info.timeout);
+       }
+
        if (helper) {
                err = ovs_ct_add_helper(&ct_info, helper, key, log);
                if (err)
@@ -1650,7 +1677,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
        return err;
 }
 
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
 static bool ovs_ct_nat_to_attr(const struct ovs_conntrack_info *info,
                               struct sk_buff *skb)
 {
@@ -1751,8 +1778,12 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
        if (ct_info->have_eventmask &&
            nla_put_u32(skb, OVS_CT_ATTR_EVENTMASK, ct_info->eventmask))
                return -EMSGSIZE;
+       if (ct_info->timeout[0]) {
+               if (nla_put_string(skb, OVS_CT_ATTR_TIMEOUT, ct_info->timeout))
+                       return -EMSGSIZE;
+       }
 
-#ifdef CONFIG_NF_NAT_NEEDED
+#if IS_ENABLED(CONFIG_NF_NAT)
        if (ct_info->nat && !ovs_ct_nat_to_attr(ct_info, skb))
                return -EMSGSIZE;
 #endif
@@ -1772,8 +1803,11 @@ static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)
 {
        if (ct_info->helper)
                nf_conntrack_helper_put(ct_info->helper);
-       if (ct_info->ct)
+       if (ct_info->ct) {
+               if (ct_info->timeout[0])
+                       nf_ct_destroy_timeout(ct_info->ct);
                nf_ct_tmpl_free(ct_info->ct);
+       }
 }
 
 #if    IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
@@ -2154,18 +2188,15 @@ static struct genl_ops ct_limit_genl_ops[] = {
        { .cmd = OVS_CT_LIMIT_CMD_SET,
                .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN
                                           * privilege. */
-               .policy = ct_limit_policy,
                .doit = ovs_ct_limit_cmd_set,
        },
        { .cmd = OVS_CT_LIMIT_CMD_DEL,
                .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN
                                           * privilege. */
-               .policy = ct_limit_policy,
                .doit = ovs_ct_limit_cmd_del,
        },
        { .cmd = OVS_CT_LIMIT_CMD_GET,
                .flags = 0,               /* OK for unprivileged users. */
-               .policy = ct_limit_policy,
                .doit = ovs_ct_limit_cmd_get,
        },
 };
@@ -2179,6 +2210,7 @@ struct genl_family dp_ct_limit_genl_family __ro_after_init = {
        .name = OVS_CT_LIMIT_FAMILY,
        .version = OVS_CT_LIMIT_VERSION,
        .maxattr = OVS_CT_LIMIT_ATTR_MAX,
+       .policy = ct_limit_policy,
        .netnsok = true,
        .parallel_ops = true,
        .ops = ct_limit_genl_ops,