Hello netdev mailing list, I am a PhD student from Germany and currently working on a project that involves monitoring packets as they are passed from kernel space towards user space applications. To achieve this, I applied the attached patch to Kernel v4.4 and implemented the two functions below that are called from - and with the parameters of - sock_recvmsg() and sock_sendmsg(). For every incoming packet I check if it belongs to the process I want to monitor. If so, I get the header information as well as the payload and save the current timestamp. Finally and set the current state to monitor for the transmission of this packet. Then I compare the payloads of outgoing packets until a match is found and print the time it took this packet to travel through the user space.
However, I seem to be unable to get the socket information and data for incoming packets in __i3_recv_monitor(), as the debug output is always something like Dec 19 08:49:51 localhost kernel: [413608.826373] [Packet received] (13739)0.0.0.0;0;0.0.0.0;0;0;413595528124549 Dec 19 08:49:51 localhost kernel: [413608.831397] [Received data] (null) Regarding outgoing packets in __i3_send_monitor(), I am at least able to get the network information from the socket. My data pointer is empty as well. Dec 19 09:00:20 localhost kernel: [414238.178057] [Packet send] (13739)192.168.200.19;36628;192.168.200.20;45110;6;414224859396846 Dec 19 09:00:20 localhost kernel: [414238.181216] [Send data] (null) The context is that I want to monitor packet processing times of user space applications that do not alter the payload before retransmitting packets. I was hoping that someone with more experience of the network stack could point me towards what I am missing or doing wrong here. I hope this is not totally the wrong place to ask such a question and already thank you in advance! Best regards, Stefan -------------------------------------------------------- void __i3_recv_monitor(struct socket * sock, struct msghdr * msg, size_t len, int flags) { int i = 0; const struct iovec * iov; if (unlikely(current_state == WAIT_FOR_RECV) && ktime_to_ns(recv_time) == 0 && current->pid == vnf_pid) { recv_time = ktime_get(); if (unlikely(debug>=2)) printk(KERN_INFO "[Packet received] (%u)%pI4;%u;%pI4;%d;%d;%lld\n", current->pid, &sock->sk->sk_rcv_saddr, sock->sk->sk_num, &sock->sk->sk_daddr, sock->sk->sk_dport, sock->sk->sk_protocol, ktime_to_ns(recv_time)); iov = msg->msg_iter.iov; recv_data = (char *)kmalloc(iov->iov_len, GFP_KERNEL); copy_from_user(recv_data, iov->iov_base, iov->iov_len); printk(KERN_INFO "[Received data] %s\n", *recv_data); current_state = WAIT_FOR_SEND; } } void __i3_send_monitor(struct socket * sock, struct msghdr * msg) { int i = 0; const struct iovec * iov; // I don't like this approach at all... think about something different!! if (unlikely(current_state == WAIT_FOR_SEND) && current->pid == vnf_pid) { send_time = ktime_get(); if (unlikely(debug>=2)) printk(KERN_INFO "[Packet send] (%u)%pI4;%u;%pI4;%d;%d;%lld\n", current->pid, &sock->sk->sk_rcv_saddr, sock->sk->sk_num, &sock->sk->sk_daddr, sock->sk->sk_dport, sock->sk->sk_protocol, ktime_to_ns(send_time)); if (ktime_to_ns(recv_time) != 0) { iov = msg->msg_iter.iov; send_data = (char *)kmalloc(iov->iov_len, GFP_KERNEL); copy_from_user(send_data, iov->iov_base, iov->iov_len); printk(KERN_INFO "[Send data] %s\n", *send_data); if (unlikely(*recv_data == *send_data)) { proc_time = ktime_sub(send_time, recv_time); if (unlikely(debug>=2)) printk(KERN_INFO "[Processing time] %lld\n", ktime_to_ns(proc_time)); recv_time = ktime_set(0, 0); current_state = SLEEP; kfree(recv_data); } kfree(send_data); } } } -------------------------------------------------------- >From 7ef3d1efe53fbfb937e0c1e5200e1a8e40e220e9 Mon Sep 17 00:00:00 2001 From: Stefan Geissler <stefan.geiss...@informatik.uni-wuerzburg.de> Date: Tue, 14 Nov 2017 12:05:39 +0100 Subject: [PATCH 1/2] Added pointers to hook into socket calls for monitoring reasons --- net/socket.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/socket.c b/net/socket.c index d730ef9..57ee946 100644 --- a/net/socket.c +++ b/net/socket.c @@ -113,6 +113,13 @@ unsigned int sysctl_net_busy_read __read_mostly; unsigned int sysctl_net_busy_poll __read_mostly; #endif +// Setup pointer to fill with external wrapper functions to monitor sockets +void (*__i3_send_monitor_ptr)(struct sock *, struct msghdr *); +void (*__i3_recv_monitor_ptr)(struct sock *, struct msghdr *, size_t , int); +EXPORT_SYMBOL(__i3_send_monitor_ptr); +EXPORT_SYMBOL(__i3_recv_monitor_ptr); + + static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to); static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from); static int sock_mmap(struct file *file, struct vm_area_struct *vma); @@ -615,6 +622,8 @@ static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) int sock_sendmsg(struct socket *sock, struct msghdr *msg) { + if ((unlikely(__i3_send_monitor_ptr)) + (*__i3_send_monitor_ptr)(sock, msg); int err = security_socket_sendmsg(sock, msg, msg_data_left(msg)); @@ -716,6 +725,8 @@ static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { + if (unlikely(__i3_recv_monitor_ptr)) + (*__i3_recv_monitor_ptr)(sock, msg, size, flags); int err = security_socket_recvmsg(sock, msg, size, flags); return err ?: sock_recvmsg_nosec(sock, msg, size, flags); @@ -2479,6 +2490,11 @@ EXPORT_SYMBOL(sock_unregister); static int __init sock_init(void) { + // Ensure pointers are set to NULL as long as no module is loaded. + // Unsetting the pointers has to be handled by the module upon exit. + __i3_recv_monitor_ptr = NULL; + __i3_send_monitor_ptr = NULL; + int err; /* * Initialize the network sysctl infrastructure. -- 2.7.4 >From 262cf38d4c576f6399851e6f5ecbd3a73a62d416 Mon Sep 17 00:00:00 2001 From: Stefan Geissler <stefan.geiss...@informatik.uni-wuerzburg.de> Date: Tue, 14 Nov 2017 14:04:56 +0100 Subject: [PATCH 2/2] Fixed ISO C90 Warnings --- net/socket.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/net/socket.c b/net/socket.c index 57ee946..2e840a8 100644 --- a/net/socket.c +++ b/net/socket.c @@ -114,8 +114,8 @@ unsigned int sysctl_net_busy_poll __read_mostly; #endif // Setup pointer to fill with external wrapper functions to monitor sockets -void (*__i3_send_monitor_ptr)(struct sock *, struct msghdr *); -void (*__i3_recv_monitor_ptr)(struct sock *, struct msghdr *, size_t , int); +void (*__i3_send_monitor_ptr)(struct socket *, struct msghdr *); +void (*__i3_recv_monitor_ptr)(struct socket *, struct msghdr *, size_t , int); EXPORT_SYMBOL(__i3_send_monitor_ptr); EXPORT_SYMBOL(__i3_recv_monitor_ptr); @@ -622,9 +622,10 @@ static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) int sock_sendmsg(struct socket *sock, struct msghdr *msg) { - if ((unlikely(__i3_send_monitor_ptr)) + int err; + if (unlikely(__i3_send_monitor_ptr)) (*__i3_send_monitor_ptr)(sock, msg); - int err = security_socket_sendmsg(sock, msg, + err = security_socket_sendmsg(sock, msg, msg_data_left(msg)); return err ?: sock_sendmsg_nosec(sock, msg); @@ -725,9 +726,10 @@ static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { + int err; if (unlikely(__i3_recv_monitor_ptr)) (*__i3_recv_monitor_ptr)(sock, msg, size, flags); - int err = security_socket_recvmsg(sock, msg, size, flags); + err = security_socket_recvmsg(sock, msg, size, flags); return err ?: sock_recvmsg_nosec(sock, msg, size, flags); } @@ -2489,13 +2491,14 @@ void sock_unregister(int family) EXPORT_SYMBOL(sock_unregister); static int __init sock_init(void) -{ +{ + int err; + // Ensure pointers are set to NULL as long as no module is loaded. // Unsetting the pointers has to be handled by the module upon exit. __i3_recv_monitor_ptr = NULL; __i3_send_monitor_ptr = NULL; - - int err; + /* * Initialize the network sysctl infrastructure. */ -- 2.7.4