From: Erdt, Ralph <hidden> Date: 2012-06-28 13:43:53
(I've send this email already in the lartc mailing list. Short after this I found the list seems dead (http://dir.gmane.org/gmane.linux.network.routing). I hope this is the correct place to ask. If not - please give me a note, where I can ask this.)
----------
Hello.
I'm writing a kernel module (net/sched) which replaces packets in the queue. I'm glad hearing your option.
Background:
In very low bandwidth network (<=9.6Kbps, shared, etc.) its hard (rather: impossible) to get all packets sent.
But some of the packets contain information, which gets obsolete over time. E.g. (GPS) positions, which will be sent periodically. If the application sends a new packet while an old position packet is still in the queue, the old packet is obsolete. This can be dropped. But just dropping the old packet and queuing the new packet will result in never sending a packet of this type.
So I'm writing a tc-qdisc scheduler module, which replaces packets in the queue on enqueuing, when this properties are given:
- UDPv4
- not fragmented
- (TOS & bitmask) = givenCompare; (bitmask and compare are adjustable)
- same source IP
- same destination IP
- same destination port
- same TOS
So, the packet got sent over the time - but with the actual information.
What do you think? Is this module worth to get released to kernel.org? Have you any other comments?
Greetings
Ralph Erdt
From: Rick Jones <hidden> Date: 2012-06-28 16:24:47
You might want to try the recent "codel" additions to the stack. They
seek to keep the size of queues more manageable while still allowing the
occasional burst.
rick jones
From: Erdt, Ralph <hidden> Date: 2012-06-29 08:46:36
Hello Rick Jones,
You might want to try the recent "codel" additions to the stack. They
seek to keep the size of queues more manageable while still allowing
the occasional burst.
Thank you for your hint. This is surly a needful solution in normal network, but this didn't help us:
We are working with very heterogeneous networks:
Internal: 100MBit and more.
Extern: 9,6*K*Bit and LESS(*), and shared, and...
A few other information: wireless (higher packet loss rate), medium access time > 100ms, RTT (standard ping) with IDLE network: 1,5 *seconds*, RTT with network load: minutes(!), and so on. Just very shocking..
TCP isn't usable over such a link. So we are only sending UDP. The codel didn't help us, as codel addresses the flow speed. It's dropping "randomly" (I know it's not random in the lower level, but it's random from the application's perspective) packets.
I'm addressing the amount of information: Trying to reduce it intelligently by REPLACING old packets with new ones.. Surely - the application must handle this. But in such a network a administrator have to configure the queues and he knows the applications.
In one private mail someone guesses that we are making VoIP. No - we just want to send status information (e.g. sensor information) which will get deprecated, when a new information is available.
I know, this is a very special problem, which didn't occur in normal or even abnormal situations. But I'm sure there are some other people having the this problem, too. So I'm glad to share my solution.
(*you remember the good ol' times with modems over telephone lines? When the internet was called BBS? And how it suddenly feels, when the BBS starts using ANSI? This was comfortable compared to our problem..)
Greetings
Ralph Erdt
From: Eric Dumazet <hidden> Date: 2012-06-29 09:07:01
On Fri, 2012-06-29 at 08:46 +0000, Erdt, Ralph wrote:
Hello Rick Jones,
quoted
You might want to try the recent "codel" additions to the stack. They
seek to keep the size of queues more manageable while still allowing
the occasional burst.
Thank you for your hint. This is surly a needful solution in normal network, but this didn't help us:
We are working with very heterogeneous networks:
Internal: 100MBit and more.
Extern: 9,6*K*Bit and LESS(*), and shared, and...
A few other information: wireless (higher packet loss rate), medium access time > 100ms, RTT (standard ping) with IDLE network: 1,5 *seconds*, RTT with network load: minutes(!), and so on. Just very shocking..
TCP isn't usable over such a link. So we are only sending UDP. The codel didn't help us, as codel addresses the flow speed. It's dropping "randomly" (I know it's not random in the lower level, but it's random from the application's perspective) packets.
I'm addressing the amount of information: Trying to reduce it intelligently by REPLACING old packets with new ones.. Surely - the application must handle this. But in such a network a administrator have to configure the queues and he knows the applications.
In one private mail someone guesses that we are making VoIP. No - we just want to send status information (e.g. sensor information) which will get deprecated, when a new information is available.
I know, this is a very special problem, which didn't occur in normal or even abnormal situations. But I'm sure there are some other people having the this problem, too. So I'm glad to share my solution.
(*you remember the good ol' times with modems over telephone lines? When the internet was called BBS? And how it suddenly feels, when the BBS starts using ANSI? This was comfortable compared to our problem..)
Problem is : with wireless, chances are high that the old packet is not
waiting in qdisc, but in wireless queues.
Anyway, adding a maxdelay to codel / fq_codel is really easy : This
would drop packet if its sejourn time is above a given limit.
You could use codel with @target being greater than @maxdelay to remove
all probabilistic drops, and only keep the @maxdelay behavior.
If you want I can cook this patch.
From: Erdt, Ralph <hidden> Date: 2012-07-02 07:02:12
Hello Eric Dumazet,
sorry for the late answer, but sometimes it's not easy here...
Problem is : with wireless, chances are high that the old packet is not
waiting in qdisc, but in wireless queues.
Even if the wireless queue is a problem (because of our setup, this is not a problem), the network stack queue (*) is the biggest queue, and a good point to optimize. And its impossible doing things 100%. We are happy to get 99%. This is a great improvement compared to the previous situation.
(* When I'm getting the picture in http://lartc.org/howto/lartc.qdisc.terminology.html correct, the qdisc is the outgoing queue and the last queue of the kernel. After this queue, there are only the hardware queues.)
Anyway, adding a maxdelay to codel / fq_codel is really easy : This
would drop packet if its sejourn time is above a given limit.
Just dropping when to old is not our goal. In fact we are avoiding blind dropping! With our replace we make sure that a packet of one class will go over the air when this packet is in line. But the information was replaced during the stay in the queue, so that the newest information got sent.
If you want I can cook this patch.
Thank for you offer/support. But as described above, this is not a solution for us (we discussed this again in our group).
Greetings
Ralph Erdt
From: Eric Dumazet <hidden> Date: 2012-07-02 07:31:53
On Mon, 2012-07-02 at 07:02 +0000, Erdt, Ralph wrote:
Even if the wireless queue is a problem (because of our setup, this is
not a problem), the network stack queue (*) is the biggest queue, and
a good point to optimize.
Hmm, I am not convinced you have no queues on wireless.
Please describe how you managed this.
In fact this is the biggest problem with wireless : mac82011 framework
aggressively pull packets from Linux packet qdisc in order to perform
packet aggregation.
Most packets don't stay in qdisc but are sitting in wireless driver,
unless you really flood it. If it happens, you already are in trouble.
So code your qdisc thing, but I am not sure you'll get much improvement.
You would need to implement it in wireless code instead.
From: Erdt, Ralph <hidden> Date: 2012-07-02 08:39:00
quoted
Even if the wireless queue is a problem (because of our setup, this
is
quoted
not a problem), the network stack queue (*) is the biggest queue, and
a good point to optimize.
Hmm, I am not convinced you have no queues on wireless.
Please describe how you managed this.
In fact this is the biggest problem with wireless : mac82011 framework
aggressively pull packets from Linux packet qdisc in order to perform
packet aggregation.
I did not talking about W-LAN (802.11). I'm talking about an property technology which is able to send over KILOMETERs (WLAN < 100m) but with VERY low bandwidth: 9600 bit (no Mega, Giga or Kilo!) (W-LAN: slowest: 1Mbit).
The devices is loosely connected to our boxes: No linux driver but a program which create an virtual network device. This just sends one packet to the devices and then waits for the acknowledgement that the packet was sent. THEN the next packet will be send. There is no further queue, because the wireless is so lame, that there is no need for that!
(BTW: the qdisc and the connector are distinct problems/programs. There is no dependency.)
Most packets don't stay in qdisc but are sitting in wireless driver,
unless you really flood it. If it happens, you already are in trouble.
We ARE in trouble... :-/
So code your qdisc thing, but I am not sure you'll get much
improvement.
It's implemented already (it's just a little source file), and it worked in the simulation. But I cannot test them on real devices ATM.
My question is: Should I do the work to create and release a kernel patch and make it perfect over the time, or is this just our internal code, which I can leave at the current state? I know our module won't be used widely (too special), but I'm sure, there are a few people out there, which would be thankful for this.
From: Rick Jones <hidden> Date: 2012-07-02 17:25:59
On 07/02/2012 01:38 AM, Erdt, Ralph wrote:
I did not talking about W-LAN (802.11). I'm talking about an
property technology which is able to send over KILOMETERs (WLAN <
100m) but with VERY low bandwidth: 9600 bit (no Mega, Giga or Kilo!)
(W-LAN: slowest: 1Mbit). The devices is loosely connected to our
boxes: No linux driver but a program which create an virtual network
device. This just sends one packet to the devices and then waits for
the acknowledgement that the packet was sent. THEN the next packet
will be send. There is no further queue, because the wireless is so
lame, that there is no need for that! (BTW: the qdisc and the
connector are distinct problems/programs. There is no dependency.)
quoted
Most packets don't stay in qdisc but are sitting in wireless
driver, unless you really flood it. If it happens, you already are
in trouble.
We ARE in trouble... :-/
While you may need to tweak some of the constants based on your bitrate
and MTU size (which if the former is 9600 bits per second I trust the
latter is rather smaller than 1500 bytes since that would be well over a
second to transmit... and so the RTT there will be large), it sounds
like codel will do good things for you. It won't replace the packet,
but its use of drop on dequeue will I believe accomplish substantially
the same effect.
rick jones
From: Nicolas de Pesloüan <hidden> Date: 2012-07-02 20:31:21
Le 02/07/2012 10:38, Erdt, Ralph a écrit :
quoted
quoted
Even if the wireless queue is a problem (because of our setup, this
is
quoted
not a problem), the network stack queue (*) is the biggest queue, and
a good point to optimize.
Hmm, I am not convinced you have no queues on wireless.
Please describe how you managed this.
In fact this is the biggest problem with wireless : mac82011 framework
aggressively pull packets from Linux packet qdisc in order to perform
packet aggregation.
I did not talking about W-LAN (802.11). I'm talking about an property technology which is able to
send over KILOMETERs (WLAN< 100m) but with VERY low bandwidth: 9600 bit (no Mega, Giga or Kilo!)
(W-LAN: slowest: 1Mbit). The devices is loosely connected to our boxes: No linux driver but a
program which create an virtual network device. This just sends one packet to the devices and
then waits for the acknowledgement that the packet was sent. THEN the next packet will be send.
There is no further queue, because the wireless is so lame, that there is no need for that! (BTW:
the qdisc and the connector are distinct problems/programs. There is no dependency.)
If I were you, I would use a tun/tap interface and manage a private packet queue in userspace. This
way, you wouldn't have to manage the overhead of porting your kernel code to every new kernel versions.
Nicolas.
From: Eric Dumazet <hidden> Date: 2012-07-02 21:56:15
On Mon, 2012-07-02 at 22:32 +0200, Nicolas de Pesloüan wrote:
Le 02/07/2012 10:38, Erdt, Ralph a écrit :
quoted
quoted
quoted
Even if the wireless queue is a problem (because of our setup, this
is
quoted
not a problem), the network stack queue (*) is the biggest queue, and
a good point to optimize.
Hmm, I am not convinced you have no queues on wireless.
Please describe how you managed this.
In fact this is the biggest problem with wireless : mac82011 framework
aggressively pull packets from Linux packet qdisc in order to perform
packet aggregation.
I did not talking about W-LAN (802.11). I'm talking about an property technology which is able to
send over KILOMETERs (WLAN< 100m) but with VERY low bandwidth: 9600 bit (no Mega, Giga or Kilo!)
(W-LAN: slowest: 1Mbit). The devices is loosely connected to our boxes: No linux driver but a
program which create an virtual network device. This just sends one packet to the devices and
then waits for the acknowledgement that the packet was sent. THEN the next packet will be send.
There is no further queue, because the wireless is so lame, that there is no need for that! (BTW:
the qdisc and the connector are distinct problems/programs. There is no dependency.)
If I were you, I would use a tun/tap interface and manage a private packet queue in userspace. This
way, you wouldn't have to manage the overhead of porting your kernel code to every new kernel versions.
This seems a good idea.
Then you can do other coalescing stuff, like TCP ACK that could be
aggregated to single ACK as well.
From: Erdt, Ralph <hidden> Date: 2012-07-03 07:29:39
quoted
If I were you, I would use a tun/tap interface and manage a private
packet queue in userspace. This way, you wouldn't have to manage the
overhead of porting your kernel code to every new kernel versions.
quoted
This seems a good idea.
Then you can do other coalescing stuff, like TCP ACK that could be
aggregated to single ACK as well.
Thanks for the idea. But this is option when just doing the replace thing.
But the charm of the qdisc solution is the complete integration to TC. It's complete compatible to the other options, so that you can create a bigger TC rule set. And creating the rules is a standard operation for the administrators - they know TC.
In terms of the other coalescing stuff (we didn't use TCP, because it's not possible) - it's already done in the device "driver" I mentioned. Yes, we can extend the "driver", but the qdisc solution has the benefit that there is a clear separation.
Nevertheless we will discuss the idea internally. Maybe the group got another idea based on this.
From: Erdt, Ralph <hidden> Date: 2012-07-03 10:02:09
Hello,
I found, that my eMail program send the eMail as UTF-8 / Base64. I'm sorry for the circumstances. I hope it's OK for you, that I'm repeating the content, so that everyone can follow it. But I will compress the whole discussion (Thanks to Eric Dumazet, Rick Jones and Nicolas de Peslouan):
-
I'm writing a kernel module (net/sched) which replaces packets in the queue. I'm glad hearing your option.
Background:
We are working with a property wireless network (no 802.11). The specifications:
Range: Kilometers.
Speed: <=9,600 bps (no Megs, Gigs or Kilo!) (*).
RTT (standard ping): idle-network: 1,5 *seconds*; network with load: minutes
Other: shared.
Connection: loosely to a Linux box, but without Linux driver.
Driver: a user-space program, which opens a virtual network device and sends
the packet from the virtual network device to the device.
Queue: The device has no queue nor the user-space program. The program waits
for the ACK from the device before sending the next packet. This is
possible, because the wireless is so lame...
(*you remember the good ol' times with modems over telephone lines? When the
internet was called BBS? And how it suddenly feels, when the BBS starts using
ANSI? This was comfortable compared to our problem..)
With such a very low bandwidth network its hard (rather: impossible) to get all
packets sent. (TCP isn't possible, so we are sending everything as UDP.)
Some of the packets contain information, which gets obsolete over time. E.g.
(GPS) positions, which will be sent periodically. If the application sends a new
packet while an old position packet is still in the queue, the old packet is
obsolete. This can be dropped. But just dropping the old packet and queuing the
new packet will result in never sending a packet of this type.
So I've written a tc-qdisc scheduler module, which replaces packets in the queue
on enqueuing, when this properties are given:
- UDPv4
- not fragmented
- (TOS & bitmask) = givenCompare; (bitmask and compare are adjustable)
- same source IP
- same destination IP
- same destination port
- same TOS
So, the packet got sent over the time - but with the actual information.
(The code is tiny - just a file (and Kconfig, etc.))
Why not using "codel"? Because codel will drop "randomly" ("random" not for the
protocol, but for the application) packets. It's made to reduce the flow speed.
But we haven't a flow, only periodic sensor data.
My qdisc won't drop random packets. It will reduce the traffic by intelligently
replacing packets in the queue. Surely - the application must handle this. But
in such a network a administrator have to configure the queues and he knows the
applications.
Why not adding a tun/tap interface and do everything in the user space?
As mentioned, the device "driver" is a user space program, which creates a tun/tap
interface. We CAN mix the code there in, but separating the work has a few benefits:
- separating the work with clear interfaces is always a good idea.
- having a qdisc will allow complex TC rules using this qdisc - it's fully compatible.
(In fact - we have guidelines given. We can handle all of the guidelines with the
given TC classes - except the replace thing.)
- administrators knowing TC can work with this qdisc without any problems
My question is: Should I do the work to create and release a kernel patch and make
it perfect over the time, or is this just our internal code, which I can leave at
the current state? I know our module won't be used widely (too special), but I'm
sure, there are a few people out there, which would be thankful for this.
Have you any other comments?
Greetings
Ralph Erdt
From: Nicolas de Pesloüan <hidden> Date: 2012-07-04 20:31:54
Le 03/07/2012 12:02, Erdt, Ralph a écrit :
My question is: Should I do the work to create and release a kernel patch and make
it perfect over the time, or is this just our internal code, which I can leave at
the current state? I know our module won't be used widely (too special), but I'm
sure, there are a few people out there, which would be thankful for this.
I suggest you try and send a properly formated patch with your code, so that people here can have a
look at it and evaluate the interest of integrating it into main line kernel.
That being said, I really think you should try to manage a userspace queue, in particular if you
already have most of the job done in userspace using a tun/tap. I don't know the details of the
special device you work with, but if you manage both side of the link, you can add many nice
features into userspace to enhance the speed/quality :
- Compression (including very clever one if you know the meaning of the data you are transmitting).
- Packet numbering, to allow the remote side to ACK packet, the same way TCP does.
- Early ACK on TCP, if you get an ACK from the other side of your link and you assure that this link
is the worst part of the path. This may help TCP to work on this low speed/high RTT link.
And I really see your packet replacement system as one of those nice features and cannot imagine a
good reason not to put it in userspace.
Nicolas.
From: Erdt, Ralph <hidden> Date: 2012-07-18 14:50:25
Hello.
I'm sorry for the very late answer. But I had top-priority family issues.
I suggest you try and send a properly formated patch with your code, so
that people here can have a look at it and evaluate the interest of
integrating it into main line kernel.
Attached at the button of the eMail.
That being said, I really think you should try to manage a userspace
queue, [..] you can
add many nice features into userspace to enhance the speed/quality
[..]
And I really see your packet replacement system as one of those nice
features and cannot imagine a good reason not to put it in userspace.
All this features are done already. E.g. we are using RoHC.
But we also want to use the TC stuff - its already there - why reprogramming?
Here the patch. But I didn't find which git tree I should use. This patch is against Linux-2.6. I'm sorry. Can you tell me, which tree I've to use?
-------------
From 52f27fa2b0867de821af38c731c2ebc763afb1f1 Mon Sep 17 00:00:00 2001
From: Ralph Erdt <redacted>
Date: Wed, 18 Jul 2012 16:43:44 +0200
Subject: [PATCH] RFC: TC qdisc "replace packet in queue"
This adds a new TC qdisc, which replaces packets in the queue. It
compares every incoming packet with all of the packets in the queue.
If the incoming and the compared packet meet all these conditions:
- UDPv4
- not fragmented
- TOS like the given value(s)
- same TOS
- same source IP
- same destination IP
- same destination port
the packet in the queue will be replaced with the incoming packet.
The variable "overlimit" is the counter of replaced packets
Background:
In very low bandwidth networks (<=9.6Kbps, shared, etc.) it's hard
(rather: impossible) to get all packets sent.
But some of the packets contain information, which gets obsolete over
time. E.g. (GPS) positions, which will be sent periodically. If the
application sends a new packet while an old position packet is still in
the queue, the old packet is obsolete. This can be dropped. But just
dropping the old packet and queuing the new packet will result in never
sending a packet of this type. So this qdisc replace the old packet with
the new one. The information gets the chance to get sent - with the
newest available information.
Code-Status:
RFC for discussing.
The configuration by "debug-fs" is ... not optimal. But following the
"litte step" rules this is a first option. A configuration with tc will
be done later (if this patch got offical).
Signed-off-by: Ralph Erdt <redacted>
---
net/sched/Kconfig | 16 +++
net/sched/Makefile | 1 +
net/sched/sch_pr.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 281 insertions(+), 0 deletions(-)
create mode 100644 net/sched/sch_pr.c
@@ -0,0 +1,264 @@+/*+*net/sched/sch_pr.c"packet replace"+*+*Copyrigth(c)2012FraunhoferFKIE,allrigthsreserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsoftheGNUGeneralPublicLicense+*aspublishedbytheFreeSoftwareFoundation;eitherversion+*2oftheLicense,or(atyouroption)anylaterversion.+*+*Authors:RalphErdt(FraunhoferFKIE),+*<ralph.robert.erdt@fkie.fraunhofer.de>+*/++#include<linux/module.h>+#include<linux/slab.h>+#include<linux/types.h>+#include<linux/kernel.h>+#include<linux/errno.h>+#include<linux/skbuff.h>+#include<net/pkt_sched.h>++#include<linux/ip.h>+#include<net/ip.h>+#include<linux/debugfs.h>++/*+*replacepacketinqueue+*==========================+*Thisisamodifiedfifoqueue(fifobyAlexeyKuznetsov).+*+*Thispacketcompareseveryincomingpacketwithallofthepacketsinthe+*queue.+*Iftheincomingandthecomparedpacketmeetalltheseconditions:+*-UDPv4+*-notfragmented+*-TOSlikethegivenvalue(s)+*-sameTOS+*-samesourceIP+*-samedestinationIP+*-samedestinationport+*thepacketinthequeuewillbereplacedwiththeincomingpacket.+*+*Thevariable"overlimit"isthecounterofreplacedpackets+*+*Background:+*Inverylowbandwidthnetworks(<=9.6Kbps,shared,etc.)it'shard+*(rather:impossible)togetallpacketssent.+*Butsomeofthepacketscontaininformation,whichgetsobsoleteovertime.+*E.g.(GPS)positions,whichwillbesentperiodically.Iftheapplication+*sendsanewpacketwhileanoldpositionpacketisstillinthequeue,the+*oldpacketisobsolete.Thiscanbedropped.Butjustdroppingtheold+*packetandqueuingthenewpacketwillresultinneversendingapacket+*ofthistype.+*Sothisqdiscreplacetheoldpacketwiththenewone.Theinformationgets+*thechancetogetsent-withthenewestavailableinformation.+*+*DRAWBACKS:+*ItsnotveryCPUcyclesaving.Butonverylowbandwithnetworksthe+*applicationhavetobecarefulwithsendingpackets.Andwithapropper+*configuration,thiswillbeOK.+*/++structdentry*dgdir,*dgfile;++#define TOSBITMASK 0+#define TOSCOMPARE 1+/* tos Flag. 1.: BitMask. 2.: Compare with */+staticu8tos[]={0xFF,0xFF};++boolpr_packet_to_work_with(structsk_buff*pkt)+{+structiphdr*hdr;++if(unlikely(pkt->protocol!=htons(ETH_P_IP)))+returnfalse;++/* Only compare UDP - Layer 4 must be there */+if(unlikely(pkt->network_header==NULL))+returnfalse;++hdr=ip_hdr(pkt);++/* Check for UDPv4 */+if(unlikely(hdr->protocol!=IPPROTO_UDP))+returnfalse;++/* no fragmented packets */+if(unlikely(ip_is_fragment(hdr)))+returnfalse;++/* Correct TOS ? */+if((hdr->tos&tos[TOSBITMASK])!=tos[TOSCOMPARE])+returnfalse;++returntrue;+}++boolcomp(structsk_buff*a,structsk_buff*b)+{+structiphdr*ah=NULL;+structiphdr*bh=NULL;+u32ipA,ipB;+u16portsA,portsB;+intpoff;+/* The packet has a header+*-theexistencewasalreadycheckedby"pr_packet_to_work_with"*/+ah=ip_hdr(a);+bh=ip_hdr(b);++/* TOS must be the same */+if(ah->tos!=bh->tos)+returnfalse;++/* IP and Port must be the same */+ipA=(__forceu32)ah->daddr;+ipB=(__forceu32)bh->daddr;+if((ipA!=ipB))+returnfalse;+ipA=(__forceu32)ah->saddr;+ipB=(__forceu32)bh->saddr;+if((ipA!=ipB))+returnfalse;++poff=proto_ports_offset(IPPROTO_UDP);+if(unlikely(poff<0))+/* This should be impossible.. */+returnfalse;++/* Src Ports are always different - just compare destination ports */+portsA=*(u16*)((void*)ah+bh->ihl*4+poff+2);+portsB=*(u16*)((void*)bh+ah->ihl*4+poff+2);+if((portsA!=portsB))+returnfalse;++returntrue;+}++staticintpr_enqueue(structsk_buff*skb,structQdisc*sch)+{+structsk_buff*replace=NULL;++/* Search, if there is a packet with same IDs */+/* Only search, if this packet is worth it */+if(pr_packet_to_work_with(skb)){+structsk_buff*it;+skb_queue_walk((&(sch->q)),it){+/* If the other packet is worth it? */+if(pr_packet_to_work_with(it)){+if(comp(skb,it)){+replace=it;+break;+}+}+}+}++if(replace==NULL){+/* a new kind of packet. Just enqueue */+if(likely(skb_queue_len(&sch->q)<sch->limit))+returnqdisc_enqueue_tail(skb,sch);+returnqdisc_reshape_fail(skb,sch);+}else{+/* replace the packet */+sch->qstats.overlimits++;+/* There is no drop nor replace. So do the replace myself */+skb->next=replace->next;+skb->prev=replace->prev;+if(replace->next!=NULL)+replace->next->prev=skb;+if(replace->prev!=NULL)+replace->prev->next=skb;+kfree_skb(replace);+returnNET_XMIT_SUCCESS;+}+}++staticintpr_init(structQdisc*sch,structnlattr*opt)+{+sch->flags|=TCQ_F_CAN_BYPASS;/* sounds good, but what? */+sch->limit=qdisc_dev(sch)->tx_queue_len?:1;+return0;+}++staticintpr_dump(structQdisc*sch,structsk_buff*skb)+{+structtc_fifo_qoptopt={.limit=sch->limit};++if(nla_put(skb,TCA_OPTIONS,sizeof(opt),&opt))+gotonla_put_failure;++returnskb->len;++nla_put_failure:+return-1;+}++structQdisc_opspr_qdisc_ops__read_mostly={+.id="pr",+.priv_size=0,+.enqueue=pr_enqueue,+.dequeue=qdisc_dequeue_head,+.peek=qdisc_peek_head,+.drop=qdisc_queue_drop,+.init=pr_init,+.reset=qdisc_reset_queue,+.change=pr_init,+.dump=pr_dump,+.owner=THIS_MODULE,+};+EXPORT_SYMBOL(pr_qdisc_ops);++/* DebugFS interface as first shot configuration */+staticssize_tdg_read_file(structfile*file,char__user*userbuf,+size_tcount,loff_t*ppos)+{+returnsimple_read_from_buffer(userbuf,count,ppos,tos,2);+}++staticssize_tdg_write_file(structfile*file,constchar__user*buf,+size_tcount,loff_t*ppos)+{+u8tmp[]={0xFF,0xFF};+intres;+if(count!=2)+return-EINVAL;++res=copy_from_user(tmp,buf,count);+if(res!=0)+return-EINVAL;++/* Two bytes to copy.. for this a memcpy with errorhandling?!? */+tos[0]=tmp[0];+tos[1]=tmp[1];++returncount;+}++staticconststructfile_operationsdgfops={+.read=dg_read_file,+.write=dg_write_file,+};++staticint__initpr_module_init(void)+{+boolret=register_qdisc(&pr_qdisc_ops);+if(!ret){+/* open Communication channel */+dgdir=debugfs_create_dir("sch_pr",NULL);+dgfile=debugfs_create_file("tos",0644,dgdir,tos,&dgfops);+}+returnret;+}++staticvoid__exitpr_module_exit(void)+{+debugfs_remove(dgfile);+debugfs_remove(dgdir);+unregister_qdisc(&pr_qdisc_ops);+}++module_init(pr_module_init);+module_exit(pr_module_exit);+MODULE_LICENSE("GPL");