1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <net/xdp_sock.h>
8 struct channels_req_info
{
9 struct ethnl_req_info base
;
12 struct channels_reply_data
{
13 struct ethnl_reply_data base
;
14 struct ethtool_channels channels
;
17 #define CHANNELS_REPDATA(__reply_base) \
18 container_of(__reply_base, struct channels_reply_data, base)
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
},
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
)
38 struct channels_reply_data
*data
= CHANNELS_REPDATA(reply_base
);
39 struct net_device
*dev
= reply_base
->dev
;
42 if (!dev
->ethtool_ops
->get_channels
)
44 ret
= ethnl_ops_begin(dev
);
47 dev
->ethtool_ops
->get_channels(dev
, &data
->channels
);
48 ethnl_ops_complete(dev
);
53 static int channels_reply_size(const struct ethnl_req_info
*req_base
,
54 const struct ethnl_reply_data
*reply_base
)
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 */
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
)
70 const struct channels_reply_data
*data
= CHANNELS_REPDATA(reply_base
);
71 const struct ethtool_channels
*channels
= &data
->channels
;
73 if ((channels
->max_rx
&&
74 (nla_put_u32(skb
, ETHTOOL_A_CHANNELS_RX_MAX
,
76 nla_put_u32(skb
, ETHTOOL_A_CHANNELS_RX_COUNT
,
77 channels
->rx_count
))) ||
79 (nla_put_u32(skb
, ETHTOOL_A_CHANNELS_TX_MAX
,
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
))))
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
,
107 .prepare_data
= channels_prepare_data
,
108 .reply_size
= channels_reply_size
,
109 .fill_reply
= channels_fill_reply
,
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
},
128 int ethnl_set_channels(struct sk_buff
*skb
, struct genl_info
*info
)
130 struct nlattr
*tb
[ETHTOOL_A_CHANNELS_MAX
+ 1];
131 unsigned int from_channel
, old_total
, i
;
132 struct ethtool_channels channels
= {};
133 struct ethnl_req_info req_info
= {};
134 const struct nlattr
*err_attr
;
135 const struct ethtool_ops
*ops
;
136 struct net_device
*dev
;
137 u32 max_rx_in_use
= 0;
141 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
,
142 ETHTOOL_A_CHANNELS_MAX
, channels_set_policy
,
146 ret
= ethnl_parse_header_dev_get(&req_info
,
147 tb
[ETHTOOL_A_CHANNELS_HEADER
],
148 genl_info_net(info
), info
->extack
,
153 ops
= dev
->ethtool_ops
;
155 if (!ops
->get_channels
|| !ops
->set_channels
)
159 ret
= ethnl_ops_begin(dev
);
162 ops
->get_channels(dev
, &channels
);
163 old_total
= channels
.combined_count
+
164 max(channels
.rx_count
, channels
.tx_count
);
166 ethnl_update_u32(&channels
.rx_count
, tb
[ETHTOOL_A_CHANNELS_RX_COUNT
],
168 ethnl_update_u32(&channels
.tx_count
, tb
[ETHTOOL_A_CHANNELS_TX_COUNT
],
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
);
178 /* ensure new channel counts are within limits */
179 if (channels
.rx_count
> channels
.max_rx
)
180 err_attr
= tb
[ETHTOOL_A_CHANNELS_RX_COUNT
];
181 else if (channels
.tx_count
> channels
.max_tx
)
182 err_attr
= tb
[ETHTOOL_A_CHANNELS_TX_COUNT
];
183 else if (channels
.other_count
> channels
.max_other
)
184 err_attr
= tb
[ETHTOOL_A_CHANNELS_OTHER_COUNT
];
185 else if (channels
.combined_count
> channels
.max_combined
)
186 err_attr
= tb
[ETHTOOL_A_CHANNELS_COMBINED_COUNT
];
191 NL_SET_ERR_MSG_ATTR(info
->extack
, err_attr
,
192 "requested channel count exceeds maximum");
196 /* ensure the new Rx count fits within the configured Rx flow
197 * indirection table settings
199 if (netif_is_rxfh_configured(dev
) &&
200 !ethtool_get_max_rxfh_channel(dev
, &max_rx_in_use
) &&
201 (channels
.combined_count
+ channels
.rx_count
) <= max_rx_in_use
) {
202 GENL_SET_ERR_MSG(info
, "requested channel counts are too low for existing indirection table settings");
206 /* Disabling channels, query zero-copy AF_XDP sockets */
207 from_channel
= channels
.combined_count
+
208 min(channels
.rx_count
, channels
.tx_count
);
209 for (i
= from_channel
; i
< old_total
; i
++)
210 if (xdp_get_umem_from_qid(dev
, i
)) {
211 GENL_SET_ERR_MSG(info
, "requested channel counts are too low for existing zerocopy AF_XDP sockets");
215 ret
= dev
->ethtool_ops
->set_channels(dev
, &channels
);
218 ethtool_notify(dev
, ETHTOOL_MSG_CHANNELS_NTF
, NULL
);
221 ethnl_ops_complete(dev
);