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

관련 정보