Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-introduce-tx-h-w-shaping-api'

Paolo Abeni says:

====================
net: introduce TX H/W shaping API

We have a plurality of shaping-related drivers API, but none flexible
enough to meet existing demand from vendors[1].

This series introduces new device APIs to configure in a flexible way
TX H/W shaping. The new functionalities are exposed via a newly
defined generic netlink interface and include introspection
capabilities. Some self-tests are included, on top of a dummy
netdevsim implementation. Finally a basic implementation for the iavf
driver is provided.

Some usage examples:

* Configure shaping on a given queue:

./tools/net/ynl/cli.py --spec Documentation/netlink/specs/shaper.yaml \
--do set --json '{"ifindex": '$IFINDEX',
"shaper": {"handle":
{"scope": "queue", "id":'$QUEUEID'},
"bw-max": 2000000}}'

* Container B/W sharing

The orchestration infrastructure wants to group the
container-related queues under a RR scheduling and limit the aggregate
bandwidth:

./tools/net/ynl/cli.py --spec Documentation/netlink/specs/shaper.yaml \
--do group --json '{"ifindex": '$IFINDEX',
"leaves": [
{"handle": {"scope": "queue", "id":'$QID1'},
"weight": '$W1'},
{"handle": {"scope": "queue", "id":'$QID2'},
"weight": '$W2'}],
{"handle": {"scope": "queue", "id":'$QID3'},
"weight": '$W3'}],
"handle": {"scope":"node"},
"bw-max": 10000000}'
{'ifindex': $IFINDEX, 'handle': {'scope': 'node', 'id': 0}}

Q1 \
\
Q2 -- node 0 ------- netdev
/ (bw-max: 10M)
Q3 /

* Delegation

A containers wants to limit the aggregate B/W bandwidth of 2 of the 3
queues it owns - the starting configuration is the one from the
previous point:

SPEC=Documentation/netlink/specs/net_shaper.yaml
./tools/net/ynl/cli.py --spec $SPEC \
--do group --json '{"ifindex": '$IFINDEX',
"leaves": [
{"handle": {"scope": "queue", "id":'$QID1'},
"weight": '$W1'},
{"handle": {"scope": "queue", "id":'$QID2'},
"weight": '$W2'}],
"handle": {"scope": "node"},
"bw-max": 5000000 }'
{'ifindex': $IFINDEX, 'handle': {'scope': 'node', 'id': 1}}

Q1 -- node 1 --------\
/ (bw-max: 5M) \
Q2 / node 0 ------- netdev
/(bw-max: 10M)
Q3 ------------------/

In a group operation, when prior to the op itself, the leaves have
different parents, the user must specify the parent handle for the
group. I.e., starting from the previous config:

./tools/net/ynl/cli.py --spec $SPEC \
--do group --json '{"ifindex": '$IFINDEX',
"leaves": [
{"handle": {"scope": "queue", "id":'$QID1'},
"weight": '$W1'},
{"handle": {"scope": "queue", "id":'$QID3'},
"weight": '$W3'}],
"handle": {"scope": "node"},
"bw-max": 3000000 }'
Netlink error: Invalid argument
nl_len = 96 (80) nl_flags = 0x300 nl_type = 2
error: -22
extack: {'msg': 'All the leaves shapers must have the same old parent'}

./tools/net/ynl/cli.py --spec $SPEC \
--do group --json '{"ifindex": '$IFINDEX',
"leaves": [
{"handle": {"scope": "queue", "id":'$QID1'},
"weight": '$W1'},
{"handle": {"scope": "queue", "id":'$QID3'},
"weight": '$W3'}],
"handle": {"scope": "node"},
"parent": {"scope": "node", "id": 1},
"bw-max": 3000000 }
{'ifindex': $IFINDEX, 'handle': {'scope': 'node', 'id': 2}}

Q1 -- node 2 ---
/(bw-max:3M)\
Q3 / \
---- node 1 \
/ (bw-max: 5M)\
Q2 node 0 ------- netdev
(bw-max: 10M)

* Cleanup:

Still starting from config 1To delete a single queue shaper

./tools/net/ynl/cli.py --spec $SPEC --do delete --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "queue", "id":'$QID3'}}'

Q1 -- node 2 ---
(bw-max:3M)\
\
---- node 1 \
/ (bw-max: 5M)\
Q2 node 0 ------- netdev
(bw-max: 10M)

Deleting a node shaper relinks all its leaves to the node's parent:

./tools/net/ynl/cli.py --spec $SPEC --do delete --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "node", "id":2}}'

Q1 ---\
\
node 1----- \
/ (bw-max: 5M)\
Q2----/ node 0 ------- netdev
(bw-max: 10M)

Deleting the last shaper under a node shaper deletes the node, too:

./tools/net/ynl/cli.py --spec $SPEC --do delete --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "queue", "id":'$QID1'}}'
./tools/net/ynl/cli.py --spec $SPEC --do delete --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "queue", "id":'$QID2'}}'
./tools/net/ynl/cli.py --spec $SPEC --do get --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "node", "id": 1}}'
Netlink error: No such file or directory
nl_len = 44 (28) nl_flags = 0x300 nl_type = 2
error: -2
extack: {'bad-attr': '.handle'}

Such delete recurses on parents that are left over with no leaves:

./tools/net/ynl/cli.py --spec $SPEC --do get --json \
'{"ifindex": '$IFINDEX',
"handle": {"scope": "node", "id": 0}}'
Netlink error: No such file or directory
nl_len = 44 (28) nl_flags = 0x300 nl_type = 2
error: -2
extack: {'bad-attr': '.handle'}

v8: https://lore.kernel.org/cover.1727704215.git.pabeni@redhat.com
v7: https://lore.kernel.org/cover.1725919039.git.pabeni@redhat.com
v6: https://lore.kernel.org/cover.1725457317.git.pabeni@redhat.com
v5: https://lore.kernel.org/cover.1724944116.git.pabeni@redhat.com
v4: https://lore.kernel.org/cover.1724165948.git.pabeni@redhat.com
v3: https://lore.kernel.org/cover.1722357745.git.pabeni@redhat.com
RFC v2: https://lore.kernel.org/cover.1721851988.git.pabeni@redhat.com
RFC v1: https://lore.kernel.org/cover.1719518113.git.pabeni@redhat.com
====================

