br_sysfs_if.c 10.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9
/*
 *	Sysfs attributes of bridge ports
 *	Linux ethernet bridge
 *
 *	Authors:
 *	Stephen Hemminger		<shemminger@osdl.org>
 */

10
#include <linux/capability.h>
L
Linus Torvalds 已提交
11 12 13 14 15
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/if_bridge.h>
#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
16
#include <linux/sched/signal.h>
L
Linus Torvalds 已提交
17 18 19 20 21 22

#include "br_private.h"

struct brport_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct net_bridge_port *, char *);
23
	int (*store)(struct net_bridge_port *, unsigned long);
24 25 26 27 28 29 30 31 32
	int (*store_raw)(struct net_bridge_port *, char *);
};

#define BRPORT_ATTR_RAW(_name, _mode, _show, _store)			\
const struct brport_attribute brport_attr_##_name = {			\
	.attr		= {.name = __stringify(_name),			\
			   .mode = _mode },				\
	.show		= _show,					\
	.store_raw	= _store,					\
L
Linus Torvalds 已提交
33 34
};

35
#define BRPORT_ATTR(_name, _mode, _show, _store)		\
36
const struct brport_attribute brport_attr_##_name = { 	        \
L
Linus Torvalds 已提交
37
	.attr = {.name = __stringify(_name), 			\
38
		 .mode = _mode },				\
L
Linus Torvalds 已提交
39 40 41 42
	.show	= _show,					\
	.store	= _store,					\
};

43 44 45 46 47 48 49
#define BRPORT_ATTR_FLAG(_name, _mask)				\
static ssize_t show_##_name(struct net_bridge_port *p, char *buf) \
{								\
	return sprintf(buf, "%d\n", !!(p->flags & _mask));	\
}								\
static int store_##_name(struct net_bridge_port *p, unsigned long v) \
{								\
50
	return store_flag(p, v, _mask);				\
51
}								\
52
static BRPORT_ATTR(_name, 0644,					\
53 54
		   show_##_name, store_##_name)

55 56 57
static int store_flag(struct net_bridge_port *p, unsigned long v,
		      unsigned long mask)
{
58 59 60
	unsigned long flags;

	flags = p->flags;
61 62 63 64 65 66 67 68

	if (v)
		flags |= mask;
	else
		flags &= ~mask;

	if (flags != p->flags) {
		p->flags = flags;
69
		br_port_flags_change(p, mask);
70 71 72
	}
	return 0;
}
73

L
Linus Torvalds 已提交
74 75 76 77
static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->path_cost);
}
78

79
static BRPORT_ATTR(path_cost, 0644,
80
		   show_path_cost, br_stp_set_path_cost);
L
Linus Torvalds 已提交
81 82 83 84 85

static ssize_t show_priority(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->priority);
}
86

87
static BRPORT_ATTR(priority, 0644,
88
			 show_priority, br_stp_set_port_priority);
L
Linus Torvalds 已提交
89 90 91 92 93

static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
{
	return br_show_bridge_id(buf, &p->designated_root);
}
94
static BRPORT_ATTR(designated_root, 0444, show_designated_root, NULL);
L
Linus Torvalds 已提交
95 96 97 98 99

static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
{
	return br_show_bridge_id(buf, &p->designated_bridge);
}
100
static BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL);
L
Linus Torvalds 已提交
101 102 103 104 105

static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->designated_port);
}
106
static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL);
L
Linus Torvalds 已提交
107 108 109 110 111

static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->designated_cost);
}
112
static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL);
L
Linus Torvalds 已提交
113 114 115 116 117

static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "0x%x\n", p->port_id);
}
118
static BRPORT_ATTR(port_id, 0444, show_port_id, NULL);
L
Linus Torvalds 已提交
119 120 121 122 123 124

static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "0x%x\n", p->port_no);
}

125
static BRPORT_ATTR(port_no, 0444, show_port_no, NULL);
L
Linus Torvalds 已提交
126 127 128 129 130

static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->topology_change_ack);
}
131
static BRPORT_ATTR(change_ack, 0444, show_change_ack, NULL);
L
Linus Torvalds 已提交
132 133 134 135 136

static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->config_pending);
}
137
static BRPORT_ATTR(config_pending, 0444, show_config_pending, NULL);
L
Linus Torvalds 已提交
138 139 140 141 142

