2005-04-17 02:20:36 +04:00
/******************************************************************************
* vlanproc . c VLAN Module . / proc filesystem interface .
*
* This module is completely hardware - independent and provides
* access to the router using Linux / proc filesystem .
*
* Author : Ben Greear , < greearb @ candelatech . com > coppied from wanproc . c
* by : Gene Kozin < genek @ compuserve . com >
*
* Copyright : ( c ) 1998 Ben Greear
*
* 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 .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Jan 20 , 1998 Ben Greear Initial Version
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/module.h>
2008-07-15 09:51:55 +04:00
# include <linux/errno.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
2008-07-15 09:51:55 +04:00
# include <linux/string.h>
2005-04-17 02:20:36 +04:00
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/fs.h>
# include <linux/netdevice.h>
# include <linux/if_vlan.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2008-04-16 11:51:51 +04:00
# include <net/netns/generic.h>
2005-04-17 02:20:36 +04:00
# include "vlanproc.h"
# include "vlan.h"
/****** Function Prototypes *************************************************/
/* Methods for preparing data for reading proc entries */
static int vlan_seq_show ( struct seq_file * seq , void * v ) ;
static void * vlan_seq_start ( struct seq_file * seq , loff_t * pos ) ;
static void * vlan_seq_next ( struct seq_file * seq , void * v , loff_t * pos ) ;
static void vlan_seq_stop ( struct seq_file * seq , void * ) ;
static int vlandev_seq_show ( struct seq_file * seq , void * v ) ;
/*
* Global Data
*/
/*
2007-02-09 17:24:25 +03:00
* Names of the proc directory entries
2005-04-17 02:20:36 +04:00
*/
static const char name_root [ ] = " vlan " ;
static const char name_conf [ ] = " config " ;
/*
* Structures for interfacing with the / proc filesystem .
* VLAN creates its own directory / proc / net / vlan with the folowing
* entries :
* config device status / configuration
* < device > entry for each device
*/
/*
2007-02-09 17:24:25 +03:00
* Generic / proc / net / vlan / < file > file and inode operations
2005-04-17 02:20:36 +04:00
*/
2007-07-11 10:07:31 +04:00
static const struct seq_operations vlan_seq_ops = {
2005-04-17 02:20:36 +04:00
. start = vlan_seq_start ,
. next = vlan_seq_next ,
. stop = vlan_seq_stop ,
. show = vlan_seq_show ,
} ;
static int vlan_seq_open ( struct inode * inode , struct file * file )
{
2008-04-16 11:52:24 +04:00
return seq_open_net ( inode , file , & vlan_seq_ops ,
sizeof ( struct seq_net_private ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:35 +03:00
static const struct file_operations vlan_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = vlan_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
2008-04-16 11:52:24 +04:00
. release = seq_release_net ,
2005-04-17 02:20:36 +04:00
} ;
/*
* / proc / net / vlan / < device > file and inode operations
*/
static int vlandev_seq_open ( struct inode * inode , struct file * file )
{
return single_open ( file , vlandev_seq_show , PDE ( inode ) - > data ) ;
}
2007-02-12 11:55:35 +03:00
static const struct file_operations vlandev_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = vlandev_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
/*
* Proc filesystem derectory entries .
*/
/* Strings */
static const char * vlan_name_type_str [ VLAN_NAME_TYPE_HIGHEST ] = {
2008-01-21 11:26:41 +03:00
[ VLAN_NAME_TYPE_RAW_PLUS_VID ] = " VLAN_NAME_TYPE_RAW_PLUS_VID " ,
[ VLAN_NAME_TYPE_PLUS_VID_NO_PAD ] = " VLAN_NAME_TYPE_PLUS_VID_NO_PAD " ,
[ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD ] = " VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD " ,
[ VLAN_NAME_TYPE_PLUS_VID ] = " VLAN_NAME_TYPE_PLUS_VID " ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Interface functions
*/
/*
* Clean up / proc / net / vlan entries
*/
2008-04-16 11:51:12 +04:00
void vlan_proc_cleanup ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2008-04-16 11:51:12 +04:00
2008-04-16 11:51:51 +04:00
if ( vn - > proc_vlan_conf )
remove_proc_entry ( name_conf , vn - > proc_vlan_dir ) ;
2005-04-17 02:20:36 +04:00
2008-04-16 11:51:51 +04:00
if ( vn - > proc_vlan_dir )
proc_net_remove ( net , name_root ) ;
2005-04-17 02:20:36 +04:00
/* Dynamically added entries should be cleaned up as their vlan_device
* is removed , so we should not have to take care of it here . . .
*/
}
/*
* Create / proc / net / vlan entries
*/
2008-04-16 11:51:12 +04:00
int vlan_proc_init ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2008-04-16 11:51:12 +04:00
2008-04-16 11:51:51 +04:00
vn - > proc_vlan_dir = proc_net_mkdir ( net , name_root , net - > proc_net ) ;
if ( ! vn - > proc_vlan_dir )
2008-01-21 11:25:15 +03:00
goto err ;
2008-04-16 11:51:51 +04:00
vn - > proc_vlan_conf = proc_create ( name_conf , S_IFREG | S_IRUSR | S_IWUSR ,
vn - > proc_vlan_dir , & vlan_fops ) ;
if ( ! vn - > proc_vlan_conf )
2008-01-21 11:25:15 +03:00
goto err ;
return 0 ;
err :
2008-03-06 07:47:47 +03:00
pr_err ( " %s: can't create entry in proc filesystem! \n " , __func__ ) ;
2008-04-16 11:51:12 +04:00
vlan_proc_cleanup ( net ) ;
2005-04-17 02:20:36 +04:00
return - ENOBUFS ;
}
/*
* Add directory entry for VLAN device .
*/
2008-01-21 11:26:41 +03:00
int vlan_proc_add_dev ( struct net_device * vlandev )
2005-04-17 02:20:36 +04:00
{
2008-01-21 11:26:07 +03:00
struct vlan_dev_info * dev_info = vlan_dev_info ( vlandev ) ;
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( dev_net ( vlandev ) , vlan_net_id ) ;
2005-04-17 02:20:36 +04:00
2008-05-02 15:09:11 +04:00
dev_info - > dent =
proc_create_data ( vlandev - > name , S_IFREG | S_IRUSR | S_IWUSR ,
vn - > proc_vlan_dir , & vlandev_fops , vlandev ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev_info - > dent )
return - ENOBUFS ;
return 0 ;
}
/*
* Delete directory entry for VLAN device .
*/
int vlan_proc_rem_dev ( struct net_device * vlandev )
{
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( dev_net ( vlandev ) , vlan_net_id ) ;
2005-04-17 02:20:36 +04:00
/** NOTE: This will consume the memory pointed to by dent, it seems. */
2008-01-21 11:26:07 +03:00
if ( vlan_dev_info ( vlandev ) - > dent ) {
2008-01-21 11:26:41 +03:00
remove_proc_entry ( vlan_dev_info ( vlandev ) - > dent - > name ,
2008-04-16 11:51:51 +04:00
vn - > proc_vlan_dir ) ;
2008-01-21 11:26:07 +03:00
vlan_dev_info ( vlandev ) - > dent = NULL ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/****** Proc filesystem entry points ****************************************/
/*
* The following few functions build the content of / proc / net / vlan / config
*/
2007-02-09 17:24:25 +03:00
/* start read of /proc/net/vlan/config */
2005-04-17 02:20:36 +04:00
static void * vlan_seq_start ( struct seq_file * seq , loff_t * pos )
2008-01-22 04:27:44 +03:00
__acquires ( dev_base_lock )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
2008-04-16 11:52:24 +04:00
struct net * net = seq_file_net ( seq ) ;
2005-04-17 02:20:36 +04:00
loff_t i = 1 ;
read_lock ( & dev_base_lock ) ;
if ( * pos = = 0 )
return SEQ_START_TOKEN ;
2007-02-09 17:24:25 +03:00
2008-04-16 11:52:24 +04:00
for_each_netdev ( net , dev ) {
2007-05-04 02:13:45 +04:00
if ( ! is_vlan_dev ( dev ) )
continue ;
if ( i + + = = * pos )
return dev ;
}
2007-02-09 17:24:25 +03:00
2007-05-04 02:13:45 +04:00
return NULL ;
2007-02-09 17:24:25 +03:00
}
2005-04-17 02:20:36 +04:00
static void * vlan_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
2007-05-04 02:13:45 +04:00
struct net_device * dev ;
2008-04-16 11:52:24 +04:00
struct net * net = seq_file_net ( seq ) ;
2007-05-04 02:13:45 +04:00
2005-04-17 02:20:36 +04:00
+ + * pos ;
2007-05-04 02:13:45 +04:00
dev = ( struct net_device * ) v ;
if ( v = = SEQ_START_TOKEN )
2008-04-16 11:52:24 +04:00
dev = net_device_entry ( & net - > dev_base_head ) ;
2007-05-04 02:13:45 +04:00
2008-04-16 11:52:24 +04:00
for_each_netdev_continue ( net , dev ) {
2007-05-04 02:13:45 +04:00
if ( ! is_vlan_dev ( dev ) )
continue ;
return dev ;
}
return NULL ;
2005-04-17 02:20:36 +04:00
}
static void vlan_seq_stop ( struct seq_file * seq , void * v )
2008-01-22 04:27:44 +03:00
__releases ( dev_base_lock )
2005-04-17 02:20:36 +04:00
{
read_unlock ( & dev_base_lock ) ;
}
static int vlan_seq_show ( struct seq_file * seq , void * v )
{
2008-04-16 11:54:39 +04:00
struct net * net = seq_file_net ( seq ) ;
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2005-04-17 02:20:36 +04:00
if ( v = = SEQ_START_TOKEN ) {
const char * nmtype = NULL ;
seq_puts ( seq , " VLAN Dev name | VLAN ID \n " ) ;
2008-04-16 11:54:39 +04:00
if ( vn - > name_type < ARRAY_SIZE ( vlan_name_type_str ) )
nmtype = vlan_name_type_str [ vn - > name_type ] ;
2005-04-17 02:20:36 +04:00
2007-02-09 17:24:25 +03:00
seq_printf ( seq , " Name-Type: %s \n " ,
2008-01-21 11:26:41 +03:00
nmtype ? nmtype : " UNKNOWN " ) ;
2005-04-17 02:20:36 +04:00
} else {
const struct net_device * vlandev = v ;
2008-01-21 11:26:07 +03:00
const struct vlan_dev_info * dev_info = vlan_dev_info ( vlandev ) ;
2005-04-17 02:20:36 +04:00
2007-02-09 17:24:25 +03:00
seq_printf ( seq , " %-15s| %d | %s \n " , vlandev - > name ,
2005-04-17 02:20:36 +04:00
dev_info - > vlan_id , dev_info - > real_dev - > name ) ;
}
return 0 ;
}
static int vlandev_seq_show ( struct seq_file * seq , void * offset )
{
struct net_device * vlandev = ( struct net_device * ) seq - > private ;
2008-01-21 11:26:07 +03:00
const struct vlan_dev_info * dev_info = vlan_dev_info ( vlandev ) ;
2008-01-21 11:19:31 +03:00
struct net_device_stats * stats = & vlandev - > stats ;
2005-04-17 02:20:36 +04:00
static const char fmt [ ] = " %30s %12lu \n " ;
int i ;
2008-07-08 14:22:16 +04:00
if ( ! is_vlan_dev ( vlandev ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-01-21 11:26:41 +03:00
seq_printf ( seq ,
" %s VID: %d REORDER_HDR: %i dev->priv_flags: %hx \n " ,
vlandev - > name , dev_info - > vlan_id ,
( int ) ( dev_info - > flags & 1 ) , vlandev - > priv_flags ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , fmt , " total frames received " , stats - > rx_packets ) ;
seq_printf ( seq , fmt , " total bytes received " , stats - > rx_bytes ) ;
seq_printf ( seq , fmt , " Broadcast/Multicast Rcvd " , stats - > multicast ) ;
seq_puts ( seq , " \n " ) ;
seq_printf ( seq , fmt , " total frames transmitted " , stats - > tx_packets ) ;
seq_printf ( seq , fmt , " total bytes transmitted " , stats - > tx_bytes ) ;
2007-02-09 17:24:25 +03:00
seq_printf ( seq , fmt , " total headroom inc " ,
2005-04-17 02:20:36 +04:00
dev_info - > cnt_inc_headroom_on_tx ) ;
2007-02-09 17:24:25 +03:00
seq_printf ( seq , fmt , " total encap on xmit " ,
2005-04-17 02:20:36 +04:00
dev_info - > cnt_encap_on_xmit ) ;
seq_printf ( seq , " Device: %s " , dev_info - > real_dev - > name ) ;
/* now show all PRIORITY mappings relating to this VLAN */
2008-01-21 11:26:41 +03:00
seq_printf ( seq , " \n INGRESS priority mappings: "
" 0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u \n " ,
dev_info - > ingress_priority_map [ 0 ] ,
dev_info - > ingress_priority_map [ 1 ] ,
dev_info - > ingress_priority_map [ 2 ] ,
dev_info - > ingress_priority_map [ 3 ] ,
dev_info - > ingress_priority_map [ 4 ] ,
dev_info - > ingress_priority_map [ 5 ] ,
dev_info - > ingress_priority_map [ 6 ] ,
dev_info - > ingress_priority_map [ 7 ] ) ;
2005-04-17 02:20:36 +04:00
2008-11-11 00:37:40 +03:00
seq_printf ( seq , " EGRESS priority mappings: " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 16 ; i + + ) {
const struct vlan_priority_tci_mapping * mp
= dev_info - > egress_priority_map [ i ] ;
while ( mp ) {
2007-06-13 23:07:07 +04:00
seq_printf ( seq , " %u:%hu " ,
2005-04-17 02:20:36 +04:00
mp - > priority , ( ( mp - > vlan_qos > > 13 ) & 0x7 ) ) ;
mp = mp - > next ;
}
}
seq_puts ( seq , " \n " ) ;
return 0 ;
}