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 <georges.larsen@nordicsemi.no>
This commit is contained in:
Georges Oates_Larsen 2023-04-04 11:03:13 -07:00 committed by Carles Cufí
parent 6cda221c53
commit b6897c211a
4 changed files with 178 additions and 5 deletions

View File

@ -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 */

View File

@ -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.

View File

@ -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;

View File

@ -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 */