0

I understand that the receive flow for a UDP packet is

  1. Check udp header for errors
  2. Match destination to socket
  3. Send an error message back if no such socket
  4. Put packet into appropriate socket receive queue
  5. Wake up process waiting for data for that socket

But in the above stages what would /proc/net/udp count as a drop? Does the failure of any step above constitute as a drop? Or is it only when the receive queue/buffer is full?

1 Answer 1

5

In Linux 5.4.66, the pseudo-file /proc/net/udp is generated by a function in 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;
}

That calls udp4_format_sock() in the same file:

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

Note that the value of the drops field comes from atomic_read(&sp->sk_drops). That value is incremented using atomic_inc(&sk->sk_drops) in a couple of places.

  1. The receive queue is full

    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. Bad checksum frames

    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. Failure to read

    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. Failures during receive

    static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
    {
            ...
    drop:
            ...
            atomic_inc(&sk->sk_drops);
    
  5. Failures during multicast processing when trying to clone the message

    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);
    
    
1
  • 1
    Great answer thank you :) Sep 30, 2020 at 13:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .