2005-04-17 02:20:36 +04:00
/*
* Sysfs attributes of bridge ports
* Linux ethernet bridge
*
* Authors :
* Stephen Hemminger < shemminger @ osdl . 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 .
*/
2006-01-11 23:17:47 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/netdevice.h>
# include <linux/if_bridge.h>
# include <linux/rtnetlink.h>
# include <linux/spinlock.h>
# include "br_private.h"
struct brport_attribute {
struct attribute attr ;
ssize_t ( * show ) ( struct net_bridge_port * , char * ) ;
2011-04-04 18:03:33 +04:00
int ( * store ) ( struct net_bridge_port * , unsigned long ) ;
2005-04-17 02:20:36 +04:00
} ;
2013-12-19 09:28:12 +04:00
# define BRPORT_ATTR(_name, _mode, _show, _store) \
2012-07-30 12:55:49 +04:00
const struct brport_attribute brport_attr_ # # _name = { \
2005-04-17 02:20:36 +04:00
. attr = { . name = __stringify ( _name ) , \
2007-06-13 22:45:17 +04:00
. mode = _mode } , \
2005-04-17 02:20:36 +04:00
. show = _show , \
. store = _store , \
} ;
2012-11-13 11:53:06 +04:00
# define BRPORT_ATTR_FLAG(_name, _mask) \
static ssize_t show_ # # _name ( struct net_bridge_port * p , char * buf ) \
{ \
return sprintf ( buf , " %d \n " , ! ! ( p - > flags & _mask ) ) ; \
} \
static int store_ # # _name ( struct net_bridge_port * p , unsigned long v ) \
{ \
2014-05-16 17:59:15 +04:00
return store_flag ( p , v , _mask ) ; \
2012-11-13 11:53:06 +04:00
} \
static BRPORT_ATTR ( _name , S_IRUGO | S_IWUSR , \
show_ # # _name , store_ # # _name )
2014-05-16 17:59:15 +04:00
static int store_flag ( struct net_bridge_port * p , unsigned long v ,
unsigned long mask )
{
2014-05-16 17:59:16 +04:00
unsigned long flags ;
flags = p - > flags ;
2014-05-16 17:59:15 +04:00
if ( v )
flags | = mask ;
else
flags & = ~ mask ;
if ( flags ! = p - > flags ) {
p - > flags = flags ;
2014-05-16 17:59:16 +04:00
br_port_flags_change ( p , mask ) ;
2014-05-16 17:59:15 +04:00
}
return 0 ;
}
2012-11-13 11:53:06 +04:00
2005-04-17 02:20:36 +04:00
static ssize_t show_path_cost ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > path_cost ) ;
}
2011-04-04 18:03:33 +04:00
2005-04-17 02:20:36 +04:00
static BRPORT_ATTR ( path_cost , S_IRUGO | S_IWUSR ,
2011-04-04 18:03:33 +04:00
show_path_cost , br_stp_set_path_cost ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_priority ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > priority ) ;
}
2011-04-04 18:03:33 +04:00
2005-04-17 02:20:36 +04:00
static BRPORT_ATTR ( priority , S_IRUGO | S_IWUSR ,
2011-04-04 18:03:33 +04:00
show_priority , br_stp_set_port_priority ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_designated_root ( struct net_bridge_port * p , char * buf )
{
return br_show_bridge_id ( buf , & p - > designated_root ) ;
}
static BRPORT_ATTR ( designated_root , S_IRUGO , show_designated_root , NULL ) ;
static ssize_t show_designated_bridge ( struct net_bridge_port * p , char * buf )
{
return br_show_bridge_id ( buf , & p - > designated_bridge ) ;
}
static BRPORT_ATTR ( designated_bridge , S_IRUGO , show_designated_bridge , NULL ) ;
static ssize_t show_designated_port ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > designated_port ) ;
}
static BRPORT_ATTR ( designated_port , S_IRUGO , show_designated_port , NULL ) ;
static ssize_t show_designated_cost ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > designated_cost ) ;
}
static BRPORT_ATTR ( designated_cost , S_IRUGO , show_designated_cost , NULL ) ;
static ssize_t show_port_id ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " 0x%x \n " , p - > port_id ) ;
}
static BRPORT_ATTR ( port_id , S_IRUGO , show_port_id , NULL ) ;
static ssize_t show_port_no ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " 0x%x \n " , p - > port_no ) ;
}
static BRPORT_ATTR ( port_no , S_IRUGO , show_port_no , NULL ) ;
static ssize_t show_change_ack ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > topology_change_ack ) ;
}
static BRPORT_ATTR ( change_ack , S_IRUGO , show_change_ack , NULL ) ;
static ssize_t show_config_pending ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > config_pending ) ;
}
static BRPORT_ATTR ( config_pending , S_IRUGO , show_config_pending , NULL ) ;
static ssize_t show_port_state ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > state ) ;
}
static BRPORT_ATTR ( state , S_IRUGO , show_port_state , NULL ) ;
static ssize_t show_message_age_timer ( struct net_bridge_port * p ,
char * buf )
{
return sprintf ( buf , " %ld \n " , br_timer_value ( & p - > message_age_timer ) ) ;
}
static BRPORT_ATTR ( message_age_timer , S_IRUGO , show_message_age_timer , NULL ) ;
static ssize_t show_forward_delay_timer ( struct net_bridge_port * p ,
char * buf )
{
return sprintf ( buf , " %ld \n " , br_timer_value ( & p - > forward_delay_timer ) ) ;
}
static BRPORT_ATTR ( forward_delay_timer , S_IRUGO , show_forward_delay_timer , NULL ) ;
static ssize_t show_hold_timer ( struct net_bridge_port * p ,
char * buf )
{
return sprintf ( buf , " %ld \n " , br_timer_value ( & p - > hold_timer ) ) ;
}
static BRPORT_ATTR ( hold_timer , S_IRUGO , show_hold_timer , NULL ) ;
2011-04-04 18:03:33 +04:00
static int store_flush ( struct net_bridge_port * p , unsigned long v )
2007-04-09 23:57:54 +04:00
{
2015-06-23 15:28:16 +03:00
br_fdb_delete_by_port ( p - > br , p , 0 , 0 ) ; // Don't delete local entry
2007-04-09 23:57:54 +04:00
return 0 ;
}
static BRPORT_ATTR ( flush , S_IWUSR , NULL , store_flush ) ;
2012-11-13 11:53:06 +04:00
BRPORT_ATTR_FLAG ( hairpin_mode , BR_HAIRPIN_MODE ) ;
2012-11-13 11:53:07 +04:00
BRPORT_ATTR_FLAG ( bpdu_guard , BR_BPDU_GUARD ) ;
2012-11-13 11:53:08 +04:00
BRPORT_ATTR_FLAG ( root_block , BR_ROOT_BLOCK ) ;
2013-06-05 18:08:00 +04:00
BRPORT_ATTR_FLAG ( learning , BR_LEARNING ) ;
2013-06-05 18:08:01 +04:00
BRPORT_ATTR_FLAG ( unicast_flood , BR_FLOOD ) ;
2014-10-24 01:49:17 +04:00
BRPORT_ATTR_FLAG ( proxyarp , BR_PROXYARP ) ;
2015-03-04 13:54:21 +03:00
BRPORT_ATTR_FLAG ( proxyarp_wifi , BR_PROXYARP_WIFI ) ;
2016-08-31 16:36:52 +03:00
BRPORT_ATTR_FLAG ( multicast_flood , BR_MCAST_FLOOD ) ;
2009-08-13 10:55:16 +04:00
2010-02-27 22:41:49 +03:00
# ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static ssize_t show_multicast_router ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > multicast_router ) ;
}
2011-04-04 18:03:33 +04:00
static int store_multicast_router ( struct net_bridge_port * p ,
2010-02-27 22:41:49 +03:00
unsigned long v )
{
return br_multicast_set_port_router ( p , v ) ;
}
static BRPORT_ATTR ( multicast_router , S_IRUGO | S_IWUSR , show_multicast_router ,
store_multicast_router ) ;
2012-12-04 03:56:40 +04:00
2012-12-06 01:24:45 +04:00
BRPORT_ATTR_FLAG ( multicast_fast_leave , BR_MULTICAST_FAST_LEAVE ) ;
2010-02-27 22:41:49 +03:00
# endif
2012-07-30 12:55:49 +04:00
static const struct brport_attribute * brport_attrs [ ] = {
2005-04-17 02:20:36 +04:00
& brport_attr_path_cost ,
& brport_attr_priority ,
& brport_attr_port_id ,
& brport_attr_port_no ,
& brport_attr_designated_root ,
& brport_attr_designated_bridge ,
& brport_attr_designated_port ,
& brport_attr_designated_cost ,
& brport_attr_state ,
& brport_attr_change_ack ,
& brport_attr_config_pending ,
& brport_attr_message_age_timer ,
& brport_attr_forward_delay_timer ,
& brport_attr_hold_timer ,
2007-04-09 23:57:54 +04:00
& brport_attr_flush ,
2009-08-13 10:55:16 +04:00
& brport_attr_hairpin_mode ,
2012-11-13 11:53:07 +04:00
& brport_attr_bpdu_guard ,
2012-11-13 11:53:08 +04:00
& brport_attr_root_block ,
2013-06-05 18:08:00 +04:00
& brport_attr_learning ,
2013-06-05 18:08:01 +04:00
& brport_attr_unicast_flood ,
2010-02-27 22:41:49 +03:00
# ifdef CONFIG_BRIDGE_IGMP_SNOOPING
& brport_attr_multicast_router ,
2012-12-04 03:56:40 +04:00
& brport_attr_multicast_fast_leave ,
2010-02-27 22:41:49 +03:00
# endif
2014-10-24 01:49:17 +04:00
& brport_attr_proxyarp ,
2015-03-04 13:54:21 +03:00
& brport_attr_proxyarp_wifi ,
2005-04-17 02:20:36 +04:00
NULL
} ;
# define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
# define to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
2013-12-19 09:28:13 +04:00
static ssize_t brport_show ( struct kobject * kobj ,
struct attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2013-12-19 09:28:13 +04:00
struct brport_attribute * brport_attr = to_brport_attr ( attr ) ;
struct net_bridge_port * p = to_brport ( kobj ) ;
2005-04-17 02:20:36 +04:00
return brport_attr - > show ( p , buf ) ;
}
2013-12-19 09:28:13 +04:00
static ssize_t brport_store ( struct kobject * kobj ,
struct attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2013-12-19 09:28:13 +04:00
struct brport_attribute * brport_attr = to_brport_attr ( attr ) ;
struct net_bridge_port * p = to_brport ( kobj ) ;
2005-04-17 02:20:36 +04:00
ssize_t ret = - EINVAL ;
char * endp ;
unsigned long val ;
2012-11-16 07:03:08 +04:00
if ( ! ns_capable ( dev_net ( p - > dev ) - > user_ns , CAP_NET_ADMIN ) )
2005-04-17 02:20:36 +04:00
return - EPERM ;
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( endp ! = buf ) {
2009-05-13 21:00:41 +04:00
if ( ! rtnl_trylock ( ) )
return restart_syscall ( ) ;
2005-04-17 02:20:36 +04:00
if ( p - > dev & & p - > br & & brport_attr - > store ) {
spin_lock_bh ( & p - > br - > lock ) ;
ret = brport_attr - > store ( p , val ) ;
spin_unlock_bh ( & p - > br - > lock ) ;
2016-04-08 19:03:32 +03:00
if ( ! ret ) {
br_ifinfo_notify ( RTM_NEWLINK , p ) ;
2005-04-17 02:20:36 +04:00
ret = count ;
2016-04-08 19:03:32 +03:00
}
2005-04-17 02:20:36 +04:00
}
rtnl_unlock ( ) ;
}
return ret ;
}
2010-01-19 04:58:23 +03:00
const struct sysfs_ops brport_sysfs_ops = {
2005-04-17 02:20:36 +04:00
. show = brport_show ,
. store = brport_store ,
} ;
/*
* Add sysfs entries to ethernet device added to a bridge .
* Creates a brport subdirectory with bridge attributes .
2010-05-10 13:31:11 +04:00
* Puts symlink in bridge ' s brif subdirectory
2005-04-17 02:20:36 +04:00
*/
int br_sysfs_addif ( struct net_bridge_port * p )
{
struct net_bridge * br = p - > br ;
2012-07-30 12:55:49 +04:00
const struct brport_attribute * * a ;
2005-04-17 02:20:36 +04:00
int err ;
2002-04-09 23:14:34 +04:00
err = sysfs_create_link ( & p - > kobj , & br - > dev - > dev . kobj ,
2005-04-17 02:20:36 +04:00
SYSFS_BRIDGE_PORT_LINK ) ;
if ( err )
2010-05-10 13:31:11 +04:00
return err ;
2005-04-17 02:20:36 +04:00
for ( a = brport_attrs ; * a ; + + a ) {
err = sysfs_create_file ( & p - > kobj , & ( ( * a ) - > attr ) ) ;
if ( err )
2010-05-10 13:31:11 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2010-05-10 13:31:11 +04:00
strlcpy ( p - > sysfs_name , p - > dev - > name , IFNAMSIZ ) ;
return sysfs_create_link ( br - > ifobj , & p - > kobj , p - > sysfs_name ) ;
}
/* Rename bridge's brif symlink */
int br_sysfs_renameif ( struct net_bridge_port * p )
{
struct net_bridge * br = p - > br ;
int err ;
/* If a rename fails, the rollback will cause another
* rename call with the existing name .
*/
if ( ! strncmp ( p - > sysfs_name , p - > dev - > name , IFNAMSIZ ) )
return 0 ;
err = sysfs_rename_link ( br - > ifobj , & p - > kobj ,
p - > sysfs_name , p - > dev - > name ) ;
if ( err )
netdev_notice ( br - > dev , " unable to rename link %s to %s " ,
p - > sysfs_name , p - > dev - > name ) ;
else
strlcpy ( p - > sysfs_name , p - > dev - > name , IFNAMSIZ ) ;
2005-04-17 02:20:36 +04:00
return err ;
}