ell.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 02/12] dhcp: Set lease expiry based on frame reception times
@ 2022-03-07 14:55 Andrew Zaborowski
  0 siblings, 0 replies; only message in thread
From: Andrew Zaborowski @ 2022-03-07 14:55 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 10226 bytes --]

Use the SO_TIMESTAMP socket option to request the packet rx timestamps
from the kernel and pass those values from dhcp-transport to
dhcp-client/server to use in lease expiry time calculation.

Apparently linux has a few different variants of SO_TIMESTAMP, use the
most basic one.  Additionally the rx times can be obtained without
SO_TIMESTAMP using the SIOCGSTAMP ioctl on each packet.  The advantage
would be that we'd only parse the timestamps for the frames where we
actually care about timing.  The disadvantage would be an extra syscall
for those frames, which we don't incur with SO_TIMESTAMP.
---
 ell/dhcp-private.h   |  2 +-
 ell/dhcp-server.c    | 29 +++++++++++++++++------------
 ell/dhcp-transport.c | 41 +++++++++++++++++++++++++++++++++++------
 ell/dhcp.c           | 12 ++++++++----
 4 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 1c12cbe..b695e4e 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -108,7 +108,7 @@ uint16_t _dhcp_checksum(const void *buf, size_t len);
 uint16_t _dhcp_checksumv(const struct iovec *iov, size_t iov_cnt);
 
 typedef void (*dhcp_transport_rx_cb_t)(const void *, size_t, void *,
-					const uint8_t *);
+					const uint8_t *, uint64_t);
 
 struct dhcp_transport {
 	int (*open)(struct dhcp_transport *s, uint32_t xid);
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index ff0784f..5c0774b 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -299,7 +299,8 @@ static void lease_expired_cb(struct l_timeout *timeout, void *user_data)
 
 static struct l_dhcp_lease *add_lease(struct l_dhcp_server *server,
 					bool offering, const uint8_t *client_id,
-					const uint8_t *chaddr, uint32_t yiaddr)
+					const uint8_t *chaddr, uint32_t yiaddr,
+					uint64_t timestamp)
 {
 	struct l_dhcp_lease *lease = NULL;
 	int ret;
@@ -328,7 +329,7 @@ static struct l_dhcp_lease *add_lease(struct l_dhcp_server *server,
 		lease->client_id = l_memdup(client_id, client_id[0] + 1);
 
 	lease->offering = offering;
-	lease->bound_time = l_time_now();
+	lease->bound_time = timestamp;
 
 	if (!offering) {
 		lease->lifetime = server->lease_seconds;
@@ -572,7 +573,7 @@ static void copy_client_id(struct dhcp_message_builder *builder,
 static void send_offer(struct l_dhcp_server *server,
 			const struct dhcp_message *client_msg,
 			struct l_dhcp_lease *lease, uint32_t requested_ip,
-			const uint8_t *client_id)
+			const uint8_t *client_id, uint64_t timestamp)
 {
 	struct dhcp_message_builder builder;
 	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
@@ -595,7 +596,7 @@ static void send_offer(struct l_dhcp_server *server,
 	}
 
 	lease = add_lease(server, true, client_id, client_msg->chaddr,
-				reply->yiaddr);
+				reply->yiaddr, timestamp);
 	if (!lease) {
 		SERVER_DEBUG("add_lease() failed");
 		return;
@@ -668,7 +669,8 @@ static void send_nak(struct l_dhcp_server *server,
 static void send_ack(struct l_dhcp_server *server,
 			const struct dhcp_message *client_msg,
 			struct l_dhcp_lease *lease,
-			bool rapid_commit)
+			bool rapid_commit,
+			uint64_t timestamp)
 {
 	struct dhcp_message_builder builder;
 	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
@@ -706,7 +708,7 @@ static void send_ack(struct l_dhcp_server *server,
 		return;
 
 	lease = add_lease(server, false, client_id, reply->chaddr,
-				reply->yiaddr);
+				reply->yiaddr, timestamp);
 
 	if (server->event_handler)
 		server->event_handler(server, L_DHCP_SERVER_EVENT_NEW_LEASE,
@@ -714,7 +716,7 @@ static void send_ack(struct l_dhcp_server *server,
 }
 
 static void listener_event(const void *data, size_t len, void *user_data,
-				const uint8_t *saddr)
+				const uint8_t *saddr, uint64_t timestamp)
 {
 	struct l_dhcp_server *server = user_data;
 	const struct dhcp_message *message = data;
@@ -803,12 +805,13 @@ static void listener_event(const void *data, size_t len, void *user_data,
 				break;
 			}
 
-			send_ack(server, message, lease, rapid_commit_opt);
+			send_ack(server, message, lease, rapid_commit_opt,
+					timestamp);
 			break;
 		}
 
 		send_offer(server, message, lease, requested_ip_opt,
-				client_id_opt);
+				client_id_opt, timestamp);
 		break;
 	case DHCP_MESSAGE_TYPE_REQUEST:
 		SERVER_DEBUG("Received REQUEST, requested IP "NIPQUAD_FMT,
@@ -903,7 +906,7 @@ static void listener_event(const void *data, size_t len, void *user_data,
 			}
 		}
 
-		send_ack(server, message, lease, false);
+		send_ack(server, message, lease, false, timestamp);
 		break;
 	case DHCP_MESSAGE_TYPE_DECLINE:
 		SERVER_DEBUG("Received DECLINE");
@@ -1350,7 +1353,8 @@ LIB_EXPORT struct l_dhcp_lease *l_dhcp_server_discover(
 		}
 	}
 
-	lease = add_lease(server, true, client_id, mac, requested_ip_opt);
+	lease = add_lease(server, true, client_id, mac, requested_ip_opt,
+				l_time_now());
 	if (unlikely(!lease)) {
 		SERVER_DEBUG("add_lease() failed");
 		return NULL;
@@ -1373,7 +1377,8 @@ LIB_EXPORT bool l_dhcp_server_request(struct l_dhcp_server *server,
 			NIPQUAD(lease->address), MAC_STR(lease->mac));
 
 	memcpy(mac, lease->mac, ETH_ALEN);
-	lease = add_lease(server, false, NULL, mac, lease->address);
+	lease = add_lease(server, false, NULL, mac, lease->address,
+				lease->bound_time);
 
 	if (server->event_handler)
 		server->event_handler(server, L_DHCP_SERVER_EVENT_NEW_LEASE,
diff --git a/ell/dhcp-transport.c b/ell/dhcp-transport.c
index 7c73fee..d73930b 100644
--- a/ell/dhcp-transport.c
+++ b/ell/dhcp-transport.c
@@ -44,6 +44,7 @@
 #include "io.h"
 #include "util.h"
 #include "private.h"
+#include "time.h"
 #include "dhcp-private.h"
 
 struct dhcp_default_transport {
@@ -112,10 +113,20 @@ static bool _dhcp_default_transport_read_handler(struct l_io *io,
 	struct dhcp_packet *p;
 	uint16_t c;
 	struct sockaddr_ll saddr;
-	socklen_t saddr_len = sizeof(saddr);
-
-	len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) &saddr,
-			&saddr_len);
+	uint64_t timestamp = 0;
+	struct cmsghdr *cmsg;
+	struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
+	struct msghdr msg = {};
+	unsigned char control[32];
+
+	msg.msg_name = &saddr;
+	msg.msg_namelen = sizeof(saddr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = control;
+	msg.msg_controllen = sizeof(control);
+
+	len = recvmsg(fd, &msg, 0);
 	if (len < 0)
 		return false;
 
@@ -151,14 +162,28 @@ static bool _dhcp_default_transport_read_handler(struct l_io *io,
 
 	len -= sizeof(struct udphdr) - sizeof(struct iphdr);
 
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+					cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+				cmsg->cmsg_type == SCM_TIMESTAMP) {
+			const struct timeval *tv = (void *) CMSG_DATA(cmsg);
+
+			timestamp = tv->tv_sec * L_USEC_PER_SEC + tv->tv_usec;
+		}
+	}
+
+	if (!timestamp)
+		timestamp = l_time_now();
+
 	if (transport->super.rx_cb) {
 		const uint8_t *src_mac = NULL;
 
-		if (saddr_len >= sizeof(saddr) && saddr.sll_halen == ETH_ALEN)
+		if (msg.msg_namelen >= sizeof(saddr) &&
+				saddr.sll_halen == ETH_ALEN)
 			src_mac = saddr.sll_addr;
 
 		transport->super.rx_cb(&p->dhcp, len, transport->super.rx_data,
-					src_mac);
+					src_mac, timestamp);
 	}
 
 	return true;
@@ -443,6 +468,7 @@ static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid)
 		.len = L_ARRAY_SIZE(filter),
 		.filter = filter
 	};
+	int one = 1;
 
 	s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (s < 0)
@@ -452,6 +478,9 @@ static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid)
 						&fprog, sizeof(fprog)) < 0)
 		goto error;
 
