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 .
*
* Version : $ Id : proc . c , v 1.17 2002 / 02 / 01 22 : 01 : 04 davem Exp $
*
* 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>
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 struct proc_dir_entry * proc_net_devsnmp6 ;
static int sockstat6_seq_show ( struct seq_file * seq , void * v )
{
seq_printf ( seq , " TCP6: inuse %d \n " ,
2008-04-01 06:41:46 +04:00
sock_prot_inuse_get ( & init_net , & tcpv6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " UDP6: inuse %d \n " ,
2008-04-01 06:41:46 +04:00
sock_prot_inuse_get ( & init_net , & udpv6_prot ) ) ;
2006-11-27 22:10:57 +03:00
seq_printf ( seq , " UDPLITE6: inuse %d \n " ,
2008-04-01 06:41:46 +04:00
sock_prot_inuse_get ( & init_net , & udplitev6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " RAW6: inuse %d \n " ,
2008-04-01 06:41:46 +04:00
sock_prot_inuse_get ( & init_net , & rawv6_prot ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " FRAG6: inuse %d memory %d \n " ,
2008-01-22 17:07:25 +03:00
ip6_frag_nqueues ( & init_net ) , ip6_frag_mem ( & init_net ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static struct snmp_mib snmp6_ipstats_list [ ] = {
/* ipv6 mib according to RFC 2465 */
SNMP_MIB_ITEM ( " Ip6InReceives " , IPSTATS_MIB_INRECEIVES ) ,
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 ) ,
SNMP_MIB_ITEM ( " Ip6OutRequests " , IPSTATS_MIB_OUTREQUESTS ) ,
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 ) ,
SNMP_MIB_SENTINEL
} ;
static 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 ) ,
SNMP_MIB_SENTINEL
} ;
2007-09-17 03:52:35 +04:00
/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */
static char * icmp6type2name [ 256 ] = {
[ 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
} ;
2005-04-17 02:20:36 +04:00
static struct snmp_mib snmp6_udp6_list [ ] = {
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 ) ,
SNMP_MIB_SENTINEL
} ;
2006-11-27 22:10:57 +03:00
static struct snmp_mib snmp6_udplite6_list [ ] = {
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 ) ,
SNMP_MIB_SENTINEL
} ;
2007-09-17 03:52:35 +04:00
static void snmp6_seq_show_icmpv6msg ( struct seq_file * seq , void * * mib )
{
static char name [ 32 ] ;
int i ;
/* print by name -- deprecated items */
for ( i = 0 ; i < ICMP6MSG_MIB_MAX ; i + + ) {
int icmptype ;
char * p ;
icmptype = i & 0xff ;
p = icmp6type2name [ icmptype ] ;
if ( ! p ) /* don't print un-named types here */
continue ;
( void ) snprintf ( name , sizeof ( name ) - 1 , " Icmp6%s%s " ,
i & 0x100 ? " Out " : " In " , p ) ;
seq_printf ( seq , " %-32s \t %lu \n " , name ,
snmp_fold_field ( mib , i ) ) ;
}
/* print by number (nonzero only) - ICMPMsgStat format */
for ( i = 0 ; i < ICMP6MSG_MIB_MAX ; i + + ) {
unsigned long val ;
val = snmp_fold_field ( mib , i ) ;
if ( ! val )
continue ;
( void ) snprintf ( name , sizeof ( name ) - 1 , " Icmp6%sType%u " ,
i & 0x100 ? " Out " : " In " , i & 0xff ) ;
seq_printf ( seq , " %-32s \t %lu \n " , name , val ) ;
}
return ;
}
2005-04-17 02:20:36 +04:00
static inline void
snmp6_seq_show_item ( struct seq_file * seq , void * * mib , struct snmp_mib * itemlist )
{
int i ;
for ( i = 0 ; itemlist [ i ] . name ; i + + )
2007-02-09 17:24:49 +03:00
seq_printf ( seq , " %-32s \t %lu \n " , itemlist [ i ] . name ,
2007-04-25 08:54:09 +04:00
snmp_fold_field ( mib , itemlist [ i ] . entry ) ) ;
2005-04-17 02:20:36 +04:00
}
static int snmp6_seq_show ( struct seq_file * seq , void * v )
{
struct inet6_dev * idev = ( struct inet6_dev * ) seq - > private ;
if ( idev ) {
seq_printf ( seq , " %-32s \t %u \n " , " ifIndex " , idev - > dev - > ifindex ) ;
2006-11-04 14:11:37 +03:00
snmp6_seq_show_item ( seq , ( void * * ) idev - > stats . ipv6 , snmp6_ipstats_list ) ;
2005-04-17 02:20:36 +04:00
snmp6_seq_show_item ( seq , ( void * * ) idev - > stats . icmpv6 , snmp6_icmp6_list ) ;
2007-09-17 03:52:35 +04:00
snmp6_seq_show_icmpv6msg ( seq , ( void * * ) idev - > stats . icmpv6msg ) ;
2005-04-17 02:20:36 +04:00
} else {
snmp6_seq_show_item ( seq , ( void * * ) ipv6_statistics , snmp6_ipstats_list ) ;
snmp6_seq_show_item ( seq , ( void * * ) icmpv6_statistics , snmp6_icmp6_list ) ;
2007-09-17 03:52:35 +04:00
snmp6_seq_show_icmpv6msg ( seq , ( void * * ) icmpv6msg_statistics ) ;
2005-04-17 02:20:36 +04:00
snmp6_seq_show_item ( seq , ( void * * ) udp_stats_in6 , snmp6_udp6_list ) ;
2006-11-27 22:10:57 +03:00
snmp6_seq_show_item ( seq , ( void * * ) udplite_stats_in6 , snmp6_udplite6_list ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int sockstat6_seq_open ( struct inode * inode , struct file * file )
{
return single_open ( file , sockstat6_seq_show , NULL ) ;
}
2007-02-12 11:55:35 +03:00
static const struct file_operations sockstat6_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = sockstat6_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static int snmp6_seq_open ( struct inode * inode , struct file * file )
{
return single_open ( file , snmp6_seq_show , PDE ( inode ) - > data ) ;
}
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 ,
. release = single_release ,
} ;
int snmp6_register_dev ( struct inet6_dev * idev )
{
struct proc_dir_entry * p ;
if ( ! idev | | ! idev - > dev )
return - EINVAL ;
2008-03-25 15:47:49 +03:00
if ( dev_net ( idev - > dev ) ! = & init_net )
2008-03-05 21:46:31 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( ! proc_net_devsnmp6 )
return - ENOENT ;
2008-02-29 01:13:46 +03:00
p = proc_create ( idev - > dev - > name , S_IRUGO ,
proc_net_devsnmp6 , & snmp6_seq_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
return - ENOMEM ;
p - > data = idev ;
idev - > stats . proc_dir_entry = p ;
return 0 ;
}
int snmp6_unregister_dev ( struct inet6_dev * idev )
{
if ( ! proc_net_devsnmp6 )
return - ENOENT ;
if ( ! idev | | ! idev - > stats . proc_dir_entry )
return - EINVAL ;
remove_proc_entry ( idev - > stats . proc_dir_entry - > name ,
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 ;
}
2008-04-01 06:42:37 +04:00
static int ipv6_proc_init_net ( struct net * net )
{
if ( ! proc_net_fops_create ( net , " sockstat6 " , S_IRUGO ,
& sockstat6_seq_fops ) )
return - ENOMEM ;
return 0 ;
}
static void ipv6_proc_exit_net ( struct net * net )
{
proc_net_remove ( net , " sockstat6 " ) ;
}
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 )
{
int rc = 0 ;
2008-04-01 06:42:37 +04:00
if ( register_pernet_subsys ( & ipv6_proc_ops ) )
goto proc_net_fail ;
2007-09-12 14:01:34 +04:00
if ( ! proc_net_fops_create ( & init_net , " snmp6 " , S_IRUGO , & snmp6_seq_fops ) )
2005-04-17 02:20:36 +04:00
goto proc_snmp6_fail ;
2007-09-12 14:01:34 +04:00
proc_net_devsnmp6 = proc_mkdir ( " dev_snmp6 " , init_net . proc_net ) ;
2005-04-17 02:20:36 +04:00
if ( ! proc_net_devsnmp6 )
goto proc_dev_snmp6_fail ;
out :
return rc ;
proc_dev_snmp6_fail :
2007-09-12 14:01:34 +04:00
proc_net_remove ( & init_net , " snmp6 " ) ;
2005-04-17 02:20:36 +04:00
proc_snmp6_fail :
2008-04-01 06:42:37 +04:00
unregister_pernet_subsys ( & ipv6_proc_ops ) ;
proc_net_fail :
2005-04-17 02:20:36 +04:00
rc = - ENOMEM ;
goto out ;
}
void ipv6_misc_proc_exit ( void )
{
2007-09-12 14:01:34 +04:00
proc_net_remove ( & init_net , " sockstat6 " ) ;
proc_net_remove ( & init_net , " dev_snmp6 " ) ;
proc_net_remove ( & init_net , " snmp6 " ) ;
2008-04-01 06:42:37 +04:00
unregister_pernet_subsys ( & ipv6_proc_ops ) ;
2005-04-17 02:20:36 +04:00
}