summary refs log tree commit diff
diff options
context:
space:
mode:
authorNeil Horman <nhorman@redhat.com>2005-04-28 12:02:04 -0700
committerDavid S. Miller <davem@davemloft.net>2005-04-28 12:02:04 -0700
commit4eb701dfc618491c9b97377df6e61de36dfc39ce (patch)
treeb49f31ebecda19d071d3ae3777be2a6a8c9e5c34
parent594ccc14dfe4d61b476491758425a1c2ca4ec71b (diff)
downloadlinux-4eb701dfc618491c9b97377df6e61de36dfc39ce.tar.gz
[SCTP] Fix SCTP sendbuffer accouting.
- Include chunk and skb sizes in sendbuffer accounting.
- 2 policies are supported. 0: per socket accouting, 1: per association
  accounting

DaveM: I've made the default per-socket.

Signed-off-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--include/net/sctp/structs.h11
-rw-r--r--net/sctp/endpointola.c1
-rw-r--r--net/sctp/protocol.c3
-rw-r--r--net/sctp/socket.c36
-rw-r--r--net/sctp/sysctl.c8
6 files changed, 54 insertions, 6 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 358d52b0c445..772998147e3e 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -643,6 +643,7 @@ enum {
 	NET_SCTP_MAX_BURST               = 12,
 	NET_SCTP_ADDIP_ENABLE		 = 13,
 	NET_SCTP_PRSCTP_ENABLE		 = 14,
+	NET_SCTP_SNDBUF_POLICY		 = 15,
 };
 
 /* /proc/sys/net/bridge */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 7e64cf6bda1e..6c24d9cd3d66 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -154,6 +154,13 @@ extern struct sctp_globals {
 	int max_retrans_path;
 	int max_retrans_init;
 
+	/*
+	 * Policy for preforming sctp/socket accounting
+	 * 0   - do socket level accounting, all assocs share sk_sndbuf
+	 * 1   - do sctp accounting, each asoc may use sk_sndbuf bytes
+	 */
+	int sndbuf_policy;
+
 	/* HB.interval		    - 30 seconds  */
 	int hb_interval;
 
@@ -207,6 +214,7 @@ extern struct sctp_globals {
 #define sctp_valid_cookie_life		(sctp_globals.valid_cookie_life)
 #define sctp_cookie_preserve_enable	(sctp_globals.cookie_preserve_enable)
 #define sctp_max_retrans_association	(sctp_globals.max_retrans_association)
+#define sctp_sndbuf_policy	 	(sctp_globals.sndbuf_policy)
 #define sctp_max_retrans_path		(sctp_globals.max_retrans_path)
 #define sctp_max_retrans_init		(sctp_globals.max_retrans_init)
 #define sctp_hb_interval		(sctp_globals.hb_interval)
@@ -1212,7 +1220,8 @@ struct sctp_endpoint {
 	/* Default timeouts.  */
 	int timeouts[SCTP_NUM_TIMEOUT_TYPES];
 
-	/* Various thresholds.	*/
+	/* sendbuf acct. policy.	*/
+	__u32 sndbuf_policy;
 
 	/* Name for debugging output... */
 	char *debug_name;
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 544b75077dbd..334f61773e6d 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -125,6 +125,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
 		sp->autoclose * HZ;
 
 	/* Use SCTP specific send buffer space queues.  */
+	ep->sndbuf_policy = sctp_sndbuf_policy;
 	sk->sk_write_space = sctp_write_space;
 	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 23c85a236c41..2e1f9c3556f5 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1043,6 +1043,9 @@ SCTP_STATIC __init int sctp_init(void)
 	sctp_max_retrans_path		= 5;
 	sctp_max_retrans_init		= 8;
 
+	/* Sendbuffer growth	    - do per-socket accounting */
+	sctp_sndbuf_policy		= 0;
+
 	/* HB.interval              - 30 seconds */
 	sctp_hb_interval		= 30 * HZ;
 
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 32f2249411fa..0b338eca6dc0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sctp_association *asoc)
 	struct sock *sk = asoc->base.sk;
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	if (asoc->ep->sndbuf_policy) {
+		/* make sure that no association uses more than sk_sndbuf */
+		amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	} else {
+		/* do socket level accounting */
+		amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+	}
+
 	if (amt < 0)
 		amt = 0;
+
 	return amt;
 }
 
@@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
 	/* The sndbuf space is tracked per association.  */
 	sctp_association_hold(asoc);
 
+	skb_set_owner_w(chunk->skb, sk);
+
 	chunk->skb->destructor = sctp_wfree;
 	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
 	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
 
-	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
+	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
 }
 
 /* Verify that this is a valid address. */
@@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb)
 	chunk = *((struct sctp_chunk **)(skb->cb));
 	asoc = chunk->asoc;
 	sk = asoc->base.sk;
-	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
+	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) +
+				sizeof(struct sk_buff) +
+				sizeof(struct sctp_chunk);
+
+	atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+
+	sock_wfree(skb);
 	__sctp_write_space(asoc);
 
 	sctp_association_put(asoc);
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 89fa20c73a5c..7fc31849312b 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -110,6 +110,14 @@ static ctl_table sctp_table[] = {
 		.proc_handler	= &proc_dointvec
 	},
 	{
+		.ctl_name	= NET_SCTP_SNDBUF_POLICY,
+		.procname	= "sndbuf_policy",
+		.data		= &sctp_sndbuf_policy,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
 		.ctl_name	= NET_SCTP_PATH_MAX_RETRANS,
 		.procname	= "path_max_retrans",
 		.data		= &sctp_max_retrans_path,