On Sun, May 05, 2019 at 05:40:16PM +0200, Stéphane Veyret wrote:
> This patch allows to add, list and delete expectations via nft objref
> infrastructure and assigning these expectations via nft rule.

Please, add to your patch title your patch version, ie.

[PATCH nf-next,v2] nft_ct: add ct expectations support

Could you describe the usecase example for this infrastructure, please?

More comments below.

> Signed-off-by: Stéphane Veyret <svey...@gmail.com>
> ---
>  include/uapi/linux/netfilter/nf_tables.h |  15 ++-
>  net/netfilter/nft_ct.c                   | 124 ++++++++++++++++++++++-
>  2 files changed, 136 insertions(+), 3 deletions(-)
> 
> diff --git a/include/uapi/linux/netfilter/nf_tables.h 
> b/include/uapi/linux/netfilter/nf_tables.h
> index f0cf7b0f4f35..0a3452ca684c 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -968,6 +968,7 @@ enum nft_socket_keys {
>   * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
>   * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack
>   * @NFT_CT_ID: conntrack id
> + * @NFT_CT_EXPECT: connection tracking expectation
>   */
>  enum nft_ct_keys {
>       NFT_CT_STATE,
> @@ -995,6 +996,7 @@ enum nft_ct_keys {
>       NFT_CT_DST_IP6,
>       NFT_CT_TIMEOUT,
>       NFT_CT_ID,
> +     NFT_CT_EXPECT,

You don't this definition, or I don't find where this is used.

>       __NFT_CT_MAX
>  };
>  #define NFT_CT_MAX           (__NFT_CT_MAX - 1)
> @@ -1447,6 +1449,16 @@ enum nft_ct_timeout_timeout_attributes {
>  };
>  #define NFTA_CT_TIMEOUT_MAX  (__NFTA_CT_TIMEOUT_MAX - 1)
>  
> +enum nft_ct_expectation_attributes {
> +     NFTA_CT_EXPECT_UNSPEC,
> +     NFTA_CT_EXPECT_L3PROTO,
> +     NFTA_CT_EXPECT_L4PROTO,
> +     NFTA_CT_EXPECT_DPORT,
> +     NFTA_CT_EXPECT_TIMEOUT,
> +     __NFTA_CT_EXPECT_MAX,
> +};
> +#define NFTA_CT_EXPECT_MAX   (__NFTA_CT_EXPECT_MAX - 1)
> +
>  #define NFT_OBJECT_UNSPEC    0
>  #define NFT_OBJECT_COUNTER   1
>  #define NFT_OBJECT_QUOTA     2
> @@ -1456,7 +1468,8 @@ enum nft_ct_timeout_timeout_attributes {
>  #define NFT_OBJECT_TUNNEL    6
>  #define NFT_OBJECT_CT_TIMEOUT        7
>  #define NFT_OBJECT_SECMARK   8
> -#define __NFT_OBJECT_MAX     9
> +#define NFT_OBJECT_CT_EXPECT 9
> +#define __NFT_OBJECT_MAX     10
>  #define NFT_OBJECT_MAX               (__NFT_OBJECT_MAX - 1)
>  
>  /**
> diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
> index f043936763f3..06c13b2dfb78 100644
> --- a/net/netfilter/nft_ct.c
> +++ b/net/netfilter/nft_ct.c
> @@ -24,6 +24,7 @@
>  #include <net/netfilter/nf_conntrack_labels.h>
>  #include <net/netfilter/nf_conntrack_timeout.h>
>  #include <net/netfilter/nf_conntrack_l4proto.h>
> +#include <net/netfilter/nf_conntrack_expect.h>
>  
>  struct nft_ct {
>       enum nft_ct_keys        key:8;
> @@ -790,6 +791,117 @@ static struct nft_expr_type nft_notrack_type 
> __read_mostly = {
>       .owner          = THIS_MODULE,
>  };
>  
> +struct nft_ct_expect_obj {
> +     int                     l3num;
> +     u8                      l4proto;
> +     __be16          dport;
> +     u32                     timeout;
> +};
> +
> +static int nft_ct_expect_obj_init(const struct nft_ctx *ctx,
> +                                const struct nlattr * const tb[],
> +                                struct nft_object *obj)
> +{
> +     struct nft_ct_expect_obj *priv = nft_obj_data(obj);
> +     int ret;
> +
> +     if (!tb[NFTA_CT_EXPECT_L4PROTO] ||
> +         !tb[NFTA_CT_EXPECT_DPORT])
> +             return -EINVAL;
> +
> +     priv->l3num = ctx->family;
> +     if (tb[NFTA_CT_EXPECT_L3PROTO])
> +             priv->l3num = ntohs(nla_get_be16(tb[NFTA_CT_EXPECT_L3PROTO]));
> +     priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]);
> +
> +     priv->dportmin = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT_MIN]);

Where is NFTA_CT_EXPECT_DPORT_MIN defined? You don't check for this
attribute, it may not be present. Looks like a leftover?

> +
> +     priv->timeout = 0;
> +     if (tb[NFTA_CT_EXPECT_TIMEOUT])
> +             priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]);
> +
> +     ret = nf_ct_netns_get(ctx->net, ctx->family);
> +     if (ret < 0)
> +             return ret;
> +
> +     return 0;
> +}
> +
> +static void nft_ct_expect_obj_destroy(const struct nft_ctx *ctx,
> +                                    struct nft_object *obj)
> +{
> +     nf_ct_netns_put(ctx->net, ctx->family);
> +}
> +
> +static int nft_ct_expect_obj_dump(struct sk_buff *skb,
> +                                struct nft_object *obj, bool reset)
> +{
> +     const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
> +
> +     if (nla_put_be16(skb, NFTA_CT_EXPECT_L3PROTO, htons(priv->l3num)) ||
> +         nla_put_u8(skb, NFTA_CT_EXPECT_L4PROTO, priv->l4proto) ||
> +         nla_put_be16(skb, NFTA_CT_EXPECT_DPORT, priv->dport) ||
> +         nla_put_u32(skb, NFTA_CT_EXPECT_TIMEOUT, priv->timeout))
> +     return -1

This won't compile, missing ';'. Also indentation.

> +
> +     return 0;
> +}
> +
> +static void nft_ct_expect_obj_eval(struct nft_object *obj,
> +                                 struct nft_regs *regs,
> +                                 const struct nft_pktinfo *pkt)
> +{
> +     const struct nft_ct_expect_obj *priv = nft_obj_data(obj);
> +     enum ip_conntrack_info ctinfo;
> +     struct nf_conn *ct = nf_ct_get(pkt->skb, ctinfo);
> +     int dir = CTINFO2DIR(ctinfo);
> +     struct nf_conntrack_expect *exp;
> +
> +     exp = nf_ct_expect_alloc(ct);
> +     if (exp == NULL) {
> +             nf_ct_helper_log(skb, ct, "cannot allocate expectation");
> +             regs->verdict.code = NF_DROP;
> +             return;
> +     }
> +
> +     nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, priv->l3num,
> +             &ct->tuplehash[!dir].tuple.src.u3, 
> &ct->tuplehash[!dir].tuple.dst.u3,
> +             priv->l4proto, NULL, &priv->dport);

Coding style:

        nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, priv->l3num,
                          &ct->tuplehash[!dir].tuple.src.u3,
                          &ct->tuplehash[!dir].tuple.dst.u3,
                          priv->l4proto, NULL, &priv->dport);

> +     if (priv->timeout)
> +             exp->timeout.expires = jiffies + priv->timeout * HZ;

timeout should be made mandatory? why check if it's set?

> +     if (nf_ct_expect_related(exp) != 0) {
> +             nf_ct_helper_log(skb, ct, "cannot add expectation");
> +             regs->verdict.code = NF_DROP;
> +     }
> +}
> +
> +static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX + 1] 
> = {
> +     [NFTA_CT_EXPECT_L3PROTO] = {.type = NLA_U16 },
> +     [NFTA_CT_EXPECT_L4PROTO] = {.type = NLA_U8 },
> +     [NFTA_CT_EXPECT_DPORT] = {.type = NLA_U16 },
> +     [NFTA_CT_EXPECT_TIMEOUT] = {.type = NLA_U32 },

I'd prefer:

        [NFTA_CT_EXPECT_L3PROTO]        = { .type = NLA_U16 },
        [NFTA_CT_EXPECT_L4PROTO]        = { .type = NLA_U8 },
        [NFTA_CT_EXPECT_DPORT]          = { .type = NLA_U16 },
        [NFTA_CT_EXPECT_TIMEOUT]        = { .type = NLA_U32 },

Thanks!

Reply via email to