static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->state);
}
143
static BRPORT_ATTR(state, 0444, show_port_state, NULL);
L
Linus Torvalds 已提交
144 145 146 147 148 149

static ssize_t show_message_age_timer(struct net_bridge_port *p,
					    char *buf)
{
	return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
}
150
static BRPORT_ATTR(message_age_timer, 0444, show_message_age_timer, NULL);
L
Linus Torvalds 已提交
151 152 153 154 155 156

static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
					    char *buf)
{
	return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
}
157
static BRPORT_ATTR(forward_delay_timer, 0444, show_forward_delay_timer, NULL);
L
Linus Torvalds 已提交
158 159 160 161 162 163

static ssize_t show_hold_timer(struct net_bridge_port *p,
					    char *buf)
{
	return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
}
164
static BRPORT_ATTR(hold_timer, 0444, show_hold_timer, NULL);
L
Linus Torvalds 已提交
165

166
static int store_flush(struct net_bridge_port *p, unsigned long v)
167
{
168
	br_fdb_delete_by_port(p->br, p, 0, 0); // Don't delete local entry
169 170
	return 0;
}
171
static BRPORT_ATTR(flush, 0200, NULL, store_flush);
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186
static ssize_t show_group_fwd_mask(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%#x\n", p->group_fwd_mask);
}

static int store_group_fwd_mask(struct net_bridge_port *p,
				unsigned long v)
{
	if (v & BR_GROUPFWD_MACPAUSE)
		return -EINVAL;
	p->group_fwd_mask = v;

	return 0;
}
187
static BRPORT_ATTR(group_fwd_mask, 0644, show_group_fwd_mask,
188 189
		   store_group_fwd_mask);

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
static ssize_t show_backup_port(struct net_bridge_port *p, char *buf)
{
	struct net_bridge_port *backup_p;
	int ret = 0;

	rcu_read_lock();
	backup_p = rcu_dereference(p->backup_port);
	if (backup_p)
		ret = sprintf(buf, "%s\n", backup_p->dev->name);
	rcu_read_unlock();

	return ret;
}

static int store_backup_port(struct net_bridge_port *p, char *buf)
{
	struct net_device *backup_dev = NULL;
	char *nl = strchr(buf, '\n');

	if (nl)
		*nl = '\0';

	if (strlen(buf) > 0) {
		backup_dev = __dev_get_by_name(dev_net(p->dev), buf);
		if (!backup_dev)
			return -ENOENT;
	}

	return nbp_backup_change(p, backup_dev);
}
static BRPORT_ATTR_RAW(backup_port, 0644, show_backup_port, store_backup_port);

222
BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
223
BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
S
stephen hemminger 已提交
224
BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
225
BRPORT_ATTR_FLAG(learning, BR_LEARNING);
226
BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
227
BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
228
BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
229
BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
230
BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
231
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
232
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
233

234 235 236 237 238 239
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->multicast_router);
}

240
static int store_multicast_router(struct net_bridge_port *p,
241 242 243 244
				      unsigned long v)
{
	return br_multicast_set_port_router(p, v);
}
245
static BRPORT_ATTR(multicast_router, 0644, show_multicast_router,
246
		   store_multicast_router);
247

248
BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
F
Felix Fietkau 已提交
249
BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
250 251
#endif

252
static const struct brport_attribute *brport_attrs[] = {
L
Linus Torvalds 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266
	&brport_attr_path_cost,
	&brport_attr_priority,
	&brport_attr_port_id,
	&brport_attr_port_no,
	&brport_attr_designated_root,
	&brport_attr_designated_bridge,
	&brport_attr_designated_port,
	&brport_attr_designated_cost,
	&brport_attr_state,
	&brport_attr_change_ack,
	&brport_attr_config_pending,
	&brport_attr_message_age_timer,
	&brport_attr_forward_delay_timer,
	&brport_attr_hold_timer,
267
	&brport_attr_flush,
268
	&brport_attr_hairpin_mode,
269
	&brport_attr_bpdu_guard,
S
stephen hemminger 已提交
270
	&brport_attr_root_block,
271
	&brport_attr_learning,
272
	&brport_attr_unicast_flood,
273 274
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
	&brport_attr_multicast_router,
275
	&brport_attr_multicast_fast_leave,
F
Felix Fietkau 已提交
276
	&brport_attr_multicast_to_unicast,
277
#endif
278
	&brport_attr_proxyarp,
279
	&brport_attr_proxyarp_wifi,
280
	&brport_attr_multicast_flood,
281
	&brport_attr_broadcast_flood,
282
	&brport_attr_group_fwd_mask,
283
	&brport_attr_neigh_suppress,
284
	&brport_attr_isolated,
285
	&brport_attr_backup_port,
L
Linus Torvalds 已提交
286 287 288 289 290
	NULL
};

