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

Commit 440f0d58 authored by Patrick McHardy's avatar Patrick McHardy
Browse files

netfilter: nf_conntrack: use per-conntrack locks for protocol data



Introduce per-conntrack locks and use them instead of the global protocol
locks to avoid contention. Especially tcp_lock shows up very high in
profiles on larger machines.

This will also allow to simplify the upcoming reliable event delivery patches.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent a31e1ffd
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -93,6 +93,8 @@ struct nf_conn {
           plus 1 for any connection(s) we are `master' for */
	struct nf_conntrack ct_general;

	spinlock_t lock;

	/* XXX should I move this to the tail ? - Y.K */
	/* These are my tuples; original and reply */
	struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+2 −2
Original line number Diff line number Diff line
@@ -59,11 +59,11 @@ struct nf_conntrack_l4proto
			   const struct nf_conntrack_tuple *);

	/* Print out the private part of the conntrack. */
	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
	int (*print_conntrack)(struct seq_file *s, struct nf_conn *);

	/* convert protoinfo to nfnetink attributes */
	int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
			 const struct nf_conn *ct);
			 struct nf_conn *ct);
	/* Calculate protoinfo nlattr size */
	int (*nlattr_size)(void);

+1 −0
Original line number Diff line number Diff line
@@ -519,6 +519,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
		return ERR_PTR(-ENOMEM);
	}

	spin_lock_init(&ct->lock);
	atomic_set(&ct->ct_general.use, 1);
	ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
	ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
+2 −2
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
}

static inline int
ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
{
	struct nf_conntrack_l4proto *l4proto;
	struct nlattr *nest_proto;
@@ -347,7 +347,7 @@ ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)

static int
ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
		    int event, const struct nf_conn *ct)
		    int event, struct nf_conn *ct)
{
	struct nlmsghdr *nlh;
	struct nfgenmsg *nfmsg;
+11 −13
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_log.h>

static DEFINE_RWLOCK(dccp_lock);

/* Timeouts are based on values from RFC4340:
 *
 * - REQUEST:
@@ -491,7 +489,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
		return NF_ACCEPT;
	}

	write_lock_bh(&dccp_lock);
	spin_lock_bh(&ct->lock);

	role = ct->proto.dccp.role[dir];
	old_state = ct->proto.dccp.state;
@@ -535,13 +533,13 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
		ct->proto.dccp.last_dir = dir;
		ct->proto.dccp.last_pkt = type;

		write_unlock_bh(&dccp_lock);
		spin_unlock_bh(&ct->lock);
		if (LOG_INVALID(net, IPPROTO_DCCP))
			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
				      "nf_ct_dccp: invalid packet ignored ");
		return NF_ACCEPT;
	case CT_DCCP_INVALID:
		write_unlock_bh(&dccp_lock);
		spin_unlock_bh(&ct->lock);
		if (LOG_INVALID(net, IPPROTO_DCCP))
			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
				      "nf_ct_dccp: invalid state transition ");
@@ -551,7 +549,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
	ct->proto.dccp.last_dir = dir;
	ct->proto.dccp.last_pkt = type;
	ct->proto.dccp.state = new_state;
	write_unlock_bh(&dccp_lock);
	spin_unlock_bh(&ct->lock);

	dn = dccp_pernet(net);
	nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
@@ -617,18 +615,18 @@ static int dccp_print_tuple(struct seq_file *s,
			  ntohs(tuple->dst.u.dccp.port));
}

static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct)
static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{
	return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
}

#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
			  const struct nf_conn *ct)
			  struct nf_conn *ct)
{
	struct nlattr *nest_parms;

	read_lock_bh(&dccp_lock);
	spin_lock_bh(&ct->lock);
	nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED);
	if (!nest_parms)
		goto nla_put_failure;
@@ -638,11 +636,11 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
	NLA_PUT_BE64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
		     cpu_to_be64(ct->proto.dccp.handshake_seq));
	nla_nest_end(skb, nest_parms);
	read_unlock_bh(&dccp_lock);
	spin_unlock_bh(&ct->lock);
	return 0;

nla_put_failure:
	read_unlock_bh(&dccp_lock);
	spin_unlock_bh(&ct->lock);
	return -1;
}

@@ -673,7 +671,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
		return -EINVAL;
	}

	write_lock_bh(&dccp_lock);
	spin_lock_bh(&ct->lock);
	ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
	if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
		ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
@@ -686,7 +684,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
		ct->proto.dccp.handshake_seq =
		be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]));
	}
	write_unlock_bh(&dccp_lock);
	spin_unlock_bh(&ct->lock);
	return 0;
}

Loading