Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
19c7c61c
Commit
19c7c61c
authored
Mar 18, 2004
by
Stephen Hemminger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[NET_SCHED]: Add packet delay scheduler.
parent
096acddf
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
287 additions
and
0 deletions
+287
-0
include/linux/pkt_sched.h
include/linux/pkt_sched.h
+6
-0
net/sched/Kconfig
net/sched/Kconfig
+11
-0
net/sched/Makefile
net/sched/Makefile
+1
-0
net/sched/sch_delay.c
net/sched/sch_delay.c
+269
-0
No files found.
include/linux/pkt_sched.h
View file @
19c7c61c
...
...
@@ -432,4 +432,10 @@ enum {
#define TCA_ATM_MAX TCA_ATM_STATE
/* Delay section */
struct
tc_dly_qopt
{
__u32
latency
;
__u32
limit
;
};
#endif
net/sched/Kconfig
View file @
19c7c61c
...
...
@@ -164,6 +164,17 @@ config NET_SCH_DSMARK
To compile this code as a module, choose M here: the
module will be called sch_dsmark.
config NET_SCH_DELAY
tristate "Delay simulator"
depends on NET_SCHED
help
Say Y if you want to delay packets by a fixed amount of
time. This is often useful to simulate network delay when
testing applications or protocols.
To compile this driver as a module, choose M here: the module
will be called sch_delay.
config NET_SCH_INGRESS
tristate "Ingress Qdisc"
depends on NET_SCHED && NETFILTER
...
...
net/sched/Makefile
View file @
19c7c61c
...
...
@@ -22,6 +22,7 @@ obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o
obj-$(CONFIG_NET_SCH_TEQL)
+=
sch_teql.o
obj-$(CONFIG_NET_SCH_PRIO)
+=
sch_prio.o
obj-$(CONFIG_NET_SCH_ATM)
+=
sch_atm.o
obj-$(CONFIG_NET_SCH_DELAY)
+=
sch_delay.o
obj-$(CONFIG_NET_CLS_U32)
+=
cls_u32.o
obj-$(CONFIG_NET_CLS_ROUTE4)
+=
cls_route.o
obj-$(CONFIG_NET_CLS_FW)
+=
cls_fw.o
...
...
net/sched/sch_delay.c
0 → 100644
View file @
19c7c61c
/*
* net/sched/sch_delay.c Simple constant delay
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Stephen Hemminger <shemminger@osdl.org>
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/notifier.h>
#include <net/ip.h>
#include <net/route.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
/* Network delay simulator
This scheduler adds a fixed delay to all packets.
Similar to NISTnet and BSD Dummynet.
It uses byte fifo underneath similar to TBF */
struct
dly_sched_data
{
u32
latency
;
u32
limit
;
struct
timer_list
timer
;
struct
Qdisc
*
qdisc
;
};
/* Time stamp put into socket buffer control block */
struct
dly_skb_cb
{
psched_time_t
queuetime
;
};
/* Enqueue packets with underlying discipline (fifo)
* but mark them with current time first.
*/
static
int
dly_enqueue
(
struct
sk_buff
*
skb
,
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
struct
dly_skb_cb
*
cb
=
(
struct
dly_skb_cb
*
)
skb
->
cb
;
int
ret
;
PSCHED_GET_TIME
(
cb
->
queuetime
);
/* Queue to underlying scheduler */
ret
=
q
->
qdisc
->
enqueue
(
skb
,
q
->
qdisc
);
if
(
ret
)
sch
->
stats
.
drops
++
;
else
{
sch
->
q
.
qlen
++
;
sch
->
stats
.
bytes
+=
skb
->
len
;
sch
->
stats
.
packets
++
;
}
return
0
;
}
/* Requeue packets but don't change time stamp */
static
int
dly_requeue
(
struct
sk_buff
*
skb
,
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
int
ret
;
ret
=
q
->
qdisc
->
ops
->
requeue
(
skb
,
q
->
qdisc
);
if
(
ret
==
0
)
sch
->
q
.
qlen
++
;
return
ret
;
}
static
unsigned
int
dly_drop
(
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
unsigned
int
len
;
len
=
q
->
qdisc
->
ops
->
drop
(
q
->
qdisc
);
if
(
len
)
{
sch
->
q
.
qlen
--
;
sch
->
stats
.
drops
++
;
}
return
len
;
}
/* Dequeue packet.
* If packet needs to be held up, then stop the
* queue and set timer to wakeup later.
*/
static
struct
sk_buff
*
dly_dequeue
(
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
struct
sk_buff
*
skb
=
q
->
qdisc
->
dequeue
(
q
->
qdisc
);
if
(
skb
)
{
struct
dly_skb_cb
*
cb
=
(
struct
dly_skb_cb
*
)
skb
->
cb
;
psched_time_t
now
;
long
diff
;
PSCHED_GET_TIME
(
now
);
diff
=
q
->
latency
-
PSCHED_TDIFF
(
now
,
cb
->
queuetime
);
if
(
diff
<=
0
)
{
sch
->
q
.
qlen
--
;
sch
->
flags
&=
~
TCQ_F_THROTTLED
;
return
skb
;
}
if
(
!
netif_queue_stopped
(
sch
->
dev
))
{
long
delay
=
PSCHED_US2JIFFIE
(
diff
);
if
(
delay
<=
0
)
delay
=
1
;
mod_timer
(
&
q
->
timer
,
jiffies
+
delay
);
}
if
(
q
->
qdisc
->
ops
->
requeue
(
skb
,
q
->
qdisc
)
!=
NET_XMIT_SUCCESS
)
{
sch
->
q
.
qlen
--
;
sch
->
stats
.
drops
++
;
}
sch
->
flags
|=
TCQ_F_THROTTLED
;
}
return
NULL
;
}
static
void
dly_reset
(
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
qdisc_reset
(
q
->
qdisc
);
sch
->
q
.
qlen
=
0
;
sch
->
flags
&=
~
TCQ_F_THROTTLED
;
del_timer
(
&
q
->
timer
);
}
static
void
dly_timer
(
unsigned
long
arg
)
{
struct
Qdisc
*
sch
=
(
struct
Qdisc
*
)
arg
;
sch
->
flags
&=
~
TCQ_F_THROTTLED
;
netif_schedule
(
sch
->
dev
);
}
/* Tell Fifo the new limit. */
static
int
change_limit
(
struct
Qdisc
*
q
,
u32
limit
)
{
struct
rtattr
*
rta
;
int
ret
;
rta
=
kmalloc
(
RTA_LENGTH
(
sizeof
(
struct
tc_fifo_qopt
)),
GFP_KERNEL
);
if
(
!
rta
)
return
-
ENOMEM
;
rta
->
rta_type
=
RTM_NEWQDISC
;
((
struct
tc_fifo_qopt
*
)
RTA_DATA
(
rta
))
->
limit
=
limit
;
ret
=
q
->
ops
->
change
(
q
,
rta
);
kfree
(
rta
);
return
ret
;
}
/* Setup underlying FIFO discipline */
static
int
dly_change
(
struct
Qdisc
*
sch
,
struct
rtattr
*
opt
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
struct
tc_dly_qopt
*
qopt
=
RTA_DATA
(
opt
);
int
err
;
if
(
q
->
qdisc
==
&
noop_qdisc
)
{
struct
Qdisc
*
child
=
qdisc_create_dflt
(
sch
->
dev
,
&
bfifo_qdisc_ops
);
if
(
!
child
)
return
-
EINVAL
;
q
->
qdisc
=
child
;
}
err
=
change_limit
(
q
->
qdisc
,
qopt
->
limit
);
if
(
err
)
{
qdisc_destroy
(
q
->
qdisc
);
q
->
qdisc
=
&
noop_qdisc
;
}
else
{
q
->
latency
=
qopt
->
latency
;
q
->
limit
=
qopt
->
limit
;
}
return
err
;
}
static
int
dly_init
(
struct
Qdisc
*
sch
,
struct
rtattr
*
opt
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
if
(
!
opt
)
return
-
EINVAL
;
init_timer
(
&
q
->
timer
);
q
->
timer
.
function
=
dly_timer
;
q
->
timer
.
data
=
(
unsigned
long
)
sch
;
q
->
qdisc
=
&
noop_qdisc
;
return
dly_change
(
sch
,
opt
);
}
static
void
dly_destroy
(
struct
Qdisc
*
sch
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
del_timer
(
&
q
->
timer
);
qdisc_destroy
(
q
->
qdisc
);
q
->
qdisc
=
&
noop_qdisc
;
}
static
int
dly_dump
(
struct
Qdisc
*
sch
,
struct
sk_buff
*
skb
)
{
struct
dly_sched_data
*
q
=
(
struct
dly_sched_data
*
)
sch
->
data
;
unsigned
char
*
b
=
skb
->
tail
;
struct
tc_dly_qopt
qopt
;
qopt
.
latency
=
q
->
latency
;
qopt
.
limit
=
q
->
limit
;
RTA_PUT
(
skb
,
TCA_OPTIONS
,
sizeof
(
qopt
),
&
qopt
);
return
skb
->
len
;
rtattr_failure:
skb_trim
(
skb
,
b
-
skb
->
data
);
return
-
1
;
}
static
struct
Qdisc_ops
dly_qdisc_ops
=
{
.
id
=
"delay"
,
.
priv_size
=
sizeof
(
struct
dly_sched_data
),
.
enqueue
=
dly_enqueue
,
.
dequeue
=
dly_dequeue
,
.
requeue
=
dly_requeue
,
.
drop
=
dly_drop
,
.
init
=
dly_init
,
.
reset
=
dly_reset
,
.
destroy
=
dly_destroy
,
.
change
=
dly_change
,
.
dump
=
dly_dump
,
.
owner
=
THIS_MODULE
,
};
static
int
__init
dly_module_init
(
void
)
{
return
register_qdisc
(
&
dly_qdisc_ops
);
}
static
void
__exit
dly_module_exit
(
void
)
{
unregister_qdisc
(
&
dly_qdisc_ops
);
}
module_init
(
dly_module_init
)
module_exit
(
dly_module_exit
)
MODULE_LICENSE
(
"GPL"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment