据我所知,UDP数据包的接收流程是
- 检查 udp 标头是否有错误
- 将目的地与套接字匹配
- 如果没有这样的套接字,则发送错误消息
- 将数据包放入适当的套接字接收队列
- 唤醒进程等待该套接字的数据
但在上述阶段,什么才算/proc/net/udp
是下降呢?上述任何一步失败是否构成掉落?或者仅当接收队列/缓冲区已满时才执行?
答案1
在 Linux 5.4.66 中,伪文件/proc/net/udp
由以下函数生成net/ipv4/udp.c
:
int udp4_seq_show(struct seq_file *seq, void *v)
{
seq_setwidth(seq, 127);
if (v == SEQ_START_TOKEN)
seq_puts(seq, " sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout "
"inode ref pointer drops");
else {
struct udp_iter_state *state = seq->private;
udp4_format_sock(v, seq, state->bucket);
}
seq_pad(seq, '\n');
return 0;
}
这udp4_format_sock()
在同一个文件中调用:
static void udp4_format_sock(struct sock *sp, struct seq_file *f,
int bucket)
{
struct inet_sock *inet = inet_sk(sp);
__be32 dest = inet->inet_daddr;
__be32 src = inet->inet_rcv_saddr;
__u16 destp = ntohs(inet->inet_dport);
__u16 srcp = ntohs(inet->inet_sport);
seq_printf(f, "%5d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
udp_rqueue_get(sp),
0, 0L, 0,
from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
0, sock_i_ino(sp),
refcount_read(&sp->sk_refcnt), sp,
atomic_read(&sp->sk_drops));
}
请注意,该字段的值drops
来自atomic_read(&sp->sk_drops)
.该值使用以下方法递增atomic_inc(&sk->sk_drops)
在几个地方使用时会增加。
接收队列已满
int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb) { ... /* try to avoid the costly atomic add/sub pair when the receive * queue is full; always allow at least a packet */ rmem = atomic_read(&sk->sk_rmem_alloc); if (rmem > sk->sk_rcvbuf) goto drop; ... drop: atomic_inc(&sk->sk_drops);
错误的校验和帧
static struct sk_buff *__first_packet_length(struct sock *sk, struct sk_buff_head *rcvq, int *total) { struct sk_buff *skb; while ((skb = skb_peek(rcvq)) != NULL) { if (udp_lib_checksum_complete(skb)) { ... atomic_inc(&sk->sk_drops);
无法阅读
int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { ... if (checksum_valid || udp_skb_csum_unnecessary(skb)) { if (udp_skb_is_linear(skb)) err = copy_linear_skb(skb, copied, off, &msg->msg_iter); else err = skb_copy_datagram_msg(skb, off, msg, copied); } else { err = skb_copy_and_csum_datagram_msg(skb, off, msg); if (err == -EINVAL) goto csum_copy_err; } if (unlikely(err)) { if (!peeking) { atomic_inc(&sk->sk_drops);
接收期间失败
static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) { ... drop: ... atomic_inc(&sk->sk_drops);
尝试克隆消息时多播处理期间失败
static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct udphdr *uh, __be32 saddr, __be32 daddr, struct udp_table *udptable, int proto) { ... sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { ... nskb = skb_clone(skb, GFP_ATOMIC); if (unlikely(!nskb)) { atomic_inc(&sk->sk_drops);