summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas BESNARD2024-11-20 16:34:30 +0000
committerÁlvaro Fernández Rojas2025-11-03 15:21:24 +0000
commitaf669fb23cd3b8090beda8bbeda0df57e92eb204 (patch)
tree6ec4067877976251bbb0034c7aaee635280a2fa0
parent3a1a599fecb7b06f1a6847d5a4dc44c886c12f81 (diff)
dhcpv6: implement statistics for DHCPv6
Problem: odhcp6c does not provide any statistics. Solution: Count the number of packets transmitted or received by message type. Add a UBus RPC method to get this information. Signed-off-by: Nicolas BESNARD <nico.besnard31@gmail.com> Signed-off-by: Paul Donald <newtwen+github@gmail.com> Link: https://github.com/openwrt/odhcp6c/pull/106 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
-rw-r--r--src/dhcpv6.c68
-rw-r--r--src/odhcp6c.h19
-rw-r--r--src/ubus.c43
3 files changed, 129 insertions, 1 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 9637ada..dc48fe0 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -118,6 +118,9 @@ static uint8_t reconf_key[16];
// client options
static unsigned int client_options = 0;
+// counters for statistics
+static struct dhcpv6_stats dhcpv6_stats = {0};
+
static uint32_t ntohl_unaligned(const uint8_t *data)
{
uint32_t buf;
@@ -138,6 +141,54 @@ static void dhcpv6_prev_state(void)
dhcpv6_reset_state_timeout();
}
+static void dhcpv6_inc_counter(enum dhcpv6_msg type)
+{
+ switch (type) {
+ case DHCPV6_MSG_SOLICIT:
+ dhcpv6_stats.solicit++;
+ break;
+
+ case DHCPV6_MSG_ADVERT:
+ dhcpv6_stats.advertise++;
+ break;
+
+ case DHCPV6_MSG_REQUEST:
+ dhcpv6_stats.request++;
+ break;
+
+ case DHCPV6_MSG_RENEW:
+ dhcpv6_stats.renew++;
+ break;
+
+ case DHCPV6_MSG_REBIND:
+ dhcpv6_stats.rebind++;
+ break;
+
+ case DHCPV6_MSG_REPLY:
+ dhcpv6_stats.reply++;
+ break;
+
+ case DHCPV6_MSG_RELEASE:
+ dhcpv6_stats.release++;
+ break;
+
+ case DHCPV6_MSG_DECLINE:
+ dhcpv6_stats.decline++;
+ break;
+
+ case DHCPV6_MSG_RECONF:
+ dhcpv6_stats.reconfigure++;
+ break;
+
+ case DHCPV6_MSG_INFO_REQ:
+ dhcpv6_stats.information_request++;
+ break;
+
+ default:
+ break;
+ }
+}
+
static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
{
switch (msg) {
@@ -340,6 +391,16 @@ void dhcpv6_reset_state_timeout(void)
dhcpv6_state_timeout = 0;
}
+struct dhcpv6_stats dhcpv6_get_stats(void)
+{
+ return dhcpv6_stats;
+}
+
+void dhcpv6_reset_stats(void)
+{
+ memset(&dhcpv6_stats, 0, sizeof(dhcpv6_stats));
+}
+
int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout, unsigned int dscp)
{
client_options = options;
@@ -794,6 +855,9 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
dhcpv6_msg_to_str(type),
inet_ntop(AF_INET6, (const void *)&srv.sin6_addr,
in6_str, sizeof(in6_str)), strerror(errno));
+ dhcpv6_stats.transmit_failures++;
+ } else {
+ dhcpv6_inc_counter(type);
}
}
@@ -1900,14 +1964,18 @@ int dhcpv6_receive_response(enum dhcpv6_msg type)
}
if (pktinfo == NULL) {
+ dhcpv6_stats.discarded_packets++;
return -1;
}
if (!dhcpv6_response_is_valid(buf, len, retx->tr_id, type,
&pktinfo->ipi6_addr)) {
+ dhcpv6_stats.discarded_packets++;
return -1;
}
+ dhcpv6_inc_counter(hdr->msg_type);
+
uint8_t *opt = &buf[4];
uint8_t *opt_end = opt + len - 4;
retx->round_start = odhcp6c_get_milli_time();
diff --git a/src/odhcp6c.h b/src/odhcp6c.h
index a28decc..740dce7 100644
--- a/src/odhcp6c.h
+++ b/src/odhcp6c.h
@@ -323,7 +323,22 @@ struct dhcpv6_server_cand {
size_t ia_pd_len;
};
-
+struct dhcpv6_stats {
+ uint64_t solicit;
+ uint64_t advertise;
+ uint64_t request;
+ uint64_t confirm;
+ uint64_t renew;
+ uint64_t rebind;
+ uint64_t reply;
+ uint64_t release;
+ uint64_t decline;
+ uint64_t reconfigure;
+ uint64_t information_request;
+ uint64_t discarded_packets;
+ uint64_t transmit_failures;
+};
+
enum odhcp6c_state {
STATE_CLIENT_ID,
STATE_SERVER_ID,
@@ -437,6 +452,8 @@ int dhcpv6_receive_response(enum dhcpv6_msg type);
enum dhcpv6_state dhcpv6_get_state(void);
void dhcpv6_set_state(enum dhcpv6_state state);
int dhcpv6_get_socket(void);
+struct dhcpv6_stats dhcpv6_get_stats(void);
+void dhcpv6_reset_stats(void);
int dhcpv6_state_processing(enum dhcpv6_msg type);
int dhcpv6_get_state_timeout(void);
void dhcpv6_set_state_timeout(int timeout);
diff --git a/src/ubus.c b/src/ubus.c
index ebe16ae..402ba68 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -103,9 +103,15 @@ static char ubus_name[24];
static int ubus_handle_get_state(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+static int ubus_handle_get_stats(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+static int ubus_handle_reset_stats(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method, struct blob_attr *msg);
static struct ubus_method odhcp6c_object_methods[] = {
UBUS_METHOD_NOARG("get_state", ubus_handle_get_state),
+ UBUS_METHOD_NOARG("get_statistics", ubus_handle_get_stats),
+ UBUS_METHOD_NOARG("reset_statistics", ubus_handle_reset_stats),
};
static struct ubus_object_type odhcp6c_object_type =
@@ -528,6 +534,43 @@ static int states_to_blob(void)
return UBUS_STATUS_OK;
}
+static int ubus_handle_get_stats(struct ubus_context *ctx, _unused struct ubus_object *obj,
+ struct ubus_request_data *req, _unused const char *method,
+ _unused struct blob_attr *msg)
+{
+ struct dhcpv6_stats stats = dhcpv6_get_stats();
+
+ blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
+ blobmsg_add_u64(&b, "dhcp_solicit", stats.solicit);
+ blobmsg_add_u64(&b, "dhcp_advertise", stats.advertise);
+ blobmsg_add_u64(&b, "dhcp_request", stats.request);
+ blobmsg_add_u64(&b, "dhcp_confirm", stats.confirm);
+ blobmsg_add_u64(&b, "dhcp_renew", stats.renew);
+ blobmsg_add_u64(&b, "dhcp_rebind", stats.rebind);
+ blobmsg_add_u64(&b, "dhcp_reply", stats.reply);
+ blobmsg_add_u64(&b, "dhcp_release", stats.release);
+ blobmsg_add_u64(&b, "dhcp_decline", stats.decline);
+ blobmsg_add_u64(&b, "dhcp_reconfigure", stats.reconfigure);
+ blobmsg_add_u64(&b, "dhcp_information_request", stats.information_request);
+ blobmsg_add_u64(&b, "dhcp_discarded_packets", stats.discarded_packets);
+ blobmsg_add_u64(&b, "dhcp_transmit_failures", stats.transmit_failures);
+
+ CHECK(ubus_send_reply(ctx, req, b.head));
+ blob_buf_free(&b);
+
+ return UBUS_STATUS_OK;
+}
+
+static int ubus_handle_reset_stats(_unused struct ubus_context *ctx, _unused struct ubus_object *obj,
+ _unused struct ubus_request_data *req, _unused const char *method,
+ _unused struct blob_attr *msg)
+{
+ dhcpv6_reset_stats();
+
+ return UBUS_STATUS_OK;
+}
+
+
static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_object *obj,
struct ubus_request_data *req, _unused const char *method,
_unused struct blob_attr *msg)