xref: /openbmc/linux/net/bridge/br_sysfs_if.c (revision 14f98f25)
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)		        \
301da177e4SLinus Torvalds 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 
371da177e4SLinus Torvalds static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->path_cost);
401da177e4SLinus Torvalds }
4114f98f25Sstephen hemminger 
421da177e4SLinus Torvalds static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
4314f98f25Sstephen hemminger 		   show_path_cost, br_stp_set_path_cost);
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds static ssize_t show_priority(struct net_bridge_port *p, char *buf)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->priority);
481da177e4SLinus Torvalds }
4914f98f25Sstephen hemminger 
501da177e4SLinus Torvalds static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
5114f98f25Sstephen hemminger 			 show_priority, br_stp_set_port_priority);
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
541da177e4SLinus Torvalds {
551da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_root);
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_bridge);
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_port);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_cost);
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_id);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_no);
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->topology_change_ack);
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->config_pending);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->state);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds static ssize_t show_message_age_timer(struct net_bridge_port *p,
1091da177e4SLinus Torvalds 					    char *buf)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
1161da177e4SLinus Torvalds 					    char *buf)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static ssize_t show_hold_timer(struct net_bridge_port *p,
1231da177e4SLinus Torvalds 					    char *buf)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
1281da177e4SLinus Torvalds 
12914f98f25Sstephen hemminger static int store_flush(struct net_bridge_port *p, unsigned long v)
1309cf63747SStephen Hemminger {
1319cf63747SStephen Hemminger 	br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry
1329cf63747SStephen Hemminger 	return 0;
1339cf63747SStephen Hemminger }
1349cf63747SStephen Hemminger static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);
1359cf63747SStephen Hemminger 
1363982d3d2SFischer, Anna static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf)
1373982d3d2SFischer, Anna {
1383982d3d2SFischer, Anna 	int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0;
1393982d3d2SFischer, Anna 	return sprintf(buf, "%d\n", hairpin_mode);
1403982d3d2SFischer, Anna }
14114f98f25Sstephen hemminger static int store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
1423982d3d2SFischer, Anna {
1433982d3d2SFischer, Anna 	if (v)
1443982d3d2SFischer, Anna 		p->flags |= BR_HAIRPIN_MODE;
1453982d3d2SFischer, Anna 	else
1463982d3d2SFischer, Anna 		p->flags &= ~BR_HAIRPIN_MODE;
1473982d3d2SFischer, Anna 	return 0;
1483982d3d2SFischer, Anna }
1493982d3d2SFischer, Anna static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
1503982d3d2SFischer, Anna 		   show_hairpin_mode, store_hairpin_mode);
1513982d3d2SFischer, Anna 
1520909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1530909e117SHerbert Xu static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
1540909e117SHerbert Xu {
1550909e117SHerbert Xu 	return sprintf(buf, "%d\n", p->multicast_router);
1560909e117SHerbert Xu }
1570909e117SHerbert Xu 
15814f98f25Sstephen hemminger static int store_multicast_router(struct net_bridge_port *p,
1590909e117SHerbert Xu 				      unsigned long v)
1600909e117SHerbert Xu {
1610909e117SHerbert Xu 	return br_multicast_set_port_router(p, v);
1620909e117SHerbert Xu }
1630909e117SHerbert Xu static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
1640909e117SHerbert Xu 		   store_multicast_router);
1650909e117SHerbert Xu #endif
1660909e117SHerbert Xu 
1671da177e4SLinus Torvalds static struct brport_attribute *brport_attrs[] = {
1681da177e4SLinus Torvalds 	&brport_attr_path_cost,
1691da177e4SLinus Torvalds 	&brport_attr_priority,
1701da177e4SLinus Torvalds 	&brport_attr_port_id,
1711da177e4SLinus Torvalds 	&brport_attr_port_no,
1721da177e4SLinus Torvalds 	&brport_attr_designated_root,
1731da177e4SLinus Torvalds 	&brport_attr_designated_bridge,
1741da177e4SLinus Torvalds 	&brport_attr_designated_port,
1751da177e4SLinus Torvalds 	&brport_attr_designated_cost,
1761da177e4SLinus Torvalds 	&brport_attr_state,
1771da177e4SLinus Torvalds 	&brport_attr_change_ack,
1781da177e4SLinus Torvalds 	&brport_attr_config_pending,
1791da177e4SLinus Torvalds 	&brport_attr_message_age_timer,
1801da177e4SLinus Torvalds 	&brport_attr_forward_delay_timer,
1811da177e4SLinus Torvalds 	&brport_attr_hold_timer,
1829cf63747SStephen Hemminger 	&brport_attr_flush,
1833982d3d2SFischer, Anna 	&brport_attr_hairpin_mode,
1840909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1850909e117SHerbert Xu 	&brport_attr_multicast_router,
1860909e117SHerbert Xu #endif
1871da177e4SLinus Torvalds 	NULL
1881da177e4SLinus Torvalds };
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
1911da177e4SLinus Torvalds #define to_brport(obj)	container_of(obj, struct net_bridge_port, kobj)
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds static ssize_t brport_show(struct kobject * kobj,
1941da177e4SLinus Torvalds 			   struct attribute * attr, char * buf)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	struct brport_attribute * brport_attr = to_brport_attr(attr);
1971da177e4SLinus Torvalds 	struct net_bridge_port * p = to_brport(kobj);
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	return brport_attr->show(p, buf);
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds static ssize_t brport_store(struct kobject * kobj,
2031da177e4SLinus Torvalds 			    struct attribute * attr,
2041da177e4SLinus Torvalds 			    const char * buf, size_t count)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds 	struct brport_attribute * brport_attr = to_brport_attr(attr);
2071da177e4SLinus Torvalds 	struct net_bridge_port * p = to_brport(kobj);
2081da177e4SLinus Torvalds 	ssize_t ret = -EINVAL;
2091da177e4SLinus Torvalds 	char *endp;
2101da177e4SLinus Torvalds 	unsigned long val;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	if (!capable(CAP_NET_ADMIN))
2131da177e4SLinus Torvalds 		return -EPERM;
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	val = simple_strtoul(buf, &endp, 0);
2161da177e4SLinus Torvalds 	if (endp != buf) {
217af38f298SEric W. Biederman 		if (!rtnl_trylock())
218af38f298SEric W. Biederman 			return restart_syscall();
2191da177e4SLinus Torvalds 		if (p->dev && p->br && brport_attr->store) {
2201da177e4SLinus Torvalds 			spin_lock_bh(&p->br->lock);
2211da177e4SLinus Torvalds 			ret = brport_attr->store(p, val);
2221da177e4SLinus Torvalds 			spin_unlock_bh(&p->br->lock);
2231da177e4SLinus Torvalds 			if (ret == 0)
2241da177e4SLinus Torvalds 				ret = count;
2251da177e4SLinus Torvalds 		}
2261da177e4SLinus Torvalds 		rtnl_unlock();
2271da177e4SLinus Torvalds 	}
2281da177e4SLinus Torvalds 	return ret;
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
23152cf25d0SEmese Revfy const struct sysfs_ops brport_sysfs_ops = {
2321da177e4SLinus Torvalds 	.show = brport_show,
2331da177e4SLinus Torvalds 	.store = brport_store,
2341da177e4SLinus Torvalds };
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds /*
2371da177e4SLinus Torvalds  * Add sysfs entries to ethernet device added to a bridge.
2381da177e4SLinus Torvalds  * Creates a brport subdirectory with bridge attributes.
239e0f43752SSimon Arlott  * Puts symlink in bridge's brif subdirectory
2401da177e4SLinus Torvalds  */
2411da177e4SLinus Torvalds int br_sysfs_addif(struct net_bridge_port *p)
2421da177e4SLinus Torvalds {
2431da177e4SLinus Torvalds 	struct net_bridge *br = p->br;
2441da177e4SLinus Torvalds 	struct brport_attribute **a;
2451da177e4SLinus Torvalds 	int err;
2461da177e4SLinus Torvalds 
24743cb76d9SGreg Kroah-Hartman 	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
2481da177e4SLinus Torvalds 				SYSFS_BRIDGE_PORT_LINK);
2491da177e4SLinus Torvalds 	if (err)
250e0f43752SSimon Arlott 		return err;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	for (a = brport_attrs; *a; ++a) {
2531da177e4SLinus Torvalds 		err = sysfs_create_file(&p->kobj, &((*a)->attr));
2541da177e4SLinus Torvalds 		if (err)
255e0f43752SSimon Arlott 			return err;
2561da177e4SLinus Torvalds 	}
2571da177e4SLinus Torvalds 
258e0f43752SSimon Arlott 	strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
259e0f43752SSimon Arlott 	return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
260e0f43752SSimon Arlott }
261e0f43752SSimon Arlott 
262e0f43752SSimon Arlott /* Rename bridge's brif symlink */
263e0f43752SSimon Arlott int br_sysfs_renameif(struct net_bridge_port *p)
264e0f43752SSimon Arlott {
265e0f43752SSimon Arlott 	struct net_bridge *br = p->br;
266e0f43752SSimon Arlott 	int err;
267e0f43752SSimon Arlott 
268e0f43752SSimon Arlott 	/* If a rename fails, the rollback will cause another
269e0f43752SSimon Arlott 	 * rename call with the existing name.
270e0f43752SSimon Arlott 	 */
271e0f43752SSimon Arlott 	if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
272e0f43752SSimon Arlott 		return 0;
273e0f43752SSimon Arlott 
274e0f43752SSimon Arlott 	err = sysfs_rename_link(br->ifobj, &p->kobj,
275e0f43752SSimon Arlott 				p->sysfs_name, p->dev->name);
276e0f43752SSimon Arlott 	if (err)
277e0f43752SSimon Arlott 		netdev_notice(br->dev, "unable to rename link %s to %s",
278e0f43752SSimon Arlott 			      p->sysfs_name, p->dev->name);
279e0f43752SSimon Arlott 	else
280e0f43752SSimon Arlott 		strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
281e0f43752SSimon Arlott 
2821da177e4SLinus Torvalds 	return err;
2831da177e4SLinus Torvalds }
284