Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
emulab
emulab-devel
Commits
6518579c
Commit
6518579c
authored
Dec 28, 2000
by
mac
Browse files
Old dummynet code and ipfw mods. Moved to attic.
parent
9f194304
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
delay/Makefile
deleted
100644 → 0
View file @
9f194304
OBJS
=
delay.o
POBJS
=
delay.po
CFLAGS
+=
-Wall
-O2
-DSPIN_OK
#-DDEBUG=1 -g
CC
=
gcc
LIBS
=
-L
.
-ldivert
PLIBS
=
-L
.
-ldivert_p
all
:
delay
delay.po
:
delay.c
${CC}
delay.c
-pg
-c
-o
$@
delay
:
${OBJS}
$(CC)
$(OBJS)
${LIBS}
-o
delay
delay_p
:
${POBJS}
$(CC)
-pg
$(POBJS)
${PLIBS}
-o
$@
libdivert.a
:
divert.o divert_hash.o
${AR}
cr libdivert.a divert.o divert_hash.o
${RANLIB}
libdivert.a
install
:
delay
cp
-f
delay /tmp/delay
clean
:
/bin/rm
-rf
$(OBJS)
delay
delay/delay.c
deleted
100644 → 0
View file @
9f194304
/*
* Delay packets using divert sockets in FreeBSD or the OSKit with
* the FreeBSD 3.0 libs. Uses some functions from my divert sockets
* library to set up the ipfw rules and perform socket accounting.
*
* Inefficient, and the timers have potentially poor granularity.
* Nevertheless, it should be sufficient for large-scale delays
* (on the order of 10s of miliseconds), but will *not* work for
* delays < 1ms, for sure.
*
* Author: Dave Andersen <danderse@cs.utah.edu> <angio@pobox.com>
* 1999-08-27
*/
/*
* Account for the time it takes us to enqueue and such.
* Could be variable depending on load, of course, but this
* is better than nothing.
*/
#ifndef DELAY_COMPENSATION
#define DELAY_COMPENSATION 70
#endif
#include
<sys/types.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<unistd.h>
#include
<sys/signal.h>
#include
<assert.h>
#include
<sys/time.h>
#include
<string.h>
#include
<errno.h>
#include
<sys/socket.h>
#include
<limits.h>
#include
"divert.h"
struct
msockinfo
*
msock
,
*
outsock
;
#ifdef DEBUG
#define DPRINTF(fmt, args...) printf(fmt , ##args )
#else
#define DPRINTF(args...)
#endif
long
timediff
(
struct
timeval
*
time_now
,
struct
timeval
*
time_prev
);
/*
* I'm lazy, but want to see if an allocation fails...
*/
inline
void
*
C_MALLOC
(
size_t
size
)
{
void
*
tmp
;
tmp
=
malloc
(
size
);
assert
(
tmp
!=
NULL
);
return
tmp
;
}
struct
packet
*
phead
=
NULL
;
struct
packet
*
ptail
=
NULL
;
int
sniffsock
;
struct
packet
{
char
*
data
;
int
datalen
;
struct
timeval
exptime
;
struct
sockaddr_in
from
;
int
fromlen
;
struct
packet
*
next
;
};
struct
bufq
{
struct
bufq
*
next
;
};
struct
bufq
*
bufhead
=
NULL
;
int
bufq_size
=
0
;
void
dump_stats
()
{
printf
(
"At exit, bufq contains %d buffers
\n
"
,
bufq_size
);
}
/* Buffer management */
void
*
getbuf
()
{
struct
bufq
*
nextbuf
;
if
(
!
bufhead
)
{
return
malloc
(
MAXPACKET
);
}
nextbuf
=
bufhead
;
bufhead
=
bufhead
->
next
;
bufq_size
--
;
return
nextbuf
;
}
void
freebuf
(
void
*
freeme
)
{
((
struct
bufq
*
)
freeme
)
->
next
=
bufhead
;
bufhead
=
(
struct
bufq
*
)
freeme
;
bufq_size
++
;
}
/*
* Put a packet at the end of the waiting queue.
*
* Right now, I simply run the full list at each clock tick, which is pretty
* inefficient, but this is a prototype. :-) It would be better to be more
* intelligent about this - keep a counter of the times elapsed, process
* packets until we hit one that isn't ready to go out, and then just
* increment that counter. Then start running the list with the counter.
* Would take more accounting, of course.
*
* Or just use the TCP timeout counters from the kernel. :)
*/
int
packet_enq
(
char
*
data
,
int
datalen
,
struct
timeval
exptime
,
struct
sockaddr_in
from
,
int
fromlen
)
{
struct
packet
*
tmp
;
tmp
=
C_MALLOC
(
sizeof
(
*
tmp
));
if
(
ptail
)
{
ptail
->
next
=
tmp
;
ptail
=
tmp
;
}
else
{
phead
=
ptail
=
tmp
;
}
ptail
->
data
=
data
;
ptail
->
datalen
=
datalen
;
ptail
->
exptime
=
exptime
;
ptail
->
from
=
from
;
ptail
->
fromlen
=
fromlen
;
ptail
->
next
=
NULL
;
return
0
;
}
/*
* Put the packet back on the wire, unmodified.
*/
void
packet_forw
(
struct
packet
*
packet
)
{
int
wlen
;
#ifdef DEBUG
printf
(
"Sock: %d, len: %d, fromlen: %d
\n
"
,
msock
->
sock
,
packet
->
datalen
,
packet
->
fromlen
);
IPDUMP
((
struct
ip
*
)(
packet
->
data
));
#endif
wlen
=
sendto
(
msock
->
sock
,
packet
->
data
,
packet
->
datalen
,
0
,
(
struct
sockaddr
*
)
&
(
packet
->
from
),
packet
->
fromlen
);
if
(
wlen
<=
0
)
{
perror
(
"sendto"
);
}
#if 0
printf("Forwarded, got %d\n", wlen);
#endif
}
/*
* Process the packet queue, forwarding any packets which are ready for
* forwarding, and removing them from the queue.
*/
int
pq_run
(
struct
timeval
*
curtime
)
{
struct
packet
*
tmp
;
struct
packet
*
prev
=
NULL
;
struct
packet
*
next
=
NULL
;
tmp
=
phead
;
while
(
tmp
!=
NULL
)
{
next
=
tmp
->
next
;
if
(
timediff
(
&
tmp
->
exptime
,
curtime
)
<=
0
)
{
packet_forw
(
tmp
);
if
(
prev
)
{
prev
->
next
=
next
;
}
else
{
if
(
tmp
==
phead
)
{
phead
=
next
;
}
}
if
(
tmp
==
ptail
)
{
ptail
=
NULL
;
}
freebuf
(
tmp
->
data
);
free
(
tmp
);
tmp
=
NULL
;
}
else
{
/* No more packets to check... if the head
* isn't ready, nothing is */
return
0
;
}
if
(
!
prev
&&
!
next
)
{
phead
=
ptail
=
NULL
;
return
0
;
}
tmp
=
next
;
}
return
0
;
}
/*
* Close things down, delete the ipfw mappings, and exit
*/
void
cleanup
(
int
sig
)
{
DPRINTF
(
"Sig %d caught
\n
"
,
sig
);
dump_stats
();
free_socket
(
msock
);
exit
(
0
);
}
/*
* Return the # of microseconds difference between two
* timevals. Note that this could overflow if you start
* dealing with large delays, but 35 minutes is an awfully
* long time to delay a packet. :-)
*/
long
timediff
(
struct
timeval
*
time_now
,
struct
timeval
*
time_prev
)
{
long
usecs_now
;
if
(
time_prev
->
tv_sec
==
0
&&
time_prev
->
tv_usec
==
0
)
{
return
0
;
}
usecs_now
=
(
time_now
->
tv_sec
-
time_prev
->
tv_sec
)
*
1000000
;
usecs_now
+=
time_now
->
tv_usec
;
return
usecs_now
-
time_prev
->
tv_usec
;
}
void
usage
()
{
fprintf
(
stderr
,
"usage: delay [-h] [-ui] [-p port/type] [-d delay]
\n
"
);
}
void
help
()
{
usage
();
fprintf
(
stderr
,
" -h help (this message)
\n
"
" -u delay UDP packets (default)
\n
"
" -i delay ICMP packets
\n
"
" -p <port/type> UDP: delay packets to this port
\n
"
" ICMP: Delay this ICMP type
\n
"
" -d <delay> Delay for this many microseconds
\n
"
"
\n
"
);
}
/*
* Set up our sockets, and start the receive / enqueue / run queue
* loop
*/
int
main
(
int
argc
,
char
**
argv
)
{
int
port
=
0
;
char
*
packetbuf
=
NULL
;
unsigned
long
granularity
;
/* Kind of */
unsigned
long
delay
=
1000000
;
struct
timeval
mytv
,
time_now
,
exptime
;
int
rc
;
int
proto
=
IPPROTO_UDP
;
fd_set
readfds
;
/* getopt stuff */
extern
char
*
optarg
;
extern
int
optind
;
int
ch
;
while
((
ch
=
getopt
(
argc
,
argv
,
"huip:d:"
))
!=
-
1
)
switch
(
ch
)
{
case
'u'
:
proto
=
IPPROTO_UDP
;
break
;
case
'i'
:
proto
=
IPPROTO_ICMP
;
break
;
case
'p'
:
port
=
atoi
(
optarg
);
break
;
case
'd'
:
delay
=
atoi
(
optarg
);
break
;
case
'h'
:
help
();
exit
(
-
1
);
default:
usage
();
exit
(
-
1
);
}
argc
-=
optind
;
argv
+=
optind
;
if
(
!
port
)
{
fprintf
(
stderr
,
"must supply a port to divert
\n
"
);
usage
();
exit
(
-
1
);
}
signal
(
SIGTERM
,
cleanup
);
signal
(
SIGQUIT
,
cleanup
);
signal
(
SIGINT
,
cleanup
);
msock
=
get_socket
();
if
(
proto
==
IPPROTO_UDP
)
{
add_mask_port
(
msock
,
port
);
}
else
if
(
proto
==
IPPROTO_ICMP
)
{
add_mask_icmp
(
msock
,
port
);
}
else
{
fprintf
(
stderr
,
"unknown proto type %d
\n
"
,
proto
);
cleanup
(
0
);
exit
(
-
1
);
}
granularity
=
delay
/
100
;
/* Gotta love those 10ms timers... */
#define MIN_USEC 10000
if
(
granularity
<
MIN_USEC
)
granularity
=
MIN_USEC
;
mytv
.
tv_sec
=
granularity
/
1000000
;
mytv
.
tv_usec
=
granularity
%
1000000
;
if
(
mytv
.
tv_sec
==
0
&&
mytv
.
tv_usec
<
MIN_USEC
)
{
mytv
.
tv_usec
=
MIN_USEC
;
}
/* Do our delays by simply breaking out of the recvfrom every
* now and then. Note that this is potentially INACCURATE if
* we're getting a trickle of data - the timeout is actually
* an inactivity timer, so the "right pace" of data arriving could
* throw things off. Not to mention, we're only accurate to about
* 2% of the timeout anyway. We should be able to squeeze more
* accuracy out of this by decreasing the granularity, at the
* expense of effectively spinning waiting for data...
*
* I've tested it with a 1ms delay (and 10us granularity) and
* it doesn't seem to kill things.
*
* Yes, better ways exist and should be used.
*/
rc
=
setsockopt
(
msock
->
sock
,
SOL_SOCKET
,
SO_RCVTIMEO
,
&
mytv
,
sizeof
(
mytv
));
if
(
rc
)
{
perror
(
"Setsockopt for timeout failed"
);
exit
(
errno
);
}
DPRINTF
(
"Timeout set for receive divert socket
\n
"
);
/*
* The meat:
* 1 - Receive any packets. Enqueue them if necessary.
* 2 - Run the queue.
* 3 - Loop dat puppy.
*
* Note that order matters here - you have to enqueue the packets
* after running the queue, or they don't rest long enough.
*/
FD_ZERO
(
&
readfds
);
granularity
=
delay
/
100
;
while
(
1
)
{
struct
sockaddr_in
from
;
int
fromlen
;
int
len
;
int
rc
;
long
addusec
;
if
(
!
packetbuf
)
{
packetbuf
=
getbuf
();
}
if
(
granularity
<
MIN_USEC
)
{
#ifdef SPIN_OK
granularity
=
0
;
#else
granularity
=
MIN_USEC
;
#endif
}
mytv
.
tv_sec
=
granularity
/
1000000
;
mytv
.
tv_usec
=
granularity
%
1000000
;
FD_SET
(
msock
->
sock
,
&
readfds
);
rc
=
select
(
msock
->
sock
+
1
,
&
readfds
,
NULL
,
NULL
,
&
mytv
);
len
=
0
;
if
(
FD_ISSET
(
msock
->
sock
,
&
readfds
))
{
bzero
(
&
from
,
sizeof
(
from
));
fromlen
=
sizeof
(
struct
sockaddr_in
);
len
=
recvfrom
(
msock
->
sock
,
packetbuf
,
MAXPACKET
,
0
,
(
struct
sockaddr
*
)
&
from
,
&
fromlen
);
if
(
len
>
0
)
{
DPRINTF
(
"Received packet of length %d
\n
"
,
len
);
}
}
gettimeofday
(
&
time_now
,
NULL
);
pq_run
(
&
time_now
);
if
(
len
<=
0
)
{
continue
;
}
exptime
=
time_now
;
/* XXX: Cheap hack alert. Beware of this one */
addusec
=
delay
-
DELAY_COMPENSATION
;
exptime
.
tv_sec
+=
addusec
/
1000000
;
addusec
%=
1000000
;
if
((
LONG_MAX
-
addusec
)
<
exptime
.
tv_usec
)
{
exptime
.
tv_sec
++
;
exptime
.
tv_usec
=
exptime
.
tv_usec
-
LONG_MAX
+
addusec
;
}
else
{
exptime
.
tv_usec
+=
addusec
;
}
packet_enq
(
packetbuf
,
len
,
exptime
,
from
,
fromlen
);
packetbuf
=
NULL
;
}
free_socket
(
msock
);
DPRINTF
(
"Exiting
\n
"
);
exit
(
0
);
}
delay/dummynet_mods/ip_dummynet.c
deleted
100644 → 0
View file @
9f194304
This diff is collapsed.
Click to expand it.
delay/dummynet_mods/ip_dummynet.h
deleted
100644 → 0
View file @
9f194304
/*
* Copyright (c) 1998-2000 Luigi Rizzo, Universita` di Pisa
* Portions Copyright (c) 2000 Akamba Corp.
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _IP_DUMMYNET_H
#define _IP_DUMMYNET_H
/*
* Definition of dummynet data structures.
* We first start with the heap which is used by the scheduler.
*
* Each list contains a set of parameters identifying the pipe, and
* a set of packets queued on the pipe itself.
*
* I could have used queue macros, but the management i have
* is pretty simple and this makes the code more portable.
*/
typedef
u_int32_t
dn_key
;
/* sorting key */
#define DN_KEY_LT(a,b) ((int)((a)-(b)) < 0)
#define DN_KEY_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define DN_KEY_GT(a,b) ((int)((a)-(b)) > 0)
#define DN_KEY_GEQ(a,b) ((int)((a)-(b)) >= 0)
struct
dn_heap_entry
{
dn_key
key
;
/* sorting key. Topmost element is smallest one */
void
*
object
;
/* object pointer */
}
;
struct
dn_heap
{
int
size
;
int
elements
;
struct
dn_heap_entry
*
p
;
/* really an array of "size" entries */
}
;
/*
* MT_DUMMYNET is a new (fake) mbuf type that is prepended to the
* packet when it comes out of a pipe. The definition
* ought to go in /sys/sys/mbuf.h but here it is less intrusive.
*/
#define MT_DUMMYNET MT_CONTROL
/*
* struct dn_pkt identifies a packet in the dummynet queue. The
* first part is really an m_hdr for implementation purposes, and some
* fields are saved there. When passing the packet back to the ip_input/
* ip_output(), the struct is prepended to the mbuf chain with type
* MT_DUMMYNET, and contains the pointer to the matching rule.
*/
struct
dn_pkt
{
struct
m_hdr
hdr
;
#define dn_next hdr.mh_nextpkt
/* next element in queue */
#define DN_NEXT(x) (struct dn_pkt *)(x)->dn_next
#define dn_m hdr.mh_next
/* packet to be forwarded */
/* #define dn_dst hdr.mh_len -* dst, for ip_output */
#define dn_dir hdr.mh_flags
/* action when pkt extracted from a queue */
#define DN_TO_IP_OUT 1
#define DN_TO_IP_IN 2
#define DN_TO_BDG_FWD 3
dn_key
output_time
;
/* when the pkt is due for delivery */
struct
ifnet
*
ifp
;
/* interface, for ip_output */
struct
sockaddr_in
*
dn_dst
;
struct
route
ro
;
/* route, for ip_output. MUST COPY */
int
flags
;
/* flags, for ip_output (IPv6 ?) */
};
struct
dn_queue
{
struct
dn_pkt
*
head
,
*
tail
;
}
;
/*
* We use per flow queues. Hashing is used to select the right slot,
* then we scan the list to match the flow-id.
* The pipe is shared as it is only a delay line and thus one is enough.
*/
struct
dn_flow_queue
{
struct
dn_flow_queue
*
next
;
struct
ipfw_flow_id
id
;
struct
dn_pipe
*
p
;
/* parent pipe */
struct
dn_queue
r
;
long
numbytes
;
u_int
len
;
u_int
len_bytes
;
u_int64_t
tot_pkts
;
/* statistics counters */
u_int64_t
tot_bytes
;
u_int32_t
drops
;
int
hash_slot
;
/* debugging/diagnostic */
}
;
/* distribution types */
#define DN_DIST_CONST_TIME 0x01
#define DN_DIST_CONST_RATE 0x02
#define DN_DIST_UNIFORM 0x04
#define DN_DIST_POISSON 0x08
#define DN_DIST_TABLE_RANDOM 0x10
#define DN_DIST_TABLE_DETERM 0x20
#define DN_TABLE_DIST \
(DN_DIST_TABLE_RANDOM|DN_DIST_TABLE_DETERM|DN_DIST_POISSON)
#define DN_CONST_DIST (DN_DIST_CONST_RATE|DN_DIST_CONST_TIME)
/* delay, bandwidth, loss parameters for dn_pipe */
struct
dn_delay
{
int
delay
;
/* really, ticks */
int
dist
;
/* distribution type */
int
mean
;
int
stddev
;
int
*
table
;
/* table of possible values */
int
entries
;
/* entries in table */
int
tablepos
;
/* current pos in table for deterministic */
};
struct
dn_bw
{
int
bandwidth
;
/* bits/sec */
int
dist
;
/* distribution type */
int
mean
;
int
stddev
;
int
quantum
;
/* how frequently to recalculate bw */
int
quantum_expire
;
/* its expiration date */
int
*
table
;
/* table of possible values */
int
entries
;
/* entries in table */
int
tablepos
;
/* current pos in table for deterministic */
};
struct
dn_loss
{
int
plr
;
/* pkt loss rate (2^31-1 means 100%) */
int
dist
;
/* distribution type */
int
nextdroptime
;
/* time to drop pkt at head of queue */
int
mean
;
int
stddev
;
int
quantum
;
/* how frequently to recalc loss rate */
int
quantum_expire
;
/* its expiration date */
int
*
table
;
/* table of possible values */
int
entries
;
/* entries in table */
int
tablepos
;
/* current pos in table for deterministic */
};
/*
* Pipe descriptor. Contains global parameters, delay-line queue,