From: Nicolas BESNARD Date: Wed, 20 Nov 2024 16:34:30 +0000 (+0000) Subject: dhcpv6: implement statistics for DHCPv6 X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=af669fb23cd3b8090beda8bbeda0df57e92eb204;p=project%2Fodhcp6c.git 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 Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcp6c/pull/106 Signed-off-by: Álvaro Fernández Rojas --- 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)