*
* This software is provided ``AS IS'' without any warranties of any kind.
*
- * $FreeBSD: user/luigi/ipfw3-head/sbin/ipfw/dummynet.c 203321 2010-01-31 21:39:25Z luigi $
+ * $FreeBSD: head/sbin/ipfw/dummynet.c 206843 2010-04-19 15:11:45Z luigi $
*
* dummynet support
*/
return ret;
}
+/* handle variable lenght structures moving back the pointer and fixing lenght */
+static void *
+o_compact(struct dn_id **o, int len, int real_length, int type)
+{
+ struct dn_id *ret = *o;
+
+ ret = O_NEXT(*o, -len);
+ oid_fill(ret, real_length, type, 0);
+ *o = O_NEXT(ret, real_length);
+ return ret;
+}
+
#if 0
static int
sort_q(void *arg, const void *pa, const void *pb)
id->proto,
id->src_ip, id->src_port,
id->dst_ip, id->dst_port);
-
- printf("BKT Prot ___Source IP/port____ "
- "____Dest. IP/port____ "
- "Tot_pkt/bytes Pkt/Byte Drp\n");
} else {
char buf[255];
printf("\n mask: %sproto: 0x%02x, flow_id: 0x%08x, ",
printf("%s/0x%04x -> ", buf, id->src_port);
inet_ntop(AF_INET6, &(id->dst_ip6), buf, sizeof(buf));
printf("%s/0x%04x\n", buf, id->dst_port);
+ }
+}
+static void
+print_header(struct ipfw_flow_id *id)
+{
+ if (!IS_IP6_FLOW_ID(id))
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ else
printf("BKT ___Prot___ _flow-id_ "
"______________Source IPv6/port_______________ "
"_______________Dest. IPv6/port_______________ "
"Tot_pkt/bytes Pkt/Byte Drp\n");
- }
}
static void
-list_flow(struct dn_flow *ni)
+list_flow(struct dn_flow *ni, int *print)
{
char buff[255];
struct protoent *pe = NULL;
struct in_addr ina;
struct ipfw_flow_id *id = &ni->fid;
+ if (*print) {
+ print_header(&ni->fid);
+ *print = 0;
+ }
pe = getprotobynumber(id->proto);
/* XXX: Should check for IPv4 flows */
printf("%3u%c", (ni->oid.id) & 0xff,
inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
id->dst_port);
}
-
- /* Tcc relies on msvcrt.dll for printf, and
- * it does not support ANSI %llu syntax
- */
-#ifndef TCC
- printf("%4llu %8llu %2u %4u %3u\n",
- align_uint64(&ni->tot_pkts),
- align_uint64(&ni->tot_bytes),
+ pr_u64(&ni->tot_pkts, 4);
+ pr_u64(&ni->tot_bytes, 8);
+ printf("%2u %4u %3u\n",
ni->length, ni->len_bytes, ni->drops);
-#else
- /* XXX This should be printed correctly, but for some
- * weird reason, it is not. Making a printf for each
- * value is a workaround, until we don't undestand what's wrong
- */
- /*printf("%4I64u %8I64u %2u %4u %3u\n",
- align_uint64(&ni->tot_pkts),
- align_uint64(&ni->tot_bytes),
- ni->length, ni->len_bytes, ni->drops);*/
-
- printf("%4I64u ",align_uint64(&ni->tot_pkts));
- printf("%8I64u ",align_uint64(&ni->tot_bytes));
- printf("%2u ",ni->length);
- printf("%4u ",ni->len_bytes);
- printf("%3u\n",ni->drops);
-#endif
}
static void
list_pipes(struct dn_id *oid, struct dn_id *end)
{
char buf[160]; /* pending buffer */
+ int toPrint = 1; /* print header */
+
buf[0] = '\0';
-
for (; oid != end; oid = O_NEXT(oid, oid->len)) {
if (oid->len < sizeof(*oid))
errx(1, "invalid oid len %d\n", oid->len);
s->sched_nr,
s->name, s->flags, s->buckets, s->oid.id);
if (s->flags & DN_HAVE_MASK)
- print_mask(&s->sched_mask);
+ print_mask(&s->sched_mask);
}
break;
case DN_FLOW:
- list_flow((struct dn_flow *)oid);
+ list_flow((struct dn_flow *)oid, &toPrint);
break;
case DN_LINK: {
print_extra_delay_parms((struct dn_profile *)oid);
}
flush_buf(buf); // XXX does it really go here ?
- }
+ }
}
/*
#define ED_EFMT(s) EX_DATAERR,"error in %s at line %d: "#s,filename,lineno
+/*
+ * Interpolate a set of proability-value tuples.
+ *
+ * This function takes as input a tuple of values <prob, value>
+ * and samples the interpolated curve described from the tuples.
+ *
+ * The user defined points are stored in the ponts structure.
+ * The number of points is stored in points_no.
+ * The user defined sampling value is stored in samples_no.
+ * The resulting samples are in the "samples" pointer.
+ *
+ * We assume that The last point for the '1' value of the
+ * probability should be defined. (XXX add checks for this)
+ *
+ * The input data are points and points_no.
+ * The output data are s (the array of s_no samples)
+ * and s_no (the number of samples)
+ *
+ */
+static void
+interpolate_samples(struct point *p, int points_no,
+ int *samples, int samples_no, const char *filename)
+{
+ double dy; /* delta on the y axis */
+ double y; /* current value of y */
+ double x; /* current value of x */
+ double m; /* the y slope */
+ int i; /* samples index */
+ int curr; /* points current index */
+
+ /* make sure that there are enough points. */
+ /* XXX Duplicated should be removed */
+ if (points_no < 3)
+ errx(EX_DATAERR, "%s too few samples, need at least %d",
+ filename, 3);
+
+ qsort(p, points_no, sizeof(struct point), compare_points);
+
+ dy = 1.0/samples_no;
+ y = 0;
+
+ for (i=0, curr = 0; i < samples_no; i++, y+=dy) {
+ /* This statment move the curr pointer to the next point
+ * skipping the points with the same x value. We are
+ * guaranteed to exit from the loop because the
+ * last possible value of y is stricly less than 1
+ * and the last possible value of the y points is 1 */
+ while ( y >= p[curr+1].prob ) curr++;
+
+ /* compute the slope of the curve */
+ m = (p[curr+1].delay - p[curr].delay) / (p[curr+1].prob - p[curr].prob);
+ /* compute the x value starting from the current point */
+ x = p[curr].delay + (y - p[curr].prob) * m;
+ samples[i] = x;
+ }
+
+ /* add the last sample */
+ samples[i] = p[curr+1].delay;
+}
+
+/*
+ * p is the link (old pipe)
+ * pf is the profile
+ */
static void
load_extra_delays(const char *filename, struct dn_profile *p,
struct dn_link *link)
char line[ED_MAX_LINE_LEN];
FILE *f;
int lineno = 0;
- int i;
int samples = -1;
double loss = -1.0;
p->link_nr = link->link_nr;
profile_name[0] = '\0';
+
f = fopen(filename, "r");
if (f == NULL)
err(EX_UNAVAILABLE, "fopen: %s", filename);
else
arg = s;
}
- if (name == NULL) /* empty line */
+
+ if ((name == NULL) || (*name == '#')) /* empty line */
continue;
- if (arg == NULL)
- errx(ED_EFMT("missing arg for %s"), name);
if (!strcasecmp(name, ED_TOK_SAMPLES)) {
if (samples > 0)
if (atoi(arg) <=0)
errx(ED_EFMT("invalid number of samples"));
samples = atoi(arg);
- if (samples>ED_MAX_SAMPLES_NO)
+ if (samples>=ED_MAX_SAMPLES_NO-1)
errx(ED_EFMT("too many samples, maximum is %d"),
- ED_MAX_SAMPLES_NO);
+ ED_MAX_SAMPLES_NO-1);
do_points = 0;
} else if (!strcasecmp(name, ED_TOK_BW)) {
char buf[IFNAMSIZ];
read_bandwidth(arg, &link->bandwidth, buf, sizeof(buf));
+ p->bandwidth = link->bandwidth;
} else if (!strcasecmp(name, ED_TOK_LOSS)) {
if (loss != -1.0)
errx(ED_EFMT("duplicated token: %s"), name);
loss = 1;
}
- /* make sure that there are enough points. */
- if (points_no < ED_MIN_SAMPLES_NO)
- errx(ED_EFMT("too few samples, need at least %d"),
- ED_MIN_SAMPLES_NO);
-
- qsort(points, points_no, sizeof(struct point), compare_points);
-
- /* interpolation */
- for (i = 0; i<points_no-1; ++i) {
- double y1 = points[i].prob * samples;
- double x1 = points[i].delay;
- double y2 = points[i+1].prob * samples;
- double x2 = points[i+1].delay;
+ interpolate_samples(points, points_no, p->samples, samples, filename);
- int ix = y1;
- int stop = y2;
-
- if (x1 == x2) {
- for (; ix<stop; ++ix)
- p->samples[ix] = x1;
- } else {
- double m = (y2-y1)/(x2-x1);
- double c = y1 - m*x1;
- for (; ix<stop ; ++ix)
- p->samples[ix] = (ix - c)/m;
- }
- }
- p->samples_no = samples;
+ p->samples_no = samples++;
p->loss_level = loss * samples;
strncpy(p->name, profile_name, sizeof(p->name));
}
struct ipfw_flow_id *mask = NULL;
int lmax;
uint32_t _foo = 0, *flags = &_foo , *buckets = &_foo;
+ size_t max_pf_size = sizeof(struct dn_profile) + ED_MAX_SAMPLES_NO * sizeof(int);
/*
* allocate space for 1 header,
*/
lmax = sizeof(struct dn_id); /* command header */
lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
- sizeof(struct dn_fs) + sizeof(struct dn_profile);
+ sizeof(struct dn_fs);
+ lmax += max_pf_size;
av++; ac--;
/* Pipe number */
break;
case TOK_PROFILE:
+ {
+ size_t real_length;
+
NEED((!pf), "profile already set");
NEED(p, "profile");
- {
NEED1("extra delay needs the file name\n");
- pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
+
+ /* load the profile structure using the DN_API */
+ pf = o_next(&buf, max_pf_size, DN_PROFILE);
load_extra_delays(av[0], pf, p); //XXX can't fail?
+
+ /* compact the dn_id structure */
+ real_length = sizeof(struct dn_profile) +
+ pf->samples_no * sizeof(int);
+ o_compact(&buf, max_pf_size, real_length, DN_PROFILE);
--ac; ++av;
}
break;
}
if (fs) {
/* XXX accept a 0 scheduler to keep the default */
- if (fs->flags & DN_QSIZE_BYTES) {
- size_t len;
+ if (fs->flags & DN_QSIZE_BYTES) {
+ size_t len;
long limit;
len = sizeof(limit);
} else {
ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
if (ret != 0 || oid->id <= sizeof(*oid))
- goto done;
+ goto done;
buflen = oid->id + max_size;
oid->len = sizeof(*oid); /* restore */
}