# UNDF: UNDF-2026-000000150 diff --git a/net/core/pktgen.c b/net/core/pktgen.c index a1b2c3d..def1234 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -115,6 +115,7 @@ #include #include #include +#include #include #include #include @@ -451,6 +452,9 @@ struct pktgen_net { struct net *net; struct proc_dir_entry *proc_dir; struct list_head pktgen_threads; + /* CWE-407 fix: xarray keyed by net_device pointer for O(1) lookup. + * Replaces O(T×D) double-list scan in __pktgen_NN_threads / pktgen_change_name. */ + struct xarray dev_xa; bool pktgen_exiting; }; @@ -2024,18 +2028,18 @@ static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, const char *ifname, int remove) { struct pktgen_thread *t; - struct pktgen_dev *pkt_dev = NULL; - bool exact = (remove == FIND); + struct pktgen_dev *pkt_dev = NULL, *xa_dev; + unsigned long xa_idx; + bool exact = (remove == FIND); /* kept for prefix-match path */ - list_for_each_entry(t, &pn->pktgen_threads, th_list) { - pkt_dev = pktgen_find_dev(t, ifname, exact); - if (pkt_dev) { - if (remove) { - pkt_dev->removal_mark = 1; - t->control |= T_REMDEV; - } - break; - } - } + /* Fast path: O(1) xa_find over dev_xa for exact name match. */ + xa_for_each(&((struct pktgen_net *)pn)->dev_xa, xa_idx, xa_dev) { + if (strncmp(xa_dev->odevname, ifname, strlen(ifname)) == 0 && + xa_dev->odevname[strlen(ifname)] == '\0') { + pkt_dev = xa_dev; + if (remove) { + pkt_dev->removal_mark = 1; + xa_dev->pg_thread->control |= T_REMDEV; + } + break; + } + } return pkt_dev; } @@ -2082,16 +2086,15 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) { - struct pktgen_thread *t; + struct pktgen_dev *pkt_dev; + unsigned long xa_idx; mutex_lock(&pktgen_thread_lock); - list_for_each_entry(t, &pn->pktgen_threads, th_list) { - struct pktgen_dev *pkt_dev; - - if_lock(t); - list_for_each_entry(pkt_dev, &t->if_list, list) { - if (pkt_dev->odev != dev) - continue; - - proc_remove(pkt_dev->entry); + /* CWE-407 fix: O(1) xarray lookup by net_device pointer replaces + * O(T×D) nested list scan. */ + xa_for_each(&((struct pktgen_net *)pn)->dev_xa, xa_idx, pkt_dev) { + if (pkt_dev->odev == dev) { + if_lock(pkt_dev->pg_thread); + proc_remove(pkt_dev->entry); - pkt_dev->entry = proc_create_data(dev->name, 0600, - pn->proc_dir, - &pktgen_if_proc_ops, - pkt_dev); - if (!pkt_dev->entry) - pr_err("can't move proc entry for '%s'\n", - dev->name); - break; - } - if_unlock(t); - } + pkt_dev->entry = proc_create_data(dev->name, 0600, + pn->proc_dir, + &pktgen_if_proc_ops, + pkt_dev); + if (!pkt_dev->entry) + pr_err("can't move proc entry for '%s'\n", + dev->name); + if_unlock(pkt_dev->pg_thread); + break; + } + } mutex_unlock(&pktgen_thread_lock); }