summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/networkd-link.c69
-rw-r--r--src/network/networkd-manager.c18
-rw-r--r--src/network/networkd.h16
-rw-r--r--src/systemd/sd-network.h4
4 files changed, 81 insertions, 26 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 3ca86261b9..04a2f8ccbe 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 2e3b4bb885..c4a325de42 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 46ed2ac66f..cfe24f5702 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 e42d1060e6..7d05086be6 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
*/