^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) struct rings_req_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) struct ethnl_req_info base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) struct rings_reply_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct ethnl_reply_data base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct ethtool_ringparam ringparam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define RINGS_REPDATA(__reply_base) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) container_of(__reply_base, struct rings_reply_data, base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) const struct nla_policy ethnl_rings_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) [ETHTOOL_A_RINGS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int rings_prepare_data(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct ethnl_reply_data *reply_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct rings_reply_data *data = RINGS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct net_device *dev = reply_base->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (!dev->ethtool_ops->get_ringparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) dev->ethtool_ops->get_ringparam(dev, &data->ringparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static int rings_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return nla_total_size(sizeof(u32)) + /* _RINGS_RX_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) nla_total_size(sizeof(u32)) + /* _RINGS_RX_MINI_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) nla_total_size(sizeof(u32)) + /* _RINGS_RX_JUMBO_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) nla_total_size(sizeof(u32)) + /* _RINGS_TX_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) nla_total_size(sizeof(u32)) + /* _RINGS_RX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) nla_total_size(sizeof(u32)) + /* _RINGS_RX_MINI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) nla_total_size(sizeof(u32)) + /* _RINGS_RX_JUMBO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) nla_total_size(sizeof(u32)); /* _RINGS_TX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static int rings_fill_reply(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) const struct rings_reply_data *data = RINGS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const struct ethtool_ringparam *ringparam = &data->ringparam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if ((ringparam->rx_max_pending &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ringparam->rx_max_pending) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) nla_put_u32(skb, ETHTOOL_A_RINGS_RX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ringparam->rx_pending))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) (ringparam->rx_mini_max_pending &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MINI_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ringparam->rx_mini_max_pending) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MINI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ringparam->rx_mini_pending))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) (ringparam->rx_jumbo_max_pending &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_JUMBO_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ringparam->rx_jumbo_max_pending) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) nla_put_u32(skb, ETHTOOL_A_RINGS_RX_JUMBO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ringparam->rx_jumbo_pending))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) (ringparam->tx_max_pending &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) (nla_put_u32(skb, ETHTOOL_A_RINGS_TX_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ringparam->tx_max_pending) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) nla_put_u32(skb, ETHTOOL_A_RINGS_TX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ringparam->tx_pending))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) const struct ethnl_request_ops ethnl_rings_request_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .request_cmd = ETHTOOL_MSG_RINGS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .reply_cmd = ETHTOOL_MSG_RINGS_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .hdr_attr = ETHTOOL_A_RINGS_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .req_info_size = sizeof(struct rings_req_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .reply_data_size = sizeof(struct rings_reply_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .prepare_data = rings_prepare_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .reply_size = rings_reply_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .fill_reply = rings_fill_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* RINGS_SET */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) const struct nla_policy ethnl_rings_set_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) [ETHTOOL_A_RINGS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) [ETHTOOL_A_RINGS_RX] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) [ETHTOOL_A_RINGS_RX_MINI] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) [ETHTOOL_A_RINGS_RX_JUMBO] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) [ETHTOOL_A_RINGS_TX] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct ethtool_ringparam ringparam = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct ethnl_req_info req_info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) const struct nlattr *err_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) const struct ethtool_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) bool mod = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ret = ethnl_parse_header_dev_get(&req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) tb[ETHTOOL_A_RINGS_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) genl_info_net(info), info->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev = req_info.dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!ops->get_ringparam || !ops->set_ringparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) goto out_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto out_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ops->get_ringparam(dev, &ringparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ethnl_update_u32(&ringparam.rx_pending, tb[ETHTOOL_A_RINGS_RX], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ethnl_update_u32(&ringparam.rx_mini_pending,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) tb[ETHTOOL_A_RINGS_RX_MINI], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ethnl_update_u32(&ringparam.rx_jumbo_pending,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) tb[ETHTOOL_A_RINGS_RX_JUMBO], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ethnl_update_u32(&ringparam.tx_pending, tb[ETHTOOL_A_RINGS_TX], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (!mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* ensure new ring parameters are within limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (ringparam.rx_pending > ringparam.rx_max_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) err_attr = tb[ETHTOOL_A_RINGS_RX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) else if (ringparam.rx_mini_pending > ringparam.rx_mini_max_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) err_attr = tb[ETHTOOL_A_RINGS_RX_MINI];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) else if (ringparam.rx_jumbo_pending > ringparam.rx_jumbo_max_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) err_attr = tb[ETHTOOL_A_RINGS_RX_JUMBO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) else if (ringparam.tx_pending > ringparam.tx_max_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) err_attr = tb[ETHTOOL_A_RINGS_TX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) err_attr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (err_attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) NL_SET_ERR_MSG_ATTR(info->extack, err_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) "requested ring size exceeds maximum");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ret = dev->ethtool_ops->set_ringparam(dev, &ringparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) out_ops:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) out_rtnl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) out_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }