netfilter: ctnetlink: add callbacks to the per-proto nlattrs
Holger Eitzenberger [Wed, 25 Mar 2009 17:24:48 +0000 (18:24 +0100)]
There is added a single callback for the l3 proto helper.  The two
callbacks for the l4 protos are necessary because of the general
structure of a ctnetlink event, which is in short:

 CTA_TUPLE_ORIG
   <l3/l4-proto-attributes>
 CTA_TUPLE_REPLY
   <l3/l4-proto-attributes>
 CTA_ID
 ...
 CTA_PROTOINFO
   <l4-proto-attributes>
 CTA_TUPLE_MASTER
   <l3/l4-proto-attributes>

Therefore the formular is

 size := sizeof(generic-nlas) + 3 * sizeof(tuple_nlas) + sizeof(protoinfo_nlas)

Some of the NLAs are optional, e. g. CTA_TUPLE_MASTER, which is only
set if it's an expected connection.  But the number of optional NLAs is
small enough to prevent netlink_trim() from reallocating if calculated
properly.

Signed-off-by: Holger Eitzenberger <holger@eitzenberger.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>

include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_conntrack_l4proto.h
net/netfilter/nf_conntrack_proto.c

index 0378676..9f99d36 100644 (file)
@@ -53,10 +53,17 @@ struct nf_conntrack_l3proto
        int (*tuple_to_nlattr)(struct sk_buff *skb,
                               const struct nf_conntrack_tuple *t);
 
+       /*
+        * Calculate size of tuple nlattr
+        */
+       int (*nlattr_tuple_size)(void);
+
        int (*nlattr_to_tuple)(struct nlattr *tb[],
                               struct nf_conntrack_tuple *t);
        const struct nla_policy *nla_policy;
 
+       size_t nla_size;
+
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *ctl_table_header;
        struct ctl_path         *ctl_table_path;
index b01070b..a120990 100644 (file)
@@ -64,16 +64,22 @@ struct nf_conntrack_l4proto
        /* convert protoinfo to nfnetink attributes */
        int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
                         const struct nf_conn *ct);
+       /* Calculate protoinfo nlattr size */
+       int (*nlattr_size)(void);
 
        /* convert nfnetlink attributes to protoinfo */
        int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct);
 
        int (*tuple_to_nlattr)(struct sk_buff *skb,
                               const struct nf_conntrack_tuple *t);
+       /* Calculate tuple nlattr size */
+       int (*nlattr_tuple_size)(void);
        int (*nlattr_to_tuple)(struct nlattr *tb[],
                               struct nf_conntrack_tuple *t);
        const struct nla_policy *nla_policy;
 
+       size_t nla_size;
+
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header **ctl_table_header;
        struct ctl_table        *ctl_table;
index 9a62b4e..1a4568b 100644 (file)
@@ -167,6 +167,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
        if (proto->l3proto >= AF_MAX)
                return -EBUSY;
 
+       if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size)
+               return -EINVAL;
+
        mutex_lock(&nf_ct_proto_mutex);
        if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) {
                ret = -EBUSY;
@@ -177,6 +180,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
        if (ret < 0)
                goto out_unlock;
 
+       if (proto->nlattr_tuple_size)
+               proto->nla_size = 3 * proto->nlattr_tuple_size();
+
        rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
 
 out_unlock:
@@ -263,6 +269,10 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
        if (l4proto->l3proto >= PF_MAX)
                return -EBUSY;
 
+       if ((l4proto->to_nlattr && !l4proto->nlattr_size)
+               || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
+               return -EINVAL;
+
        mutex_lock(&nf_ct_proto_mutex);
        if (!nf_ct_protos[l4proto->l3proto]) {
                /* l3proto may be loaded latter. */
@@ -290,6 +300,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
        if (ret < 0)
                goto out_unlock;
 
+       l4proto->nla_size = 0;
+       if (l4proto->nlattr_size)
+               l4proto->nla_size += l4proto->nlattr_size();
+       if (l4proto->nlattr_tuple_size)
+               l4proto->nla_size += 3 * l4proto->nlattr_tuple_size();
+
        rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
                           l4proto);