br_sysfs_if.c 10.6 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
	struct netlink_ext_ack extack = {0};
63 64
	unsigned long flags = p->flags;
	int err;
65 66 67 68 69 70 71

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

	if (flags != p->flags) {
72 73 74
		err = br_switchdev_set_port_flag(p, flags, mask, &extack);
		if (err) {
			netdev_err(p->dev, "%s\n", extack._msg);
75
			return err;
76
		}
77

78
		p->flags = flags;
79
		br_port_flags_change(p, mask);
80 81 82
	}
	return 0;
}
83

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

89
static BRPORT_ATTR(path_cost, 0644,
90
		   show_path_cost, br_stp_set_path_cost);
L
Linus Torvalds 已提交
91 92 93 94 95

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

97
static BRPORT_ATTR(priority, 0644,
98
			 show_priority, br_stp_set_port_priority);
L
Linus Torvalds 已提交
99 100 101 102 103

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

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

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

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

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

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

135
static BRPORT_ATTR(port_no, 0444, show_port_no, NULL);
L
Linus Torvalds 已提交
136 137 138 139 140

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

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

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

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

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

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

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

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

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 229 230 231
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);

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

244 245 246 247 248 249
#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);
}

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

258
BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
F
Felix Fietkau 已提交
259
BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
260 261
#endif

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

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

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

307 308 309
	if (!brport_attr->show)
		return -EINVAL;

L
Linus Torvalds 已提交
310 311 312
	return brport_attr->show(p, buf);
}

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

323
	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
L
Linus Torvalds 已提交
324 325
		return -EPERM;

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

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

L
Linus Torvalds 已提交
357 358 359
	return ret;
}

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

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

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

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

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