linux/net/sctp/proc.c
<<
>>
Prefs
   1/* SCTP kernel implementation
   2 * Copyright (c) 2003 International Business Machines, Corp.
   3 *
   4 * This file is part of the SCTP kernel implementation
   5 *
   6 * This SCTP implementation is free software;
   7 * you can redistribute it and/or modify it under the terms of
   8 * the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2, or (at your option)
  10 * any later version.
  11 *
  12 * This SCTP implementation is distributed in the hope that it
  13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  14 *                 ************************
  15 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16 * See the GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with GNU CC; see the file COPYING.  If not, write to
  20 * the Free Software Foundation, 59 Temple Place - Suite 330,
  21 * Boston, MA 02111-1307, USA.
  22 *
  23 * Please send any bug reports or fixes you make to the
  24 * email address(es):
  25 *    lksctp developers <lksctp-developers@lists.sourceforge.net>
  26 *
  27 * Or submit a bug report through the following website:
  28 *    http://www.sf.net/projects/lksctp
  29 *
  30 * Written or modified by:
  31 *    Sridhar Samudrala <sri@us.ibm.com>
  32 *
  33 * Any bugs reported given to us we will try to fix... any fixes shared will
  34 * be incorporated into the next SCTP release.
  35 */
  36
  37#include <linux/types.h>
  38#include <linux/seq_file.h>
  39#include <linux/init.h>
  40#include <linux/export.h>
  41#include <net/sctp/sctp.h>
  42#include <net/ip.h> /* for snmp_fold_field */
  43
  44static const struct snmp_mib sctp_snmp_list[] = {
  45        SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
  46        SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
  47        SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
  48        SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS),
  49        SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS),
  50        SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES),
  51        SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS),
  52        SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS),
  53        SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS),
  54        SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS),
  55        SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS),
  56        SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS),
  57        SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS),
  58        SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS),
  59        SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS),
  60        SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS),
  61        SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS),
  62        SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS),
  63        SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS),
  64        SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS),
  65        SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS),
  66        SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS),
  67        SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS),
  68        SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS),
  69        SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS),
  70        SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS),
  71        SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS),
  72        SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS),
  73        SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ),
  74        SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG),
  75        SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS),
  76        SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS),
  77        SNMP_MIB_SENTINEL
  78};
  79
  80/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
  81static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
  82{
  83        struct net *net = seq->private;
  84        int i;
  85
  86        for (i = 0; sctp_snmp_list[i].name != NULL; i++)
  87                seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
  88                           snmp_fold_field((void __percpu **)net->sctp.sctp_statistics,
  89                                      sctp_snmp_list[i].entry));
  90
  91        return 0;
  92}
  93
  94/* Initialize the seq file operations for 'snmp' object. */
  95static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
  96{
  97        return single_open_net(inode, file, sctp_snmp_seq_show);
  98}
  99
 100static const struct file_operations sctp_snmp_seq_fops = {
 101        .owner   = THIS_MODULE,
 102        .open    = sctp_snmp_seq_open,
 103        .read    = seq_read,
 104        .llseek  = seq_lseek,
 105        .release = single_release_net,
 106};
 107
 108/* Set up the proc fs entry for 'snmp' object. */
 109int __net_init sctp_snmp_proc_init(struct net *net)
 110{
 111        struct proc_dir_entry *p;
 112
 113        p = proc_create("snmp", S_IRUGO, net->sctp.proc_net_sctp,
 114                        &sctp_snmp_seq_fops);
 115        if (!p)
 116                return -ENOMEM;
 117
 118        return 0;
 119}
 120
 121/* Cleanup the proc fs entry for 'snmp' object. */
 122void sctp_snmp_proc_exit(struct net *net)
 123{
 124        remove_proc_entry("snmp", net->sctp.proc_net_sctp);
 125}
 126
 127/* Dump local addresses of an association/endpoint. */
 128static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
 129{
 130        struct sctp_association *asoc;
 131        struct sctp_sockaddr_entry *laddr;
 132        struct sctp_transport *peer;
 133        union sctp_addr *addr, *primary = NULL;
 134        struct sctp_af *af;
 135
 136        if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
 137            asoc = sctp_assoc(epb);
 138            peer = asoc->peer.primary_path;
 139            primary = &peer->saddr;
 140        }
 141
 142        list_for_each_entry(laddr, &epb->bind_addr.address_list, list) {
 143                addr = &laddr->a;
 144                af = sctp_get_af_specific(addr->sa.sa_family);
 145                if (primary && af->cmp_addr(addr, primary)) {
 146                        seq_printf(seq, "*");
 147                }
 148                af->seq_dump_addr(seq, addr);
 149        }
 150}
 151
 152/* Dump remote addresses of an association. */
 153static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
 154{
 155        struct sctp_transport *transport;
 156        union sctp_addr *addr, *primary;
 157        struct sctp_af *af;
 158
 159        primary = &assoc->peer.primary_addr;
 160        list_for_each_entry(transport, &assoc->peer.transport_addr_list,
 161                        transports) {
 162                addr = &transport->ipaddr;
 163                af = sctp_get_af_specific(addr->sa.sa_family);
 164                if (af->cmp_addr(addr, primary)) {
 165                        seq_printf(seq, "*");
 166                }
 167                af->seq_dump_addr(seq, addr);
 168        }
 169}
 170
 171static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
 172{
 173        if (*pos >= sctp_ep_hashsize)
 174                return NULL;
 175
 176        if (*pos < 0)
 177                *pos = 0;
 178
 179        if (*pos == 0)
 180                seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");
 181
 182        return (void *)pos;
 183}
 184
 185static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
 186{
 187}
 188
 189
 190static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 191{
 192        if (++*pos >= sctp_ep_hashsize)
 193                return NULL;
 194
 195        return pos;
 196}
 197
 198
 199/* Display sctp endpoints (/proc/net/sctp/eps). */
 200static int sctp_eps_seq_show(struct seq_file *seq, void *v)
 201{
 202        struct sctp_hashbucket *head;
 203        struct sctp_ep_common *epb;
 204        struct sctp_endpoint *ep;
 205        struct sock *sk;
 206        struct hlist_node *node;
 207        int    hash = *(loff_t *)v;
 208
 209        if (hash >= sctp_ep_hashsize)
 210                return -ENOMEM;
 211
 212        head = &sctp_ep_hashtable[hash];
 213        sctp_local_bh_disable();
 214        read_lock(&head->lock);
 215        sctp_for_each_hentry(epb, node, &head->chain) {
 216                ep = sctp_ep(epb);
 217                sk = epb->sk;
 218                if (!net_eq(sock_net(sk), seq_file_net(seq)))
 219                        continue;
 220                seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
 221                           sctp_sk(sk)->type, sk->sk_state, hash,
 222                           epb->bind_addr.port,
 223                           from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 224                           sock_i_ino(sk));
 225
 226                sctp_seq_dump_local_addrs(seq, epb);
 227                seq_printf(seq, "\n");
 228        }
 229        read_unlock(&head->lock);
 230        sctp_local_bh_enable();
 231
 232        return 0;
 233}
 234
 235static const struct seq_operations sctp_eps_ops = {
 236        .start = sctp_eps_seq_start,
 237        .next  = sctp_eps_seq_next,
 238        .stop  = sctp_eps_seq_stop,
 239        .show  = sctp_eps_seq_show,
 240};
 241
 242
 243/* Initialize the seq file operations for 'eps' object. */
 244static int sctp_eps_seq_open(struct inode *inode, struct file *file)
 245{
 246        return seq_open_net(inode, file, &sctp_eps_ops,
 247                            sizeof(struct seq_net_private));
 248}
 249
 250static const struct file_operations sctp_eps_seq_fops = {
 251        .open    = sctp_eps_seq_open,
 252        .read    = seq_read,
 253        .llseek  = seq_lseek,
 254        .release = seq_release_net,
 255};
 256
 257/* Set up the proc fs entry for 'eps' object. */
 258int __net_init sctp_eps_proc_init(struct net *net)
 259{
 260        struct proc_dir_entry *p;
 261
 262        p = proc_create("eps", S_IRUGO, net->sctp.proc_net_sctp,
 263                        &sctp_eps_seq_fops);
 264        if (!p)
 265                return -ENOMEM;
 266
 267        return 0;
 268}
 269
 270/* Cleanup the proc fs entry for 'eps' object. */
 271void sctp_eps_proc_exit(struct net *net)
 272{
 273        remove_proc_entry("eps", net->sctp.proc_net_sctp);
 274}
 275
 276
 277static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
 278{
 279        if (*pos >= sctp_assoc_hashsize)
 280                return NULL;
 281
 282        if (*pos < 0)
 283                *pos = 0;
 284
 285        if (*pos == 0)
 286                seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT "
 287                                "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
 288                                "RPORT LADDRS <-> RADDRS "
 289                                "HBINT INS OUTS MAXRT T1X T2X RTXC\n");
 290
 291        return (void *)pos;
 292}
 293
 294static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
 295{
 296}
 297
 298
 299static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 300{
 301        if (++*pos >= sctp_assoc_hashsize)
 302                return NULL;
 303
 304        return pos;
 305}
 306
 307/* Display sctp associations (/proc/net/sctp/assocs). */
 308static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
 309{
 310        struct sctp_hashbucket *head;
 311        struct sctp_ep_common *epb;
 312        struct sctp_association *assoc;
 313        struct sock *sk;
 314        struct hlist_node *node;
 315        int    hash = *(loff_t *)v;
 316
 317        if (hash >= sctp_assoc_hashsize)
 318                return -ENOMEM;
 319
 320        head = &sctp_assoc_hashtable[hash];
 321        sctp_local_bh_disable();
 322        read_lock(&head->lock);
 323        sctp_for_each_hentry(epb, node, &head->chain) {
 324                assoc = sctp_assoc(epb);
 325                sk = epb->sk;
 326                if (!net_eq(sock_net(sk), seq_file_net(seq)))
 327                        continue;
 328                seq_printf(seq,
 329                           "%8pK %8pK %-3d %-3d %-2d %-4d "
 330                           "%4d %8d %8d %7d %5lu %-5d %5d ",
 331                           assoc, sk, sctp_sk(sk)->type, sk->sk_state,
 332                           assoc->state, hash,
 333                           assoc->assoc_id,
 334                           assoc->sndbuf_used,
 335                           atomic_read(&assoc->rmem_alloc),
 336                           from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 337                           sock_i_ino(sk),
 338                           epb->bind_addr.port,
 339                           assoc->peer.port);
 340                seq_printf(seq, " ");
 341                sctp_seq_dump_local_addrs(seq, epb);
 342                seq_printf(seq, "<-> ");
 343                sctp_seq_dump_remote_addrs(seq, assoc);
 344                seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ",
 345                        assoc->hbinterval, assoc->c.sinit_max_instreams,
 346                        assoc->c.sinit_num_ostreams, assoc->max_retrans,
 347                        assoc->init_retries, assoc->shutdown_retries,
 348                        assoc->rtx_data_chunks);
 349                seq_printf(seq, "\n");
 350        }
 351        read_unlock(&head->lock);
 352        sctp_local_bh_enable();
 353
 354        return 0;
 355}
 356
 357static const struct seq_operations sctp_assoc_ops = {
 358        .start = sctp_assocs_seq_start,
 359        .next  = sctp_assocs_seq_next,
 360        .stop  = sctp_assocs_seq_stop,
 361        .show  = sctp_assocs_seq_show,
 362};
 363
 364/* Initialize the seq file operations for 'assocs' object. */
 365static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
 366{
 367        return seq_open_net(inode, file, &sctp_assoc_ops,
 368                            sizeof(struct seq_net_private));
 369}
 370
 371static const struct file_operations sctp_assocs_seq_fops = {
 372        .open    = sctp_assocs_seq_open,
 373        .read    = seq_read,
 374        .llseek  = seq_lseek,
 375        .release = seq_release_net,
 376};
 377
 378/* Set up the proc fs entry for 'assocs' object. */
 379int __net_init sctp_assocs_proc_init(struct net *net)
 380{
 381        struct proc_dir_entry *p;
 382
 383        p = proc_create("assocs", S_IRUGO, net->sctp.proc_net_sctp,
 384                        &sctp_assocs_seq_fops);
 385        if (!p)
 386                return -ENOMEM;
 387
 388        return 0;
 389}
 390
 391/* Cleanup the proc fs entry for 'assocs' object. */
 392void sctp_assocs_proc_exit(struct net *net)
 393{
 394        remove_proc_entry("assocs", net->sctp.proc_net_sctp);
 395}
 396
 397static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
 398{
 399        if (*pos >= sctp_assoc_hashsize)
 400                return NULL;
 401
 402        if (*pos < 0)
 403                *pos = 0;
 404
 405        if (*pos == 0)
 406                seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
 407                                "REM_ADDR_RTX  START\n");
 408
 409        return (void *)pos;
 410}
 411
 412static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 413{
 414        if (++*pos >= sctp_assoc_hashsize)
 415                return NULL;
 416
 417        return pos;
 418}
 419
 420static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
 421{
 422}
 423
 424static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
 425{
 426        struct sctp_hashbucket *head;
 427        struct sctp_ep_common *epb;
 428        struct sctp_association *assoc;
 429        struct hlist_node *node;
 430        struct sctp_transport *tsp;
 431        int    hash = *(loff_t *)v;
 432
 433        if (hash >= sctp_assoc_hashsize)
 434                return -ENOMEM;
 435
 436        head = &sctp_assoc_hashtable[hash];
 437        sctp_local_bh_disable();
 438        read_lock(&head->lock);
 439        sctp_for_each_hentry(epb, node, &head->chain) {
 440                if (!net_eq(sock_net(epb->sk), seq_file_net(seq)))
 441                        continue;
 442                assoc = sctp_assoc(epb);
 443                list_for_each_entry(tsp, &assoc->peer.transport_addr_list,
 444                                        transports) {
 445                        /*
 446                         * The remote address (ADDR)
 447                         */
 448                        tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr);
 449                        seq_printf(seq, " ");
 450
 451                        /*
 452                         * The association ID (ASSOC_ID)
 453                         */
 454                        seq_printf(seq, "%d ", tsp->asoc->assoc_id);
 455
 456                        /*
 457                         * If the Heartbeat is active (HB_ACT)
 458                         * Note: 1 = Active, 0 = Inactive
 459                         */
 460                        seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer));
 461
 462                        /*
 463                         * Retransmit time out (RTO)
 464                         */
 465                        seq_printf(seq, "%lu ", tsp->rto);
 466
 467                        /*
 468                         * Maximum path retransmit count (PATH_MAX_RTX)
 469                         */
 470                        seq_printf(seq, "%d ", tsp->pathmaxrxt);
 471
 472                        /*
 473                         * remote address retransmit count (REM_ADDR_RTX)
 474                         * Note: We don't have a way to tally this at the moment
 475                         * so lets just leave it as zero for the moment
 476                         */
 477                        seq_printf(seq, "0 ");
 478
 479                        /*
 480                         * remote address start time (START).  This is also not
 481                         * currently implemented, but we can record it with a
 482                         * jiffies marker in a subsequent patch
 483                         */
 484                        seq_printf(seq, "0");
 485
 486                        seq_printf(seq, "\n");
 487                }
 488        }
 489
 490        read_unlock(&head->lock);
 491        sctp_local_bh_enable();
 492
 493        return 0;
 494
 495}
 496
 497static const struct seq_operations sctp_remaddr_ops = {
 498        .start = sctp_remaddr_seq_start,
 499        .next  = sctp_remaddr_seq_next,
 500        .stop  = sctp_remaddr_seq_stop,
 501        .show  = sctp_remaddr_seq_show,
 502};
 503
 504/* Cleanup the proc fs entry for 'remaddr' object. */
 505void sctp_remaddr_proc_exit(struct net *net)
 506{
 507        remove_proc_entry("remaddr", net->sctp.proc_net_sctp);
 508}
 509
 510static int sctp_remaddr_seq_open(struct inode *inode, struct file *file)
 511{
 512        return seq_open_net(inode, file, &sctp_remaddr_ops,
 513                            sizeof(struct seq_net_private));
 514}
 515
 516static const struct file_operations sctp_remaddr_seq_fops = {
 517        .open = sctp_remaddr_seq_open,
 518        .read = seq_read,
 519        .llseek = seq_lseek,
 520        .release = seq_release_net,
 521};
 522
 523int __net_init sctp_remaddr_proc_init(struct net *net)
 524{
 525        struct proc_dir_entry *p;
 526
 527        p = proc_create("remaddr", S_IRUGO, net->sctp.proc_net_sctp,
 528                        &sctp_remaddr_seq_fops);
 529        if (!p)
 530                return -ENOMEM;
 531        return 0;
 532}
 533
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.