diff options
Diffstat (limited to 'net/bridge/br_sysfs_if.c')
| -rw-r--r-- | net/bridge/br_sysfs_if.c | 200 |
1 files changed, 120 insertions, 80 deletions
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 0ac0355d16d..e561cd59b8a 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -23,43 +23,64 @@ struct brport_attribute { struct attribute attr; ssize_t (*show)(struct net_bridge_port *, char *); - ssize_t (*store)(struct net_bridge_port *, unsigned long); + int (*store)(struct net_bridge_port *, unsigned long); }; -#define BRPORT_ATTR(_name,_mode,_show,_store) \ -struct brport_attribute brport_attr_##_name = { \ +#define BRPORT_ATTR(_name, _mode, _show, _store) \ +const struct brport_attribute brport_attr_##_name = { \ .attr = {.name = __stringify(_name), \ - .mode = _mode, \ - .owner = THIS_MODULE, }, \ + .mode = _mode }, \ .show = _show, \ .store = _store, \ }; -static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) +#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) \ +{ \ + return store_flag(p, v, _mask); \ +} \ +static BRPORT_ATTR(_name, S_IRUGO | S_IWUSR, \ + show_##_name, store_##_name) + +static int store_flag(struct net_bridge_port *p, unsigned long v, + unsigned long mask) { - return sprintf(buf, "%d\n", p->path_cost); + unsigned long flags; + + flags = p->flags; + + if (v) + flags |= mask; + else + flags &= ~mask; + + if (flags != p->flags) { + p->flags = flags; + br_port_flags_change(p, mask); + br_ifinfo_notify(RTM_NEWLINK, p); + } + return 0; } -static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v) + +static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) { - br_stp_set_path_cost(p, v); - return 0; + return sprintf(buf, "%d\n", p->path_cost); } + static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR, - show_path_cost, store_path_cost); + show_path_cost, br_stp_set_path_cost); static ssize_t show_priority(struct net_bridge_port *p, char *buf) { return sprintf(buf, "%d\n", p->priority); } -static ssize_t store_priority(struct net_bridge_port *p, unsigned long v) -{ - if (v >= (1<<(16-BR_PORT_BITS))) - return -ERANGE; - br_stp_set_port_priority(p, v); - return 0; -} + static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR, - show_priority, store_priority); + show_priority, br_stp_set_port_priority); static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) { @@ -137,7 +158,37 @@ static ssize_t show_hold_timer(struct net_bridge_port *p, } static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); -static struct brport_attribute *brport_attrs[] = { +static int store_flush(struct net_bridge_port *p, unsigned long v) +{ + br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry + return 0; +} +static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); + +BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE); +BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD); +BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); +BRPORT_ATTR_FLAG(learning, BR_LEARNING); +BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); + +#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); +} + +static int store_multicast_router(struct net_bridge_port *p, + 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); + +BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); +#endif + +static const struct brport_attribute *brport_attrs[] = { &brport_attr_path_cost, &brport_attr_priority, &brport_attr_port_id, @@ -152,37 +203,48 @@ static struct brport_attribute *brport_attrs[] = { &brport_attr_message_age_timer, &brport_attr_forward_delay_timer, &brport_attr_hold_timer, + &brport_attr_flush, + &brport_attr_hairpin_mode, + &brport_attr_bpdu_guard, + &brport_attr_root_block, + &brport_attr_learning, + &brport_attr_unicast_flood, +#ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, +#endif 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) -static ssize_t brport_show(struct kobject * kobj, - struct attribute * attr, char * buf) +static ssize_t brport_show(struct kobject *kobj, + struct attribute *attr, char *buf) { - struct brport_attribute * brport_attr = to_brport_attr(attr); - struct net_bridge_port * p = to_brport(kobj); + struct brport_attribute *brport_attr = to_brport_attr(attr); + struct net_bridge_port *p = to_brport(kobj); return brport_attr->show(p, buf); } -static ssize_t brport_store(struct kobject * kobj, - struct attribute * attr, - const char * buf, size_t count) +static ssize_t brport_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) { - struct brport_attribute * brport_attr = to_brport_attr(attr); - struct net_bridge_port * p = to_brport(kobj); + struct brport_attribute *brport_attr = to_brport_attr(attr); + struct net_bridge_port *p = to_brport(kobj); ssize_t ret = -EINVAL; char *endp; unsigned long val; - if (!capable(CAP_NET_ADMIN)) + if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN)) return -EPERM; val = simple_strtoul(buf, &endp, 0); if (endp != buf) { - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (p->dev && p->br && brport_attr->store) { spin_lock_bh(&p->br->lock); ret = brport_attr->store(p, val); @@ -195,78 +257,56 @@ static ssize_t brport_store(struct kobject * kobj, return ret; } -/* called from kobject_put when port ref count goes to zero. */ -static void brport_release(struct kobject *kobj) -{ - kfree(container_of(kobj, struct net_bridge_port, kobj)); -} - -static struct sysfs_ops brport_sysfs_ops = { +const struct sysfs_ops brport_sysfs_ops = { .show = brport_show, .store = brport_store, }; -static struct kobj_type brport_ktype = { - .sysfs_ops = &brport_sysfs_ops, - .release = brport_release, -}; - - /* * Add sysfs entries to ethernet device added to a bridge. * Creates a brport subdirectory with bridge attributes. - * Puts symlink in bridge's brport subdirectory + * Puts symlink in bridge's brif subdirectory */ int br_sysfs_addif(struct net_bridge_port *p) { struct net_bridge *br = p->br; - struct brport_attribute **a; + const struct brport_attribute **a; int err; - ASSERT_RTNL(); - - kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); - p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(p->dev->class_dev.kobj); - p->kobj.kset = NULL; - - err = kobject_add(&p->kobj); - if(err) - goto out1; - - err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, + err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, SYSFS_BRIDGE_PORT_LINK); if (err) - goto out2; + return err; for (a = brport_attrs; *a; ++a) { err = sysfs_create_file(&p->kobj, &((*a)->attr)); if (err) - goto out2; + return err; } - err = sysfs_create_link(&br->ifobj, &p->kobj, p->dev->name); - if (err) - goto out2; - - kobject_uevent(&p->kobj, KOBJ_ADD); - return 0; - out2: - kobject_del(&p->kobj); - out1: - return err; + strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ); + return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name); } -void br_sysfs_removeif(struct net_bridge_port *p) +/* Rename bridge's brif symlink */ +int br_sysfs_renameif(struct net_bridge_port *p) { - pr_debug("br_sysfs_removeif\n"); - sysfs_remove_link(&p->br->ifobj, p->dev->name); - kobject_uevent(&p->kobj, KOBJ_REMOVE); - kobject_del(&p->kobj); -} + struct net_bridge *br = p->br; + int err; -void br_sysfs_freeif(struct net_bridge_port *p) -{ - pr_debug("br_sysfs_freeif\n"); - kobject_put(&p->kobj); + /* 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); + + return err; } |
