Improved UBus supported

- aligned the handling of UBus connections with the DBus code as it
makes it a bit easier to comprehend;
- added logging to the various UBus calls to aid debugging from an
enduser point of view, but be careful to not flood the logs;
- show the (lack of) support for UBus in the configuration string.
This commit is contained in:
Jan Willem Janssen
2019-03-25 12:42:23 +01:00
committed by Simon Kelley
parent 5c464ef62e
commit a2b8220f4e
4 changed files with 157 additions and 23 deletions

View File

@@ -362,6 +362,10 @@ static char *compile_opts =
"no-" "no-"
#endif #endif
"DBus " "DBus "
#ifndef HAVE_UBUS
"no-"
#endif
"UBus "
#ifndef LOCALEDIR #ifndef LOCALEDIR
"no-" "no-"
#endif #endif

View File

@@ -420,6 +420,16 @@ int main (int argc, char **argv)
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF); die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
#endif #endif
if (option_bool(OPT_UBUS))
#ifdef HAVE_UBUS
{
daemon->ubus = NULL;
ubus_init();
}
#else
die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
#endif
if (daemon->port != 0) if (daemon->port != 0)
pre_allocate_sfds(); pre_allocate_sfds();
@@ -811,6 +821,16 @@ int main (int argc, char **argv)
} }
#endif #endif
#ifdef HAVE_UBUS
if (option_bool(OPT_UBUS))
{
if (daemon->ubus)
my_syslog(LOG_INFO, _("UBus support enabled: connected to system bus"));
else
my_syslog(LOG_INFO, _("UBus support enabled: bus connection pending"));
}
#endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
{ {
@@ -999,7 +1019,7 @@ int main (int argc, char **argv)
#ifdef HAVE_UBUS #ifdef HAVE_UBUS
if (option_bool(OPT_UBUS)) if (option_bool(OPT_UBUS))
set_ubus_listeners(); set_ubus_listeners();
#endif #endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
@@ -1134,7 +1154,15 @@ int main (int argc, char **argv)
#ifdef HAVE_UBUS #ifdef HAVE_UBUS
if (option_bool(OPT_UBUS)) if (option_bool(OPT_UBUS))
check_ubus_listeners(); {
/* if we didn't create a UBus connection, retry now. */
if (!daemon->ubus)
{
ubus_init();
}
check_ubus_listeners();
}
#endif #endif
check_dns_listeners(now); check_dns_listeners(now);

View File

@@ -1130,6 +1130,11 @@ extern struct daemon {
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
struct watch *watches; struct watch *watches;
#endif #endif
/* UBus stuff */
#ifdef HAVE_UBUS
/* void * here to avoid depending on ubus headers outside ubus.c */
void *ubus;
#endif
/* TFTP stuff */ /* TFTP stuff */
struct tftp_transfer *tftp_trans, *tftp_done_trans; struct tftp_transfer *tftp_trans, *tftp_done_trans;
@@ -1467,6 +1472,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
/* ubus.c */ /* ubus.c */
#ifdef HAVE_UBUS #ifdef HAVE_UBUS
void ubus_init(void);
void set_ubus_listeners(void); void set_ubus_listeners(void);
void check_ubus_listeners(void); void check_ubus_listeners(void);
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface); void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);

View File

@@ -20,29 +20,112 @@
#include <libubus.h> #include <libubus.h>
static struct ubus_context *ubus = NULL;
static struct blob_buf b; static struct blob_buf b;
static int notify;
static int error_logged = 0;
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct ubus_request_data *req, const char *method,
struct blob_attr *msg); struct blob_attr *msg);
static struct ubus_method ubus_object_methods[] = {
{.name = "metrics", .handler = ubus_handle_metrics}, static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
static const struct ubus_method ubus_object_methods[] = {
UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
}; };
static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods); static struct ubus_object_type ubus_object_type =
UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
static struct ubus_object ubus_object = { static struct ubus_object ubus_object = {
.name = "dnsmasq", .name = "dnsmasq",
.type = &ubus_object_type, .type = &ubus_object_type,
.methods = ubus_object_methods, .methods = ubus_object_methods,
.n_methods = ARRAY_SIZE(ubus_object_methods), .n_methods = ARRAY_SIZE(ubus_object_methods),
.subscribe_cb = ubus_subscribe_cb,
}; };
static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
{
(void)ctx;
my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
notify = obj->has_subscribers;
}
static void ubus_destroy(struct ubus_context *ubus)
{
// Forces re-initialization when we're reusing the same definitions later on.
ubus_object.id = 0;
ubus_object_type.id = 0;
ubus_free(ubus);
daemon->ubus = NULL;
}
static void ubus_disconnect_cb(struct ubus_context *ubus)
{
int ret;
ret = ubus_reconnect(ubus, NULL);
if (ret)
{
my_syslog(LOG_ERR, _("Cannot reconnect to UBus: %s"), ubus_strerror(ret));
ubus_destroy(ubus);
}
}
void ubus_init()
{
struct ubus_context *ubus = NULL;
int ret = 0;
ubus = ubus_connect(NULL);
if (!ubus)
{
if (!error_logged)
{
my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed"));
error_logged = 1;
}
ubus_destroy(ubus);
return;
}
ret = ubus_add_object(ubus, &ubus_object);
if (ret)
{
if (!error_logged)
{
my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
error_logged = 1;
}
return;
}
ubus->connection_lost = ubus_disconnect_cb;
daemon->ubus = ubus;
error_logged = 0;
my_syslog(LOG_INFO, _("Connected to system UBus"));
}
void set_ubus_listeners() void set_ubus_listeners()
{ {
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
if (!ubus) if (!ubus)
return; {
if (!error_logged)
{
my_syslog(LOG_ERR, _("Cannot set UBus listeners: no connection"));
error_logged = 1;
}
return;
}
error_logged = 0;
poll_listen(ubus->sock.fd, POLLIN); poll_listen(ubus->sock.fd, POLLIN);
poll_listen(ubus->sock.fd, POLLERR); poll_listen(ubus->sock.fd, POLLERR);
@@ -51,46 +134,57 @@ void set_ubus_listeners()
void check_ubus_listeners() void check_ubus_listeners()
{ {
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
if (!ubus) if (!ubus)
{ {
ubus = ubus_connect(NULL); if (!error_logged)
if (!ubus) {
return; my_syslog(LOG_ERR, _("Cannot poll UBus listeners: no connection"));
ubus_add_object(ubus, &ubus_object); error_logged = 1;
}
return;
} }
error_logged = 0;
if (poll_check(ubus->sock.fd, POLLIN)) if (poll_check(ubus->sock.fd, POLLIN))
ubus_handle_event(ubus); ubus_handle_event(ubus);
if (poll_check(ubus->sock.fd, POLLHUP)) if (poll_check(ubus->sock.fd, POLLHUP | POLLERR))
{ {
ubus_free(ubus); my_syslog(LOG_INFO, _("Disconnecting from UBus"));
ubus = NULL;
ubus_destroy(ubus);
} }
} }
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct ubus_request_data *req, const char *method,
struct blob_attr *msg) struct blob_attr *msg)
{ {
int i; int i;
blob_buf_init(&b, 0);
for(i=0; i < __METRIC_MAX; i++) (void)obj;
(void)method;
(void)msg;
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
for (i=0; i < __METRIC_MAX; i++)
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]); blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
ubus_send_reply(ctx, req, b.head); return ubus_send_reply(ctx, req, b.head);
return 0;
} }
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface) void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
{ {
if (!ubus || !ubus_object.has_subscribers) struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
int ret;
if (!ubus || !notify)
return; return;
blob_buf_init(&b, 0); blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
if (mac) if (mac)
blobmsg_add_string(&b, "mac", mac); blobmsg_add_string(&b, "mac", mac);
if (ip) if (ip)
@@ -100,7 +194,9 @@ void ubus_event_bcast(const char *type, const char *mac, const char *ip, const c
if (interface) if (interface)
blobmsg_add_string(&b, "interface", interface); blobmsg_add_string(&b, "interface", interface);
ubus_notify(ubus, &ubus_object, type, b.head, -1); ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
if (!ret)
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
} }