#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)

291 292
static ssize_t brport_show(struct kobject *kobj,
			   struct attribute *attr, char *buf)
L
Linus Torvalds 已提交
293
{
294
	struct brport_attribute *brport_attr = to_brport_attr(attr);
295
	struct net_bridge_port *p = kobj_to_brport(kobj);
L
Linus Torvalds 已提交
296

297 298 299
	if (!brport_attr->show)
		return -EINVAL;

L
Linus Torvalds 已提交
300 301 302
	return brport_attr->show(p, buf);
}

303 304 305
static ssize_t brport_store(struct kobject *kobj,
			    struct attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
306
{
307
	struct brport_attribute *brport_attr = to_brport_attr(attr);
308
	struct net_bridge_port *p = kobj_to_brport(kobj);
L
Linus Torvalds 已提交
309 310
	ssize_t ret = -EINVAL;
	unsigned long val;
311
	char *endp;
L
Linus Torvalds 已提交
312

313
	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
L
Linus Torvalds 已提交
314 315
		return -EPERM;

316 317 318 319 320 321 322 323 324 325
	if (!rtnl_trylock())
		return restart_syscall();

	if (brport_attr->store_raw) {
		char *buf_copy;

		buf_copy = kstrndup(buf, count, GFP_KERNEL);
		if (!buf_copy) {
			ret = -ENOMEM;
			goto out_unlock;
L
Linus Torvalds 已提交
326
		}
327 328 329 330 331 332 333 334 335 336 337
		spin_lock_bh(&p->br->lock);
		ret = brport_attr->store_raw(p, buf_copy);
		spin_unlock_bh(&p->br->lock);
		kfree(buf_copy);
	} else if (brport_attr->store) {
		val = simple_strtoul(buf, &endp, 0);
		if (endp == buf)
			goto out_unlock;
		spin_lock_bh(&p->br->lock);
		ret = brport_attr->store(p, val);
		spin_unlock_bh(&p->br->lock);
L
Linus Torvalds 已提交
338
	}
339 340 341 342 343 344 345 346

	if (!ret) {
		br_ifinfo_notify(RTM_NEWLINK, NULL, p);
		ret = count;
	}
out_unlock:
	rtnl_unlock();

L
Linus Torvalds 已提交
347 348 349
	return ret;
}

350
const struct sysfs_ops brport_sysfs_ops = {
L
Linus Torvalds 已提交
351 352 353 354 355 356 357
	.show = brport_show,
	.store = brport_store,
};

/*
 * Add sysfs entries to ethernet device added to a bridge.
 * Creates a brport subdirectory with bridge attributes.
358
 * Puts symlink in bridge's brif subdirectory
L
Linus Torvalds 已提交
359 360 361 362
 */
int br_sysfs_addif(struct net_bridge_port *p)
{
	struct net_bridge *br = p->br;
363
	const struct brport_attribute **a;
L
Linus Torvalds 已提交
364 365
	int err;

366
	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
L
Linus Torvalds 已提交
367 368
				SYSFS_BRIDGE_PORT_LINK);
	if (err)
369
		return err;
L
Linus Torvalds 已提交
370 371 372 373

	for (a = brport_attrs; *a; ++a) {
		err = sysfs_create_file(&p->kobj, &((*a)->attr));
		if (err)
374
			return err;
L
Linus Torvalds 已提交
375 376
	}

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
	strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
	return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
}

/* Rename bridge's brif symlink */
int br_sysfs_renameif(struct net_bridge_port *p)
{
	struct net_bridge *br = p->br;
	int err;

	/* If a rename fails, the rollback will cause another
	 * rename call with the existing name.
	 */
	if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
		return 0;

	err = sysfs_rename_link(br->ifobj, &p->kobj,
				p->sysfs_name, p->dev->name);
	if (err)
		netdev_notice(br->dev, "unable to rename link %s to %s",
			      p->sysfs_name, p->dev->name);
	else
		strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);

L
Linus Torvalds 已提交
401 402
	return err;
}