blob: 7db06e3f642a093a41e22bb72e339d91b854b731 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Wang Sheng-Hui15401942013-08-06 08:44:46 +08003 * Sysfs attributes of bridge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Linux ethernet bridge
5 *
6 * Authors:
7 * Stephen Hemminger <shemminger@osdl.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Randy Dunlap4fc268d2006-01-11 12:17:47 -080010#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/kernel.h>
12#include <linux/netdevice.h>
John Fastabendb3343a22012-09-18 00:01:12 +000013#include <linux/etherdevice.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/if_bridge.h>
15#include <linux/rtnetlink.h>
16#include <linux/spinlock.h>
17#include <linux/times.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010018#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20#include "br_private.h"
21
Wang Chen524ad0a2008-11-12 23:39:10 -080022#define to_bridge(cd) ((struct net_bridge *)netdev_priv(to_net_dev(cd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24/*
25 * Common code for storing bridge parameters.
26 */
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070027static ssize_t store_bridge_parm(struct device *d,
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 const char *buf, size_t len,
Stephen Hemminger8d4698f72008-09-08 13:44:40 -070029 int (*set)(struct net_bridge *, unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -070030{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070031 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 char *endp;
33 unsigned long val;
Stephen Hemminger8d4698f72008-09-08 13:44:40 -070034 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Eric W. Biedermancb990502012-11-16 03:03:08 +000036 if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 return -EPERM;
38
39 val = simple_strtoul(buf, &endp, 0);
40 if (endp == buf)
41 return -EINVAL;
42
Xin Long047831a2016-04-09 00:03:31 +080043 if (!rtnl_trylock())
44 return restart_syscall();
45
Stephen Hemminger8d4698f72008-09-08 13:44:40 -070046 err = (*set)(br, val);
Xin Long047831a2016-04-09 00:03:31 +080047 if (!err)
48 netdev_state_change(br->dev);
49 rtnl_unlock();
50
Stephen Hemminger8d4698f72008-09-08 13:44:40 -070051 return err ? err : len;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052}
53
54
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080055static ssize_t forward_delay_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070056 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070057{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070058 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
60}
61
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080062static ssize_t forward_delay_store(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070063 struct device_attribute *attr,
64 const char *buf, size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
stephen hemminger14f98f22011-04-04 14:03:33 +000066 return store_bridge_parm(d, buf, len, br_set_forward_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080068static DEVICE_ATTR_RW(forward_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080070static ssize_t hello_time_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070071 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
73 return sprintf(buf, "%lu\n",
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070074 jiffies_to_clock_t(to_bridge(d)->hello_time));
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}
76
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080077static ssize_t hello_time_store(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070078 struct device_attribute *attr, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 size_t len)
80{
stephen hemminger14f98f22011-04-04 14:03:33 +000081 return store_bridge_parm(d, buf, len, br_set_hello_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080083static DEVICE_ATTR_RW(hello_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080085static ssize_t max_age_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070086 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 return sprintf(buf, "%lu\n",
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070089 jiffies_to_clock_t(to_bridge(d)->max_age));
Linus Torvalds1da177e2005-04-16 15:20:36 -070090}
91
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080092static ssize_t max_age_store(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -070093 const char *buf, size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
stephen hemminger14f98f22011-04-04 14:03:33 +000095 return store_bridge_parm(d, buf, len, br_set_max_age);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080097static DEVICE_ATTR_RW(max_age);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -080099static ssize_t ageing_time_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700100 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700102 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
104}
105
Stephen Hemminger8d4698f72008-09-08 13:44:40 -0700106static int set_ageing_time(struct net_bridge *br, unsigned long val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
Xin Long047831a2016-04-09 00:03:31 +0800108 return br_set_ageing_time(br, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800111static ssize_t ageing_time_store(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700112 struct device_attribute *attr,
113 const char *buf, size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700115 return store_bridge_parm(d, buf, len, set_ageing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800117static DEVICE_ATTR_RW(ageing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800119static ssize_t stp_state_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700120 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700122 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return sprintf(buf, "%d\n", br->stp_enabled);
124}
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Xin Long44361562016-04-09 00:03:30 +0800127static int set_stp_state(struct net_bridge *br, unsigned long val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
Horatiu Vultur419dba8a2020-04-26 15:22:08 +0200129 return br_stp_set_enabled(br, val, NULL);
Xin Long44361562016-04-09 00:03:30 +0800130}
131
132static ssize_t stp_state_store(struct device *d,
133 struct device_attribute *attr, const char *buf,
134 size_t len)
135{
136 return store_bridge_parm(d, buf, len, set_stp_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800138static DEVICE_ATTR_RW(stp_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800140static ssize_t group_fwd_mask_show(struct device *d,
141 struct device_attribute *attr,
142 char *buf)
stephen hemminger515853c2011-10-03 18:14:46 +0000143{
144 struct net_bridge *br = to_bridge(d);
145 return sprintf(buf, "%#x\n", br->group_fwd_mask);
146}
147
Xin Long347db6b2016-04-09 00:03:29 +0800148static int set_group_fwd_mask(struct net_bridge *br, unsigned long val)
149{
150 if (val & BR_GROUPFWD_RESTRICTED)
151 return -EINVAL;
152
153 br->group_fwd_mask = val;
154
155 return 0;
156}
stephen hemminger515853c2011-10-03 18:14:46 +0000157
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800158static ssize_t group_fwd_mask_store(struct device *d,
159 struct device_attribute *attr,
160 const char *buf,
161 size_t len)
stephen hemminger515853c2011-10-03 18:14:46 +0000162{
Xin Long347db6b2016-04-09 00:03:29 +0800163 return store_bridge_parm(d, buf, len, set_group_fwd_mask);
stephen hemminger515853c2011-10-03 18:14:46 +0000164}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800165static DEVICE_ATTR_RW(group_fwd_mask);
stephen hemminger515853c2011-10-03 18:14:46 +0000166
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800167static ssize_t priority_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700168 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700170 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 return sprintf(buf, "%d\n",
172 (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
173}
174
Stephen Hemminger8d4698f72008-09-08 13:44:40 -0700175static int set_priority(struct net_bridge *br, unsigned long val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
177 br_stp_set_bridge_priority(br, (u16) val);
Stephen Hemminger8d4698f72008-09-08 13:44:40 -0700178 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800181static ssize_t priority_store(struct device *d, struct device_attribute *attr,
182 const char *buf, size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700184 return store_bridge_parm(d, buf, len, set_priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800186static DEVICE_ATTR_RW(priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800188static ssize_t root_id_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700189 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700191 return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800193static DEVICE_ATTR_RO(root_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800195static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700196 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700198 return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800200static DEVICE_ATTR_RO(bridge_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800202static ssize_t root_port_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700203 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700205 return sprintf(buf, "%d\n", to_bridge(d)->root_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800207static DEVICE_ATTR_RO(root_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800209static ssize_t root_path_cost_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700210 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700212 return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800214static DEVICE_ATTR_RO(root_path_cost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800216static ssize_t topology_change_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700217 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700219 return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800221static DEVICE_ATTR_RO(topology_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800223static ssize_t topology_change_detected_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700224 struct device_attribute *attr,
225 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700227 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 return sprintf(buf, "%d\n", br->topology_change_detected);
229}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800230static DEVICE_ATTR_RO(topology_change_detected);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800232static ssize_t hello_timer_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700233 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700235 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
237}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800238static DEVICE_ATTR_RO(hello_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800240static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700241 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700243 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
245}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800246static DEVICE_ATTR_RO(tcn_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800248static ssize_t topology_change_timer_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700249 struct device_attribute *attr,
250 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700252 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
254}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800255static DEVICE_ATTR_RO(topology_change_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800257static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700258 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700260 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovf7cdee82017-02-04 18:05:07 +0100261 return sprintf(buf, "%ld\n", br_timer_value(&br->gc_work.timer));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800263static DEVICE_ATTR_RO(gc_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800265static ssize_t group_addr_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700266 struct device_attribute *attr, char *buf)
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800267{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700268 struct net_bridge *br = to_bridge(d);
Andy Shevchenko223b2292017-12-19 20:10:53 +0200269 return sprintf(buf, "%pM\n", br->group_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800270}
271
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800272static ssize_t group_addr_store(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700273 struct device_attribute *attr,
274 const char *buf, size_t len)
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800275{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700276 struct net_bridge *br = to_bridge(d);
Ben Hutchings4197f242012-11-01 09:10:04 +0000277 u8 new_addr[6];
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800278
Eric W. Biedermancb990502012-11-16 03:03:08 +0000279 if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800280 return -EPERM;
281
Andy Shevchenko223b2292017-12-19 20:10:53 +0200282 if (!mac_pton(buf, new_addr))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800283 return -EINVAL;
284
Ben Hutchings46acc462012-11-01 09:11:11 +0000285 if (!is_link_local_ether_addr(new_addr))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800286 return -EINVAL;
287
Joe Perchesf64f9e72009-11-29 16:55:45 -0800288 if (new_addr[5] == 1 || /* 802.3x Pause address */
289 new_addr[5] == 2 || /* 802.3ad Slow protocols */
290 new_addr[5] == 3) /* 802.1X PAE address */
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800291 return -EINVAL;
292
Toshiaki Makita204177f2014-06-10 20:59:25 +0900293 if (!rtnl_trylock())
294 return restart_syscall();
295
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800296 spin_lock_bh(&br->lock);
Andy Shevchenko223b2292017-12-19 20:10:53 +0200297 ether_addr_copy(br->group_addr, new_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800298 spin_unlock_bh(&br->lock);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900299
Nikolay Aleksandrovbe3664a2018-09-26 17:01:02 +0300300 br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900301 br_recalculate_fwd_mask(br);
Xin Long047831a2016-04-09 00:03:31 +0800302 netdev_state_change(br->dev);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900303
304 rtnl_unlock();
305
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800306 return len;
307}
308
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800309static DEVICE_ATTR_RW(group_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800310
Xin Long14f31bb2016-04-09 00:03:28 +0800311static int set_flush(struct net_bridge *br, unsigned long val)
312{
313 br_fdb_flush(br);
314 return 0;
315}
316
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800317static ssize_t flush_store(struct device *d,
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700318 struct device_attribute *attr,
319 const char *buf, size_t len)
320{
Xin Long14f31bb2016-04-09 00:03:28 +0800321 return store_bridge_parm(d, buf, len, set_flush);
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700322}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800323static DEVICE_ATTR_WO(flush);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800324
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200325static ssize_t no_linklocal_learn_show(struct device *d,
326 struct device_attribute *attr,
327 char *buf)
328{
329 struct net_bridge *br = to_bridge(d);
330 return sprintf(buf, "%d\n", br_boolopt_get(br, BR_BOOLOPT_NO_LL_LEARN));
331}
332
333static int set_no_linklocal_learn(struct net_bridge *br, unsigned long val)
334{
335 return br_boolopt_toggle(br, BR_BOOLOPT_NO_LL_LEARN, !!val, NULL);
336}
337
338static ssize_t no_linklocal_learn_store(struct device *d,
339 struct device_attribute *attr,
340 const char *buf, size_t len)
341{
342 return store_bridge_parm(d, buf, len, set_no_linklocal_learn);
343}
344static DEVICE_ATTR_RW(no_linklocal_learn);
345
Herbert Xu0909e112010-02-27 19:41:49 +0000346#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800347static ssize_t multicast_router_show(struct device *d,
Herbert Xu0909e112010-02-27 19:41:49 +0000348 struct device_attribute *attr, char *buf)
349{
350 struct net_bridge *br = to_bridge(d);
351 return sprintf(buf, "%d\n", br->multicast_router);
352}
353
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800354static ssize_t multicast_router_store(struct device *d,
Herbert Xu0909e112010-02-27 19:41:49 +0000355 struct device_attribute *attr,
356 const char *buf, size_t len)
357{
358 return store_bridge_parm(d, buf, len, br_multicast_set_router);
359}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800360static DEVICE_ATTR_RW(multicast_router);
Herbert Xu561f1102010-02-27 19:41:50 +0000361
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800362static ssize_t multicast_snooping_show(struct device *d,
Herbert Xu561f1102010-02-27 19:41:50 +0000363 struct device_attribute *attr,
364 char *buf)
365{
366 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov13cefad2018-09-26 17:01:03 +0300367 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED));
Herbert Xu561f1102010-02-27 19:41:50 +0000368}
369
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800370static ssize_t multicast_snooping_store(struct device *d,
Herbert Xu561f1102010-02-27 19:41:50 +0000371 struct device_attribute *attr,
372 const char *buf, size_t len)
373{
374 return store_bridge_parm(d, buf, len, br_multicast_toggle);
375}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800376static DEVICE_ATTR_RW(multicast_snooping);
Herbert Xub1951672010-02-27 19:41:51 +0000377
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800378static ssize_t multicast_query_use_ifaddr_show(struct device *d,
379 struct device_attribute *attr,
380 char *buf)
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000381{
382 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300383 return sprintf(buf, "%d\n",
384 br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR));
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000385}
386
387static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val)
388{
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300389 br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val);
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000390 return 0;
391}
392
393static ssize_t
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800394multicast_query_use_ifaddr_store(struct device *d,
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000395 struct device_attribute *attr,
396 const char *buf, size_t len)
397{
398 return store_bridge_parm(d, buf, len, set_query_use_ifaddr);
399}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800400static DEVICE_ATTR_RW(multicast_query_use_ifaddr);
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000401
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800402static ssize_t multicast_querier_show(struct device *d,
Herbert Xuc5c23262012-04-13 02:37:42 +0000403 struct device_attribute *attr,
404 char *buf)
405{
406 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300407 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_QUERIER));
Herbert Xuc5c23262012-04-13 02:37:42 +0000408}
409
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800410static ssize_t multicast_querier_store(struct device *d,
Herbert Xuc5c23262012-04-13 02:37:42 +0000411 struct device_attribute *attr,
412 const char *buf, size_t len)
413{
414 return store_bridge_parm(d, buf, len, br_multicast_set_querier);
415}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800416static DEVICE_ATTR_RW(multicast_querier);
Herbert Xuc5c23262012-04-13 02:37:42 +0000417
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800418static ssize_t hash_elasticity_show(struct device *d,
Herbert Xub1951672010-02-27 19:41:51 +0000419 struct device_attribute *attr, char *buf)
420{
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +0200421 return sprintf(buf, "%u\n", RHT_ELASTICITY);
Herbert Xub1951672010-02-27 19:41:51 +0000422}
423
424static int set_elasticity(struct net_bridge *br, unsigned long val)
425{
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +0200426 br_warn(br, "the hash_elasticity option has been deprecated and is always %u\n",
427 RHT_ELASTICITY);
Herbert Xub1951672010-02-27 19:41:51 +0000428 return 0;
429}
430
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800431static ssize_t hash_elasticity_store(struct device *d,
Herbert Xub1951672010-02-27 19:41:51 +0000432 struct device_attribute *attr,
433 const char *buf, size_t len)
434{
435 return store_bridge_parm(d, buf, len, set_elasticity);
436}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800437static DEVICE_ATTR_RW(hash_elasticity);
Herbert Xub1951672010-02-27 19:41:51 +0000438
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800439static ssize_t hash_max_show(struct device *d, struct device_attribute *attr,
Herbert Xub1951672010-02-27 19:41:51 +0000440 char *buf)
441{
442 struct net_bridge *br = to_bridge(d);
443 return sprintf(buf, "%u\n", br->hash_max);
444}
445
Nikolay Aleksandrov19e3a9c2018-12-05 15:14:24 +0200446static int set_hash_max(struct net_bridge *br, unsigned long val)
447{
448 br->hash_max = val;
449 return 0;
450}
451
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800452static ssize_t hash_max_store(struct device *d, struct device_attribute *attr,
Herbert Xub1951672010-02-27 19:41:51 +0000453 const char *buf, size_t len)
454{
Nikolay Aleksandrov19e3a9c2018-12-05 15:14:24 +0200455 return store_bridge_parm(d, buf, len, set_hash_max);
Herbert Xub1951672010-02-27 19:41:51 +0000456}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800457static DEVICE_ATTR_RW(hash_max);
Herbert Xud902eee2010-02-27 19:41:52 +0000458
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +0100459static ssize_t multicast_igmp_version_show(struct device *d,
460 struct device_attribute *attr,
461 char *buf)
462{
463 struct net_bridge *br = to_bridge(d);
464
465 return sprintf(buf, "%u\n", br->multicast_igmp_version);
466}
467
468static ssize_t multicast_igmp_version_store(struct device *d,
469 struct device_attribute *attr,
470 const char *buf, size_t len)
471{
472 return store_bridge_parm(d, buf, len, br_multicast_set_igmp_version);
473}
474static DEVICE_ATTR_RW(multicast_igmp_version);
475
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800476static ssize_t multicast_last_member_count_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000477 struct device_attribute *attr,
478 char *buf)
479{
480 struct net_bridge *br = to_bridge(d);
481 return sprintf(buf, "%u\n", br->multicast_last_member_count);
482}
483
484static int set_last_member_count(struct net_bridge *br, unsigned long val)
485{
486 br->multicast_last_member_count = val;
487 return 0;
488}
489
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800490static ssize_t multicast_last_member_count_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000491 struct device_attribute *attr,
492 const char *buf, size_t len)
493{
494 return store_bridge_parm(d, buf, len, set_last_member_count);
495}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800496static DEVICE_ATTR_RW(multicast_last_member_count);
Herbert Xud902eee2010-02-27 19:41:52 +0000497
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800498static ssize_t multicast_startup_query_count_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000499 struct device *d, struct device_attribute *attr, char *buf)
500{
501 struct net_bridge *br = to_bridge(d);
502 return sprintf(buf, "%u\n", br->multicast_startup_query_count);
503}
504
505static int set_startup_query_count(struct net_bridge *br, unsigned long val)
506{
507 br->multicast_startup_query_count = val;
508 return 0;
509}
510
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800511static ssize_t multicast_startup_query_count_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000512 struct device *d, struct device_attribute *attr, const char *buf,
513 size_t len)
514{
515 return store_bridge_parm(d, buf, len, set_startup_query_count);
516}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800517static DEVICE_ATTR_RW(multicast_startup_query_count);
Herbert Xud902eee2010-02-27 19:41:52 +0000518
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800519static ssize_t multicast_last_member_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000520 struct device *d, struct device_attribute *attr, char *buf)
521{
522 struct net_bridge *br = to_bridge(d);
523 return sprintf(buf, "%lu\n",
524 jiffies_to_clock_t(br->multicast_last_member_interval));
525}
526
527static int set_last_member_interval(struct net_bridge *br, unsigned long val)
528{
529 br->multicast_last_member_interval = clock_t_to_jiffies(val);
530 return 0;
531}
532
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800533static ssize_t multicast_last_member_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000534 struct device *d, struct device_attribute *attr, const char *buf,
535 size_t len)
536{
537 return store_bridge_parm(d, buf, len, set_last_member_interval);
538}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800539static DEVICE_ATTR_RW(multicast_last_member_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000540
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800541static ssize_t multicast_membership_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000542 struct device *d, struct device_attribute *attr, char *buf)
543{
544 struct net_bridge *br = to_bridge(d);
545 return sprintf(buf, "%lu\n",
546 jiffies_to_clock_t(br->multicast_membership_interval));
547}
548
549static int set_membership_interval(struct net_bridge *br, unsigned long val)
550{
551 br->multicast_membership_interval = clock_t_to_jiffies(val);
552 return 0;
553}
554
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800555static ssize_t multicast_membership_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000556 struct device *d, struct device_attribute *attr, const char *buf,
557 size_t len)
558{
559 return store_bridge_parm(d, buf, len, set_membership_interval);
560}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800561static DEVICE_ATTR_RW(multicast_membership_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000562
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800563static ssize_t multicast_querier_interval_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000564 struct device_attribute *attr,
565 char *buf)
566{
567 struct net_bridge *br = to_bridge(d);
568 return sprintf(buf, "%lu\n",
569 jiffies_to_clock_t(br->multicast_querier_interval));
570}
571
572static int set_querier_interval(struct net_bridge *br, unsigned long val)
573{
574 br->multicast_querier_interval = clock_t_to_jiffies(val);
575 return 0;
576}
577
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800578static ssize_t multicast_querier_interval_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000579 struct device_attribute *attr,
580 const char *buf, size_t len)
581{
582 return store_bridge_parm(d, buf, len, set_querier_interval);
583}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800584static DEVICE_ATTR_RW(multicast_querier_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000585
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800586static ssize_t multicast_query_interval_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000587 struct device_attribute *attr,
588 char *buf)
589{
590 struct net_bridge *br = to_bridge(d);
591 return sprintf(buf, "%lu\n",
592 jiffies_to_clock_t(br->multicast_query_interval));
593}
594
595static int set_query_interval(struct net_bridge *br, unsigned long val)
596{
597 br->multicast_query_interval = clock_t_to_jiffies(val);
598 return 0;
599}
600
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800601static ssize_t multicast_query_interval_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000602 struct device_attribute *attr,
603 const char *buf, size_t len)
604{
605 return store_bridge_parm(d, buf, len, set_query_interval);
606}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800607static DEVICE_ATTR_RW(multicast_query_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000608
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800609static ssize_t multicast_query_response_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000610 struct device *d, struct device_attribute *attr, char *buf)
611{
612 struct net_bridge *br = to_bridge(d);
613 return sprintf(
614 buf, "%lu\n",
615 jiffies_to_clock_t(br->multicast_query_response_interval));
616}
617
618static int set_query_response_interval(struct net_bridge *br, unsigned long val)
619{
620 br->multicast_query_response_interval = clock_t_to_jiffies(val);
621 return 0;
622}
623
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800624static ssize_t multicast_query_response_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000625 struct device *d, struct device_attribute *attr, const char *buf,
626 size_t len)
627{
628 return store_bridge_parm(d, buf, len, set_query_response_interval);
629}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800630static DEVICE_ATTR_RW(multicast_query_response_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000631
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800632static ssize_t multicast_startup_query_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000633 struct device *d, struct device_attribute *attr, char *buf)
634{
635 struct net_bridge *br = to_bridge(d);
636 return sprintf(
637 buf, "%lu\n",
638 jiffies_to_clock_t(br->multicast_startup_query_interval));
639}
640
641static int set_startup_query_interval(struct net_bridge *br, unsigned long val)
642{
643 br->multicast_startup_query_interval = clock_t_to_jiffies(val);
644 return 0;
645}
646
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800647static ssize_t multicast_startup_query_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000648 struct device *d, struct device_attribute *attr, const char *buf,
649 size_t len)
650{
651 return store_bridge_parm(d, buf, len, set_startup_query_interval);
652}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800653static DEVICE_ATTR_RW(multicast_startup_query_interval);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200654
655static ssize_t multicast_stats_enabled_show(struct device *d,
656 struct device_attribute *attr,
657 char *buf)
658{
659 struct net_bridge *br = to_bridge(d);
660
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300661 return sprintf(buf, "%d\n",
662 br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED));
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200663}
664
665static int set_stats_enabled(struct net_bridge *br, unsigned long val)
666{
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300667 br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200668 return 0;
669}
670
671static ssize_t multicast_stats_enabled_store(struct device *d,
672 struct device_attribute *attr,
673 const char *buf,
674 size_t len)
675{
676 return store_bridge_parm(d, buf, len, set_stats_enabled);
677}
678static DEVICE_ATTR_RW(multicast_stats_enabled);
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +0100679
680#if IS_ENABLED(CONFIG_IPV6)
681static ssize_t multicast_mld_version_show(struct device *d,
682 struct device_attribute *attr,
683 char *buf)
684{
685 struct net_bridge *br = to_bridge(d);
686
687 return sprintf(buf, "%u\n", br->multicast_mld_version);
688}
689
690static ssize_t multicast_mld_version_store(struct device *d,
691 struct device_attribute *attr,
692 const char *buf, size_t len)
693{
694 return store_bridge_parm(d, buf, len, br_multicast_set_mld_version);
695}
696static DEVICE_ATTR_RW(multicast_mld_version);
697#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000698#endif
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200699#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800700static ssize_t nf_call_iptables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200701 struct device *d, struct device_attribute *attr, char *buf)
702{
703 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300704 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200705}
706
707static int set_nf_call_iptables(struct net_bridge *br, unsigned long val)
708{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300709 br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200710 return 0;
711}
712
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800713static ssize_t nf_call_iptables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200714 struct device *d, struct device_attribute *attr, const char *buf,
715 size_t len)
716{
717 return store_bridge_parm(d, buf, len, set_nf_call_iptables);
718}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800719static DEVICE_ATTR_RW(nf_call_iptables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200720
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800721static ssize_t nf_call_ip6tables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200722 struct device *d, struct device_attribute *attr, char *buf)
723{
724 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300725 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200726}
727
728static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val)
729{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300730 br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200731 return 0;
732}
733
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800734static ssize_t nf_call_ip6tables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200735 struct device *d, struct device_attribute *attr, const char *buf,
736 size_t len)
737{
738 return store_bridge_parm(d, buf, len, set_nf_call_ip6tables);
739}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800740static DEVICE_ATTR_RW(nf_call_ip6tables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200741
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800742static ssize_t nf_call_arptables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200743 struct device *d, struct device_attribute *attr, char *buf)
744{
745 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300746 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200747}
748
749static int set_nf_call_arptables(struct net_bridge *br, unsigned long val)
750{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300751 br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200752 return 0;
753}
754
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800755static ssize_t nf_call_arptables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200756 struct device *d, struct device_attribute *attr, const char *buf,
757 size_t len)
758{
759 return store_bridge_parm(d, buf, len, set_nf_call_arptables);
760}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800761static DEVICE_ATTR_RW(nf_call_arptables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200762#endif
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000763#ifdef CONFIG_BRIDGE_VLAN_FILTERING
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800764static ssize_t vlan_filtering_show(struct device *d,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000765 struct device_attribute *attr,
766 char *buf)
767{
768 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovae757672018-09-26 17:01:00 +0300769 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED));
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000770}
771
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800772static ssize_t vlan_filtering_store(struct device *d,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000773 struct device_attribute *attr,
774 const char *buf, size_t len)
775{
776 return store_bridge_parm(d, buf, len, br_vlan_filter_toggle);
777}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800778static DEVICE_ATTR_RW(vlan_filtering);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900779
780static ssize_t vlan_protocol_show(struct device *d,
781 struct device_attribute *attr,
782 char *buf)
783{
784 struct net_bridge *br = to_bridge(d);
785 return sprintf(buf, "%#06x\n", ntohs(br->vlan_proto));
786}
787
788static ssize_t vlan_protocol_store(struct device *d,
789 struct device_attribute *attr,
790 const char *buf, size_t len)
791{
792 return store_bridge_parm(d, buf, len, br_vlan_set_proto);
793}
794static DEVICE_ATTR_RW(vlan_protocol);
Vlad Yasevich96a20d92014-10-03 11:29:16 -0400795
796static ssize_t default_pvid_show(struct device *d,
797 struct device_attribute *attr,
798 char *buf)
799{
800 struct net_bridge *br = to_bridge(d);
801 return sprintf(buf, "%d\n", br->default_pvid);
802}
803
804static ssize_t default_pvid_store(struct device *d,
805 struct device_attribute *attr,
806 const char *buf, size_t len)
807{
808 return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid);
809}
810static DEVICE_ATTR_RW(default_pvid);
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200811
812static ssize_t vlan_stats_enabled_show(struct device *d,
813 struct device_attribute *attr,
814 char *buf)
815{
816 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovae757672018-09-26 17:01:00 +0300817 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED));
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200818}
819
820static ssize_t vlan_stats_enabled_store(struct device *d,
821 struct device_attribute *attr,
822 const char *buf, size_t len)
823{
824 return store_bridge_parm(d, buf, len, br_vlan_set_stats);
825}
826static DEVICE_ATTR_RW(vlan_stats_enabled);
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +0300827
828static ssize_t vlan_stats_per_port_show(struct device *d,
829 struct device_attribute *attr,
830 char *buf)
831{
832 struct net_bridge *br = to_bridge(d);
833 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT));
834}
835
836static ssize_t vlan_stats_per_port_store(struct device *d,
837 struct device_attribute *attr,
838 const char *buf, size_t len)
839{
840 return store_bridge_parm(d, buf, len, br_vlan_set_stats_per_port);
841}
842static DEVICE_ATTR_RW(vlan_stats_per_port);
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000843#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845static struct attribute *bridge_attrs[] = {
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700846 &dev_attr_forward_delay.attr,
847 &dev_attr_hello_time.attr,
848 &dev_attr_max_age.attr,
849 &dev_attr_ageing_time.attr,
850 &dev_attr_stp_state.attr,
stephen hemminger515853c2011-10-03 18:14:46 +0000851 &dev_attr_group_fwd_mask.attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700852 &dev_attr_priority.attr,
853 &dev_attr_bridge_id.attr,
854 &dev_attr_root_id.attr,
855 &dev_attr_root_path_cost.attr,
856 &dev_attr_root_port.attr,
857 &dev_attr_topology_change.attr,
858 &dev_attr_topology_change_detected.attr,
859 &dev_attr_hello_timer.attr,
860 &dev_attr_tcn_timer.attr,
861 &dev_attr_topology_change_timer.attr,
862 &dev_attr_gc_timer.attr,
863 &dev_attr_group_addr.attr,
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700864 &dev_attr_flush.attr,
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200865 &dev_attr_no_linklocal_learn.attr,
Herbert Xu0909e112010-02-27 19:41:49 +0000866#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
867 &dev_attr_multicast_router.attr,
Herbert Xu561f1102010-02-27 19:41:50 +0000868 &dev_attr_multicast_snooping.attr,
Herbert Xuc5c23262012-04-13 02:37:42 +0000869 &dev_attr_multicast_querier.attr,
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000870 &dev_attr_multicast_query_use_ifaddr.attr,
Herbert Xub1951672010-02-27 19:41:51 +0000871 &dev_attr_hash_elasticity.attr,
872 &dev_attr_hash_max.attr,
Herbert Xud902eee2010-02-27 19:41:52 +0000873 &dev_attr_multicast_last_member_count.attr,
874 &dev_attr_multicast_startup_query_count.attr,
875 &dev_attr_multicast_last_member_interval.attr,
876 &dev_attr_multicast_membership_interval.attr,
877 &dev_attr_multicast_querier_interval.attr,
878 &dev_attr_multicast_query_interval.attr,
879 &dev_attr_multicast_query_response_interval.attr,
880 &dev_attr_multicast_startup_query_interval.attr,
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200881 &dev_attr_multicast_stats_enabled.attr,
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +0100882 &dev_attr_multicast_igmp_version.attr,
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +0100883#if IS_ENABLED(CONFIG_IPV6)
884 &dev_attr_multicast_mld_version.attr,
885#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000886#endif
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200887#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
Patrick McHardy4df53d82010-07-02 09:32:57 +0200888 &dev_attr_nf_call_iptables.attr,
889 &dev_attr_nf_call_ip6tables.attr,
890 &dev_attr_nf_call_arptables.attr,
891#endif
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000892#ifdef CONFIG_BRIDGE_VLAN_FILTERING
893 &dev_attr_vlan_filtering.attr,
Toshiaki Makita204177f2014-06-10 20:59:25 +0900894 &dev_attr_vlan_protocol.attr,
Vlad Yasevich96a20d92014-10-03 11:29:16 -0400895 &dev_attr_default_pvid.attr,
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200896 &dev_attr_vlan_stats_enabled.attr,
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +0300897 &dev_attr_vlan_stats_per_port.attr,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000898#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 NULL
900};
901
Arvind Yadavcddbb792017-06-29 16:39:38 +0530902static const struct attribute_group bridge_group = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 .name = SYSFS_BRIDGE_ATTR,
904 .attrs = bridge_attrs,
905};
906
907/*
908 * Export the forwarding information table as a binary file
909 * The records are struct __fdb_entry.
910 *
911 * Returns the number of bytes read.
912 */
Chris Wright2c3c8be2010-05-12 18:28:57 -0700913static ssize_t brforward_read(struct file *filp, struct kobject *kobj,
Zhang Rui91a69022007-06-09 13:57:22 +0800914 struct bin_attribute *bin_attr,
915 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Geliang Tangaeb7ed12015-12-23 20:42:21 +0800917 struct device *dev = kobj_to_dev(kobj);
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700918 struct net_bridge *br = to_bridge(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 int n;
920
921 /* must read whole records */
922 if (off % sizeof(struct __fdb_entry) != 0)
923 return -EINVAL;
924
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900925 n = br_fdb_fillbuf(br, buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 count / sizeof(struct __fdb_entry),
927 off / sizeof(struct __fdb_entry));
928
929 if (n > 0)
930 n *= sizeof(struct __fdb_entry);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return n;
933}
934
935static struct bin_attribute bridge_forward = {
936 .attr = { .name = SYSFS_BRIDGE_FDB,
Joe Perchesd6444062018-03-23 15:54:38 -0700937 .mode = 0444, },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 .read = brforward_read,
939};
940
941/*
942 * Add entries in sysfs onto the existing network class device
943 * for the bridge.
944 * Adds a attribute group "bridge" containing tuning parameters.
945 * Binary attribute containing the forward table
946 * Sub directory to hold links to interfaces.
947 *
948 * Note: the ifobj exists only to be a subdirectory
949 * to hold links. The ifobj exists in same data structure
950 * as it's parent the bridge so reference counting works.
951 */
952int br_sysfs_addbr(struct net_device *dev)
953{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700954 struct kobject *brobj = &dev->dev.kobj;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 struct net_bridge *br = netdev_priv(dev);
956 int err;
957
958 err = sysfs_create_group(brobj, &bridge_group);
959 if (err) {
960 pr_info("%s: can't create group %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800961 __func__, dev->name, bridge_group.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 goto out1;
963 }
964
965 err = sysfs_create_bin_file(brobj, &bridge_forward);
966 if (err) {
Randy Dunlap1842c4b2006-10-25 23:07:37 -0700967 pr_info("%s: can't create attribute file %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800968 __func__, dev->name, bridge_forward.attr.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 goto out2;
970 }
971
Greg Kroah-Hartman43b98c42007-12-17 15:54:39 -0400972 br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
973 if (!br->ifobj) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 pr_info("%s: can't add kobject (directory) %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800975 __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
Pan Bianb5958962016-12-03 19:33:23 +0800976 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 goto out3;
978 }
979 return 0;
980 out3:
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700981 sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 out2:
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700983 sysfs_remove_group(&dev->dev.kobj, &bridge_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 out1:
985 return err;
986
987}
988
989void br_sysfs_delbr(struct net_device *dev)
990{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700991 struct kobject *kobj = &dev->dev.kobj;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 struct net_bridge *br = netdev_priv(dev);
993
Greg Kroah-Hartman78a2d902007-12-20 08:13:05 -0800994 kobject_put(br->ifobj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 sysfs_remove_bin_file(kobj, &bridge_forward);
996 sysfs_remove_group(kobj, &bridge_group);
997}