Link: https://patch.msgid.link/cover.1728460186.git.pabeni@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+3640 -15
+362
Documentation/netlink/specs/net_shaper.yaml
··· 1 + # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + name: net-shaper 3 + 4 + doc: | 5 + Networking HW rate limiting configuration. 6 + 7 + This API allows configuring HW shapers available on the network 8 + devices at different levels (queues, network device) and allows 9 + arbitrary manipulation of the scheduling tree of the involved 10 + shapers. 11 + 12 + Each @shaper is identified within the given device, by a @handle, 13 + comprising both a @scope and an @id. 14 + 15 + Depending on the @scope value, the shapers are attached to specific 16 + HW objects (queues, devices) or, for @node scope, represent a 17 + scheduling group, that can be placed in an arbitrary location of 18 + the scheduling tree. 19 + 20 + Shapers can be created with two different operations: the @set 21 + operation, to create and update a single "attached" shaper, and 22 + the @group operation, to create and update a scheduling 23 + group. Only the @group operation can create @node scope shapers. 24 + 25 + Existing shapers can be deleted/reset via the @delete operation. 26 + 27 + The user can query the running configuration via the @get operation. 28 + 29 + Different devices can provide different feature sets, e.g. with no 30 + support for complex scheduling hierarchy, or for some shaping 31 + parameters. The user can introspect the HW capabilities via the 32 + @cap-get operation. 33 + 34 + definitions: 35 + - 36 + type: enum 37 + name: scope 38 + doc: Defines the shaper @id interpretation. 39 + render-max: true 40 + entries: 41 + - name: unspec 42 + doc: The scope is not specified. 43 + - 44 + name: netdev 45 + doc: The main shaper for the given network device. 46 + - 47 + name: queue 48 + doc: | 49 + The shaper is attached to the given device queue, 50 + the @id represents the queue number. 51 + - 52 + name: node 53 + doc: | 54 + The shaper allows grouping of queues or other 55 + node shapers; can be nested in either @netdev 56 + shapers or other @node shapers, allowing placement 57 + in any location of the scheduling tree, except 58 + leaves and root. 59 + - 60 + type: enum 61 + name: metric 62 + doc: Different metric supported by the shaper. 63 + entries: 64 + - 65 + name: bps 66 + doc: Shaper operates on a bits per second basis. 67 + - 68 + name: pps 69 + doc: Shaper operates on a packets per second basis. 70 + 71 + attribute-sets: 72 + - 73 + name: net-shaper 74 + attributes: 75 + - 76 + name: handle 77 + type: nest 78 + nested-attributes: handle 79 + doc: Unique identifier for the given shaper inside the owning device. 80 + - 81 + name: metric 82 + type: u32 83 + enum: metric 84 + doc: Metric used by the given shaper for bw-min, bw-max and burst. 85 + - 86 + name: bw-min 87 + type: uint 88 + doc: Guaranteed bandwidth for the given shaper. 89 + - 90 + name: bw-max 91 + type: uint 92 + doc: Maximum bandwidth for the given shaper or 0 when unlimited. 93 + - 94 + name: burst 95 + type: uint 96 + doc: | 97 + Maximum burst-size for shaping. Should not be interpreted 98 + as a quantum. 99 + - 100 + name: priority 101 + type: u32 102 + doc: | 103 + Scheduling priority for the given shaper. The priority 104 + scheduling is applied to sibling shapers. 105 + - 106 + name: weight 107 + type: u32 108 + doc: | 109 + Relative weight for round robin scheduling of the 110 + given shaper. 111 + The scheduling is applied to all sibling shapers 112 + with the same priority. 113 + - 114 + name: ifindex 115 + type: u32 116 + doc: Interface index owning the specified shaper. 117 + - 118 + name: parent 119 + type: nest 120 + nested-attributes: handle 121 + doc: | 122 + Identifier for the parent of the affected shaper. 123 + Only needed for @group operation. 124 + - 125 + name: leaves 126 + type: nest 127 + multi-attr: true 128 + nested-attributes: leaf-info 129 + doc: | 130 + Describes a set of leaves shapers for a @group operation. 131 + - 132 + name: handle 133 + attributes: 134 + - 135 + name: scope 136 + type: u32 137 + enum: scope 138 + doc: Defines the shaper @id interpretation. 139 + - 140 + name: id 141 + type: u32 142 + doc: | 143 + Numeric identifier of a shaper. The id semantic depends on 144 + the scope. For @queue scope it's the queue id and for @node 145 + scope it's the node identifier. 146 + - 147 + name: leaf-info 148 + subset-of: net-shaper 149 + attributes: 150 + - 151 + name: handle 152 + - 153 + name: priority 154 + - 155 + name: weight 156 + - 157 + name: caps 158 + attributes: 159 + - 160 + name: ifindex 161 + type: u32 162 + doc: Interface index queried for shapers capabilities. 163 + - 164 + name: scope 165 + type: u32 166 + enum: scope 167 + doc: The scope to which the queried capabilities apply. 168 + - 169 + name: support-metric-bps 170 + type: flag 171 + doc: The device accepts 'bps' metric for bw-min, bw-max and burst. 172 + - 173 + name: support-metric-pps 174 + type: flag 175 + doc: The device accepts 'pps' metric for bw-min, bw-max and burst. 176 + - 177 + name: support-nesting 178 + type: flag 179 + doc: | 180 + The device supports nesting shaper belonging to this scope 181 + below 'node' scoped shapers. Only 'queue' and 'node' 182 + scope can have flag 'support-nesting'. 183 + - 184 + name: support-bw-min 185 + type: flag 186 + doc: The device supports a minimum guaranteed B/W. 187 + - 188 + name: support-bw-max 189 + type: flag 190 + doc: The device supports maximum B/W shaping. 191 + - 192 + name: support-burst 193 + type: flag 194 + doc: The device supports a maximum burst size. 195 + - 196 + name: support-priority 197 + type: flag 198 + doc: The device supports priority scheduling. 199 + - 200 + name: support-weight 201 + type: flag 202 + doc: The device supports weighted round robin scheduling. 203 + 204 + operations: 205 + list: 206 + - 207 + name: get 208 + doc: | 209 + Get information about a shaper for a given device. 210 + attribute-set: net-shaper 211 + 212 + do: 213 + pre: net-shaper-nl-pre-doit 214 + post: net-shaper-nl-post-doit 215 + request: 216 + attributes: &ns-binding 217 + - ifindex 218 + - handle 219 + reply: 220 + attributes: &ns-attrs 221 + - ifindex 222 + - parent 223 + - handle 224 + - metric 225 + - bw-min 226 + - bw-max 227 + - burst 228 + - priority 229 + - weight 230 + 231 + dump: 232 + pre: net-shaper-nl-pre-dumpit 233 + post: net-shaper-nl-post-dumpit 234 + request: 235 + attributes: 236 + - ifindex 237 + reply: 238 + attributes: *ns-attrs 239 + - 240 + name: set 241 + doc: | 242 + Create or update the specified shaper. 243 + The set operation can't be used to create a @node scope shaper, 244 + use the @group operation instead. 245 + attribute-set: net-shaper 246 + flags: [ admin-perm ] 247 + 248 + do: 249 + pre: net-shaper-nl-pre-doit 250 + post: net-shaper-nl-post-doit 251 + request: 252 + attributes: 253 + - ifindex 254 + - handle 255 + - metric 256 + - bw-min 257 + - bw-max 258 + - burst 259 + - priority 260 + - weight 261 + 262 + - 263 + name: delete 264 + doc: | 265 + Clear (remove) the specified shaper. When deleting 266 + a @node shaper, reattach all the node's leaves to the 267 + deleted node's parent. 268 + If, after the removal, the parent shaper has no more 269 + leaves and the parent shaper scope is @node, the parent 270 + node is deleted, recursively. 271 + When deleting a @queue shaper or a @netdev shaper, 272 + the shaper disappears from the hierarchy, but the 273 + queue/device can still send traffic: it has an implicit 274 + node with infinite bandwidth. The queue's implicit node 275 + feeds an implicit RR node at the root of the hierarchy. 276 + attribute-set: net-shaper 277 + flags: [ admin-perm ] 278 + 279 + do: 280 + pre: net-shaper-nl-pre-doit 281 + post: net-shaper-nl-post-doit 282 + request: 283 + attributes: *ns-binding 284 + 285 + - 286 + name: group 287 + doc: | 288 + Create or update a scheduling group, attaching the specified 289 + @leaves shapers under the specified node identified by @handle. 290 + The @leaves shapers scope must be @queue and the node shaper 291 + scope must be either @node or @netdev. 292 + When the node shaper has @node scope, if the @handle @id is not 293 + specified, a new shaper of such scope is created, otherwise the 294 + specified node must already exist. 295 + When updating an existing node shaper, the specified @leaves are 296 + added to the existing node; such node will also retain any preexisting 297 + leave. 298 + The @parent handle for a new node shaper defaults to the parent 299 + of all the leaves, provided all the leaves share the same parent. 300 + Otherwise @parent handle must be specified. 301 + The user can optionally provide shaping attributes for the node 302 + shaper. 303 + The operation is atomic, on failure no change is applied to 304 + the device shaping configuration, otherwise the @node shaper 305 + full identifier, comprising @binding and @handle, is provided 306 + as the reply. 307 + attribute-set: net-shaper 308 + flags: [ admin-perm ] 309 + 310 + do: 311 + pre: net-shaper-nl-pre-doit 312 + post: net-shaper-nl-post-doit 313 + request: 314 + attributes: 315 + - ifindex 316 + - parent 317 + - handle 318 + - metric 319 + - bw-min 320 + - bw-max 321 + - burst 322 + - priority 323 + - weight 324 + - leaves 325 + reply: 326 + attributes: *ns-binding 327 + 328 + - 329 + name: cap-get 330 + doc: | 331 + Get the shaper capabilities supported by the given device 332 + for the specified scope. 333 + attribute-set: caps 334 + 335 + do: 336 + pre: net-shaper-nl-cap-pre-doit 337 + post: net-shaper-nl-cap-post-doit 338 + request: 339 + attributes: 340 + - ifindex 341 + - scope 342 + reply: 343 + attributes: &cap-attrs 344 + - ifindex 345 + - scope 346 + - support-metric-bps 347 + - support-metric-pps 348 + - support-nesting 349 + - support-bw-min 350 + - support-bw-max 351 + - support-burst 352 + - support-priority 353 + - support-weight 354 + 355 + dump: 356 + pre: net-shaper-nl-cap-pre-dumpit 357 + post: net-shaper-nl-cap-post-dumpit 358 + request: 359 + attributes: 360 + - ifindex 361 + reply: 362 + attributes: *cap-attrs
+3
Documentation/networking/kapi.rst
··· 104 104 .. kernel-doc:: include/linux/netdevice.h 105 105 :internal: 106 106 107 + .. kernel-doc:: include/net/net_shaper.h 108 + :internal: 109 + 107 110 PHY Support 108 111 ----------- 109 112
+1
MAINTAINERS
··· 16116 16116 F: include/uapi/linux/cn_proc.h 16117 16117 F: include/uapi/linux/ethtool_netlink.h 16118 16118 F: include/uapi/linux/if_* 16119 + F: include/uapi/linux/net_shaper.h 16119 16120 F: include/uapi/linux/netdev* 16120 16121 F: tools/testing/selftests/drivers/net/ 16121 16122 X: Documentation/devicetree/bindings/net/bluetooth/
+1
drivers/net/Kconfig
··· 641 641 depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n 642 642 select NET_DEVLINK 643 643 select PAGE_POOL 644 + select NET_SHAPER 644 645 help 645 646 This driver is a developer testing tool and software model that can 646 647 be used to test various control path networking APIs, especially
+1
drivers/net/ethernet/intel/Kconfig
··· 258 258 config IAVF 259 259 tristate 260 260 select LIBIE 261 + select NET_SHAPER 261 262 262 263 config I40EVF 263 264 tristate "Intel(R) Ethernet Adaptive Virtual Function support"
+13
drivers/net/ethernet/intel/iavf/iavf.h
··· 34 34 #include <net/tc_act/tc_gact.h> 35 35 #include <net/tc_act/tc_mirred.h> 36 36 #include <net/tc_act/tc_skbedit.h> 37 + #include <net/net_shaper.h> 37 38 38 39 #include "iavf_type.h" 39 40 #include <linux/avf/virtchnl.h> ··· 251 250 #define IAVF_RESET_WAIT_DETECTED_COUNT 500 252 251 #define IAVF_RESET_WAIT_COMPLETE_COUNT 2000 253 252 253 + #define IAVF_MAX_QOS_TC_NUM 8 254 + #define IAVF_DEFAULT_QUANTA_SIZE 1024 255 + 254 256 /* board specific private data structure */ 255 257 struct iavf_adapter { 256 258 struct workqueue_struct *wq; ··· 340 336 #define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION BIT_ULL(36) 341 337 #define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION BIT_ULL(37) 342 338 #define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION BIT_ULL(38) 339 + #define IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW BIT_ULL(39) 340 + #define IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE BIT_ULL(40) 341 + #define IAVF_FLAG_AQ_GET_QOS_CAPS BIT_ULL(41) 343 342 344 343 /* flags for processing extended capability messages during 345 344 * __IAVF_INIT_EXTENDED_CAPS. Each capability exchange requires ··· 415 408 VIRTCHNL_VF_OFFLOAD_FDIR_PF) 416 409 #define ADV_RSS_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \ 417 410 VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF) 411 + #define QOS_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \ 412 + VIRTCHNL_VF_OFFLOAD_QOS) 418 413 struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */ 419 414 struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ 420 415 struct virtchnl_version_info pf_version; ··· 425 416 struct virtchnl_vlan_caps vlan_v2_caps; 426 417 u16 msg_enable; 427 418 struct iavf_eth_stats current_stats; 419 + struct virtchnl_qos_cap_list *qos_caps; 428 420 struct iavf_vsi vsi; 429 421 u32 aq_wait_count; 430 422 /* RSS stuff */ ··· 581 571 enum virtchnl_ops v_opcode, 582 572 enum iavf_status v_retval, u8 *msg, u16 msglen); 583 573 int iavf_config_rss(struct iavf_adapter *adapter); 574 + void iavf_cfg_queues_bw(struct iavf_adapter *adapter); 575 + void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter); 576 + void iavf_get_qos_caps(struct iavf_adapter *adapter); 584 577 void iavf_enable_channels(struct iavf_adapter *adapter); 585 578 void iavf_disable_channels(struct iavf_adapter *adapter); 586 579 void iavf_add_cloud_filter(struct iavf_adapter *adapter);
+159 -2
drivers/net/ethernet/intel/iavf/iavf_main.c
··· 1972 1972 1973 1973 adapter = container_of(work, struct iavf_adapter, finish_config); 1974 1974 1975 - /* Always take RTNL first to prevent circular lock dependency */ 1975 + /* Always take RTNL first to prevent circular lock dependency; 1976 + * The dev->lock is needed to update the queue number 1977 + */ 1976 1978 rtnl_lock(); 1979 + mutex_lock(&adapter->netdev->lock); 1977 1980 mutex_lock(&adapter->crit_lock); 1978 1981 1979 1982 if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && ··· 2020 2017 2021 2018 out: 2022 2019 mutex_unlock(&adapter->crit_lock); 2020 + mutex_unlock(&adapter->netdev->lock); 2023 2021 rtnl_unlock(); 2024 2022 } 2025 2023 ··· 2086 2082 2087 2083 if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) { 2088 2084 iavf_disable_vlan_stripping(adapter); 2085 + return 0; 2086 + } 2087 + 2088 + if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW) { 2089 + iavf_cfg_queues_bw(adapter); 2090 + return 0; 2091 + } 2092 + 2093 + if (adapter->aq_required & IAVF_FLAG_AQ_GET_QOS_CAPS) { 2094 + iavf_get_qos_caps(adapter); 2095 + return 0; 2096 + } 2097 + 2098 + if (adapter->aq_required & IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE) { 2099 + iavf_cfg_queues_quanta_size(adapter); 2089 2100 return 0; 2090 2101 } 2091 2102 ··· 2689 2670 /* request initial VLAN offload settings */ 2690 2671 iavf_set_vlan_offload_features(adapter, 0, netdev->features); 2691 2672 2673 + if (QOS_ALLOWED(adapter)) 2674 + adapter->aq_required |= IAVF_FLAG_AQ_GET_QOS_CAPS; 2675 + 2692 2676 iavf_schedule_finish_config(adapter); 2693 2677 return; 2694 2678 ··· 2941 2919 } 2942 2920 2943 2921 /** 2922 + * iavf_reconfig_qs_bw - Call-back task to handle hardware reset 2923 + * @adapter: board private structure 2924 + * 2925 + * After a reset, the shaper parameters of queues need to be replayed again. 2926 + * Since the net_shaper object inside TX rings persists across reset, 2927 + * set the update flag for all queues so that the virtchnl message is triggered 2928 + * for all queues. 2929 + **/ 2930 + static void iavf_reconfig_qs_bw(struct iavf_adapter *adapter) 2931 + { 2932 + int i, num = 0; 2933 + 2934 + for (i = 0; i < adapter->num_active_queues; i++) 2935 + if (adapter->tx_rings[i].q_shaper.bw_min || 2936 + adapter->tx_rings[i].q_shaper.bw_max) { 2937 + adapter->tx_rings[i].q_shaper_update = true; 2938 + num++; 2939 + } 2940 + 2941 + if (num) 2942 + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; 2943 + } 2944 + 2945 + /** 2944 2946 * iavf_reset_task - Call-back task to handle hardware reset 2945 2947 * @work: pointer to work_struct 2946 2948 * ··· 2990 2944 /* When device is being removed it doesn't make sense to run the reset 2991 2945 * task, just return in such a case. 2992 2946 */ 2947 + mutex_lock(&netdev->lock); 2993 2948 if (!mutex_trylock(&adapter->crit_lock)) { 2994 2949 if (adapter->state != __IAVF_REMOVE) 2995 2950 queue_work(adapter->wq, &adapter->reset_task); 2996 2951 2952 + mutex_unlock(&netdev->lock); 2997 2953 return; 2998 2954 } 2999 2955 ··· 3043 2995 reg_val); 3044 2996 iavf_disable_vf(adapter); 3045 2997 mutex_unlock(&adapter->crit_lock); 2998 + mutex_unlock(&netdev->lock); 3046 2999 return; /* Do not attempt to reinit. It's dead, Jim. */ 3047 3000 } 3048 3001 ··· 3173 3124 iavf_up_complete(adapter); 3174 3125 3175 3126 iavf_irq_enable(adapter, true); 3127 + 3128 + iavf_reconfig_qs_bw(adapter); 3176 3129 } else { 3177 3130 iavf_change_state(adapter, __IAVF_DOWN); 3178 3131 wake_up(&adapter->down_waitqueue); ··· 3184 3133 3185 3134 wake_up(&adapter->reset_waitqueue); 3186 3135 mutex_unlock(&adapter->crit_lock); 3136 + mutex_unlock(&netdev->lock); 3187 3137 3188 3138 return; 3189 3139 reset_err: ··· 3195 3143 iavf_disable_vf(adapter); 3196 3144 3197 3145 mutex_unlock(&adapter->crit_lock); 3146 + mutex_unlock(&netdev->lock); 3198 3147 dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); 3199 3148 } 3200 3149 ··· 3667 3614 if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) 3668 3615 return 0; 3669 3616 3617 + mutex_lock(&netdev->lock); 3670 3618 netif_set_real_num_rx_queues(netdev, total_qps); 3671 3619 netif_set_real_num_tx_queues(netdev, total_qps); 3620 + mutex_unlock(&netdev->lock); 3672 3621 3673 3622 return ret; 3674 3623 } ··· 4948 4893 return iavf_fix_strip_features(adapter, features); 4949 4894 } 4950 4895 4896 + static int 4897 + iavf_verify_shaper(struct net_shaper_binding *binding, 4898 + const struct net_shaper *shaper, 4899 + struct netlink_ext_ack *extack) 4900 + { 4901 + struct iavf_adapter *adapter = netdev_priv(binding->netdev); 4902 + u64 vf_max; 4903 + 4904 + if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE) { 4905 + vf_max = adapter->qos_caps->cap[0].shaper.peak; 4906 + if (vf_max && shaper->bw_max > vf_max) { 4907 + NL_SET_ERR_MSG_FMT(extack, "Max rate (%llu) of queue %d can't exceed max TX rate of VF (%llu kbps)", 4908 + shaper->bw_max, shaper->handle.id, 4909 + vf_max); 4910 + return -EINVAL; 4911 + } 4912 + } 4913 + return 0; 4914 + } 4915 + 4916 + static int 4917 + iavf_shaper_set(struct net_shaper_binding *binding, 4918 + const struct net_shaper *shaper, 4919 + struct netlink_ext_ack *extack) 4920 + { 4921 + struct iavf_adapter *adapter = netdev_priv(binding->netdev); 4922 + const struct net_shaper_handle *handle = &shaper->handle; 4923 + struct iavf_ring *tx_ring; 4924 + int ret = 0; 4925 + 4926 + mutex_lock(&adapter->crit_lock); 4927 + if (handle->id >= adapter->num_active_queues) 4928 + goto unlock; 4929 + 4930 + ret = iavf_verify_shaper(binding, shaper, extack); 4931 + if (ret) 4932 + goto unlock; 4933 + 4934 + tx_ring = &adapter->tx_rings[handle->id]; 4935 + 4936 + tx_ring->q_shaper.bw_min = div_u64(shaper->bw_min, 1000); 4937 + tx_ring->q_shaper.bw_max = div_u64(shaper->bw_max, 1000); 4938 + tx_ring->q_shaper_update = true; 4939 + 4940 + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; 4941 + 4942 + unlock: 4943 + mutex_unlock(&adapter->crit_lock); 4944 + return ret; 4945 + } 4946 + 4947 + static int iavf_shaper_del(struct net_shaper_binding *binding, 4948 + const struct net_shaper_handle *handle, 4949 + struct netlink_ext_ack *extack) 4950 + { 4951 + struct iavf_adapter *adapter = netdev_priv(binding->netdev); 4952 + struct iavf_ring *tx_ring; 4953 + 4954 + mutex_lock(&adapter->crit_lock); 4955 + if (handle->id >= adapter->num_active_queues) 4956 + goto unlock; 4957 + 4958 + tx_ring = &adapter->tx_rings[handle->id]; 4959 + tx_ring->q_shaper.bw_min = 0; 4960 + tx_ring->q_shaper.bw_max = 0; 4961 + tx_ring->q_shaper_update = true; 4962 + 4963 + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; 4964 + 4965 + unlock: 4966 + mutex_unlock(&adapter->crit_lock); 4967 + return 0; 4968 + } 4969 + 4970 + static void iavf_shaper_cap(struct net_shaper_binding *binding, 4971 + enum net_shaper_scope scope, 4972 + unsigned long *flags) 4973 + { 4974 + if (scope != NET_SHAPER_SCOPE_QUEUE) 4975 + return; 4976 + 4977 + *flags = BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MIN) | 4978 + BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX) | 4979 + BIT(NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS); 4980 + } 4981 + 4982 + static const struct net_shaper_ops iavf_shaper_ops = { 4983 + .set = iavf_shaper_set, 4984 + .delete = iavf_shaper_del, 4985 + .capabilities = iavf_shaper_cap, 4986 + }; 4987 + 4951 4988 static const struct net_device_ops iavf_netdev_ops = { 4952 4989 .ndo_open = iavf_open, 4953 4990 .ndo_stop = iavf_close, ··· 5055 4908 .ndo_fix_features = iavf_fix_features, 5056 4909 .ndo_set_features = iavf_set_features, 5057 4910 .ndo_setup_tc = iavf_setup_tc, 4911 + .net_shaper_ops = &iavf_shaper_ops, 5058 4912 }; 5059 4913 5060 4914 /** ··· 5202 5054 struct net_device *netdev; 5203 5055 struct iavf_adapter *adapter = NULL; 5204 5056 struct iavf_hw *hw = NULL; 5205 - int err; 5057 + int err, len; 5206 5058 5207 5059 err = pci_enable_device(pdev); 5208 5060 if (err) ··· 5270 5122 hw->bus.func = PCI_FUNC(pdev->devfn); 5271 5123 hw->bus.bus_id = pdev->bus->number; 5272 5124 5125 + len = struct_size(adapter->qos_caps, cap, IAVF_MAX_QOS_TC_NUM); 5126 + adapter->qos_caps = kzalloc(len, GFP_KERNEL); 5127 + if (!adapter->qos_caps) { 5128 + err = -ENOMEM; 5129 + goto err_alloc_qos_cap; 5130 + } 5131 + 5273 5132 /* set up the locks for the AQ, do this only once in probe 5274 5133 * and destroy them only once in remove 5275 5134 */ ··· 5315 5160 /* Initialization goes on in the work. Do not add more of it below. */ 5316 5161 return 0; 5317 5162 5163 + err_alloc_qos_cap: 5164 + iounmap(hw->hw_addr); 5318 5165 err_ioremap: 5319 5166 destroy_workqueue(adapter->wq); 5320 5167 err_alloc_wq:
+2
drivers/net/ethernet/intel/iavf/iavf_txrx.h
··· 296 296 */ 297 297 298 298 u32 rx_buf_len; 299 + struct net_shaper q_shaper; 300 + bool q_shaper_update; 299 301 } ____cacheline_internodealigned_in_smp; 300 302 301 303 #define IAVF_ITR_ADAPTIVE_MIN_INC 0x0002
+156 -1
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
··· 151 151 VIRTCHNL_VF_OFFLOAD_USO | 152 152 VIRTCHNL_VF_OFFLOAD_FDIR_PF | 153 153 VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF | 154 - VIRTCHNL_VF_CAP_ADV_LINK_SPEED; 154 + VIRTCHNL_VF_CAP_ADV_LINK_SPEED | 155 + VIRTCHNL_VF_OFFLOAD_QOS; 155 156 156 157 adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; 157 158 adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG; ··· 1509 1508 } 1510 1509 1511 1510 /** 1511 + * iavf_get_qos_caps - get qos caps support 1512 + * @adapter: iavf adapter struct instance 1513 + * 1514 + * This function requests PF for Supported QoS Caps. 1515 + */ 1516 + void iavf_get_qos_caps(struct iavf_adapter *adapter) 1517 + { 1518 + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { 1519 + /* bail because we already have a command pending */ 1520 + dev_err(&adapter->pdev->dev, 1521 + "Cannot get qos caps, command %d pending\n", 1522 + adapter->current_op); 1523 + return; 1524 + } 1525 + 1526 + adapter->current_op = VIRTCHNL_OP_GET_QOS_CAPS; 1527 + adapter->aq_required &= ~IAVF_FLAG_AQ_GET_QOS_CAPS; 1528 + iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_QOS_CAPS, NULL, 0); 1529 + } 1530 + 1531 + /** 1532 + * iavf_set_quanta_size - set quanta size of queue chunk 1533 + * @adapter: iavf adapter struct instance 1534 + * @quanta_size: quanta size in bytes 1535 + * @queue_index: starting index of queue chunk 1536 + * @num_queues: number of queues in the queue chunk 1537 + * 1538 + * This function requests PF to set quanta size of queue chunk 1539 + * starting at queue_index. 1540 + */ 1541 + static void 1542 + iavf_set_quanta_size(struct iavf_adapter *adapter, u16 quanta_size, 1543 + u16 queue_index, u16 num_queues) 1544 + { 1545 + struct virtchnl_quanta_cfg quanta_cfg; 1546 + 1547 + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { 1548 + /* bail because we already have a command pending */ 1549 + dev_err(&adapter->pdev->dev, 1550 + "Cannot set queue quanta size, command %d pending\n", 1551 + adapter->current_op); 1552 + return; 1553 + } 1554 + 1555 + adapter->current_op = VIRTCHNL_OP_CONFIG_QUANTA; 1556 + quanta_cfg.quanta_size = quanta_size; 1557 + quanta_cfg.queue_select.type = VIRTCHNL_QUEUE_TYPE_TX; 1558 + quanta_cfg.queue_select.start_queue_id = queue_index; 1559 + quanta_cfg.queue_select.num_queues = num_queues; 1560 + adapter->aq_required &= ~IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE; 1561 + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_QUANTA, 1562 + (u8 *)&quanta_cfg, sizeof(quanta_cfg)); 1563 + } 1564 + 1565 + /** 1566 + * iavf_cfg_queues_quanta_size - configure quanta size of queues 1567 + * @adapter: adapter structure 1568 + * 1569 + * Request that the PF configure quanta size of allocated queues. 1570 + **/ 1571 + void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter) 1572 + { 1573 + int quanta_size = IAVF_DEFAULT_QUANTA_SIZE; 1574 + 1575 + /* Set Queue Quanta Size to default */ 1576 + iavf_set_quanta_size(adapter, quanta_size, 0, 1577 + adapter->num_active_queues); 1578 + } 1579 + 1580 + /** 1581 + * iavf_cfg_queues_bw - configure bandwidth of allocated queues 1582 + * @adapter: iavf adapter structure instance 1583 + * 1584 + * This function requests PF to configure queue bandwidth of allocated queues 1585 + */ 1586 + void iavf_cfg_queues_bw(struct iavf_adapter *adapter) 1587 + { 1588 + struct virtchnl_queues_bw_cfg *qs_bw_cfg; 1589 + struct net_shaper *q_shaper; 1590 + int qs_to_update = 0; 1591 + int i, inx = 0; 1592 + size_t len; 1593 + 1594 + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { 1595 + /* bail because we already have a command pending */ 1596 + dev_err(&adapter->pdev->dev, 1597 + "Cannot set tc queue bw, command %d pending\n", 1598 + adapter->current_op); 1599 + return; 1600 + } 1601 + 1602 + for (i = 0; i < adapter->num_active_queues; i++) { 1603 + if (adapter->tx_rings[i].q_shaper_update) 1604 + qs_to_update++; 1605 + } 1606 + len = struct_size(qs_bw_cfg, cfg, qs_to_update); 1607 + qs_bw_cfg = kzalloc(len, GFP_KERNEL); 1608 + if (!qs_bw_cfg) 1609 + return; 1610 + 1611 + qs_bw_cfg->vsi_id = adapter->vsi.id; 1612 + qs_bw_cfg->num_queues = qs_to_update; 1613 + 1614 + for (i = 0; i < adapter->num_active_queues; i++) { 1615 + struct iavf_ring *tx_ring = &adapter->tx_rings[i]; 1616 + 1617 + q_shaper = &tx_ring->q_shaper; 1618 + if (tx_ring->q_shaper_update) { 1619 + qs_bw_cfg->cfg[inx].queue_id = i; 1620 + qs_bw_cfg->cfg[inx].shaper.peak = q_shaper->bw_max; 1621 + qs_bw_cfg->cfg[inx].shaper.committed = q_shaper->bw_min; 1622 + qs_bw_cfg->cfg[inx].tc = 0; 1623 + inx++; 1624 + } 1625 + } 1626 + 1627 + adapter->current_op = VIRTCHNL_OP_CONFIG_QUEUE_BW; 1628 + adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; 1629 + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_QUEUE_BW, 1630 + (u8 *)qs_bw_cfg, len); 1631 + kfree(qs_bw_cfg); 1632 + } 1633 + 1634 + /** 1512 1635 * iavf_enable_channels 1513 1636 * @adapter: adapter structure 1514 1637 * ··· 2352 2227 VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC; 2353 2228 2354 2229 break; 2230 + case VIRTCHNL_OP_GET_QOS_CAPS: 2231 + dev_warn(&adapter->pdev->dev, "Failed to Get Qos CAPs, error %s\n", 2232 + iavf_stat_str(&adapter->hw, v_retval)); 2233 + break; 2234 + case VIRTCHNL_OP_CONFIG_QUANTA: 2235 + dev_warn(&adapter->pdev->dev, "Failed to Config Quanta, error %s\n", 2236 + iavf_stat_str(&adapter->hw, v_retval)); 2237 + break; 2238 + case VIRTCHNL_OP_CONFIG_QUEUE_BW: 2239 + dev_warn(&adapter->pdev->dev, "Failed to Config Queue BW, error %s\n", 2240 + iavf_stat_str(&adapter->hw, v_retval)); 2241 + break; 2355 2242 default: 2356 2243 dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n", 2357 2244 v_retval, iavf_stat_str(&adapter->hw, v_retval), ··· 2705 2568 */ 2706 2569 if (!v_retval) 2707 2570 iavf_netdev_features_vlan_strip_set(netdev, false); 2571 + break; 2572 + case VIRTCHNL_OP_GET_QOS_CAPS: { 2573 + u16 len = struct_size(adapter->qos_caps, cap, 2574 + IAVF_MAX_QOS_TC_NUM); 2575 + 2576 + memcpy(adapter->qos_caps, msg, min(msglen, len)); 2577 + 2578 + adapter->aq_required |= IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE; 2579 + } 2580 + break; 2581 + case VIRTCHNL_OP_CONFIG_QUANTA: 2582 + break; 2583 + case VIRTCHNL_OP_CONFIG_QUEUE_BW: { 2584 + int i; 2585 + /* shaper configuration is successful for all queues */ 2586 + for (i = 0; i < adapter->num_active_queues; i++) 2587 + adapter->tx_rings[i].q_shaper_update = false; 2588 + } 2708 2589 break; 2709 2590 default: 2710 2591 if (adapter->current_op && (v_opcode != adapter->current_op))
+2
drivers/net/ethernet/intel/ice/ice.h
··· 667 667 struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES]; 668 668 struct ice_dplls dplls; 669 669 struct device *hwmon_dev; 670 + 671 + u8 num_quanta_prof_used; 670 672 }; 671 673 672 674 extern struct workqueue_struct *ice_lag_wq;
+2
drivers/net/ethernet/intel/ice/ice_base.c
··· 347 347 break; 348 348 } 349 349 350 + tlan_ctx->quanta_prof_idx = ring->quanta_prof_id; 351 + 350 352 tlan_ctx->tso_ena = ICE_TX_LEGACY; 351 353 tlan_ctx->tso_qnum = pf_q; 352 354
+21
drivers/net/ethernet/intel/ice/ice_common.c
··· 2437 2437 } 2438 2438 2439 2439 /** 2440 + * ice_func_id_to_logical_id - map from function id to logical pf id 2441 + * @active_function_bitmap: active function bitmap 2442 + * @pf_id: function number of device 2443 + * 2444 + * Return: logical PF ID. 2445 + */ 2446 + static int ice_func_id_to_logical_id(u32 active_function_bitmap, u8 pf_id) 2447 + { 2448 + u8 logical_id = 0; 2449 + u8 i; 2450 + 2451 + for (i = 0; i < pf_id; i++) 2452 + if (active_function_bitmap & BIT(i)) 2453 + logical_id++; 2454 + 2455 + return logical_id; 2456 + } 2457 + 2458 + /** 2440 2459 * ice_parse_valid_functions_cap - Parse ICE_AQC_CAPS_VALID_FUNCTIONS caps 2441 2460 * @hw: pointer to the HW struct 2442 2461 * @dev_p: pointer to device capabilities structure ··· 2472 2453 dev_p->num_funcs = hweight32(number); 2473 2454 ice_debug(hw, ICE_DBG_INIT, "dev caps: num_funcs = %d\n", 2474 2455 dev_p->num_funcs); 2456 + 2457 + hw->logical_pf_id = ice_func_id_to_logical_id(number, hw->pf_id); 2475 2458 } 2476 2459 2477 2460 /**
+8
drivers/net/ethernet/intel/ice/ice_hw_autogen.h
··· 6 6 #ifndef _ICE_HW_AUTOGEN_H_ 7 7 #define _ICE_HW_AUTOGEN_H_ 8 8 9 + #define GLCOMM_QUANTA_PROF(_i) (0x002D2D68 + ((_i) * 4)) 10 + #define GLCOMM_QUANTA_PROF_MAX_INDEX 15 11 + #define GLCOMM_QUANTA_PROF_QUANTA_SIZE_S 0 12 + #define GLCOMM_QUANTA_PROF_QUANTA_SIZE_M ICE_M(0x3FFF, 0) 13 + #define GLCOMM_QUANTA_PROF_MAX_CMD_S 16 14 + #define GLCOMM_QUANTA_PROF_MAX_CMD_M ICE_M(0xFF, 16) 15 + #define GLCOMM_QUANTA_PROF_MAX_DESC_S 24 16 + #define GLCOMM_QUANTA_PROF_MAX_DESC_M ICE_M(0x3F, 24) 9 17 #define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4)) 10 18 #define QTX_COMM_HEAD(_DBQM) (0x000E0000 + ((_DBQM) * 4)) 11 19 #define QTX_COMM_HEAD_HEAD_S 0
+1
drivers/net/ethernet/intel/ice/ice_txrx.h
··· 407 407 #define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2) 408 408 u8 flags; 409 409 u8 dcb_tc; /* Traffic class of ring */ 410 + u16 quanta_prof_id; 410 411 } ____cacheline_internodealigned_in_smp; 411 412 412 413 static inline bool ice_ring_uses_build_skb(struct ice_rx_ring *ring)
+1
drivers/net/ethernet/intel/ice/ice_type.h
··· 905 905 u8 revision_id; 906 906 907 907 u8 pf_id; /* device profile info */ 908 + u8 logical_pf_id; 908 909 909 910 u16 max_burst_size; /* driver sets this value */ 910 911
+8
drivers/net/ethernet/intel/ice/ice_vf_lib.h
··· 59 59 u64 fdir_active_cnt; 60 60 }; 61 61 62 + struct ice_vf_qs_bw { 63 + u32 committed; 64 + u32 peak; 65 + u16 queue_id; 66 + u8 tc; 67 + }; 68 + 62 69 /* VF operations */ 63 70 struct ice_vf_ops { 64 71 enum ice_disq_rst_src reset_type; ··· 147 140 struct devlink_port devlink_port; 148 141 149 142 u16 num_msix; /* num of MSI-X configured on this VF */ 143 + struct ice_vf_qs_bw qs_bw[ICE_MAX_RSS_QS_PER_VF]; 150 144 }; 151 145 152 146 /* Flags for controlling behavior of ice_reset_vf */
+335
drivers/net/ethernet/intel/ice/ice_virtchnl.c
··· 495 495 if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) 496 496 vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_USO; 497 497 498 + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_QOS) 499 + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_QOS; 500 + 498 501 vfres->num_vsis = 1; 499 502 /* Tx and Rx queue are equal for VF */ 500 503 vfres->num_queue_pairs = vsi->num_txq; ··· 1035 1032 error_param: 1036 1033 return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_HFUNC, v_ret, 1037 1034 NULL, 0); 1035 + } 1036 + 1037 + /** 1038 + * ice_vc_get_qos_caps - Get current QoS caps from PF 1039 + * @vf: pointer to the VF info 1040 + * 1041 + * Get VF's QoS capabilities, such as TC number, arbiter and 1042 + * bandwidth from PF. 1043 + * 1044 + * Return: 0 on success or negative error value. 1045 + */ 1046 + static int ice_vc_get_qos_caps(struct ice_vf *vf) 1047 + { 1048 + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 1049 + struct virtchnl_qos_cap_list *cap_list = NULL; 1050 + u8 tc_prio[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 1051 + struct virtchnl_qos_cap_elem *cfg = NULL; 1052 + struct ice_vsi_ctx *vsi_ctx; 1053 + struct ice_pf *pf = vf->pf; 1054 + struct ice_port_info *pi; 1055 + struct ice_vsi *vsi; 1056 + u8 numtc, tc; 1057 + u16 len = 0; 1058 + int ret, i; 1059 + 1060 + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 1061 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1062 + goto err; 1063 + } 1064 + 1065 + vsi = ice_get_vf_vsi(vf); 1066 + if (!vsi) { 1067 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1068 + goto err; 1069 + } 1070 + 1071 + pi = pf->hw.port_info; 1072 + numtc = vsi->tc_cfg.numtc; 1073 + 1074 + vsi_ctx = ice_get_vsi_ctx(pi->hw, vf->lan_vsi_idx); 1075 + if (!vsi_ctx) { 1076 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1077 + goto err; 1078 + } 1079 + 1080 + len = struct_size(cap_list, cap, numtc); 1081 + cap_list = kzalloc(len, GFP_KERNEL); 1082 + if (!cap_list) { 1083 + v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 1084 + len = 0; 1085 + goto err; 1086 + } 1087 + 1088 + cap_list->vsi_id = vsi->vsi_num; 1089 + cap_list->num_elem = numtc; 1090 + 1091 + /* Store the UP2TC configuration from DCB to a user priority bitmap 1092 + * of each TC. Each element of prio_of_tc represents one TC. Each 1093 + * bitmap indicates the user priorities belong to this TC. 1094 + */ 1095 + for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { 1096 + tc = pi->qos_cfg.local_dcbx_cfg.etscfg.prio_table[i]; 1097 + tc_prio[tc] |= BIT(i); 1098 + } 1099 + 1100 + for (i = 0; i < numtc; i++) { 1101 + cfg = &cap_list->cap[i]; 1102 + cfg->tc_num = i; 1103 + cfg->tc_prio = tc_prio[i]; 1104 + cfg->arbiter = pi->qos_cfg.local_dcbx_cfg.etscfg.tsatable[i]; 1105 + cfg->weight = VIRTCHNL_STRICT_WEIGHT; 1106 + cfg->type = VIRTCHNL_BW_SHAPER; 1107 + cfg->shaper.committed = vsi_ctx->sched.bw_t_info[i].cir_bw.bw; 1108 + cfg->shaper.peak = vsi_ctx->sched.bw_t_info[i].eir_bw.bw; 1109 + } 1110 + 1111 + err: 1112 + ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_QOS_CAPS, v_ret, 1113 + (u8 *)cap_list, len); 1114 + kfree(cap_list); 1115 + return ret; 1116 + } 1117 + 1118 + /** 1119 + * ice_vf_cfg_qs_bw - Configure per queue bandwidth 1120 + * @vf: pointer to the VF info 1121 + * @num_queues: number of queues to be configured 1122 + * 1123 + * Configure per queue bandwidth. 1124 + * 1125 + * Return: 0 on success or negative error value. 1126 + */ 1127 + static int ice_vf_cfg_qs_bw(struct ice_vf *vf, u16 num_queues) 1128 + { 1129 + struct ice_hw *hw = &vf->pf->hw; 1130 + struct ice_vsi *vsi; 1131 + int ret; 1132 + u16 i; 1133 + 1134 + vsi = ice_get_vf_vsi(vf); 1135 + if (!vsi) 1136 + return -EINVAL; 1137 + 1138 + for (i = 0; i < num_queues; i++) { 1139 + u32 p_rate, min_rate; 1140 + u8 tc; 1141 + 1142 + p_rate = vf->qs_bw[i].peak; 1143 + min_rate = vf->qs_bw[i].committed; 1144 + tc = vf->qs_bw[i].tc; 1145 + if (p_rate) 1146 + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, 1147 + vf->qs_bw[i].queue_id, 1148 + ICE_MAX_BW, p_rate); 1149 + else 1150 + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, 1151 + vf->qs_bw[i].queue_id, 1152 + ICE_MAX_BW); 1153 + if (ret) 1154 + return ret; 1155 + 1156 + if (min_rate) 1157 + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, 1158 + vf->qs_bw[i].queue_id, 1159 + ICE_MIN_BW, min_rate); 1160 + else 1161 + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, 1162 + vf->qs_bw[i].queue_id, 1163 + ICE_MIN_BW); 1164 + 1165 + if (ret) 1166 + return ret; 1167 + } 1168 + 1169 + return 0; 1170 + } 1171 + 1172 + /** 1173 + * ice_vf_cfg_q_quanta_profile - Configure quanta profile 1174 + * @vf: pointer to the VF info 1175 + * @quanta_prof_idx: pointer to the quanta profile index 1176 + * @quanta_size: quanta size to be set 1177 + * 1178 + * This function chooses available quanta profile and configures the register. 1179 + * The quanta profile is evenly divided by the number of device ports, and then 1180 + * available to the specific PF and VFs. The first profile for each PF is a 1181 + * reserved default profile. Only quanta size of the rest unused profile can be 1182 + * modified. 1183 + * 1184 + * Return: 0 on success or negative error value. 1185 + */ 1186 + static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size, 1187 + u16 *quanta_prof_idx) 1188 + { 1189 + const u16 n_desc = calc_quanta_desc(quanta_size); 1190 + struct ice_hw *hw = &vf->pf->hw; 1191 + const u16 n_cmd = 2 * n_desc; 1192 + struct ice_pf *pf = vf->pf; 1193 + u16 per_pf, begin_id; 1194 + u8 n_used; 1195 + u32 reg; 1196 + 1197 + begin_id = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / hw->dev_caps.num_funcs * 1198 + hw->logical_pf_id; 1199 + 1200 + if (quanta_size == ICE_DFLT_QUANTA) { 1201 + *quanta_prof_idx = begin_id; 1202 + } else { 1203 + per_pf = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / 1204 + hw->dev_caps.num_funcs; 1205 + n_used = pf->num_quanta_prof_used; 1206 + if (n_used < per_pf) { 1207 + *quanta_prof_idx = begin_id + 1 + n_used; 1208 + pf->num_quanta_prof_used++; 1209 + } else { 1210 + return -EINVAL; 1211 + } 1212 + } 1213 + 1214 + reg = FIELD_PREP(GLCOMM_QUANTA_PROF_QUANTA_SIZE_M, quanta_size) | 1215 + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_CMD_M, n_cmd) | 1216 + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_DESC_M, n_desc); 1217 + wr32(hw, GLCOMM_QUANTA_PROF(*quanta_prof_idx), reg); 1218 + 1219 + return 0; 1038 1220 } 1039 1221 1040 1222 /** ··· 1821 1633 /* send the response to the VF */ 1822 1634 return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, v_ret, 1823 1635 NULL, 0); 1636 + } 1637 + 1638 + /** 1639 + * ice_vc_cfg_q_bw - Configure per queue bandwidth 1640 + * @vf: pointer to the VF info 1641 + * @msg: pointer to the msg buffer which holds the command descriptor 1642 + * 1643 + * Configure VF queues bandwidth. 1644 + * 1645 + * Return: 0 on success or negative error value. 1646 + */ 1647 + static int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg) 1648 + { 1649 + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 1650 + struct virtchnl_queues_bw_cfg *qbw = 1651 + (struct virtchnl_queues_bw_cfg *)msg; 1652 + struct ice_vsi *vsi; 1653 + u16 i; 1654 + 1655 + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || 1656 + !ice_vc_isvalid_vsi_id(vf, qbw->vsi_id)) { 1657 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1658 + goto err; 1659 + } 1660 + 1661 + vsi = ice_get_vf_vsi(vf); 1662 + if (!vsi) { 1663 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1664 + goto err; 1665 + } 1666 + 1667 + if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF || 1668 + qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { 1669 + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", 1670 + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); 1671 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1672 + goto err; 1673 + } 1674 + 1675 + for (i = 0; i < qbw->num_queues; i++) { 1676 + if (qbw->cfg[i].shaper.peak != 0 && vf->max_tx_rate != 0 && 1677 + qbw->cfg[i].shaper.peak > vf->max_tx_rate) 1678 + dev_warn(ice_pf_to_dev(vf->pf), "The maximum queue %d rate limit configuration may not take effect because the maximum TX rate for VF-%d is %d\n", 1679 + qbw->cfg[i].queue_id, vf->vf_id, 1680 + vf->max_tx_rate); 1681 + if (qbw->cfg[i].shaper.committed != 0 && vf->min_tx_rate != 0 && 1682 + qbw->cfg[i].shaper.committed < vf->min_tx_rate) 1683 + dev_warn(ice_pf_to_dev(vf->pf), "The minimum queue %d rate limit configuration may not take effect because the minimum TX rate for VF-%d is %d\n", 1684 + qbw->cfg[i].queue_id, vf->vf_id, 1685 + vf->max_tx_rate); 1686 + } 1687 + 1688 + for (i = 0; i < qbw->num_queues; i++) { 1689 + vf->qs_bw[i].queue_id = qbw->cfg[i].queue_id; 1690 + vf->qs_bw[i].peak = qbw->cfg[i].shaper.peak; 1691 + vf->qs_bw[i].committed = qbw->cfg[i].shaper.committed; 1692 + vf->qs_bw[i].tc = qbw->cfg[i].tc; 1693 + } 1694 + 1695 + if (ice_vf_cfg_qs_bw(vf, qbw->num_queues)) 1696 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1697 + 1698 + err: 1699 + /* send the response to the VF */ 1700 + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUEUE_BW, 1701 + v_ret, NULL, 0); 1702 + } 1703 + 1704 + /** 1705 + * ice_vc_cfg_q_quanta - Configure per queue quanta 1706 + * @vf: pointer to the VF info 1707 + * @msg: pointer to the msg buffer which holds the command descriptor 1708 + * 1709 + * Configure VF queues quanta. 1710 + * 1711 + * Return: 0 on success or negative error value. 1712 + */ 1713 + static int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg) 1714 + { 1715 + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 1716 + u16 quanta_prof_id, quanta_size, start_qid, end_qid, i; 1717 + struct virtchnl_quanta_cfg *qquanta = 1718 + (struct virtchnl_quanta_cfg *)msg; 1719 + struct ice_vsi *vsi; 1720 + int ret; 1721 + 1722 + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 1723 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1724 + goto err; 1725 + } 1726 + 1727 + vsi = ice_get_vf_vsi(vf); 1728 + if (!vsi) { 1729 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1730 + goto err; 1731 + } 1732 + 1733 + end_qid = qquanta->queue_select.start_queue_id + 1734 + qquanta->queue_select.num_queues; 1735 + if (end_qid > ICE_MAX_RSS_QS_PER_VF || 1736 + end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { 1737 + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", 1738 + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); 1739 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1740 + goto err; 1741 + } 1742 + 1743 + quanta_size = qquanta->quanta_size; 1744 + if (quanta_size > ICE_MAX_QUANTA_SIZE || 1745 + quanta_size < ICE_MIN_QUANTA_SIZE) { 1746 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1747 + goto err; 1748 + } 1749 + 1750 + if (quanta_size % 64) { 1751 + dev_err(ice_pf_to_dev(vf->pf), "quanta size should be the product of 64\n"); 1752 + v_ret = VIRTCHNL_STATUS_ERR_PARAM; 1753 + goto err; 1754 + } 1755 + 1756 + ret = ice_vf_cfg_q_quanta_profile(vf, quanta_size, 1757 + &quanta_prof_id); 1758 + if (ret) { 1759 + v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; 1760 + goto err; 1761 + } 1762 + 1763 + start_qid = qquanta->queue_select.start_queue_id; 1764 + for (i = start_qid; i < end_qid; i++) 1765 + vsi->tx_rings[i]->quanta_prof_id = quanta_prof_id; 1766 + 1767 + err: 1768 + /* send the response to the VF */ 1769 + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUANTA, 1770 + v_ret, NULL, 0); 1824 1771 } 1825 1772 1826 1773 /** ··· 4142 3819 .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg, 4143 3820 .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg, 4144 3821 .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg, 3822 + .get_qos_caps = ice_vc_get_qos_caps, 3823 + .cfg_q_bw = ice_vc_cfg_q_bw, 3824 + .cfg_q_quanta = ice_vc_cfg_q_quanta, 4145 3825 }; 4146 3826 4147 3827 /** ··· 4502 4176 break; 4503 4177 case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2: 4504 4178 err = ops->dis_vlan_insertion_v2_msg(vf, msg); 4179 + break; 4180 + case VIRTCHNL_OP_GET_QOS_CAPS: 4181 + err = ops->get_qos_caps(vf); 4182 + break; 4183 + case VIRTCHNL_OP_CONFIG_QUEUE_BW: 4184 + err = ops->cfg_q_bw(vf, msg); 4185 + break; 4186 + case VIRTCHNL_OP_CONFIG_QUANTA: 4187 + err = ops->cfg_q_quanta(vf, msg); 4505 4188 break; 4506 4189 case VIRTCHNL_OP_UNKNOWN: 4507 4190 default:
+11
drivers/net/ethernet/intel/ice/ice_virtchnl.h
··· 13 13 /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */ 14 14 #define ICE_MAX_VLAN_PER_VF 8 15 15 16 + #define ICE_DFLT_QUANTA 1024 17 + #define ICE_MAX_QUANTA_SIZE 4096 18 + #define ICE_MIN_QUANTA_SIZE 256 19 + 20 + #define calc_quanta_desc(x) \ 21 + max_t(u16, 12, min_t(u16, 63, (((x) + 66) / 132) * 2 + 4)) 22 + 16 23 /* MAC filters: 1 is reserved for the VF's default/perm_addr/LAA MAC, 1 for 17 24 * broadcast, and 16 for additional unicast/multicast filters 18 25 */ ··· 68 61 int (*dis_vlan_stripping_v2_msg)(struct ice_vf *vf, u8 *msg); 69 62 int (*ena_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg); 70 63 int (*dis_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg); 64 + int (*get_qos_caps)(struct ice_vf *vf); 65 + int (*cfg_q_tc_map)(struct ice_vf *vf, u8 *msg); 66 + int (*cfg_q_bw)(struct ice_vf *vf, u8 *msg); 67 + int (*cfg_q_quanta)(struct ice_vf *vf, u8 *msg); 71 68 }; 72 69 73 70 #ifdef CONFIG_PCI_IOV
+6
drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c
··· 84 84 VIRTCHNL_OP_ADD_FDIR_FILTER, VIRTCHNL_OP_DEL_FDIR_FILTER, 85 85 }; 86 86 87 + static const u32 tc_allowlist_opcodes[] = { 88 + VIRTCHNL_OP_GET_QOS_CAPS, VIRTCHNL_OP_CONFIG_QUEUE_BW, 89 + VIRTCHNL_OP_CONFIG_QUANTA, 90 + }; 91 + 87 92 struct allowlist_opcode_info { 88 93 const u32 *opcodes; 89 94 size_t size; ··· 109 104 ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF, adv_rss_pf_allowlist_opcodes), 110 105 ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_FDIR_PF, fdir_pf_allowlist_opcodes), 111 106 ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes), 107 + ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_QOS, tc_allowlist_opcodes), 112 108 }; 113 109 114 110 /**
+2
drivers/net/netdevsim/ethtool.c
··· 103 103 struct netdevsim *ns = netdev_priv(dev); 104 104 int err; 105 105 106 + mutex_lock(&dev->lock); 106 107 err = netif_set_real_num_queues(dev, ch->combined_count, 107 108 ch->combined_count); 109 + mutex_unlock(&dev->lock); 108 110 if (err) 109 111 return err; 110 112
+39
drivers/net/netdevsim/netdev.c
··· 22 22 #include <net/netdev_queues.h> 23 23 #include <net/page_pool/helpers.h> 24 24 #include <net/netlink.h> 25 + #include <net/net_shaper.h> 25 26 #include <net/pkt_cls.h> 26 27 #include <net/rtnetlink.h> 27 28 #include <net/udp_tunnel.h> ··· 476 475 return 0; 477 476 } 478 477 478 + static int nsim_shaper_set(struct net_shaper_binding *binding, 479 + const struct net_shaper *shaper, 480 + struct netlink_ext_ack *extack) 481 + { 482 + return 0; 483 + } 484 + 485 + static int nsim_shaper_del(struct net_shaper_binding *binding, 486 + const struct net_shaper_handle *handle, 487 + struct netlink_ext_ack *extack) 488 + { 489 + return 0; 490 + } 491 + 492 + static int nsim_shaper_group(struct net_shaper_binding *binding, 493 + int leaves_count, 494 + const struct net_shaper *leaves, 495 + const struct net_shaper *root, 496 + struct netlink_ext_ack *extack) 497 + { 498 + return 0; 499 + } 500 + 501 + static void nsim_shaper_cap(struct net_shaper_binding *binding, 502 + enum net_shaper_scope scope, 503 + unsigned long *flags) 504 + { 505 + *flags = ULONG_MAX; 506 + } 507 + 508 + static const struct net_shaper_ops nsim_shaper_ops = { 509 + .set = nsim_shaper_set, 510 + .delete = nsim_shaper_del, 511 + .group = nsim_shaper_group, 512 + .capabilities = nsim_shaper_cap, 513 + }; 514 + 479 515 static const struct net_device_ops nsim_netdev_ops = { 480 516 .ndo_start_xmit = nsim_start_xmit, 481 517 .ndo_set_rx_mode = nsim_set_rx_mode, ··· 534 496 .ndo_bpf = nsim_bpf, 535 497 .ndo_open = nsim_open, 536 498 .ndo_stop = nsim_stop, 499 + .net_shaper_ops = &nsim_shaper_ops, 537 500 }; 538 501 539 502 static const struct net_device_ops nsim_vf_netdev_ops = {
+1 -1
drivers/net/vxlan/vxlan_mdb.c
··· 284 284 285 285 ASSERT_RTNL(); 286 286 287 - NL_ASSERT_DUMP_CTX_FITS(struct vxlan_mdb_dump_ctx); 287 + NL_ASSERT_CTX_FITS(struct vxlan_mdb_dump_ctx); 288 288 289 289 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, 290 290 cb->nlh->nlmsg_seq, RTM_NEWMDB, sizeof(*bpm),
+119
include/linux/avf/virtchnl.h
··· 89 89 VIRTCHNL_RX_HSPLIT_SPLIT_SCTP = 8, 90 90 }; 91 91 92 + enum virtchnl_bw_limit_type { 93 + VIRTCHNL_BW_SHAPER = 0, 94 + }; 92 95 /* END GENERIC DEFINES */ 93 96 94 97 /* Opcodes for VF-PF communication. These are placed in the v_opcode field ··· 154 151 VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2 = 55, 155 152 VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2 = 56, 156 153 VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2 = 57, 154 + /* opcode 57 - 65 are reserved */ 155 + VIRTCHNL_OP_GET_QOS_CAPS = 66, 156 + /* opcode 68 through 111 are reserved */ 157 + VIRTCHNL_OP_CONFIG_QUEUE_BW = 112, 158 + VIRTCHNL_OP_CONFIG_QUANTA = 113, 157 159 VIRTCHNL_OP_MAX, 158 160 }; 159 161 ··· 269 261 #define VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC BIT(26) 270 262 #define VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF BIT(27) 271 263 #define VIRTCHNL_VF_OFFLOAD_FDIR_PF BIT(28) 264 + #define VIRTCHNL_VF_OFFLOAD_QOS BIT(29) 272 265 273 266 #define VF_BASE_MODE_OFFLOADS (VIRTCHNL_VF_OFFLOAD_L2 | \ 274 267 VIRTCHNL_VF_OFFLOAD_VLAN | \ ··· 1425 1416 1426 1417 VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_fdir_del); 1427 1418 1419 + struct virtchnl_shaper_bw { 1420 + /* Unit is Kbps */ 1421 + u32 committed; 1422 + u32 peak; 1423 + }; 1424 + 1425 + VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_shaper_bw); 1426 + 1427 + /* VIRTCHNL_OP_GET_QOS_CAPS 1428 + * VF sends this message to get its QoS Caps, such as 1429 + * TC number, Arbiter and Bandwidth. 1430 + */ 1431 + struct virtchnl_qos_cap_elem { 1432 + u8 tc_num; 1433 + u8 tc_prio; 1434 + #define VIRTCHNL_ABITER_STRICT 0 1435 + #define VIRTCHNL_ABITER_ETS 2 1436 + u8 arbiter; 1437 + #define VIRTCHNL_STRICT_WEIGHT 1 1438 + u8 weight; 1439 + enum virtchnl_bw_limit_type type; 1440 + union { 1441 + struct virtchnl_shaper_bw shaper; 1442 + u8 pad2[32]; 1443 + }; 1444 + }; 1445 + 1446 + VIRTCHNL_CHECK_STRUCT_LEN(40, virtchnl_qos_cap_elem); 1447 + 1448 + struct virtchnl_qos_cap_list { 1449 + u16 vsi_id; 1450 + u16 num_elem; 1451 + struct virtchnl_qos_cap_elem cap[]; 1452 + }; 1453 + 1454 + VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_qos_cap_list); 1455 + #define virtchnl_qos_cap_list_LEGACY_SIZEOF 44 1456 + 1457 + /* VIRTCHNL_OP_CONFIG_QUEUE_BW */ 1458 + struct virtchnl_queue_bw { 1459 + u16 queue_id; 1460 + u8 tc; 1461 + u8 pad; 1462 + struct virtchnl_shaper_bw shaper; 1463 + }; 1464 + 1465 + VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_queue_bw); 1466 + 1467 + struct virtchnl_queues_bw_cfg { 1468 + u16 vsi_id; 1469 + u16 num_queues; 1470 + struct virtchnl_queue_bw cfg[]; 1471 + }; 1472 + 1473 + VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_queues_bw_cfg); 1474 + #define virtchnl_queues_bw_cfg_LEGACY_SIZEOF 16 1475 + 1476 + enum virtchnl_queue_type { 1477 + VIRTCHNL_QUEUE_TYPE_TX = 0, 1478 + VIRTCHNL_QUEUE_TYPE_RX = 1, 1479 + }; 1480 + 1481 + /* structure to specify a chunk of contiguous queues */ 1482 + struct virtchnl_queue_chunk { 1483 + /* see enum virtchnl_queue_type */ 1484 + s32 type; 1485 + u16 start_queue_id; 1486 + u16 num_queues; 1487 + }; 1488 + 1489 + VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_queue_chunk); 1490 + 1491 + struct virtchnl_quanta_cfg { 1492 + u16 quanta_size; 1493 + struct virtchnl_queue_chunk queue_select; 1494 + }; 1495 + 1496 + VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_quanta_cfg); 1497 + 1428 1498 #define __vss_byone(p, member, count, old) \ 1429 1499 (struct_size(p, member, count) + (old - 1 - struct_size(p, member, 0))) 1430 1500 ··· 1526 1438 __vss(virtchnl_vlan_filter_list_v2, __vss_byelem, p, m, c), \ 1527 1439 __vss(virtchnl_tc_info, __vss_byelem, p, m, c), \ 1528 1440 __vss(virtchnl_rdma_qvlist_info, __vss_byelem, p, m, c), \ 1441 + __vss(virtchnl_qos_cap_list, __vss_byelem, p, m, c), \ 1442 + __vss(virtchnl_queues_bw_cfg, __vss_byelem, p, m, c), \ 1529 1443 __vss(virtchnl_rss_key, __vss_byone, p, m, c), \ 1530 1444 __vss(virtchnl_rss_lut, __vss_byone, p, m, c)) 1531 1445 ··· 1726 1636 case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2: 1727 1637 case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2: 1728 1638 valid_len = sizeof(struct virtchnl_vlan_setting); 1639 + break; 1640 + case VIRTCHNL_OP_GET_QOS_CAPS: 1641 + break; 1642 + case VIRTCHNL_OP_CONFIG_QUEUE_BW: 1643 + valid_len = virtchnl_queues_bw_cfg_LEGACY_SIZEOF; 1644 + if (msglen >= valid_len) { 1645 + struct virtchnl_queues_bw_cfg *q_bw = 1646 + (struct virtchnl_queues_bw_cfg *)msg; 1647 + 1648 + valid_len = virtchnl_struct_size(q_bw, cfg, 1649 + q_bw->num_queues); 1650 + if (q_bw->num_queues == 0) { 1651 + err_msg_format = true; 1652 + break; 1653 + } 1654 + } 1655 + break; 1656 + case VIRTCHNL_OP_CONFIG_QUANTA: 1657 + valid_len = sizeof(struct virtchnl_quanta_cfg); 1658 + if (msglen >= valid_len) { 1659 + struct virtchnl_quanta_cfg *q_quanta = 1660 + (struct virtchnl_quanta_cfg *)msg; 1661 + 1662 + if (q_quanta->quanta_size == 0 || 1663 + q_quanta->queue_select.num_queues == 0) { 1664 + err_msg_format = true; 1665 + break; 1666 + } 1667 + } 1729 1668 break; 1730 1669 /* These are always errors coming from the VF. */ 1731 1670 case VIRTCHNL_OP_EVENT:
+21
include/linux/netdevice.h
··· 1603 1603 int (*ndo_hwtstamp_set)(struct net_device *dev, 1604 1604 struct kernel_hwtstamp_config *kernel_config, 1605 1605 struct netlink_ext_ack *extack); 1606 + 1607 + #if IS_ENABLED(CONFIG_NET_SHAPER) 1608 + /** 1609 + * @net_shaper_ops: Device shaping offload operations 1610 + * see include/net/net_shapers.h 1611 + */ 1612 + const struct net_shaper_ops *net_shaper_ops; 1613 + #endif 1606 1614 }; 1607 1615 1608 1616 /** ··· 2414 2406 2415 2407 u64 max_pacing_offload_horizon; 2416 2408 2409 + /** 2410 + * @lock: protects @net_shaper_hierarchy, feel free to use for other 2411 + * netdev-scope protection. Ordering: take after rtnl_lock. 2412 + */ 2413 + struct mutex lock; 2414 + 2415 + #if IS_ENABLED(CONFIG_NET_SHAPER) 2416 + /** 2417 + * @net_shaper_hierarchy: data tracking the current shaper status 2418 + * see include/net/net_shapers.h 2419 + */ 2420 + struct net_shaper_hierarchy *net_shaper_hierarchy; 2421 + #endif 2417 2422 u8 priv[] ____cacheline_aligned 2418 2423 __counted_by(priv_len); 2419 2424 } ____cacheline_aligned;
+3 -2
include/linux/netlink.h
··· 34 34 35 35 #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) 36 36 #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) 37 + #define NETLINK_CTX_SIZE 48 37 38 38 39 39 40 void netlink_table_grab(void); ··· 294 293 int flags; 295 294 bool strict_check; 296 295 union { 297 - u8 ctx[48]; 296 + u8 ctx[NETLINK_CTX_SIZE]; 298 297 299 298 /* args is deprecated. Cast a struct over ctx instead 300 299 * for proper type safety. ··· 303 302 }; 304 303 }; 305 304 306 - #define NL_ASSERT_DUMP_CTX_FITS(type_name) \ 305 + #define NL_ASSERT_CTX_FITS(type_name) \ 307 306 BUILD_BUG_ON(sizeof(type_name) > \ 308 307 sizeof_field(struct netlink_callback, ctx)) 309 308
+6 -2
include/net/genetlink.h
··· 124 124 * @genlhdr: generic netlink message header 125 125 * @attrs: netlink attributes 126 126 * @_net: network namespace 127 - * @user_ptr: user pointers 127 + * @ctx: storage space for the use by the family 128 + * @user_ptr: user pointers (deprecated, use ctx instead) 128 129 * @extack: extended ACK report struct 129 130 */ 130 131 struct genl_info { ··· 136 135 struct genlmsghdr * genlhdr; 137 136 struct nlattr ** attrs; 138 137 possible_net_t _net; 139 - void * user_ptr[2]; 138 + union { 139 + u8 ctx[NETLINK_CTX_SIZE]; 140 + void * user_ptr[2]; 141 + }; 140 142 struct netlink_ext_ack *extack; 141 143 }; 142 144
+120
include/net/net_shaper.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + 3 + #ifndef _NET_SHAPER_H_ 4 + #define _NET_SHAPER_H_ 5 + 6 + #include <linux/types.h> 7 + 8 + #include <uapi/linux/net_shaper.h> 9 + 10 + struct net_device; 11 + struct devlink; 12 + struct netlink_ext_ack; 13 + 14 + enum net_shaper_binding_type { 15 + NET_SHAPER_BINDING_TYPE_NETDEV, 16 + /* NET_SHAPER_BINDING_TYPE_DEVLINK_PORT */ 17 + }; 18 + 19 + struct net_shaper_binding { 20 + enum net_shaper_binding_type type; 21 + union { 22 + struct net_device *netdev; 23 + struct devlink *devlink; 24 + }; 25 + }; 26 + 27 + struct net_shaper_handle { 28 + enum net_shaper_scope scope; 29 + u32 id; 30 + }; 31 + 32 + /** 33 + * struct net_shaper - represents a shaping node on the NIC H/W 34 + * zeroed field are considered not set. 35 + * @parent: Unique identifier for the shaper parent, usually implied 36 + * @handle: Unique identifier for this shaper 37 + * @metric: Specify if the rate limits refers to PPS or BPS 38 + * @bw_min: Minimum guaranteed rate for this shaper 39 + * @bw_max: Maximum peak rate allowed for this shaper 40 + * @burst: Maximum burst for the peek rate of this shaper 41 + * @priority: Scheduling priority for this shaper 42 + * @weight: Scheduling weight for this shaper 43 + */ 44 + struct net_shaper { 45 + struct net_shaper_handle parent; 46 + struct net_shaper_handle handle; 47 + enum net_shaper_metric metric; 48 + u64 bw_min; 49 + u64 bw_max; 50 + u64 burst; 51 + u32 priority; 52 + u32 weight; 53 + 54 + /* private: */ 55 + u32 leaves; /* accounted only for NODE scope */ 56 + struct rcu_head rcu; 57 + }; 58 + 59 + /** 60 + * struct net_shaper_ops - Operations on device H/W shapers 61 + * 62 + * The operations applies to either net_device and devlink objects. 63 + * The initial shaping configuration at device initialization is empty: 64 + * does not constraint the rate in any way. 65 + * The network core keeps track of the applied user-configuration in 66 + * the net_device or devlink structure. 67 + * The operations are serialized via a per device lock. 68 + * 69 + * Device not supporting any kind of nesting should not provide the 70 + * group operation. 71 + * 72 + * Each shaper is uniquely identified within the device with a 'handle' 73 + * comprising the shaper scope and a scope-specific id. 74 + */ 75 + struct net_shaper_ops { 76 + /** 77 + * @group: create the specified shapers scheduling group 78 + * 79 + * Nest the @leaves shapers identified under the * @node shaper. 80 + * All the shapers belong to the device specified by @binding. 81 + * The @leaves arrays size is specified by @leaves_count. 82 + * Create either the @leaves and the @node shaper; or if they already 83 + * exists, links them together in the desired way. 84 + * @leaves scope must be NET_SHAPER_SCOPE_QUEUE. 85 + */ 86 + int (*group)(struct net_shaper_binding *binding, int leaves_count, 87 + const struct net_shaper *leaves, 88 + const struct net_shaper *node, 89 + struct netlink_ext_ack *extack); 90 + 91 + /** 92 + * @set: Updates the specified shaper 93 + * 94 + * Updates or creates the @shaper on the device specified by @binding. 95 + */ 96 + int (*set)(struct net_shaper_binding *binding, 97 + const struct net_shaper *shaper, 98 + struct netlink_ext_ack *extack); 99 + 100 + /** 101 + * @delete: Removes the specified shaper 102 + * 103 + * Removes the shaper configuration as identified by the given @handle 104 + * on the device specified by @binding, restoring the default behavior. 105 + */ 106 + int (*delete)(struct net_shaper_binding *binding, 107 + const struct net_shaper_handle *handle, 108 + struct netlink_ext_ack *extack); 109 + 110 + /** 111 + * @capabilities: get the shaper features supported by the device 112 + * 113 + * Fills the bitmask @cap with the supported capabilities for the 114 + * specified @scope and device specified by @binding. 115 + */ 116 + void (*capabilities)(struct net_shaper_binding *binding, 117 + enum net_shaper_scope scope, unsigned long *cap); 118 + }; 119 + 120 + #endif
+95
include/uapi/linux/net_shaper.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/net_shaper.yaml */ 4 + /* YNL-GEN uapi header */ 5 + 6 + #ifndef _UAPI_LINUX_NET_SHAPER_H 7 + #define _UAPI_LINUX_NET_SHAPER_H 8 + 9 + #define NET_SHAPER_FAMILY_NAME "net-shaper" 10 + #define NET_SHAPER_FAMILY_VERSION 1 11 + 12 + /** 13 + * enum net_shaper_scope - Defines the shaper @id interpretation. 14 + * @NET_SHAPER_SCOPE_UNSPEC: The scope is not specified. 15 + * @NET_SHAPER_SCOPE_NETDEV: The main shaper for the given network device. 16 + * @NET_SHAPER_SCOPE_QUEUE: The shaper is attached to the given device queue, 17 + * the @id represents the queue number. 18 + * @NET_SHAPER_SCOPE_NODE: The shaper allows grouping of queues or other node 19 + * shapers; can be nested in either @netdev shapers or other @node shapers, 20 + * allowing placement in any location of the scheduling tree, except leaves 21 + * and root. 22 + */ 23 + enum net_shaper_scope { 24 + NET_SHAPER_SCOPE_UNSPEC, 25 + NET_SHAPER_SCOPE_NETDEV, 26 + NET_SHAPER_SCOPE_QUEUE, 27 + NET_SHAPER_SCOPE_NODE, 28 + 29 + /* private: */ 30 + __NET_SHAPER_SCOPE_MAX, 31 + NET_SHAPER_SCOPE_MAX = (__NET_SHAPER_SCOPE_MAX - 1) 32 + }; 33 + 34 + /** 35 + * enum net_shaper_metric - Different metric supported by the shaper. 36 + * @NET_SHAPER_METRIC_BPS: Shaper operates on a bits per second basis. 37 + * @NET_SHAPER_METRIC_PPS: Shaper operates on a packets per second basis. 38 + */ 39 + enum net_shaper_metric { 40 + NET_SHAPER_METRIC_BPS, 41 + NET_SHAPER_METRIC_PPS, 42 + }; 43 + 44 + enum { 45 + NET_SHAPER_A_HANDLE = 1, 46 + NET_SHAPER_A_METRIC, 47 + NET_SHAPER_A_BW_MIN, 48 + NET_SHAPER_A_BW_MAX, 49 + NET_SHAPER_A_BURST, 50 + NET_SHAPER_A_PRIORITY, 51 + NET_SHAPER_A_WEIGHT, 52 + NET_SHAPER_A_IFINDEX, 53 + NET_SHAPER_A_PARENT, 54 + NET_SHAPER_A_LEAVES, 55 + 56 + __NET_SHAPER_A_MAX, 57 + NET_SHAPER_A_MAX = (__NET_SHAPER_A_MAX - 1) 58 + }; 59 + 60 + enum { 61 + NET_SHAPER_A_HANDLE_SCOPE = 1, 62 + NET_SHAPER_A_HANDLE_ID, 63 + 64 + __NET_SHAPER_A_HANDLE_MAX, 65 + NET_SHAPER_A_HANDLE_MAX = (__NET_SHAPER_A_HANDLE_MAX - 1) 66 + }; 67 + 68 + enum { 69 + NET_SHAPER_A_CAPS_IFINDEX = 1, 70 + NET_SHAPER_A_CAPS_SCOPE, 71 + NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS, 72 + NET_SHAPER_A_CAPS_SUPPORT_METRIC_PPS, 73 + NET_SHAPER_A_CAPS_SUPPORT_NESTING, 74 + NET_SHAPER_A_CAPS_SUPPORT_BW_MIN, 75 + NET_SHAPER_A_CAPS_SUPPORT_BW_MAX, 76 + NET_SHAPER_A_CAPS_SUPPORT_BURST, 77 + NET_SHAPER_A_CAPS_SUPPORT_PRIORITY, 78 + NET_SHAPER_A_CAPS_SUPPORT_WEIGHT, 79 + 80 + __NET_SHAPER_A_CAPS_MAX, 81 + NET_SHAPER_A_CAPS_MAX = (__NET_SHAPER_A_CAPS_MAX - 1) 82 + }; 83 + 84 + enum { 85 + NET_SHAPER_CMD_GET = 1, 86 + NET_SHAPER_CMD_SET, 87 + NET_SHAPER_CMD_DELETE, 88 + NET_SHAPER_CMD_GROUP, 89 + NET_SHAPER_CMD_CAP_GET, 90 + 91 + __NET_SHAPER_CMD_MAX, 92 + NET_SHAPER_CMD_MAX = (__NET_SHAPER_CMD_MAX - 1) 93 + }; 94 + 95 + #endif /* _UAPI_LINUX_NET_SHAPER_H */
+3
net/Kconfig
··· 72 72 depends on GENERIC_ALLOCATOR 73 73 depends on PAGE_POOL 74 74 75 + config NET_SHAPER 76 + bool 77 + 75 78 menu "Networking options" 76 79 77 80 source "net/packet/Kconfig"
+1
net/Makefile
··· 79 79 obj-$(CONFIG_MPTCP) += mptcp/ 80 80 obj-$(CONFIG_MCTP) += mctp/ 81 81 obj-$(CONFIG_NET_HANDSHAKE) += handshake/ 82 + obj-$(CONFIG_NET_SHAPER) += shaper/
+8
net/core/dev.c
··· 2949 2949 if (dev->num_tc) 2950 2950 netif_setup_tc(dev, txq); 2951 2951 2952 + net_shaper_set_real_num_tx_queues(dev, txq); 2953 + 2952 2954 dev_qdisc_change_real_num_tx(dev, txq); 2953 2955 2954 2956 dev->real_num_tx_queues = txq; ··· 11149 11147 hash_init(dev->qdisc_hash); 11150 11148 #endif 11151 11149 11150 + mutex_init(&dev->lock); 11151 + 11152 11152 dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; 11153 11153 setup(dev); 11154 11154 ··· 11220 11216 dev->needs_free_netdev = true; 11221 11217 return; 11222 11218 } 11219 + 11220 + mutex_destroy(&dev->lock); 11223 11221 11224 11222 kfree(dev->ethtool); 11225 11223 netif_free_tx_queues(dev); ··· 11431 11425 dev->netdev_ops->ndo_uninit(dev); 11432 11426 11433 11427 mutex_destroy(&dev->ethtool->rss_lock); 11428 + 11429 + net_shaper_flush_netdev(dev); 11434 11430 11435 11431 if (skb) 11436 11432 rtmsg_ifinfo_send(skb, dev, GFP_KERNEL, portid, nlh);
+10
net/core/dev.h
··· 35 35 int dev_addr_init(struct net_device *dev); 36 36 void dev_addr_check(struct net_device *dev); 37 37 38 + #if IS_ENABLED(CONFIG_NET_SHAPER) 39 + void net_shaper_flush_netdev(struct net_device *dev); 40 + void net_shaper_set_real_num_tx_queues(struct net_device *dev, 41 + unsigned int txq); 42 + #else 43 + static inline void net_shaper_flush_netdev(struct net_device *dev) {} 44 + static inline void net_shaper_set_real_num_tx_queues(struct net_device *dev, 45 + unsigned int txq) {} 46 + #endif 47 + 38 48 /* sysctls not referred to from outside net/core/ */ 39 49 extern int netdev_unregister_timeout_secs; 40 50 extern int weight_p;
+1 -1
net/core/netdev-genl.c
··· 24 24 25 25 static struct netdev_nl_dump_ctx *netdev_dump_ctx(struct netlink_callback *cb) 26 26 { 27 - NL_ASSERT_DUMP_CTX_FITS(struct netdev_nl_dump_ctx); 27 + NL_ASSERT_CTX_FITS(struct netdev_nl_dump_ctx); 28 28 29 29 return (struct netdev_nl_dump_ctx *)cb->ctx; 30 30 }
+1 -1
net/core/rtnetlink.c
··· 6243 6243 int idx, s_idx; 6244 6244 int err; 6245 6245 6246 - NL_ASSERT_DUMP_CTX_FITS(struct rtnl_mdb_dump_ctx); 6246 + NL_ASSERT_CTX_FITS(struct rtnl_mdb_dump_ctx); 6247 6247 6248 6248 if (cb->strict_check) { 6249 6249 err = rtnl_mdb_valid_dump_req(cb->nlh, cb->extack);
+1 -1
net/devlink/devl_internal.h
··· 166 166 static inline struct devlink_nl_dump_state * 167 167 devlink_dump_state(struct netlink_callback *cb) 168 168 { 169 - NL_ASSERT_DUMP_CTX_FITS(struct devlink_nl_dump_state); 169 + NL_ASSERT_CTX_FITS(struct devlink_nl_dump_state); 170 170 171 171 return (struct devlink_nl_dump_state *)cb->ctx; 172 172 }
+1 -1
net/ethtool/rss.c
··· 224 224 225 225 static struct rss_nl_dump_ctx *rss_dump_ctx(struct netlink_callback *cb) 226 226 { 227 - NL_ASSERT_DUMP_CTX_FITS(struct rss_nl_dump_ctx); 227 + NL_ASSERT_CTX_FITS(struct rss_nl_dump_ctx); 228 228 229 229 return (struct rss_nl_dump_ctx *)cb->ctx; 230 230 }
+1 -1
net/netfilter/nf_conntrack_netlink.c
··· 3870 3870 { 3871 3871 int ret; 3872 3872 3873 - NL_ASSERT_DUMP_CTX_FITS(struct ctnetlink_list_dump_ctx); 3873 + NL_ASSERT_CTX_FITS(struct ctnetlink_list_dump_ctx); 3874 3874 3875 3875 ret = nfnetlink_subsys_register(&ctnl_subsys); 3876 3876 if (ret < 0) {
+2 -2
net/netlink/genetlink.c
··· 997 997 info->info.attrs = attrs; 998 998 genl_info_net_set(&info->info, sock_net(cb->skb->sk)); 999 999 info->info.extack = cb->extack; 1000 - memset(&info->info.user_ptr, 0, sizeof(info->info.user_ptr)); 1000 + memset(&info->info.ctx, 0, sizeof(info->info.ctx)); 1001 1001 1002 1002 cb->data = info; 1003 1003 if (ops->start) { ··· 1104 1104 info.attrs = attrbuf; 1105 1105 info.extack = extack; 1106 1106 genl_info_net_set(&info, net); 1107 - memset(&info.user_ptr, 0, sizeof(info.user_ptr)); 1107 + memset(&info.ctx, 0, sizeof(info.ctx)); 1108 1108 1109 1109 if (ops->pre_doit) { 1110 1110 err = ops->pre_doit(ops, skb, &info);
+8
net/shaper/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Makefile for the net shaper infrastructure. 4 + # 5 + # Copyright (c) 2024, Red Hat, Inc. 6 + # 7 + 8 + obj-y += shaper.o shaper_nl_gen.o
+1438
net/shaper/shaper.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <linux/bits.h> 4 + #include <linux/bitfield.h> 5 + #include <linux/idr.h> 6 + #include <linux/kernel.h> 7 + #include <linux/netdevice.h> 8 + #include <linux/netlink.h> 9 + #include <linux/skbuff.h> 10 + #include <linux/xarray.h> 11 + #include <net/devlink.h> 12 + #include <net/net_shaper.h> 13 + 14 + #include "shaper_nl_gen.h" 15 + 16 + #include "../core/dev.h" 17 + 18 + #define NET_SHAPER_SCOPE_SHIFT 26 19 + #define NET_SHAPER_ID_MASK GENMASK(NET_SHAPER_SCOPE_SHIFT - 1, 0) 20 + #define NET_SHAPER_SCOPE_MASK GENMASK(31, NET_SHAPER_SCOPE_SHIFT) 21 + 22 + #define NET_SHAPER_ID_UNSPEC NET_SHAPER_ID_MASK 23 + 24 + struct net_shaper_hierarchy { 25 + struct xarray shapers; 26 + }; 27 + 28 + struct net_shaper_nl_ctx { 29 + struct net_shaper_binding binding; 30 + netdevice_tracker dev_tracker; 31 + unsigned long start_index; 32 + }; 33 + 34 + static struct net_shaper_binding *net_shaper_binding_from_ctx(void *ctx) 35 + { 36 + return &((struct net_shaper_nl_ctx *)ctx)->binding; 37 + } 38 + 39 + static void net_shaper_lock(struct net_shaper_binding *binding) 40 + { 41 + switch (binding->type) { 42 + case NET_SHAPER_BINDING_TYPE_NETDEV: 43 + mutex_lock(&binding->netdev->lock); 44 + break; 45 + } 46 + } 47 + 48 + static void net_shaper_unlock(struct net_shaper_binding *binding) 49 + { 50 + switch (binding->type) { 51 + case NET_SHAPER_BINDING_TYPE_NETDEV: 52 + mutex_unlock(&binding->netdev->lock); 53 + break; 54 + } 55 + } 56 + 57 + static struct net_shaper_hierarchy * 58 + net_shaper_hierarchy(struct net_shaper_binding *binding) 59 + { 60 + /* Pairs with WRITE_ONCE() in net_shaper_hierarchy_setup. */ 61 + if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV) 62 + return READ_ONCE(binding->netdev->net_shaper_hierarchy); 63 + 64 + /* No other type supported yet. */ 65 + return NULL; 66 + } 67 + 68 + static const struct net_shaper_ops * 69 + net_shaper_ops(struct net_shaper_binding *binding) 70 + { 71 + if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV) 72 + return binding->netdev->netdev_ops->net_shaper_ops; 73 + 74 + /* No other type supported yet. */ 75 + return NULL; 76 + } 77 + 78 + /* Count the number of [multi] attributes of the given type. */ 79 + static int net_shaper_list_len(struct genl_info *info, int type) 80 + { 81 + struct nlattr *attr; 82 + int rem, cnt = 0; 83 + 84 + nla_for_each_attr_type(attr, type, genlmsg_data(info->genlhdr), 85 + genlmsg_len(info->genlhdr), rem) 86 + cnt++; 87 + return cnt; 88 + } 89 + 90 + static int net_shaper_handle_size(void) 91 + { 92 + return nla_total_size(nla_total_size(sizeof(u32)) + 93 + nla_total_size(sizeof(u32))); 94 + } 95 + 96 + static int net_shaper_fill_binding(struct sk_buff *msg, 97 + const struct net_shaper_binding *binding, 98 + u32 type) 99 + { 100 + /* Should never happen, as currently only NETDEV is supported. */ 101 + if (WARN_ON_ONCE(binding->type != NET_SHAPER_BINDING_TYPE_NETDEV)) 102 + return -EINVAL; 103 + 104 + if (nla_put_u32(msg, type, binding->netdev->ifindex)) 105 + return -EMSGSIZE; 106 + 107 + return 0; 108 + } 109 + 110 + static int net_shaper_fill_handle(struct sk_buff *msg, 111 + const struct net_shaper_handle *handle, 112 + u32 type) 113 + { 114 + struct nlattr *handle_attr; 115 + 116 + if (handle->scope == NET_SHAPER_SCOPE_UNSPEC) 117 + return 0; 118 + 119 + handle_attr = nla_nest_start(msg, type); 120 + if (!handle_attr) 121 + return -EMSGSIZE; 122 + 123 + if (nla_put_u32(msg, NET_SHAPER_A_HANDLE_SCOPE, handle->scope) || 124 + (handle->scope >= NET_SHAPER_SCOPE_QUEUE && 125 + nla_put_u32(msg, NET_SHAPER_A_HANDLE_ID, handle->id))) 126 + goto handle_nest_cancel; 127 + 128 + nla_nest_end(msg, handle_attr); 129 + return 0; 130 + 131 + handle_nest_cancel: 132 + nla_nest_cancel(msg, handle_attr); 133 + return -EMSGSIZE; 134 + } 135 + 136 + static int 137 + net_shaper_fill_one(struct sk_buff *msg, 138 + const struct net_shaper_binding *binding, 139 + const struct net_shaper *shaper, 140 + const struct genl_info *info) 141 + { 142 + void *hdr; 143 + 144 + hdr = genlmsg_iput(msg, info); 145 + if (!hdr) 146 + return -EMSGSIZE; 147 + 148 + if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_IFINDEX) || 149 + net_shaper_fill_handle(msg, &shaper->parent, 150 + NET_SHAPER_A_PARENT) || 151 + net_shaper_fill_handle(msg, &shaper->handle, 152 + NET_SHAPER_A_HANDLE) || 153 + ((shaper->bw_min || shaper->bw_max || shaper->burst) && 154 + nla_put_u32(msg, NET_SHAPER_A_METRIC, shaper->metric)) || 155 + (shaper->bw_min && 156 + nla_put_uint(msg, NET_SHAPER_A_BW_MIN, shaper->bw_min)) || 157 + (shaper->bw_max && 158 + nla_put_uint(msg, NET_SHAPER_A_BW_MAX, shaper->bw_max)) || 159 + (shaper->burst && 160 + nla_put_uint(msg, NET_SHAPER_A_BURST, shaper->burst)) || 161 + (shaper->priority && 162 + nla_put_u32(msg, NET_SHAPER_A_PRIORITY, shaper->priority)) || 163 + (shaper->weight && 164 + nla_put_u32(msg, NET_SHAPER_A_WEIGHT, shaper->weight))) 165 + goto nla_put_failure; 166 + 167 + genlmsg_end(msg, hdr); 168 + 169 + return 0; 170 + 171 + nla_put_failure: 172 + genlmsg_cancel(msg, hdr); 173 + return -EMSGSIZE; 174 + } 175 + 176 + /* Initialize the context fetching the relevant device and 177 + * acquiring a reference to it. 178 + */ 179 + static int net_shaper_ctx_setup(const struct genl_info *info, int type, 180 + struct net_shaper_nl_ctx *ctx) 181 + { 182 + struct net *ns = genl_info_net(info); 183 + struct net_device *dev; 184 + int ifindex; 185 + 186 + if (GENL_REQ_ATTR_CHECK(info, type)) 187 + return -EINVAL; 188 + 189 + ifindex = nla_get_u32(info->attrs[type]); 190 + dev = netdev_get_by_index(ns, ifindex, &ctx->dev_tracker, GFP_KERNEL); 191 + if (!dev) { 192 + NL_SET_BAD_ATTR(info->extack, info->attrs[type]); 193 + return -ENOENT; 194 + } 195 + 196 + if (!dev->netdev_ops->net_shaper_ops) { 197 + NL_SET_BAD_ATTR(info->extack, info->attrs[type]); 198 + netdev_put(dev, &ctx->dev_tracker); 199 + return -EOPNOTSUPP; 200 + } 201 + 202 + ctx->binding.type = NET_SHAPER_BINDING_TYPE_NETDEV; 203 + ctx->binding.netdev = dev; 204 + return 0; 205 + } 206 + 207 + static void net_shaper_ctx_cleanup(struct net_shaper_nl_ctx *ctx) 208 + { 209 + if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV) 210 + netdev_put(ctx->binding.netdev, &ctx->dev_tracker); 211 + } 212 + 213 + static u32 net_shaper_handle_to_index(const struct net_shaper_handle *handle) 214 + { 215 + return FIELD_PREP(NET_SHAPER_SCOPE_MASK, handle->scope) | 216 + FIELD_PREP(NET_SHAPER_ID_MASK, handle->id); 217 + } 218 + 219 + static void net_shaper_index_to_handle(u32 index, 220 + struct net_shaper_handle *handle) 221 + { 222 + handle->scope = FIELD_GET(NET_SHAPER_SCOPE_MASK, index); 223 + handle->id = FIELD_GET(NET_SHAPER_ID_MASK, index); 224 + } 225 + 226 + static void net_shaper_default_parent(const struct net_shaper_handle *handle, 227 + struct net_shaper_handle *parent) 228 + { 229 + switch (handle->scope) { 230 + case NET_SHAPER_SCOPE_UNSPEC: 231 + case NET_SHAPER_SCOPE_NETDEV: 232 + case __NET_SHAPER_SCOPE_MAX: 233 + parent->scope = NET_SHAPER_SCOPE_UNSPEC; 234 + break; 235 + 236 + case NET_SHAPER_SCOPE_QUEUE: 237 + case NET_SHAPER_SCOPE_NODE: 238 + parent->scope = NET_SHAPER_SCOPE_NETDEV; 239 + break; 240 + } 241 + parent->id = 0; 242 + } 243 + 244 + /* 245 + * MARK_0 is already in use due to XA_FLAGS_ALLOC, can't reuse such flag as 246 + * it's cleared by xa_store(). 247 + */ 248 + #define NET_SHAPER_NOT_VALID XA_MARK_1 249 + 250 + static struct net_shaper * 251 + net_shaper_lookup(struct net_shaper_binding *binding, 252 + const struct net_shaper_handle *handle) 253 + { 254 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 255 + u32 index = net_shaper_handle_to_index(handle); 256 + 257 + if (!hierarchy || xa_get_mark(&hierarchy->shapers, index, 258 + NET_SHAPER_NOT_VALID)) 259 + return NULL; 260 + 261 + return xa_load(&hierarchy->shapers, index); 262 + } 263 + 264 + /* Allocate on demand the per device shaper's hierarchy container. 265 + * Called under the net shaper lock 266 + */ 267 + static struct net_shaper_hierarchy * 268 + net_shaper_hierarchy_setup(struct net_shaper_binding *binding) 269 + { 270 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 271 + 272 + if (hierarchy) 273 + return hierarchy; 274 + 275 + hierarchy = kmalloc(sizeof(*hierarchy), GFP_KERNEL); 276 + if (!hierarchy) 277 + return NULL; 278 + 279 + /* The flag is required for ID allocation */ 280 + xa_init_flags(&hierarchy->shapers, XA_FLAGS_ALLOC); 281 + 282 + switch (binding->type) { 283 + case NET_SHAPER_BINDING_TYPE_NETDEV: 284 + /* Pairs with READ_ONCE in net_shaper_hierarchy. */ 285 + WRITE_ONCE(binding->netdev->net_shaper_hierarchy, hierarchy); 286 + break; 287 + } 288 + return hierarchy; 289 + } 290 + 291 + /* Prepare the hierarchy container to actually insert the given shaper, doing 292 + * in advance the needed allocations. 293 + */ 294 + static int net_shaper_pre_insert(struct net_shaper_binding *binding, 295 + struct net_shaper_handle *handle, 296 + struct netlink_ext_ack *extack) 297 + { 298 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 299 + struct net_shaper *prev, *cur; 300 + bool id_allocated = false; 301 + int ret, index; 302 + 303 + if (!hierarchy) 304 + return -ENOMEM; 305 + 306 + index = net_shaper_handle_to_index(handle); 307 + cur = xa_load(&hierarchy->shapers, index); 308 + if (cur) 309 + return 0; 310 + 311 + /* Allocated a new id, if needed. */ 312 + if (handle->scope == NET_SHAPER_SCOPE_NODE && 313 + handle->id == NET_SHAPER_ID_UNSPEC) { 314 + u32 min, max; 315 + 316 + handle->id = NET_SHAPER_ID_MASK - 1; 317 + max = net_shaper_handle_to_index(handle); 318 + handle->id = 0; 319 + min = net_shaper_handle_to_index(handle); 320 + 321 + ret = xa_alloc(&hierarchy->shapers, &index, NULL, 322 + XA_LIMIT(min, max), GFP_KERNEL); 323 + if (ret < 0) { 324 + NL_SET_ERR_MSG(extack, "Can't allocate new id for NODE shaper"); 325 + return ret; 326 + } 327 + 328 + net_shaper_index_to_handle(index, handle); 329 + id_allocated = true; 330 + } 331 + 332 + cur = kzalloc(sizeof(*cur), GFP_KERNEL); 333 + if (!cur) { 334 + ret = -ENOMEM; 335 + goto free_id; 336 + } 337 + 338 + /* Mark 'tentative' shaper inside the hierarchy container. 339 + * xa_set_mark is a no-op if the previous store fails. 340 + */ 341 + xa_lock(&hierarchy->shapers); 342 + prev = __xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL); 343 + __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_NOT_VALID); 344 + xa_unlock(&hierarchy->shapers); 345 + if (xa_err(prev)) { 346 + NL_SET_ERR_MSG(extack, "Can't insert shaper into device store"); 347 + kfree_rcu(cur, rcu); 348 + ret = xa_err(prev); 349 + goto free_id; 350 + } 351 + return 0; 352 + 353 + free_id: 354 + if (id_allocated) 355 + xa_erase(&hierarchy->shapers, index); 356 + return ret; 357 + } 358 + 359 + /* Commit the tentative insert with the actual values. 360 + * Must be called only after a successful net_shaper_pre_insert(). 361 + */ 362 + static void net_shaper_commit(struct net_shaper_binding *binding, 363 + int nr_shapers, const struct net_shaper *shapers) 364 + { 365 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 366 + struct net_shaper *cur; 367 + int index; 368 + int i; 369 + 370 + xa_lock(&hierarchy->shapers); 371 + for (i = 0; i < nr_shapers; ++i) { 372 + index = net_shaper_handle_to_index(&shapers[i].handle); 373 + 374 + cur = xa_load(&hierarchy->shapers, index); 375 + if (WARN_ON_ONCE(!cur)) 376 + continue; 377 + 378 + /* Successful update: drop the tentative mark 379 + * and update the hierarchy container. 380 + */ 381 + __xa_clear_mark(&hierarchy->shapers, index, 382 + NET_SHAPER_NOT_VALID); 383 + *cur = shapers[i]; 384 + } 385 + xa_unlock(&hierarchy->shapers); 386 + } 387 + 388 + /* Rollback all the tentative inserts from the hierarchy. */ 389 + static void net_shaper_rollback(struct net_shaper_binding *binding) 390 + { 391 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 392 + struct net_shaper *cur; 393 + unsigned long index; 394 + 395 + if (!hierarchy) 396 + return; 397 + 398 + xa_lock(&hierarchy->shapers); 399 + xa_for_each_marked(&hierarchy->shapers, index, cur, 400 + NET_SHAPER_NOT_VALID) { 401 + __xa_erase(&hierarchy->shapers, index); 402 + kfree(cur); 403 + } 404 + xa_unlock(&hierarchy->shapers); 405 + } 406 + 407 + static int net_shaper_parse_handle(const struct nlattr *attr, 408 + const struct genl_info *info, 409 + struct net_shaper_handle *handle) 410 + { 411 + struct nlattr *tb[NET_SHAPER_A_HANDLE_MAX + 1]; 412 + struct nlattr *id_attr; 413 + u32 id = 0; 414 + int ret; 415 + 416 + ret = nla_parse_nested(tb, NET_SHAPER_A_HANDLE_MAX, attr, 417 + net_shaper_handle_nl_policy, info->extack); 418 + if (ret < 0) 419 + return ret; 420 + 421 + if (NL_REQ_ATTR_CHECK(info->extack, attr, tb, 422 + NET_SHAPER_A_HANDLE_SCOPE)) 423 + return -EINVAL; 424 + 425 + handle->scope = nla_get_u32(tb[NET_SHAPER_A_HANDLE_SCOPE]); 426 + 427 + /* The default id for NODE scope shapers is an invalid one 428 + * to help the 'group' operation discriminate between new 429 + * NODE shaper creation (ID_UNSPEC) and reuse of existing 430 + * shaper (any other value). 431 + */ 432 + id_attr = tb[NET_SHAPER_A_HANDLE_ID]; 433 + if (id_attr) 434 + id = nla_get_u32(id_attr); 435 + else if (handle->scope == NET_SHAPER_SCOPE_NODE) 436 + id = NET_SHAPER_ID_UNSPEC; 437 + 438 + handle->id = id; 439 + return 0; 440 + } 441 + 442 + static int net_shaper_validate_caps(struct net_shaper_binding *binding, 443 + struct nlattr **tb, 444 + const struct genl_info *info, 445 + struct net_shaper *shaper) 446 + { 447 + const struct net_shaper_ops *ops = net_shaper_ops(binding); 448 + struct nlattr *bad = NULL; 449 + unsigned long caps = 0; 450 + 451 + ops->capabilities(binding, shaper->handle.scope, &caps); 452 + 453 + if (tb[NET_SHAPER_A_PRIORITY] && 454 + !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_PRIORITY))) 455 + bad = tb[NET_SHAPER_A_PRIORITY]; 456 + if (tb[NET_SHAPER_A_WEIGHT] && 457 + !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_WEIGHT))) 458 + bad = tb[NET_SHAPER_A_WEIGHT]; 459 + if (tb[NET_SHAPER_A_BW_MIN] && 460 + !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MIN))) 461 + bad = tb[NET_SHAPER_A_BW_MIN]; 462 + if (tb[NET_SHAPER_A_BW_MAX] && 463 + !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX))) 464 + bad = tb[NET_SHAPER_A_BW_MAX]; 465 + if (tb[NET_SHAPER_A_BURST] && 466 + !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BURST))) 467 + bad = tb[NET_SHAPER_A_BURST]; 468 + 469 + if (!caps) 470 + bad = tb[NET_SHAPER_A_HANDLE]; 471 + 472 + if (bad) { 473 + NL_SET_BAD_ATTR(info->extack, bad); 474 + return -EOPNOTSUPP; 475 + } 476 + 477 + if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE && 478 + binding->type == NET_SHAPER_BINDING_TYPE_NETDEV && 479 + shaper->handle.id >= binding->netdev->real_num_tx_queues) { 480 + NL_SET_ERR_MSG_FMT(info->extack, 481 + "Not existing queue id %d max %d", 482 + shaper->handle.id, 483 + binding->netdev->real_num_tx_queues); 484 + return -ENOENT; 485 + } 486 + 487 + /* The metric is really used only if there is *any* rate-related 488 + * setting, either in current attributes set or in pre-existing 489 + * values. 490 + */ 491 + if (shaper->burst || shaper->bw_min || shaper->bw_max) { 492 + u32 metric_cap = NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS + 493 + shaper->metric; 494 + 495 + /* The metric test can fail even when the user did not 496 + * specify the METRIC attribute. Pointing to rate related 497 + * attribute will be confusing, as the attribute itself 498 + * could be indeed supported, with a different metric. 499 + * Be more specific. 500 + */ 501 + if (!(caps & BIT(metric_cap))) { 502 + NL_SET_ERR_MSG_FMT(info->extack, "Bad metric %d", 503 + shaper->metric); 504 + return -EOPNOTSUPP; 505 + } 506 + } 507 + return 0; 508 + } 509 + 510 + static int net_shaper_parse_info(struct net_shaper_binding *binding, 511 + struct nlattr **tb, 512 + const struct genl_info *info, 513 + struct net_shaper *shaper, 514 + bool *exists) 515 + { 516 + struct net_shaper *old; 517 + int ret; 518 + 519 + /* The shaper handle is the only mandatory attribute. */ 520 + if (NL_REQ_ATTR_CHECK(info->extack, NULL, tb, NET_SHAPER_A_HANDLE)) 521 + return -EINVAL; 522 + 523 + ret = net_shaper_parse_handle(tb[NET_SHAPER_A_HANDLE], info, 524 + &shaper->handle); 525 + if (ret) 526 + return ret; 527 + 528 + if (shaper->handle.scope == NET_SHAPER_SCOPE_UNSPEC) { 529 + NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]); 530 + return -EINVAL; 531 + } 532 + 533 + /* Fetch existing hierarchy, if any, so that user provide info will 534 + * incrementally update the existing shaper configuration. 535 + */ 536 + old = net_shaper_lookup(binding, &shaper->handle); 537 + if (old) 538 + *shaper = *old; 539 + *exists = !!old; 540 + 541 + if (tb[NET_SHAPER_A_METRIC]) 542 + shaper->metric = nla_get_u32(tb[NET_SHAPER_A_METRIC]); 543 + 544 + if (tb[NET_SHAPER_A_BW_MIN]) 545 + shaper->bw_min = nla_get_uint(tb[NET_SHAPER_A_BW_MIN]); 546 + 547 + if (tb[NET_SHAPER_A_BW_MAX]) 548 + shaper->bw_max = nla_get_uint(tb[NET_SHAPER_A_BW_MAX]); 549 + 550 + if (tb[NET_SHAPER_A_BURST]) 551 + shaper->burst = nla_get_uint(tb[NET_SHAPER_A_BURST]); 552 + 553 + if (tb[NET_SHAPER_A_PRIORITY]) 554 + shaper->priority = nla_get_u32(tb[NET_SHAPER_A_PRIORITY]); 555 + 556 + if (tb[NET_SHAPER_A_WEIGHT]) 557 + shaper->weight = nla_get_u32(tb[NET_SHAPER_A_WEIGHT]); 558 + 559 + ret = net_shaper_validate_caps(binding, tb, info, shaper); 560 + if (ret < 0) 561 + return ret; 562 + 563 + return 0; 564 + } 565 + 566 + static int net_shaper_validate_nesting(struct net_shaper_binding *binding, 567 + const struct net_shaper *shaper, 568 + struct netlink_ext_ack *extack) 569 + { 570 + const struct net_shaper_ops *ops = net_shaper_ops(binding); 571 + unsigned long caps = 0; 572 + 573 + ops->capabilities(binding, shaper->handle.scope, &caps); 574 + if (!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_NESTING))) { 575 + NL_SET_ERR_MSG_FMT(extack, 576 + "Nesting not supported for scope %d", 577 + shaper->handle.scope); 578 + return -EOPNOTSUPP; 579 + } 580 + return 0; 581 + } 582 + 583 + /* Fetch the existing leaf and update it with the user-provided 584 + * attributes. 585 + */ 586 + static int net_shaper_parse_leaf(struct net_shaper_binding *binding, 587 + const struct nlattr *attr, 588 + const struct genl_info *info, 589 + const struct net_shaper *node, 590 + struct net_shaper *shaper) 591 + { 592 + struct nlattr *tb[NET_SHAPER_A_WEIGHT + 1]; 593 + bool exists; 594 + int ret; 595 + 596 + ret = nla_parse_nested(tb, NET_SHAPER_A_WEIGHT, attr, 597 + net_shaper_leaf_info_nl_policy, info->extack); 598 + if (ret < 0) 599 + return ret; 600 + 601 + ret = net_shaper_parse_info(binding, tb, info, shaper, &exists); 602 + if (ret < 0) 603 + return ret; 604 + 605 + if (shaper->handle.scope != NET_SHAPER_SCOPE_QUEUE) { 606 + NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]); 607 + return -EINVAL; 608 + } 609 + 610 + if (node->handle.scope == NET_SHAPER_SCOPE_NODE) { 611 + ret = net_shaper_validate_nesting(binding, shaper, 612 + info->extack); 613 + if (ret < 0) 614 + return ret; 615 + } 616 + 617 + if (!exists) 618 + net_shaper_default_parent(&shaper->handle, &shaper->parent); 619 + return 0; 620 + } 621 + 622 + /* Alike net_parse_shaper_info(), but additionally allow the user specifying 623 + * the shaper's parent handle. 624 + */ 625 + static int net_shaper_parse_node(struct net_shaper_binding *binding, 626 + struct nlattr **tb, 627 + const struct genl_info *info, 628 + struct net_shaper *shaper) 629 + { 630 + bool exists; 631 + int ret; 632 + 633 + ret = net_shaper_parse_info(binding, tb, info, shaper, &exists); 634 + if (ret) 635 + return ret; 636 + 637 + if (shaper->handle.scope != NET_SHAPER_SCOPE_NODE && 638 + shaper->handle.scope != NET_SHAPER_SCOPE_NETDEV) { 639 + NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]); 640 + return -EINVAL; 641 + } 642 + 643 + if (tb[NET_SHAPER_A_PARENT]) { 644 + ret = net_shaper_parse_handle(tb[NET_SHAPER_A_PARENT], info, 645 + &shaper->parent); 646 + if (ret) 647 + return ret; 648 + 649 + if (shaper->parent.scope != NET_SHAPER_SCOPE_NODE && 650 + shaper->parent.scope != NET_SHAPER_SCOPE_NETDEV) { 651 + NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_PARENT]); 652 + return -EINVAL; 653 + } 654 + } 655 + return 0; 656 + } 657 + 658 + static int net_shaper_generic_pre(struct genl_info *info, int type) 659 + { 660 + struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)info->ctx; 661 + 662 + BUILD_BUG_ON(sizeof(*ctx) > sizeof(info->ctx)); 663 + 664 + return net_shaper_ctx_setup(info, type, ctx); 665 + } 666 + 667 + int net_shaper_nl_pre_doit(const struct genl_split_ops *ops, 668 + struct sk_buff *skb, struct genl_info *info) 669 + { 670 + return net_shaper_generic_pre(info, NET_SHAPER_A_IFINDEX); 671 + } 672 + 673 + static void net_shaper_generic_post(struct genl_info *info) 674 + { 675 + net_shaper_ctx_cleanup((struct net_shaper_nl_ctx *)info->ctx); 676 + } 677 + 678 + void net_shaper_nl_post_doit(const struct genl_split_ops *ops, 679 + struct sk_buff *skb, struct genl_info *info) 680 + { 681 + net_shaper_generic_post(info); 682 + } 683 + 684 + int net_shaper_nl_pre_dumpit(struct netlink_callback *cb) 685 + { 686 + struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx; 687 + const struct genl_info *info = genl_info_dump(cb); 688 + 689 + return net_shaper_ctx_setup(info, NET_SHAPER_A_IFINDEX, ctx); 690 + } 691 + 692 + int net_shaper_nl_post_dumpit(struct netlink_callback *cb) 693 + { 694 + net_shaper_ctx_cleanup((struct net_shaper_nl_ctx *)cb->ctx); 695 + return 0; 696 + } 697 + 698 + int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops, 699 + struct sk_buff *skb, struct genl_info *info) 700 + { 701 + return net_shaper_generic_pre(info, NET_SHAPER_A_CAPS_IFINDEX); 702 + } 703 + 704 + void net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops, 705 + struct sk_buff *skb, struct genl_info *info) 706 + { 707 + net_shaper_generic_post(info); 708 + } 709 + 710 + int net_shaper_nl_cap_pre_dumpit(struct netlink_callback *cb) 711 + { 712 + struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx; 713 + 714 + return net_shaper_ctx_setup(genl_info_dump(cb), 715 + NET_SHAPER_A_CAPS_IFINDEX, ctx); 716 + } 717 + 718 + int net_shaper_nl_cap_post_dumpit(struct netlink_callback *cb) 719 + { 720 + struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx; 721 + 722 + net_shaper_ctx_cleanup(ctx); 723 + return 0; 724 + } 725 + 726 + int net_shaper_nl_get_doit(struct sk_buff *skb, struct genl_info *info) 727 + { 728 + struct net_shaper_binding *binding; 729 + struct net_shaper_handle handle; 730 + struct net_shaper *shaper; 731 + struct sk_buff *msg; 732 + int ret; 733 + 734 + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_HANDLE)) 735 + return -EINVAL; 736 + 737 + binding = net_shaper_binding_from_ctx(info->ctx); 738 + ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info, 739 + &handle); 740 + if (ret < 0) 741 + return ret; 742 + 743 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 744 + if (!msg) 745 + return -ENOMEM; 746 + 747 + rcu_read_lock(); 748 + shaper = net_shaper_lookup(binding, &handle); 749 + if (!shaper) { 750 + NL_SET_BAD_ATTR(info->extack, 751 + info->attrs[NET_SHAPER_A_HANDLE]); 752 + rcu_read_unlock(); 753 + ret = -ENOENT; 754 + goto free_msg; 755 + } 756 + 757 + ret = net_shaper_fill_one(msg, binding, shaper, info); 758 + rcu_read_unlock(); 759 + if (ret) 760 + goto free_msg; 761 + 762 + ret = genlmsg_reply(msg, info); 763 + if (ret) 764 + goto free_msg; 765 + 766 + return 0; 767 + 768 + free_msg: 769 + nlmsg_free(msg); 770 + return ret; 771 + } 772 + 773 + int net_shaper_nl_get_dumpit(struct sk_buff *skb, 774 + struct netlink_callback *cb) 775 + { 776 + struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx; 777 + const struct genl_info *info = genl_info_dump(cb); 778 + struct net_shaper_hierarchy *hierarchy; 779 + struct net_shaper_binding *binding; 780 + struct net_shaper *shaper; 781 + int ret = 0; 782 + 783 + /* Don't error out dumps performed before any set operation. */ 784 + binding = net_shaper_binding_from_ctx(ctx); 785 + hierarchy = net_shaper_hierarchy(binding); 786 + if (!hierarchy) 787 + return 0; 788 + 789 + rcu_read_lock(); 790 + for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, 791 + U32_MAX, XA_PRESENT)); ctx->start_index++) { 792 + ret = net_shaper_fill_one(skb, binding, shaper, info); 793 + if (ret) 794 + break; 795 + } 796 + rcu_read_unlock(); 797 + 798 + return ret; 799 + } 800 + 801 + int net_shaper_nl_set_doit(struct sk_buff *skb, struct genl_info *info) 802 + { 803 + struct net_shaper_hierarchy *hierarchy; 804 + struct net_shaper_binding *binding; 805 + const struct net_shaper_ops *ops; 806 + struct net_shaper_handle handle; 807 + struct net_shaper shaper = {}; 808 + bool exists; 809 + int ret; 810 + 811 + binding = net_shaper_binding_from_ctx(info->ctx); 812 + 813 + net_shaper_lock(binding); 814 + ret = net_shaper_parse_info(binding, info->attrs, info, &shaper, 815 + &exists); 816 + if (ret) 817 + goto unlock; 818 + 819 + if (!exists) 820 + net_shaper_default_parent(&shaper.handle, &shaper.parent); 821 + 822 + hierarchy = net_shaper_hierarchy_setup(binding); 823 + if (!hierarchy) { 824 + ret = -ENOMEM; 825 + goto unlock; 826 + } 827 + 828 + /* The 'set' operation can't create node-scope shapers. */ 829 + handle = shaper.handle; 830 + if (handle.scope == NET_SHAPER_SCOPE_NODE && 831 + !net_shaper_lookup(binding, &handle)) { 832 + ret = -ENOENT; 833 + goto unlock; 834 + } 835 + 836 + ret = net_shaper_pre_insert(binding, &handle, info->extack); 837 + if (ret) 838 + goto unlock; 839 + 840 + ops = net_shaper_ops(binding); 841 + ret = ops->set(binding, &shaper, info->extack); 842 + if (ret) { 843 + net_shaper_rollback(binding); 844 + goto unlock; 845 + } 846 + 847 + net_shaper_commit(binding, 1, &shaper); 848 + 849 + unlock: 850 + net_shaper_unlock(binding); 851 + return ret; 852 + } 853 + 854 + static int __net_shaper_delete(struct net_shaper_binding *binding, 855 + struct net_shaper *shaper, 856 + struct netlink_ext_ack *extack) 857 + { 858 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 859 + struct net_shaper_handle parent_handle, handle = shaper->handle; 860 + const struct net_shaper_ops *ops = net_shaper_ops(binding); 861 + int ret; 862 + 863 + again: 864 + parent_handle = shaper->parent; 865 + 866 + ret = ops->delete(binding, &handle, extack); 867 + if (ret < 0) 868 + return ret; 869 + 870 + xa_erase(&hierarchy->shapers, net_shaper_handle_to_index(&handle)); 871 + kfree_rcu(shaper, rcu); 872 + 873 + /* Eventually delete the parent, if it is left over with no leaves. */ 874 + if (parent_handle.scope == NET_SHAPER_SCOPE_NODE) { 875 + shaper = net_shaper_lookup(binding, &parent_handle); 876 + if (shaper && !--shaper->leaves) { 877 + handle = parent_handle; 878 + goto again; 879 + } 880 + } 881 + return 0; 882 + } 883 + 884 + static int net_shaper_handle_cmp(const struct net_shaper_handle *a, 885 + const struct net_shaper_handle *b) 886 + { 887 + /* Must avoid holes in struct net_shaper_handle. */ 888 + BUILD_BUG_ON(sizeof(*a) != 8); 889 + 890 + return memcmp(a, b, sizeof(*a)); 891 + } 892 + 893 + static int net_shaper_parent_from_leaves(int leaves_count, 894 + const struct net_shaper *leaves, 895 + struct net_shaper *node, 896 + struct netlink_ext_ack *extack) 897 + { 898 + struct net_shaper_handle parent = leaves[0].parent; 899 + int i; 900 + 901 + for (i = 1; i < leaves_count; ++i) { 902 + if (net_shaper_handle_cmp(&leaves[i].parent, &parent)) { 903 + NL_SET_ERR_MSG_FMT(extack, "All the leaves shapers must have the same old parent"); 904 + return -EINVAL; 905 + } 906 + } 907 + 908 + node->parent = parent; 909 + return 0; 910 + } 911 + 912 + static int __net_shaper_group(struct net_shaper_binding *binding, 913 + bool update_node, int leaves_count, 914 + struct net_shaper *leaves, 915 + struct net_shaper *node, 916 + struct netlink_ext_ack *extack) 917 + { 918 + const struct net_shaper_ops *ops = net_shaper_ops(binding); 919 + struct net_shaper_handle leaf_handle; 920 + struct net_shaper *parent = NULL; 921 + bool new_node = false; 922 + int i, ret; 923 + 924 + if (node->handle.scope == NET_SHAPER_SCOPE_NODE) { 925 + new_node = node->handle.id == NET_SHAPER_ID_UNSPEC; 926 + 927 + if (!new_node && !net_shaper_lookup(binding, &node->handle)) { 928 + /* The related attribute is not available when 929 + * reaching here from the delete() op. 930 + */ 931 + NL_SET_ERR_MSG_FMT(extack, "Node shaper %d:%d does not exists", 932 + node->handle.scope, node->handle.id); 933 + return -ENOENT; 934 + } 935 + 936 + /* When unspecified, the node parent scope is inherited from 937 + * the leaves. 938 + */ 939 + if (node->parent.scope == NET_SHAPER_SCOPE_UNSPEC) { 940 + ret = net_shaper_parent_from_leaves(leaves_count, 941 + leaves, node, 942 + extack); 943 + if (ret) 944 + return ret; 945 + } 946 + 947 + } else { 948 + net_shaper_default_parent(&node->handle, &node->parent); 949 + } 950 + 951 + if (node->parent.scope == NET_SHAPER_SCOPE_NODE) { 952 + parent = net_shaper_lookup(binding, &node->parent); 953 + if (!parent) { 954 + NL_SET_ERR_MSG_FMT(extack, "Node parent shaper %d:%d does not exists", 955 + node->parent.scope, node->parent.id); 956 + return -ENOENT; 957 + } 958 + 959 + ret = net_shaper_validate_nesting(binding, node, extack); 960 + if (ret < 0) 961 + return ret; 962 + } 963 + 964 + if (update_node) { 965 + /* For newly created node scope shaper, the following will 966 + * update the handle, due to id allocation. 967 + */ 968 + ret = net_shaper_pre_insert(binding, &node->handle, extack); 969 + if (ret) 970 + return ret; 971 + } 972 + 973 + for (i = 0; i < leaves_count; ++i) { 974 + leaf_handle = leaves[i].handle; 975 + 976 + ret = net_shaper_pre_insert(binding, &leaf_handle, extack); 977 + if (ret) 978 + goto rollback; 979 + 980 + if (!net_shaper_handle_cmp(&leaves[i].parent, &node->handle)) 981 + continue; 982 + 983 + /* The leaves shapers will be nested to the node, update the 984 + * linking accordingly. 985 + */ 986 + leaves[i].parent = node->handle; 987 + node->leaves++; 988 + } 989 + 990 + ret = ops->group(binding, leaves_count, leaves, node, extack); 991 + if (ret < 0) 992 + goto rollback; 993 + 994 + /* The node's parent gains a new leaf only when the node itself 995 + * is created by this group operation 996 + */ 997 + if (new_node && parent) 998 + parent->leaves++; 999 + if (update_node) 1000 + net_shaper_commit(binding, 1, node); 1001 + net_shaper_commit(binding, leaves_count, leaves); 1002 + return 0; 1003 + 1004 + rollback: 1005 + net_shaper_rollback(binding); 1006 + return ret; 1007 + } 1008 + 1009 + static int net_shaper_pre_del_node(struct net_shaper_binding *binding, 1010 + const struct net_shaper *shaper, 1011 + struct netlink_ext_ack *extack) 1012 + { 1013 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 1014 + struct net_shaper *cur, *leaves, node = {}; 1015 + int ret, leaves_count = 0; 1016 + unsigned long index; 1017 + bool update_node; 1018 + 1019 + if (!shaper->leaves) 1020 + return 0; 1021 + 1022 + /* Fetch the new node information. */ 1023 + node.handle = shaper->parent; 1024 + cur = net_shaper_lookup(binding, &node.handle); 1025 + if (cur) { 1026 + node = *cur; 1027 + } else { 1028 + /* A scope NODE shaper can be nested only to the NETDEV scope 1029 + * shaper without creating the latter, this check may fail only 1030 + * if the data is in inconsistent status. 1031 + */ 1032 + if (WARN_ON_ONCE(node.handle.scope != NET_SHAPER_SCOPE_NETDEV)) 1033 + return -EINVAL; 1034 + } 1035 + 1036 + leaves = kcalloc(shaper->leaves, sizeof(struct net_shaper), 1037 + GFP_KERNEL); 1038 + if (!leaves) 1039 + return -ENOMEM; 1040 + 1041 + /* Build the leaves arrays. */ 1042 + xa_for_each(&hierarchy->shapers, index, cur) { 1043 + if (net_shaper_handle_cmp(&cur->parent, &shaper->handle)) 1044 + continue; 1045 + 1046 + if (WARN_ON_ONCE(leaves_count == shaper->leaves)) { 1047 + ret = -EINVAL; 1048 + goto free; 1049 + } 1050 + 1051 + leaves[leaves_count++] = *cur; 1052 + } 1053 + 1054 + /* When re-linking to the netdev shaper, avoid the eventual, implicit, 1055 + * creation of the new node, would be surprising since the user is 1056 + * doing a delete operation. 1057 + */ 1058 + update_node = node.handle.scope != NET_SHAPER_SCOPE_NETDEV; 1059 + ret = __net_shaper_group(binding, update_node, leaves_count, 1060 + leaves, &node, extack); 1061 + 1062 + free: 1063 + kfree(leaves); 1064 + return ret; 1065 + } 1066 + 1067 + int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info) 1068 + { 1069 + struct net_shaper_hierarchy *hierarchy; 1070 + struct net_shaper_binding *binding; 1071 + struct net_shaper_handle handle; 1072 + struct net_shaper *shaper; 1073 + int ret; 1074 + 1075 + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_HANDLE)) 1076 + return -EINVAL; 1077 + 1078 + binding = net_shaper_binding_from_ctx(info->ctx); 1079 + 1080 + net_shaper_lock(binding); 1081 + ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info, 1082 + &handle); 1083 + if (ret) 1084 + goto unlock; 1085 + 1086 + hierarchy = net_shaper_hierarchy(binding); 1087 + if (!hierarchy) { 1088 + ret = -ENOENT; 1089 + goto unlock; 1090 + } 1091 + 1092 + shaper = net_shaper_lookup(binding, &handle); 1093 + if (!shaper) { 1094 + ret = -ENOENT; 1095 + goto unlock; 1096 + } 1097 + 1098 + if (handle.scope == NET_SHAPER_SCOPE_NODE) { 1099 + ret = net_shaper_pre_del_node(binding, shaper, info->extack); 1100 + if (ret) 1101 + goto unlock; 1102 + } 1103 + 1104 + ret = __net_shaper_delete(binding, shaper, info->extack); 1105 + 1106 + unlock: 1107 + net_shaper_unlock(binding); 1108 + return ret; 1109 + } 1110 + 1111 + static int net_shaper_group_send_reply(struct net_shaper_binding *binding, 1112 + const struct net_shaper_handle *handle, 1113 + struct genl_info *info, 1114 + struct sk_buff *msg) 1115 + { 1116 + void *hdr; 1117 + 1118 + hdr = genlmsg_iput(msg, info); 1119 + if (!hdr) 1120 + goto free_msg; 1121 + 1122 + if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_IFINDEX) || 1123 + net_shaper_fill_handle(msg, handle, NET_SHAPER_A_HANDLE)) 1124 + goto free_msg; 1125 + 1126 + genlmsg_end(msg, hdr); 1127 + 1128 + return genlmsg_reply(msg, info); 1129 + 1130 + free_msg: 1131 + /* Should never happen as msg is pre-allocated with enough space. */ 1132 + WARN_ONCE(true, "calculated message payload length (%d)", 1133 + net_shaper_handle_size()); 1134 + nlmsg_free(msg); 1135 + return -EMSGSIZE; 1136 + } 1137 + 1138 + int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info) 1139 + { 1140 + struct net_shaper **old_nodes, *leaves, node = {}; 1141 + struct net_shaper_hierarchy *hierarchy; 1142 + struct net_shaper_binding *binding; 1143 + int i, ret, rem, leaves_count; 1144 + int old_nodes_count = 0; 1145 + struct sk_buff *msg; 1146 + struct nlattr *attr; 1147 + 1148 + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_LEAVES)) 1149 + return -EINVAL; 1150 + 1151 + binding = net_shaper_binding_from_ctx(info->ctx); 1152 + 1153 + /* The group operation is optional. */ 1154 + if (!net_shaper_ops(binding)->group) 1155 + return -EOPNOTSUPP; 1156 + 1157 + net_shaper_lock(binding); 1158 + leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES); 1159 + if (!leaves_count) { 1160 + NL_SET_BAD_ATTR(info->extack, 1161 + info->attrs[NET_SHAPER_A_LEAVES]); 1162 + ret = -EINVAL; 1163 + goto unlock; 1164 + } 1165 + 1166 + leaves = kcalloc(leaves_count, sizeof(struct net_shaper) + 1167 + sizeof(struct net_shaper *), GFP_KERNEL); 1168 + if (!leaves) { 1169 + ret = -ENOMEM; 1170 + goto unlock; 1171 + } 1172 + old_nodes = (void *)&leaves[leaves_count]; 1173 + 1174 + ret = net_shaper_parse_node(binding, info->attrs, info, &node); 1175 + if (ret) 1176 + goto free_leaves; 1177 + 1178 + i = 0; 1179 + nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES, 1180 + genlmsg_data(info->genlhdr), 1181 + genlmsg_len(info->genlhdr), rem) { 1182 + if (WARN_ON_ONCE(i >= leaves_count)) 1183 + goto free_leaves; 1184 + 1185 + ret = net_shaper_parse_leaf(binding, attr, info, 1186 + &node, &leaves[i]); 1187 + if (ret) 1188 + goto free_leaves; 1189 + i++; 1190 + } 1191 + 1192 + /* Prepare the msg reply in advance, to avoid device operation 1193 + * rollback on allocation failure. 1194 + */ 1195 + msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL); 1196 + if (!msg) 1197 + goto free_leaves; 1198 + 1199 + hierarchy = net_shaper_hierarchy_setup(binding); 1200 + if (!hierarchy) { 1201 + ret = -ENOMEM; 1202 + goto free_msg; 1203 + } 1204 + 1205 + /* Record the node shapers that this group() operation can make 1206 + * childless for later cleanup. 1207 + */ 1208 + for (i = 0; i < leaves_count; i++) { 1209 + if (leaves[i].parent.scope == NET_SHAPER_SCOPE_NODE && 1210 + net_shaper_handle_cmp(&leaves[i].parent, &node.handle)) { 1211 + struct net_shaper *tmp; 1212 + 1213 + tmp = net_shaper_lookup(binding, &leaves[i].parent); 1214 + if (!tmp) 1215 + continue; 1216 + 1217 + old_nodes[old_nodes_count++] = tmp; 1218 + } 1219 + } 1220 + 1221 + ret = __net_shaper_group(binding, true, leaves_count, leaves, &node, 1222 + info->extack); 1223 + if (ret) 1224 + goto free_msg; 1225 + 1226 + /* Check if we need to delete any node left alone by the new leaves 1227 + * linkage. 1228 + */ 1229 + for (i = 0; i < old_nodes_count; ++i) { 1230 + struct net_shaper *tmp = old_nodes[i]; 1231 + 1232 + if (--tmp->leaves > 0) 1233 + continue; 1234 + 1235 + /* Errors here are not fatal: the grouping operation is 1236 + * completed, and user-space can still explicitly clean-up 1237 + * left-over nodes. 1238 + */ 1239 + __net_shaper_delete(binding, tmp, info->extack); 1240 + } 1241 + 1242 + ret = net_shaper_group_send_reply(binding, &node.handle, info, msg); 1243 + if (ret) 1244 + GENL_SET_ERR_MSG_FMT(info, "Can't send reply"); 1245 + 1246 + free_leaves: 1247 + kfree(leaves); 1248 + 1249 + unlock: 1250 + net_shaper_unlock(binding); 1251 + return ret; 1252 + 1253 + free_msg: 1254 + kfree_skb(msg); 1255 + goto free_leaves; 1256 + } 1257 + 1258 + static int 1259 + net_shaper_cap_fill_one(struct sk_buff *msg, 1260 + struct net_shaper_binding *binding, 1261 + enum net_shaper_scope scope, unsigned long flags, 1262 + const struct genl_info *info) 1263 + { 1264 + unsigned long cur; 1265 + void *hdr; 1266 + 1267 + hdr = genlmsg_iput(msg, info); 1268 + if (!hdr) 1269 + return -EMSGSIZE; 1270 + 1271 + if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_CAPS_IFINDEX) || 1272 + nla_put_u32(msg, NET_SHAPER_A_CAPS_SCOPE, scope)) 1273 + goto nla_put_failure; 1274 + 1275 + for (cur = NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS; 1276 + cur <= NET_SHAPER_A_CAPS_MAX; ++cur) { 1277 + if (flags & BIT(cur) && nla_put_flag(msg, cur)) 1278 + goto nla_put_failure; 1279 + } 1280 + 1281 + genlmsg_end(msg, hdr); 1282 + 1283 + return 0; 1284 + 1285 + nla_put_failure: 1286 + genlmsg_cancel(msg, hdr); 1287 + return -EMSGSIZE; 1288 + } 1289 + 1290 + int net_shaper_nl_cap_get_doit(struct sk_buff *skb, struct genl_info *info) 1291 + { 1292 + struct net_shaper_binding *binding; 1293 + const struct net_shaper_ops *ops; 1294 + enum net_shaper_scope scope; 1295 + unsigned long flags = 0; 1296 + struct sk_buff *msg; 1297 + int ret; 1298 + 1299 + if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_CAPS_SCOPE)) 1300 + return -EINVAL; 1301 + 1302 + binding = net_shaper_binding_from_ctx(info->ctx); 1303 + scope = nla_get_u32(info->attrs[NET_SHAPER_A_CAPS_SCOPE]); 1304 + ops = net_shaper_ops(binding); 1305 + ops->capabilities(binding, scope, &flags); 1306 + if (!flags) 1307 + return -EOPNOTSUPP; 1308 + 1309 + msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1310 + if (!msg) 1311 + return -ENOMEM; 1312 + 1313 + ret = net_shaper_cap_fill_one(msg, binding, scope, flags, info); 1314 + if (ret) 1315 + goto free_msg; 1316 + 1317 + ret = genlmsg_reply(msg, info); 1318 + if (ret) 1319 + goto free_msg; 1320 + return 0; 1321 + 1322 + free_msg: 1323 + nlmsg_free(msg); 1324 + return ret; 1325 + } 1326 + 1327 + int net_shaper_nl_cap_get_dumpit(struct sk_buff *skb, 1328 + struct netlink_callback *cb) 1329 + { 1330 + const struct genl_info *info = genl_info_dump(cb); 1331 + struct net_shaper_binding *binding; 1332 + const struct net_shaper_ops *ops; 1333 + enum net_shaper_scope scope; 1334 + int ret; 1335 + 1336 + binding = net_shaper_binding_from_ctx(cb->ctx); 1337 + ops = net_shaper_ops(binding); 1338 + for (scope = 0; scope <= NET_SHAPER_SCOPE_MAX; ++scope) { 1339 + unsigned long flags = 0; 1340 + 1341 + ops->capabilities(binding, scope, &flags); 1342 + if (!flags) 1343 + continue; 1344 + 1345 + ret = net_shaper_cap_fill_one(skb, binding, scope, flags, 1346 + info); 1347 + if (ret) 1348 + return ret; 1349 + } 1350 + 1351 + return 0; 1352 + } 1353 + 1354 + static void net_shaper_flush(struct net_shaper_binding *binding) 1355 + { 1356 + struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding); 1357 + struct net_shaper *cur; 1358 + unsigned long index; 1359 + 1360 + if (!hierarchy) 1361 + return; 1362 + 1363 + net_shaper_lock(binding); 1364 + xa_lock(&hierarchy->shapers); 1365 + xa_for_each(&hierarchy->shapers, index, cur) { 1366 + __xa_erase(&hierarchy->shapers, index); 1367 + kfree(cur); 1368 + } 1369 + xa_unlock(&hierarchy->shapers); 1370 + net_shaper_unlock(binding); 1371 + 1372 + kfree(hierarchy); 1373 + } 1374 + 1375 + void net_shaper_flush_netdev(struct net_device *dev) 1376 + { 1377 + struct net_shaper_binding binding = { 1378 + .type = NET_SHAPER_BINDING_TYPE_NETDEV, 1379 + .netdev = dev, 1380 + }; 1381 + 1382 + net_shaper_flush(&binding); 1383 + } 1384 + 1385 + void net_shaper_set_real_num_tx_queues(struct net_device *dev, 1386 + unsigned int txq) 1387 + { 1388 + struct net_shaper_hierarchy *hierarchy; 1389 + struct net_shaper_binding binding; 1390 + int i; 1391 + 1392 + binding.type = NET_SHAPER_BINDING_TYPE_NETDEV; 1393 + binding.netdev = dev; 1394 + hierarchy = net_shaper_hierarchy(&binding); 1395 + if (!hierarchy) 1396 + return; 1397 + 1398 + /* Only drivers implementing shapers support ensure 1399 + * the lock is acquired in advance. 1400 + */ 1401 + lockdep_assert_held(&dev->lock); 1402 + 1403 + /* Take action only when decreasing the tx queue number. */ 1404 + for (i = txq; i < dev->real_num_tx_queues; ++i) { 1405 + struct net_shaper_handle handle, parent_handle; 1406 + struct net_shaper *shaper; 1407 + u32 index; 1408 + 1409 + handle.scope = NET_SHAPER_SCOPE_QUEUE; 1410 + handle.id = i; 1411 + shaper = net_shaper_lookup(&binding, &handle); 1412 + if (!shaper) 1413 + continue; 1414 + 1415 + /* Don't touch the H/W for the queue shaper, the drivers already 1416 + * deleted the queue and related resources. 1417 + */ 1418 + parent_handle = shaper->parent; 1419 + index = net_shaper_handle_to_index(&handle); 1420 + xa_erase(&hierarchy->shapers, index); 1421 + kfree_rcu(shaper, rcu); 1422 + 1423 + /* The recursion on parent does the full job. */ 1424 + if (parent_handle.scope != NET_SHAPER_SCOPE_NODE) 1425 + continue; 1426 + 1427 + shaper = net_shaper_lookup(&binding, &parent_handle); 1428 + if (shaper && !--shaper->leaves) 1429 + __net_shaper_delete(&binding, shaper, NULL); 1430 + } 1431 + } 1432 + 1433 + static int __init shaper_init(void) 1434 + { 1435 + return genl_register_family(&net_shaper_nl_family); 1436 + } 1437 + 1438 + subsys_initcall(shaper_init);
+154
net/shaper/shaper_nl_gen.c
··· 1 + // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/net_shaper.yaml */ 4 + /* YNL-GEN kernel source */ 5 + 6 + #include <net/netlink.h> 7 + #include <net/genetlink.h> 8 + 9 + #include "shaper_nl_gen.h" 10 + 11 + #include <uapi/linux/net_shaper.h> 12 + 13 + /* Common nested types */ 14 + const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1] = { 15 + [NET_SHAPER_A_HANDLE_SCOPE] = NLA_POLICY_MAX(NLA_U32, 3), 16 + [NET_SHAPER_A_HANDLE_ID] = { .type = NLA_U32, }, 17 + }; 18 + 19 + const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1] = { 20 + [NET_SHAPER_A_HANDLE] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 21 + [NET_SHAPER_A_PRIORITY] = { .type = NLA_U32, }, 22 + [NET_SHAPER_A_WEIGHT] = { .type = NLA_U32, }, 23 + }; 24 + 25 + /* NET_SHAPER_CMD_GET - do */ 26 + static const struct nla_policy net_shaper_get_do_nl_policy[NET_SHAPER_A_IFINDEX + 1] = { 27 + [NET_SHAPER_A_IFINDEX] = { .type = NLA_U32, }, 28 + [NET_SHAPER_A_HANDLE] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 29 + }; 30 + 31 + /* NET_SHAPER_CMD_GET - dump */ 32 + static const struct nla_policy net_shaper_get_dump_nl_policy[NET_SHAPER_A_IFINDEX + 1] = { 33 + [NET_SHAPER_A_IFINDEX] = { .type = NLA_U32, }, 34 + }; 35 + 36 + /* NET_SHAPER_CMD_SET - do */ 37 + static const struct nla_policy net_shaper_set_nl_policy[NET_SHAPER_A_IFINDEX + 1] = { 38 + [NET_SHAPER_A_IFINDEX] = { .type = NLA_U32, }, 39 + [NET_SHAPER_A_HANDLE] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 40 + [NET_SHAPER_A_METRIC] = NLA_POLICY_MAX(NLA_U32, 1), 41 + [NET_SHAPER_A_BW_MIN] = { .type = NLA_UINT, }, 42 + [NET_SHAPER_A_BW_MAX] = { .type = NLA_UINT, }, 43 + [NET_SHAPER_A_BURST] = { .type = NLA_UINT, }, 44 + [NET_SHAPER_A_PRIORITY] = { .type = NLA_U32, }, 45 + [NET_SHAPER_A_WEIGHT] = { .type = NLA_U32, }, 46 + }; 47 + 48 + /* NET_SHAPER_CMD_DELETE - do */ 49 + static const struct nla_policy net_shaper_delete_nl_policy[NET_SHAPER_A_IFINDEX + 1] = { 50 + [NET_SHAPER_A_IFINDEX] = { .type = NLA_U32, }, 51 + [NET_SHAPER_A_HANDLE] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 52 + }; 53 + 54 + /* NET_SHAPER_CMD_GROUP - do */ 55 + static const struct nla_policy net_shaper_group_nl_policy[NET_SHAPER_A_LEAVES + 1] = { 56 + [NET_SHAPER_A_IFINDEX] = { .type = NLA_U32, }, 57 + [NET_SHAPER_A_PARENT] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 58 + [NET_SHAPER_A_HANDLE] = NLA_POLICY_NESTED(net_shaper_handle_nl_policy), 59 + [NET_SHAPER_A_METRIC] = NLA_POLICY_MAX(NLA_U32, 1), 60 + [NET_SHAPER_A_BW_MIN] = { .type = NLA_UINT, }, 61 + [NET_SHAPER_A_BW_MAX] = { .type = NLA_UINT, }, 62 + [NET_SHAPER_A_BURST] = { .type = NLA_UINT, }, 63 + [NET_SHAPER_A_PRIORITY] = { .type = NLA_U32, }, 64 + [NET_SHAPER_A_WEIGHT] = { .type = NLA_U32, }, 65 + [NET_SHAPER_A_LEAVES] = NLA_POLICY_NESTED(net_shaper_leaf_info_nl_policy), 66 + }; 67 + 68 + /* NET_SHAPER_CMD_CAP_GET - do */ 69 + static const struct nla_policy net_shaper_cap_get_do_nl_policy[NET_SHAPER_A_CAPS_SCOPE + 1] = { 70 + [NET_SHAPER_A_CAPS_IFINDEX] = { .type = NLA_U32, }, 71 + [NET_SHAPER_A_CAPS_SCOPE] = NLA_POLICY_MAX(NLA_U32, 3), 72 + }; 73 + 74 + /* NET_SHAPER_CMD_CAP_GET - dump */ 75 + static const struct nla_policy net_shaper_cap_get_dump_nl_policy[NET_SHAPER_A_CAPS_IFINDEX + 1] = { 76 + [NET_SHAPER_A_CAPS_IFINDEX] = { .type = NLA_U32, }, 77 + }; 78 + 79 + /* Ops table for net_shaper */ 80 + static const struct genl_split_ops net_shaper_nl_ops[] = { 81 + { 82 + .cmd = NET_SHAPER_CMD_GET, 83 + .pre_doit = net_shaper_nl_pre_doit, 84 + .doit = net_shaper_nl_get_doit, 85 + .post_doit = net_shaper_nl_post_doit, 86 + .policy = net_shaper_get_do_nl_policy, 87 + .maxattr = NET_SHAPER_A_IFINDEX, 88 + .flags = GENL_CMD_CAP_DO, 89 + }, 90 + { 91 + .cmd = NET_SHAPER_CMD_GET, 92 + .start = net_shaper_nl_pre_dumpit, 93 + .dumpit = net_shaper_nl_get_dumpit, 94 + .done = net_shaper_nl_post_dumpit, 95 + .policy = net_shaper_get_dump_nl_policy, 96 + .maxattr = NET_SHAPER_A_IFINDEX, 97 + .flags = GENL_CMD_CAP_DUMP, 98 + }, 99 + { 100 + .cmd = NET_SHAPER_CMD_SET, 101 + .pre_doit = net_shaper_nl_pre_doit, 102 + .doit = net_shaper_nl_set_doit, 103 + .post_doit = net_shaper_nl_post_doit, 104 + .policy = net_shaper_set_nl_policy, 105 + .maxattr = NET_SHAPER_A_IFINDEX, 106 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 107 + }, 108 + { 109 + .cmd = NET_SHAPER_CMD_DELETE, 110 + .pre_doit = net_shaper_nl_pre_doit, 111 + .doit = net_shaper_nl_delete_doit, 112 + .post_doit = net_shaper_nl_post_doit, 113 + .policy = net_shaper_delete_nl_policy, 114 + .maxattr = NET_SHAPER_A_IFINDEX, 115 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 116 + }, 117 + { 118 + .cmd = NET_SHAPER_CMD_GROUP, 119 + .pre_doit = net_shaper_nl_pre_doit, 120 + .doit = net_shaper_nl_group_doit, 121 + .post_doit = net_shaper_nl_post_doit, 122 + .policy = net_shaper_group_nl_policy, 123 + .maxattr = NET_SHAPER_A_LEAVES, 124 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 125 + }, 126 + { 127 + .cmd = NET_SHAPER_CMD_CAP_GET, 128 + .pre_doit = net_shaper_nl_cap_pre_doit, 129 + .doit = net_shaper_nl_cap_get_doit, 130 + .post_doit = net_shaper_nl_cap_post_doit, 131 + .policy = net_shaper_cap_get_do_nl_policy, 132 + .maxattr = NET_SHAPER_A_CAPS_SCOPE, 133 + .flags = GENL_CMD_CAP_DO, 134 + }, 135 + { 136 + .cmd = NET_SHAPER_CMD_CAP_GET, 137 + .start = net_shaper_nl_cap_pre_dumpit, 138 + .dumpit = net_shaper_nl_cap_get_dumpit, 139 + .done = net_shaper_nl_cap_post_dumpit, 140 + .policy = net_shaper_cap_get_dump_nl_policy, 141 + .maxattr = NET_SHAPER_A_CAPS_IFINDEX, 142 + .flags = GENL_CMD_CAP_DUMP, 143 + }, 144 + }; 145 + 146 + struct genl_family net_shaper_nl_family __ro_after_init = { 147 + .name = NET_SHAPER_FAMILY_NAME, 148 + .version = NET_SHAPER_FAMILY_VERSION, 149 + .netnsok = true, 150 + .parallel_ops = true, 151 + .module = THIS_MODULE, 152 + .split_ops = net_shaper_nl_ops, 153 + .n_split_ops = ARRAY_SIZE(net_shaper_nl_ops), 154 + };
+44
net/shaper/shaper_nl_gen.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/net_shaper.yaml */ 4 + /* YNL-GEN kernel header */ 5 + 6 + #ifndef _LINUX_NET_SHAPER_GEN_H 7 + #define _LINUX_NET_SHAPER_GEN_H 8 + 9 + #include <net/netlink.h> 10 + #include <net/genetlink.h> 11 + 12 + #include <uapi/linux/net_shaper.h> 13 + 14 + /* Common nested types */ 15 + extern const struct nla_policy net_shaper_handle_nl_policy[NET_SHAPER_A_HANDLE_ID + 1]; 16 + extern const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGHT + 1]; 17 + 18 + int net_shaper_nl_pre_doit(const struct genl_split_ops *ops, 19 + struct sk_buff *skb, struct genl_info *info); 20 + int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops, 21 + struct sk_buff *skb, struct genl_info *info); 22 + void 23 + net_shaper_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 24 + struct genl_info *info); 25 + void 26 + net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops, 27 + struct sk_buff *skb, struct genl_info *info); 28 + int net_shaper_nl_pre_dumpit(struct netlink_callback *cb); 29 + int net_shaper_nl_cap_pre_dumpit(struct netlink_callback *cb); 30 + int net_shaper_nl_post_dumpit(struct netlink_callback *cb); 31 + int net_shaper_nl_cap_post_dumpit(struct netlink_callback *cb); 32 + 33 + int net_shaper_nl_get_doit(struct sk_buff *skb, struct genl_info *info); 34 + int net_shaper_nl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); 35 + int net_shaper_nl_set_doit(struct sk_buff *skb, struct genl_info *info); 36 + int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info); 37 + int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info); 38 + int net_shaper_nl_cap_get_doit(struct sk_buff *skb, struct genl_info *info); 39 + int net_shaper_nl_cap_get_dumpit(struct sk_buff *skb, 40 + struct netlink_callback *cb); 41 + 42 + extern struct genl_family net_shaper_nl_family; 43 + 44 + #endif /* _LINUX_NET_SHAPER_GEN_H */
+1
tools/testing/selftests/drivers/net/Makefile
··· 9 9 ping.py \ 10 10 queues.py \ 11 11 stats.py \ 12 + shaper.py 12 13 # end of TEST_PROGS 13 14 14 15 include ../../lib.mk
+461
tools/testing/selftests/drivers/net/shaper.py
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_true, KsftSkipEx 5 + from lib.py import EthtoolFamily, NetshaperFamily 6 + from lib.py import NetDrvEnv 7 + from lib.py import NlError 8 + from lib.py import cmd 9 + 10 + def get_shapers(cfg, nl_shaper) -> None: 11 + try: 12 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 13 + except NlError as e: 14 + if e.error == 95: 15 + raise KsftSkipEx("shapers not supported by the device") 16 + raise 17 + 18 + # Default configuration: no shapers configured. 19 + ksft_eq(len(shapers), 0) 20 + 21 + def get_caps(cfg, nl_shaper) -> None: 22 + try: 23 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex}, dump=True) 24 + except NlError as e: 25 + if e.error == 95: 26 + raise KsftSkipEx("shapers not supported by the device") 27 + raise 28 + 29 + # Each device implementing shaper support must support some 30 + # features in at least a scope. 31 + ksft_true(len(caps)> 0) 32 + 33 + def set_qshapers(cfg, nl_shaper) -> None: 34 + try: 35 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 36 + 'scope':'queue'}) 37 + except NlError as e: 38 + if e.error == 95: 39 + raise KsftSkipEx("shapers not supported by the device") 40 + raise 41 + if not 'support-bw-max' in caps or not 'support-metric-bps' in caps: 42 + raise KsftSkipEx("device does not support queue scope shapers with bw_max and metric bps") 43 + 44 + cfg.queues = True; 45 + netnl = EthtoolFamily() 46 + channels = netnl.channels_get({'header': {'dev-index': cfg.ifindex}}) 47 + if channels['combined-count'] == 0: 48 + cfg.rx_type = 'rx' 49 + cfg.nr_queues = channels['rx-count'] 50 + else: 51 + cfg.rx_type = 'combined' 52 + cfg.nr_queues = channels['combined-count'] 53 + if cfg.nr_queues < 3: 54 + raise KsftSkipEx(f"device does not support enough queues min 3 found {cfg.nr_queues}") 55 + 56 + nl_shaper.set({'ifindex': cfg.ifindex, 57 + 'handle': {'scope': 'queue', 'id': 1}, 58 + 'metric': 'bps', 59 + 'bw-max': 10000}) 60 + nl_shaper.set({'ifindex': cfg.ifindex, 61 + 'handle': {'scope': 'queue', 'id': 2}, 62 + 'metric': 'bps', 63 + 'bw-max': 20000}) 64 + 65 + # Querying a specific shaper not yet configured must fail. 66 + raised = False 67 + try: 68 + shaper_q0 = nl_shaper.get({'ifindex': cfg.ifindex, 69 + 'handle': {'scope': 'queue', 'id': 0}}) 70 + except (NlError): 71 + raised = True 72 + ksft_eq(raised, True) 73 + 74 + shaper_q1 = nl_shaper.get({'ifindex': cfg.ifindex, 75 + 'handle': {'scope': 'queue', 'id': 1}}) 76 + ksft_eq(shaper_q1, {'ifindex': cfg.ifindex, 77 + 'parent': {'scope': 'netdev'}, 78 + 'handle': {'scope': 'queue', 'id': 1}, 79 + 'metric': 'bps', 80 + 'bw-max': 10000}) 81 + 82 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 83 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 84 + 'parent': {'scope': 'netdev'}, 85 + 'handle': {'scope': 'queue', 'id': 1}, 86 + 'metric': 'bps', 87 + 'bw-max': 10000}, 88 + {'ifindex': cfg.ifindex, 89 + 'parent': {'scope': 'netdev'}, 90 + 'handle': {'scope': 'queue', 'id': 2}, 91 + 'metric': 'bps', 92 + 'bw-max': 20000}]) 93 + 94 + def del_qshapers(cfg, nl_shaper) -> None: 95 + if not cfg.queues: 96 + raise KsftSkipEx("queue shapers not supported by device, skipping delete") 97 + 98 + nl_shaper.delete({'ifindex': cfg.ifindex, 99 + 'handle': {'scope': 'queue', 'id': 2}}) 100 + nl_shaper.delete({'ifindex': cfg.ifindex, 101 + 'handle': {'scope': 'queue', 'id': 1}}) 102 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 103 + ksft_eq(len(shapers), 0) 104 + 105 + def set_nshapers(cfg, nl_shaper) -> None: 106 + # Check required features. 107 + try: 108 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 109 + 'scope':'netdev'}) 110 + except NlError as e: 111 + if e.error == 95: 112 + raise KsftSkipEx("shapers not supported by the device") 113 + raise 114 + if not 'support-bw-max' in caps or not 'support-metric-bps' in caps: 115 + raise KsftSkipEx("device does not support nested netdev scope shapers with weight") 116 + 117 + cfg.netdev = True; 118 + nl_shaper.set({'ifindex': cfg.ifindex, 119 + 'handle': {'scope': 'netdev', 'id': 0}, 120 + 'bw-max': 100000}) 121 + 122 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 123 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 124 + 'handle': {'scope': 'netdev'}, 125 + 'metric': 'bps', 126 + 'bw-max': 100000}]) 127 + 128 + def del_nshapers(cfg, nl_shaper) -> None: 129 + if not cfg.netdev: 130 + raise KsftSkipEx("netdev shaper not supported by device, skipping delete") 131 + 132 + nl_shaper.delete({'ifindex': cfg.ifindex, 133 + 'handle': {'scope': 'netdev'}}) 134 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 135 + ksft_eq(len(shapers), 0) 136 + 137 + def basic_groups(cfg, nl_shaper) -> None: 138 + if not cfg.netdev: 139 + raise KsftSkipEx("netdev shaper not supported by the device") 140 + if cfg.nr_queues < 3: 141 + raise KsftSkipEx(f"netdev does not have enough queues min 3 reported {cfg.nr_queues}") 142 + 143 + try: 144 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 145 + 'scope':'queue'}) 146 + except NlError as e: 147 + if e.error == 95: 148 + raise KsftSkipEx("shapers not supported by the device") 149 + raise 150 + if not 'support-weight' in caps: 151 + raise KsftSkipEx("device does not support queue scope shapers with weight") 152 + 153 + node_handle = nl_shaper.group({ 154 + 'ifindex': cfg.ifindex, 155 + 'leaves':[{'handle': {'scope': 'queue', 'id': 1}, 156 + 'weight': 1}, 157 + {'handle': {'scope': 'queue', 'id': 2}, 158 + 'weight': 2}], 159 + 'handle': {'scope':'netdev'}, 160 + 'metric': 'bps', 161 + 'bw-max': 10000}) 162 + ksft_eq(node_handle, {'ifindex': cfg.ifindex, 163 + 'handle': {'scope': 'netdev'}}) 164 + 165 + shaper = nl_shaper.get({'ifindex': cfg.ifindex, 166 + 'handle': {'scope': 'queue', 'id': 1}}) 167 + ksft_eq(shaper, {'ifindex': cfg.ifindex, 168 + 'parent': {'scope': 'netdev'}, 169 + 'handle': {'scope': 'queue', 'id': 1}, 170 + 'weight': 1 }) 171 + 172 + nl_shaper.delete({'ifindex': cfg.ifindex, 173 + 'handle': {'scope': 'queue', 'id': 2}}) 174 + nl_shaper.delete({'ifindex': cfg.ifindex, 175 + 'handle': {'scope': 'queue', 'id': 1}}) 176 + 177 + # Deleting all the leaves shaper does not affect the node one 178 + # when the latter has 'netdev' scope. 179 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 180 + ksft_eq(len(shapers), 1) 181 + 182 + nl_shaper.delete({'ifindex': cfg.ifindex, 183 + 'handle': {'scope': 'netdev'}}) 184 + 185 + def qgroups(cfg, nl_shaper) -> None: 186 + if cfg.nr_queues < 4: 187 + raise KsftSkipEx(f"netdev does not have enough queues min 4 reported {cfg.nr_queues}") 188 + try: 189 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 190 + 'scope':'node'}) 191 + except NlError as e: 192 + if e.error == 95: 193 + raise KsftSkipEx("shapers not supported by the device") 194 + raise 195 + if not 'support-bw-max' in caps or not 'support-metric-bps' in caps: 196 + raise KsftSkipEx("device does not support node scope shapers with bw_max and metric bps") 197 + try: 198 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 199 + 'scope':'queue'}) 200 + except NlError as e: 201 + if e.error == 95: 202 + raise KsftSkipEx("shapers not supported by the device") 203 + raise 204 + if not 'support-nesting' in caps or not 'support-weight' in caps or not 'support-metric-bps' in caps: 205 + raise KsftSkipEx("device does not support nested queue scope shapers with weight") 206 + 207 + cfg.groups = True; 208 + node_handle = nl_shaper.group({ 209 + 'ifindex': cfg.ifindex, 210 + 'leaves':[{'handle': {'scope': 'queue', 'id': 1}, 211 + 'weight': 3}, 212 + {'handle': {'scope': 'queue', 'id': 2}, 213 + 'weight': 2}], 214 + 'handle': {'scope':'node'}, 215 + 'metric': 'bps', 216 + 'bw-max': 10000}) 217 + node_id = node_handle['handle']['id'] 218 + 219 + shaper = nl_shaper.get({'ifindex': cfg.ifindex, 220 + 'handle': {'scope': 'queue', 'id': 1}}) 221 + ksft_eq(shaper, {'ifindex': cfg.ifindex, 222 + 'parent': {'scope': 'node', 'id': node_id}, 223 + 'handle': {'scope': 'queue', 'id': 1}, 224 + 'weight': 3}) 225 + shaper = nl_shaper.get({'ifindex': cfg.ifindex, 226 + 'handle': {'scope': 'node', 'id': node_id}}) 227 + ksft_eq(shaper, {'ifindex': cfg.ifindex, 228 + 'handle': {'scope': 'node', 'id': node_id}, 229 + 'parent': {'scope': 'netdev'}, 230 + 'metric': 'bps', 231 + 'bw-max': 10000}) 232 + 233 + # Grouping to a specified, not existing node scope shaper must fail 234 + raised = False 235 + try: 236 + nl_shaper.group({ 237 + 'ifindex': cfg.ifindex, 238 + 'leaves':[{'handle': {'scope': 'queue', 'id': 3}, 239 + 'weight': 3}], 240 + 'handle': {'scope':'node', 'id': node_id + 1}, 241 + 'metric': 'bps', 242 + 'bw-max': 10000}) 243 + 244 + except (NlError): 245 + raised = True 246 + ksft_eq(raised, True) 247 + 248 + # Add to an existing node 249 + node_handle = nl_shaper.group({ 250 + 'ifindex': cfg.ifindex, 251 + 'leaves':[{'handle': {'scope': 'queue', 'id': 3}, 252 + 'weight': 4}], 253 + 'handle': {'scope':'node', 'id': node_id}}) 254 + ksft_eq(node_handle, {'ifindex': cfg.ifindex, 255 + 'handle': {'scope': 'node', 'id': node_id}}) 256 + 257 + shaper = nl_shaper.get({'ifindex': cfg.ifindex, 258 + 'handle': {'scope': 'queue', 'id': 3}}) 259 + ksft_eq(shaper, {'ifindex': cfg.ifindex, 260 + 'parent': {'scope': 'node', 'id': node_id}, 261 + 'handle': {'scope': 'queue', 'id': 3}, 262 + 'weight': 4}) 263 + 264 + nl_shaper.delete({'ifindex': cfg.ifindex, 265 + 'handle': {'scope': 'queue', 'id': 2}}) 266 + nl_shaper.delete({'ifindex': cfg.ifindex, 267 + 'handle': {'scope': 'queue', 'id': 1}}) 268 + 269 + # Deleting a non empty node will move the leaves downstream. 270 + nl_shaper.delete({'ifindex': cfg.ifindex, 271 + 'handle': {'scope': 'node', 'id': node_id}}) 272 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 273 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 274 + 'parent': {'scope': 'netdev'}, 275 + 'handle': {'scope': 'queue', 'id': 3}, 276 + 'weight': 4}]) 277 + 278 + # Finish and verify the complete cleanup. 279 + nl_shaper.delete({'ifindex': cfg.ifindex, 280 + 'handle': {'scope': 'queue', 'id': 3}}) 281 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 282 + ksft_eq(len(shapers), 0) 283 + 284 + def delegation(cfg, nl_shaper) -> None: 285 + if not cfg.groups: 286 + raise KsftSkipEx("device does not support node scope") 287 + try: 288 + caps = nl_shaper.cap_get({'ifindex': cfg.ifindex, 289 + 'scope':'node'}) 290 + except NlError as e: 291 + if e.error == 95: 292 + raise KsftSkipEx("node scope shapers not supported by the device") 293 + raise 294 + if not 'support-nesting' in caps: 295 + raise KsftSkipEx("device does not support node scope shapers nesting") 296 + 297 + node_handle = nl_shaper.group({ 298 + 'ifindex': cfg.ifindex, 299 + 'leaves':[{'handle': {'scope': 'queue', 'id': 1}, 300 + 'weight': 3}, 301 + {'handle': {'scope': 'queue', 'id': 2}, 302 + 'weight': 2}, 303 + {'handle': {'scope': 'queue', 'id': 3}, 304 + 'weight': 1}], 305 + 'handle': {'scope':'node'}, 306 + 'metric': 'bps', 307 + 'bw-max': 10000}) 308 + node_id = node_handle['handle']['id'] 309 + 310 + # Create the nested node and validate the hierarchy 311 + nested_node_handle = nl_shaper.group({ 312 + 'ifindex': cfg.ifindex, 313 + 'leaves':[{'handle': {'scope': 'queue', 'id': 1}, 314 + 'weight': 3}, 315 + {'handle': {'scope': 'queue', 'id': 2}, 316 + 'weight': 2}], 317 + 'handle': {'scope':'node'}, 318 + 'metric': 'bps', 319 + 'bw-max': 5000}) 320 + nested_node_id = nested_node_handle['handle']['id'] 321 + ksft_true(nested_node_id != node_id) 322 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 323 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 324 + 'parent': {'scope': 'node', 'id': nested_node_id}, 325 + 'handle': {'scope': 'queue', 'id': 1}, 326 + 'weight': 3}, 327 + {'ifindex': cfg.ifindex, 328 + 'parent': {'scope': 'node', 'id': nested_node_id}, 329 + 'handle': {'scope': 'queue', 'id': 2}, 330 + 'weight': 2}, 331 + {'ifindex': cfg.ifindex, 332 + 'parent': {'scope': 'node', 'id': node_id}, 333 + 'handle': {'scope': 'queue', 'id': 3}, 334 + 'weight': 1}, 335 + {'ifindex': cfg.ifindex, 336 + 'parent': {'scope': 'netdev'}, 337 + 'handle': {'scope': 'node', 'id': node_id}, 338 + 'metric': 'bps', 339 + 'bw-max': 10000}, 340 + {'ifindex': cfg.ifindex, 341 + 'parent': {'scope': 'node', 'id': node_id}, 342 + 'handle': {'scope': 'node', 'id': nested_node_id}, 343 + 'metric': 'bps', 344 + 'bw-max': 5000}]) 345 + 346 + # Deleting a non empty node will move the leaves downstream. 347 + nl_shaper.delete({'ifindex': cfg.ifindex, 348 + 'handle': {'scope': 'node', 'id': nested_node_id}}) 349 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 350 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 351 + 'parent': {'scope': 'node', 'id': node_id}, 352 + 'handle': {'scope': 'queue', 'id': 1}, 353 + 'weight': 3}, 354 + {'ifindex': cfg.ifindex, 355 + 'parent': {'scope': 'node', 'id': node_id}, 356 + 'handle': {'scope': 'queue', 'id': 2}, 357 + 'weight': 2}, 358 + {'ifindex': cfg.ifindex, 359 + 'parent': {'scope': 'node', 'id': node_id}, 360 + 'handle': {'scope': 'queue', 'id': 3}, 361 + 'weight': 1}, 362 + {'ifindex': cfg.ifindex, 363 + 'parent': {'scope': 'netdev'}, 364 + 'handle': {'scope': 'node', 'id': node_id}, 365 + 'metric': 'bps', 366 + 'bw-max': 10000}]) 367 + 368 + # Final cleanup. 369 + for i in range(1, 4): 370 + nl_shaper.delete({'ifindex': cfg.ifindex, 371 + 'handle': {'scope': 'queue', 'id': i}}) 372 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 373 + ksft_eq(len(shapers), 0) 374 + 375 + def queue_update(cfg, nl_shaper) -> None: 376 + if cfg.nr_queues < 4: 377 + raise KsftSkipEx(f"netdev does not have enough queues min 4 reported {cfg.nr_queues}") 378 + if not cfg.queues: 379 + raise KsftSkipEx("device does not support queue scope") 380 + 381 + for i in range(3): 382 + nl_shaper.set({'ifindex': cfg.ifindex, 383 + 'handle': {'scope': 'queue', 'id': i}, 384 + 'metric': 'bps', 385 + 'bw-max': (i + 1) * 1000}) 386 + # Delete a channel, with no shapers configured on top of the related 387 + # queue: no changes expected 388 + cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} 3", timeout=10) 389 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 390 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 391 + 'parent': {'scope': 'netdev'}, 392 + 'handle': {'scope': 'queue', 'id': 0}, 393 + 'metric': 'bps', 394 + 'bw-max': 1000}, 395 + {'ifindex': cfg.ifindex, 396 + 'parent': {'scope': 'netdev'}, 397 + 'handle': {'scope': 'queue', 'id': 1}, 398 + 'metric': 'bps', 399 + 'bw-max': 2000}, 400 + {'ifindex': cfg.ifindex, 401 + 'parent': {'scope': 'netdev'}, 402 + 'handle': {'scope': 'queue', 'id': 2}, 403 + 'metric': 'bps', 404 + 'bw-max': 3000}]) 405 + 406 + # Delete a channel, with a shaper configured on top of the related 407 + # queue: the shaper must be deleted, too 408 + cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} 2", timeout=10) 409 + 410 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 411 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 412 + 'parent': {'scope': 'netdev'}, 413 + 'handle': {'scope': 'queue', 'id': 0}, 414 + 'metric': 'bps', 415 + 'bw-max': 1000}, 416 + {'ifindex': cfg.ifindex, 417 + 'parent': {'scope': 'netdev'}, 418 + 'handle': {'scope': 'queue', 'id': 1}, 419 + 'metric': 'bps', 420 + 'bw-max': 2000}]) 421 + 422 + # Restore the original channels number, no expected changes 423 + cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} {cfg.nr_queues}", timeout=10) 424 + shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True) 425 + ksft_eq(shapers, [{'ifindex': cfg.ifindex, 426 + 'parent': {'scope': 'netdev'}, 427 + 'handle': {'scope': 'queue', 'id': 0}, 428 + 'metric': 'bps', 429 + 'bw-max': 1000}, 430 + {'ifindex': cfg.ifindex, 431 + 'parent': {'scope': 'netdev'}, 432 + 'handle': {'scope': 'queue', 'id': 1}, 433 + 'metric': 'bps', 434 + 'bw-max': 2000}]) 435 + 436 + # Final cleanup. 437 + for i in range(0, 2): 438 + nl_shaper.delete({'ifindex': cfg.ifindex, 439 + 'handle': {'scope': 'queue', 'id': i}}) 440 + 441 + def main() -> None: 442 + with NetDrvEnv(__file__, queue_count=4) as cfg: 443 + cfg.queues = False 444 + cfg.netdev = False 445 + cfg.groups = False 446 + cfg.nr_queues = 0 447 + ksft_run([get_shapers, 448 + get_caps, 449 + set_qshapers, 450 + del_qshapers, 451 + set_nshapers, 452 + del_nshapers, 453 + basic_groups, 454 + qgroups, 455 + delegation, 456 + queue_update], args=(cfg, NetshaperFamily())) 457 + ksft_exit() 458 + 459 + 460 + if __name__ == "__main__": 461 + main()
+1
tools/testing/selftests/net/lib/py/__init__.py
··· 6 6 from .nsim import * 7 7 from .utils import * 8 8 from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily 9 + from .ynl import NetshaperFamily
+5
tools/testing/selftests/net/lib/py/ynl.py
··· 47 47 def __init__(self): 48 48 super().__init__((SPEC_PATH / Path('netdev.yaml')).as_posix(), 49 49 schema='') 50 + 51 + class NetshaperFamily(YnlFamily): 52 + def __init__(self): 53 + super().__init__((SPEC_PATH / Path('net_shaper.yaml')).as_posix(), 54 + schema='')