netifd: Interface last error support
authorHans Dedecker <dedeckeh@gmail.com>
Wed, 8 Apr 2015 14:20:22 +0000 (16:20 +0200)
committerJohn Crispin <blogic@openwrt.org>
Fri, 3 Apr 2015 08:44:54 +0000 (10:44 +0200)
Adds interface last error support which preserves the last reported
error reported by the protocol handler till the interface is up;
e.g. survives network reload and interface restarts.
This is mainly usefull for tracking down why an interface fails
to establish; eg auth failure/traffic limit for PPP interfaces

Protocol handlers register last error support by setting lasterror=1
in the proto_init function

Signed-off-by: Johan Peeters <johan.peeters111@gmail.com>
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
interface.c
proto-shell.c
proto.c
proto.h
scripts/netifd-proto.sh

index 444f3ac0f280846c33c1d75d767ee6f85ba9e7f2..8239eac60b77f9fc6cc8cc22669a4c1a79f1c906 100644 (file)
@@ -80,7 +80,7 @@ const struct uci_blob_param_list interface_attr_list = {
 };
 
 static void
-interface_clear_errors(struct interface *iface)
+interface_error_flush(struct interface *iface)
 {
        struct interface_error *error, *tmp;
 
@@ -90,6 +90,17 @@ interface_clear_errors(struct interface *iface)
        }
 }
 
+static void
+interface_clear_errors(struct interface *iface)
+{
+        /* don't flush the errors in case the configured protocol handler matches the
+           running protocol handler and is having the last error capability */
+       if (!(iface->proto &&
+              (iface->proto->handler->flags & PROTO_FLAG_LASTERROR) &&
+              (iface->proto->handler->name == iface->proto_handler->name)))
+               interface_error_flush(iface);
+}
+
 void interface_add_error(struct interface *iface, const char *subsystem,
                         const char *code, const char **data, int n_data)
 {
@@ -98,6 +109,14 @@ void interface_add_error(struct interface *iface, const char *subsystem,
        int *datalen = NULL;
        char *dest, *d_subsys, *d_code;
 
+        /* if the configured protocol handler has the last error support capability,
+           errors should only be added if the running protocol handler matches the
+           configured one */
+       if (iface->proto &&
+            (iface->proto->handler->flags & PROTO_FLAG_LASTERROR) &&
+            (iface->proto->handler->name != iface->proto_handler->name))
+               return;
+
        if (n_data) {
                len = n_data * sizeof(char *);
                datalen = alloca(len);
@@ -113,6 +132,11 @@ void interface_add_error(struct interface *iface, const char *subsystem,
        if (!error)
                return;
 
+       /* Only keep the last flagged error, prevent this list grows unlimitted in case the
+          protocol can't be established (e.g auth failure) */
+       if (iface->proto_handler->flags & PROTO_FLAG_LASTERROR)
+               interface_error_flush(iface);
+
        list_add_tail(&error->list, &iface->errors);
 
        dest = (char *) &error->data[n_data + 1];
@@ -188,6 +212,7 @@ interface_event(struct interface *iface, enum interface_event ev)
 
        switch (ev) {
        case IFEV_UP:
+               interface_error_flush(iface);
                adev = iface->l3_dev.dev;
                /* fall through */
        case IFEV_DOWN:
index 977cdbceedc8d69639dd79082838610a325cf0bc..7a1896b8374b802d7c38743aed1d91d34dd73a95 100644 (file)
@@ -819,6 +819,10 @@ proto_shell_add_handler(const char *script, const char *name, json_object *obj)
        if (tmp && json_object_get_boolean(tmp))
                handler->proto.flags |= PROTO_FLAG_RENEW_AVAILABLE;
 
+       tmp = json_get_field(obj, "lasterror", json_type_boolean);
+       if (tmp && json_object_get_boolean(tmp))
+               handler->proto.flags |= PROTO_FLAG_LASTERROR;
+
        config = json_get_field(obj, "config", json_type_array);
        if (config)
                handler->config_buf = netifd_handler_parse_config(&handler->config, config);
diff --git a/proto.c b/proto.c
index 0ba2fbe908486516c237e6999168938c1f1f7141..eaec91325653da91a74f9f589f52b1f50b443157 100644 (file)
--- a/proto.c
+++ b/proto.c
@@ -586,16 +586,20 @@ void
 proto_attach_interface(struct interface *iface, const char *proto_name)
 {
        const struct proto_handler *proto = &no_proto;
+       const char *error = NULL;
 
        if (proto_name) {
                proto = get_proto_handler(proto_name);
                if (!proto) {
-                       interface_add_error(iface, "proto", "INVALID_PROTO", NULL, 0);
+                       error = "INVALID_PROTO";
                        proto = &no_proto;
                }
        }
 
        iface->proto_handler = proto;
+
+       if (error)
+               interface_add_error(iface, "proto", error, NULL, 0);
 }
 
 int
diff --git a/proto.h b/proto.h
index 7210f4850319d6e3b694e4c437284d5dd984eff9..87dec4e9f948d865beed5d8e8dc118e28289236d 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -37,6 +37,7 @@ enum {
        PROTO_FLAG_INIT_AVAILABLE = (1 << 2),
        PROTO_FLAG_RENEW_AVAILABLE = (1 << 3),
        PROTO_FLAG_FORCE_LINK_DEFAULT = (1 << 4),
+       PROTO_FLAG_LASTERROR = (1 << 5),
 };
 
 struct interface_proto_state {
index ce60cd0cdb9a190f0cc7648ccc3f56fd3a218aa2..95c1bb33113e09126cff62c7598b322d45b3da79 100644 (file)
@@ -375,6 +375,7 @@ init_proto() {
                                json_add_boolean no-device "$no_device"
                                json_add_boolean available "$available"
                                json_add_boolean renew-handler "$renew_handler"
+                               json_add_boolean lasterror "$lasterror"
                                json_dump
                        }
                ;;