Networking
UDP 丟包
我了解 UDP 數據包的接收流是
- 檢查 udp 標頭是否有錯誤
- 將目標與套接字匹配
- 如果沒有這樣的套接字,則返回錯誤消息
- 將數據包放入適當的套接字接收隊列
- 喚醒程序等待該套接字的數據
但在上述階段,什麼
/proc/net/udp
算作下降?上述任何步驟的失敗是否構成下降?還是僅當接收隊列/緩衝區已滿時?
在 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);