diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index aa6b1fe65151..8409b61d3313 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1551,6 +1551,25 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, * Create/change qdisc. */ +static inline bool cmd_create_or_replace(struct nlmsghdr *n) +{ + return (n->nlmsg_flags & NLM_F_CREATE && + n->nlmsg_flags & NLM_F_REPLACE); +} + +static inline bool cmd_create_exclusive(struct nlmsghdr *n) +{ + return (n->nlmsg_flags & NLM_F_CREATE && + n->nlmsg_flags & NLM_F_EXCL); +} + +static inline bool cmd_change(struct nlmsghdr *n) +{ + return (!(n->nlmsg_flags & NLM_F_CREATE) && + !(n->nlmsg_flags & NLM_F_REPLACE) && + !(n->nlmsg_flags & NLM_F_EXCL)); +} + static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, struct netlink_ext_ack *extack) { @@ -1659,12 +1678,17 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, * For now we select create/graft, if * user gave KIND, which does not match existing. */ - if ((n->nlmsg_flags & NLM_F_CREATE) && - (n->nlmsg_flags & NLM_F_REPLACE) && - ((n->nlmsg_flags & NLM_F_EXCL) || - (tca[TCA_KIND] && - nla_strcmp(tca[TCA_KIND], q->ops->id)))) - goto create_n_graft; + if (tca[TCA_KIND] && + nla_strcmp(tca[TCA_KIND], q->ops->id)) { + if (cmd_create_or_replace(n) || + cmd_create_exclusive(n)) { + goto create_n_graft; + } else { + if (cmd_change(n)) + goto create_n_graft2; + } + } + } } } else { @@ -1698,6 +1722,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, NL_SET_ERR_MSG(extack, "Qdisc not found. To create specify NLM_F_CREATE flag"); return -ENOENT; } +create_n_graft2: if (clid == TC_H_INGRESS) { if (dev_ingress_queue(dev)) { q = qdisc_create(dev, dev_ingress_queue(dev),