linux/net/bridge/br_sysfs_br.c
<<
>>
Prefs
   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#include <linux/times.h>
  21
  22#include "br_private.h"
  23
  24#define to_dev(obj)     container_of(obj, struct device, kobj)
  25#define to_bridge(cd)   ((struct net_bridge *)netdev_priv(to_net_dev(cd)))
  26
  27/*
  28 * Common code for storing bridge parameters.
  29 */
  30static ssize_t store_bridge_parm(struct device *d,
  31                                 const char *buf, size_t len,
  32                                 int (*set)(struct net_bridge *, unsigned long))
  33{
  34        struct net_bridge *br = to_bridge(d);
  35        char *endp;
  36        unsigned long val;
  37        int err;
  38
  39        if (!capable(CAP_NET_ADMIN))
  40                return -EPERM;
  41
  42        val = simple_strtoul(buf, &endp, 0);
  43        if (endp == buf)
  44                return -EINVAL;
  45
  46        spin_lock_bh(&br->lock);
  47        err = (*set)(br, val);
  48        spin_unlock_bh(&br->lock);
  49        return err ? err : len;
  50}
  51
  52
  53static ssize_t show_forward_delay(struct device *d,
  54                                  struct device_attribute *attr, char *buf)
  55{
  56        struct net_bridge *br = to_bridge(d);
  57        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
  58}
  59
  60static int set_forward_delay(struct net_bridge *br, unsigned long val)
  61{
  62        unsigned long delay = clock_t_to_jiffies(val);
  63        br->forward_delay = delay;
  64        if (br_is_root_bridge(br))
  65                br->bridge_forward_delay = delay;
  66        return 0;
  67}
  68
  69static ssize_t store_forward_delay(struct device *d,
  70                                   struct device_attribute *attr,
  71                                   const char *buf, size_t len)
  72{
  73        return store_bridge_parm(d, buf, len, set_forward_delay);
  74}
  75static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
  76                   show_forward_delay, store_forward_delay);
  77
  78static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
  79                               char *buf)
  80{
  81        return sprintf(buf, "%lu\n",
  82                       jiffies_to_clock_t(to_bridge(d)->hello_time));
  83}
  84
  85static int set_hello_time(struct net_bridge *br, unsigned long val)
  86{
  87        unsigned long t = clock_t_to_jiffies(val);
  88
  89        if (t < HZ)
  90                return -EINVAL;
  91
  92        br->hello_time = t;
  93        if (br_is_root_bridge(br))
  94                br->bridge_hello_time = t;
  95        return 0;
  96}
  97
  98static ssize_t store_hello_time(struct device *d,
  99                                struct device_attribute *attr, const char *buf,
 100                                size_t len)
 101{
 102        return store_bridge_parm(d, buf, len, set_hello_time);
 103}
 104static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
 105                   store_hello_time);
 106
 107static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
 108                            char *buf)
 109{
 110        return sprintf(buf, "%lu\n",
 111                       jiffies_to_clock_t(to_bridge(d)->max_age));
 112}
 113
 114static int set_max_age(struct net_bridge *br, unsigned long val)
 115{
 116        unsigned long t = clock_t_to_jiffies(val);
 117        br->max_age = t;
 118        if (br_is_root_bridge(br))
 119                br->bridge_max_age = t;
 120        return 0;
 121}
 122
 123static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
 124                             const char *buf, size_t len)
 125{
 126        return store_bridge_parm(d, buf, len, set_max_age);
 127}
 128static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 129
 130static ssize_t show_ageing_time(struct device *d,
 131                                struct device_attribute *attr, char *buf)
 132{
 133        struct net_bridge *br = to_bridge(d);
 134        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 135}
 136
 137static int set_ageing_time(struct net_bridge *br, unsigned long val)
 138{
 139        br->ageing_time = clock_t_to_jiffies(val);
 140        return 0;
 141}
 142
 143static ssize_t store_ageing_time(struct device *d,
 144                                 struct device_attribute *attr,
 145                                 const char *buf, size_t len)
 146{
 147        return store_bridge_parm(d, buf, len, set_ageing_time);
 148}
 149static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
 150                   store_ageing_time);
 151
 152static ssize_t show_stp_state(struct device *d,
 153                              struct device_attribute *attr, char *buf)
 154{
 155        struct net_bridge *br = to_bridge(d);
 156        return sprintf(buf, "%d\n", br->stp_enabled);
 157}
 158
 159
 160static ssize_t store_stp_state(struct device *d,
 161                               struct device_attribute *attr, const char *buf,
 162                               size_t len)
 163{
 164        struct net_bridge *br = to_bridge(d);
 165        char *endp;
 166        unsigned long val;
 167
 168        if (!capable(CAP_NET_ADMIN))
 169                return -EPERM;
 170
 171        val = simple_strtoul(buf, &endp, 0);
 172        if (endp == buf)
 173                return -EINVAL;
 174
 175        if (!rtnl_trylock())
 176                return restart_syscall();
 177        br_stp_set_enabled(br, val);
 178        rtnl_unlock();
 179
 180        return len;
 181}
 182static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
 183                   store_stp_state);
 184
 185static ssize_t show_priority(struct device *d, struct device_attribute *attr,
 186                             char *buf)
 187{
 188        struct net_bridge *br = to_bridge(d);
 189        return sprintf(buf, "%d\n",
 190                       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 191}
 192
 193static int set_priority(struct net_bridge *br, unsigned long val)
 194{
 195        br_stp_set_bridge_priority(br, (u16) val);
 196        return 0;
 197}
 198
 199static ssize_t store_priority(struct device *d, struct device_attribute *attr,
 200                               const char *buf, size_t len)
 201{
 202        return store_bridge_parm(d, buf, len, set_priority);
 203}
 204static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 205
 206static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
 207                            char *buf)
 208{
 209        return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
 210}
 211static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 212
 213static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
 214                              char *buf)
 215{
 216        return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
 217}
 218static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 219
 220static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
 221                              char *buf)
 222{
 223        return sprintf(buf, "%d\n", to_bridge(d)->root_port);
 224}
 225static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 226
 227static ssize_t show_root_path_cost(struct device *d,
 228                                   struct device_attribute *attr, char *buf)
 229{
 230        return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
 231}
 232static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 233
 234static ssize_t show_topology_change(struct device *d,
 235                                    struct device_attribute *attr, char *buf)
 236{
 237        return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
 238}
 239static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 240
 241static ssize_t show_topology_change_detected(struct device *d,
 242                                             struct device_attribute *attr,
 243                                             char *buf)
 244{
 245        struct net_bridge *br = to_bridge(d);
 246        return sprintf(buf, "%d\n", br->topology_change_detected);
 247}
 248static DEVICE_ATTR(topology_change_detected, S_IRUGO,
 249                   show_topology_change_detected, NULL);
 250
 251static ssize_t show_hello_timer(struct device *d,
 252                                struct device_attribute *attr, char *buf)
 253{
 254        struct net_bridge *br = to_bridge(d);
 255        return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
 256}
 257static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 258
 259static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
 260                              char *buf)
 261{
 262        struct net_bridge *br = to_bridge(d);
 263        return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
 264}
 265static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 266
 267static ssize_t show_topology_change_timer(struct device *d,
 268                                          struct device_attribute *attr,
 269                                          char *buf)
 270{
 271        struct net_bridge *br = to_bridge(d);
 272        return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
 273}
 274static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
 275                   NULL);
 276
 277static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
 278                             char *buf)
 279{
 280        struct net_bridge *br = to_bridge(d);
 281        return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
 282}
 283static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 284
 285static ssize_t show_group_addr(struct device *d,
 286                               struct device_attribute *attr, char *buf)
 287{
 288        struct net_bridge *br = to_bridge(d);
 289        return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
 290                       br->group_addr[0], br->group_addr[1],
 291                       br->group_addr[2], br->group_addr[3],
 292                       br->group_addr[4], br->group_addr[5]);
 293}
 294
 295static ssize_t store_group_addr(struct device *d,
 296                                struct device_attribute *attr,
 297                                const char *buf, size_t len)
 298{
 299        struct net_bridge *br = to_bridge(d);
 300        unsigned new_addr[6];
 301        int i;
 302
 303        if (!capable(CAP_NET_ADMIN))
 304                return -EPERM;
 305
 306        if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
 307                   &new_addr[0], &new_addr[1], &new_addr[2],
 308                   &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
 309                return -EINVAL;
 310
 311        /* Must be 01:80:c2:00:00:0X */
 312        for (i = 0; i < 5; i++)
 313                if (new_addr[i] != br_group_address[i])
 314                        return -EINVAL;
 315
 316        if (new_addr[5] & ~0xf)
 317                return -EINVAL;
 318
 319        if (new_addr[5] == 1    /* 802.3x Pause address */
 320            || new_addr[5] == 2 /* 802.3ad Slow protocols */
 321            || new_addr[5] == 3) /* 802.1X PAE address */
 322                return -EINVAL;
 323
 324        spin_lock_bh(&br->lock);
 325        for (i = 0; i < 6; i++)
 326                br->group_addr[i] = new_addr[i];
 327        spin_unlock_bh(&br->lock);
 328        return len;
 329}
 330
 331static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
 332                   show_group_addr, store_group_addr);
 333
 334static ssize_t store_flush(struct device *d,
 335                           struct device_attribute *attr,
 336                           const char *buf, size_t len)
 337{
 338        struct net_bridge *br = to_bridge(d);
 339
 340        if (!capable(CAP_NET_ADMIN))
 341                return -EPERM;
 342
 343        br_fdb_flush(br);
 344        return len;
 345}
 346static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
 347
 348static struct attribute *bridge_attrs[] = {
 349        &dev_attr_forward_delay.attr,
 350        &dev_attr_hello_time.attr,
 351        &dev_attr_max_age.attr,
 352        &dev_attr_ageing_time.attr,
 353        &dev_attr_stp_state.attr,
 354        &dev_attr_priority.attr,
 355        &dev_attr_bridge_id.attr,
 356        &dev_attr_root_id.attr,
 357        &dev_attr_root_path_cost.attr,
 358        &dev_attr_root_port.attr,
 359        &dev_attr_topology_change.attr,
 360        &dev_attr_topology_change_detected.attr,
 361        &dev_attr_hello_timer.attr,
 362        &dev_attr_tcn_timer.attr,
 363        &dev_attr_topology_change_timer.attr,
 364        &dev_attr_gc_timer.attr,
 365        &dev_attr_group_addr.attr,
 366        &dev_attr_flush.attr,
 367        NULL
 368};
 369
 370static struct attribute_group bridge_group = {
 371        .name = SYSFS_BRIDGE_ATTR,
 372        .attrs = bridge_attrs,
 373};
 374
 375/*
 376 * Export the forwarding information table as a binary file
 377 * The records are struct __fdb_entry.
 378 *
 379 * Returns the number of bytes read.
 380 */
 381static ssize_t brforward_read(struct kobject *kobj,
 382                              struct bin_attribute *bin_attr,
 383                              char *buf, loff_t off, size_t count)
 384{
 385        struct device *dev = to_dev(kobj);
 386        struct net_bridge *br = to_bridge(dev);
 387        int n;
 388
 389        /* must read whole records */
 390        if (off % sizeof(struct __fdb_entry) != 0)
 391                return -EINVAL;
 392
 393        n =  br_fdb_fillbuf(br, buf,
 394                            count / sizeof(struct __fdb_entry),
 395                            off / sizeof(struct __fdb_entry));
 396
 397        if (n > 0)
 398                n *= sizeof(struct __fdb_entry);
 399
 400        return n;
 401}
 402
 403static struct bin_attribute bridge_forward = {
 404        .attr = { .name = SYSFS_BRIDGE_FDB,
 405                  .mode = S_IRUGO, },
 406        .read = brforward_read,
 407};
 408
 409/*
 410 * Add entries in sysfs onto the existing network class device
 411 * for the bridge.
 412 *   Adds a attribute group "bridge" containing tuning parameters.
 413 *   Binary attribute containing the forward table
 414 *   Sub directory to hold links to interfaces.
 415 *
 416 * Note: the ifobj exists only to be a subdirectory
 417 *   to hold links.  The ifobj exists in same data structure
 418 *   as it's parent the bridge so reference counting works.
 419 */
 420int br_sysfs_addbr(struct net_device *dev)
 421{
 422        struct kobject *brobj = &dev->dev.kobj;
 423        struct net_bridge *br = netdev_priv(dev);
 424        int err;
 425
 426        err = sysfs_create_group(brobj, &bridge_group);
 427        if (err) {
 428                pr_info("%s: can't create group %s/%s\n",
 429                        __func__, dev->name, bridge_group.name);
 430                goto out1;
 431        }
 432
 433        err = sysfs_create_bin_file(brobj, &bridge_forward);
 434        if (err) {
 435                pr_info("%s: can't create attribute file %s/%s\n",
 436                        __func__, dev->name, bridge_forward.attr.name);
 437                goto out2;
 438        }
 439
 440        br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
 441        if (!br->ifobj) {
 442                pr_info("%s: can't add kobject (directory) %s/%s\n",
 443                        __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
 444                goto out3;
 445        }
 446        return 0;
 447 out3:
 448        sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
 449 out2:
 450        sysfs_remove_group(&dev->dev.kobj, &bridge_group);
 451 out1:
 452        return err;
 453
 454}
 455
 456void br_sysfs_delbr(struct net_device *dev)
 457{
 458        struct kobject *kobj = &dev->dev.kobj;
 459        struct net_bridge *br = netdev_priv(dev);
 460
 461        kobject_put(br->ifobj);
 462        sysfs_remove_bin_file(kobj, &bridge_forward);
 463        sysfs_remove_group(kobj, &bridge_group);
 464}
 465