summaryrefslogtreecommitdiffstats
path: root/sys/netpfil
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2016-06-03 00:48:50 +0000
committertruckman <truckman@FreeBSD.org>2016-06-03 00:48:50 +0000
commit153cea5447c95ad5ec44fdf6519993d087a86a85 (patch)
tree775b054a22542e60ddecc4e530894814f626bada /sys/netpfil
parent6dceb8351c1d33f3e25849889fa01c46f447974e (diff)
downloadFreeBSD-src-153cea5447c95ad5ec44fdf6519993d087a86a85.zip
FreeBSD-src-153cea5447c95ad5ec44fdf6519993d087a86a85.tar.gz
MFC r266941, r266955
Needed for anticipated dummynet AQM MFC next week. r266941 | hiren | 2014-06-01 00:28:24 -0700 (Sun, 01 Jun 2014) | 9 lines ECN marking implenetation for dummynet. Changes include both DCTCP and RFC 3168 ECN marking methodology. DCTCP draft: http://tools.ietf.org/html/draft-bensley-tcpm-dctcp-00 Submitted by: Midori Kato (aoimidori27@gmail.com) Worked with: Lars Eggert (lars@netapp.com) Reviewed by: luigi, hiren r266955 | hiren | 2014-06-01 13:19:17 -0700 (Sun, 01 Jun 2014) | 5 lines DNOLD_IS_ECN introduced by r266941 is not required. DNOLD_* flags are for compat with old binaries. Suggested by: luigi Discussed with: hiren Relnotes: yes
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/ipfw/ip_dn_io.c78
-rw-r--r--sys/netpfil/ipfw/ip_dummynet.c5
2 files changed, 78 insertions, 5 deletions
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index fb75198..1930733 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -337,6 +337,8 @@ red_drops (struct dn_queue *q, int len)
return (0); /* accept packet */
}
if (q->avg >= fs->max_th) { /* average queue >= max threshold */
+ if (fs->fs.flags & DN_IS_ECN)
+ return (1);
if (fs->fs.flags & DN_IS_GENTLE_RED) {
/*
* According to Gentle-RED, if avg is greater than
@@ -352,6 +354,8 @@ red_drops (struct dn_queue *q, int len)
return (1);
}
} else if (q->avg > fs->min_th) {
+ if (fs->fs.flags & DN_IS_ECN)
+ return (1);
/*
* We compute p_b using the linear dropping function
* p_b = c_1 * avg - c_2
@@ -384,6 +388,70 @@ red_drops (struct dn_queue *q, int len)
}
/*
+ * ECN/ECT Processing (partially adopted from altq)
+ */
+static int
+ecn_mark(struct mbuf* m)
+{
+ struct ip *ip;
+ ip = mtod(m, struct ip *);
+
+ switch (ip->ip_v) {
+ case IPVERSION:
+ {
+ u_int8_t otos;
+ int sum;
+
+ if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
+ return (0); /* not-ECT */
+ if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
+ return (1); /* already marked */
+
+ /*
+ * ecn-capable but not marked,
+ * mark CE and update checksum
+ */
+ otos = ip->ip_tos;
+ ip->ip_tos |= IPTOS_ECN_CE;
+ /*
+ * update checksum (from RFC1624)
+ * HC' = ~(~HC + ~m + m')
+ */
+ sum = ~ntohs(ip->ip_sum) & 0xffff;
+ sum += (~otos & 0xffff) + ip->ip_tos;
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16); /* add carry */
+ ip->ip_sum = htons(~sum & 0xffff);
+ return (1);
+ }
+#ifdef INET6
+ case (IPV6_VERSION >> 4):
+ {
+ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ u_int32_t flowlabel;
+
+ flowlabel = ntohl(ip6->ip6_flow);
+ if ((flowlabel >> 28) != 6)
+ return (0); /* version mismatch! */
+ if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
+ (IPTOS_ECN_NOTECT << 20))
+ return (0); /* not-ECT */
+ if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
+ (IPTOS_ECN_CE << 20))
+ return (1); /* already marked */
+ /*
+ * ecn-capable but not marked, mark CE
+ */
+ flowlabel |= (IPTOS_ECN_CE << 20);
+ ip6->ip6_flow = htonl(flowlabel);
+ return (1);
+ }
+#endif
+ }
+ return (0);
+}
+
+/*
* Enqueue a packet in q, subject to space and queue management policy
* (whose parameters are in q->fs).
* Update stats for the queue and the scheduler.
@@ -414,8 +482,10 @@ dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
goto drop;
if (f->plr && random() < f->plr)
goto drop;
- if (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len))
- goto drop;
+ if (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len)) {
+ if (!(f->flags & DN_IS_ECN) || !ecn_mark(m))
+ goto drop;
+ }
if (f->flags & DN_QSIZE_BYTES) {
if (q->ni.len_bytes > f->qsize)
goto drop;
@@ -427,14 +497,14 @@ dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
q->ni.len_bytes += len;
ni->length++;
ni->len_bytes += len;
- return 0;
+ return (0);
drop:
io_pkt_drop++;
q->ni.drops++;
ni->drops++;
FREE_PKT(m);
- return 1;
+ return (1);
}
/*
diff --git a/sys/netpfil/ipfw/ip_dummynet.c b/sys/netpfil/ipfw/ip_dummynet.c
index 3a12120..58b4e61 100644
--- a/sys/netpfil/ipfw/ip_dummynet.c
+++ b/sys/netpfil/ipfw/ip_dummynet.c
@@ -1073,7 +1073,10 @@ config_red(struct dn_fsk *fs)
fs->min_th = SCALE(fs->fs.min_th);
fs->max_th = SCALE(fs->fs.max_th);
- fs->c_1 = fs->max_p / (fs->fs.max_th - fs->fs.min_th);
+ if (fs->fs.max_th == fs->fs.min_th)
+ fs->c_1 = fs->max_p;
+ else
+ fs->c_1 = SCALE((int64_t)(fs->max_p)) / (fs->fs.max_th - fs->fs.min_th);
fs->c_2 = SCALE_MUL(fs->c_1, SCALE(fs->fs.min_th));
if (fs->fs.flags & DN_IS_GENTLE_RED) {
OpenPOWER on IntegriCloud