On Thu, May 23, 2019 at 09:22:11PM +0200, Stéphane Veyret wrote: [...] > diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c > index f043936763f3..d072d3c8e6bc 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,138 @@ 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; > + u8 size; Nit: Reorder to punch out holes in the structure layout, and use appropriate datatypes: u16 l3num; __be16 dport; u8 l4proto; u8 size; 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); > + > + if (!tb[NFTA_CT_EXPECT_L4PROTO] || > + !tb[NFTA_CT_EXPECT_DPORT] || > + !tb[NFTA_CT_EXPECT_TIMEOUT] || > + !tb[NFTA_CT_EXPECT_SIZE]) > + 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->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]); > + priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]); > + priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]); > + > + return nf_ct_netns_get(ctx->net, ctx->family); > +} > + > +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) || > + nla_put_u8(skb, NFTA_CT_EXPECT_SIZE, priv->size)) > + return -1; > + > + 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); > + struct nf_conntrack_expect *exp; > + enum ip_conntrack_info ctinfo; > + int dir; Please use 'enum ip_conntrack_dir' instead of int for "dir". > + struct nf_conn *ct; > + struct nf_conn_help *ct_help; > + int l3num = priv->l3num; Reverse xmas tree for variable definitions: const struct nft_ct_expect_obj *priv = nft_obj_data(obj); struct nf_conntrack_expect *exp; enum ip_conntrack_info ctinfo; struct nf_conn_help *help; int l3num = priv->l3num; struct nf_conn *ct; int dir; >From largest line to smallest. > + > + /* Check ct exists and is tracked */ Please, remove comment. We only use comments when something is not evident to the reader, as a last resort. This forces people to write good code :-) > + ct = nf_ct_get(pkt->skb, &ctinfo); > + if (!ct || ctinfo == IP_CT_UNTRACKED) { > + regs->verdict.code = NFT_BREAK; > + return; > + } > + dir = CTINFO2DIR(ctinfo); > + > + /* ct extention is required */ > + ct_help = nfct_help(ct); > + if (!ct_help) { > + ct_help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); > + } Remove curly braces for single statement. Nitpick: I'd suggest you rename 'ct_help' to 'help', for consistency with other existing codebase. > + > + /* Did we reach the limit? */ No need for comment either. > + if (ct_help->expecting[NF_CT_EXPECT_CLASS_DEFAULT] >= priv->size) { > + regs->verdict.code = NF_DROP; Probably just NFT_BREAK instead of NF_DROP ? > + return; > + } > + > + /* If l3num is set to INET, use the current ct proto */ Remove comment. > + if (l3num == NFPROTO_INET) { > + l3num = nf_ct_l3num(ct); > + } Remove curly for single statement, ie.g if (l3num == NFPROTO_INET) l3num = nf_ct_l3num(ct); > + /* Create expectation */ Remove comment. > + exp = nf_ct_expect_alloc(ct); > + if (exp == NULL) { > + regs->verdict.code = NF_DROP; NF_DROP looks fine in this case, do not change it. > + return; > + } > + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, l3num, > + &ct->tuplehash[!dir].tuple.src.u3, > + &ct->tuplehash[!dir].tuple.dst.u3, > + priv->l4proto, NULL, &priv->dport); > + exp->timeout.expires = jiffies + priv->timeout * HZ; > + if (nf_ct_expect_related(exp) != 0) > + regs->verdict.code = NF_DROP; > +}