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