我正在尝试实现一个在UDP之上运行的自定义传输协议。我想在UDP数据字段的开头添加此协议的标头,就在用户空间的数据被复制到skbuff之前。我也希望在UDP将其交给套接字之前处理这些数据,以便我可以提取标头并在内核中执行所需的处理。所以,
struct new_header
函数的数据开头添加标题(例如udp_sendmsg()
)。我假设在将来自用户空间的任何实际数据复制到它之前或者最迟在数据上计算UDP校验和之前,应将其复制到skbuff的数据字段。代码究竟发生在哪里?udp_recvmsg()
函数中的确切位置是传递给套接字的数据?我认为这是skb_copy_datagram_iovec()
。答案 0 :(得分:1)
如何确保在udp_sendmsg()函数的数据开头添加我的标题(比如struct new_header)。我假设这个 应该在任何实际数据之前复制到skbuff的数据字段 从用户空间复制到它或最迟在UDP之前 校验和是根据数据计算的。这究竟发生在哪里 代码?
您可以考虑2个选项:
1.如果您在用户空间中实现协议,那么您可以使用UDP套接字与内核通信,并在从UDP套接字接收数据报或在将数据发送到UDP套接字之前进行封装后进行协议解除。
2.如果你想在内核空间中实现你的协议。然后你必须实现你自己的套接字类型。你可以查看一些已经存在于内核源代码中的隧道套接字代码(例如.L2TP)。一旦你在内核中注册了你的套接字类型,那么从用户空间发送到内核空间的套接字数据将由你的encap代码处理(相当于udp_sendmsg()),然后你将代码转换为udp_sendmsg()以进一步向下网络堆栈。
udp_recvmsg()函数究竟在哪里传递给套接字的数据?我认为这是skb_copy_datagram_iovec()。
不确定您正在查看哪个版本的内核。对于内核4.6,它是skb_copy_datagram_msg() - > skb_copy_datagram_iter()。这是将数据报复制到buff然后返回用户空间的位置
实际上,当用户空间尝试从套接字接收数据时,会调用udp_recvmsg(),因此udp_recvmsg()已经在套接字上下文中。
通过将数据报放在sk_receive_queue中,网络堆栈将数据报交给sock_queue_rcv_skb()中的套接字。
内核4.6中的调用链如下:
__udp4_lib_rcv -->
udp_queue_rcv_skb(sk, skb); --> sock_queue_rcv_skb()
然后userpsace通过以下方式获取数据:
recv();
... ...
-------system call ---------
... ...
udp_recvmsg -->
__skb_recv_datagram -->
__skb_try_recv_datagram --> (get the datagram from sk_receive_queue)