ifnet: add if_foreach_sleep() to allow ifnet iterations with sleep.

Subscribers: imp, ae, glebius

Differential Revision: https://reviews.freebsd.org/D38904
This commit is contained in:
Alexander V. Chernikov 2023-03-04 10:09:09 +00:00
parent 66bdbcd544
commit df2b419a41
2 changed files with 67 additions and 0 deletions

View File

@ -4535,6 +4535,71 @@ if_foreach(if_foreach_cb_t cb, void *cb_arg)
return (error);
}
/*
* Iterates over the list of interfaces, permitting callback function @cb to sleep.
* Stops iteration if @cb returns non-zero error code.
* Returns the last error code from @cb.
* @match_cb: optional match callback limiting the iteration to only matched interfaces
* @match_arg: argument to pass to @match_cb
* @cb: iteration callback
* @cb_arg: argument to pass to @cb
*/
int
if_foreach_sleep(if_foreach_match_t match_cb, void *match_arg, if_foreach_cb_t cb,
void *cb_arg)
{
int match_count = 0, array_size = 16; /* 128 bytes for malloc */
struct ifnet **match_array = NULL;
int error = 0;
MPASS(cb);
while (true) {
struct ifnet **new_array;
int new_size = array_size;
struct epoch_tracker et;
struct ifnet *ifp;
while (new_size < match_count)
new_size *= 2;
new_array = malloc(new_size * sizeof(void *), M_TEMP, M_WAITOK);
if (match_array != NULL)
memcpy(new_array, match_array, array_size * sizeof(void *));
free(match_array, M_TEMP);
match_array = new_array;
array_size = new_size;
match_count = 0;
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (match_cb != NULL && !match_cb(ifp, match_arg))
continue;
if (match_count < array_size) {
if (if_try_ref(ifp))
match_array[match_count++] = ifp;
} else
match_count++;
}
NET_EPOCH_EXIT(et);
if (match_count > array_size) {
for (int i = 0; i < array_size; i++)
if_rele(match_array[i]);
continue;
} else {
for (int i = 0; i < match_count; i++) {
if (error == 0)
error = cb(match_array[i], cb_arg);
if_rele(match_array[i]);
}
free(match_array, M_TEMP);
break;
}
}
return (error);
}
u_int
if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
{

View File

@ -680,7 +680,9 @@ typedef u_int if_addr_cb_t(void *, struct ifaddr *, u_int);
u_int if_foreach_addr_type(if_t ifp, int type, if_addr_cb_t cb, void *cb_arg);
typedef int (*if_foreach_cb_t)(if_t, void *);
typedef bool (*if_foreach_match_t)(if_t, void *);
int if_foreach(if_foreach_cb_t, void *);
int if_foreach_sleep(if_foreach_match_t, void *, if_foreach_cb_t, void *);
/* Functions */
void if_setinitfn(if_t ifp, if_init_fn_t);