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_clear_errors(struct interface *iface)
+interface_error_flush(struct interface *iface)
{
struct interface_error *error, *tmp;
{
struct interface_error *error, *tmp;
+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)
{
void interface_add_error(struct interface *iface, const char *subsystem,
const char *code, const char **data, int n_data)
{
int *datalen = NULL;
char *dest, *d_subsys, *d_code;
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);
if (n_data) {
len = n_data * sizeof(char *);
datalen = alloca(len);
+ /* 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];
list_add_tail(&error->list, &iface->errors);
dest = (char *) &error->data[n_data + 1];
switch (ev) {
case IFEV_UP:
switch (ev) {
case IFEV_UP:
+ interface_error_flush(iface);
adev = iface->l3_dev.dev;
/* fall through */
case IFEV_DOWN:
adev = iface->l3_dev.dev;
/* fall through */
case IFEV_DOWN:
if (tmp && json_object_get_boolean(tmp))
handler->proto.flags |= PROTO_FLAG_RENEW_AVAILABLE;
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);
config = json_get_field(obj, "config", json_type_array);
if (config)
handler->config_buf = netifd_handler_parse_config(&handler->config, config);
proto_attach_interface(struct interface *iface, const char *proto_name)
{
const struct proto_handler *proto = &no_proto;
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) {
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;
proto = &no_proto;
}
}
iface->proto_handler = proto;
+
+ if (error)
+ interface_add_error(iface, "proto", error, NULL, 0);
PROTO_FLAG_INIT_AVAILABLE = (1 << 2),
PROTO_FLAG_RENEW_AVAILABLE = (1 << 3),
PROTO_FLAG_FORCE_LINK_DEFAULT = (1 << 4),
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 {
};
struct interface_proto_state {
json_add_boolean no-device "$no_device"
json_add_boolean available "$available"
json_add_boolean renew-handler "$renew_handler"
json_add_boolean no-device "$no_device"
json_add_boolean available "$available"
json_add_boolean renew-handler "$renew_handler"
+ json_add_boolean lasterror "$lasterror"