Commit 2f806c2a authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-ungraft-prio'



Petr Machata says:

====================
When ungrafting from PRIO, replace child with FIFO

When a child Qdisc is removed from one of the PRIO Qdisc's bands, it is
replaced unconditionally by a NOOP qdisc. As a result, any traffic hitting
that band gets dropped. That is incorrect--no Qdisc was explicitly added
when PRIO was created, and after removal, none should have to be added
either.

In patch #2, this problem is fixed for PRIO by first attempting to create a
default Qdisc and only falling back to noop when that fails. This pattern
of attempting to create an invisible FIFO, using NOOP only as a fallback,
is also seen in some other Qdiscs.

The only driver currently offloading PRIO (and thus presumably the only one
impacted by this) is mlxsw. Therefore patch #1 extends mlxsw to handle the
replacement by an invisible FIFO gracefully.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cb6f74a1 240ce7f6
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -651,6 +651,13 @@ mlxsw_sp_qdisc_prio_graft(struct mlxsw_sp_port *mlxsw_sp_port,
	    mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle)
	    mlxsw_sp_port->tclass_qdiscs[tclass_num].handle == p->child_handle)
		return 0;
		return 0;


	if (!p->child_handle) {
		/* This is an invisible FIFO replacing the original Qdisc.
		 * Ignore it--the original Qdisc's destroy will follow.
		 */
		return 0;
	}

	/* See if the grafted qdisc is already offloaded on any tclass. If so,
	/* See if the grafted qdisc is already offloaded on any tclass. If so,
	 * unoffload it.
	 * unoffload it.
	 */
	 */
+8 −2
Original line number Original line Diff line number Diff line
@@ -292,8 +292,14 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
	struct tc_prio_qopt_offload graft_offload;
	struct tc_prio_qopt_offload graft_offload;
	unsigned long band = arg - 1;
	unsigned long band = arg - 1;


	if (new == NULL)
	if (!new) {
		new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
					TC_H_MAKE(sch->handle, arg), extack);
		if (!new)
			new = &noop_qdisc;
			new = &noop_qdisc;
		else
			qdisc_hash_add(new, true);
	}


	*old = qdisc_replace(sch, new, &q->queues[band]);
	*old = qdisc_replace(sch, new, &q->queues[band]);