.. | .. |
---|
1044 | 1044 | |
---|
1045 | 1045 | if (parent == NULL) { |
---|
1046 | 1046 | unsigned int i, num_q, ingress; |
---|
| 1047 | + struct netdev_queue *dev_queue; |
---|
1047 | 1048 | |
---|
1048 | 1049 | ingress = 0; |
---|
1049 | 1050 | num_q = dev->num_tx_queues; |
---|
1050 | 1051 | if ((q && q->flags & TCQ_F_INGRESS) || |
---|
1051 | 1052 | (new && new->flags & TCQ_F_INGRESS)) { |
---|
1052 | | - num_q = 1; |
---|
1053 | 1053 | ingress = 1; |
---|
1054 | 1054 | if (!dev_ingress_queue(dev)) { |
---|
1055 | 1055 | NL_SET_ERR_MSG(extack, "Device does not have an ingress queue"); |
---|
.. | .. |
---|
1065 | 1065 | if (new && new->ops->attach) |
---|
1066 | 1066 | goto skip; |
---|
1067 | 1067 | |
---|
1068 | | - for (i = 0; i < num_q; i++) { |
---|
1069 | | - struct netdev_queue *dev_queue = dev_ingress_queue(dev); |
---|
1070 | | - |
---|
1071 | | - if (!ingress) |
---|
| 1068 | + if (!ingress) { |
---|
| 1069 | + for (i = 0; i < num_q; i++) { |
---|
1072 | 1070 | dev_queue = netdev_get_tx_queue(dev, i); |
---|
| 1071 | + old = dev_graft_qdisc(dev_queue, new); |
---|
1073 | 1072 | |
---|
1074 | | - old = dev_graft_qdisc(dev_queue, new); |
---|
1075 | | - if (new && i > 0) |
---|
1076 | | - qdisc_refcount_inc(new); |
---|
1077 | | - |
---|
1078 | | - if (!ingress) |
---|
| 1073 | + if (new && i > 0) |
---|
| 1074 | + qdisc_refcount_inc(new); |
---|
1079 | 1075 | qdisc_put(old); |
---|
| 1076 | + } |
---|
| 1077 | + } else { |
---|
| 1078 | + dev_queue = dev_ingress_queue(dev); |
---|
| 1079 | + old = dev_graft_qdisc(dev_queue, new); |
---|
1080 | 1080 | } |
---|
1081 | 1081 | |
---|
1082 | 1082 | skip: |
---|
.. | .. |
---|
1112 | 1112 | if (!cl) { |
---|
1113 | 1113 | NL_SET_ERR_MSG(extack, "Specified class not found"); |
---|
1114 | 1114 | return -ENOENT; |
---|
| 1115 | + } |
---|
| 1116 | + |
---|
| 1117 | + if (new && new->ops == &noqueue_qdisc_ops) { |
---|
| 1118 | + NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class"); |
---|
| 1119 | + return -EINVAL; |
---|
1115 | 1120 | } |
---|
1116 | 1121 | |
---|
1117 | 1122 | err = cops->graft(parent, cl, new, &old, extack); |
---|
.. | .. |
---|
1218 | 1223 | sch->parent = parent; |
---|
1219 | 1224 | |
---|
1220 | 1225 | if (handle == TC_H_INGRESS) { |
---|
1221 | | - sch->flags |= TCQ_F_INGRESS; |
---|
| 1226 | + if (!(sch->flags & TCQ_F_INGRESS)) { |
---|
| 1227 | + NL_SET_ERR_MSG(extack, |
---|
| 1228 | + "Specified parent ID is reserved for ingress and clsact Qdiscs"); |
---|
| 1229 | + err = -EINVAL; |
---|
| 1230 | + goto err_out3; |
---|
| 1231 | + } |
---|
1222 | 1232 | handle = TC_H_MAKE(TC_H_INGRESS, 0); |
---|
1223 | 1233 | } else { |
---|
1224 | 1234 | if (handle == 0) { |
---|
.. | .. |
---|
1503 | 1513 | return 0; |
---|
1504 | 1514 | } |
---|
1505 | 1515 | |
---|
| 1516 | +static bool req_create_or_replace(struct nlmsghdr *n) |
---|
| 1517 | +{ |
---|
| 1518 | + return (n->nlmsg_flags & NLM_F_CREATE && |
---|
| 1519 | + n->nlmsg_flags & NLM_F_REPLACE); |
---|
| 1520 | +} |
---|
| 1521 | + |
---|
| 1522 | +static bool req_create_exclusive(struct nlmsghdr *n) |
---|
| 1523 | +{ |
---|
| 1524 | + return (n->nlmsg_flags & NLM_F_CREATE && |
---|
| 1525 | + n->nlmsg_flags & NLM_F_EXCL); |
---|
| 1526 | +} |
---|
| 1527 | + |
---|
| 1528 | +static bool req_change(struct nlmsghdr *n) |
---|
| 1529 | +{ |
---|
| 1530 | + return (!(n->nlmsg_flags & NLM_F_CREATE) && |
---|
| 1531 | + !(n->nlmsg_flags & NLM_F_REPLACE) && |
---|
| 1532 | + !(n->nlmsg_flags & NLM_F_EXCL)); |
---|
| 1533 | +} |
---|
| 1534 | + |
---|
1506 | 1535 | /* |
---|
1507 | 1536 | * Create/change qdisc. |
---|
1508 | 1537 | */ |
---|
1509 | | - |
---|
1510 | 1538 | static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, |
---|
1511 | 1539 | struct netlink_ext_ack *extack) |
---|
1512 | 1540 | { |
---|
.. | .. |
---|
1579 | 1607 | NL_SET_ERR_MSG(extack, "Invalid qdisc name"); |
---|
1580 | 1608 | return -EINVAL; |
---|
1581 | 1609 | } |
---|
| 1610 | + if (q->flags & TCQ_F_INGRESS) { |
---|
| 1611 | + NL_SET_ERR_MSG(extack, |
---|
| 1612 | + "Cannot regraft ingress or clsact Qdiscs"); |
---|
| 1613 | + return -EINVAL; |
---|
| 1614 | + } |
---|
1582 | 1615 | if (q == p || |
---|
1583 | 1616 | (p && check_loop(q, p, 0))) { |
---|
1584 | 1617 | NL_SET_ERR_MSG(extack, "Qdisc parent/child loop detected"); |
---|
1585 | 1618 | return -ELOOP; |
---|
| 1619 | + } |
---|
| 1620 | + if (clid == TC_H_INGRESS) { |
---|
| 1621 | + NL_SET_ERR_MSG(extack, "Ingress cannot graft directly"); |
---|
| 1622 | + return -EINVAL; |
---|
1586 | 1623 | } |
---|
1587 | 1624 | qdisc_refcount_inc(q); |
---|
1588 | 1625 | goto graft; |
---|
.. | .. |
---|
1594 | 1631 | * |
---|
1595 | 1632 | * We know, that some child q is already |
---|
1596 | 1633 | * attached to this parent and have choice: |
---|
1597 | | - * either to change it or to create/graft new one. |
---|
| 1634 | + * 1) change it or 2) create/graft new one. |
---|
| 1635 | + * If the requested qdisc kind is different |
---|
| 1636 | + * than the existing one, then we choose graft. |
---|
| 1637 | + * If they are the same then this is "change" |
---|
| 1638 | + * operation - just let it fallthrough.. |
---|
1598 | 1639 | * |
---|
1599 | 1640 | * 1. We are allowed to create/graft only |
---|
1600 | | - * if CREATE and REPLACE flags are set. |
---|
| 1641 | + * if the request is explicitly stating |
---|
| 1642 | + * "please create if it doesn't exist". |
---|
1601 | 1643 | * |
---|
1602 | | - * 2. If EXCL is set, requestor wanted to say, |
---|
1603 | | - * that qdisc tcm_handle is not expected |
---|
| 1644 | + * 2. If the request is to exclusive create |
---|
| 1645 | + * then the qdisc tcm_handle is not expected |
---|
1604 | 1646 | * to exist, so that we choose create/graft too. |
---|
1605 | 1647 | * |
---|
1606 | 1648 | * 3. The last case is when no flags are set. |
---|
| 1649 | + * This will happen when for example tc |
---|
| 1650 | + * utility issues a "change" command. |
---|
1607 | 1651 | * Alas, it is sort of hole in API, we |
---|
1608 | 1652 | * cannot decide what to do unambiguously. |
---|
1609 | | - * For now we select create/graft, if |
---|
1610 | | - * user gave KIND, which does not match existing. |
---|
| 1653 | + * For now we select create/graft. |
---|
1611 | 1654 | */ |
---|
1612 | | - if ((n->nlmsg_flags & NLM_F_CREATE) && |
---|
1613 | | - (n->nlmsg_flags & NLM_F_REPLACE) && |
---|
1614 | | - ((n->nlmsg_flags & NLM_F_EXCL) || |
---|
1615 | | - (tca[TCA_KIND] && |
---|
1616 | | - nla_strcmp(tca[TCA_KIND], q->ops->id)))) |
---|
1617 | | - goto create_n_graft; |
---|
| 1655 | + if (tca[TCA_KIND] && |
---|
| 1656 | + nla_strcmp(tca[TCA_KIND], q->ops->id)) { |
---|
| 1657 | + if (req_create_or_replace(n) || |
---|
| 1658 | + req_create_exclusive(n)) |
---|
| 1659 | + goto create_n_graft; |
---|
| 1660 | + else if (req_change(n)) |
---|
| 1661 | + goto create_n_graft2; |
---|
| 1662 | + } |
---|
1618 | 1663 | } |
---|
1619 | 1664 | } |
---|
1620 | 1665 | } else { |
---|
.. | .. |
---|
1648 | 1693 | NL_SET_ERR_MSG(extack, "Qdisc not found. To create specify NLM_F_CREATE flag"); |
---|
1649 | 1694 | return -ENOENT; |
---|
1650 | 1695 | } |
---|
| 1696 | +create_n_graft2: |
---|
1651 | 1697 | if (clid == TC_H_INGRESS) { |
---|
1652 | 1698 | if (dev_ingress_queue(dev)) { |
---|
1653 | 1699 | q = qdisc_create(dev, dev_ingress_queue(dev), p, |
---|