diff options
author | Vladislav Yasevich <vladislav.yasevich@hp.com> | 2005-06-13 18:11:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-06-13 18:11:57 -0400 |
commit | bca735bd0d5969497704a125b05344b92155172f (patch) | |
tree | 996f7096abab29bd3fee41a942372dc1a6990d12 /net | |
parent | 0fd9a65a76e883b7d16e72dde3f8bf20ebc1e82a (diff) |
[SCTP] Extend the info exported via /proc/net/sctp to support netstat for SCTP.
Signed-off-by: Vladislav Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sctp/proc.c | 194 |
1 files changed, 151 insertions, 43 deletions
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index e42fd8c2916b..98d49ec9b74b 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -132,14 +132,25 @@ void sctp_snmp_proc_exit(void) | |||
132 | static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) | 132 | static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) |
133 | { | 133 | { |
134 | struct list_head *pos; | 134 | struct list_head *pos; |
135 | struct sctp_association *asoc; | ||
135 | struct sctp_sockaddr_entry *laddr; | 136 | struct sctp_sockaddr_entry *laddr; |
136 | union sctp_addr *addr; | 137 | struct sctp_transport *peer; |
138 | union sctp_addr *addr, *primary = NULL; | ||
137 | struct sctp_af *af; | 139 | struct sctp_af *af; |
138 | 140 | ||
141 | if (epb->type == SCTP_EP_TYPE_ASSOCIATION) { | ||
142 | asoc = sctp_assoc(epb); | ||
143 | peer = asoc->peer.primary_path; | ||
144 | primary = &peer->saddr; | ||
145 | } | ||
146 | |||
139 | list_for_each(pos, &epb->bind_addr.address_list) { | 147 | list_for_each(pos, &epb->bind_addr.address_list) { |
140 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); | 148 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); |
141 | addr = (union sctp_addr *)&laddr->a; | 149 | addr = (union sctp_addr *)&laddr->a; |
142 | af = sctp_get_af_specific(addr->sa.sa_family); | 150 | af = sctp_get_af_specific(addr->sa.sa_family); |
151 | if (primary && af->cmp_addr(addr, primary)) { | ||
152 | seq_printf(seq, "*"); | ||
153 | } | ||
143 | af->seq_dump_addr(seq, addr); | 154 | af->seq_dump_addr(seq, addr); |
144 | } | 155 | } |
145 | } | 156 | } |
@@ -149,17 +160,54 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa | |||
149 | { | 160 | { |
150 | struct list_head *pos; | 161 | struct list_head *pos; |
151 | struct sctp_transport *transport; | 162 | struct sctp_transport *transport; |
152 | union sctp_addr *addr; | 163 | union sctp_addr *addr, *primary; |
153 | struct sctp_af *af; | 164 | struct sctp_af *af; |
154 | 165 | ||
166 | primary = &(assoc->peer.primary_addr); | ||
155 | list_for_each(pos, &assoc->peer.transport_addr_list) { | 167 | list_for_each(pos, &assoc->peer.transport_addr_list) { |
156 | transport = list_entry(pos, struct sctp_transport, transports); | 168 | transport = list_entry(pos, struct sctp_transport, transports); |
157 | addr = (union sctp_addr *)&transport->ipaddr; | 169 | addr = (union sctp_addr *)&transport->ipaddr; |
158 | af = sctp_get_af_specific(addr->sa.sa_family); | 170 | af = sctp_get_af_specific(addr->sa.sa_family); |
171 | if (af->cmp_addr(addr, primary)) { | ||
172 | seq_printf(seq, "*"); | ||
173 | } | ||
159 | af->seq_dump_addr(seq, addr); | 174 | af->seq_dump_addr(seq, addr); |
160 | } | 175 | } |
161 | } | 176 | } |
162 | 177 | ||
178 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) | ||
179 | { | ||
180 | if (*pos > sctp_ep_hashsize) | ||
181 | return NULL; | ||
182 | |||
183 | if (*pos < 0) | ||
184 | *pos = 0; | ||
185 | |||
186 | if (*pos == 0) | ||
187 | seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n"); | ||
188 | |||
189 | ++*pos; | ||
190 | |||
191 | return (void *)pos; | ||
192 | } | ||
193 | |||
194 | static void sctp_eps_seq_stop(struct seq_file *seq, void *v) | ||
195 | { | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | |||
200 | static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
201 | { | ||
202 | if (*pos > sctp_ep_hashsize) | ||
203 | return NULL; | ||
204 | |||
205 | ++*pos; | ||
206 | |||
207 | return pos; | ||
208 | } | ||
209 | |||
210 | |||
163 | /* Display sctp endpoints (/proc/net/sctp/eps). */ | 211 | /* Display sctp endpoints (/proc/net/sctp/eps). */ |
164 | static int sctp_eps_seq_show(struct seq_file *seq, void *v) | 212 | static int sctp_eps_seq_show(struct seq_file *seq, void *v) |
165 | { | 213 | { |
@@ -167,38 +215,50 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v) | |||
167 | struct sctp_ep_common *epb; | 215 | struct sctp_ep_common *epb; |
168 | struct sctp_endpoint *ep; | 216 | struct sctp_endpoint *ep; |
169 | struct sock *sk; | 217 | struct sock *sk; |
170 | int hash; | 218 | int hash = *(int *)v; |
171 | 219 | ||
172 | seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT LADDRS\n"); | 220 | if (hash > sctp_ep_hashsize) |
173 | for (hash = 0; hash < sctp_ep_hashsize; hash++) { | 221 | return -ENOMEM; |
174 | head = &sctp_ep_hashtable[hash]; | 222 | |
175 | read_lock(&head->lock); | 223 | head = &sctp_ep_hashtable[hash-1]; |
176 | for (epb = head->chain; epb; epb = epb->next) { | 224 | sctp_local_bh_disable(); |
177 | ep = sctp_ep(epb); | 225 | read_lock(&head->lock); |
178 | sk = epb->sk; | 226 | for (epb = head->chain; epb; epb = epb->next) { |
179 | seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk, | 227 | ep = sctp_ep(epb); |
180 | sctp_sk(sk)->type, sk->sk_state, hash, | 228 | sk = epb->sk; |
181 | epb->bind_addr.port); | 229 | seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, |
182 | sctp_seq_dump_local_addrs(seq, epb); | 230 | sctp_sk(sk)->type, sk->sk_state, hash-1, |
183 | seq_printf(seq, "\n"); | 231 | epb->bind_addr.port, |
184 | } | 232 | sock_i_uid(sk), sock_i_ino(sk)); |
185 | read_unlock(&head->lock); | 233 | |
234 | sctp_seq_dump_local_addrs(seq, epb); | ||
235 | seq_printf(seq, "\n"); | ||
186 | } | 236 | } |
237 | read_unlock(&head->lock); | ||
238 | sctp_local_bh_enable(); | ||
187 | 239 | ||
188 | return 0; | 240 | return 0; |
189 | } | 241 | } |
190 | 242 | ||
243 | static struct seq_operations sctp_eps_ops = { | ||
244 | .start = sctp_eps_seq_start, | ||
245 | .next = sctp_eps_seq_next, | ||
246 | .stop = sctp_eps_seq_stop, | ||
247 | .show = sctp_eps_seq_show, | ||
248 | }; | ||
249 | |||
250 | |||
191 | /* Initialize the seq file operations for 'eps' object. */ | 251 | /* Initialize the seq file operations for 'eps' object. */ |
192 | static int sctp_eps_seq_open(struct inode *inode, struct file *file) | 252 | static int sctp_eps_seq_open(struct inode *inode, struct file *file) |
193 | { | 253 | { |
194 | return single_open(file, sctp_eps_seq_show, NULL); | 254 | return seq_open(file, &sctp_eps_ops); |
195 | } | 255 | } |
196 | 256 | ||
197 | static struct file_operations sctp_eps_seq_fops = { | 257 | static struct file_operations sctp_eps_seq_fops = { |
198 | .open = sctp_eps_seq_open, | 258 | .open = sctp_eps_seq_open, |
199 | .read = seq_read, | 259 | .read = seq_read, |
200 | .llseek = seq_lseek, | 260 | .llseek = seq_lseek, |
201 | .release = single_release, | 261 | .release = seq_release, |
202 | }; | 262 | }; |
203 | 263 | ||
204 | /* Set up the proc fs entry for 'eps' object. */ | 264 | /* Set up the proc fs entry for 'eps' object. */ |
@@ -221,6 +281,40 @@ void sctp_eps_proc_exit(void) | |||
221 | remove_proc_entry("eps", proc_net_sctp); | 281 | remove_proc_entry("eps", proc_net_sctp); |
222 | } | 282 | } |
223 | 283 | ||
284 | |||
285 | static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) | ||
286 | { | ||
287 | if (*pos > sctp_assoc_hashsize) | ||
288 | return NULL; | ||
289 | |||
290 | if (*pos < 0) | ||
291 | *pos = 0; | ||
292 | |||
293 | if (*pos == 0) | ||
294 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " | ||
295 | "RPORT LADDRS <-> RADDRS\n"); | ||
296 | |||
297 | ++*pos; | ||
298 | |||
299 | return (void *)pos; | ||
300 | } | ||
301 | |||
302 | static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) | ||
303 | { | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | |||
308 | static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
309 | { | ||
310 | if (*pos > sctp_assoc_hashsize) | ||
311 | return NULL; | ||
312 | |||
313 | ++*pos; | ||
314 | |||
315 | return pos; | ||
316 | } | ||
317 | |||
224 | /* Display sctp associations (/proc/net/sctp/assocs). */ | 318 | /* Display sctp associations (/proc/net/sctp/assocs). */ |
225 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | 319 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) |
226 | { | 320 | { |
@@ -228,43 +322,57 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
228 | struct sctp_ep_common *epb; | 322 | struct sctp_ep_common *epb; |
229 | struct sctp_association *assoc; | 323 | struct sctp_association *assoc; |
230 | struct sock *sk; | 324 | struct sock *sk; |
231 | int hash; | 325 | int hash = *(int *)v; |
232 | 326 | ||
233 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT LPORT RPORT " | 327 | if (hash > sctp_assoc_hashsize) |
234 | "LADDRS <-> RADDRS\n"); | 328 | return -ENOMEM; |
235 | for (hash = 0; hash < sctp_assoc_hashsize; hash++) { | 329 | |
236 | head = &sctp_assoc_hashtable[hash]; | 330 | head = &sctp_assoc_hashtable[hash-1]; |
237 | read_lock(&head->lock); | 331 | sctp_local_bh_disable(); |
238 | for (epb = head->chain; epb; epb = epb->next) { | 332 | read_lock(&head->lock); |
239 | assoc = sctp_assoc(epb); | 333 | for (epb = head->chain; epb; epb = epb->next) { |
240 | sk = epb->sk; | 334 | assoc = sctp_assoc(epb); |
241 | seq_printf(seq, | 335 | sk = epb->sk; |
242 | "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ", | 336 | seq_printf(seq, |
243 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | 337 | "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", |
244 | assoc->state, hash, epb->bind_addr.port, | 338 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, |
245 | assoc->peer.port); | 339 | assoc->state, hash-1, assoc->assoc_id, |
246 | sctp_seq_dump_local_addrs(seq, epb); | 340 | (sk->sk_rcvbuf - assoc->rwnd), |
247 | seq_printf(seq, "<-> "); | 341 | assoc->sndbuf_used, |
248 | sctp_seq_dump_remote_addrs(seq, assoc); | 342 | sock_i_uid(sk), sock_i_ino(sk), |
249 | seq_printf(seq, "\n"); | 343 | epb->bind_addr.port, |
250 | } | 344 | assoc->peer.port); |
251 | read_unlock(&head->lock); | 345 | |
346 | seq_printf(seq, " "); | ||
347 | sctp_seq_dump_local_addrs(seq, epb); | ||
348 | seq_printf(seq, "<-> "); | ||
349 | sctp_seq_dump_remote_addrs(seq, assoc); | ||
350 | seq_printf(seq, "\n"); | ||
252 | } | 351 | } |
352 | read_unlock(&head->lock); | ||
353 | sctp_local_bh_enable(); | ||
253 | 354 | ||
254 | return 0; | 355 | return 0; |
255 | } | 356 | } |
256 | 357 | ||
358 | static struct seq_operations sctp_assoc_ops = { | ||
359 | .start = sctp_assocs_seq_start, | ||
360 | .next = sctp_assocs_seq_next, | ||
361 | .stop = sctp_assocs_seq_stop, | ||
362 | .show = sctp_assocs_seq_show, | ||
363 | }; | ||
364 | |||
257 | /* Initialize the seq file operations for 'assocs' object. */ | 365 | /* Initialize the seq file operations for 'assocs' object. */ |
258 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) | 366 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) |
259 | { | 367 | { |
260 | return single_open(file, sctp_assocs_seq_show, NULL); | 368 | return seq_open(file, &sctp_assoc_ops); |
261 | } | 369 | } |
262 | 370 | ||
263 | static struct file_operations sctp_assocs_seq_fops = { | 371 | static struct file_operations sctp_assocs_seq_fops = { |
264 | .open = sctp_assocs_seq_open, | 372 | .open = sctp_assocs_seq_open, |
265 | .read = seq_read, | 373 | .read = seq_read, |
266 | .llseek = seq_lseek, | 374 | .llseek = seq_lseek, |
267 | .release = single_release, | 375 | .release = seq_release, |
268 | }; | 376 | }; |
269 | 377 | ||
270 | /* Set up the proc fs entry for 'assocs' object. */ | 378 | /* Set up the proc fs entry for 'assocs' object. */ |