162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <net/genetlink.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <uapi/linux/mrp_bridge.h> 662306a36Sopenharmony_ci#include "br_private.h" 762306a36Sopenharmony_ci#include "br_private_mrp.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cistatic const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { 1062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_UNSPEC] = { .type = NLA_REJECT }, 1162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE] = { .type = NLA_NESTED }, 1262306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE] = { .type = NLA_NESTED }, 1362306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE] = { .type = NLA_NESTED }, 1462306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE] = { .type = NLA_NESTED }, 1562306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, 1662306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST] = { .type = NLA_NESTED }, 1762306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, 1862306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, 1962306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic const struct nla_policy 2362306a36Sopenharmony_cibr_mrp_instance_policy[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1] = { 2462306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_UNSPEC] = { .type = NLA_REJECT }, 2562306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_RING_ID] = { .type = NLA_U32 }, 2662306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] = { .type = NLA_U32 }, 2762306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX] = { .type = NLA_U32 }, 2862306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_PRIO] = { .type = NLA_U16 }, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int br_mrp_instance_parse(struct net_bridge *br, struct nlattr *attr, 3262306a36Sopenharmony_ci int cmd, struct netlink_ext_ack *extack) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1]; 3562306a36Sopenharmony_ci struct br_mrp_instance inst; 3662306a36Sopenharmony_ci int err; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_INSTANCE_MAX, attr, 3962306a36Sopenharmony_ci br_mrp_instance_policy, extack); 4062306a36Sopenharmony_ci if (err) 4162306a36Sopenharmony_ci return err; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID] || 4462306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] || 4562306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]) { 4662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 4762306a36Sopenharmony_ci "Missing attribute: RING_ID or P_IFINDEX or S_IFINDEX"); 4862306a36Sopenharmony_ci return -EINVAL; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci memset(&inst, 0, sizeof(inst)); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci inst.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID]); 5462306a36Sopenharmony_ci inst.p_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]); 5562306a36Sopenharmony_ci inst.s_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]); 5662306a36Sopenharmony_ci inst.prio = MRP_DEFAULT_PRIO; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]) 5962306a36Sopenharmony_ci inst.prio = nla_get_u16(tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (cmd == RTM_SETLINK) 6262306a36Sopenharmony_ci return br_mrp_add(br, &inst); 6362306a36Sopenharmony_ci else 6462306a36Sopenharmony_ci return br_mrp_del(br, &inst); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic const struct nla_policy 7062306a36Sopenharmony_cibr_mrp_port_state_policy[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1] = { 7162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC] = { .type = NLA_REJECT }, 7262306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE_STATE] = { .type = NLA_U32 }, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int br_mrp_port_state_parse(struct net_bridge_port *p, 7662306a36Sopenharmony_ci struct nlattr *attr, 7762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1]; 8062306a36Sopenharmony_ci enum br_mrp_port_state_type state; 8162306a36Sopenharmony_ci int err; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_STATE_MAX, attr, 8462306a36Sopenharmony_ci br_mrp_port_state_policy, extack); 8562306a36Sopenharmony_ci if (err) 8662306a36Sopenharmony_ci return err; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]) { 8962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Missing attribute: STATE"); 9062306a36Sopenharmony_ci return -EINVAL; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci state = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return br_mrp_set_port_state(p, state); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct nla_policy 9962306a36Sopenharmony_cibr_mrp_port_role_policy[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1] = { 10062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC] = { .type = NLA_REJECT }, 10162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE_ROLE] = { .type = NLA_U32 }, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int br_mrp_port_role_parse(struct net_bridge_port *p, 10562306a36Sopenharmony_ci struct nlattr *attr, 10662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1]; 10962306a36Sopenharmony_ci enum br_mrp_port_role_type role; 11062306a36Sopenharmony_ci int err; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_ROLE_MAX, attr, 11362306a36Sopenharmony_ci br_mrp_port_role_policy, extack); 11462306a36Sopenharmony_ci if (err) 11562306a36Sopenharmony_ci return err; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]) { 11862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Missing attribute: ROLE"); 11962306a36Sopenharmony_ci return -EINVAL; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci role = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return br_mrp_set_port_role(p, role); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const struct nla_policy 12862306a36Sopenharmony_cibr_mrp_ring_state_policy[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1] = { 12962306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_UNSPEC] = { .type = NLA_REJECT }, 13062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_RING_ID] = { .type = NLA_U32 }, 13162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_STATE] = { .type = NLA_U32 }, 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int br_mrp_ring_state_parse(struct net_bridge *br, struct nlattr *attr, 13562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1]; 13862306a36Sopenharmony_ci struct br_mrp_ring_state state; 13962306a36Sopenharmony_ci int err; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_STATE_MAX, attr, 14262306a36Sopenharmony_ci br_mrp_ring_state_policy, extack); 14362306a36Sopenharmony_ci if (err) 14462306a36Sopenharmony_ci return err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID] || 14762306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]) { 14862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 14962306a36Sopenharmony_ci "Missing attribute: RING_ID or STATE"); 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci memset(&state, 0x0, sizeof(state)); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci state.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID]); 15662306a36Sopenharmony_ci state.ring_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return br_mrp_set_ring_state(br, &state); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct nla_policy 16262306a36Sopenharmony_cibr_mrp_ring_role_policy[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1] = { 16362306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC] = { .type = NLA_REJECT }, 16462306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] = { .type = NLA_U32 }, 16562306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_ROLE] = { .type = NLA_U32 }, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int br_mrp_ring_role_parse(struct net_bridge *br, struct nlattr *attr, 16962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1]; 17262306a36Sopenharmony_ci struct br_mrp_ring_role role; 17362306a36Sopenharmony_ci int err; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_ROLE_MAX, attr, 17662306a36Sopenharmony_ci br_mrp_ring_role_policy, extack); 17762306a36Sopenharmony_ci if (err) 17862306a36Sopenharmony_ci return err; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] || 18162306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]) { 18262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 18362306a36Sopenharmony_ci "Missing attribute: RING_ID or ROLE"); 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci memset(&role, 0x0, sizeof(role)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]); 19062306a36Sopenharmony_ci role.ring_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return br_mrp_set_ring_role(br, &role); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct nla_policy 19662306a36Sopenharmony_cibr_mrp_start_test_policy[IFLA_BRIDGE_MRP_START_TEST_MAX + 1] = { 19762306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_UNSPEC] = { .type = NLA_REJECT }, 19862306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_RING_ID] = { .type = NLA_U32 }, 19962306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_INTERVAL] = { .type = NLA_U32 }, 20062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] = { .type = NLA_U32 }, 20162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_PERIOD] = { .type = NLA_U32 }, 20262306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_MONITOR] = { .type = NLA_U32 }, 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, 20662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; 20962306a36Sopenharmony_ci struct br_mrp_start_test test; 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_TEST_MAX, attr, 21362306a36Sopenharmony_ci br_mrp_start_test_policy, extack); 21462306a36Sopenharmony_ci if (err) 21562306a36Sopenharmony_ci return err; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID] || 21862306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL] || 21962306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] || 22062306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]) { 22162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 22262306a36Sopenharmony_ci "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD"); 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci memset(&test, 0x0, sizeof(test)); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci test.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID]); 22962306a36Sopenharmony_ci test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL]); 23062306a36Sopenharmony_ci test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]); 23162306a36Sopenharmony_ci test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]); 23262306a36Sopenharmony_ci test.monitor = false; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]) 23562306a36Sopenharmony_ci test.monitor = 23662306a36Sopenharmony_ci nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return br_mrp_start_test(br, &test); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic const struct nla_policy 24262306a36Sopenharmony_cibr_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { 24362306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, 24462306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_IN_ID] = { .type = NLA_U32 }, 24562306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_STATE] = { .type = NLA_U32 }, 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, 24962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; 25262306a36Sopenharmony_ci struct br_mrp_in_state state; 25362306a36Sopenharmony_ci int err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, 25662306a36Sopenharmony_ci br_mrp_in_state_policy, extack); 25762306a36Sopenharmony_ci if (err) 25862306a36Sopenharmony_ci return err; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || 26162306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { 26262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 26362306a36Sopenharmony_ci "Missing attribute: IN_ID or STATE"); 26462306a36Sopenharmony_ci return -EINVAL; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci memset(&state, 0x0, sizeof(state)); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); 27062306a36Sopenharmony_ci state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return br_mrp_set_in_state(br, &state); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic const struct nla_policy 27662306a36Sopenharmony_cibr_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { 27762306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC] = { .type = NLA_REJECT }, 27862306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, 27962306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, 28062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, 28162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, 28262306a36Sopenharmony_ci}; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, 28562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; 28862306a36Sopenharmony_ci struct br_mrp_in_role role; 28962306a36Sopenharmony_ci int err; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, 29262306a36Sopenharmony_ci br_mrp_in_role_policy, extack); 29362306a36Sopenharmony_ci if (err) 29462306a36Sopenharmony_ci return err; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || 29762306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || 29862306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || 29962306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { 30062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 30162306a36Sopenharmony_ci "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci memset(&role, 0x0, sizeof(role)); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); 30862306a36Sopenharmony_ci role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); 30962306a36Sopenharmony_ci role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); 31062306a36Sopenharmony_ci role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return br_mrp_set_in_role(br, &role); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic const struct nla_policy 31662306a36Sopenharmony_cibr_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { 31762306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, 31862306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, 31962306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] = { .type = NLA_U32 }, 32062306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] = { .type = NLA_U32 }, 32162306a36Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int br_mrp_start_in_test_parse(struct net_bridge *br, 32562306a36Sopenharmony_ci struct nlattr *attr, 32662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; 32962306a36Sopenharmony_ci struct br_mrp_start_in_test test; 33062306a36Sopenharmony_ci int err; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_IN_TEST_MAX, attr, 33362306a36Sopenharmony_ci br_mrp_start_in_test_policy, extack); 33462306a36Sopenharmony_ci if (err) 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] || 33862306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] || 33962306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] || 34062306a36Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]) { 34162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 34262306a36Sopenharmony_ci "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD"); 34362306a36Sopenharmony_ci return -EINVAL; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci memset(&test, 0x0, sizeof(test)); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci test.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID]); 34962306a36Sopenharmony_ci test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]); 35062306a36Sopenharmony_ci test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]); 35162306a36Sopenharmony_ci test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return br_mrp_start_in_test(br, &test); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciint br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, 35762306a36Sopenharmony_ci struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_MAX + 1]; 36062306a36Sopenharmony_ci int err; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* When this function is called for a port then the br pointer is 36362306a36Sopenharmony_ci * invalid, therefor set the br to point correctly 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci if (p) 36662306a36Sopenharmony_ci br = p->br; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (br->stp_enabled != BR_NO_STP) { 36962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "MRP can't be enabled if STP is already enabled"); 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_MAX, attr, 37462306a36Sopenharmony_ci br_mrp_policy, extack); 37562306a36Sopenharmony_ci if (err) 37662306a36Sopenharmony_ci return err; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_INSTANCE]) { 37962306a36Sopenharmony_ci err = br_mrp_instance_parse(br, tb[IFLA_BRIDGE_MRP_INSTANCE], 38062306a36Sopenharmony_ci cmd, extack); 38162306a36Sopenharmony_ci if (err) 38262306a36Sopenharmony_ci return err; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_PORT_STATE]) { 38662306a36Sopenharmony_ci err = br_mrp_port_state_parse(p, tb[IFLA_BRIDGE_MRP_PORT_STATE], 38762306a36Sopenharmony_ci extack); 38862306a36Sopenharmony_ci if (err) 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_PORT_ROLE]) { 39362306a36Sopenharmony_ci err = br_mrp_port_role_parse(p, tb[IFLA_BRIDGE_MRP_PORT_ROLE], 39462306a36Sopenharmony_ci extack); 39562306a36Sopenharmony_ci if (err) 39662306a36Sopenharmony_ci return err; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_RING_STATE]) { 40062306a36Sopenharmony_ci err = br_mrp_ring_state_parse(br, 40162306a36Sopenharmony_ci tb[IFLA_BRIDGE_MRP_RING_STATE], 40262306a36Sopenharmony_ci extack); 40362306a36Sopenharmony_ci if (err) 40462306a36Sopenharmony_ci return err; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_RING_ROLE]) { 40862306a36Sopenharmony_ci err = br_mrp_ring_role_parse(br, tb[IFLA_BRIDGE_MRP_RING_ROLE], 40962306a36Sopenharmony_ci extack); 41062306a36Sopenharmony_ci if (err) 41162306a36Sopenharmony_ci return err; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_TEST]) { 41562306a36Sopenharmony_ci err = br_mrp_start_test_parse(br, 41662306a36Sopenharmony_ci tb[IFLA_BRIDGE_MRP_START_TEST], 41762306a36Sopenharmony_ci extack); 41862306a36Sopenharmony_ci if (err) 41962306a36Sopenharmony_ci return err; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_IN_STATE]) { 42362306a36Sopenharmony_ci err = br_mrp_in_state_parse(br, tb[IFLA_BRIDGE_MRP_IN_STATE], 42462306a36Sopenharmony_ci extack); 42562306a36Sopenharmony_ci if (err) 42662306a36Sopenharmony_ci return err; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_IN_ROLE]) { 43062306a36Sopenharmony_ci err = br_mrp_in_role_parse(br, tb[IFLA_BRIDGE_MRP_IN_ROLE], 43162306a36Sopenharmony_ci extack); 43262306a36Sopenharmony_ci if (err) 43362306a36Sopenharmony_ci return err; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_IN_TEST]) { 43762306a36Sopenharmony_ci err = br_mrp_start_in_test_parse(br, 43862306a36Sopenharmony_ci tb[IFLA_BRIDGE_MRP_START_IN_TEST], 43962306a36Sopenharmony_ci extack); 44062306a36Sopenharmony_ci if (err) 44162306a36Sopenharmony_ci return err; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ciint br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct nlattr *tb, *mrp_tb; 45062306a36Sopenharmony_ci struct br_mrp *mrp; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); 45362306a36Sopenharmony_ci if (!mrp_tb) 45462306a36Sopenharmony_ci return -EMSGSIZE; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci hlist_for_each_entry_rcu(mrp, &br->mrp_list, list) { 45762306a36Sopenharmony_ci struct net_bridge_port *p; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); 46062306a36Sopenharmony_ci if (!tb) 46162306a36Sopenharmony_ci goto nla_info_failure; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID, 46462306a36Sopenharmony_ci mrp->ring_id)) 46562306a36Sopenharmony_ci goto nla_put_failure; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci p = rcu_dereference(mrp->p_port); 46862306a36Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX, 46962306a36Sopenharmony_ci p->dev->ifindex)) 47062306a36Sopenharmony_ci goto nla_put_failure; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci p = rcu_dereference(mrp->s_port); 47362306a36Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX, 47462306a36Sopenharmony_ci p->dev->ifindex)) 47562306a36Sopenharmony_ci goto nla_put_failure; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci p = rcu_dereference(mrp->i_port); 47862306a36Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, 47962306a36Sopenharmony_ci p->dev->ifindex)) 48062306a36Sopenharmony_ci goto nla_put_failure; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, 48362306a36Sopenharmony_ci mrp->prio)) 48462306a36Sopenharmony_ci goto nla_put_failure; 48562306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE, 48662306a36Sopenharmony_ci mrp->ring_state)) 48762306a36Sopenharmony_ci goto nla_put_failure; 48862306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE, 48962306a36Sopenharmony_ci mrp->ring_role)) 49062306a36Sopenharmony_ci goto nla_put_failure; 49162306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, 49262306a36Sopenharmony_ci mrp->test_interval)) 49362306a36Sopenharmony_ci goto nla_put_failure; 49462306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, 49562306a36Sopenharmony_ci mrp->test_max_miss)) 49662306a36Sopenharmony_ci goto nla_put_failure; 49762306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, 49862306a36Sopenharmony_ci mrp->test_monitor)) 49962306a36Sopenharmony_ci goto nla_put_failure; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, 50262306a36Sopenharmony_ci mrp->in_state)) 50362306a36Sopenharmony_ci goto nla_put_failure; 50462306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, 50562306a36Sopenharmony_ci mrp->in_role)) 50662306a36Sopenharmony_ci goto nla_put_failure; 50762306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, 50862306a36Sopenharmony_ci mrp->in_test_interval)) 50962306a36Sopenharmony_ci goto nla_put_failure; 51062306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, 51162306a36Sopenharmony_ci mrp->in_test_max_miss)) 51262306a36Sopenharmony_ci goto nla_put_failure; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci nla_nest_end(skb, tb); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci nla_nest_end(skb, mrp_tb); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cinla_put_failure: 52162306a36Sopenharmony_ci nla_nest_cancel(skb, tb); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cinla_info_failure: 52462306a36Sopenharmony_ci nla_nest_cancel(skb, mrp_tb); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return -EMSGSIZE; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ciint br_mrp_ring_port_open(struct net_device *dev, u8 loc) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct net_bridge_port *p; 53262306a36Sopenharmony_ci int err = 0; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci p = br_port_get_rcu(dev); 53562306a36Sopenharmony_ci if (!p) { 53662306a36Sopenharmony_ci err = -EINVAL; 53762306a36Sopenharmony_ci goto out; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (loc) 54162306a36Sopenharmony_ci p->flags |= BR_MRP_LOST_CONT; 54262306a36Sopenharmony_ci else 54362306a36Sopenharmony_ci p->flags &= ~BR_MRP_LOST_CONT; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciout: 54862306a36Sopenharmony_ci return err; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciint br_mrp_in_port_open(struct net_device *dev, u8 loc) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct net_bridge_port *p; 55462306a36Sopenharmony_ci int err = 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci p = br_port_get_rcu(dev); 55762306a36Sopenharmony_ci if (!p) { 55862306a36Sopenharmony_ci err = -EINVAL; 55962306a36Sopenharmony_ci goto out; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (loc) 56362306a36Sopenharmony_ci p->flags |= BR_MRP_LOST_IN_CONT; 56462306a36Sopenharmony_ci else 56562306a36Sopenharmony_ci p->flags &= ~BR_MRP_LOST_IN_CONT; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciout: 57062306a36Sopenharmony_ci return err; 57162306a36Sopenharmony_ci} 572