[PATCH grout] replace clock_t with Grout specific high-res clock

Morten Brørup mb at smartsharesystems.com
Sun May 24 12:50:35 CEST 2026


The clock_t type is implementation specific.
E.g. on Linux, it is microseconds, and on Windows it is milliseconds.

Replace all uses of clock_t and its accompanying function, gr_clock_us(),
with a new nanosecond resolution clock type, gr_clock_ns_t, and its
accompanying function, gr_grout_ns().

Note about signedness:
I condidered making the gr_clock_ns_t unsigned, but that would require
additional considerations in code where it is used, e.g. for calculating
age, to prevent wraparound in race conditions. E.g.:
age = (gr_clock_ns() - fdb->last_seen) / NS_PER_S;
If the current thread reads the clock using gr_clock_ns(), and another
thread races to set fdb->last_seen afterwards, the result of the
subtraction is negative. The division by NS_PER_S makes the age zero.
If gr_clock_ns_t was unsigned, the negative result of the subtraction
would be a very large unsigned number. Dividing this very large number
by NS_PER_S would be a large unsigned number, not zero.
Obviously, this could be fixed by type casting gr_clock_ns_t values to
signed int64_t everywhere they are used with subtraction. But such a
requirement increases the risk of bugs.
So I decided to make it signed, like type_t.

Signed-off-by: Morten Brørup <mb at smartsharesystems.com>
---
 api/gr_clock.h                           | 17 +++++++++++++----
 cli/main.c                               |  2 +-
 modules/infra/control/bond.h             |  5 +++--
 modules/infra/control/l3_nexthop.c       |  4 ++--
 modules/infra/control/lacp.c             | 14 +++++++-------
 modules/infra/control/nexthop.h          |  4 ++--
 modules/ip/api/gr_ip4.h                  |  2 +-
 modules/ip/control/icmp.c                |  6 +++---
 modules/ip/control/nexthop.c             |  2 +-
 modules/ip/datapath/arp_output_request.c |  2 +-
 modules/ip/datapath/icmp_input.c         |  2 +-
 modules/ip/datapath/icmp_local_send.c    | 10 +++++-----
 modules/ip6/api/gr_ip6.h                 |  2 +-
 modules/ip6/control/icmp6.c              | 10 +++++-----
 modules/ip6/control/nexthop.c            |  2 +-
 modules/ip6/datapath/icmp6_input.c       |  2 +-
 modules/ip6/datapath/icmp6_local_send.c  |  6 +++---
 modules/ip6/datapath/ndp_ns_output.c     |  2 +-
 modules/l2/api/gr_l2.h                   |  3 ++-
 modules/l2/cli/fdb.c                     |  2 +-
 modules/l2/control/fdb.c                 | 12 ++++++------
 modules/policy/api/gr_conntrack.h        |  2 +-
 modules/policy/cli/conntrack.c           |  6 +++---
 modules/policy/control/conntrack.c       |  6 +++---
 modules/policy/control/conntrack.h       |  2 +-
 smoke/fib_inject.c                       |  6 +++---
 26 files changed, 72 insertions(+), 61 deletions(-)

diff --git a/api/gr_clock.h b/api/gr_clock.h
index 07741b6a..a0d8f56f 100644
--- a/api/gr_clock.h
+++ b/api/gr_clock.h
@@ -1,20 +1,29 @@
 // SPDX-License-Identifier: BSD-3-Clause
 // Copyright (c) 2025 Robin Jarry
+// Copyright (c) 2026 SmartShare Systems
 
 #pragma once
 
 #include <stdint.h>
 #include <time.h>
 
-// Get the elapsed time since last boot (using a common clock across all processes).
+// High-resolution clock [nanoseconds].
+// Used with CLOCK_MONOTONIC_RAW, unless otherwise specified.
+// Note: Does not have Y2038 problems. Not even with CLOCK_REALTIME.
+// Note: Using signed, to avoid need for casting to signed in calculations where race conditions may cause negative differences.
+typedef int64_t gr_clock_ns_t;
+
+// Get powered-on (non-suspended, non-hibernated) time since last boot (using a common clock across all processes).
 static inline struct timespec gr_clock_raw(void) {
 	struct timespec tp = {0};
 	clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
 	return tp;
 }
 
