1/* 2 * Sysfs attributes of bridge ports 3 * Linux ethernet bridge 4 * 5 * Authors: 6 * Stephen Hemminger <shemminger@osdl.org> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 */ 13 14#include <linux/capability.h> 15#include <linux/kernel.h> 16#include <linux/netdevice.h> 17#include <linux/if_bridge.h> 18#include <linux/rtnetlink.h> 19#include <linux/spinlock.h> 20 21#include "br_private.h" 22 23struct brport_attribute { 24 struct attribute attr; 25 ssize_t (*show)(struct net_bridge_port *, char *); 26 ssize_t (*store)(struct net_bridge_port *, unsigned long); 27}; 28 29#define BRPORT_ATTR(_name,_mode,_show,_store) \ 30struct brport_attribute brport_attr_##_name = { \ 31 .attr = {.name = __stringify(_name), \ 32 .mode = _mode, \ 33 .owner = THIS_MODULE, }, \ 34 .show = _show, \ 35 .store = _store, \ 36}; 37 38static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) 39{ 40 return sprintf(buf, "%d\n", p->path_cost); 41} 42static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v) 43{ 44 br_stp_set_path_cost(p, v); 45 return 0; 46} 47static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR, 48 show_path_cost, store_path_cost); 49 50static ssize_t show_priority(struct net_bridge_port *p, char *buf) 51{ 52 return sprintf(buf, "%d\n", p->priority); 53} 54static ssize_t store_priority(struct net_bridge_port *p, unsigned long v) 55{ 56 if (v >= (1<<(16-BR_PORT_BITS))) 57 return -ERANGE; 58 br_stp_set_port_priority(p, v); 59 return 0; 60} 61static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR, 62 show_priority, store_priority); 63 64static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) 65{ 66 return br_show_bridge_id(buf, &p->designated_root); 67} 68static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL); 69 70static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf) 71{ 72 return br_show_bridge_id(buf, &p->designated_bridge); 73} 74static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL); 75 76static ssize_t show_designated_port(struct net_bridge_port *p, char *buf) 77{ 78 return sprintf(buf, "%d\n", p->designated_port); 79} 80static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL); 81 82static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf) 83{ 84 return sprintf(buf, "%d\n", p->designated_cost); 85} 86static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL); 87 88static ssize_t show_port_id(struct net_bridge_port *p, char *buf) 89{ 90 return sprintf(buf, "0x%x\n", p->port_id); 91} 92static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL); 93 94static ssize_t show_port_no(struct net_bridge_port *p, char *buf) 95{ 96 return sprintf(buf, "0x%x\n", p->port_no); 97} 98 99static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL); 100 101static ssize_t show_change_ack(struct net_bridge_port *p, char *buf) 102{ 103 return sprintf(buf, "%d\n", p->topology_change_ack); 104} 105static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL); 106 107static ssize_t show_config_pending(struct net_bridge_port *p, char *buf) 108{ 109 return sprintf(buf, "%d\n", p->config_pending); 110} 111static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL); 112 113static ssize_t show_port_state(struct net_bridge_port *p, char *buf) 114{ 115 return sprintf(buf, "%d\n", p->state); 116} 117static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL); 118 119static ssize_t show_message_age_timer(struct net_bridge_port *p, 120 char *buf) 121{ 122 return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer)); 123} 124static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL); 125 126static ssize_t show_forward_delay_timer(struct net_bridge_port *p, 127 char *buf) 128{ 129 return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer)); 130} 131static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL); 132 133static ssize_t show_hold_timer(struct net_bridge_port *p, 134 char *buf) 135{ 136 return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer)); 137} 138static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); 139 140static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) 141{ 142 br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry 143 return 0; 144} 145static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); 146 147static struct brport_attribute *brport_attrs[] = { 148 &brport_attr_path_cost, 149 &brport_attr_priority, 150 &brport_attr_port_id, 151 &brport_attr_port_no, 152 &brport_attr_designated_root, 153 &brport_attr_designated_bridge, 154 &brport_attr_designated_port, 155 &brport_attr_designated_cost, 156 &brport_attr_state, 157 &brport_attr_change_ack, 158 &brport_attr_config_pending, 159 &brport_attr_message_age_timer, 160 &brport_attr_forward_delay_timer, 161 &brport_attr_hold_timer, 162 &brport_attr_flush, 163 NULL 164}; 165 166#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) 167#define to_brport(obj) container_of(obj, struct net_bridge_port, kobj) 168 169static ssize_t brport_show(struct kobject * kobj, 170 struct attribute * attr, char * buf) 171{ 172 struct brport_attribute * brport_attr = to_brport_attr(attr); 173 struct net_bridge_port * p = to_brport(kobj); 174 175 return brport_attr->show(p, buf); 176} 177 178static ssize_t brport_store(struct kobject * kobj, 179 struct attribute * attr, 180 const char * buf, size_t count) 181{ 182 struct brport_attribute * brport_attr = to_brport_attr(attr); 183 struct net_bridge_port * p = to_brport(kobj); 184 ssize_t ret = -EINVAL; 185 char *endp; 186 unsigned long val; 187 188 if (!capable(CAP_NET_ADMIN)) 189 return -EPERM; 190 191 val = simple_strtoul(buf, &endp, 0); 192 if (endp != buf) { 193 rtnl_lock(); 194 if (p->dev && p->br && brport_attr->store) { 195 spin_lock_bh(&p->br->lock); 196 ret = brport_attr->store(p, val); 197 spin_unlock_bh(&p->br->lock); 198 if (ret == 0) 199 ret = count; 200 } 201 rtnl_unlock(); 202 } 203 return ret; 204} 205 206struct sysfs_ops brport_sysfs_ops = { 207 .show = brport_show, 208 .store = brport_store, 209}; 210 211/* 212 * Add sysfs entries to ethernet device added to a bridge. 213 * Creates a brport subdirectory with bridge attributes. 214 * Puts symlink in bridge's brport subdirectory 215 */ 216int br_sysfs_addif(struct net_bridge_port *p) 217{ 218 struct net_bridge *br = p->br; 219 struct brport_attribute **a; 220 int err; 221 222 err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, 223 SYSFS_BRIDGE_PORT_LINK); 224 if (err) 225 goto out2; 226 227 for (a = brport_attrs; *a; ++a) { 228 err = sysfs_create_file(&p->kobj, &((*a)->attr)); 229 if (err) 230 goto out2; 231 } 232 233 err= sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); 234out2: 235 return err; 236} 237