diff options
Diffstat (limited to 'net/sctp/proc.c')
-rw-r--r-- | net/sctp/proc.c | 316 |
1 files changed, 173 insertions, 143 deletions
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0697eda5aed8..dfa7eeccb537 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -281,88 +281,136 @@ void sctp_eps_proc_exit(struct net *net) | |||
281 | remove_proc_entry("eps", net->sctp.proc_net_sctp); | 281 | remove_proc_entry("eps", net->sctp.proc_net_sctp); |
282 | } | 282 | } |
283 | 283 | ||
284 | struct sctp_ht_iter { | ||
285 | struct seq_net_private p; | ||
286 | struct rhashtable_iter hti; | ||
287 | }; | ||
284 | 288 | ||
285 | static void *sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) | 289 | static struct sctp_transport *sctp_transport_get_next(struct seq_file *seq) |
286 | { | 290 | { |
287 | if (*pos >= sctp_assoc_hashsize) | 291 | struct sctp_ht_iter *iter = seq->private; |
288 | return NULL; | 292 | struct sctp_transport *t; |
289 | 293 | ||
290 | if (*pos < 0) | 294 | t = rhashtable_walk_next(&iter->hti); |
291 | *pos = 0; | 295 | for (; t; t = rhashtable_walk_next(&iter->hti)) { |
296 | if (IS_ERR(t)) { | ||
297 | if (PTR_ERR(t) == -EAGAIN) | ||
298 | continue; | ||
299 | break; | ||
300 | } | ||
292 | 301 | ||
293 | if (*pos == 0) | 302 | if (net_eq(sock_net(t->asoc->base.sk), seq_file_net(seq)) && |
294 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT " | 303 | t->asoc->peer.primary_path == t) |
295 | "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " | 304 | break; |
296 | "RPORT LADDRS <-> RADDRS " | 305 | } |
297 | "HBINT INS OUTS MAXRT T1X T2X RTXC " | ||
298 | "wmema wmemq sndbuf rcvbuf\n"); | ||
299 | 306 | ||
300 | return (void *)pos; | 307 | return t; |
301 | } | 308 | } |
302 | 309 | ||
303 | static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) | 310 | static struct sctp_transport *sctp_transport_get_idx(struct seq_file *seq, |
311 | loff_t pos) | ||
312 | { | ||
313 | void *obj; | ||
314 | |||
315 | while (pos && (obj = sctp_transport_get_next(seq)) && !IS_ERR(obj)) | ||
316 | pos--; | ||
317 | |||
318 | return obj; | ||
319 | } | ||
320 | |||
321 | static int sctp_transport_walk_start(struct seq_file *seq) | ||
304 | { | 322 | { |
323 | struct sctp_ht_iter *iter = seq->private; | ||
324 | int err; | ||
325 | |||
326 | err = rhashtable_walk_init(&sctp_transport_hashtable, &iter->hti); | ||
327 | if (err) | ||
328 | return err; | ||
329 | |||
330 | err = rhashtable_walk_start(&iter->hti); | ||
331 | |||
332 | return err == -EAGAIN ? 0 : err; | ||
305 | } | 333 | } |
306 | 334 | ||
335 | static void sctp_transport_walk_stop(struct seq_file *seq) | ||
336 | { | ||
337 | struct sctp_ht_iter *iter = seq->private; | ||
338 | |||
339 | rhashtable_walk_stop(&iter->hti); | ||
340 | rhashtable_walk_exit(&iter->hti); | ||
341 | } | ||
342 | |||
343 | static void *sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) | ||
344 | { | ||
345 | int err = sctp_transport_walk_start(seq); | ||
346 | |||
347 | if (err) | ||
348 | return ERR_PTR(err); | ||
349 | |||
350 | return *pos ? sctp_transport_get_idx(seq, *pos) : SEQ_START_TOKEN; | ||
351 | } | ||
352 | |||
353 | static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) | ||
354 | { | ||
355 | sctp_transport_walk_stop(seq); | ||
356 | } | ||
307 | 357 | ||
308 | static void *sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 358 | static void *sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
309 | { | 359 | { |
310 | if (++*pos >= sctp_assoc_hashsize) | 360 | ++*pos; |
311 | return NULL; | ||
312 | 361 | ||
313 | return pos; | 362 | return sctp_transport_get_next(seq); |
314 | } | 363 | } |
315 | 364 | ||
316 | /* Display sctp associations (/proc/net/sctp/assocs). */ | 365 | /* Display sctp associations (/proc/net/sctp/assocs). */ |
317 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | 366 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) |
318 | { | 367 | { |
319 | struct sctp_hashbucket *head; | 368 | struct sctp_transport *transport; |
320 | struct sctp_ep_common *epb; | ||
321 | struct sctp_association *assoc; | 369 | struct sctp_association *assoc; |
370 | struct sctp_ep_common *epb; | ||
322 | struct sock *sk; | 371 | struct sock *sk; |
323 | int hash = *(loff_t *)v; | ||
324 | |||
325 | if (hash >= sctp_assoc_hashsize) | ||
326 | return -ENOMEM; | ||
327 | 372 | ||
328 | head = &sctp_assoc_hashtable[hash]; | 373 | if (v == SEQ_START_TOKEN) { |
329 | local_bh_disable(); | 374 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT " |
330 | read_lock(&head->lock); | 375 | "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " |
331 | sctp_for_each_hentry(epb, &head->chain) { | 376 | "RPORT LADDRS <-> RADDRS " |
332 | assoc = sctp_assoc(epb); | 377 | "HBINT INS OUTS MAXRT T1X T2X RTXC " |
333 | sk = epb->sk; | 378 | "wmema wmemq sndbuf rcvbuf\n"); |
334 | if (!net_eq(sock_net(sk), seq_file_net(seq))) | 379 | return 0; |
335 | continue; | ||
336 | seq_printf(seq, | ||
337 | "%8pK %8pK %-3d %-3d %-2d %-4d " | ||
338 | "%4d %8d %8d %7u %5lu %-5d %5d ", | ||
339 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | ||
340 | assoc->state, hash, | ||
341 | assoc->assoc_id, | ||
342 | assoc->sndbuf_used, | ||
343 | atomic_read(&assoc->rmem_alloc), | ||
344 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), | ||
345 | sock_i_ino(sk), | ||
346 | epb->bind_addr.port, | ||
347 | assoc->peer.port); | ||
348 | seq_printf(seq, " "); | ||
349 | sctp_seq_dump_local_addrs(seq, epb); | ||
350 | seq_printf(seq, "<-> "); | ||
351 | sctp_seq_dump_remote_addrs(seq, assoc); | ||
352 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " | ||
353 | "%8d %8d %8d %8d", | ||
354 | assoc->hbinterval, assoc->c.sinit_max_instreams, | ||
355 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | ||
356 | assoc->init_retries, assoc->shutdown_retries, | ||
357 | assoc->rtx_data_chunks, | ||
358 | atomic_read(&sk->sk_wmem_alloc), | ||
359 | sk->sk_wmem_queued, | ||
360 | sk->sk_sndbuf, | ||
361 | sk->sk_rcvbuf); | ||
362 | seq_printf(seq, "\n"); | ||
363 | } | 380 | } |
364 | read_unlock(&head->lock); | 381 | |
365 | local_bh_enable(); | 382 | transport = (struct sctp_transport *)v; |
383 | assoc = transport->asoc; | ||
384 | epb = &assoc->base; | ||
385 | sk = epb->sk; | ||
386 | |||
387 | seq_printf(seq, | ||
388 | "%8pK %8pK %-3d %-3d %-2d %-4d " | ||
389 | "%4d %8d %8d %7u %5lu %-5d %5d ", | ||
390 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | ||
391 | assoc->state, 0, | ||
392 | assoc->assoc_id, | ||
393 | assoc->sndbuf_used, | ||
394 | atomic_read(&assoc->rmem_alloc), | ||
395 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), | ||
396 | sock_i_ino(sk), | ||
397 | epb->bind_addr.port, | ||
398 | assoc->peer.port); | ||
399 | seq_printf(seq, " "); | ||
400 | sctp_seq_dump_local_addrs(seq, epb); | ||
401 | seq_printf(seq, "<-> "); | ||
402 | sctp_seq_dump_remote_addrs(seq, assoc); | ||
403 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " | ||
404 | "%8d %8d %8d %8d", | ||
405 | assoc->hbinterval, assoc->c.sinit_max_instreams, | ||
406 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | ||
407 | assoc->init_retries, assoc->shutdown_retries, | ||
408 | assoc->rtx_data_chunks, | ||
409 | atomic_read(&sk->sk_wmem_alloc), | ||
410 | sk->sk_wmem_queued, | ||
411 | sk->sk_sndbuf, | ||
412 | sk->sk_rcvbuf); | ||
413 | seq_printf(seq, "\n"); | ||
366 | 414 | ||
367 | return 0; | 415 | return 0; |
368 | } | 416 | } |
@@ -378,7 +426,7 @@ static const struct seq_operations sctp_assoc_ops = { | |||
378 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) | 426 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) |
379 | { | 427 | { |
380 | return seq_open_net(inode, file, &sctp_assoc_ops, | 428 | return seq_open_net(inode, file, &sctp_assoc_ops, |
381 | sizeof(struct seq_net_private)); | 429 | sizeof(struct sctp_ht_iter)); |
382 | } | 430 | } |
383 | 431 | ||
384 | static const struct file_operations sctp_assocs_seq_fops = { | 432 | static const struct file_operations sctp_assocs_seq_fops = { |
@@ -409,112 +457,94 @@ void sctp_assocs_proc_exit(struct net *net) | |||
409 | 457 | ||
410 | static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) | 458 | static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) |
411 | { | 459 | { |
412 | if (*pos >= sctp_assoc_hashsize) | 460 | int err = sctp_transport_walk_start(seq); |
413 | return NULL; | ||
414 | |||
415 | if (*pos < 0) | ||
416 | *pos = 0; | ||
417 | 461 | ||
418 | if (*pos == 0) | 462 | if (err) |
419 | seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " | 463 | return ERR_PTR(err); |
420 | "REM_ADDR_RTX START STATE\n"); | ||
421 | 464 | ||
422 | return (void *)pos; | 465 | return *pos ? sctp_transport_get_idx(seq, *pos) : SEQ_START_TOKEN; |
423 | } | 466 | } |
424 | 467 | ||
425 | static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 468 | static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
426 | { | 469 | { |
427 | if (++*pos >= sctp_assoc_hashsize) | 470 | ++*pos; |
428 | return NULL; | ||
429 | 471 | ||
430 | return pos; | 472 | return sctp_transport_get_next(seq); |
431 | } | 473 | } |
432 | 474 | ||
433 | static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) | 475 | static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) |
434 | { | 476 | { |
477 | sctp_transport_walk_stop(seq); | ||
435 | } | 478 | } |
436 | 479 | ||
437 | static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | 480 | static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) |
438 | { | 481 | { |
439 | struct sctp_hashbucket *head; | ||
440 | struct sctp_ep_common *epb; | ||
441 | struct sctp_association *assoc; | 482 | struct sctp_association *assoc; |
442 | struct sctp_transport *tsp; | 483 | struct sctp_transport *tsp; |
443 | int hash = *(loff_t *)v; | ||
444 | 484 | ||
445 | if (hash >= sctp_assoc_hashsize) | 485 | if (v == SEQ_START_TOKEN) { |
446 | return -ENOMEM; | 486 | seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " |
487 | "REM_ADDR_RTX START STATE\n"); | ||
488 | return 0; | ||
489 | } | ||
447 | 490 | ||
448 | head = &sctp_assoc_hashtable[hash]; | 491 | tsp = (struct sctp_transport *)v; |
449 | local_bh_disable(); | 492 | assoc = tsp->asoc; |
450 | read_lock(&head->lock); | 493 | |
451 | rcu_read_lock(); | 494 | list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list, |
452 | sctp_for_each_hentry(epb, &head->chain) { | 495 | transports) { |
453 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) | 496 | if (tsp->dead) |
454 | continue; | 497 | continue; |
455 | assoc = sctp_assoc(epb); | 498 | /* |
456 | list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list, | 499 | * The remote address (ADDR) |
457 | transports) { | 500 | */ |
458 | if (tsp->dead) | 501 | tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); |
459 | continue; | 502 | seq_printf(seq, " "); |
503 | /* | ||
504 | * The association ID (ASSOC_ID) | ||
505 | */ | ||
506 | seq_printf(seq, "%d ", tsp->asoc->assoc_id); | ||
507 | |||
508 | /* | ||
509 | * If the Heartbeat is active (HB_ACT) | ||
510 | * Note: 1 = Active, 0 = Inactive | ||
511 | */ | ||
512 | seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); | ||
513 | |||
514 | /* | ||
515 | * Retransmit time out (RTO) | ||
516 | */ | ||
517 | seq_printf(seq, "%lu ", tsp->rto); | ||
518 | |||
519 | /* | ||
520 | * Maximum path retransmit count (PATH_MAX_RTX) | ||
521 | */ | ||
522 | seq_printf(seq, "%d ", tsp->pathmaxrxt); | ||
523 | |||
524 | /* | ||
525 | * remote address retransmit count (REM_ADDR_RTX) | ||
526 | * Note: We don't have a way to tally this at the moment | ||
527 | * so lets just leave it as zero for the moment | ||
528 | */ | ||
529 | seq_puts(seq, "0 "); | ||
530 | |||
531 | /* | ||
532 | * remote address start time (START). This is also not | ||
533 | * currently implemented, but we can record it with a | ||
534 | * jiffies marker in a subsequent patch | ||
535 | */ | ||
536 | seq_puts(seq, "0 "); | ||
537 | |||
538 | /* | ||
539 | * The current state of this destination. I.e. | ||
540 | * SCTP_ACTIVE, SCTP_INACTIVE, ... | ||
541 | */ | ||
542 | seq_printf(seq, "%d", tsp->state); | ||
460 | 543 | ||
461 | /* | 544 | seq_printf(seq, "\n"); |
462 | * The remote address (ADDR) | ||
463 | */ | ||
464 | tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); | ||
465 | seq_printf(seq, " "); | ||
466 | |||
467 | /* | ||
468 | * The association ID (ASSOC_ID) | ||
469 | */ | ||
470 | seq_printf(seq, "%d ", tsp->asoc->assoc_id); | ||
471 | |||
472 | /* | ||
473 | * If the Heartbeat is active (HB_ACT) | ||
474 | * Note: 1 = Active, 0 = Inactive | ||
475 | */ | ||
476 | seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); | ||
477 | |||
478 | /* | ||
479 | * Retransmit time out (RTO) | ||
480 | */ | ||
481 | seq_printf(seq, "%lu ", tsp->rto); | ||
482 | |||
483 | /* | ||
484 | * Maximum path retransmit count (PATH_MAX_RTX) | ||
485 | */ | ||
486 | seq_printf(seq, "%d ", tsp->pathmaxrxt); | ||
487 | |||
488 | /* | ||
489 | * remote address retransmit count (REM_ADDR_RTX) | ||
490 | * Note: We don't have a way to tally this at the moment | ||
491 | * so lets just leave it as zero for the moment | ||
492 | */ | ||
493 | seq_puts(seq, "0 "); | ||
494 | |||
495 | /* | ||
496 | * remote address start time (START). This is also not | ||
497 | * currently implemented, but we can record it with a | ||
498 | * jiffies marker in a subsequent patch | ||
499 | */ | ||
500 | seq_puts(seq, "0 "); | ||
501 | |||
502 | /* | ||
503 | * The current state of this destination. I.e. | ||
504 | * SCTP_ACTIVE, SCTP_INACTIVE, ... | ||
505 | */ | ||
506 | seq_printf(seq, "%d", tsp->state); | ||
507 | |||
508 | seq_printf(seq, "\n"); | ||
509 | } | ||
510 | } | 545 | } |
511 | 546 | ||
512 | rcu_read_unlock(); | ||
513 | read_unlock(&head->lock); | ||
514 | local_bh_enable(); | ||
515 | |||
516 | return 0; | 547 | return 0; |
517 | |||
518 | } | 548 | } |
519 | 549 | ||
520 | static const struct seq_operations sctp_remaddr_ops = { | 550 | static const struct seq_operations sctp_remaddr_ops = { |
@@ -533,7 +563,7 @@ void sctp_remaddr_proc_exit(struct net *net) | |||
533 | static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) | 563 | static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) |
534 | { | 564 | { |
535 | return seq_open_net(inode, file, &sctp_remaddr_ops, | 565 | return seq_open_net(inode, file, &sctp_remaddr_ops, |
536 | sizeof(struct seq_net_private)); | 566 | sizeof(struct sctp_ht_iter)); |
537 | } | 567 | } |
538 | 568 | ||
539 | static const struct file_operations sctp_remaddr_seq_fops = { | 569 | static const struct file_operations sctp_remaddr_seq_fops = { |