Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F138080076
D42980.id131513.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D42980.id131513.diff
View Options
diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c
--- a/sbin/ipfw/dummynet.c
+++ b/sbin/ipfw/dummynet.c
@@ -471,7 +471,7 @@
{
int l;
char qs[30];
- char plr[30];
+ char plr[40];
char red[200]; /* Display RED parameters */
l = fs->qsize;
@@ -482,9 +482,17 @@
sprintf(qs, "%d B", l);
} else
sprintf(qs, "%3d sl.", l);
- if (fs->plr)
- sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
- else
+ if (fs->plr[0] || fs->plr[1]) {
+ if (fs->plr[1] == 0)
+ sprintf(plr, "plr %f",
+ 1.0 * fs->plr[0] / (double)(0x7fffffff));
+ else
+ sprintf(plr, "plr %f,%f,%f,%f",
+ 1.0 * fs->plr[0] / (double)(0x7fffffff),
+ 1.0 * fs->plr[1] / (double)(0x7fffffff),
+ 1.0 * fs->plr[2] / (double)(0x7fffffff),
+ 1.0 * fs->plr[3] / (double)(0x7fffffff));
+ } else
plr[0] = '\0';
if (fs->flags & DN_IS_RED) { /* RED parameters */
@@ -1408,13 +1416,27 @@
case TOK_PLR:
NEED(fs, "plr is only for pipes");
- NEED1("plr needs argument 0..1\n");
- d = strtod(av[0], NULL);
- if (d > 1)
- d = 1;
- else if (d < 0)
- d = 0;
- fs->plr = (int)(d*0x7fffffff);
+ NEED1("plr needs one or four arguments 0..1\n");
+ if ((end = strsep(&av[0], ","))) {
+ d = strtod(end, NULL);
+ d = (d < 0) ? 0 : (d <= 1) ? d : 1;
+ fs->plr[0] = (int)(d*0x7fffffff);
+ }
+ if ((end = strsep(&av[0], ","))) {
+ d = strtod(end, NULL);
+ d = (d < 0) ? 0 : (d <= 1) ? d : 1;
+ fs->plr[1] = (int)(d*0x7fffffff);
+ }
+ if ((end = strsep(&av[0], ","))) {
+ d = strtod(end, NULL);
+ d = (d < 0) ? 0 : (d <= 1) ? d : 1;
+ fs->plr[2] = (int)(d*0x7fffffff);
+ }
+ if ((end = strsep(&av[0], ","))) {
+ d = strtod(end, NULL);
+ d = (d < 0) ? 0 : (d <= 1) ? d : 1;
+ fs->plr[3] = (int)(d*0x7fffffff);
+ }
ac--; av++;
break;
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,5 +1,5 @@
.\"
-.Dd September 28, 2023
+.Dd December 17, 2023
.Dt IPFW 8
.Os
.Sh NAME
@@ -3039,12 +3039,47 @@
loss or congestion at a remote router.
.Pp
.It Cm plr Ar packet-loss-rate
+.It Cm plr Ar K,p,H,r
Packet loss rate.
Argument
.Ar packet-loss-rate
is a floating-point number between 0 and 1, with 0 meaning no
loss, 1 meaning 100% loss.
-The loss rate is internally represented on 31 bits.
+.Pp
+When invoked with four arguments, the simple Gilbert-Elliott
+channel model with two states (Good and Bad) is used.
+.Bd -literal -offset indent
+ r
+ .----------------.
+ v |
+ .------------. .------------.
+ | G | | B |
+ | drop (K) | | drop (H) |
+ '------------' '------------'
+ | ^
+ '----------------'
+ p
+
+.Ed
+This has the associated probabilities
+.Po Ar K
+and
+.Ar H Pc
+for the loss probability. This is different from the literature,
+where this model is described with probabilities of successful
+transmission k and h. However, converting from literature is
+easy:
+.Pp
+K = 1 - k ; H = 1 - h
+.Pp
+This is to retain consistency within the interface and allow the
+quick re-use of loss probability when giving only a single argument.
+In addition the state change probabilities
+.Po Ar p
+and
+.Ar r Pc
+are given.
+All of the above probabilities are internally represented on 31 bits.
.Pp
.It Cm queue Brq Ar slots | size Ns Cm Kbytes
Queue size, in
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -145,7 +145,7 @@
uint32_t fs_nr; /* the flowset number */
uint32_t flags; /* userland flags */
int qsize; /* queue size in slots or bytes */
- int32_t plr; /* PLR, pkt loss rate (2^31-1 means 100%) */
+ int32_t pl_state; /* packet loss state */
uint32_t buckets; /* buckets used for the queue hash table */
struct ipfw_flow_id flow_mask;
@@ -168,6 +168,7 @@
int min_th ; /* minimum threshold for queue (scaled) */
int max_p ; /* maximum value for p_b (scaled) */
+ int32_t plr[4]; /* PLR, pkt loss rate (2^31-1 means 100%) */
};
/*
diff --git a/sys/netpfil/ipfw/ip_dn_glue.c b/sys/netpfil/ipfw/ip_dn_glue.c
--- a/sys/netpfil/ipfw/ip_dn_glue.c
+++ b/sys/netpfil/ipfw/ip_dn_glue.c
@@ -77,35 +77,35 @@
/* Common to 7.2 and 8 */
struct dn_flow_set {
- SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
+ SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
- u_short fs_nr ; /* flow_set number */
+ u_short fs_nr ; /* flow_set number */
u_short flags_fs;
#define DNOLD_HAVE_FLOW_MASK 0x0001
-#define DNOLD_IS_RED 0x0002
+#define DNOLD_IS_RED 0x0002
#define DNOLD_IS_GENTLE_RED 0x0004
-#define DNOLD_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */
-#define DNOLD_NOERROR 0x0010 /* do not report ENOBUFS on drops */
-#define DNOLD_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */
-#define DNOLD_IS_PIPE 0x4000
-#define DNOLD_IS_QUEUE 0x8000
+#define DNOLD_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */
+#define DNOLD_NOERROR 0x0010 /* do not report ENOBUFS on drops */
+#define DNOLD_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */
+#define DNOLD_IS_PIPE 0x4000
+#define DNOLD_IS_QUEUE 0x8000
- struct dn_pipe7 *pipe ; /* pointer to parent pipe */
- u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */
+ struct dn_pipe7 *pipe ; /* pointer to parent pipe */
+ u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */
- int weight ; /* WFQ queue weight */
- int qsize ; /* queue size in slots or bytes */
- int plr ; /* pkt loss rate (2^31-1 means 100%) */
+ int weight ; /* WFQ queue weight */
+ int qsize ; /* queue size in slots or bytes */
+ int plr[4] ; /* pkt loss rate (2^31-1 means 100%) */
struct ipfw_flow_id flow_mask ;
/* hash table of queues onto this flow_set */
- int rq_size ; /* number of slots */
- int rq_elements ; /* active elements */
- struct dn_flow_queue7 **rq; /* array of rq_size entries */
+ int rq_size ; /* number of slots */
+ int rq_elements ; /* active elements */
+ struct dn_flow_queue7 **rq ; /* array of rq_size entries */
- u_int32_t last_expired ; /* do not expire too frequently */
- int backlogged ; /* #active queues for this flowset */
+ u_int32_t last_expired ; /* do not expire too frequently */
+ int backlogged ; /* #active queues for this flowset */
/* RED parameters */
#define SCALE_RED 16
@@ -420,7 +420,10 @@
fs->flow_mask = f->flow_mask;
fs->buckets = f->rq_size;
fs->qsize = f->qsize;
- fs->plr = f->plr;
+ fs->plr[0] = f->plr[0];
+ fs->plr[1] = f->plr[1];
+ fs->plr[2] = f->plr[2];
+ fs->plr[3] = f->plr[3];
fs->par[0] = f->weight;
fs->flags = convertflags2new(f->flags_fs);
if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {
@@ -645,7 +648,10 @@
fs->parent_nr = l->link_nr - DN_MAX_ID;
fs->qsize = f->fs.qsize;
- fs->plr = f->fs.plr;
+ fs->plr[0] = f->fs.plr[0];
+ fs->plr[1] = f->fs.plr[1];
+ fs->plr[2] = f->fs.plr[2];
+ fs->plr[3] = f->fs.plr[3];
fs->w_q = f->fs.w_q;
fs->max_th = f->max_th;
fs->min_th = f->min_th;
@@ -698,7 +704,10 @@
fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
fs->fs_nr = f->fs.fs_nr;
fs->qsize = f->fs.qsize;
- fs->plr = f->fs.plr;
+ fs->plr[0] = f->fs.plr[0];
+ fs->plr[1] = f->fs.plr[1];
+ fs->plr[2] = f->fs.plr[2];
+ fs->plr[3] = f->fs.plr[3];
fs->w_q = f->fs.w_q;
fs->max_th = f->max_th;
fs->min_th = f->min_th;
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -497,8 +497,28 @@
ni->tot_pkts++;
if (drop)
goto drop;
- if (f->plr && random() < f->plr)
- goto drop;
+ if (f->plr[0] || f->plr[1]) {
+ if (__predict_true(f->plr[1] == 0)) {
+ if (random() < f->plr[0])
+ goto drop;
+ } else {
+ switch (f->pl_state) {
+ case PLR_STATE_B:
+ if (random() < f->plr[3])
+ f->pl_state = PLR_STATE_G;
+ if (random() < f->plr[2])
+ goto drop;
+ break;
+ case PLR_STATE_G: /* FALLTHROUGH */
+ default:
+ if (random() < f->plr[1])
+ f->pl_state = PLR_STATE_B;
+ if (random() < f->plr[0])
+ goto drop;
+ break;
+ }
+ }
+ }
if (m->m_pkthdr.rcvif != NULL)
m_rcvif_serialize(m);
#ifdef NEW_AQM
diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h
--- a/sys/netpfil/ipfw/ip_dn_private.h
+++ b/sys/netpfil/ipfw/ip_dn_private.h
@@ -392,6 +392,15 @@
PROTO_IFB = 0x0c, /* layer2 + ifbridge */
};
+/*
+ * States for the Packet Loss Rate Gilbert-Elliott
+ * channel model
+ */
+enum {
+ PLR_STATE_G = 0,
+ PLR_STATE_B,
+};
+
//extern struct dn_parms V_dn_cfg;
VNET_DECLARE(struct dn_parms, dn_cfg);
#define V_dn_cfg VNET(dn_cfg)
diff --git a/tests/sys/netpfil/common/dummynet.sh b/tests/sys/netpfil/common/dummynet.sh
--- a/tests/sys/netpfil/common/dummynet.sh
+++ b/tests/sys/netpfil/common/dummynet.sh
@@ -517,6 +517,102 @@
firewall_cleanup $1
}
+pls_basic_head()
+{
+ atf_set descr 'Basic dummynet packet loss rate test'
+ atf_set require.user root
+}
+
+pls_basic_body()
+{
+ fw=$1
+ firewall_init $fw
+ dummynet_init $fw
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail alcatraz ${epair}b
+
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
+
+ firewall_config alcatraz ${fw} \
+ "ipfw" \
+ "ipfw add 65432 ip from any to any" \
+ "pf" \
+ "pass on ${epair}b"
+
+ # Sanity check
+ atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2
+
+ jexec alcatraz dnctl pipe 1 config plr 0.1
+
+ firewall_config alcatraz ${fw} \
+ "ipfw" \
+ "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \
+ "pf" \
+ "pass on ${epair}b dnpipe 1"
+
+ # check if the expected number of pings
+ # are dropped (84 - 96 responses).
+ # repeat up to 6 times if the initial
+ # checks fail
+ atf_check -s exit:0 -o match:'100 packets transmitted, (8[4-9]|9[0-6]) packets received' -r 6:10 ping -i 0.010 -c 100 192.0.2.2
+}
+
+pls_basic_cleanup()
+{
+ firewall_cleanup $1
+}
+
+pls_gilbert_head()
+{
+ atf_set descr 'dummynet Gilbert-Elliott packet loss model test'
+ atf_set require.user root
+}
+
+pls_gilbert_body()
+{
+ fw=$1
+ firewall_init $fw
+ dummynet_init $fw
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail alcatraz ${epair}b
+
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
+
+ firewall_config alcatraz ${fw} \
+ "ipfw" \
+ "ipfw add 65432 ip from any to any" \
+ "pf" \
+ "pass on ${epair}b"
+
+ # Sanity check
+ atf_check -s exit:0 -o match:'100 packets transmitted, 100 packets received' ping -i .1 -c 100 192.0.2.2
+
+ jexec alcatraz dnctl pipe 1 config plr 0.01,0.1,0.8,0.2
+
+ firewall_config alcatraz ${fw} \
+ "ipfw" \
+ "ipfw add 1000 pipe 1 ip from 192.0.2.1 to 192.0.2.2" \
+ "pf" \
+ "pass on ${epair}b dnpipe 1"
+
+ # check if the expected number of pings
+ # are dropped (70 - 85 responses).
+ # repeat up to 6 times if the initial
+ # checks fail
+ atf_check -s exit:0 -o match:'100 packets transmitted, (7[0-9]|8[0-5]) packets received' -r 6:10 ping -i 0.010 -c 100 192.0.2.2
+}
+
+pls_gilbert_cleanup()
+{
+ firewall_cleanup $1
+}
+
+
+
setup_tests \
interface_removal \
ipfw \
@@ -539,4 +635,10 @@
ipfw \
pf \
nat \
+ pf \
+ pls_basic \
+ ipfw \
+ pf \
+ pls_gilbert \
+ ipfw \
pf
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 29, 5:39 PM (14 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26349145
Default Alt Text
D42980.id131513.diff (11 KB)
Attached To
Mode
D42980: dummynet: add simple gilbert-elliott channel model
Attached
Detach File
Event Timeline
Log In to Comment