2005-04-17 02:20:36 +04:00
/*
* INET An implementation of the TCP / IP protocol suite for the LINUX
* operating system . INET is implemented using the BSD Socket
* interface as the means of communication with the user level .
*
* This file implements the various access functions for the
* PROC file system . This is very similar to the IPv4 version ,
* except it reports the sockets in the INET6 address family .
*
* Authors : David S . Miller ( davem @ caip . rutgers . edu )
* YOSHIFUJI Hideaki < yoshfuji @ linux - ipv6 . org >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/socket.h>
# include <linux/net.h>
# include <linux/ipv6.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/stddef.h>
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2007-04-25 08:54:09 +04:00
# include <net/ip.h>
2005-04-17 02:20:36 +04:00
# include <net/sock.h>
# include <net/tcp.h>
2007-12-11 22:30:32 +03:00
# include <net/udp.h>
2005-04-17 02:20:36 +04:00
# include <net/transp_v6.h>
# include <net/ipv6.h>
static int sockstat6_seq_show ( struct seq_file * seq , void * v )
{
2008-04-01 06:43:43 +04:00
struct net * net = seq - > private ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " TCP6: inuse %d \n " ,
2008-04-01 06:43:43 +04:00
sock_prot_inuse_get ( net , & tcpv6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " UDP6: inuse %d \n " ,
2008-04-01 06:43:43 +04:00
sock_prot_inuse_get ( net , & udpv6_prot ) ) ;
2006-11-27 22:10:57 +03:00
seq_printf ( seq , " UDPLITE6: inuse %d \n " ,
2008-04-01 06:43:43 +04:00
sock_prot_inuse_get ( net , & udplitev6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " RAW6: inuse %d \n " ,
2008-04-01 06:43:43 +04:00
sock_prot_inuse_get ( net , & rawv6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " FRAG6: inuse %d memory %d \n " ,
2008-04-01 06:43:43 +04:00
ip6_frag_nqueues ( net ) , ip6_frag_mem ( net ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-10-08 01:46:47 +04:00
static int sockstat6_seq_open ( struct inode * inode , struct file * file )
{
return single_open_net ( inode , file , sockstat6_seq_show ) ;
}
static const struct file_operations sockstat6_seq_fops = {
. owner = THIS_MODULE ,
. open = sockstat6_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release_net ,
} ;
2010-01-22 13:17:26 +03:00
static const struct snmp_mib snmp6_ipstats_list [ ] = {
2005-04-17 02:20:36 +04:00
/* ipv6 mib according to RFC 2465 */
2009-04-27 13:45:02 +04:00
SNMP_MIB_ITEM ( " Ip6InReceives " , IPSTATS_MIB_INPKTS ) ,
2005-04-17 02:20:36 +04:00
SNMP_MIB_ITEM ( " Ip6InHdrErrors " , IPSTATS_MIB_INHDRERRORS ) ,
SNMP_MIB_ITEM ( " Ip6InTooBigErrors " , IPSTATS_MIB_INTOOBIGERRORS ) ,
SNMP_MIB_ITEM ( " Ip6InNoRoutes " , IPSTATS_MIB_INNOROUTES ) ,
SNMP_MIB_ITEM ( " Ip6InAddrErrors " , IPSTATS_MIB_INADDRERRORS ) ,
SNMP_MIB_ITEM ( " Ip6InUnknownProtos " , IPSTATS_MIB_INUNKNOWNPROTOS ) ,
SNMP_MIB_ITEM ( " Ip6InTruncatedPkts " , IPSTATS_MIB_INTRUNCATEDPKTS ) ,
SNMP_MIB_ITEM ( " Ip6InDiscards " , IPSTATS_MIB_INDISCARDS ) ,
SNMP_MIB_ITEM ( " Ip6InDelivers " , IPSTATS_MIB_INDELIVERS ) ,
SNMP_MIB_ITEM ( " Ip6OutForwDatagrams " , IPSTATS_MIB_OUTFORWDATAGRAMS ) ,
2009-04-27 13:45:02 +04:00
SNMP_MIB_ITEM ( " Ip6OutRequests " , IPSTATS_MIB_OUTPKTS ) ,
2005-04-17 02:20:36 +04:00
SNMP_MIB_ITEM ( " Ip6OutDiscards " , IPSTATS_MIB_OUTDISCARDS ) ,
SNMP_MIB_ITEM ( " Ip6OutNoRoutes " , IPSTATS_MIB_OUTNOROUTES ) ,
SNMP_MIB_ITEM ( " Ip6ReasmTimeout " , IPSTATS_MIB_REASMTIMEOUT ) ,
SNMP_MIB_ITEM ( " Ip6ReasmReqds " , IPSTATS_MIB_REASMREQDS ) ,
SNMP_MIB_ITEM ( " Ip6ReasmOKs " , IPSTATS_MIB_REASMOKS ) ,
SNMP_MIB_ITEM ( " Ip6ReasmFails " , IPSTATS_MIB_REASMFAILS ) ,
SNMP_MIB_ITEM ( " Ip6FragOKs " , IPSTATS_MIB_FRAGOKS ) ,
SNMP_MIB_ITEM ( " Ip6FragFails " , IPSTATS_MIB_FRAGFAILS ) ,
SNMP_MIB_ITEM ( " Ip6FragCreates " , IPSTATS_MIB_FRAGCREATES ) ,
SNMP_MIB_ITEM ( " Ip6InMcastPkts " , IPSTATS_MIB_INMCASTPKTS ) ,
SNMP_MIB_ITEM ( " Ip6OutMcastPkts " , IPSTATS_MIB_OUTMCASTPKTS ) ,
2009-04-27 13:45:02 +04:00
SNMP_MIB_ITEM ( " Ip6InOctets " , IPSTATS_MIB_INOCTETS ) ,
SNMP_MIB_ITEM ( " Ip6OutOctets " , IPSTATS_MIB_OUTOCTETS ) ,
SNMP_MIB_ITEM ( " Ip6InMcastOctets " , IPSTATS_MIB_INMCASTOCTETS ) ,
SNMP_MIB_ITEM ( " Ip6OutMcastOctets " , IPSTATS_MIB_OUTMCASTOCTETS ) ,
SNMP_MIB_ITEM ( " Ip6InBcastOctets " , IPSTATS_MIB_INBCASTOCTETS ) ,
SNMP_MIB_ITEM ( " Ip6OutBcastOctets " , IPSTATS_MIB_OUTBCASTOCTETS ) ,
2005-04-17 02:20:36 +04:00
SNMP_MIB_SENTINEL
} ;
2010-01-22 13:17:26 +03:00
static const struct snmp_mib snmp6_icmp6_list [ ] = {
2007-09-17 03:52:35 +04:00
/* icmpv6 mib according to RFC 2466 */
2005-04-17 02:20:36 +04:00
SNMP_MIB_ITEM ( " Icmp6InMsgs " , ICMP6_MIB_INMSGS ) ,
SNMP_MIB_ITEM ( " Icmp6InErrors " , ICMP6_MIB_INERRORS ) ,
SNMP_MIB_ITEM ( " Icmp6OutMsgs " , ICMP6_MIB_OUTMSGS ) ,
2010-04-04 02:09:04 +04:00
SNMP_MIB_ITEM ( " Icmp6OutErrors " , ICMP6_MIB_OUTERRORS ) ,
2005-04-17 02:20:36 +04:00
SNMP_MIB_SENTINEL
} ;
2007-09-17 03:52:35 +04:00
/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */
2009-08-05 21:42:58 +04:00
static const char * const icmp6type2name [ 256 ] = {
2007-09-17 03:52:35 +04:00
[ ICMPV6_DEST_UNREACH ] = " DestUnreachs " ,
[ ICMPV6_PKT_TOOBIG ] = " PktTooBigs " ,
[ ICMPV6_TIME_EXCEED ] = " TimeExcds " ,
[ ICMPV6_PARAMPROB ] = " ParmProblems " ,
2008-01-21 14:05:43 +03:00
[ ICMPV6_ECHO_REQUEST ] = " Echos " ,
2007-09-17 03:52:35 +04:00
[ ICMPV6_ECHO_REPLY ] = " EchoReplies " ,
[ ICMPV6_MGM_QUERY ] = " GroupMembQueries " ,
[ ICMPV6_MGM_REPORT ] = " GroupMembResponses " ,
[ ICMPV6_MGM_REDUCTION ] = " GroupMembReductions " ,
[ ICMPV6_MLD2_REPORT ] = " MLDv2Reports " ,
[ NDISC_ROUTER_ADVERTISEMENT ] = " RouterAdvertisements " ,
[ NDISC_ROUTER_SOLICITATION ] = " RouterSolicits " ,
[ NDISC_NEIGHBOUR_ADVERTISEMENT ] = " NeighborAdvertisements " ,
[ NDISC_NEIGHBOUR_SOLICITATION ] = " NeighborSolicits " ,
2008-01-21 14:05:43 +03:00
[ NDISC_REDIRECT ] = " Redirects " ,
2007-09-17 03:52:35 +04:00
} ;
2010-01-22 13:17:26 +03:00
static const struct snmp_mib snmp6_udp6_list [ ] = {
2005-04-17 02:20:36 +04:00
SNMP_MIB_ITEM ( " Udp6InDatagrams " , UDP_MIB_INDATAGRAMS ) ,
SNMP_MIB_ITEM ( " Udp6NoPorts " , UDP_MIB_NOPORTS ) ,
SNMP_MIB_ITEM ( " Udp6InErrors " , UDP_MIB_INERRORS ) ,
SNMP_MIB_ITEM ( " Udp6OutDatagrams " , UDP_MIB_OUTDATAGRAMS ) ,
2010-10-31 02:17:23 +03:00
SNMP_MIB_ITEM ( " Udp6RcvbufErrors " , UDP_MIB_RCVBUFERRORS ) ,
SNMP_MIB_ITEM ( " Udp6SndbufErrors " , UDP_MIB_SNDBUFERRORS ) ,
2005-04-17 02:20:36 +04:00
SNMP_MIB_SENTINEL
} ;
2010-01-22 13:17:26 +03:00
static const struct snmp_mib snmp6_udplite6_list [ ] = {
2006-11-27 22:10:57 +03:00
SNMP_MIB_ITEM ( " UdpLite6InDatagrams " , UDP_MIB_INDATAGRAMS ) ,
SNMP_MIB_ITEM ( " UdpLite6NoPorts " , UDP_MIB_NOPORTS ) ,
SNMP_MIB_ITEM ( " UdpLite6InErrors " , UDP_MIB_INERRORS ) ,
SNMP_MIB_ITEM ( " UdpLite6OutDatagrams " , UDP_MIB_OUTDATAGRAMS ) ,
2010-10-31 02:17:23 +03:00
SNMP_MIB_ITEM ( " UdpLite6RcvbufErrors " , UDP_MIB_RCVBUFERRORS ) ,
SNMP_MIB_ITEM ( " UdpLite6SndbufErrors " , UDP_MIB_SNDBUFERRORS ) ,
2006-11-27 22:10:57 +03:00
SNMP_MIB_SENTINEL
} ;
2011-11-13 05:24:04 +04:00
static void snmp6_seq_show_icmpv6msg ( struct seq_file * seq , atomic_long_t * smib )
2007-09-17 03:52:35 +04:00
{
2008-11-20 15:20:10 +03:00
char name [ 32 ] ;
2007-09-17 03:52:35 +04:00
int i ;
/* print by name -- deprecated items */
for ( i = 0 ; i < ICMP6MSG_MIB_MAX ; i + + ) {
int icmptype ;
2009-08-05 21:42:58 +04:00
const char * p ;
2007-09-17 03:52:35 +04:00
icmptype = i & 0xff ;
p = icmp6type2name [ icmptype ] ;
if ( ! p ) /* don't print un-named types here */
continue ;
2008-11-20 15:20:10 +03:00
snprintf ( name , sizeof ( name ) , " Icmp6%s%s " ,
2007-09-17 03:52:35 +04:00
i & 0x100 ? " Out " : " In " , p ) ;
seq_printf ( seq , " %-32s \t %lu \n " , name ,
2011-11-13 05:24:04 +04:00
atomic_long_read ( smib + i ) ) ;
2007-09-17 03:52:35 +04:00
}
/* print by number (nonzero only) - ICMPMsgStat format */
for ( i = 0 ; i < ICMP6MSG_MIB_MAX ; i + + ) {
unsigned long val ;
2011-11-13 05:24:04 +04:00
val = atomic_long_read ( smib + i ) ;
2007-09-17 03:52:35 +04:00
if ( ! val )
continue ;
2008-11-20 15:20:10 +03:00
snprintf ( name , sizeof ( name ) , " Icmp6%sType%u " ,
2007-09-17 03:52:35 +04:00
i & 0x100 ? " Out " : " In " , i & 0xff ) ;
seq_printf ( seq , " %-32s \t %lu \n " , name , val ) ;
}
}
2011-05-19 05:14:23 +04:00
/* can be called either with percpu mib (pcpumib != NULL),
* or shared one ( smib ! = NULL )
*/
static void snmp6_seq_show_item ( struct seq_file * seq , void __percpu * * pcpumib ,
atomic_long_t * smib ,
2010-01-22 13:17:26 +03:00
const struct snmp_mib * itemlist )
2005-04-17 02:20:36 +04:00
{
int i ;
2011-05-19 05:14:23 +04:00
unsigned long val ;
2010-07-01 00:31:19 +04:00
2011-05-19 05:14:23 +04:00
for ( i = 0 ; itemlist [ i ] . name ; i + + ) {
val = pcpumib ?
snmp_fold_field ( pcpumib , itemlist [ i ] . entry ) :
atomic_long_read ( smib + itemlist [ i ] . entry ) ;
seq_printf ( seq , " %-32s \t %lu \n " , itemlist [ i ] . name , val ) ;
}
2005-04-17 02:20:36 +04:00
}
2010-07-01 00:31:19 +04:00
static void snmp6_seq_show_item64 ( struct seq_file * seq , void __percpu * * mib ,
const struct snmp_mib * itemlist , size_t syncpoff )
{
int i ;
for ( i = 0 ; itemlist [ i ] . name ; i + + )
seq_printf ( seq , " %-32s \t %llu \n " , itemlist [ i ] . name ,
snmp_fold_field64 ( mib , itemlist [ i ] . entry , syncpoff ) ) ;
}
2005-04-17 02:20:36 +04:00
static int snmp6_seq_show ( struct seq_file * seq , void * v )
{
2008-10-08 01:47:37 +04:00
struct net * net = ( struct net * ) seq - > private ;
2010-07-01 00:31:19 +04:00
snmp6_seq_show_item64 ( seq , ( void __percpu * * ) net - > mib . ipv6_statistics ,
snmp6_ipstats_list , offsetof ( struct ipstats_mib , syncp ) ) ;
2010-02-16 18:20:26 +03:00
snmp6_seq_show_item ( seq , ( void __percpu * * ) net - > mib . icmpv6_statistics ,
2011-05-19 05:14:23 +04:00
NULL , snmp6_icmp6_list ) ;
2011-11-13 05:24:04 +04:00
snmp6_seq_show_icmpv6msg ( seq , net - > mib . icmpv6msg_statistics - > mibs ) ;
2010-02-16 18:20:26 +03:00
snmp6_seq_show_item ( seq , ( void __percpu * * ) net - > mib . udp_stats_in6 ,
2011-05-19 05:14:23 +04:00
NULL , snmp6_udp6_list ) ;
2010-02-16 18:20:26 +03:00
snmp6_seq_show_item ( seq , ( void __percpu * * ) net - > mib . udplite_stats_in6 ,
2011-05-19 05:14:23 +04:00
NULL , snmp6_udplite6_list ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int snmp6_seq_open ( struct inode * inode , struct file * file )
{
2008-10-08 01:47:37 +04:00
return single_open_net ( inode , file , snmp6_seq_show ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:35 +03:00
static const struct file_operations snmp6_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = snmp6_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
2008-10-08 01:47:37 +04:00
. release = single_release_net ,
2005-04-17 02:20:36 +04:00
} ;
2008-10-08 01:47:12 +04:00
static int snmp6_dev_seq_show ( struct seq_file * seq , void * v )
{
struct inet6_dev * idev = ( struct inet6_dev * ) seq - > private ;
seq_printf ( seq , " %-32s \t %u \n " , " ifIndex " , idev - > dev - > ifindex ) ;
2012-01-17 16:45:36 +04:00
snmp6_seq_show_item64 ( seq , ( void __percpu * * ) idev - > stats . ipv6 ,
snmp6_ipstats_list , offsetof ( struct ipstats_mib , syncp ) ) ;
2011-05-19 05:14:23 +04:00
snmp6_seq_show_item ( seq , NULL , idev - > stats . icmpv6dev - > mibs ,
2010-02-16 18:20:26 +03:00
snmp6_icmp6_list ) ;
2011-11-13 05:24:04 +04:00
snmp6_seq_show_icmpv6msg ( seq , idev - > stats . icmpv6msgdev - > mibs ) ;
2008-10-08 01:47:12 +04:00
return 0 ;
}
static int snmp6_dev_seq_open ( struct inode * inode , struct file * file )
{
return single_open ( file , snmp6_dev_seq_show , PDE ( inode ) - > data ) ;
}
static const struct file_operations snmp6_dev_seq_fops = {
. owner = THIS_MODULE ,
. open = snmp6_dev_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
2005-04-17 02:20:36 +04:00
int snmp6_register_dev ( struct inet6_dev * idev )
{
struct proc_dir_entry * p ;
2008-10-08 01:45:55 +04:00
struct net * net ;
2005-04-17 02:20:36 +04:00
if ( ! idev | | ! idev - > dev )
return - EINVAL ;
2008-10-08 01:45:55 +04:00
net = dev_net ( idev - > dev ) ;
if ( ! net - > mib . proc_net_devsnmp6 )
2005-04-17 02:20:36 +04:00
return - ENOENT ;
2008-05-02 13:46:55 +04:00
p = proc_create_data ( idev - > dev - > name , S_IRUGO ,
2008-10-08 01:47:12 +04:00
net - > mib . proc_net_devsnmp6 ,
& snmp6_dev_seq_fops , idev ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
return - ENOMEM ;
idev - > stats . proc_dir_entry = p ;
return 0 ;
}
int snmp6_unregister_dev ( struct inet6_dev * idev )
{
2008-10-08 01:45:55 +04:00
struct net * net = dev_net ( idev - > dev ) ;
if ( ! net - > mib . proc_net_devsnmp6 )
2005-04-17 02:20:36 +04:00
return - ENOENT ;
2010-01-10 03:43:03 +03:00
if ( ! idev - > stats . proc_dir_entry )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
remove_proc_entry ( idev - > stats . proc_dir_entry - > name ,
2008-10-08 01:45:55 +04:00
net - > mib . proc_net_devsnmp6 ) ;
2007-04-29 08:16:39 +04:00
idev - > stats . proc_dir_entry = NULL ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-01-17 06:35:32 +03:00
static int __net_init ipv6_proc_init_net ( struct net * net )
2008-04-01 06:42:37 +04:00
{
if ( ! proc_net_fops_create ( net , " sockstat6 " , S_IRUGO ,
& sockstat6_seq_fops ) )
return - ENOMEM ;
2008-10-08 01:46:18 +04:00
if ( ! proc_net_fops_create ( net , " snmp6 " , S_IRUGO , & snmp6_seq_fops ) )
goto proc_snmp6_fail ;
net - > mib . proc_net_devsnmp6 = proc_mkdir ( " dev_snmp6 " , net - > proc_net ) ;
if ( ! net - > mib . proc_net_devsnmp6 )
goto proc_dev_snmp6_fail ;
2008-04-01 06:42:37 +04:00
return 0 ;
2008-10-08 01:46:18 +04:00
proc_snmp6_fail :
proc_net_remove ( net , " sockstat6 " ) ;
proc_dev_snmp6_fail :
proc_net_remove ( net , " dev_snmp6 " ) ;
return - ENOMEM ;
2008-04-01 06:42:37 +04:00
}
2010-01-17 06:35:32 +03:00
static void __net_exit ipv6_proc_exit_net ( struct net * net )
2008-04-01 06:42:37 +04:00
{
proc_net_remove ( net , " sockstat6 " ) ;
2008-10-08 01:46:18 +04:00
proc_net_remove ( net , " dev_snmp6 " ) ;
proc_net_remove ( net , " snmp6 " ) ;
2008-04-01 06:42:37 +04:00
}
static struct pernet_operations ipv6_proc_ops = {
. init = ipv6_proc_init_net ,
. exit = ipv6_proc_exit_net ,
} ;
2005-04-17 02:20:36 +04:00
int __init ipv6_misc_proc_init ( void )
{
2008-10-08 01:46:18 +04:00
return register_pernet_subsys ( & ipv6_proc_ops ) ;
2005-04-17 02:20:36 +04:00
}
void ipv6_misc_proc_exit ( void )
{
2008-04-01 06:42:37 +04:00
unregister_pernet_subsys ( & ipv6_proc_ops ) ;
2005-04-17 02:20:36 +04:00
}