aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2005-11-11 19:08:24 -0500
committerDavid S. Miller <davem@davemloft.net>2005-11-11 19:08:24 -0500
commit049b3ff5a86d0187184a189d2e31b8654d58fe22 (patch)
treeaed83ae799e444c57d76597bad6e3b41957a828e /net/sctp
parent19c7e9eef503dc1ae926f3d26c56f88bee568d7b (diff)
[SCTP]: Include ulpevents in socket receive buffer accounting.
Also introduces a sysctl option to configure the receive buffer accounting policy to be either at socket or association level. Default is all the associations on the same socket share the receive buffer. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c9
-rw-r--r--net/sctp/endpointola.c3
-rw-r--r--net/sctp/input.c20
-rw-r--r--net/sctp/protocol.c3
-rw-r--r--net/sctp/sm_statefuns.c22
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/sctp/sysctl.c8
-rw-r--r--net/sctp/ulpevent.c24
8 files changed, 54 insertions, 39 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5f07ddb19554..dec68a604773 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -177,10 +177,10 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
177 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of 177 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
178 * 1500 bytes in one SCTP packet. 178 * 1500 bytes in one SCTP packet.
179 */ 179 */
180 if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW) 180 if ((sk->sk_rcvbuf/2) < SCTP_DEFAULT_MINWINDOW)
181 asoc->rwnd = SCTP_DEFAULT_MINWINDOW; 181 asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
182 else 182 else
183 asoc->rwnd = sk->sk_rcvbuf; 183 asoc->rwnd = sk->sk_rcvbuf/2;
184 184
185 asoc->a_rwnd = asoc->rwnd; 185 asoc->a_rwnd = asoc->rwnd;
186 186
@@ -192,6 +192,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
192 /* Set the sndbuf size for transmit. */ 192 /* Set the sndbuf size for transmit. */
193 asoc->sndbuf_used = 0; 193 asoc->sndbuf_used = 0;
194 194
195 /* Initialize the receive memory counter */
196 atomic_set(&asoc->rmem_alloc, 0);
197
195 init_waitqueue_head(&asoc->wait); 198 init_waitqueue_head(&asoc->wait);
196 199
197 asoc->c.my_vtag = sctp_generate_tag(ep); 200 asoc->c.my_vtag = sctp_generate_tag(ep);
@@ -400,6 +403,8 @@ static void sctp_association_destroy(struct sctp_association *asoc)
400 spin_unlock_bh(&sctp_assocs_id_lock); 403 spin_unlock_bh(&sctp_assocs_id_lock);
401 } 404 }
402 405
406 BUG_TRAP(!atomic_read(&asoc->rmem_alloc));
407
403 if (asoc->base.malloced) { 408 if (asoc->base.malloced) {
404 kfree(asoc); 409 kfree(asoc);
405 SCTP_DBG_OBJCNT_DEC(assoc); 410 SCTP_DBG_OBJCNT_DEC(assoc);
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 0df76897f563..67bd53070ee0 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -104,6 +104,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
104 sk->sk_write_space = sctp_write_space; 104 sk->sk_write_space = sctp_write_space;
105 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 105 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
106 106
107 /* Get the receive buffer policy for this endpoint */
108 ep->rcvbuf_policy = sctp_rcvbuf_policy;
109
107 /* Initialize the secret key used with cookie. */ 110 /* Initialize the secret key used with cookie. */
108 get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); 111 get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
109 ep->last_key = ep->current_key = 0; 112 ep->last_key = ep->current_key = 0;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 28f32243397f..b24ff2c1aef5 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -100,21 +100,6 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
100 return 0; 100 return 0;
101} 101}
102 102
103/* The free routine for skbuffs that sctp receives */
104static void sctp_rfree(struct sk_buff *skb)
105{
106 atomic_sub(sizeof(struct sctp_chunk),&skb->sk->sk_rmem_alloc);
107 sock_rfree(skb);
108}
109
110/* The ownership wrapper routine to do receive buffer accounting */
111static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
112{
113 skb_set_owner_r(skb,sk);
114 skb->destructor = sctp_rfree;
115 atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
116}
117
118struct sctp_input_cb { 103struct sctp_input_cb {
119 union { 104 union {
120 struct inet_skb_parm h4; 105 struct inet_skb_parm h4;
@@ -217,9 +202,6 @@ int sctp_rcv(struct sk_buff *skb)
217 rcvr = &ep->base; 202 rcvr = &ep->base;
218 } 203 }
219 204
220 if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
221 goto discard_release;
222
223 /* 205 /*
224 * RFC 2960, 8.4 - Handle "Out of the blue" Packets. 206 * RFC 2960, 8.4 - Handle "Out of the blue" Packets.
225 * An SCTP packet is called an "out of the blue" (OOTB) 207 * An SCTP packet is called an "out of the blue" (OOTB)
@@ -256,8 +238,6 @@ int sctp_rcv(struct sk_buff *skb)
256 } 238 }
257 SCTP_INPUT_CB(skb)->chunk = chunk; 239 SCTP_INPUT_CB(skb)->chunk = chunk;
258 240
259 sctp_rcv_set_owner_r(skb,sk);
260
261 /* Remember what endpoint is to handle this packet. */ 241 /* Remember what endpoint is to handle this packet. */
262 chunk->rcvr = rcvr; 242 chunk->rcvr = rcvr;
263 243
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index dc9dff396fad..f775d78aa59d 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1050,6 +1050,9 @@ SCTP_STATIC __init int sctp_init(void)
1050 /* Sendbuffer growth - do per-socket accounting */ 1050 /* Sendbuffer growth - do per-socket accounting */
1051 sctp_sndbuf_policy = 0; 1051 sctp_sndbuf_policy = 0;
1052 1052
1053 /* Rcvbuffer growth - do per-socket accounting */
1054 sctp_rcvbuf_policy = 0;
1055
1053 /* HB.interval - 30 seconds */ 1056 /* HB.interval - 30 seconds */
1054 sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; 1057 sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
1055 1058
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 505c7de10c50..475bfb4972d9 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -5160,6 +5160,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
5160 sctp_verb_t deliver; 5160 sctp_verb_t deliver;
5161 int tmp; 5161 int tmp;
5162 __u32 tsn; 5162 __u32 tsn;
5163 int account_value;
5164 struct sock *sk = asoc->base.sk;
5163 5165
5164 data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; 5166 data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
5165 skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); 5167 skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
@@ -5169,6 +5171,26 @@ static int sctp_eat_data(const struct sctp_association *asoc,
5169 5171
5170 /* ASSERT: Now skb->data is really the user data. */ 5172 /* ASSERT: Now skb->data is really the user data. */
5171 5173
5174 /*
5175 * if we are established, and we have used up our receive
5176 * buffer memory, drop the frame
5177 */
5178 if (asoc->state == SCTP_STATE_ESTABLISHED) {
5179 /*
5180 * If the receive buffer policy is 1, then each
5181 * association can allocate up to sk_rcvbuf bytes
5182 * otherwise, all the associations in aggregate
5183 * may allocate up to sk_rcvbuf bytes
5184 */
5185 if (asoc->ep->rcvbuf_policy)
5186 account_value = atomic_read(&asoc->rmem_alloc);
5187 else
5188 account_value = atomic_read(&sk->sk_rmem_alloc);
5189
5190 if (account_value > sk->sk_rcvbuf)
5191 return SCTP_IERROR_IGNORE_TSN;
5192 }
5193
5172 /* Process ECN based congestion. 5194 /* Process ECN based congestion.
5173 * 5195 *
5174 * Since the chunk structure is reused for all chunks within 5196 * Since the chunk structure is reused for all chunks within
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 4d1b8d8904c4..abab81f3818f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -5114,8 +5114,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5114 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 5114 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
5115 event = sctp_skb2event(skb); 5115 event = sctp_skb2event(skb);
5116 if (event->asoc == assoc) { 5116 if (event->asoc == assoc) {
5117 sock_rfree(skb);
5117 __skb_unlink(skb, &oldsk->sk_receive_queue); 5118 __skb_unlink(skb, &oldsk->sk_receive_queue);
5118 __skb_queue_tail(&newsk->sk_receive_queue, skb); 5119 __skb_queue_tail(&newsk->sk_receive_queue, skb);
5120 skb_set_owner_r(skb, newsk);
5119 } 5121 }
5120 } 5122 }
5121 5123
@@ -5143,8 +5145,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5143 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 5145 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
5144 event = sctp_skb2event(skb); 5146 event = sctp_skb2event(skb);
5145 if (event->asoc == assoc) { 5147 if (event->asoc == assoc) {
5148 sock_rfree(skb);
5146 __skb_unlink(skb, &oldsp->pd_lobby); 5149 __skb_unlink(skb, &oldsp->pd_lobby);
5147 __skb_queue_tail(queue, skb); 5150 __skb_queue_tail(queue, skb);
5151 skb_set_owner_r(skb, newsk);
5148 } 5152 }
5149 } 5153 }
5150 5154
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 75b28dd634fe..fcd7096c953d 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -121,6 +121,14 @@ static ctl_table sctp_table[] = {
121 .proc_handler = &proc_dointvec 121 .proc_handler = &proc_dointvec
122 }, 122 },
123 { 123 {
124 .ctl_name = NET_SCTP_RCVBUF_POLICY,
125 .procname = "rcvbuf_policy",
126 .data = &sctp_rcvbuf_policy,
127 .maxlen = sizeof(int),
128 .mode = 0644,
129 .proc_handler = &proc_dointvec
130 },
131 {
124 .ctl_name = NET_SCTP_PATH_MAX_RETRANS, 132 .ctl_name = NET_SCTP_PATH_MAX_RETRANS,
125 .procname = "path_max_retrans", 133 .procname = "path_max_retrans",
126 .data = &sctp_max_retrans_path, 134 .data = &sctp_max_retrans_path,
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index e049f41faa47..ba97f974f57c 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -52,19 +52,6 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
52 struct sctp_association *asoc); 52 struct sctp_association *asoc);
53static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); 53static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
54 54
55/* Stub skb destructor. */
56static void sctp_stub_rfree(struct sk_buff *skb)
57{
58/* WARNING: This function is just a warning not to use the
59 * skb destructor. If the skb is shared, we may get the destructor
60 * callback on some processor that does not own the sock_lock. This
61 * was occuring with PACKET socket applications that were monitoring
62 * our skbs. We can't take the sock_lock, because we can't risk
63 * recursing if we do really own the sock lock. Instead, do all
64 * of our rwnd manipulation while we own the sock_lock outright.
65 */
66}
67
68/* Initialize an ULP event from an given skb. */ 55/* Initialize an ULP event from an given skb. */
69SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) 56SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
70{ 57{
@@ -111,15 +98,19 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
111 */ 98 */
112 sctp_association_hold((struct sctp_association *)asoc); 99 sctp_association_hold((struct sctp_association *)asoc);
113 skb = sctp_event2skb(event); 100 skb = sctp_event2skb(event);
114 skb->sk = asoc->base.sk;
115 event->asoc = (struct sctp_association *)asoc; 101 event->asoc = (struct sctp_association *)asoc;
116 skb->destructor = sctp_stub_rfree; 102 atomic_add(skb->truesize, &event->asoc->rmem_alloc);
103 skb_set_owner_r(skb, asoc->base.sk);
117} 104}
118 105
119/* A simple destructor to give up the reference to the association. */ 106/* A simple destructor to give up the reference to the association. */
120static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) 107static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
121{ 108{
122 sctp_association_put(event->asoc); 109 struct sctp_association *asoc = event->asoc;
110 struct sk_buff *skb = sctp_event2skb(event);
111
112 atomic_sub(skb->truesize, &asoc->rmem_alloc);
113 sctp_association_put(asoc);
123} 114}
124 115
125/* Create and initialize an SCTP_ASSOC_CHANGE event. 116/* Create and initialize an SCTP_ASSOC_CHANGE event.
@@ -922,7 +913,6 @@ done:
922/* Free a ulpevent that has an owner. It includes releasing the reference 913/* Free a ulpevent that has an owner. It includes releasing the reference
923 * to the owner, updating the rwnd in case of a DATA event and freeing the 914 * to the owner, updating the rwnd in case of a DATA event and freeing the
924 * skb. 915 * skb.
925 * See comments in sctp_stub_rfree().
926 */ 916 */
927void sctp_ulpevent_free(struct sctp_ulpevent *event) 917void sctp_ulpevent_free(struct sctp_ulpevent *event)
928{ 918{