UDP stop transmitting packets!!!

From: Mathieu Giguere (LMC) (lmcmgig@lmc.ericsson.se)
Date: Fri Mar 16 2001 - 16:16:08 EST


Hi all,

I will try to explain your the situation of test:

kernel 2.2.17 (yeah an old one but the goal of this comments is for future
kernel to remove this littel bug)
You need to stress your network (4 pings in fload mode with packet size of
125 bytes should do the thing)
And you pass some traffic on a UDP socket port something.

What append if you look in /proc/net/udp
you will see the rx_queue column going up (no problem with that)
but when you reach the maximum queue size, all packet to be drop.

you can see why in the 2 function here:

net/ipv4/udp.c

static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
{
        /*
         * Charge it to the socket, dropping if the queue is full.
         */

#if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)
        if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
                if ((unsigned short)csum_fold(csum_partial(skb->h.raw,
skb->len, skb->csum))) {
                        udp_statistics.UdpInErrors++;
                        ip_statistics.IpInDiscards++;
                        ip_statistics.IpInDelivers--;
                        kfree_skb(skb);
                        return -1;
                }
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
#endif

// When you try to queue the message it will faild because the queue is
full
        if (sock_queue_rcv_skb(sk,skb)<0) {
                udp_statistics.UdpInErrors++;
                ip_statistics.IpInDiscards++;
                ip_statistics.IpInDelivers--;
                kfree_skb(skb);
                return -1;
        }
        udp_statistics.UdpInDatagrams++;
        return 0;
}

include/net/sock.h

extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff
*skb)
{
#ifdef CONFIG_FILTER
        struct sk_filter *filter;
#endif
        /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
           number of warnings when compiling with -W --ANK
         */

//you try to check if you have enough space and if not you discard the
packet (ok fine)
        if (atomic_read(&sk->rmem_alloc) + skb->truesize >=
(unsigned)sk->rcvbuf)
                return -ENOMEM;

#ifdef CONFIG_FILTER
        if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
                return -EPERM; /* Toss packet */
#endif /* CONFIG_FILTER */

        skb_set_owner_r(skb, sk);
        skb_queue_tail(&sk->receive_queue, skb);
        if (!sk->dead)
                sk->data_ready(sk,skb->len);
        return 0;
}

The problem with the previous code, when the queue become full (for any
reason) you don't try to de-queue packet form it.
So no packet can be process and all are reject by udp
(udp_statistics.UdpInErrors++;)

A possible solution can be something like that:
try to de-queue packets when the queue is full! (a little protection here)

        if (atomic_read(&sk->rmem_alloc) + skb->truesize >=
(unsigned)sk->rcvbuf) {
                     if (!sk->dead) sk->data_ready(sk,0);
                return -ENOMEM;
        }

/mathieu

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Mar 23 2001 - 21:00:09 EST