2001-03-16 21:17:15

by Mathieu Giguere (LMC)

[permalink] [raw]
Subject: UDP stop transmitting packets!!!

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


2001-03-16 21:30:05

by David Miller

[permalink] [raw]
Subject: Re: UDP stop transmitting packets!!!


Mathieu Giguere (LMC) writes:
> The problem with the previous code, when the queue become full (for any
> reason) you don't try to de-queue packet form it.

That is right, UDP is an unreliable transport so it doesn't
matter which packets we drop in such a case.

In fact, the current choice is optimal. If the problem is that we are
being hit with too many packets too quickly, the most desirable course
of action is the one which requires the least amount of computing
power. Doing nothing to the receive queue is better than trying to
"dequeue" some of the packets there to allow the new one to be added.

Later,
David S. Miller
[email protected]

2001-03-16 21:47:36

by David Miller

[permalink] [raw]
Subject: RE: UDP stop transmitting packets!!!


Mathieu Giguere (LMC) writes:
> Ok fine to live with that for security reason, but the socket will be dead
> for ever! (the only way to remove it is to reboot the machine)

If you kill the application, the queue is emptied and tossed
by the kernel.

Later,
David S. Miller
[email protected]

2001-03-16 21:44:46

by Mathieu Giguere (LMC)

[permalink] [raw]
Subject: RE: UDP stop transmitting packets!!!

Ok fine to live with that for security reason, but the socket will be dead
for ever! (the only way to remove it is to reboot the machine)
Can be possible to have a timer when the queue is full (something like 1
minute) to wait before dequeueing all of it and retrying to continue to
process request?

Because we need to process a large amount of UDP packets and this anoying
trick come break the machine quickly (like 12 minutes).

/mathieu
> -----Original Message-----
> From: David S. Miller [SMTP:[email protected]]
> Sent: Friday, March 16, 2001 4:29 PM
> To: Mathieu Giguere (LMC)
> Cc: '[email protected]'; Claude LeFrancois (LMC)
> Subject: Re: UDP stop transmitting packets!!!
>
>
> Mathieu Giguere (LMC) writes:
> > The problem with the previous code, when the queue become full (for any
> > reason) you don't try to de-queue packet form it.
>
> That is right, UDP is an unreliable transport so it doesn't
> matter which packets we drop in such a case.
>
> In fact, the current choice is optimal. If the problem is that we are
> being hit with too many packets too quickly, the most desirable course
> of action is the one which requires the least amount of computing
> power. Doing nothing to the receive queue is better than trying to
> "dequeue" some of the packets there to allow the new one to be added.
>
> Later,
> David S. Miller
> [email protected]

2001-03-16 21:48:56

by Mathieu Giguere (LMC)

[permalink] [raw]
Subject: RE: UDP stop transmitting packets!!!

Thanks for your answer.
We will have a patch internally to handle this protection.

/mathieu

> -----Original Message-----
> From: David S. Miller [SMTP:[email protected]]
> Sent: Friday, March 16, 2001 4:46 PM
> To: Mathieu Giguere (LMC)
> Cc: '[email protected]'; Claude LeFrancois (LMC)
> Subject: RE: UDP stop transmitting packets!!!
>
>
> Mathieu Giguere (LMC) writes:
> > Ok fine to live with that for security reason, but the socket will be
> dead
> > for ever! (the only way to remove it is to reboot the machine)
>
> If you kill the application, the queue is emptied and tossed
> by the kernel.
>
> Later,
> David S. Miller
> [email protected]

2001-03-16 21:53:26

by David Miller

[permalink] [raw]
Subject: RE: UDP stop transmitting packets!!!


Mathieu Giguere (LMC) writes:
> Thanks for your answer.
> We will have a patch internally to handle this protection.

I would like to clarify my statements:

> > -----Original Message-----
> > From: David S. Miller [SMTP:[email protected]]
> > Subject: RE: UDP stop transmitting packets!!!
> >
> > If you kill the application, the queue is emptied and tossed
> > by the kernel.

This should be "If you close the socket" then the queue will
be drained and free'd by the kernel. Killing the application
is one way to get the socket closed.

Later,
David S. Miller
[email protected]

2001-03-16 22:11:56

by Craig Milo Rogers

[permalink] [raw]
Subject: Re: UDP stop transmitting packets!!!

>In fact, the current choice is optimal. If the problem is that we are
>being hit with too many packets too quickly, the most desirable course
>of action is the one which requires the least amount of computing
>power. Doing nothing to the receive queue is better than trying to
>"dequeue" some of the packets there to allow the new one to be added.

A study by Greg Finn <[email protected]> determined that randomly
dropping packets in a congested queue may be preferable to dropping
only newly received packets. Dropping only newly-arrived packets can
be suboptimal, depending upon the details of how your packets are
generated, of course. YMMV.

"A Connectionless Congestion Control Algorithm"
Finn, Greg
ACM Computer Communication Review, Vol. 19, No. 5., pp. 12-31,Oct. 1989.

The way I view this result is that each packet is part of a
flow (true even for most UDP packets). Dropping a packet penalizes
the flow. All packets in a queue contribute to the queue's
congestion, not simply the most recently-arrived packet. Dropping a
random packet in the queue distributes the penalty among the flows in
the queue. Over the statistical average, this is more optimal than
dropping the latest packet.

Craig Milo Rogers