162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*	Sysfs attributes of bond slaves
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *      Copyright (c) 2014 Scott Feldman <sfeldma@cumulusnetworks.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/capability.h>
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/netdevice.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <net/bonding.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct slave_attribute {
1462306a36Sopenharmony_ci	struct attribute attr;
1562306a36Sopenharmony_ci	ssize_t (*show)(struct slave *, char *);
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define SLAVE_ATTR_RO(_name)					\
1962306a36Sopenharmony_ciconst struct slave_attribute slave_attr_##_name = __ATTR_RO(_name)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic ssize_t state_show(struct slave *slave, char *buf)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	switch (bond_slave_state(slave)) {
2462306a36Sopenharmony_ci	case BOND_STATE_ACTIVE:
2562306a36Sopenharmony_ci		return sysfs_emit(buf, "active\n");
2662306a36Sopenharmony_ci	case BOND_STATE_BACKUP:
2762306a36Sopenharmony_ci		return sysfs_emit(buf, "backup\n");
2862306a36Sopenharmony_ci	default:
2962306a36Sopenharmony_ci		return sysfs_emit(buf, "UNKNOWN\n");
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_cistatic SLAVE_ATTR_RO(state);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic ssize_t mii_status_show(struct slave *slave, char *buf)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", bond_slave_link_status(slave->link));
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_cistatic SLAVE_ATTR_RO(mii_status);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic ssize_t link_failure_count_show(struct slave *slave, char *buf)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", slave->link_failure_count);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_cistatic SLAVE_ATTR_RO(link_failure_count);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic ssize_t perm_hwaddr_show(struct slave *slave, char *buf)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return sysfs_emit(buf, "%*phC\n",
4962306a36Sopenharmony_ci		       slave->dev->addr_len,
5062306a36Sopenharmony_ci		       slave->perm_hwaddr);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_cistatic SLAVE_ATTR_RO(perm_hwaddr);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic ssize_t queue_id_show(struct slave *slave, char *buf)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", slave->queue_id);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_cistatic SLAVE_ATTR_RO(queue_id);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	const struct aggregator *agg;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
6562306a36Sopenharmony_ci		agg = SLAVE_AD_INFO(slave)->port.aggregator;
6662306a36Sopenharmony_ci		if (agg)
6762306a36Sopenharmony_ci			return sysfs_emit(buf, "%d\n",
6862306a36Sopenharmony_ci					  agg->aggregator_identifier);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return sysfs_emit(buf, "N/A\n");
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_cistatic SLAVE_ATTR_RO(ad_aggregator_id);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	const struct port *ad_port;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
8062306a36Sopenharmony_ci		ad_port = &SLAVE_AD_INFO(slave)->port;
8162306a36Sopenharmony_ci		if (ad_port->aggregator)
8262306a36Sopenharmony_ci			return sysfs_emit(buf, "%u\n",
8362306a36Sopenharmony_ci				       ad_port->actor_oper_port_state);
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return sysfs_emit(buf, "N/A\n");
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_cistatic SLAVE_ATTR_RO(ad_actor_oper_port_state);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	const struct port *ad_port;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
9562306a36Sopenharmony_ci		ad_port = &SLAVE_AD_INFO(slave)->port;
9662306a36Sopenharmony_ci		if (ad_port->aggregator)
9762306a36Sopenharmony_ci			return sysfs_emit(buf, "%u\n",
9862306a36Sopenharmony_ci				       ad_port->partner_oper.port_state);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return sysfs_emit(buf, "N/A\n");
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_cistatic SLAVE_ATTR_RO(ad_partner_oper_port_state);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const struct attribute *slave_attrs[] = {
10662306a36Sopenharmony_ci	&slave_attr_state.attr,
10762306a36Sopenharmony_ci	&slave_attr_mii_status.attr,
10862306a36Sopenharmony_ci	&slave_attr_link_failure_count.attr,
10962306a36Sopenharmony_ci	&slave_attr_perm_hwaddr.attr,
11062306a36Sopenharmony_ci	&slave_attr_queue_id.attr,
11162306a36Sopenharmony_ci	&slave_attr_ad_aggregator_id.attr,
11262306a36Sopenharmony_ci	&slave_attr_ad_actor_oper_port_state.attr,
11362306a36Sopenharmony_ci	&slave_attr_ad_partner_oper_port_state.attr,
11462306a36Sopenharmony_ci	NULL
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define to_slave_attr(_at) container_of(_at, struct slave_attribute, attr)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic ssize_t slave_show(struct kobject *kobj,
12062306a36Sopenharmony_ci			  struct attribute *attr, char *buf)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct slave_attribute *slave_attr = to_slave_attr(attr);
12362306a36Sopenharmony_ci	struct slave *slave = to_slave(kobj);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return slave_attr->show(slave, buf);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciconst struct sysfs_ops slave_sysfs_ops = {
12962306a36Sopenharmony_ci	.show = slave_show,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciint bond_sysfs_slave_add(struct slave *slave)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return sysfs_create_files(&slave->kobj, slave_attrs);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_civoid bond_sysfs_slave_del(struct slave *slave)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	sysfs_remove_files(&slave->kobj, slave_attrs);
14062306a36Sopenharmony_ci}
141