From b6897c211a151369942160e1cdd7dfd9ff8f00fa Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Tue, 4 Apr 2023 11:03:13 -0700 Subject: [PATCH] net: conn_mgr: Ignore ifaces and L2s Adds a flag to allow ifaces and L2s to be ignored. This is so that applictions have better control over what ifaces they want connectivity management for. Enabling the flag forces conn_mgr to consider the iface unready. Also increase NET_CONNECTION_MANAGER_PRIORITY default value from 0 to 1 so that applications can register SYS_INIT callbacks that fire just before conn_mgr initializes. This allows ignored ifaces to be configured before conn_mgr starts, if needed. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/conn_mgr.h | 64 ++++++++++++++ subsys/net/conn_mgr/Kconfig | 3 +- subsys/net/conn_mgr/conn_mgr.c | 111 ++++++++++++++++++++++++- subsys/net/conn_mgr/conn_mgr_private.h | 5 +- 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/conn_mgr.h b/include/zephyr/net/conn_mgr.h index bd6b4e5d3fc..5a40ad25317 100644 --- a/include/zephyr/net/conn_mgr.h +++ b/include/zephyr/net/conn_mgr.h @@ -13,11 +13,75 @@ extern "C" { #if defined(CONFIG_NET_CONNECTION_MANAGER) +struct net_if; +struct net_l2; + +/** + * @brief Resend either NET_L4_CONNECTED or NET_L4_DISCONNECTED depending on whether connectivity + * is currently available. + */ void conn_mgr_resend_status(void); +/** + * @brief Mark an iface to be ignored by conn_mgr. + * + * Ignoring an iface forces conn_mgr to consider it unready/disconnected. + * + * This means that events related to the iface connecting/disconnecting will not be fired, + * and if the iface was connected before being ignored, events will be fired as though it + * disconnected at that moment. + * + * @param iface - iface to be ignored. + */ +void conn_mgr_ignore_iface(struct net_if *iface); + +/** + * @brief Watch (stop ignoring) an iface. + * + * conn_mgr will no longer be forced to consider the iface unreadly/disconnected. + * + * Events related to the iface connecting/disconnecting will no longer be blocked, + * and if the iface was connected before being watched, events will be fired as though + * it connected in that moment. + * + * @param iface - iface to no longer ignore. + */ +void conn_mgr_watch_iface(struct net_if *iface); + +/** + * @brief Check whether the provided iface is currently ignored. + * + * @param iface - The iface to check. + * @retval true if the iface is being ignored by conn_mgr. + * @retval false if the iface is being watched by conn_mgr. + */ +bool conn_mgr_is_iface_ignored(struct net_if *iface); + +/** + * @brief Mark an L2 to be ignored by conn_mgr. + * + * This is a wrapper for conn_mgr_ignore_iface that ignores all ifaces that use the L2. + * + * @param l2 - L2 to be ignored. + */ +void conn_mgr_ignore_l2(const struct net_l2 *l2); + +/** + * @brief Watch (stop ignoring) an L2. + * + * This is a wrapper for conn_mgr_watch_iface that watches all ifaces that use the L2. + * + * @param l2 - L2 to watch. + */ +void conn_mgr_watch_l2(const struct net_l2 *l2); + #else #define conn_mgr_resend_status(...) +#define conn_mgr_ignore_iface(...) +#define conn_mgr_watch_iface(...) +#define conn_mgr_ignore_l2(...) +#define conn_mgr_watch_l2(...) #endif /* CONFIG_NET_CONNECTION_MANAGER */ diff --git a/subsys/net/conn_mgr/Kconfig b/subsys/net/conn_mgr/Kconfig index 93efffd7e6b..5c742fb852f 100644 --- a/subsys/net/conn_mgr/Kconfig +++ b/subsys/net/conn_mgr/Kconfig @@ -31,7 +31,8 @@ config NET_CONNECTION_MANAGER_STACK_SIZE config NET_CONNECTION_MANAGER_PRIORITY int "Thread starting priority" - default 0 + default 1 + range 1 99 help This sets the starting priority of the connection manager thread. diff --git a/subsys/net/conn_mgr/conn_mgr.c b/subsys/net/conn_mgr/conn_mgr.c index 645b6cea5dc..72aeeb3cd08 100644 --- a/subsys/net/conn_mgr/conn_mgr.c +++ b/subsys/net/conn_mgr/conn_mgr.c @@ -73,6 +73,17 @@ static struct net_if *conn_mgr_get_if_by_index(int index) return net_if_get_by_index(index + 1); } +/** + * @brief Gets the index in iface_states for the state corresponding to a provided iface. + * + * @param iface - iface to find the index of. + * @return int - The index found. + */ +static int conn_mgr_get_index_for_if(struct net_if *iface) +{ + return net_if_get_by_iface(iface) - 1; +} + /** * @brief Notifies listeners of the current readiness state of the iface at the given index * @@ -118,11 +129,11 @@ static void conn_mgr_act_on_changes(void) bool is_l4_ready; bool is_oper_up; bool was_l4_ready; + bool is_ignored; k_mutex_lock(&conn_mgr_lock, K_FOREVER); for (idx = 0; idx < ARRAY_SIZE(iface_states); idx++) { - if (iface_states[idx] == 0) { /* This interface is not used */ continue; @@ -140,7 +151,8 @@ static void conn_mgr_act_on_changes(void) is_ip_ready = conn_mgr_is_if_ipv6_ready(idx) || conn_mgr_is_if_ipv4_ready(idx); is_oper_up = iface_states[idx] & CONN_MGR_IF_UP; was_l4_ready = iface_states[idx] & CONN_MGR_IF_READY; - is_l4_ready = is_oper_up && is_ip_ready; + is_ignored = iface_states[idx] & CONN_MGR_IF_IGNORED; + is_l4_ready = is_oper_up && is_ip_ready && !is_ignored; /* Respond to changes to iface readiness */ if (was_l4_ready != is_l4_ready) { @@ -167,7 +179,7 @@ static void conn_mgr_initial_state(struct net_if *iface) if (net_if_is_up(iface)) { NET_DBG("Iface %p UP", iface); - iface_states[idx] = CONN_MGR_IF_UP; + iface_states[idx] |= CONN_MGR_IF_UP; } if (IS_ENABLED(CONFIG_NET_NATIVE_IPV6)) { @@ -240,6 +252,99 @@ void conn_mgr_resend_status(void) k_mutex_unlock(&conn_mgr_lock); } +void conn_mgr_ignore_iface(struct net_if *iface) +{ + int idx = conn_mgr_get_index_for_if(iface); + + k_mutex_lock(&conn_mgr_lock, K_FOREVER); + + if (!(iface_states[idx] & CONN_MGR_IF_IGNORED)) { + /* Set ignored flag and mark state as changed */ + iface_states[idx] |= CONN_MGR_IF_IGNORED; + iface_states[idx] |= CONN_MGR_IF_CHANGED; + k_sem_give(&conn_mgr_event_signal); + } + + k_mutex_unlock(&conn_mgr_lock); +} + +void conn_mgr_watch_iface(struct net_if *iface) +{ + int idx = conn_mgr_get_index_for_if(iface); + + k_mutex_lock(&conn_mgr_lock, K_FOREVER); + + if (iface_states[idx] & CONN_MGR_IF_IGNORED) { + /* Clear ignored flag and mark state as changed */ + iface_states[idx] &= ~CONN_MGR_IF_IGNORED; + iface_states[idx] |= CONN_MGR_IF_CHANGED; + k_sem_give(&conn_mgr_event_signal); + } + + k_mutex_unlock(&conn_mgr_lock); +} + +bool conn_mgr_is_iface_ignored(struct net_if *iface) +{ + int idx = conn_mgr_get_index_for_if(iface); + + bool ret = false; + + k_mutex_lock(&conn_mgr_lock, K_FOREVER); + + ret = iface_states[idx] & CONN_MGR_IF_IGNORED; + + k_mutex_unlock(&conn_mgr_lock); + + return ret; +} + +/** + * @brief Check whether a provided iface uses the provided L2. + * + * @param iface - iface to check. + * @param l2 - L2 to check. NULL will match offloaded ifaces. + * @retval true if the iface uses the provided L2. + * @retval false otherwise. + */ +static bool iface_uses_l2(struct net_if *iface, const struct net_l2 *l2) +{ + return (!l2 && net_if_offload(iface)) || + (net_if_l2(iface) == l2); +} + +void conn_mgr_ignore_l2(const struct net_l2 *l2) +{ + /* conn_mgr_ignore_iface already locks the mutex, but we lock it here too + * so that all matching ifaces are updated simultaneously. + */ + k_mutex_lock(&conn_mgr_lock, K_FOREVER); + + STRUCT_SECTION_FOREACH(net_if, iface) { + if (iface_uses_l2(iface, l2)) { + conn_mgr_ignore_iface(iface); + } + } + + k_mutex_unlock(&conn_mgr_lock); +} + +void conn_mgr_watch_l2(const struct net_l2 *l2) +{ + /* conn_mgr_watch_iface already locks the mutex, but we lock it here too + * so that all matching ifaces are updated simultaneously. + */ + k_mutex_lock(&conn_mgr_lock, K_FOREVER); + + STRUCT_SECTION_FOREACH(net_if, iface) { + if (iface_uses_l2(iface, l2)) { + conn_mgr_watch_iface(iface); + } + } + + k_mutex_unlock(&conn_mgr_lock); +} + static int conn_mgr_init(void) { int i; diff --git a/subsys/net/conn_mgr/conn_mgr_private.h b/subsys/net/conn_mgr/conn_mgr_private.h index 097b501d682..42c41e318f1 100644 --- a/subsys/net/conn_mgr/conn_mgr_private.h +++ b/subsys/net/conn_mgr/conn_mgr_private.h @@ -24,7 +24,10 @@ #define CONN_MGR_IF_IPV6_DAD_OK BIT(2) #define CONN_MGR_IF_IPV4_SET BIT(3) -/* Internal state flags */ +/* Configuration flags */ +#define CONN_MGR_IF_IGNORED BIT(7) + +/* Internal state flags*/ #define CONN_MGR_IF_READY BIT(14) /* Event flags */