aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {
643 NET_SCTP_MAX_BURST = 12, 643 NET_SCTP_MAX_BURST = 12,
644 NET_SCTP_ADDIP_ENABLE = 13, 644 NET_SCTP_ADDIP_ENABLE = 13,
645 NET_SCTP_PRSCTP_ENABLE = 14, 645 NET_SCTP_PRSCTP_ENABLE = 14,
646 NET_SCTP_SNDBUF_POLICY = 15,
646}; 647};
647 648
648/* /proc/sys/net/bridge */ 649/* /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 {
154 int max_retrans_path; 154 int max_retrans_path;
155 int max_retrans_init; 155 int max_retrans_init;
156 156
157 /*
158 * Policy for preforming sctp/socket accounting
159 * 0 - do socket level accounting, all assocs share sk_sndbuf
160 * 1 - do sctp accounting, each asoc may use sk_sndbuf bytes
161 */
162 int sndbuf_policy;
163
157 /* HB.interval - 30 seconds */ 164 /* HB.interval - 30 seconds */
158 int hb_interval; 165 int hb_interval;
159 166
@@ -207,6 +214,7 @@ extern struct sctp_globals {
207#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life) 214#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life)
208#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable) 215#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable)
209#define sctp_max_retrans_association (sctp_globals.max_retrans_association) 216#define sctp_max_retrans_association (sctp_globals.max_retrans_association)
217#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy)
210#define sctp_max_retrans_path (sctp_globals.max_retrans_path) 218#define sctp_max_retrans_path (sctp_globals.max_retrans_path)
211#define sctp_max_retrans_init (sctp_globals.max_retrans_init) 219#define sctp_max_retrans_init (sctp_globals.max_retrans_init)
212#define sctp_hb_interval (sctp_globals.hb_interval) 220#define sctp_hb_interval (sctp_globals.hb_interval)
@@ -1212,7 +1220,8 @@ struct sctp_endpoint {
1212 /* Default timeouts. */ 1220 /* Default timeouts. */
1213 int timeouts[SCTP_NUM_TIMEOUT_TYPES]; 1221 int timeouts[SCTP_NUM_TIMEOUT_TYPES];
1214 1222
1215 /* Various thresholds. */ 1223 /* sendbuf acct. policy. */
1224 __u32 sndbuf_policy;
1216 1225
1217 /* Name for debugging output... */ 1226 /* Name for debugging output... */
1218 char *debug_name; 1227 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,
125 sp->autoclose * HZ; 125 sp->autoclose * HZ;
126 126
127 /* Use SCTP specific send buffer space queues. */ 127 /* Use SCTP specific send buffer space queues. */
128 ep->sndbuf_policy = sctp_sndbuf_policy;
128 sk->sk_write_space = sctp_write_space; 129 sk->sk_write_space = sctp_write_space;
129 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 130 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
130 131
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)
1043 sctp_max_retrans_path = 5; 1043 sctp_max_retrans_path = 5;
1044 sctp_max_retrans_init = 8; 1044 sctp_max_retrans_init = 8;
1045 1045
1046 /* Sendbuffer growth - do per-socket accounting */
1047 sctp_sndbuf_policy = 0;
1048
1046 /* HB.interval - 30 seconds */ 1049 /* HB.interval - 30 seconds */
1047 sctp_hb_interval = 30 * HZ; 1050 sctp_hb_interval = 30 * HZ;
1048 1051
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)
115 struct sock *sk = asoc->base.sk; 115 struct sock *sk = asoc->base.sk;
116 int amt = 0; 116 int amt = 0;
117 117
118 amt = sk->sk_sndbuf - asoc->sndbuf_used; 118 if (asoc->ep->sndbuf_policy) {
119 /* make sure that no association uses more than sk_sndbuf */
120 amt = sk->sk_sndbuf - asoc->sndbuf_used;
121 } else {
122 /* do socket level accounting */
123 amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
124 }
125
119 if (amt < 0) 126 if (amt < 0)
120 amt = 0; 127 amt = 0;
128
121 return amt; 129 return amt;
122} 130}
123 131
@@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
138 /* The sndbuf space is tracked per association. */ 146 /* The sndbuf space is tracked per association. */
139 sctp_association_hold(asoc); 147 sctp_association_hold(asoc);
140 148
149 skb_set_owner_w(chunk->skb, sk);
150
141 chunk->skb->destructor = sctp_wfree; 151 chunk->skb->destructor = sctp_wfree;
142 /* Save the chunk pointer in skb for sctp_wfree to use later. */ 152 /* Save the chunk pointer in skb for sctp_wfree to use later. */
143 *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; 153 *((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
144 154
145 asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); 155 asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) +
146 sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); 156 sizeof(struct sk_buff) +
157 sizeof(struct sctp_chunk);
158
159 sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) +
160 sizeof(struct sk_buff) +
161 sizeof(struct sctp_chunk);
162
163 atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
147} 164}
148 165
149/* Verify that this is a valid address. */ 166/* Verify that this is a valid address. */
@@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb)
4422 chunk = *((struct sctp_chunk **)(skb->cb)); 4439 chunk = *((struct sctp_chunk **)(skb->cb));
4423 asoc = chunk->asoc; 4440 asoc = chunk->asoc;
4424 sk = asoc->base.sk; 4441 sk = asoc->base.sk;
4425 asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); 4442 asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) +
4426 sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); 4443 sizeof(struct sk_buff) +
4444 sizeof(struct sctp_chunk);
4445
4446 sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) +
4447 sizeof(struct sk_buff) +
4448 sizeof(struct sctp_chunk);
4449
4450 atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
4451
4452 sock_wfree(skb);
4427 __sctp_write_space(asoc); 4453 __sctp_write_space(asoc);
4428 4454
4429 sctp_association_put(asoc); 4455 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[] = {
110 .proc_handler = &proc_dointvec 110 .proc_handler = &proc_dointvec
111 }, 111 },
112 { 112 {
113 .ctl_name = NET_SCTP_SNDBUF_POLICY,
114 .procname = "sndbuf_policy",
115 .data = &sctp_sndbuf_policy,
116 .maxlen = sizeof(int),
117 .mode = 0644,
118 .proc_handler = &proc_dointvec
119 },
120 {
113 .ctl_name = NET_SCTP_PATH_MAX_RETRANS, 121 .ctl_name = NET_SCTP_PATH_MAX_RETRANS,
114 .procname = "path_max_retrans", 122 .procname = "path_max_retrans",
115 .data = &sctp_max_retrans_path, 123 .data = &sctp_max_retrans_path,