br_sysfs_if.c 10.5 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

#include "br_private.h"

20 21 22 23
/* IMPORTANT: new bridge port options must be added with netlink support only
 *            please do not add new sysfs entries
 */

L
Linus Torvalds 已提交
24 25 26
struct brport_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct net_bridge_port *, char *);
27
	int (*store)(struct net_bridge_port *, unsigned long);
28 29 30 31 32 33 34 35 36
	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 已提交
37 38
};

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

47 48 49 50 51 52 53
#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) \
{								\
54
	return store_flag(p, v, _mask);				\
55
}								\
56
static BRPORT_ATTR(_name, 0644,					\
57 58
		   show_##_name, store_##_name)

59 60 61
static int store_flag(struct net_bridge_port *p, unsigned long v,
		      unsigned long mask)
{
62 63
	unsigned long flags = p->flags;
	int err;
64 65 66 67 68 69 70

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

	if (flags != p->flags) {
71 72 73 74
		err = br_switchdev_set_port_flag(p, flags, mask);
		if (err)
			return err;

75
		p->flags = flags;
76
		br_port_flags_change(p, mask);
77 78 79
	}
	return 0;
}
80

L
Linus Torvalds 已提交
81 82 83 84
static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "%d\n", p->path_cost);
}
85

86
static BRPORT_ATTR(path_cost, 0644,
87
		   show_path_cost, br_stp_set_path_cost);
L
Linus Torvalds 已提交
88 89 90 91 92

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

94
static BRPORT_ATTR(priority, 0644,
95
			 show_priority, br_stp_set_port_priority);
L
Linus Torvalds 已提交
96 97 98 99 100

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

static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
{
	return br_show_bridge_id(buf, &p->designated_bridge);
}
107
static BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL);
L
Linus Torvalds 已提交
108 109 110 111 112

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

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

static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
{
	return sprintf(buf, "0x%x\n", p->port_id);
}
125
static BRPORT_ATTR(port_id, 0444, show_port_id, NULL);
L
Linus Torvalds 已提交
126 127 128 129 130 131

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

132
static BRPORT_ATTR(port_no, 0444, show_port_no, NULL);
L
Linus Torvalds 已提交
133 134 135 136 137

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

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

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

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));
}
157
static BRPORT_ATTR(message_age_timer, 0444, show_message_age_timer, NULL);
L
Linus Torvalds 已提交
158 159 160 161 162 163

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));
}
164
static BRPORT_ATTR(forward_delay_timer, 0444, show_forward_delay_timer, NULL);
L
Linus Torvalds 已提交
165 166 167 168 169 170

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

173
static int store_flush(struct net_bridge_port *p, unsigned long v)
174
{
175
	br_fdb_delete_by_port(p->br, p, 0, 0); // Don't delete local entry
176 177
	return 0;
}
178
static BRPORT_ATTR(flush, 0200, NULL, store_flush);
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193
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;
}
194
static BRPORT_ATTR(group_fwd_mask, 0644, show_group_fwd_mask,
195 196
		   store_group_fwd_mask);

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 222 223 224 225 226 227 228
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);

229
BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
230
BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
S
stephen hemminger 已提交
231
BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
232
BRPORT_ATTR_FLAG(learning, BR_LEARNING);
233
BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
234
BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
235
BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
236
BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
237
BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
238
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
239
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
240

241 242 243 244 245 246
#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);
}

247
static int store_multicast_router(struct net_bridge_port *p,
248 249 250 251
				      unsigned long v)
{
	return br_multicast_set_port_router(p, v);
}
252
static BRPORT_ATTR(multicast_router, 0644, show_multicast_router,
253
		   store_multicast_router);
254

255
BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
F
Felix Fietkau 已提交
256
BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
257 258
#endif

259
static const struct brport_attribute *brport_attrs[] = {
L
Linus Torvalds 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273
	&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,
274
	&brport_attr_flush,
275
	&brport_attr_hairpin_mode,
276
	&brport_attr_bpdu_guard,
S
stephen hemminger 已提交
277
	&brport_attr_root_block,
278
	&brport_attr_learning,
279
	&brport_attr_unicast_flood,
280 281
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
	&brport_attr_multicast_router,
282
	&brport_attr_multicast_fast_leave,
F
Felix Fietkau 已提交
283
	&brport_attr_multicast_to_unicast,
284
#endif
285
	&brport_attr_proxyarp,
286
	&brport_attr_proxyarp_wifi,
287
	&brport_attr_multicast_flood,
288
	&brport_attr_broadcast_flood,
289
	&brport_attr_group_fwd_mask,
290
	&brport_attr_neigh_suppress,
291
	&brport_attr_isolated,
292
	&brport_attr_backup_port,
L
Linus Torvalds 已提交
293 294 295 296 297
	NULL
};

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

298 299
static ssize_t brport_show(struct kobject *kobj,
			   struct attribute *attr, char *buf)
L
Linus Torvalds 已提交
300
{
301
	struct brport_attribute *brport_attr = to_brport_attr(attr);
302
	struct net_bridge_port *p = kobj_to_brport(kobj);
L
Linus Torvalds 已提交
303

304 305 306
	if (!brport_attr->show)
		return -EINVAL;

L
Linus Torvalds 已提交
307 308 309
	return brport_attr->show(p, buf);
}

310 311 312
static ssize_t brport_store(struct kobject *kobj,
			    struct attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
313
{
314
	struct brport_attribute *brport_attr = to_brport_attr(attr);
315
	struct net_bridge_port *p = kobj_to_brport(kobj);
L
Linus Torvalds 已提交
316 317
	ssize_t ret = -EINVAL;
	unsigned long val;
318
	char *endp;
L
Linus Torvalds 已提交
319

320
	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
L
Linus Torvalds 已提交
321 322
		return -EPERM;

323 324 325 326 327 328 329 330 331 332
	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 已提交
333
		}
334 335 336 337 338 339 340 341 342 343 344
		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 已提交
345
	}
346 347 348 349 350 351 352 353

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

L
Linus Torvalds 已提交
354 355 356
	return ret;
}

357
const struct sysfs_ops brport_sysfs_ops = {
L
Linus Torvalds 已提交
358 359 360 361 362 363 364
	.show = brport_show,
	.store = brport_store,
};

/*
 * Add sysfs entries to ethernet device added to a bridge.
 * Creates a brport subdirectory with bridge attributes.
365
 * Puts symlink in bridge's brif subdirectory
L
Linus Torvalds 已提交
366 367 368 369
 */
int br_sysfs_addif(struct net_bridge_port *p)
{
	struct net_bridge *br = p->br;
370
	const struct brport_attribute **a;
L
Linus Torvalds 已提交
371 372
	int err;

373
	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
L
Linus Torvalds 已提交
374 375
				SYSFS_BRIDGE_PORT_LINK);
	if (err)
376
		return err;
L
Linus Torvalds 已提交
377 378 379 380

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

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	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 已提交
408 409
	return err;
}