linux/net/sctp/proc.c
<<
>>
Prefs
   1/* SCTP kernel reference Implementation
   2 * Copyright (c) 2003 International Business Machines, Corp.
   3 *
   4 * This file is part of the SCTP kernel reference Implementation
   5 *
   6 * The SCTP reference 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 * The SCTP reference 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 <net/sctp/sctp.h>
  41
  42static struct snmp_mib sctp_snmp_list[] = {
  43        SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
  44        SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
  45        SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
  46        SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS),
  47        SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS),
  48        SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES),
  49        SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS),
  50        SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS),
  51        SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS),
  52        SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS),
  53        SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS),
  54        SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS),
  55        SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS),
  56        SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS),
  57        SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS),
  58        SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS),
  59        SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS),
  60        SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS),
  61        SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS),
  62        SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS),
  63        SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS),
  64        SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS),
  65        SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS),
  66        SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS),
  67        SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS),
  68        SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS),
  69        SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS),
  70        SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS),
  71        SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ),
  72        SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG),
  73        SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS),
  74        SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS),
  75        SNMP_MIB_SENTINEL
  76};
  77
  78/* Return the current value of a particular entry in the mib by adding its
  79 * per cpu counters.
  80 */
  81static unsigned long
  82fold_field(void *mib[], int nr)
  83{
  84        unsigned long res = 0;
  85        int i;
  86
  87        for_each_possible_cpu(i) {
  88                res +=
  89                    *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) +
  90                                         sizeof (unsigned long) * nr));
  91                res +=
  92                    *((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) +
  93                                         sizeof (unsigned long) * nr));
  94        }
  95        return res;
  96}
  97
  98/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
  99static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
 100{
 101        int i;
 102
 103        for (i = 0; sctp_snmp_list[i].name != NULL; i++)
 104                seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
 105                           fold_field((void **)sctp_statistics,
 106                                      sctp_snmp_list[i].entry));
 107
 108        return 0;
 109}
 110
 111/* Initialize the seq file operations for 'snmp' object. */
 112static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
 113{
 114        return single_open(file, sctp_snmp_seq_show, NULL);
 115}
 116
 117static const struct file_operations sctp_snmp_seq_fops = {
 118        .owner   = THIS_MODULE,
 119        .open    = sctp_snmp_seq_open,
 120        .read    = seq_read,
 121        .llseek  = seq_lseek,
 122        .release = single_release,
 123};
 124
 125/* Set up the proc fs entry for 'snmp' object. */
 126int __init sctp_snmp_proc_init(void)
 127{
 128        struct proc_dir_entry *p;
 129
 130        p = create_proc_entry("snmp", S_IRUGO, proc_net_sctp);
 131        if (!p)
 132                return -ENOMEM;
 133
 134        p->proc_fops = &sctp_snmp_seq_fops;
 135
 136        return 0;
 137}
 138
 139/* Cleanup the proc fs entry for 'snmp' object. */
 140void sctp_snmp_proc_exit(void)
 141{
 142        remove_proc_entry("snmp", proc_net_sctp);
 143}
 144
 145/* Dump local addresses of an association/endpoint. */
 146static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
 147{
 148        struct list_head *pos;
 149        struct sctp_association *asoc;
 150        struct sctp_sockaddr_entry *laddr;
 151        struct sctp_transport *peer;
 152        union sctp_addr *addr, *primary = NULL;
 153        struct sctp_af *af;
 154
 155        if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
 156            asoc = sctp_assoc(epb);
 157            peer = asoc->peer.primary_path;
 158            primary = &peer->saddr;
 159        }
 160
 161        list_for_each(pos, &epb->bind_addr.address_list) {
 162                laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
 163                addr = &laddr->a;
 164                af = sctp_get_af_specific(addr->sa.sa_family);
 165                if (primary && af->cmp_addr(addr, primary)) {
 166                        seq_printf(seq, "*");
 167                }
 168                af->seq_dump_addr(seq, addr);
 169        }
 170}
 171
 172/* Dump remote addresses of an association. */
 173static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
 174{
 175        struct list_head *pos;
 176        struct sctp_transport *transport;
 177        union sctp_addr *addr, *primary;
 178        struct sctp_af *af;
 179
 180        primary = &assoc->peer.primary_addr;
 181        list_for_each(pos, &assoc->peer.transport_addr_list) {
 182                transport = list_entry(pos, struct sctp_transport, transports);
 183                addr = &transport->ipaddr;
 184                af = sctp_get_af_specific(addr->sa.sa_family);
 185                if (af->cmp_addr(addr, primary)) {
 186                        seq_printf(seq, "*");
 187                }
 188                af->seq_dump_addr(seq, addr);
 189        }
 190}
 191
 192static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
 193{
 194        if (*pos >= sctp_ep_hashsize)
 195                return NULL;
 196
 197        if (*pos < 0)
 198                *pos = 0;
 199
 200        if (*pos == 0)
 201                seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");
 202
 203        return (void *)pos;
 204}
 205
 206static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
 207{
 208        return;
 209}
 210
 211
 212static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 213{
 214        if (++*pos >= sctp_ep_hashsize)
 215                return NULL;
 216
 217        return pos;
 218}
 219
 220
 221/* Display sctp endpoints (/proc/net/sctp/eps). */
 222static int sctp_eps_seq_show(struct seq_file *seq, void *v)
 223{
 224        struct sctp_hashbucket *head;
 225        struct sctp_ep_common *epb;
 226        struct sctp_endpoint *ep;
 227        struct sock *sk;
 228        struct hlist_node *node;
 229        int    hash = *(loff_t *)v;
 230
 231        if (hash >= sctp_ep_hashsize)
 232                return -ENOMEM;
 233
 234        head = &sctp_ep_hashtable[hash];
 235        sctp_local_bh_disable();
 236        read_lock(&head->lock);
 237        sctp_for_each_hentry(epb, node, &head->chain) {
 238                ep = sctp_ep(epb);
 239                sk = epb->sk;
 240                seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
 241                           sctp_sk(sk)->type, sk->sk_state, hash,
 242                           epb->bind_addr.port,
 243                           sock_i_uid(sk), sock_i_ino(sk));
 244
 245                sctp_seq_dump_local_addrs(seq, epb);
 246                seq_printf(seq, "\n");
 247        }
 248        read_unlock(&head->lock);
 249        sctp_local_bh_enable();
 250
 251        return 0;
 252}
 253
 254static const struct seq_operations sctp_eps_ops = {
 255        .start = sctp_eps_seq_start,
 256        .next  = sctp_eps_seq_next,
 257        .stop  = sctp_eps_seq_stop,
 258        .show  = sctp_eps_seq_show,
 259};
 260
 261
 262/* Initialize the seq file operations for 'eps' object. */
 263static int sctp_eps_seq_open(struct inode *inode, struct file *file)
 264{
 265        return seq_open(file, &sctp_eps_ops);
 266}
 267
 268static const struct file_operations sctp_eps_seq_fops = {
 269        .open    = sctp_eps_seq_open,
 270        .read    = seq_read,
 271        .llseek  = seq_lseek,
 272        .release = seq_release,
 273};
 274
 275/* Set up the proc fs entry for 'eps' object. */
 276int __init sctp_eps_proc_init(void)
 277{
 278        struct proc_dir_entry *p;
 279
 280        p = create_proc_entry("eps", S_IRUGO, proc_net_sctp);
 281        if (!p)
 282                return -ENOMEM;
 283
 284        p->proc_fops = &sctp_eps_seq_fops;
 285
 286        return 0;
 287}
 288
 289/* Cleanup the proc fs entry for 'eps' object. */
 290void sctp_eps_proc_exit(void)
 291{
 292        remove_proc_entry("eps", proc_net_sctp);
 293}
 294
 295
 296static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
 297{
 298        if (*pos >= sctp_assoc_hashsize)
 299                return NULL;
 300
 301        if (*pos < 0)
 302                *pos = 0;
 303
 304        if (*pos == 0)
 305                seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
 306                                "RPORT LADDRS <-> RADDRS\n");
 307
 308        return (void *)pos;
 309}
 310
 311static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
 312{
 313        return;
 314}
 315
 316
 317static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 318{
 319        if (++*pos >= sctp_assoc_hashsize)
 320                return NULL;
 321
 322        return pos;
 323}
 324
 325/* Display sctp associations (/proc/net/sctp/assocs). */
 326static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
 327{
 328        struct sctp_hashbucket *head;
 329        struct sctp_ep_common *epb;
 330        struct sctp_association *assoc;
 331        struct sock *sk;
 332        struct hlist_node *node;
 333        int    hash = *(loff_t *)v;
 334
 335        if (hash >= sctp_assoc_hashsize)
 336                return -ENOMEM;
 337
 338        head = &sctp_assoc_hashtable[hash];
 339        sctp_local_bh_disable();
 340        read_lock(&head->lock);
 341        sctp_for_each_hentry(epb, node, &head->chain) {
 342                assoc = sctp_assoc(epb);
 343                sk = epb->sk;
 344                seq_printf(seq,
 345                           "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
 346                           assoc, sk, sctp_sk(sk)->type, sk->sk_state,
 347                           assoc->state, hash, assoc->assoc_id,
 348                           assoc->sndbuf_used,
 349                           atomic_read(&assoc->rmem_alloc),
 350                           sock_i_uid(sk), sock_i_ino(sk),
 351                           epb->bind_addr.port,
 352                           assoc->peer.port);
 353
 354                seq_printf(seq, " ");
 355                sctp_seq_dump_local_addrs(seq, epb);
 356                seq_printf(seq, "<-> ");
 357                sctp_seq_dump_remote_addrs(seq, assoc);
 358                seq_printf(seq, "\n");
 359        }
 360        read_unlock(&head->lock);
 361        sctp_local_bh_enable();
 362
 363        return 0;
 364}
 365
 366static const struct seq_operations sctp_assoc_ops = {
 367        .start = sctp_assocs_seq_start,
 368        .next  = sctp_assocs_seq_next,
 369        .stop  = sctp_assocs_seq_stop,
 370        .show  = sctp_assocs_seq_show,
 371};
 372
 373/* Initialize the seq file operations for 'assocs' object. */
 374static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
 375{
 376        return seq_open(file, &sctp_assoc_ops);
 377}
 378
 379static const struct file_operations sctp_assocs_seq_fops = {
 380        .open    = sctp_assocs_seq_open,
 381        .read    = seq_read,
 382        .llseek  = seq_lseek,
 383        .release = seq_release,
 384};
 385
 386/* Set up the proc fs entry for 'assocs' object. */
 387int __init sctp_assocs_proc_init(void)
 388{
 389        struct proc_dir_entry *p;
 390
 391        p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp);
 392        if (!p)
 393                return -ENOMEM;
 394
 395        p->proc_fops = &sctp_assocs_seq_fops;
 396
 397        return 0;
 398}
 399
 400/* Cleanup the proc fs entry for 'assocs' object. */
 401void sctp_assocs_proc_exit(void)
 402{
 403        remove_proc_entry("assocs", proc_net_sctp);
 404}
 405