+	if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) < 0)
+		goto error;
+
 	memset(&addr, 0, sizeof(addr));
 	addr.sll_family = AF_PACKET;
 	addr.sll_protocol = htons(ETH_P_IP);
diff --git a/ell/dhcp.c b/ell/dhcp.c
index e2d18fc..2d04900 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -675,7 +675,7 @@ static void dhcp_client_address_add_cb(int error, uint16_t type,
 static int dhcp_client_receive_ack(struct l_dhcp_client *client,
 					const uint8_t *saddr,
 					const struct dhcp_message *ack,
-					size_t len)
+					size_t len, uint64_t timestamp)
 {
 	struct dhcp_message_iter iter;
 	struct l_dhcp_lease *lease;
@@ -727,6 +727,7 @@ static int dhcp_client_receive_ack(struct l_dhcp_client *client,
 		uint32_t l = l_dhcp_lease_get_lifetime(client->lease);
 		L_AUTO_FREE_VAR(char *, broadcast) =
 				l_dhcp_lease_get_broadcast(client->lease);
+		uint64_t et = timestamp + l * L_USEC_PER_SEC;
 
 		prefix_len = l_dhcp_lease_get_prefix_length(client->lease);
 		if (!prefix_len)
@@ -735,6 +736,7 @@ static int dhcp_client_receive_ack(struct l_dhcp_client *client,
 		a = l_rtnl_address_new(ip, prefix_len);
 		l_rtnl_address_set_noprefixroute(a, true);
 		l_rtnl_address_set_lifetimes(a, l, l);
+		l_rtnl_address_set_expiry(a, et, et);
 		l_rtnl_address_set_broadcast(a, broadcast);
 
 		client->rtnl_add_cmdid =
@@ -817,7 +819,8 @@ static bool dhcp_client_handle_offer(struct l_dhcp_client *client,
 }
 
 static void dhcp_client_rx_message(const void *data, size_t len, void *userdata,
-					const uint8_t *saddr)
+					const uint8_t *saddr,
+					uint64_t timestamp)
 {
 	struct l_dhcp_client *client = userdata;
 	const struct dhcp_message *message = data;
@@ -898,7 +901,8 @@ static void dhcp_client_rx_message(const void *data, size_t len, void *userdata,
 		if (msg_type != DHCP_MESSAGE_TYPE_ACK)
 			return;
 
-		r = dhcp_client_receive_ack(client, saddr, message, len);
+		r = dhcp_client_receive_ack(client, saddr, message, len,
+						timestamp);
 		if (r < 0)
 			return;
 
@@ -917,7 +921,7 @@ static void dhcp_client_rx_message(const void *data, size_t len, void *userdata,
 
 		dhcp_client_event_notify(client, r);
 
-		client->lease->bound_time = l_time_now();
+		client->lease->bound_time = timestamp;
 
 		/*
 		 * Start T1, once it expires we will start the T2 timer.  If
-- 
2.32.0

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-03-07 14:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-07 14:55 [PATCH 02/12] dhcp: Set lease expiry based on frame reception times Andrew Zaborowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).