1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <net/xdp_sock_drv.h> 4 5 #include "netlink.h" 6 #include "common.h" 7 8 struct channels_req_info { 9 struct ethnl_req_info base; 10 }; 11 12 struct channels_reply_data { 13 struct ethnl_reply_data base; 14 struct ethtool_channels channels; 15 }; 16 17 #define CHANNELS_REPDATA(__reply_base) \ 18 container_of(__reply_base, struct channels_reply_data, base) 19 20 static const struct nla_policy 21 channels_get_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { 22 [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, 23 [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, 24 [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, 25 [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, 26 [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, 27 [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, 28 [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_REJECT }, 29 [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_REJECT }, 30 [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_REJECT }, 31 [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .type = NLA_REJECT }, 32 }; 33 34 static int channels_prepare_data(const struct ethnl_req_info *req_base, 35 struct ethnl_reply_data *reply_base, 36 struct genl_info *info) 37 { 38 struct channels_reply_data *data = CHANNELS_REPDATA(reply_base); 39 struct net_device *dev = reply_base->dev; 40 int ret; 41 42 if (!dev->ethtool_ops->get_channels) 43 return -EOPNOTSUPP; 44 ret = ethnl_ops_begin(dev); 45 if (ret < 0) 46 return ret; 47 dev->ethtool_ops->get_channels(dev, &data->channels); 48 ethnl_ops_complete(dev); 49 50 return 0; 51 } 52 53 static int channels_reply_size(const struct ethnl_req_info *req_base, 54 const struct ethnl_reply_data *reply_base) 55 { 56 return nla_total_size(sizeof(u32)) + /* _CHANNELS_RX_MAX */ 57 nla_total_size(sizeof(u32)) + /* _CHANNELS_TX_MAX */ 58 nla_total_size(sizeof(u32)) + /* _CHANNELS_OTHER_MAX */ 59 nla_total_size(sizeof(u32)) + /* _CHANNELS_COMBINED_MAX */ 60 nla_total_size(sizeof(u32)) + /* _CHANNELS_RX_COUNT */ 61 nla_total_size(sizeof(u32)) + /* _CHANNELS_TX_COUNT */ 62 nla_total_size(sizeof(u32)) + /* _CHANNELS_OTHER_COUNT */ 63 nla_total_size(sizeof(u32)); /* _CHANNELS_COMBINED_COUNT */ 64 } 65 66 static int channels_fill_reply(struct sk_buff *skb, 67 const struct ethnl_req_info *req_base, 68 const struct ethnl_reply_data *reply_base) 69 { 70 const struct channels_reply_data *data = CHANNELS_REPDATA(reply_base); 71 const struct ethtool_channels *channels = &data->channels; 72 73 if ((channels->max_rx && 74 (nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_MAX, 75 channels->max_rx) || 76 nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_COUNT, 77 channels->rx_count))) || 78 (channels->max_tx && 79 (nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_MAX, 80 channels->max_tx) || 81 nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_COUNT, 82 channels->tx_count))) || 83 (channels->max_other && 84 (nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_MAX, 85 channels->max_other) || 86 nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_COUNT, 87 channels->other_count))) || 88 (channels->max_combined && 89 (nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_MAX, 90 channels->max_combined) || 91 nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_COUNT, 92 channels->combined_count)))) 93 return -EMSGSIZE; 94 95 return 0; 96 } 97 98 const struct ethnl_request_ops ethnl_channels_request_ops = { 99 .request_cmd = ETHTOOL_MSG_CHANNELS_GET, 100 .reply_cmd = ETHTOOL_MSG_CHANNELS_GET_REPLY, 101 .hdr_attr = ETHTOOL_A_CHANNELS_HEADER, 102 .max_attr = ETHTOOL_A_CHANNELS_MAX, 103 .req_info_size = sizeof(struct channels_req_info), 104 .reply_data_size = sizeof(struct channels_reply_data), 105 .request_policy = channels_get_policy, 106 107 .prepare_data = channels_prepare_data, 108 .reply_size = channels_reply_size, 109 .fill_reply = channels_fill_reply, 110 }; 111 112 /* CHANNELS_SET */ 113 114 static const struct nla_policy 115 channels_set_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { 116 [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, 117 [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, 118 [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, 119 [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, 120 [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, 121 [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, 122 [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_U32 }, 123 [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_U32 }, 124 [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_U32 }, 125 [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .type = NLA_U32 }, 126 }; 127 128 int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info) 129 { 130 struct nlattr *tb[ETHTOOL_A_CHANNELS_MAX + 1]; 131 unsigned int from_channel, old_total, i; 132 bool mod = false, mod_combined = false; 133 struct ethtool_channels channels = {}; 134 struct ethnl_req_info req_info = {}; 135 const struct nlattr *err_attr; 136 const struct ethtool_ops *ops; 137 struct net_device *dev; 138 u32 max_rx_in_use = 0; 139 int ret; 140 141 ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 142 ETHTOOL_A_CHANNELS_MAX, channels_set_policy, 143 info->extack); 144 if (ret < 0) 145 return ret; 146 ret = ethnl_parse_header_dev_get(&req_info, 147 tb[ETHTOOL_A_CHANNELS_HEADER], 148 genl_info_net(info), info->extack, 149 true); 150 if (ret < 0) 151 return ret; 152 dev = req_info.dev; 153 ops = dev->ethtool_ops; 154 ret = -EOPNOTSUPP; 155 if (!ops->get_channels || !ops->set_channels) 156 goto out_dev; 157 158 rtnl_lock(); 159 ret = ethnl_ops_begin(dev); 160 if (ret < 0) 161 goto out_rtnl; 162 ops->get_channels(dev, &channels); 163 old_total = channels.combined_count + 164 max(channels.rx_count, channels.tx_count); 165 166 ethnl_update_u32(&channels.rx_count, tb[ETHTOOL_A_CHANNELS_RX_COUNT], 167 &mod); 168 ethnl_update_u32(&channels.tx_count, tb[ETHTOOL_A_CHANNELS_TX_COUNT], 169 &mod); 170 ethnl_update_u32(&channels.other_count, 171 tb[ETHTOOL_A_CHANNELS_OTHER_COUNT], &mod); 172 ethnl_update_u32(&channels.combined_count, 173 tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT], &mod_combined); 174 mod |= mod_combined; 175 ret = 0; 176 if (!mod) 177 goto out_ops; 178 179 /* ensure new channel counts are within limits */ 180 if (channels.rx_count > channels.max_rx) 181 err_attr = tb[ETHTOOL_A_CHANNELS_RX_COUNT]; 182 else if (channels.tx_count > channels.max_tx) 183 err_attr = tb[ETHTOOL_A_CHANNELS_TX_COUNT]; 184 else if (channels.other_count > channels.max_other) 185 err_attr = tb[ETHTOOL_A_CHANNELS_OTHER_COUNT]; 186 else if (channels.combined_count > channels.max_combined) 187 err_attr = tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT]; 188 else 189 err_attr = NULL; 190 if (err_attr) { 191 ret = -EINVAL; 192 NL_SET_ERR_MSG_ATTR(info->extack, err_attr, 193 "requested channel count exceeds maximum"); 194 goto out_ops; 195 } 196 197 /* ensure there is at least one RX and one TX channel */ 198 if (!channels.combined_count && !channels.rx_count) 199 err_attr = tb[ETHTOOL_A_CHANNELS_RX_COUNT]; 200 else if (!channels.combined_count && !channels.tx_count) 201 err_attr = tb[ETHTOOL_A_CHANNELS_TX_COUNT]; 202 else 203 err_attr = NULL; 204 if (err_attr) { 205 if (mod_combined) 206 err_attr = tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT]; 207 ret = -EINVAL; 208 NL_SET_ERR_MSG_ATTR(info->extack, err_attr, "requested channel counts would result in no RX or TX channel being configured"); 209 goto out_ops; 210 } 211 212 /* ensure the new Rx count fits within the configured Rx flow 213 * indirection table settings 214 */ 215 if (netif_is_rxfh_configured(dev) && 216 !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) && 217 (channels.combined_count + channels.rx_count) <= max_rx_in_use) { 218 GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing indirection table settings"); 219 return -EINVAL; 220 } 221 222 /* Disabling channels, query zero-copy AF_XDP sockets */ 223 from_channel = channels.combined_count + 224 min(channels.rx_count, channels.tx_count); 225 for (i = from_channel; i < old_total; i++) 226 if (xdp_get_umem_from_qid(dev, i)) { 227 GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing zerocopy AF_XDP sockets"); 228 return -EINVAL; 229 } 230 231 ret = dev->ethtool_ops->set_channels(dev, &channels); 232 if (ret < 0) 233 goto out_ops; 234 ethtool_notify(dev, ETHTOOL_MSG_CHANNELS_NTF, NULL); 235 236 out_ops: 237 ethnl_ops_complete(dev); 238 out_rtnl: 239 rtnl_unlock(); 240 out_dev: 241 dev_put(dev); 242 return ret; 243 } 244