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

Configure Feed

Select the types of activity you want to include in your feed.

net: sched: cls_api: improve the error message for ID allocation failure

We run into an exhaustion problem with the kernel-allocated filter IDs.
Our allocation problem can be fixed on the user space side,
but the error message in this case was quite misleading:

"Filter with specified priority/protocol not found" (EINVAL)

Specifically when we can't allocate a _new_ ID because filter with
lowest ID already _exists_, saying "filter not found", is confusing.

Kernel allocates IDs in range of 0xc0000 -> 0x8000, giving out ID one
lower than lowest existing in that range. The error message makes sense
when tcf_chain_tp_find() gets called for GET and DEL but for NEW we
need to provide more specific error messages for all three cases:

- user wants the ID to be auto-allocated but filter with ID 0x8000
already exists

- filter already exists and can be replaced, but user asked
for a protocol change

- filter doesn't exist

Caller of tcf_chain_tp_insert_unique() doesn't set extack today,
so don't bother plumbing it in.

Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/20241108010254.2995438-1-kuba@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jakub Kicinski and committed by
Paolo Abeni
a58f00ed 12079a59

+25 -14
+25 -14
net/sched/cls_api.c
··· 1933 1933 static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain, 1934 1934 struct tcf_chain_info *chain_info, 1935 1935 u32 protocol, u32 prio, 1936 - bool prio_allocate); 1936 + bool prio_allocate, 1937 + struct netlink_ext_ack *extack); 1937 1938 1938 1939 /* Try to insert new proto. 1939 1940 * If proto with specified priority already exists, free new proto ··· 1958 1957 return ERR_PTR(-EAGAIN); 1959 1958 } 1960 1959 1961 - tp = tcf_chain_tp_find(chain, &chain_info, 1962 - protocol, prio, false); 1960 + tp = tcf_chain_tp_find(chain, &chain_info, protocol, prio, false, NULL); 1963 1961 if (!tp) 1964 1962 err = tcf_chain_tp_insert(chain, &chain_info, tp_new); 1965 1963 mutex_unlock(&chain->filter_chain_lock); ··· 2018 2018 static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain, 2019 2019 struct tcf_chain_info *chain_info, 2020 2020 u32 protocol, u32 prio, 2021 - bool prio_allocate) 2021 + bool prio_allocate, 2022 + struct netlink_ext_ack *extack) 2022 2023 { 2023 2024 struct tcf_proto **pprev; 2024 2025 struct tcf_proto *tp; ··· 2030 2029 pprev = &tp->next) { 2031 2030 if (tp->prio >= prio) { 2032 2031 if (tp->prio == prio) { 2033 - if (prio_allocate || 2034 - (tp->protocol != protocol && protocol)) 2032 + if (prio_allocate) { 2033 + NL_SET_ERR_MSG(extack, "Lowest ID from auto-alloc range already in use"); 2034 + return ERR_PTR(-ENOSPC); 2035 + } 2036 + if (tp->protocol != protocol && protocol) { 2037 + NL_SET_ERR_MSG(extack, "Protocol mismatch for filter with specified priority"); 2035 2038 return ERR_PTR(-EINVAL); 2039 + } 2036 2040 } else { 2037 2041 tp = NULL; 2038 2042 } ··· 2318 2312 2319 2313 mutex_lock(&chain->filter_chain_lock); 2320 2314 tp = tcf_chain_tp_find(chain, &chain_info, protocol, 2321 - prio, prio_allocate); 2315 + prio, prio_allocate, extack); 2322 2316 if (IS_ERR(tp)) { 2323 - NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found"); 2324 2317 err = PTR_ERR(tp); 2325 2318 goto errout_locked; 2326 2319 } ··· 2544 2539 2545 2540 mutex_lock(&chain->filter_chain_lock); 2546 2541 tp = tcf_chain_tp_find(chain, &chain_info, protocol, 2547 - prio, false); 2548 - if (!tp || IS_ERR(tp)) { 2542 + prio, false, extack); 2543 + if (!tp) { 2544 + err = -ENOENT; 2549 2545 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found"); 2550 - err = tp ? PTR_ERR(tp) : -ENOENT; 2546 + goto errout_locked; 2547 + } else if (IS_ERR(tp)) { 2548 + err = PTR_ERR(tp); 2551 2549 goto errout_locked; 2552 2550 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) { 2553 2551 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one"); ··· 2687 2679 2688 2680 mutex_lock(&chain->filter_chain_lock); 2689 2681 tp = tcf_chain_tp_find(chain, &chain_info, protocol, 2690 - prio, false); 2682 + prio, false, extack); 2691 2683 mutex_unlock(&chain->filter_chain_lock); 2692 - if (!tp || IS_ERR(tp)) { 2684 + if (!tp) { 2685 + err = -ENOENT; 2693 2686 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found"); 2694 - err = tp ? PTR_ERR(tp) : -ENOENT; 2687 + goto errout; 2688 + } else if (IS_ERR(tp)) { 2689 + err = PTR_ERR(tp); 2695 2690 goto errout; 2696 2691 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) { 2697 2692 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");