UDPパケット損失

UDPパケット損失

私が知っている限り、UDPパケットの受信プロセスは次のとおりです。

  1. UDPヘッダーにエラーがないか確認してください。
  2. ターゲットをソケットと一致させる
  3. 対応するソケットがない場合は、エラーメッセージが送信されます。
  4. パケットを適切なソケット受信キューに入れます。
  5. このソケットでデータを待つプロセスを覚醒させます。

しかし、上記の段階で/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)。複数の場所で使用すると増加します。

  1. 受信キューがいっぱいです。

    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);
    
  2. 無効なチェックサムフレーム

    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);
    
  3. 読めない

    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);
    
  4. 受信中に失敗

    static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
    {
            ...
    drop:
            ...
            atomic_inc(&sk->sk_drops);
    
  5. メッセージを複製しようとしたときにマルチキャスト処理中に失敗しました。

    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);
    
    

おすすめ記事