Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2732c4e4 authored by Holger Eitzenberger's avatar Holger Eitzenberger Committed by Patrick McHardy
Browse files

netfilter: ctnetlink: allocate right-sized ctnetlink skb



Try to allocate a Netlink skb roughly the size of the actual
message, with the help from the l3 and l4 protocol helpers.
This is all to prevent a reallocation in netlink_trim() later.

The overhead of allocating the right-sized skb is rather small, with
ctnetlink_alloc_skb() actually being inlined away on my x86_64 box.
The size of the per-proto space is determined at registration time of
the protocol helper.

Signed-off-by: default avatarHolger Eitzenberger <holger@eitzenberger.org>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent ea781f19
Loading
Loading
Loading
Loading
+64 −1
Original line number Original line Diff line number Diff line
@@ -405,6 +405,69 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
}
}


#ifdef CONFIG_NF_CONNTRACK_EVENTS
#ifdef CONFIG_NF_CONNTRACK_EVENTS
/*
 * The general structure of a ctnetlink event is
 *
 *  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(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas)
 *		+ sizeof(protoinfo_nlas)
 */
static struct sk_buff *
ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp)
{
	struct nf_conntrack_l3proto *l3proto;
	struct nf_conntrack_l4proto *l4proto;
	int len;

#define NLA_TYPE_SIZE(type)		nla_total_size(sizeof(type))

	/* proto independant part */
	len = NLMSG_SPACE(sizeof(struct nfgenmsg))
		+ 3 * nla_total_size(0)		/* CTA_TUPLE_ORIG|REPL|MASTER */
		+ 3 * nla_total_size(0)		/* CTA_TUPLE_IP */
		+ 3 * nla_total_size(0)		/* CTA_TUPLE_PROTO */
		+ 3 * NLA_TYPE_SIZE(u_int8_t)	/* CTA_PROTO_NUM */
		+ NLA_TYPE_SIZE(u_int32_t)	/* CTA_ID */
		+ NLA_TYPE_SIZE(u_int32_t)	/* CTA_STATUS */
		+ 2 * nla_total_size(0)		/* CTA_COUNTERS_ORIG|REPL */
		+ 2 * NLA_TYPE_SIZE(uint64_t)	/* CTA_COUNTERS_PACKETS */
		+ 2 * NLA_TYPE_SIZE(uint64_t)	/* CTA_COUNTERS_BYTES */
		+ NLA_TYPE_SIZE(u_int32_t)	/* CTA_TIMEOUT */
		+ nla_total_size(0)		/* CTA_PROTOINFO */
		+ nla_total_size(0)		/* CTA_HELP */
		+ nla_total_size(NF_CT_HELPER_NAME_LEN)	/* CTA_HELP_NAME */
		+ NLA_TYPE_SIZE(u_int32_t)	/* CTA_SECMARK */
		+ 2 * nla_total_size(0)		/* CTA_NAT_SEQ_ADJ_ORIG|REPL */
		+ 2 * NLA_TYPE_SIZE(u_int32_t)	/* CTA_NAT_SEQ_CORRECTION_POS */
		+ 2 * NLA_TYPE_SIZE(u_int32_t)	/* CTA_NAT_SEQ_CORRECTION_BEFORE */
		+ 2 * NLA_TYPE_SIZE(u_int32_t)	/* CTA_NAT_SEQ_CORRECTION_AFTER */
		+ NLA_TYPE_SIZE(u_int32_t);	/* CTA_MARK */

#undef NLA_TYPE_SIZE

	rcu_read_lock();
	l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
	len += l3proto->nla_size;

	l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
	len += l4proto->nla_size;
	rcu_read_unlock();

	return alloc_skb(len, gfp);
}

static int ctnetlink_conntrack_event(struct notifier_block *this,
static int ctnetlink_conntrack_event(struct notifier_block *this,
				     unsigned long events, void *ptr)
				     unsigned long events, void *ptr)
{
{
@@ -438,7 +501,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
	if (!item->report && !nfnetlink_has_listeners(group))
	if (!item->report && !nfnetlink_has_listeners(group))
		return NOTIFY_DONE;
		return NOTIFY_DONE;


	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
	skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC);
	if (!skb)
	if (!skb)
		return NOTIFY_DONE;
		return NOTIFY_DONE;