xref: /openbmc/linux/net/bridge/br_sysfs_if.c (revision 50426b59)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Sysfs attributes of bridge ports
31da177e4SLinus Torvalds  *	Linux ethernet bridge
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	Authors:
61da177e4SLinus Torvalds  *	Stephen Hemminger		<shemminger@osdl.org>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
91da177e4SLinus Torvalds  *	modify it under the terms of the GNU General Public License
101da177e4SLinus Torvalds  *	as published by the Free Software Foundation; either version
111da177e4SLinus Torvalds  *	2 of the License, or (at your option) any later version.
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
144fc268d2SRandy Dunlap #include <linux/capability.h>
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/netdevice.h>
171da177e4SLinus Torvalds #include <linux/if_bridge.h>
181da177e4SLinus Torvalds #include <linux/rtnetlink.h>
191da177e4SLinus Torvalds #include <linux/spinlock.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include "br_private.h"
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds struct brport_attribute {
241da177e4SLinus Torvalds 	struct attribute	attr;
251da177e4SLinus Torvalds 	ssize_t (*show)(struct net_bridge_port *, char *);
2614f98f25Sstephen hemminger 	int (*store)(struct net_bridge_port *, unsigned long);
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define BRPORT_ATTR(_name,_mode,_show,_store)		        \
305a0d513bSstephen hemminger const struct brport_attribute brport_attr_##_name = { 	        \
311da177e4SLinus Torvalds 	.attr = {.name = __stringify(_name), 			\
327b595756STejun Heo 		 .mode = _mode },				\
331da177e4SLinus Torvalds 	.show	= _show,					\
341da177e4SLinus Torvalds 	.store	= _store,					\
351da177e4SLinus Torvalds };
361da177e4SLinus Torvalds 
37cd753732Sstephen hemminger #define BRPORT_ATTR_FLAG(_name, _mask)				\
38cd753732Sstephen hemminger static ssize_t show_##_name(struct net_bridge_port *p, char *buf) \
39cd753732Sstephen hemminger {								\
40cd753732Sstephen hemminger 	return sprintf(buf, "%d\n", !!(p->flags & _mask));	\
41cd753732Sstephen hemminger }								\
42cd753732Sstephen hemminger static int store_##_name(struct net_bridge_port *p, unsigned long v) \
43cd753732Sstephen hemminger {								\
44cd753732Sstephen hemminger 	unsigned long flags = p->flags;				\
45cd753732Sstephen hemminger 	if (v)							\
46cd753732Sstephen hemminger 		flags |= _mask;					\
47cd753732Sstephen hemminger 	else							\
48cd753732Sstephen hemminger 		flags &= ~_mask;				\
49cd753732Sstephen hemminger 	if (flags != p->flags) {				\
50cd753732Sstephen hemminger 		p->flags = flags;				\
51cd753732Sstephen hemminger 		br_ifinfo_notify(RTM_NEWLINK, p);		\
52cd753732Sstephen hemminger 	}							\
53cd753732Sstephen hemminger 	return 0;						\
54cd753732Sstephen hemminger }								\
55cd753732Sstephen hemminger static BRPORT_ATTR(_name, S_IRUGO | S_IWUSR,			\
56cd753732Sstephen hemminger 		   show_##_name, store_##_name)
57cd753732Sstephen hemminger 
58cd753732Sstephen hemminger 
591da177e4SLinus Torvalds static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->path_cost);
621da177e4SLinus Torvalds }
6314f98f25Sstephen hemminger 
641da177e4SLinus Torvalds static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
6514f98f25Sstephen hemminger 		   show_path_cost, br_stp_set_path_cost);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds static ssize_t show_priority(struct net_bridge_port *p, char *buf)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->priority);
701da177e4SLinus Torvalds }
7114f98f25Sstephen hemminger 
721da177e4SLinus Torvalds static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
7314f98f25Sstephen hemminger 			 show_priority, br_stp_set_port_priority);
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
761da177e4SLinus Torvalds {
771da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_root);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
821da177e4SLinus Torvalds {
831da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_bridge);
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_port);
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_cost);
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_id);
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_no);
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->topology_change_ack);
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->config_pending);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->state);
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds static ssize_t show_message_age_timer(struct net_bridge_port *p,
1311da177e4SLinus Torvalds 					    char *buf)
1321da177e4SLinus Torvalds {
1331da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
1381da177e4SLinus Torvalds 					    char *buf)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds static ssize_t show_hold_timer(struct net_bridge_port *p,
1451da177e4SLinus Torvalds 					    char *buf)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
1501da177e4SLinus Torvalds 
15114f98f25Sstephen hemminger static int store_flush(struct net_bridge_port *p, unsigned long v)
1529cf63747SStephen Hemminger {
1539cf63747SStephen Hemminger 	br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry
1549cf63747SStephen Hemminger 	return 0;
1559cf63747SStephen Hemminger }
1569cf63747SStephen Hemminger static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);
1579cf63747SStephen Hemminger 
158cd753732Sstephen hemminger BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
159a2e01a65Sstephen hemminger BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
1601007dd1aSstephen hemminger BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
1613982d3d2SFischer, Anna 
1620909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1630909e117SHerbert Xu static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
1640909e117SHerbert Xu {
1650909e117SHerbert Xu 	return sprintf(buf, "%d\n", p->multicast_router);
1660909e117SHerbert Xu }
1670909e117SHerbert Xu 
16814f98f25Sstephen hemminger static int store_multicast_router(struct net_bridge_port *p,
1690909e117SHerbert Xu 				      unsigned long v)
1700909e117SHerbert Xu {
1710909e117SHerbert Xu 	return br_multicast_set_port_router(p, v);
1720909e117SHerbert Xu }
1730909e117SHerbert Xu static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
1740909e117SHerbert Xu 		   store_multicast_router);
17550426b59SAmerigo Wang 
17650426b59SAmerigo Wang static ssize_t show_multicast_fast_leave(struct net_bridge_port *p,
17750426b59SAmerigo Wang 					 char *buf)
17850426b59SAmerigo Wang {
17950426b59SAmerigo Wang 	return sprintf(buf, "%d\n", p->multicast_fast_leave);
18050426b59SAmerigo Wang }
18150426b59SAmerigo Wang 
18250426b59SAmerigo Wang static int store_multicast_fast_leave(struct net_bridge_port *p,
18350426b59SAmerigo Wang 				      unsigned long v)
18450426b59SAmerigo Wang {
18550426b59SAmerigo Wang 	if (p->br->multicast_disabled)
18650426b59SAmerigo Wang 		return -EINVAL;
18750426b59SAmerigo Wang 
18850426b59SAmerigo Wang 	p->multicast_fast_leave = !!v;
18950426b59SAmerigo Wang 	return 0;
19050426b59SAmerigo Wang }
19150426b59SAmerigo Wang 
19250426b59SAmerigo Wang static BRPORT_ATTR(multicast_fast_leave, S_IRUGO | S_IWUSR,
19350426b59SAmerigo Wang 		   show_multicast_fast_leave, store_multicast_fast_leave);
1940909e117SHerbert Xu #endif
1950909e117SHerbert Xu 
1965a0d513bSstephen hemminger static const struct brport_attribute *brport_attrs[] = {
1971da177e4SLinus Torvalds 	&brport_attr_path_cost,
1981da177e4SLinus Torvalds 	&brport_attr_priority,
1991da177e4SLinus Torvalds 	&brport_attr_port_id,
2001da177e4SLinus Torvalds 	&brport_attr_port_no,
2011da177e4SLinus Torvalds 	&brport_attr_designated_root,
2021da177e4SLinus Torvalds 	&brport_attr_designated_bridge,
2031da177e4SLinus Torvalds 	&brport_attr_designated_port,
2041da177e4SLinus Torvalds 	&brport_attr_designated_cost,
2051da177e4SLinus Torvalds 	&brport_attr_state,
2061da177e4SLinus Torvalds 	&brport_attr_change_ack,
2071da177e4SLinus Torvalds 	&brport_attr_config_pending,
2081da177e4SLinus Torvalds 	&brport_attr_message_age_timer,
2091da177e4SLinus Torvalds 	&brport_attr_forward_delay_timer,
2101da177e4SLinus Torvalds 	&brport_attr_hold_timer,
2119cf63747SStephen Hemminger 	&brport_attr_flush,
2123982d3d2SFischer, Anna 	&brport_attr_hairpin_mode,
213a2e01a65Sstephen hemminger 	&brport_attr_bpdu_guard,
2141007dd1aSstephen hemminger 	&brport_attr_root_block,
2150909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
2160909e117SHerbert Xu 	&brport_attr_multicast_router,
21750426b59SAmerigo Wang 	&brport_attr_multicast_fast_leave,
2180909e117SHerbert Xu #endif
2191da177e4SLinus Torvalds 	NULL
2201da177e4SLinus Torvalds };
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
2231da177e4SLinus Torvalds #define to_brport(obj)	container_of(obj, struct net_bridge_port, kobj)
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds static ssize_t brport_show(struct kobject * kobj,
2261da177e4SLinus Torvalds 			   struct attribute * attr, char * buf)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	struct brport_attribute * brport_attr = to_brport_attr(attr);
2291da177e4SLinus Torvalds 	struct net_bridge_port * p = to_brport(kobj);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	return brport_attr->show(p, buf);
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds static ssize_t brport_store(struct kobject * kobj,
2351da177e4SLinus Torvalds 			    struct attribute * attr,
2361da177e4SLinus Torvalds 			    const char * buf, size_t count)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds 	struct brport_attribute * brport_attr = to_brport_attr(attr);
2391da177e4SLinus Torvalds 	struct net_bridge_port * p = to_brport(kobj);
2401da177e4SLinus Torvalds 	ssize_t ret = -EINVAL;
2411da177e4SLinus Torvalds 	char *endp;
2421da177e4SLinus Torvalds 	unsigned long val;
2431da177e4SLinus Torvalds 
244cb990503SEric W. Biederman 	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
2451da177e4SLinus Torvalds 		return -EPERM;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	val = simple_strtoul(buf, &endp, 0);
2481da177e4SLinus Torvalds 	if (endp != buf) {
249af38f298SEric W. Biederman 		if (!rtnl_trylock())
250af38f298SEric W. Biederman 			return restart_syscall();
2511da177e4SLinus Torvalds 		if (p->dev && p->br && brport_attr->store) {
2521da177e4SLinus Torvalds 			spin_lock_bh(&p->br->lock);
2531da177e4SLinus Torvalds 			ret = brport_attr->store(p, val);
2541da177e4SLinus Torvalds 			spin_unlock_bh(&p->br->lock);
2551da177e4SLinus Torvalds 			if (ret == 0)
2561da177e4SLinus Torvalds 				ret = count;
2571da177e4SLinus Torvalds 		}
2581da177e4SLinus Torvalds 		rtnl_unlock();
2591da177e4SLinus Torvalds 	}
2601da177e4SLinus Torvalds 	return ret;
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds 
26352cf25d0SEmese Revfy const struct sysfs_ops brport_sysfs_ops = {
2641da177e4SLinus Torvalds 	.show = brport_show,
2651da177e4SLinus Torvalds 	.store = brport_store,
2661da177e4SLinus Torvalds };
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds /*
2691da177e4SLinus Torvalds  * Add sysfs entries to ethernet device added to a bridge.
2701da177e4SLinus Torvalds  * Creates a brport subdirectory with bridge attributes.
271e0f43752SSimon Arlott  * Puts symlink in bridge's brif subdirectory
2721da177e4SLinus Torvalds  */
2731da177e4SLinus Torvalds int br_sysfs_addif(struct net_bridge_port *p)
2741da177e4SLinus Torvalds {
2751da177e4SLinus Torvalds 	struct net_bridge *br = p->br;
2765a0d513bSstephen hemminger 	const struct brport_attribute **a;
2771da177e4SLinus Torvalds 	int err;
2781da177e4SLinus Torvalds 
27943cb76d9SGreg Kroah-Hartman 	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
2801da177e4SLinus Torvalds 				SYSFS_BRIDGE_PORT_LINK);
2811da177e4SLinus Torvalds 	if (err)
282e0f43752SSimon Arlott 		return err;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	for (a = brport_attrs; *a; ++a) {
2851da177e4SLinus Torvalds 		err = sysfs_create_file(&p->kobj, &((*a)->attr));
2861da177e4SLinus Torvalds 		if (err)
287e0f43752SSimon Arlott 			return err;
2881da177e4SLinus Torvalds 	}
2891da177e4SLinus Torvalds 
290e0f43752SSimon Arlott 	strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
291e0f43752SSimon Arlott 	return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
292e0f43752SSimon Arlott }
293e0f43752SSimon Arlott 
294e0f43752SSimon Arlott /* Rename bridge's brif symlink */
295e0f43752SSimon Arlott int br_sysfs_renameif(struct net_bridge_port *p)
296e0f43752SSimon Arlott {
297e0f43752SSimon Arlott 	struct net_bridge *br = p->br;
298e0f43752SSimon Arlott 	int err;
299e0f43752SSimon Arlott 
300e0f43752SSimon Arlott 	/* If a rename fails, the rollback will cause another
301e0f43752SSimon Arlott 	 * rename call with the existing name.
302e0f43752SSimon Arlott 	 */
303e0f43752SSimon Arlott 	if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
304e0f43752SSimon Arlott 		return 0;
305e0f43752SSimon Arlott 
306e0f43752SSimon Arlott 	err = sysfs_rename_link(br->ifobj, &p->kobj,
307e0f43752SSimon Arlott 				p->sysfs_name, p->dev->name);
308e0f43752SSimon Arlott 	if (err)
309e0f43752SSimon Arlott 		netdev_notice(br->dev, "unable to rename link %s to %s",
310e0f43752SSimon Arlott 			      p->sysfs_name, p->dev->name);
311e0f43752SSimon Arlott 	else
312e0f43752SSimon Arlott 		strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
313e0f43752SSimon Arlott 
3141da177e4SLinus Torvalds 	return err;
3151da177e4SLinus Torvalds }
316