From e375dcde7202d5df4e29f5258e0f8c2bcea4535c Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 19 May 2014 20:44:21 +0200 Subject: [PATCH] networkd/sd-network: extend operational states Expose states 'degraded' or 'routable' if a link has a site/link-local or a routable address, respectively. --- src/network/networkd-link.c | 69 ++++++++++++++++++++++++++++------ src/network/networkd-manager.c | 18 ++++----- src/network/networkd.h | 16 +++++++- src/systemd/sd-network.h | 4 +- 4 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 3ca86261b..04a2f8ccb 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1253,9 +1253,9 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) { if (r < 0) /* if we got a message without operstate, take it to mean the state was unchanged */ - operstate = link->operstate; + operstate = link->kernel_operstate; - if ((link->flags == flags) && (link->operstate == operstate)) + if ((link->flags == flags) && (link->kernel_operstate == operstate)) return 0; if (link->flags != flags) { @@ -1299,13 +1299,13 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) { unknown_flags_removed); } - carrier_gained = !link_has_carrier(link->flags, link->operstate) && + carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) && link_has_carrier(flags, operstate); - carrier_lost = link_has_carrier(link->flags, link->operstate) && + carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) && !link_has_carrier(flags, operstate); link->flags = flags; - link->operstate = operstate; + link->kernel_operstate = operstate; link_save(link); @@ -1663,7 +1663,7 @@ static int link_configure(Link *link) { } } - if (link_has_carrier(link->flags, link->operstate)) { + if (link_has_carrier(link->flags, link->kernel_operstate)) { r = link_acquire_conf(link); if (r < 0) return r; @@ -1750,7 +1750,13 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen); if (r < 0) { - log_warning_link(link, "rtnl: recevied address with invalid prefixlen, ignoring"); + log_warning_link(link, "rtnl: received address with invalid prefixlen, ignoring"); + return 0; + } + + r = sd_rtnl_message_addr_get_scope(message, &address->scope); + if (r < 0) { + log_warning_link(link, "rtnl: received address with invalid scope, ignoring"); return 0; } @@ -1986,10 +1992,39 @@ static void serialize_addresses(FILE *f, const char *key, Address *address) { fputs("\n", f); } +static void link_update_operstate(Link *link) { + + assert(link); + + if (link->kernel_operstate == IF_OPER_DORMANT) + link->operstate = LINK_OPERSTATE_DORMANT; + else if (link_has_carrier(link->flags, link->kernel_operstate)) { + Address *address; + uint8_t scope = RT_SCOPE_NOWHERE; + + /* if we have carrier, check what addresses we have */ + LIST_FOREACH(addresses, address, link->addresses) { + if (address->scope < scope) + scope = address->scope; + } + + if (scope < RT_SCOPE_SITE) + /* universally accessible addresses found */ + link->operstate = LINK_OPERSTATE_ROUTABLE; + else if (scope < RT_SCOPE_HOST) + /* only link or site local addresses found */ + link->operstate = LINK_OPERSTATE_DEGRADED; + else + /* no useful addresses found */ + link->operstate = LINK_OPERSTATE_CARRIER; + } else + link->operstate = LINK_OPERSTATE_UNKNOWN; +} + int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; - const char *admin_state, *oper_state = "unknown"; + const char *admin_state, *oper_state; int r; assert(link); @@ -1997,6 +2032,8 @@ int link_save(Link *link) { assert(link->lease_file); assert(link->manager); + link_update_operstate(link); + r = manager_save(link->manager); if (r < 0) return r; @@ -2009,10 +2046,8 @@ int link_save(Link *link) { admin_state = link_state_to_string(link->state); assert(admin_state); - if (link->operstate == IF_OPER_DORMANT) - oper_state = "dormant"; - else if (link_has_carrier(link->flags, link->operstate)) - oper_state = "carrier"; + oper_state = link_operstate_to_string(link->operstate); + assert(oper_state); r = fopen_temporary(link->state_file, &f, &temp_path); if (r < 0) @@ -2074,3 +2109,13 @@ static const char* const link_state_table[_LINK_STATE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState); + +static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = { + [LINK_OPERSTATE_UNKNOWN] = "unknown", + [LINK_OPERSTATE_DORMANT] = "dormant", + [LINK_OPERSTATE_CARRIER] = "carrier", + [LINK_OPERSTATE_DEGRADED] = "degraded", + [LINK_OPERSTATE_ROUTABLE] = "routable", +}; + +DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 2e3b4bb88..c4a325de4 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -424,8 +424,8 @@ int manager_save(Manager *m) { Iterator i; _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; - const char *oper_state = "unknown"; - bool dormant = false, carrier = false; + LinkOperationalState operstate = LINK_OPERSTATE_UNKNOWN; + const char *operstate_str; int r; assert(m); @@ -435,16 +435,12 @@ int manager_save(Manager *m) { if (link->flags & IFF_LOOPBACK) continue; - if (link_has_carrier(link->flags, link->operstate)) - carrier = true; - else if (link->operstate == IF_OPER_DORMANT) - dormant = true; + if (link->operstate > operstate) + operstate = link->operstate; } - if (carrier) - oper_state = "carrier"; - else if (dormant) - oper_state = "dormant"; + operstate_str = link_operstate_to_string(operstate); + assert(operstate_str); r = fopen_temporary(m->state_file, &f, &temp_path); if (r < 0) @@ -454,7 +450,7 @@ int manager_save(Manager *m) { fprintf(f, "# This is private data. Do not parse.\n" - "OPER_STATE=%s\n", oper_state); + "OPER_STATE=%s\n", operstate_str); fflush(f); diff --git a/src/network/networkd.h b/src/network/networkd.h index 46ed2ac66..cfe24f570 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -212,6 +212,16 @@ typedef enum LinkState { _LINK_STATE_INVALID = -1 } LinkState; +typedef enum LinkOperationalState { + LINK_OPERSTATE_UNKNOWN, + LINK_OPERSTATE_DORMANT, + LINK_OPERSTATE_CARRIER, + LINK_OPERSTATE_DEGRADED, + LINK_OPERSTATE_ROUTABLE, + _LINK_OPERSTATE_MAX, + _LINK_OPERSTATE_INVALID = -1 +} LinkOperationalState; + struct Link { Manager *manager; @@ -224,11 +234,12 @@ struct Link { struct udev_device *udev_device; unsigned flags; - uint8_t operstate; + uint8_t kernel_operstate; Network *network; LinkState state; + LinkOperationalState operstate; unsigned addr_messages; unsigned route_messages; @@ -423,6 +434,9 @@ bool link_has_carrier(unsigned flags, uint8_t operstate); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; +const char* link_operstate_to_string(LinkOperationalState s) _const_; +LinkOperationalState link_operstate_from_string(const char *s) _pure_; + DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref); #define _cleanup_link_unref_ _cleanup_(link_unrefp) diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index e42d1060e..7d05086be 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -61,14 +61,14 @@ _SD_BEGIN_DECLARATIONS; int sd_network_get_link_state(unsigned index, char **state); /* Get operatinal state from ifindex. - * Possible states: unknown, dormant, carrier + * Possible states: unknown, dormant, carrier, degraded, routable * Possible return codes: * -ENODATA: networkd is not aware of the link */ int sd_network_get_link_operational_state(unsigned index, char **state); /* Get overall opeartional state - * Possible states: unknown, dormant, carrier + * Possible states: unknown, dormant, carrier, degraded, routable * Possible return codes: * -ENODATA: networkd is not aware of any links */ -- 2.30.2