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 )
2014-08-25 00:53:10 +04:00
* YOSHIFUJI Hideaki < yoshfuji @ linux - ipv6 . org >
2005-04-17 02:20:36 +04:00
*
* 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>
2016-09-30 06:29:00 +03:00
# define MAX4(a, b, c, d) \
max_t ( u32 , max_t ( u32 , a , b ) , max_t ( u32 , c , d ) )
# define SNMP_MIB_MAX MAX4(UDP_MIB_MAX, TCP_MIB_MAX, \
IPSTATS_MIB_MAX , ICMP_MIB_MAX )
2005-04-17 02:20:36 +04:00
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 ) ) ;
2018-03-31 22:58:53 +03:00
seq_printf ( seq , " FRAG6: inuse %u memory %lu \n " ,
2019-05-24 19:03:32 +03:00
atomic_read ( & net - > ipv6 . fqdir . rhashtable . nelems ) ,
frag_mem_limit ( & net - > ipv6 . fqdir ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
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 ) ,
2013-05-31 09:37:57 +04:00
/* IPSTATS_MIB_CSUMERRORS is not relevant in IPv6 (no checksum) */
2013-08-06 14:32:11 +04:00
SNMP_MIB_ITEM ( " Ip6InNoECTPkts " , IPSTATS_MIB_NOECTPKTS ) ,
SNMP_MIB_ITEM ( " Ip6InECT1Pkts " , IPSTATS_MIB_ECT1PKTS ) ,
SNMP_MIB_ITEM ( " Ip6InECT0Pkts " , IPSTATS_MIB_ECT0PKTS ) ,
SNMP_MIB_ITEM ( " Ip6InCEPkts " , IPSTATS_MIB_CEPKTS ) ,
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 ) ,
2013-04-29 12:39:56 +04:00
SNMP_MIB_ITEM ( " Icmp6InCsumErrors " , ICMP6_MIB_CSUMERRORS ) ,
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 ) ,
2013-04-29 12:39:56 +04:00
SNMP_MIB_ITEM ( " Udp6InCsumErrors " , UDP_MIB_CSUMERRORS ) ,
2014-11-06 21:37:54 +03:00
SNMP_MIB_ITEM ( " Udp6IgnoredMulti " , UDP_MIB_IGNOREDMULTI ) ,
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 ) ,
2013-04-29 12:39:56 +04:00
SNMP_MIB_ITEM ( " UdpLite6InCsumErrors " , UDP_MIB_CSUMERRORS ) ,
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 )
*/
2014-05-13 03:52:02 +04:00
static void snmp6_seq_show_item ( struct seq_file * seq , void __percpu * pcpumib ,
2011-05-19 05:14:23 +04:00
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
{
2016-09-30 06:29:00 +03:00
unsigned long buff [ SNMP_MIB_MAX ] ;
2005-04-17 02:20:36 +04:00
int i ;
2010-07-01 00:31:19 +04:00
2016-09-30 06:29:00 +03:00
if ( pcpumib ) {
memset ( buff , 0 , sizeof ( unsigned long ) * SNMP_MIB_MAX ) ;
snmp_get_cpu_field_batch ( buff , itemlist , pcpumib ) ;
for ( i = 0 ; itemlist [ i ] . name ; i + + )
seq_printf ( seq , " %-32s \t %lu \n " ,
itemlist [ i ] . name , buff [ i ] ) ;
} else {
for ( i = 0 ; itemlist [ i ] . name ; i + + )
seq_printf ( seq , " %-32s \t %lu \n " , itemlist [ i ] . name ,
atomic_long_read ( smib + itemlist [ i ] . entry ) ) ;
2011-05-19 05:14:23 +04:00
}
2005-04-17 02:20:36 +04:00
}
2014-05-06 02:55:55 +04:00
static void snmp6_seq_show_item64 ( struct seq_file * seq , void __percpu * mib ,
2010-07-01 00:31:19 +04:00
const struct snmp_mib * itemlist , size_t syncpoff )
{
2016-09-30 06:29:00 +03:00
u64 buff64 [ SNMP_MIB_MAX ] ;
2010-07-01 00:31:19 +04:00
int i ;
2017-06-12 11:06:57 +03:00
memset ( buff64 , 0 , sizeof ( u64 ) * SNMP_MIB_MAX ) ;
2016-09-30 06:29:00 +03:00
snmp_get_cpu_field64_batch ( buff64 , itemlist , mib , syncpoff ) ;
2010-07-01 00:31:19 +04:00
for ( i = 0 ; itemlist [ i ] . name ; i + + )
2016-09-30 06:29:00 +03:00
seq_printf ( seq , " %-32s \t %llu \n " , itemlist [ i ] . name , buff64 [ i ] ) ;
2010-07-01 00:31:19 +04:00
}
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 ;
2014-05-06 02:55:55 +04:00
snmp6_seq_show_item64 ( seq , net - > mib . ipv6_statistics ,
2010-07-01 00:31:19 +04:00
snmp6_ipstats_list , offsetof ( struct ipstats_mib , syncp ) ) ;
2014-05-13 03:52:02 +04:00
snmp6_seq_show_item ( seq , 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 ) ;
2014-05-13 03:52:02 +04:00
snmp6_seq_show_item ( seq , net - > mib . udp_stats_in6 ,
2011-05-19 05:14:23 +04:00
NULL , snmp6_udp6_list ) ;
2014-05-13 03:52:02 +04:00
snmp6_seq_show_item ( seq , 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 ;
}
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 ) ;
2014-05-06 02:55:55 +04:00
snmp6_seq_show_item64 ( seq , idev - > stats . ipv6 ,
2012-01-17 16:45:36 +04:00
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 ;
}
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 ;
2018-05-15 16:57:23 +03:00
p = proc_create_single_data ( idev - > dev - > name , 0444 ,
net - > mib . proc_net_devsnmp6 , snmp6_dev_seq_show , 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 ;
2013-04-12 20:27:28 +04:00
proc_remove ( idev - > stats . proc_dir_entry ) ;
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
{
2018-04-13 21:38:35 +03:00
if ( ! proc_create_net_single ( " sockstat6 " , 0444 , net - > proc_net ,
sockstat6_seq_show , NULL ) )
2008-04-01 06:42:37 +04:00
return - ENOMEM ;
2008-10-08 01:46:18 +04:00
2018-04-13 21:38:35 +03:00
if ( ! proc_create_net_single ( " snmp6 " , 0444 , net - > proc_net ,
snmp6_seq_show , NULL ) )
2008-10-08 01:46:18 +04:00
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
2012-08-13 02:31:58 +04:00
proc_dev_snmp6_fail :
2013-02-18 05:34:56 +04:00
remove_proc_entry ( " snmp6 " , net - > proc_net ) ;
2008-10-08 01:46:18 +04:00
proc_snmp6_fail :
2013-02-18 05:34:56 +04:00
remove_proc_entry ( " sockstat6 " , net - > proc_net ) ;
2008-10-08 01:46:18 +04:00
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
{
2013-02-18 05:34:56 +04:00
remove_proc_entry ( " sockstat6 " , net - > proc_net ) ;
remove_proc_entry ( " dev_snmp6 " , net - > proc_net ) ;
remove_proc_entry ( " snmp6 " , net - > proc_net ) ;
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
}