blob: 9ab0f00b10811fb339b39e8e1b075953a0a35249 [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{
Stephen Hemminger17120882007-08-14 13:21:34 -0700129 br_stp_set_enabled(br, val);
Stephen Hemminger17120882007-08-14 13:21:34 -0700130
Xin Long44361562016-04-09 00:03:30 +0800131 return 0;
132}
133
134static ssize_t stp_state_store(struct device *d,
135 struct device_attribute *attr, const char *buf,
136 size_t len)
137{
138 return store_bridge_parm(d, buf, len, set_stp_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800140static DEVICE_ATTR_RW(stp_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800142static ssize_t group_fwd_mask_show(struct device *d,
143 struct device_attribute *attr,
144 char *buf)
stephen hemminger515853c2011-10-03 18:14:46 +0000145{
146 struct net_bridge *br = to_bridge(d);
147 return sprintf(buf, "%#x\n", br->group_fwd_mask);
148}
149
Xin Long347db6b2016-04-09 00:03:29 +0800150static int set_group_fwd_mask(struct net_bridge *br, unsigned long val)
151{
152 if (val & BR_GROUPFWD_RESTRICTED)
153 return -EINVAL;
154
155 br->group_fwd_mask = val;
156
157 return 0;
158}
stephen hemminger515853c2011-10-03 18:14:46 +0000159
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800160static ssize_t group_fwd_mask_store(struct device *d,
161 struct device_attribute *attr,
162 const char *buf,
163 size_t len)
stephen hemminger515853c2011-10-03 18:14:46 +0000164{
Xin Long347db6b2016-04-09 00:03:29 +0800165 return store_bridge_parm(d, buf, len, set_group_fwd_mask);
stephen hemminger515853c2011-10-03 18:14:46 +0000166}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800167static DEVICE_ATTR_RW(group_fwd_mask);
stephen hemminger515853c2011-10-03 18:14:46 +0000168
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800169static ssize_t priority_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700170 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700172 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return sprintf(buf, "%d\n",
174 (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
175}
176
Stephen Hemminger8d4698f72008-09-08 13:44:40 -0700177static int set_priority(struct net_bridge *br, unsigned long val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
179 br_stp_set_bridge_priority(br, (u16) val);
Stephen Hemminger8d4698f72008-09-08 13:44:40 -0700180 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800183static ssize_t priority_store(struct device *d, struct device_attribute *attr,
184 const char *buf, size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700186 return store_bridge_parm(d, buf, len, set_priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800188static DEVICE_ATTR_RW(priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800190static ssize_t root_id_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700191 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700193 return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800195static DEVICE_ATTR_RO(root_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800197static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700198 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700200 return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800202static DEVICE_ATTR_RO(bridge_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800204static ssize_t root_port_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700205 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700207 return sprintf(buf, "%d\n", to_bridge(d)->root_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800209static DEVICE_ATTR_RO(root_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800211static ssize_t root_path_cost_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700212 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700214 return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800216static DEVICE_ATTR_RO(root_path_cost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800218static ssize_t topology_change_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700219 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700221 return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800223static DEVICE_ATTR_RO(topology_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800225static ssize_t topology_change_detected_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700226 struct device_attribute *attr,
227 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700229 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 return sprintf(buf, "%d\n", br->topology_change_detected);
231}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800232static DEVICE_ATTR_RO(topology_change_detected);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800234static ssize_t hello_timer_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700235 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700237 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
239}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800240static DEVICE_ATTR_RO(hello_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800242static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700243 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700245 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
247}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800248static DEVICE_ATTR_RO(tcn_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800250static ssize_t topology_change_timer_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700251 struct device_attribute *attr,
252 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700254 struct net_bridge *br = to_bridge(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
256}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800257static DEVICE_ATTR_RO(topology_change_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800259static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700260 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700262 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovf7cdee82017-02-04 18:05:07 +0100263 return sprintf(buf, "%ld\n", br_timer_value(&br->gc_work.timer));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800265static DEVICE_ATTR_RO(gc_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800267static ssize_t group_addr_show(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700268 struct device_attribute *attr, char *buf)
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800269{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700270 struct net_bridge *br = to_bridge(d);
Andy Shevchenko223b2292017-12-19 20:10:53 +0200271 return sprintf(buf, "%pM\n", br->group_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800272}
273
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800274static ssize_t group_addr_store(struct device *d,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700275 struct device_attribute *attr,
276 const char *buf, size_t len)
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800277{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700278 struct net_bridge *br = to_bridge(d);
Ben Hutchings4197f242012-11-01 09:10:04 +0000279 u8 new_addr[6];
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800280
Eric W. Biedermancb990502012-11-16 03:03:08 +0000281 if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800282 return -EPERM;
283
Andy Shevchenko223b2292017-12-19 20:10:53 +0200284 if (!mac_pton(buf, new_addr))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800285 return -EINVAL;
286
Ben Hutchings46acc462012-11-01 09:11:11 +0000287 if (!is_link_local_ether_addr(new_addr))
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800288 return -EINVAL;
289
Joe Perchesf64f9e72009-11-29 16:55:45 -0800290 if (new_addr[5] == 1 || /* 802.3x Pause address */
291 new_addr[5] == 2 || /* 802.3ad Slow protocols */
292 new_addr[5] == 3) /* 802.1X PAE address */
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800293 return -EINVAL;
294
Toshiaki Makita204177f2014-06-10 20:59:25 +0900295 if (!rtnl_trylock())
296 return restart_syscall();
297
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800298 spin_lock_bh(&br->lock);
Andy Shevchenko223b2292017-12-19 20:10:53 +0200299 ether_addr_copy(br->group_addr, new_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800300 spin_unlock_bh(&br->lock);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900301
Nikolay Aleksandrovbe3664a2018-09-26 17:01:02 +0300302 br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900303 br_recalculate_fwd_mask(br);
Xin Long047831a2016-04-09 00:03:31 +0800304 netdev_state_change(br->dev);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900305
306 rtnl_unlock();
307
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800308 return len;
309}
310
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800311static DEVICE_ATTR_RW(group_addr);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800312
Xin Long14f31bb2016-04-09 00:03:28 +0800313static int set_flush(struct net_bridge *br, unsigned long val)
314{
315 br_fdb_flush(br);
316 return 0;
317}
318
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800319static ssize_t flush_store(struct device *d,
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700320 struct device_attribute *attr,
321 const char *buf, size_t len)
322{
Xin Long14f31bb2016-04-09 00:03:28 +0800323 return store_bridge_parm(d, buf, len, set_flush);
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700324}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800325static DEVICE_ATTR_WO(flush);
Stephen Hemmingerfda93d92006-03-20 22:59:21 -0800326
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200327static ssize_t no_linklocal_learn_show(struct device *d,
328 struct device_attribute *attr,
329 char *buf)
330{
331 struct net_bridge *br = to_bridge(d);
332 return sprintf(buf, "%d\n", br_boolopt_get(br, BR_BOOLOPT_NO_LL_LEARN));
333}
334
335static int set_no_linklocal_learn(struct net_bridge *br, unsigned long val)
336{
337 return br_boolopt_toggle(br, BR_BOOLOPT_NO_LL_LEARN, !!val, NULL);
338}
339
340static ssize_t no_linklocal_learn_store(struct device *d,
341 struct device_attribute *attr,
342 const char *buf, size_t len)
343{
344 return store_bridge_parm(d, buf, len, set_no_linklocal_learn);
345}
346static DEVICE_ATTR_RW(no_linklocal_learn);
347
Herbert Xu0909e112010-02-27 19:41:49 +0000348#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800349static ssize_t multicast_router_show(struct device *d,
Herbert Xu0909e112010-02-27 19:41:49 +0000350 struct device_attribute *attr, char *buf)
351{
352 struct net_bridge *br = to_bridge(d);
353 return sprintf(buf, "%d\n", br->multicast_router);
354}
355
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800356static ssize_t multicast_router_store(struct device *d,
Herbert Xu0909e112010-02-27 19:41:49 +0000357 struct device_attribute *attr,
358 const char *buf, size_t len)
359{
360 return store_bridge_parm(d, buf, len, br_multicast_set_router);
361}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800362static DEVICE_ATTR_RW(multicast_router);
Herbert Xu561f1102010-02-27 19:41:50 +0000363
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800364static ssize_t multicast_snooping_show(struct device *d,
Herbert Xu561f1102010-02-27 19:41:50 +0000365 struct device_attribute *attr,
366 char *buf)
367{
368 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov13cefad2018-09-26 17:01:03 +0300369 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED));
Herbert Xu561f1102010-02-27 19:41:50 +0000370}
371
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800372static ssize_t multicast_snooping_store(struct device *d,
Herbert Xu561f1102010-02-27 19:41:50 +0000373 struct device_attribute *attr,
374 const char *buf, size_t len)
375{
376 return store_bridge_parm(d, buf, len, br_multicast_toggle);
377}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800378static DEVICE_ATTR_RW(multicast_snooping);
Herbert Xub1951672010-02-27 19:41:51 +0000379
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800380static ssize_t multicast_query_use_ifaddr_show(struct device *d,
381 struct device_attribute *attr,
382 char *buf)
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000383{
384 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300385 return sprintf(buf, "%d\n",
386 br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR));
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000387}
388
389static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val)
390{
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300391 br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val);
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000392 return 0;
393}
394
395static ssize_t
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800396multicast_query_use_ifaddr_store(struct device *d,
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000397 struct device_attribute *attr,
398 const char *buf, size_t len)
399{
400 return store_bridge_parm(d, buf, len, set_query_use_ifaddr);
401}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800402static DEVICE_ATTR_RW(multicast_query_use_ifaddr);
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000403
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800404static ssize_t multicast_querier_show(struct device *d,
Herbert Xuc5c23262012-04-13 02:37:42 +0000405 struct device_attribute *attr,
406 char *buf)
407{
408 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300409 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_QUERIER));
Herbert Xuc5c23262012-04-13 02:37:42 +0000410}
411
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800412static ssize_t multicast_querier_store(struct device *d,
Herbert Xuc5c23262012-04-13 02:37:42 +0000413 struct device_attribute *attr,
414 const char *buf, size_t len)
415{
416 return store_bridge_parm(d, buf, len, br_multicast_set_querier);
417}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800418static DEVICE_ATTR_RW(multicast_querier);
Herbert Xuc5c23262012-04-13 02:37:42 +0000419
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800420static ssize_t hash_elasticity_show(struct device *d,
Herbert Xub1951672010-02-27 19:41:51 +0000421 struct device_attribute *attr, char *buf)
422{
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +0200423 return sprintf(buf, "%u\n", RHT_ELASTICITY);
Herbert Xub1951672010-02-27 19:41:51 +0000424}
425
426static int set_elasticity(struct net_bridge *br, unsigned long val)
427{
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +0200428 br_warn(br, "the hash_elasticity option has been deprecated and is always %u\n",
429 RHT_ELASTICITY);
Herbert Xub1951672010-02-27 19:41:51 +0000430 return 0;
431}
432
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800433static ssize_t hash_elasticity_store(struct device *d,
Herbert Xub1951672010-02-27 19:41:51 +0000434 struct device_attribute *attr,
435 const char *buf, size_t len)
436{
437 return store_bridge_parm(d, buf, len, set_elasticity);
438}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800439static DEVICE_ATTR_RW(hash_elasticity);
Herbert Xub1951672010-02-27 19:41:51 +0000440
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800441static ssize_t hash_max_show(struct device *d, struct device_attribute *attr,
Herbert Xub1951672010-02-27 19:41:51 +0000442 char *buf)
443{
444 struct net_bridge *br = to_bridge(d);
445 return sprintf(buf, "%u\n", br->hash_max);
446}
447
Nikolay Aleksandrov19e3a9c2018-12-05 15:14:24 +0200448static int set_hash_max(struct net_bridge *br, unsigned long val)
449{
450 br->hash_max = val;
451 return 0;
452}
453
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800454static ssize_t hash_max_store(struct device *d, struct device_attribute *attr,
Herbert Xub1951672010-02-27 19:41:51 +0000455 const char *buf, size_t len)
456{
Nikolay Aleksandrov19e3a9c2018-12-05 15:14:24 +0200457 return store_bridge_parm(d, buf, len, set_hash_max);
Herbert Xub1951672010-02-27 19:41:51 +0000458}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800459static DEVICE_ATTR_RW(hash_max);
Herbert Xud902eee2010-02-27 19:41:52 +0000460
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +0100461static ssize_t multicast_igmp_version_show(struct device *d,
462 struct device_attribute *attr,
463 char *buf)
464{
465 struct net_bridge *br = to_bridge(d);
466
467 return sprintf(buf, "%u\n", br->multicast_igmp_version);
468}
469
470static ssize_t multicast_igmp_version_store(struct device *d,
471 struct device_attribute *attr,
472 const char *buf, size_t len)
473{
474 return store_bridge_parm(d, buf, len, br_multicast_set_igmp_version);
475}
476static DEVICE_ATTR_RW(multicast_igmp_version);
477
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800478static ssize_t multicast_last_member_count_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000479 struct device_attribute *attr,
480 char *buf)
481{
482 struct net_bridge *br = to_bridge(d);
483 return sprintf(buf, "%u\n", br->multicast_last_member_count);
484}
485
486static int set_last_member_count(struct net_bridge *br, unsigned long val)
487{
488 br->multicast_last_member_count = val;
489 return 0;
490}
491
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800492static ssize_t multicast_last_member_count_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000493 struct device_attribute *attr,
494 const char *buf, size_t len)
495{
496 return store_bridge_parm(d, buf, len, set_last_member_count);
497}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800498static DEVICE_ATTR_RW(multicast_last_member_count);
Herbert Xud902eee2010-02-27 19:41:52 +0000499
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800500static ssize_t multicast_startup_query_count_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000501 struct device *d, struct device_attribute *attr, char *buf)
502{
503 struct net_bridge *br = to_bridge(d);
504 return sprintf(buf, "%u\n", br->multicast_startup_query_count);
505}
506
507static int set_startup_query_count(struct net_bridge *br, unsigned long val)
508{
509 br->multicast_startup_query_count = val;
510 return 0;
511}
512
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800513static ssize_t multicast_startup_query_count_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000514 struct device *d, struct device_attribute *attr, const char *buf,
515 size_t len)
516{
517 return store_bridge_parm(d, buf, len, set_startup_query_count);
518}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800519static DEVICE_ATTR_RW(multicast_startup_query_count);
Herbert Xud902eee2010-02-27 19:41:52 +0000520
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800521static ssize_t multicast_last_member_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000522 struct device *d, struct device_attribute *attr, char *buf)
523{
524 struct net_bridge *br = to_bridge(d);
525 return sprintf(buf, "%lu\n",
526 jiffies_to_clock_t(br->multicast_last_member_interval));
527}
528
529static int set_last_member_interval(struct net_bridge *br, unsigned long val)
530{
531 br->multicast_last_member_interval = clock_t_to_jiffies(val);
532 return 0;
533}
534
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800535static ssize_t multicast_last_member_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000536 struct device *d, struct device_attribute *attr, const char *buf,
537 size_t len)
538{
539 return store_bridge_parm(d, buf, len, set_last_member_interval);
540}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800541static DEVICE_ATTR_RW(multicast_last_member_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000542
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800543static ssize_t multicast_membership_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000544 struct device *d, struct device_attribute *attr, char *buf)
545{
546 struct net_bridge *br = to_bridge(d);
547 return sprintf(buf, "%lu\n",
548 jiffies_to_clock_t(br->multicast_membership_interval));
549}
550
551static int set_membership_interval(struct net_bridge *br, unsigned long val)
552{
553 br->multicast_membership_interval = clock_t_to_jiffies(val);
554 return 0;
555}
556
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800557static ssize_t multicast_membership_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000558 struct device *d, struct device_attribute *attr, const char *buf,
559 size_t len)
560{
561 return store_bridge_parm(d, buf, len, set_membership_interval);
562}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800563static DEVICE_ATTR_RW(multicast_membership_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000564
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800565static ssize_t multicast_querier_interval_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000566 struct device_attribute *attr,
567 char *buf)
568{
569 struct net_bridge *br = to_bridge(d);
570 return sprintf(buf, "%lu\n",
571 jiffies_to_clock_t(br->multicast_querier_interval));
572}
573
574static int set_querier_interval(struct net_bridge *br, unsigned long val)
575{
576 br->multicast_querier_interval = clock_t_to_jiffies(val);
577 return 0;
578}
579
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800580static ssize_t multicast_querier_interval_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000581 struct device_attribute *attr,
582 const char *buf, size_t len)
583{
584 return store_bridge_parm(d, buf, len, set_querier_interval);
585}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800586static DEVICE_ATTR_RW(multicast_querier_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000587
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800588static ssize_t multicast_query_interval_show(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000589 struct device_attribute *attr,
590 char *buf)
591{
592 struct net_bridge *br = to_bridge(d);
593 return sprintf(buf, "%lu\n",
594 jiffies_to_clock_t(br->multicast_query_interval));
595}
596
597static int set_query_interval(struct net_bridge *br, unsigned long val)
598{
599 br->multicast_query_interval = clock_t_to_jiffies(val);
600 return 0;
601}
602
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800603static ssize_t multicast_query_interval_store(struct device *d,
Herbert Xud902eee2010-02-27 19:41:52 +0000604 struct device_attribute *attr,
605 const char *buf, size_t len)
606{
607 return store_bridge_parm(d, buf, len, set_query_interval);
608}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800609static DEVICE_ATTR_RW(multicast_query_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000610
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800611static ssize_t multicast_query_response_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000612 struct device *d, struct device_attribute *attr, char *buf)
613{
614 struct net_bridge *br = to_bridge(d);
615 return sprintf(
616 buf, "%lu\n",
617 jiffies_to_clock_t(br->multicast_query_response_interval));
618}
619
620static int set_query_response_interval(struct net_bridge *br, unsigned long val)
621{
622 br->multicast_query_response_interval = clock_t_to_jiffies(val);
623 return 0;
624}
625
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800626static ssize_t multicast_query_response_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000627 struct device *d, struct device_attribute *attr, const char *buf,
628 size_t len)
629{
630 return store_bridge_parm(d, buf, len, set_query_response_interval);
631}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800632static DEVICE_ATTR_RW(multicast_query_response_interval);
Herbert Xud902eee2010-02-27 19:41:52 +0000633
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800634static ssize_t multicast_startup_query_interval_show(
Herbert Xud902eee2010-02-27 19:41:52 +0000635 struct device *d, struct device_attribute *attr, char *buf)
636{
637 struct net_bridge *br = to_bridge(d);
638 return sprintf(
639 buf, "%lu\n",
640 jiffies_to_clock_t(br->multicast_startup_query_interval));
641}
642
643static int set_startup_query_interval(struct net_bridge *br, unsigned long val)
644{
645 br->multicast_startup_query_interval = clock_t_to_jiffies(val);
646 return 0;
647}
648
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800649static ssize_t multicast_startup_query_interval_store(
Herbert Xud902eee2010-02-27 19:41:52 +0000650 struct device *d, struct device_attribute *attr, const char *buf,
651 size_t len)
652{
653 return store_bridge_parm(d, buf, len, set_startup_query_interval);
654}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800655static DEVICE_ATTR_RW(multicast_startup_query_interval);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200656
657static ssize_t multicast_stats_enabled_show(struct device *d,
658 struct device_attribute *attr,
659 char *buf)
660{
661 struct net_bridge *br = to_bridge(d);
662
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300663 return sprintf(buf, "%d\n",
664 br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED));
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200665}
666
667static int set_stats_enabled(struct net_bridge *br, unsigned long val)
668{
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +0300669 br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200670 return 0;
671}
672
673static ssize_t multicast_stats_enabled_store(struct device *d,
674 struct device_attribute *attr,
675 const char *buf,
676 size_t len)
677{
678 return store_bridge_parm(d, buf, len, set_stats_enabled);
679}
680static DEVICE_ATTR_RW(multicast_stats_enabled);
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +0100681
682#if IS_ENABLED(CONFIG_IPV6)
683static ssize_t multicast_mld_version_show(struct device *d,
684 struct device_attribute *attr,
685 char *buf)
686{
687 struct net_bridge *br = to_bridge(d);
688
689 return sprintf(buf, "%u\n", br->multicast_mld_version);
690}
691
692static ssize_t multicast_mld_version_store(struct device *d,
693 struct device_attribute *attr,
694 const char *buf, size_t len)
695{
696 return store_bridge_parm(d, buf, len, br_multicast_set_mld_version);
697}
698static DEVICE_ATTR_RW(multicast_mld_version);
699#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000700#endif
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200701#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800702static ssize_t nf_call_iptables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200703 struct device *d, struct device_attribute *attr, char *buf)
704{
705 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300706 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200707}
708
709static int set_nf_call_iptables(struct net_bridge *br, unsigned long val)
710{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300711 br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200712 return 0;
713}
714
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800715static ssize_t nf_call_iptables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200716 struct device *d, struct device_attribute *attr, const char *buf,
717 size_t len)
718{
719 return store_bridge_parm(d, buf, len, set_nf_call_iptables);
720}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800721static DEVICE_ATTR_RW(nf_call_iptables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200722
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800723static ssize_t nf_call_ip6tables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200724 struct device *d, struct device_attribute *attr, char *buf)
725{
726 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300727 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200728}
729
730static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val)
731{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300732 br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200733 return 0;
734}
735
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800736static ssize_t nf_call_ip6tables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200737 struct device *d, struct device_attribute *attr, const char *buf,
738 size_t len)
739{
740 return store_bridge_parm(d, buf, len, set_nf_call_ip6tables);
741}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800742static DEVICE_ATTR_RW(nf_call_ip6tables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200743
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800744static ssize_t nf_call_arptables_show(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200745 struct device *d, struct device_attribute *attr, char *buf)
746{
747 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300748 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES));
Patrick McHardy4df53d82010-07-02 09:32:57 +0200749}
750
751static int set_nf_call_arptables(struct net_bridge *br, unsigned long val)
752{
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +0300753 br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200754 return 0;
755}
756
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800757static ssize_t nf_call_arptables_store(
Patrick McHardy4df53d82010-07-02 09:32:57 +0200758 struct device *d, struct device_attribute *attr, const char *buf,
759 size_t len)
760{
761 return store_bridge_parm(d, buf, len, set_nf_call_arptables);
762}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800763static DEVICE_ATTR_RW(nf_call_arptables);
Patrick McHardy4df53d82010-07-02 09:32:57 +0200764#endif
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000765#ifdef CONFIG_BRIDGE_VLAN_FILTERING
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800766static ssize_t vlan_filtering_show(struct device *d,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000767 struct device_attribute *attr,
768 char *buf)
769{
770 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovae757672018-09-26 17:01:00 +0300771 return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED));
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000772}
773
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800774static ssize_t vlan_filtering_store(struct device *d,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000775 struct device_attribute *attr,
776 const char *buf, size_t len)
777{
778 return store_bridge_parm(d, buf, len, br_vlan_filter_toggle);
779}
sfeldma@cumulusnetworks.comfbf26712014-01-06 11:00:44 -0800780static DEVICE_ATTR_RW(vlan_filtering);
Toshiaki Makita204177f2014-06-10 20:59:25 +0900781
782static ssize_t vlan_protocol_show(struct device *d,
783 struct device_attribute *attr,
784 char *buf)
785{
786 struct net_bridge *br = to_bridge(d);
787 return sprintf(buf, "%#06x\n", ntohs(br->vlan_proto));
788}
789
790static ssize_t vlan_protocol_store(struct device *d,
791 struct device_attribute *attr,
792 const char *buf, size_t len)
793{
794 return store_bridge_parm(d, buf, len, br_vlan_set_proto);
795}
796static DEVICE_ATTR_RW(vlan_protocol);
Vlad Yasevich96a20d92014-10-03 11:29:16 -0400797
798static ssize_t default_pvid_show(struct device *d,
799 struct device_attribute *attr,
800 char *buf)
801{
802 struct net_bridge *br = to_bridge(d);
803 return sprintf(buf, "%d\n", br->default_pvid);
804}
805
806static ssize_t default_pvid_store(struct device *d,
807 struct device_attribute *attr,
808 const char *buf, size_t len)
809{
810 return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid);
811}
812static DEVICE_ATTR_RW(default_pvid);
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200813
814static ssize_t vlan_stats_enabled_show(struct device *d,
815 struct device_attribute *attr,
816 char *buf)
817{
818 struct net_bridge *br = to_bridge(d);
Nikolay Aleksandrovae757672018-09-26 17:01:00 +0300819 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED));
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200820}
821
822static ssize_t vlan_stats_enabled_store(struct device *d,
823 struct device_attribute *attr,
824 const char *buf, size_t len)
825{
826 return store_bridge_parm(d, buf, len, br_vlan_set_stats);
827}
828static DEVICE_ATTR_RW(vlan_stats_enabled);
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +0300829
830static ssize_t vlan_stats_per_port_show(struct device *d,
831 struct device_attribute *attr,
832 char *buf)
833{
834 struct net_bridge *br = to_bridge(d);
835 return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT));
836}
837
838static ssize_t vlan_stats_per_port_store(struct device *d,
839 struct device_attribute *attr,
840 const char *buf, size_t len)
841{
842 return store_bridge_parm(d, buf, len, br_vlan_set_stats_per_port);
843}
844static DEVICE_ATTR_RW(vlan_stats_per_port);
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000845#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847static struct attribute *bridge_attrs[] = {
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700848 &dev_attr_forward_delay.attr,
849 &dev_attr_hello_time.attr,
850 &dev_attr_max_age.attr,
851 &dev_attr_ageing_time.attr,
852 &dev_attr_stp_state.attr,
stephen hemminger515853c2011-10-03 18:14:46 +0000853 &dev_attr_group_fwd_mask.attr,
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700854 &dev_attr_priority.attr,
855 &dev_attr_bridge_id.attr,
856 &dev_attr_root_id.attr,
857 &dev_attr_root_path_cost.attr,
858 &dev_attr_root_port.attr,
859 &dev_attr_topology_change.attr,
860 &dev_attr_topology_change_detected.attr,
861 &dev_attr_hello_timer.attr,
862 &dev_attr_tcn_timer.attr,
863 &dev_attr_topology_change_timer.attr,
864 &dev_attr_gc_timer.attr,
865 &dev_attr_group_addr.attr,
Stephen Hemminger9cf63742007-04-09 12:57:54 -0700866 &dev_attr_flush.attr,
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200867 &dev_attr_no_linklocal_learn.attr,
Herbert Xu0909e112010-02-27 19:41:49 +0000868#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
869 &dev_attr_multicast_router.attr,
Herbert Xu561f1102010-02-27 19:41:50 +0000870 &dev_attr_multicast_snooping.attr,
Herbert Xuc5c23262012-04-13 02:37:42 +0000871 &dev_attr_multicast_querier.attr,
Cong Wang1c8ad5b2013-05-21 21:52:54 +0000872 &dev_attr_multicast_query_use_ifaddr.attr,
Herbert Xub1951672010-02-27 19:41:51 +0000873 &dev_attr_hash_elasticity.attr,
874 &dev_attr_hash_max.attr,
Herbert Xud902eee2010-02-27 19:41:52 +0000875 &dev_attr_multicast_last_member_count.attr,
876 &dev_attr_multicast_startup_query_count.attr,
877 &dev_attr_multicast_last_member_interval.attr,
878 &dev_attr_multicast_membership_interval.attr,
879 &dev_attr_multicast_querier_interval.attr,
880 &dev_attr_multicast_query_interval.attr,
881 &dev_attr_multicast_query_response_interval.attr,
882 &dev_attr_multicast_startup_query_interval.attr,
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +0200883 &dev_attr_multicast_stats_enabled.attr,
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +0100884 &dev_attr_multicast_igmp_version.attr,
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +0100885#if IS_ENABLED(CONFIG_IPV6)
886 &dev_attr_multicast_mld_version.attr,
887#endif
Herbert Xu0909e112010-02-27 19:41:49 +0000888#endif
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200889#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
Patrick McHardy4df53d82010-07-02 09:32:57 +0200890 &dev_attr_nf_call_iptables.attr,
891 &dev_attr_nf_call_ip6tables.attr,
892 &dev_attr_nf_call_arptables.attr,
893#endif
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000894#ifdef CONFIG_BRIDGE_VLAN_FILTERING
895 &dev_attr_vlan_filtering.attr,
Toshiaki Makita204177f2014-06-10 20:59:25 +0900896 &dev_attr_vlan_protocol.attr,
Vlad Yasevich96a20d92014-10-03 11:29:16 -0400897 &dev_attr_default_pvid.attr,
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +0200898 &dev_attr_vlan_stats_enabled.attr,
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +0300899 &dev_attr_vlan_stats_per_port.attr,
Vlad Yasevich243a2e62013-02-13 12:00:09 +0000900#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 NULL
902};
903
Arvind Yadavcddbb792017-06-29 16:39:38 +0530904static const struct attribute_group bridge_group = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 .name = SYSFS_BRIDGE_ATTR,
906 .attrs = bridge_attrs,
907};
908
909/*
910 * Export the forwarding information table as a binary file
911 * The records are struct __fdb_entry.
912 *
913 * Returns the number of bytes read.
914 */
Chris Wright2c3c8be2010-05-12 18:28:57 -0700915static ssize_t brforward_read(struct file *filp, struct kobject *kobj,
Zhang Rui91a69022007-06-09 13:57:22 +0800916 struct bin_attribute *bin_attr,
917 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Geliang Tangaeb7ed12015-12-23 20:42:21 +0800919 struct device *dev = kobj_to_dev(kobj);
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700920 struct net_bridge *br = to_bridge(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 int n;
922
923 /* must read whole records */
924 if (off % sizeof(struct __fdb_entry) != 0)
925 return -EINVAL;
926
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900927 n = br_fdb_fillbuf(br, buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 count / sizeof(struct __fdb_entry),
929 off / sizeof(struct __fdb_entry));
930
931 if (n > 0)
932 n *= sizeof(struct __fdb_entry);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return n;
935}
936
937static struct bin_attribute bridge_forward = {
938 .attr = { .name = SYSFS_BRIDGE_FDB,
Joe Perchesd6444062018-03-23 15:54:38 -0700939 .mode = 0444, },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 .read = brforward_read,
941};
942
943/*
944 * Add entries in sysfs onto the existing network class device
945 * for the bridge.
946 * Adds a attribute group "bridge" containing tuning parameters.
947 * Binary attribute containing the forward table
948 * Sub directory to hold links to interfaces.
949 *
950 * Note: the ifobj exists only to be a subdirectory
951 * to hold links. The ifobj exists in same data structure
952 * as it's parent the bridge so reference counting works.
953 */
954int br_sysfs_addbr(struct net_device *dev)
955{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700956 struct kobject *brobj = &dev->dev.kobj;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 struct net_bridge *br = netdev_priv(dev);
958 int err;
959
960 err = sysfs_create_group(brobj, &bridge_group);
961 if (err) {
962 pr_info("%s: can't create group %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800963 __func__, dev->name, bridge_group.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 goto out1;
965 }
966
967 err = sysfs_create_bin_file(brobj, &bridge_forward);
968 if (err) {
Randy Dunlap1842c4b2006-10-25 23:07:37 -0700969 pr_info("%s: can't create attribute file %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800970 __func__, dev->name, bridge_forward.attr.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 goto out2;
972 }
973
Greg Kroah-Hartman43b98c42007-12-17 15:54:39 -0400974 br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
975 if (!br->ifobj) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 pr_info("%s: can't add kobject (directory) %s/%s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800977 __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
Pan Bianb5958962016-12-03 19:33:23 +0800978 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 goto out3;
980 }
981 return 0;
982 out3:
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700983 sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 out2:
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700985 sysfs_remove_group(&dev->dev.kobj, &bridge_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 out1:
987 return err;
988
989}
990
991void br_sysfs_delbr(struct net_device *dev)
992{
Greg Kroah-Hartman43cb76d2002-04-09 12:14:34 -0700993 struct kobject *kobj = &dev->dev.kobj;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 struct net_bridge *br = netdev_priv(dev);
995
Greg Kroah-Hartman78a2d902007-12-20 08:13:05 -0800996 kobject_put(br->ifobj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 sysfs_remove_bin_file(kobj, &bridge_forward);
998 sysfs_remove_group(kobj, &bridge_group);
999}