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

net/sched: pass netlink extack to mqprio and taprio offload

With the multiplexed ndo_setup_tc() model which lacks a first-class
struct netlink_ext_ack * argument, the only way to pass the netlink
extended ACK message down to the device driver is to embed it within the
offload structure.

Do this for struct tc_mqprio_qopt_offload and struct tc_taprio_qopt_offload.

Since struct tc_taprio_qopt_offload also contains a tc_mqprio_qopt_offload
structure, and since device drivers might effectively reuse their mqprio
implementation for the mqprio portion of taprio, we make taprio set the
extack in both offload structures to point at the same netlink extack
message.

In fact, the taprio handling is a bit more tricky, for 2 reasons.

First is because the offload structure has a longer lifetime than the
extack structure. The driver is supposed to populate the extack
synchronously from ndo_setup_tc() and leave it alone afterwards.
To not have any use-after-free surprises, we zero out the extack pointer
when we leave taprio_enable_offload().

The second reason is because taprio does overwrite the extack message on
ndo_setup_tc() error. We need to switch to the weak form of setting an
extack message, which preserves a potential message set by the driver.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vladimir Oltean and committed by
Jakub Kicinski
c54876cd ab277d20

+16 -3
+2
include/net/pkt_sched.h
··· 166 166 struct tc_mqprio_qopt_offload { 167 167 /* struct tc_mqprio_qopt must always be the first element */ 168 168 struct tc_mqprio_qopt qopt; 169 + struct netlink_ext_ack *extack; 169 170 u16 mode; 170 171 u16 shaper; 171 172 u32 flags; ··· 194 193 195 194 struct tc_taprio_qopt_offload { 196 195 struct tc_mqprio_qopt_offload mqprio; 196 + struct netlink_ext_ack *extack; 197 197 u8 enable; 198 198 ktime_t base_time; 199 199 u64 cycle_time;
+4 -1
net/sched/sch_mqprio.c
··· 33 33 const struct tc_mqprio_qopt *qopt, 34 34 struct netlink_ext_ack *extack) 35 35 { 36 - struct tc_mqprio_qopt_offload mqprio = {.qopt = *qopt}; 37 36 struct mqprio_sched *priv = qdisc_priv(sch); 38 37 struct net_device *dev = qdisc_dev(sch); 38 + struct tc_mqprio_qopt_offload mqprio = { 39 + .qopt = *qopt, 40 + .extack = extack, 41 + }; 39 42 int err, i; 40 43 41 44 switch (priv->mode) {
+10 -2
net/sched/sch_taprio.c
··· 1520 1520 return -ENOMEM; 1521 1521 } 1522 1522 offload->enable = 1; 1523 + offload->extack = extack; 1523 1524 mqprio_qopt_reconstruct(dev, &offload->mqprio.qopt); 1525 + offload->mqprio.extack = extack; 1524 1526 taprio_sched_to_offload(dev, sched, offload, &caps); 1525 1527 1526 1528 for (tc = 0; tc < TC_MAX_QUEUE; tc++) ··· 1530 1528 1531 1529 err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload); 1532 1530 if (err < 0) { 1533 - NL_SET_ERR_MSG(extack, 1534 - "Device failed to setup taprio offload"); 1531 + NL_SET_ERR_MSG_WEAK(extack, 1532 + "Device failed to setup taprio offload"); 1535 1533 goto done; 1536 1534 } 1537 1535 1538 1536 q->offloaded = true; 1539 1537 1540 1538 done: 1539 + /* The offload structure may linger around via a reference taken by the 1540 + * device driver, so clear up the netlink extack pointer so that the 1541 + * driver isn't tempted to dereference data which stopped being valid 1542 + */ 1543 + offload->extack = NULL; 1544 + offload->mqprio.extack = NULL; 1541 1545 taprio_offload_free(offload); 1542 1546 1543 1547 return err;