2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* Sysfs attributes of bridge ports
* Linux ethernet bridge
*
* Authors :
* Stephen Hemminger < shemminger @ osdl . org >
*/
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>
2017-02-02 21:15:33 +03:00
# include <linux/sched/signal.h>
2005-04-17 02:20:36 +04:00
# include "br_private.h"
2021-01-29 14:51:42 +03:00
/* IMPORTANT: new bridge port options must be added with netlink support only
* please do not add new sysfs entries
*/
2005-04-17 02:20:36 +04:00
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 ) ;
2018-07-23 11:16:58 +03:00
int ( * store_raw ) ( struct net_bridge_port * , char * ) ;
} ;
# define BRPORT_ATTR_RAW(_name, _mode, _show, _store) \
const struct brport_attribute brport_attr_ # # _name = { \
. attr = { . name = __stringify ( _name ) , \
. mode = _mode } , \
. show = _show , \
. store_raw = _store , \
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
} \
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( _name , 0644 , \
2012-11-13 11:53:06 +04:00
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 )
{
2021-02-12 18:15:53 +03:00
struct netlink_ext_ack extack = { 0 } ;
2021-02-07 22:47:33 +03:00
unsigned long flags = p - > flags ;
int err ;
2014-05-16 17:59:15 +04:00
if ( v )
flags | = mask ;
else
flags & = ~ mask ;
if ( flags ! = p - > flags ) {
2021-02-12 18:15:53 +03:00
err = br_switchdev_set_port_flag ( p , flags , mask , & extack ) ;
if ( err ) {
netdev_err ( p - > dev , " %s \n " , extack . _msg ) ;
2021-02-07 22:47:33 +03:00
return err ;
2021-02-12 18:15:53 +03:00
}
2021-02-07 22:47:33 +03:00
2014-05-16 17:59:15 +04:00
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
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( path_cost , 0644 ,
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
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( priority , 0644 ,
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 ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( designated_root , 0444 , show_designated_root , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_designated_bridge ( struct net_bridge_port * p , char * buf )
{
return br_show_bridge_id ( buf , & p - > designated_bridge ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( designated_bridge , 0444 , show_designated_bridge , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_designated_port ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > designated_port ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( designated_port , 0444 , show_designated_port , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_designated_cost ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > designated_cost ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( designated_cost , 0444 , show_designated_cost , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_port_id ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " 0x%x \n " , p - > port_id ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( port_id , 0444 , show_port_id , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_port_no ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " 0x%x \n " , p - > port_no ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( port_no , 0444 , show_port_no , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_change_ack ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > topology_change_ack ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( change_ack , 0444 , show_change_ack , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_config_pending ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > config_pending ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( config_pending , 0444 , show_config_pending , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_port_state ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %d \n " , p - > state ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( state , 0444 , show_port_state , NULL ) ;
2005-04-17 02:20:36 +04:00
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 ) ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( message_age_timer , 0444 , show_message_age_timer , NULL ) ;
2005-04-17 02:20:36 +04:00
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 ) ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( forward_delay_timer , 0444 , show_forward_delay_timer , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t show_hold_timer ( struct net_bridge_port * p ,
char * buf )
{
return sprintf ( buf , " %ld \n " , br_timer_value ( & p - > hold_timer ) ) ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( hold_timer , 0444 , show_hold_timer , NULL ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( flush , 0200 , NULL , store_flush ) ;
2007-04-09 23:57:54 +04:00
2017-09-27 16:12:44 +03:00
static ssize_t show_group_fwd_mask ( struct net_bridge_port * p , char * buf )
{
return sprintf ( buf , " %#x \n " , p - > group_fwd_mask ) ;
}
static int store_group_fwd_mask ( struct net_bridge_port * p ,
unsigned long v )
{
if ( v & BR_GROUPFWD_MACPAUSE )
return - EINVAL ;
p - > group_fwd_mask = v ;
return 0 ;
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( group_fwd_mask , 0644 , show_group_fwd_mask ,
2017-09-27 16:12:44 +03:00
store_group_fwd_mask ) ;
2018-07-23 11:16:59 +03:00
static ssize_t show_backup_port ( struct net_bridge_port * p , char * buf )
{
struct net_bridge_port * backup_p ;
int ret = 0 ;
rcu_read_lock ( ) ;
backup_p = rcu_dereference ( p - > backup_port ) ;
if ( backup_p )
ret = sprintf ( buf , " %s \n " , backup_p - > dev - > name ) ;
rcu_read_unlock ( ) ;
return ret ;
}
static int store_backup_port ( struct net_bridge_port * p , char * buf )
{
struct net_device * backup_dev = NULL ;
char * nl = strchr ( buf , ' \n ' ) ;
if ( nl )
* nl = ' \0 ' ;
if ( strlen ( buf ) > 0 ) {
backup_dev = __dev_get_by_name ( dev_net ( p - > dev ) , buf ) ;
if ( ! backup_dev )
return - ENOENT ;
}
return nbp_backup_change ( p , backup_dev ) ;
}
static BRPORT_ATTR_RAW ( backup_port , 0644 , show_backup_port , store_backup_port ) ;
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 ) ;
2017-04-26 16:48:09 +03:00
BRPORT_ATTR_FLAG ( broadcast_flood , BR_BCAST_FLOOD ) ;
2017-10-07 08:12:37 +03:00
BRPORT_ATTR_FLAG ( neigh_suppress , BR_NEIGH_SUPPRESS ) ;
2018-05-24 11:56:48 +03:00
BRPORT_ATTR_FLAG ( isolated , BR_ISOLATED ) ;
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 )
{
2021-07-19 20:06:23 +03:00
return sprintf ( buf , " %d \n " , p - > multicast_ctx . multicast_router ) ;
2010-02-27 22:41:49 +03:00
}
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 )
{
2021-08-20 15:42:54 +03:00
return br_multicast_set_port_router ( & p - > multicast_ctx , v ) ;
2010-02-27 22:41:49 +03:00
}
2018-03-24 01:54:38 +03:00
static BRPORT_ATTR ( multicast_router , 0644 , show_multicast_router ,
2010-02-27 22:41:49 +03:00
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 ) ;
2017-01-21 23:01:32 +03:00
BRPORT_ATTR_FLAG ( multicast_to_unicast , BR_MULTICAST_TO_UNICAST ) ;
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 ,
2017-01-21 23:01:32 +03:00
& brport_attr_multicast_to_unicast ,
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 ,
2016-10-13 16:20:52 +03:00
& brport_attr_multicast_flood ,
2017-04-26 16:48:09 +03:00
& brport_attr_broadcast_flood ,
2017-09-27 16:12:44 +03:00
& brport_attr_group_fwd_mask ,
2017-10-07 08:12:37 +03:00
& brport_attr_neigh_suppress ,
2018-05-24 11:56:48 +03:00
& brport_attr_isolated ,
2018-07-23 11:16:59 +03:00
& brport_attr_backup_port ,
2005-04-17 02:20:36 +04:00
NULL
} ;
# define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
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 ) ;
2018-07-21 00:56:54 +03:00
struct net_bridge_port * p = kobj_to_brport ( kobj ) ;
2005-04-17 02:20:36 +04:00
2018-02-12 12:15:40 +03:00
if ( ! brport_attr - > show )
return - EINVAL ;
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 ) ;
2018-07-21 00:56:54 +03:00
struct net_bridge_port * p = kobj_to_brport ( kobj ) ;
2005-04-17 02:20:36 +04:00
ssize_t ret = - EINVAL ;
unsigned long val ;
2018-07-23 11:16:58 +03:00
char * endp ;
2005-04-17 02:20:36 +04:00
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 ;
2018-07-23 11:16:58 +03:00
if ( ! rtnl_trylock ( ) )
return restart_syscall ( ) ;
if ( brport_attr - > store_raw ) {
char * buf_copy ;
buf_copy = kstrndup ( buf , count , GFP_KERNEL ) ;
if ( ! buf_copy ) {
ret = - ENOMEM ;
goto out_unlock ;
2005-04-17 02:20:36 +04:00
}
2018-07-23 11:16:58 +03:00
spin_lock_bh ( & p - > br - > lock ) ;
ret = brport_attr - > store_raw ( p , buf_copy ) ;
spin_unlock_bh ( & p - > br - > lock ) ;
kfree ( buf_copy ) ;
} else if ( brport_attr - > store ) {
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( endp = = buf )
goto out_unlock ;
spin_lock_bh ( & p - > br - > lock ) ;
ret = brport_attr - > store ( p , val ) ;
spin_unlock_bh ( & p - > br - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2018-07-23 11:16:58 +03:00
if ( ! ret ) {
br_ifinfo_notify ( RTM_NEWLINK , NULL , p ) ;
ret = count ;
}
out_unlock :
rtnl_unlock ( ) ;
2005-04-17 02:20:36 +04:00
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 ;
}