-// Get elapsed time since last boot in microseconds.
-static inline clock_t gr_clock_us(void) {
+// Get powered-on (non-suspended, non-hibernated) time since last boot in nanoseconds.
+// Does not return negative values.
+static inline gr_clock_ns_t gr_clock_ns(void) {
 	struct timespec tp = gr_clock_raw();
-	return (tp.tv_sec * CLOCKS_PER_SEC) + (tp.tv_nsec / 1000);
+	uint64_t ret = (uint64_t)tp.tv_sec * UINT64_C(1000000000) + (uint64_t)tp.tv_nsec;
+	return (int64_t)ret;
 }
diff --git a/cli/main.c b/cli/main.c
index 17b822c6..defaedcf 100644
--- a/cli/main.c
+++ b/cli/main.c
@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
 	tty_init();
 
 	// initialize a non-constant seed for random() calls
-	srandom(gr_clock_us());
+	srandom(gr_clock_ns());
 
 	if (ec_init() < 0) {
 		errorf("ec_init: %s", strerror(errno));
diff --git a/modules/infra/control/bond.h b/modules/infra/control/bond.h
index 371c5bad..ad7d4dd6 100644
--- a/modules/infra/control/bond.h
+++ b/modules/infra/control/bond.h
@@ -6,6 +6,7 @@
 #include "iface.h"
 #include "lacp.h"
 
+#include <gr_clock.h>
 #include <gr_infra.h>
 
 #include <stdint.h>
@@ -16,8 +17,8 @@ struct bond_member {
 	struct iface *iface;
 	bool active;
 	bool need_to_transmit; // Need to send immediately
-	clock_t next_tx; // Next time we need to send a LACP packet
-	clock_t last_rx; // Last time we received a LACP packet
+	gr_clock_ns_t next_tx; // Next time we need to send a LACP packet
+	gr_clock_ns_t last_rx; // Last time we received a LACP packet
 	// For direct inclusion in LACP packets
 	struct lacp_participant local;
 	struct lacp_participant remote;
diff --git a/modules/infra/control/l3_nexthop.c b/modules/infra/control/l3_nexthop.c
index 90076ea3..92ca484b 100644
--- a/modules/infra/control/l3_nexthop.c
+++ b/modules/infra/control/l3_nexthop.c
@@ -295,12 +295,12 @@ static struct nexthop_type_ops l3_nh_ops = {
 
 static void l3_age(struct nexthop *nh, struct nexthop_info_l3 *l3) {
 	const struct nexthop_af_ops *ops;
-	clock_t now = gr_clock_us();
+	gr_clock_ns_t now = gr_clock_ns();
 	unsigned probes, max_probes;
 	time_t reply_age;
 
 	ops = af_ops[l3->af];
-	reply_age = (now - l3->last_reply) / CLOCKS_PER_SEC;
+	reply_age = (now - l3->last_reply) / NS_PER_S;
 	max_probes = nh_conf.max_ucast_probes + nh_conf.max_bcast_probes;
 	probes = l3->ucast_probes + l3->bcast_probes;
 
diff --git a/modules/infra/control/lacp.c b/modules/infra/control/lacp.c
index 63fb101b..cf3b693e 100644
--- a/modules/infra/control/lacp.c
+++ b/modules/infra/control/lacp.c
@@ -65,7 +65,7 @@ void lacp_input_cb(void *obj, uintptr_t, const struct control_queue_drain *drain
 
 	// Store partner information from received PDU
 	member->remote = pdu->actor;
-	member->last_rx = gr_clock_us();
+	member->last_rx = gr_clock_ns();
 
 	// Save old member state to detect changes
 	bool old_active = member->active;
@@ -119,10 +119,10 @@ static void lacp_periodic(evutil_socket_t, short, void *) {
 	struct iface_info_bond *bond;
 	struct bond_member *member;
 	const struct iface *port;
-	clock_t now, timeout;
+	gr_clock_ns_t now, timeout;
 	struct iface *iface;
 
-	now = gr_clock_us();
+	now = gr_clock_ns();
 
 	iface = NULL;
 	while ((iface = iface_next(GR_IFACE_TYPE_BOND, iface)) != NULL) {
@@ -139,9 +139,9 @@ static void lacp_periodic(evutil_socket_t, short, void *) {
 			// Check for timeout if we've received at least one PDU
 			if (member->last_rx != 0) {
 				if (member->local.state & LACP_STATE_FAST)
-					timeout = LACP_SHORT_TIMEOUT * US_PER_S;
+					timeout = LACP_SHORT_TIMEOUT * (gr_clock_ns_t)NS_PER_S;
 				else
-					timeout = LACP_LONG_TIMEOUT * US_PER_S;
+					timeout = LACP_LONG_TIMEOUT * (gr_clock_ns_t)NS_PER_S;
 
 				if (now - member->last_rx > timeout && member->active) {
 					// Partner timed out - enter FAILED state
@@ -175,9 +175,9 @@ static void lacp_periodic(evutil_socket_t, short, void *) {
 
 			member->need_to_transmit = false;
 			if (member->remote.state & LACP_STATE_FAST)
-				member->next_tx = now + LACP_SHORT_TIMEOUT * US_PER_S;
+				member->next_tx = now + LACP_SHORT_TIMEOUT * (gr_clock_ns_t)NS_PER_S;
 			else
-				member->next_tx = now + LACP_LONG_TIMEOUT * US_PER_S;
+				member->next_tx = now + LACP_LONG_TIMEOUT * (gr_clock_ns_t)NS_PER_S;
 		}
 
 		// Update active members list if any port timed out
diff --git a/modules/infra/control/nexthop.h b/modules/infra/control/nexthop.h
index 934796bf..5cf72a3a 100644
--- a/modules/infra/control/nexthop.h
+++ b/modules/infra/control/nexthop.h
@@ -41,8 +41,8 @@ static_assert(sizeof(struct nexthop) <= (RTE_CACHE_LINE_MIN_SIZE * 2));
 GR_NH_TYPE_INFO(GR_NH_T_L3, nexthop_info_l3, {
 	BASE(gr_nexthop_info_l3);
 
-	clock_t last_reply; //!< timestamp when last update was received
-	clock_t last_request;
+	gr_clock_ns_t last_reply; //!< timestamp when last update was received
+	gr_clock_ns_t last_request;
 
 	uint8_t ucast_probes;
 	uint8_t bcast_probes;
diff --git a/modules/ip/api/gr_ip4.h b/modules/ip/api/gr_ip4.h
index c150863e..8bf13a4b 100644
--- a/modules/ip/api/gr_ip4.h
+++ b/modules/ip/api/gr_ip4.h
@@ -143,7 +143,7 @@ struct gr_ip4_icmp_recv_resp {
 	uint16_t ident;
 	uint16_t seq_num;
 	ip4_addr_t src_addr;
-	clock_t response_time;
+	gr_clock_ns_t response_time;
 };
 
 GR_REQ(GR_IP4_ICMP_RECV, struct gr_ip4_icmp_recv_req, struct gr_ip4_icmp_recv_resp);
diff --git a/modules/ip/control/icmp.c b/modules/ip/control/icmp.c
index c07712e5..9e836c5b 100644
--- a/modules/ip/control/icmp.c
+++ b/modules/ip/control/icmp.c
@@ -15,7 +15,7 @@
 
 struct icmp_queue_item {
 	struct rte_mbuf *mbuf;
-	clock_t timestamp;
+	gr_clock_ns_t timestamp;
 	STAILQ_ENTRY(icmp_queue_item) next;
 };
 
@@ -46,7 +46,7 @@ static void icmp_input_cb(void *m, uintptr_t timestamp, const struct control_que
 
 // Search for the oldest ICMP response matching the given identifier.
 // If found, the packet is removed from the queue.
-static struct rte_mbuf *get_icmp_response(uint16_t ident, uint16_t seq_num, clock_t *timestamp) {
+static struct rte_mbuf *get_icmp_response(uint16_t ident, uint16_t seq_num, gr_clock_ns_t *timestamp) {
 	struct icmp_queue_item *i, *tmp;
 	struct rte_mbuf *mbuf = NULL;
 
@@ -105,7 +105,7 @@ out:
 static struct api_out icmp_recv(const void *request, struct api_ctx *) {
 	const struct gr_ip4_icmp_recv_req *icmp_req = request;
 	struct gr_ip4_icmp_recv_resp *resp = NULL;
-	clock_t *pkt_timestamp, rcv_timestamp;
+	gr_clock_ns_t *pkt_timestamp, rcv_timestamp;
 	struct rte_icmp_hdr *icmp;
 	struct rte_ipv4_hdr *ip;
 	struct rte_mbuf *m;
diff --git a/modules/ip/control/nexthop.c b/modules/ip/control/nexthop.c
index c9006146..3ef0c3e9 100644
--- a/modules/ip/control/nexthop.c
+++ b/modules/ip/control/nexthop.c
@@ -187,7 +187,7 @@ void arp_probe_input_cb(void *obj, uintptr_t, const struct control_queue_drain *
 	// static next hops never need updating
 	if (!(l3->flags & GR_NH_F_STATIC)) {
 		// Refresh all fields.
-		l3->last_reply = gr_clock_us();
+		l3->last_reply = gr_clock_ns();
 		l3->state = GR_NH_S_REACHABLE;
 		l3->ucast_probes = 0;
 		l3->bcast_probes = 0;
diff --git a/modules/ip/datapath/arp_output_request.c b/modules/ip/datapath/arp_output_request.c
index 67db9df0..9633cdcf 100644
--- a/modules/ip/datapath/arp_output_request.c
+++ b/modules/ip/datapath/arp_output_request.c
@@ -35,7 +35,7 @@ int arp_output_request_solicit(struct nexthop *nh) {
 	} else {
 		// This function is called by the control plane main thread.
 		// It is OK to modify the nexthop here.
-		l3->last_request = gr_clock_us();
+		l3->last_request = gr_clock_ns();
 		if (l3->ucast_probes < nh_conf.max_ucast_probes)
 			l3->ucast_probes++;
 		else
diff --git a/modules/ip/datapath/icmp_input.c b/modules/ip/datapath/icmp_input.c
index 167cc9d7..b0426246 100644
--- a/modules/ip/datapath/icmp_input.c
+++ b/modules/ip/datapath/icmp_input.c
@@ -55,7 +55,7 @@ icmp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs,
 			ip_data->src = ip;
 			edge = OUTPUT;
 		} else if (icmp_cb[icmp->icmp_type]) {
-			control_output_set_cb(mbuf, icmp_cb[icmp->icmp_type], gr_clock_us());
+			control_output_set_cb(mbuf, icmp_cb[icmp->icmp_type], gr_clock_ns());
 			edge = CONTROL;
 		} else {
 			edge = UNSUPPORTED;
diff --git a/modules/ip/datapath/icmp_local_send.c b/modules/ip/datapath/icmp_local_send.c
index cc504e5c..3377b3a8 100644
--- a/modules/ip/datapath/icmp_local_send.c
+++ b/modules/ip/datapath/icmp_local_send.c
@@ -90,18 +90,18 @@ static uint16_t icmp_local_send_process(
 	struct rte_icmp_hdr *icmp;
 	struct ctl_to_stack *msg;
 	struct rte_mbuf *mbuf;
-	clock_t *payload;
+	gr_clock_ns_t *payload;
 	rte_edge_t next;
 
 	for (unsigned i = 0; i < n_objs; i++) {
 		mbuf = objs[i];
 		msg = control_input_mbuf_data(mbuf)->data;
 		icmp = (struct rte_icmp_hdr *)rte_pktmbuf_append(
-			mbuf, sizeof(*icmp) + sizeof(clock_t)
+			mbuf, sizeof(*icmp) + sizeof(gr_clock_ns_t)
 		);
 
-		payload = rte_pktmbuf_mtod_offset(mbuf, clock_t *, sizeof(*icmp));
-		*payload = gr_clock_us();
+		payload = rte_pktmbuf_mtod_offset(mbuf, gr_clock_ns_t *, sizeof(*icmp));
+		*payload = gr_clock_ns();
 
 		// Build ICMP packet
 		icmp->icmp_type = RTE_ICMP_TYPE_ECHO_REQUEST;
@@ -116,7 +116,7 @@ static uint16_t icmp_local_send_process(
 
 		data = ip_local_mbuf_data(mbuf);
 		data->proto = IPPROTO_ICMP;
-		data->len = sizeof(*icmp) + sizeof(clock_t);
+		data->len = sizeof(*icmp) + sizeof(gr_clock_ns_t);
 		data->dst = msg->dst;
 		data->src = msg->src;
 		data->vrf_id = msg->vrf_id;
diff --git a/modules/ip6/api/gr_ip6.h b/modules/ip6/api/gr_ip6.h
index bb147a43..d060b191 100644
--- a/modules/ip6/api/gr_ip6.h
+++ b/modules/ip6/api/gr_ip6.h
@@ -208,7 +208,7 @@ struct gr_ip6_icmp_recv_resp {
 	uint16_t ident;
 	uint16_t seq_num;
 	struct rte_ipv6_addr src_addr;
-	clock_t response_time;
+	gr_clock_ns_t response_time;
 };
 
 GR_REQ(GR_IP6_ICMP6_RECV, struct gr_ip6_icmp_recv_req, struct gr_ip6_icmp_recv_resp);
diff --git a/modules/ip6/control/icmp6.c b/modules/ip6/control/icmp6.c
index d0ae86dc..2a3098eb 100644
--- a/modules/ip6/control/icmp6.c
+++ b/modules/ip6/control/icmp6.c
@@ -15,7 +15,7 @@
 
 struct icmp_queue_item {
 	struct rte_mbuf *mbuf;
-	clock_t timestamp;
+	gr_clock_ns_t timestamp;
 	STAILQ_ENTRY(icmp_queue_item) next;
 };
 
@@ -44,13 +44,13 @@ static void icmp6_input_cb(void *m, uintptr_t timestamp, const struct control_qu
 }
 
 #define ICMP6_ERROR_PKT_LEN                                                                        \
-	(GR_ICMP6_HDR_LEN + sizeof(struct rte_ipv6_hdr) + GR_ICMP6_HDR_LEN + sizeof(clock_t))
+	(GR_ICMP6_HDR_LEN + sizeof(struct rte_ipv6_hdr) + GR_ICMP6_HDR_LEN + sizeof(gr_clock_ns_t))
 
 static struct rte_mbuf *get_icmp6_echo_reply(
 	uint16_t ident,
 	uint16_t seq_num,
 	struct icmp6 **out_icmp6,
-	clock_t *timestamp
+	gr_clock_ns_t *timestamp
 ) {
 	struct icmp_queue_item *i, *tmp;
 	struct rte_mbuf *mbuf;
@@ -61,7 +61,7 @@ static struct rte_mbuf *get_icmp6_echo_reply(
 	STAILQ_FOREACH_SAFE (i, &icmp_queue, next, tmp) {
 		mbuf = i->mbuf;
 
-		if (rte_pktmbuf_pkt_len(mbuf) < GR_ICMP6_HDR_LEN + sizeof(clock_t))
+		if (rte_pktmbuf_pkt_len(mbuf) < GR_ICMP6_HDR_LEN + sizeof(gr_clock_ns_t))
 			goto free_and_skip;
 
 		icmp6 = rte_pktmbuf_mtod(mbuf, struct icmp6 *);
@@ -112,7 +112,7 @@ static struct api_out icmp6_recv(const void *request, struct api_ctx *) {
 	struct ip6_local_mbuf_data *d_ip6;
 	struct icmp6 *icmp6;
 	struct icmp6_echo_reply *icmp6_echo;
-	clock_t *pkt_timestamp, rcv_timestamp;
+	gr_clock_ns_t *pkt_timestamp, rcv_timestamp;
 	struct rte_mbuf *m;
 	int ret = 0;
 
diff --git a/modules/ip6/control/nexthop.c b/modules/ip6/control/nexthop.c
index 2012bda1..5e53cc52 100644
--- a/modules/ip6/control/nexthop.c
+++ b/modules/ip6/control/nexthop.c
@@ -236,7 +236,7 @@ void ndp_probe_input_cb(void *obj, uintptr_t, const struct control_queue_drain *
 
 	if (!(l3->flags & GR_NH_F_STATIC) && lladdr_found == ICMP6_OPT_FOUND) {
 		// Refresh all fields.
-		l3->last_reply = gr_clock_us();
+		l3->last_reply = gr_clock_ns();
 		l3->state = GR_NH_S_REACHABLE;
 		l3->ucast_probes = 0;
 		l3->bcast_probes = 0;
diff --git a/modules/ip6/datapath/icmp6_input.c b/modules/ip6/datapath/icmp6_input.c
index 6ce747d0..cbeb3f7e 100644
--- a/modules/ip6/datapath/icmp6_input.c
+++ b/modules/ip6/datapath/icmp6_input.c
@@ -82,7 +82,7 @@ icmp6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs,
 		case ICMP6_TYPE_ROUTER_ADVERT:
 		default:
 			if (icmp6_cb[icmp6->type] != NULL) {
-				control_output_set_cb(mbuf, icmp6_cb[icmp6->type], gr_clock_us());
+				control_output_set_cb(mbuf, icmp6_cb[icmp6->type], gr_clock_ns());
 				next = CONTROL;
 			} else {
 				next = UNSUPPORTED;
diff --git a/modules/ip6/datapath/icmp6_local_send.c b/modules/ip6/datapath/icmp6_local_send.c
index 676935c2..4da94801 100644
--- a/modules/ip6/datapath/icmp6_local_send.c
+++ b/modules/ip6/datapath/icmp6_local_send.c
@@ -85,14 +85,14 @@ static uint16_t icmp6_local_send_process(
 	struct ctl_to_stack *msg;
 	struct rte_mbuf *mbuf;
 	struct icmp6 *icmp6;
-	clock_t *payload;
+	gr_clock_ns_t *payload;
 	rte_edge_t next;
 	size_t pkt_len;
 
 	for (unsigned i = 0; i < n_objs; i++) {
 		mbuf = objs[i];
 		msg = control_input_mbuf_data(mbuf)->data;
-		pkt_len = sizeof(*icmp6) + sizeof(*icmp6_echo) + sizeof(clock_t);
+		pkt_len = sizeof(*icmp6) + sizeof(*icmp6_echo) + sizeof(gr_clock_ns_t);
 		icmp6 = (struct icmp6 *)rte_pktmbuf_append(mbuf, pkt_len);
 
 		icmp6->type = ICMP6_TYPE_ECHO_REQUEST;
@@ -108,7 +108,7 @@ static uint16_t icmp6_local_send_process(
 		mbuf->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
 
 		payload = PAYLOAD(icmp6_echo);
-		*payload = gr_clock_us();
+		*payload = gr_clock_ns();
 
 		data = ip6_local_mbuf_data(mbuf);
 		data->iface = iface_from_id(msg->iface_id);
diff --git a/modules/ip6/datapath/ndp_ns_output.c b/modules/ip6/datapath/ndp_ns_output.c
index 22f9da34..7c059392 100644
--- a/modules/ip6/datapath/ndp_ns_output.c
+++ b/modules/ip6/datapath/ndp_ns_output.c
@@ -32,7 +32,7 @@ int nh6_solicit(struct nexthop *nh) {
 
 	// This function is called by the control plane main thread.
 	// It is OK to modify the nexthop here.
-	l3->last_request = gr_clock_us();
+	l3->last_request = gr_clock_ns();
 	if (l3->ucast_probes < nh_conf.max_ucast_probes)
 		l3->ucast_probes++;
 	else
diff --git a/modules/l2/api/gr_l2.h b/modules/l2/api/gr_l2.h
index b1088a4e..071ec409 100644
--- a/modules/l2/api/gr_l2.h
+++ b/modules/l2/api/gr_l2.h
@@ -5,6 +5,7 @@
 
 #include <gr_api.h>
 #include <gr_bitops.h>
+#include <gr_clock.h>
 #include <gr_macro.h>
 #include <gr_net_types.h>
 
@@ -74,7 +75,7 @@ struct gr_fdb_entry {
 	uint16_t iface_id; // Updated automatically when a MAC moves between members.
 	struct l3_addr vtep; // Remote VTEP for VXLAN-learned entries, 0 for local.
 	gr_fdb_flags_t flags;
-	clock_t last_seen; // Refreshed on each datapath hit for learned entries.
+	gr_clock_ns_t last_seen; // Refreshed on each datapath hit for learned entries.
 };
 
 enum gr_l2_requests : uint32_t {
diff --git a/modules/l2/cli/fdb.c b/modules/l2/cli/fdb.c
index 532e5045..94439741 100644
--- a/modules/l2/cli/fdb.c
+++ b/modules/l2/cli/fdb.c
@@ -138,7 +138,7 @@ static cmd_status_t fdb_show(struct gr_api_client *c, const struct ec_pnode *p)
 		if (fdb_format_flags(flags, sizeof(flags), fdb->flags))
 			gr_table_cell(table, 5, "%s", flags);
 
-		gr_table_cell(table, 6, "%ld", (gr_clock_us() - fdb->last_seen) / CLOCKS_PER_SEC);
+		gr_table_cell(table, 6, "%ld", (gr_clock_ns() - fdb->last_seen) / INT64_C(1000000000));
 
 		if (gr_table_print_row(table) < 0)
 			break;
diff --git a/modules/l2/control/fdb.c b/modules/l2/control/fdb.c
index 3982cce1..0c8b87b6 100644
--- a/modules/l2/control/fdb.c
+++ b/modules/l2/control/fdb.c
@@ -138,7 +138,7 @@ void fdb_learn(
 		fdb = data;
 	}
 
-	fdb->last_seen = gr_clock_us();
+	fdb->last_seen = gr_clock_ns();
 
 	if ((fdb->flags & GR_FDB_F_LEARN)
 	    && (fdb->iface_id != iface_id || !l3_addr_eq(&fdb->vtep, vtep))) {
@@ -207,7 +207,7 @@ static struct api_out fdb_add(const void *request, struct api_ctx *) {
 		e = data;
 		*e = req->fdb;
 		e->bridge_id = iface->id;
-		e->last_seen = gr_clock_us();
+		e->last_seen = gr_clock_ns();
 
 		if ((ret = rte_hash_add_key_data(fdb_hash, &key, data)) < 0) {
 			rte_mempool_put(fdb_pool, e);
@@ -219,7 +219,7 @@ static struct api_out fdb_add(const void *request, struct api_ctx *) {
 		e = data;
 		*e = req->fdb;
 		e->bridge_id = iface->id;
-		e->last_seen = gr_clock_us();
+		e->last_seen = gr_clock_ns();
 
 		event_push(GR_EVENT_FDB_UPDATE, e);
 	} else {
@@ -400,11 +400,11 @@ static void fdb_ageing_cb(evutil_socket_t, short /*what*/, void * /*priv*/) {
 	uint32_t next = 0;
 	uint16_t max_age;
 	const void *key;
-	clock_t now;
+	gr_clock_ns_t now;
 	void *data;
 	time_t age;
 
-	now = gr_clock_us();
+	now = gr_clock_ns();
 
 	while (rte_hash_iterate(fdb_hash, &key, &data, &next) >= 0) {
 		fdb = data;
@@ -412,7 +412,7 @@ static void fdb_ageing_cb(evutil_socket_t, short /*what*/, void * /*priv*/) {
 		if ((fdb->flags & GR_FDB_F_STATIC) || !(fdb->flags & GR_FDB_F_LEARN))
 			continue;
 
-		age = (now - fdb->last_seen) / CLOCKS_PER_SEC;
+		age = (now - fdb->last_seen) / NS_PER_S;
 
 		bridge = iface_from_id(fdb->bridge_id);
 		if (bridge != NULL)
diff --git a/modules/policy/api/gr_conntrack.h b/modules/policy/api/gr_conntrack.h
index de9722b3..5d6bd75b 100644
--- a/modules/policy/api/gr_conntrack.h
+++ b/modules/policy/api/gr_conntrack.h
@@ -70,7 +70,7 @@ struct gr_conntrack {
 	uint8_t proto;
 	struct gr_conntrack_flow fwd_flow;
 	struct gr_conntrack_flow rev_flow;
-	clock_t last_update;
+	gr_clock_ns_t last_update;
 	uint32_t id;
 	gr_conn_state_t state;
 };
diff --git a/modules/policy/cli/conntrack.c b/modules/policy/cli/conntrack.c
index 7eb38121..6b717fc8 100644
--- a/modules/policy/cli/conntrack.c
+++ b/modules/policy/cli/conntrack.c
@@ -16,7 +16,7 @@
 
 static cmd_status_t conn_list(struct gr_api_client *c, const struct ec_pnode *) {
 	const struct gr_conntrack *conn;
-	clock_t now;
+	gr_clock_ns_t now;
 	int ret;
 
 	struct gr_table *table = gr_table_new();
@@ -31,7 +31,7 @@ static cmd_status_t conn_list(struct gr_api_client *c, const struct ec_pnode *)
 	gr_table_column(table, "DPORT", GR_DISP_RIGHT | GR_DISP_INT); // 8
 	gr_table_column(table, "LAST_UPDATE", GR_DISP_RIGHT); // 9
 
-	now = gr_clock_us();
+	now = gr_clock_ns();
 
 	gr_api_client_stream_foreach (conn, ret, c, GR_CONNTRACK_LIST, 0, NULL) {
 		gr_table_cell(table, 0, "%s", iface_name_from_id(c, conn->iface_id));
@@ -55,7 +55,7 @@ static cmd_status_t conn_list(struct gr_api_client *c, const struct ec_pnode *)
 
 		gr_table_cell(table, 7, "%u", ntohs(conn->fwd_flow.src_id));
 		gr_table_cell(table, 8, "%u", ntohs(conn->fwd_flow.dst_id));
-		gr_table_cell(table, 9, "%lu", (now - conn->last_update) / 1000000);
+		gr_table_cell(table, 9, "%ld", (now - conn->last_update) / NS_PER_S);
 
 		if (gr_table_print_row(table) < 0)
 			break;
diff --git a/modules/policy/control/conntrack.c b/modules/policy/control/conntrack.c
index 713bc554..fcbf04fe 100644
--- a/modules/policy/control/conntrack.c
+++ b/modules/policy/control/conntrack.c
@@ -240,7 +240,7 @@ again:
 			goto again;
 	}
 
-	atomic_store(&c->last_update, gr_clock_us());
+	atomic_store(&c->last_update, gr_clock_ns());
 }
 
 bool gr_conn_parse_key(
@@ -389,7 +389,7 @@ struct conn *gr_conn_insert(const struct conn_key *fwd_key, const struct conn_ke
 }
 
 static void do_ageing(evutil_socket_t, short /*what*/, void * /*priv*/) {
-	clock_t now = gr_clock_us(), last;
+	gr_clock_ns_t now = gr_clock_ns(), last;
 	uint64_t age, timeout;
 	struct conn *conn;
 	const void *key;
@@ -444,7 +444,7 @@ static void do_ageing(evutil_socket_t, short /*what*/, void * /*priv*/) {
 		last = atomic_load(&conn->last_update);
 		if (last > now)
 			continue;
-		age = (now - last) / 1000000ULL;
+		age = (now - last) / NS_PER_S;
 		if (age > timeout)
 			gr_conn_destroy(conn);
 	}
diff --git a/modules/policy/control/conntrack.h b/modules/policy/control/conntrack.h
index bb3ea1e5..51f8dd7c 100644
--- a/modules/policy/control/conntrack.h
+++ b/modules/policy/control/conntrack.h
@@ -43,7 +43,7 @@ struct conn {
 	struct conn_key fwd_key;
 	struct conn_key rev_key;
 	_Atomic(gr_conn_state_t) state;
-	_Atomic(clock_t) last_update;
+	_Atomic(gr_clock_ns_t) last_update;
 	struct nat44 nat;
 };
 
diff --git a/smoke/fib_inject.c b/smoke/fib_inject.c
index fee50c32..bf7b96ab 100644
--- a/smoke/fib_inject.c
+++ b/smoke/fib_inject.c
@@ -194,7 +194,7 @@ int main(int argc, char **argv) {
 	unsigned dist_count;
 	bool ipv6 = false;
 	float duration;
-	clock_t time;
+	gr_clock_ns_t time;
 	int ret;
 	int o;
 
@@ -242,14 +242,14 @@ int main(int argc, char **argv) {
 	if (create_nexthops(c) < 0)
 		return EXIT_FAILURE;
 
-	time = gr_clock_us();
+	time = gr_clock_ns();
 
 	if (ipv6)
 		ret = inject_ipv6(c, count);
 	else
 		ret = inject_ipv4(c, count);
 
-	duration = (float)(gr_clock_us() - time) / (float)CLOCKS_PER_SEC;
+	duration = (float)(gr_clock_ns() - time) / (float)1000000000;
 
 	printf("total time: %.1fs (%.1f routes/s)\n", duration, (float)count / duration);
 
-- 
2.43.0



More information about the grout mailing list