linux/net/ipv6/proc.c
<<
>>
Prefs
   1/*
   2 * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3 *              operating system.  INET is implemented using the  BSD Socket
   4 *              interface as the means of communication with the user level.
   5 *
   6 *              This file implements the various access functions for the
   7 *              PROC file system.  This is very similar to the IPv4 version,
   8 *              except it reports the sockets in the INET6 address family.
   9 *
  10 * Authors:     David S. Miller (davem@caip.rutgers.edu)
  11 *              YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  12 *
  13 *              This program is free software; you can redistribute it and/or
  14 *              modify it under the terms of the GNU General Public License
  15 *              as published by the Free Software Foundation; either version
  16 *              2 of the License, or (at your option) any later version.
  17 */
  18#include <linux/socket.h>
  19#include <linux/net.h>
  20#include <linux/ipv6.h>
  21#include <linux/proc_fs.h>
  22#include <linux/seq_file.h>
  23#include <linux/stddef.h>
  24#include <net/net_namespace.h>
  25#include <net/ip.h>
  26#include <net/sock.h>
  27#include <net/tcp.h>
  28#include <net/udp.h>
  29#include <net/transp_v6.h>
  30#include <net/ipv6.h>
  31
  32static int sockstat6_seq_show(struct seq_file *seq, void *v)
  33{
  34        struct net *net = seq->private;
  35
  36        seq_printf(seq, "TCP6: inuse %d\n",
  37                       sock_prot_inuse_get(net, &tcpv6_prot));
  38        seq_printf(seq, "UDP6: inuse %d\n",
  39                       sock_prot_inuse_get(net, &udpv6_prot));
  40        seq_printf(seq, "UDPLITE6: inuse %d\n",
  41                        sock_prot_inuse_get(net, &udplitev6_prot));
  42        seq_printf(seq, "RAW6: inuse %d\n",
  43                       sock_prot_inuse_get(net, &rawv6_prot));
  44        seq_printf(seq, "FRAG6: inuse %d memory %d\n",
  45                       ip6_frag_nqueues(net), ip6_frag_mem(net));
  46        return 0;
  47}
  48
  49static int sockstat6_seq_open(struct inode *inode, struct file *file)
  50{
  51        return single_open_net(inode, file, sockstat6_seq_show);
  52}
  53
  54static const struct file_operations sockstat6_seq_fops = {
  55        .owner   = THIS_MODULE,
  56        .open    = sockstat6_seq_open,
  57        .read    = seq_read,
  58        .llseek  = seq_lseek,
  59        .release = single_release_net,
  60};
  61
  62static const struct snmp_mib snmp6_ipstats_list[] = {
  63/* ipv6 mib according to RFC 2465 */
  64        SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS),
  65        SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS),
  66        SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS),
  67        SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES),
  68        SNMP_MIB_ITEM("Ip6InAddrErrors", IPSTATS_MIB_INADDRERRORS),
  69        SNMP_MIB_ITEM("Ip6InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS),
  70        SNMP_MIB_ITEM("Ip6InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS),
  71        SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS),
  72        SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS),
  73        SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS),
  74        SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTPKTS),
  75        SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS),
  76        SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES),
  77        SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT),
  78        SNMP_MIB_ITEM("Ip6ReasmReqds", IPSTATS_MIB_REASMREQDS),
  79        SNMP_MIB_ITEM("Ip6ReasmOKs", IPSTATS_MIB_REASMOKS),
  80        SNMP_MIB_ITEM("Ip6ReasmFails", IPSTATS_MIB_REASMFAILS),
  81        SNMP_MIB_ITEM("Ip6FragOKs", IPSTATS_MIB_FRAGOKS),
  82        SNMP_MIB_ITEM("Ip6FragFails", IPSTATS_MIB_FRAGFAILS),
  83        SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES),
  84        SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS),
  85        SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS),
  86        SNMP_MIB_ITEM("Ip6InOctets", IPSTATS_MIB_INOCTETS),
  87        SNMP_MIB_ITEM("Ip6OutOctets", IPSTATS_MIB_OUTOCTETS),
  88        SNMP_MIB_ITEM("Ip6InMcastOctets", IPSTATS_MIB_INMCASTOCTETS),
  89        SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS),
  90        SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
  91        SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
  92        SNMP_MIB_SENTINEL
  93};
  94
  95static const struct snmp_mib snmp6_icmp6_list[] = {
  96/* icmpv6 mib according to RFC 2466 */
  97        SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS),
  98        SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS),
  99        SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
 100        SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
 101        SNMP_MIB_SENTINEL
 102};
 103
 104/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */
 105static const char *const icmp6type2name[256] = {
 106        [ICMPV6_DEST_UNREACH] = "DestUnreachs",
 107        [ICMPV6_PKT_TOOBIG] = "PktTooBigs",
 108        [ICMPV6_TIME_EXCEED] = "TimeExcds",
 109        [ICMPV6_PARAMPROB] = "ParmProblems",
 110        [ICMPV6_ECHO_REQUEST] = "Echos",
 111        [ICMPV6_ECHO_REPLY] = "EchoReplies",
 112        [ICMPV6_MGM_QUERY] = "GroupMembQueries",
 113        [ICMPV6_MGM_REPORT] = "GroupMembResponses",
 114        [ICMPV6_MGM_REDUCTION] = "GroupMembReductions",
 115        [ICMPV6_MLD2_REPORT] = "MLDv2Reports",
 116        [NDISC_ROUTER_ADVERTISEMENT] = "RouterAdvertisements",
 117        [NDISC_ROUTER_SOLICITATION] = "RouterSolicits",
 118        [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements",
 119        [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits",
 120        [NDISC_REDIRECT] = "Redirects",
 121};
 122
 123
 124static const struct snmp_mib snmp6_udp6_list[] = {
 125        SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS),
 126        SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS),
 127        SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS),
 128        SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
 129        SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
 130        SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS),
 131        SNMP_MIB_SENTINEL
 132};
 133
 134static const struct snmp_mib snmp6_udplite6_list[] = {
 135        SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS),
 136        SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS),
 137        SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS),
 138        SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
 139        SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
 140        SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS),
 141        SNMP_MIB_SENTINEL
 142};
 143
 144static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib)
 145{
 146        char name[32];
 147        int i;
 148
 149        /* print by name -- deprecated items */
 150        for (i = 0; i < ICMP6MSG_MIB_MAX; i++) {
 151                int icmptype;
 152                const char *p;
 153
 154                icmptype = i & 0xff;
 155                p = icmp6type2name[icmptype];
 156                if (!p) /* don't print un-named types here */
 157                        continue;
 158                snprintf(name, sizeof(name), "Icmp6%s%s",
 159                        i & 0x100 ? "Out" : "In", p);
 160                seq_printf(seq, "%-32s\t%lu\n", name,
 161                        snmp_fold_field(mib, i));
 162        }
 163
 164        /* print by number (nonzero only) - ICMPMsgStat format */
 165        for (i = 0; i < ICMP6MSG_MIB_MAX; i++) {
 166                unsigned long val;
 167
 168                val = snmp_fold_field(mib, i);
 169                if (!val)
 170                        continue;
 171                snprintf(name, sizeof(name), "Icmp6%sType%u",
 172                        i & 0x100 ?  "Out" : "In", i & 0xff);
 173                seq_printf(seq, "%-32s\t%lu\n", name, val);
 174        }
 175}
 176
 177static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
 178                                const struct snmp_mib *itemlist)
 179{
 180        int i;
 181
 182        for (i = 0; itemlist[i].name; i++)
 183                seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
 184                           snmp_fold_field(mib, itemlist[i].entry));
 185}
 186
 187static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib,
 188                                  const struct snmp_mib *itemlist, size_t syncpoff)
 189{
 190        int i;
 191
 192        for (i = 0; itemlist[i].name; i++)
 193                seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name,
 194                           snmp_fold_field64(mib, itemlist[i].entry, syncpoff));
 195}
 196
 197static int snmp6_seq_show(struct seq_file *seq, void *v)
 198{
 199        struct net *net = (struct net *)seq->private;
 200
 201        snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics,
 202                            snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
 203        snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
 204                            snmp6_icmp6_list);
 205        snmp6_seq_show_icmpv6msg(seq,
 206                            (void __percpu **)net->mib.icmpv6msg_statistics);
 207        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6,
 208                            snmp6_udp6_list);
 209        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6,
 210                            snmp6_udplite6_list);
 211        return 0;
 212}
 213
 214static int snmp6_seq_open(struct inode *inode, struct file *file)
 215{
 216        return single_open_net(inode, file, snmp6_seq_show);
 217}
 218
 219static const struct file_operations snmp6_seq_fops = {
 220        .owner   = THIS_MODULE,
 221        .open    = snmp6_seq_open,
 222        .read    = seq_read,
 223        .llseek  = seq_lseek,
 224        .release = single_release_net,
 225};
 226
 227static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
 228{
 229        struct inet6_dev *idev = (struct inet6_dev *)seq->private;
 230
 231        seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
 232        snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6,
 233                            snmp6_ipstats_list);
 234        snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6,
 235                            snmp6_icmp6_list);
 236        snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg);
 237        return 0;
 238}
 239
 240static int snmp6_dev_seq_open(struct inode *inode, struct file *file)
 241{
 242        return single_open(file, snmp6_dev_seq_show, PDE(inode)->data);
 243}
 244
 245static const struct file_operations snmp6_dev_seq_fops = {
 246        .owner   = THIS_MODULE,
 247        .open    = snmp6_dev_seq_open,
 248        .read    = seq_read,
 249        .llseek  = seq_lseek,
 250        .release = single_release,
 251};
 252
 253int snmp6_register_dev(struct inet6_dev *idev)
 254{
 255        struct proc_dir_entry *p;
 256        struct net *net;
 257
 258        if (!idev || !idev->dev)
 259                return -EINVAL;
 260
 261        net = dev_net(idev->dev);
 262        if (!net->mib.proc_net_devsnmp6)
 263                return -ENOENT;
 264
 265        p = proc_create_data(idev->dev->name, S_IRUGO,
 266                             net->mib.proc_net_devsnmp6,
 267                             &snmp6_dev_seq_fops, idev);
 268        if (!p)
 269                return -ENOMEM;
 270
 271        idev->stats.proc_dir_entry = p;
 272        return 0;
 273}
 274
 275int snmp6_unregister_dev(struct inet6_dev *idev)
 276{
 277        struct net *net = dev_net(idev->dev);
 278        if (!net->mib.proc_net_devsnmp6)
 279                return -ENOENT;
 280        if (!idev->stats.proc_dir_entry)
 281                return -EINVAL;
 282        remove_proc_entry(idev->stats.proc_dir_entry->name,
 283                          net->mib.proc_net_devsnmp6);
 284        idev->stats.proc_dir_entry = NULL;
 285        return 0;
 286}
 287
 288static int __net_init ipv6_proc_init_net(struct net *net)
 289{
 290        if (!proc_net_fops_create(net, "sockstat6", S_IRUGO,
 291                        &sockstat6_seq_fops))
 292                return -ENOMEM;
 293
 294        if (!proc_net_fops_create(net, "snmp6", S_IRUGO, &snmp6_seq_fops))
 295                goto proc_snmp6_fail;
 296
 297        net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net);
 298        if (!net->mib.proc_net_devsnmp6)
 299                goto proc_dev_snmp6_fail;
 300        return 0;
 301
 302proc_snmp6_fail:
 303        proc_net_remove(net, "sockstat6");
 304proc_dev_snmp6_fail:
 305        proc_net_remove(net, "dev_snmp6");
 306        return -ENOMEM;
 307}
 308
 309static void __net_exit ipv6_proc_exit_net(struct net *net)
 310{
 311        proc_net_remove(net, "sockstat6");
 312        proc_net_remove(net, "dev_snmp6");
 313        proc_net_remove(net, "snmp6");
 314}
 315
 316static struct pernet_operations ipv6_proc_ops = {
 317        .init = ipv6_proc_init_net,
 318        .exit = ipv6_proc_exit_net,
 319};
 320
 321int __init ipv6_misc_proc_init(void)
 322{
 323        return register_pernet_subsys(&ipv6_proc_ops);
 324}
 325
 326void ipv6_misc_proc_exit(void)
 327{
 328        unregister_pernet_subsys(&ipv6_proc_ops);
 329}
 330
 331