staticvoid mlx5e_htb_node_delete(struct mlx5e_htb *htb, struct mlx5e_qos_node *node)
{
hash_del_rcu(&node->hnode); if (node->qid != MLX5E_QOS_QID_INNER) {
__clear_bit(node->qid, htb->qos_used_qids);
mlx5e_update_tx_netdev_queues(htb->priv);
} /* Make sure this qid is no longer selected by mlx5e_select_queue, so * that mlx5e_reactivate_qos_sq can safely restart the netdev TX queue.
*/
synchronize_net();
kfree(node);
}
/* TX datapath API */
int mlx5e_htb_get_txq_by_classid(struct mlx5e_htb *htb, u16 classid)
{ struct mlx5e_qos_node *node;
u16 qid; int res;
rcu_read_lock();
node = mlx5e_htb_node_find_rcu(htb, classid); if (!node) {
res = -ENOENT; goto out;
}
qid = READ_ONCE(node->qid); if (qid == MLX5E_QOS_QID_INNER) {
res = -EINVAL; goto out;
}
res = mlx5e_qid_from_qos(&htb->priv->channels, qid);
/* Wait until real_num_tx_queues is updated for mlx5e_select_queue, * so that we can safely switch to its non-HTB non-PTP fastpath.
*/
synchronize_net();
err_destroy_hw_node:
tmp_err = mlx5_qos_destroy_node(htb->mdev, new_hw_id); if (tmp_err) /* Not fatal. */
qos_warn(htb->mdev, "Failed to roll back creation of an inner node %u (class %04x), err = %d\n",
new_hw_id, classid, tmp_err); return err;
}
node = mlx5e_htb_node_find(htb, *classid); if (!node) return -ENOENT;
/* Store qid for reuse. */
qid = node->qid;
opened = test_bit(MLX5E_STATE_OPENED, &priv->state); if (opened) {
txq = netdev_get_tx_queue(htb->netdev,
mlx5e_qid_from_qos(&priv->channels, qid));
mlx5e_deactivate_qos_sq(priv, qid);
mlx5e_close_qos_sq(priv, qid);
}
err = mlx5_qos_destroy_node(htb->mdev, node->hw_id); if (err) /* Not fatal. */
qos_warn(htb->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
node->hw_id, *classid, err);
mlx5e_htb_node_delete(htb, node);
moved_qid = mlx5e_htb_cur_leaf_nodes(htb);
if (moved_qid == 0) { /* The last QoS SQ was just destroyed. */ if (opened)
mlx5e_reactivate_qos_sq(priv, qid, txq); return0;
}
moved_qid--;
if (moved_qid < qid) { /* The highest QoS SQ was just destroyed. */
WARN(moved_qid != qid - 1, "Gaps in queue numeration: destroyed queue %u, the highest queue is %u",
qid, moved_qid); if (opened)
mlx5e_reactivate_qos_sq(priv, qid, txq); return0;
}
WARN(moved_qid == qid, "Can't move node with qid %u to itself", qid);
qos_dbg(htb->mdev, "Moving QoS SQ %u to %u\n", moved_qid, qid);
node = mlx5e_htb_node_find_by_qid(htb, moved_qid);
WARN(!node, "Could not find a node with qid %u to move to queue %u",
moved_qid, qid);
/* Stop traffic to the old queue. */
WRITE_ONCE(node->qid, MLX5E_QOS_QID_INNER);
__clear_bit(moved_qid, priv->htb->qos_used_qids);
qos_dbg(htb->mdev, "TC_HTB_LEAF_DEL_LAST%s classid %04x\n",
force ? "_FORCE" : "", classid);
node = mlx5e_htb_node_find(htb, classid); if (!node) return -ENOENT;
err = mlx5_qos_create_leaf_node(htb->mdev, node->parent->parent->hw_id,
node->parent->bw_share,
node->parent->max_average_bw,
&new_hw_id); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Firmware error when creating a leaf node.");
qos_err(htb->mdev, "Failed to create a leaf node (class %04x), err = %d\n",
classid, err); if (!force) return err;
saved_err = err;
}
/* Store qid for reuse and prevent clearing the bit. */
qid = node->qid; /* Pairs with mlx5e_htb_get_txq_by_classid. */
WRITE_ONCE(node->qid, MLX5E_QOS_QID_INNER);
if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
mlx5e_deactivate_qos_sq(priv, qid);
mlx5e_close_qos_sq(priv, qid);
}
/* Prevent packets from the old class from getting into the new one. */
mlx5e_reset_qdisc(htb->netdev, qid);
err = mlx5_qos_destroy_node(htb->mdev, node->hw_id); if (err) /* Not fatal. */
qos_warn(htb->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
node->hw_id, classid, err);
/* Early return on error in force mode. Parent will still be an inner * node to be deleted by a following delete operation.
*/ if (saved_err) return saved_err;
old_hw_id = node->hw_id;
node->hw_id = new_hw_id;
if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
err = mlx5e_open_qos_sq(priv, &priv->channels, node->qid, node->hw_id); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Error creating an SQ.");
qos_warn(htb->mdev, "Failed to create a QoS SQ (class %04x), err = %d\n",
classid, err);
} else {
mlx5e_activate_qos_sq(priv, node->qid, node->hw_id);
}
}
err = mlx5_qos_destroy_node(htb->mdev, old_hw_id); if (err) /* Not fatal. */
qos_warn(htb->mdev, "Failed to destroy leaf node %u (class %04x), err = %d\n",
node->hw_id, classid, err);
return0;
}
staticint
mlx5e_htb_update_children(struct mlx5e_htb *htb, struct mlx5e_qos_node *node, struct netlink_ext_ack *extack)
{ struct mlx5e_qos_node *child; int err = 0; int bkt;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.