summaryrefslogtreecommitdiffstats
path: root/sys/netpfil
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2013-03-20 10:35:33 +0000
committermelifaro <melifaro@FreeBSD.org>2013-03-20 10:35:33 +0000
commit31a6358fffd6950960c98280182bba118f5ac9f9 (patch)
tree44e82abbb64d1051fdaf7d30eff801b105e36c64 /sys/netpfil
parentfde3650fd88d5b6ebbf80e8fdc864164130256ac (diff)
downloadFreeBSD-src-31a6358fffd6950960c98280182bba118f5ac9f9.zip
FreeBSD-src-31a6358fffd6950960c98280182bba118f5ac9f9.tar.gz
Add ipfw support for setting/matching DiffServ codepoints (DSCP).
Setting DSCP support is done via O_SETDSCP which works for both IPv4 and IPv6 packets. Fast checksum recalculation (RFC 1624) is done for IPv4. Dscp can be specified by name (AFXY, CSX, BE, EF), by value (0..63) or via tablearg. Matching DSCP is done via another opcode (O_DSCP) which accepts several classes at once (af11,af22,be). Classes are stored in bitmask (2 u32 words). Many people made their variants of this patch, the ones I'm aware of are (in alphabetic order): Dmitrii Tejblum Marcelo Araujo Roman Bogorodskiy (novel) Sergey Matveichuk (sem) Sergey Ryabin PR: kern/102471, kern/121122 MFC after: 2 weeks
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c52
-rw-r--r--sys/netpfil/ipfw/ip_fw_log.c6
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c5
3 files changed, 59 insertions, 4 deletions
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 1c096d9..5e0675b 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -1624,6 +1624,32 @@ do { \
flags_match(cmd, ip->ip_tos));
break;
+ case O_DSCP:
+ {
+ uint32_t *p;
+ uint16_t x;
+
+ p = ((ipfw_insn_u32 *)cmd)->d;
+
+ if (is_ipv4)
+ x = ip->ip_tos >> 2;
+ else if (is_ipv6) {
+ uint8_t *v;
+ v = &((struct ip6_hdr *)ip)->ip6_vfc;
+ x = (*v & 0x0F) << 2;
+ v++;
+ x |= *v >> 6;
+ } else
+ break;
+
+ /* DSCP bitmask is stored as low_u32 high_u32 */
+ if (x > 32)
+ match = *(p + 1) & (1 << (x - 32));
+ else
+ match = *p & (1 << x);
+ }
+ break;
+
case O_TCPDATALEN:
if (proto == IPPROTO_TCP && offset == 0) {
struct tcphdr *tcp;
@@ -2353,6 +2379,32 @@ do { \
break;
}
+ case O_SETDSCP: {
+ uint16_t code;
+
+ code = IP_FW_ARG_TABLEARG(cmd->arg1) & 0x3F;
+ l = 0; /* exit inner loop */
+ if (is_ipv4) {
+ uint16_t a;
+
+ a = ip->ip_tos;
+ ip->ip_tos = (code << 2) | (ip->ip_tos & 0x03);
+ a += ntohs(ip->ip_sum) - ip->ip_tos;
+ ip->ip_sum = htons(a);
+ } else if (is_ipv6) {
+ uint8_t *v;
+
+ v = &((struct ip6_hdr *)ip)->ip6_vfc;
+ *v = (*v & 0xF0) | (code >> 2);
+ v++;
+ *v = (*v & 0x3F) | ((code & 0x03) << 6);
+ } else
+ break;
+
+ IPFW_INC_RULE_COUNTER(f, pktlen);
+ break;
+ }
+
case O_NAT:
if (!IPFW_NAT_LOADED) {
retval = IP_FW_DENY;
diff --git a/sys/netpfil/ipfw/ip_fw_log.c b/sys/netpfil/ipfw/ip_fw_log.c
index 48e6791..0f3ab9d 100644
--- a/sys/netpfil/ipfw/ip_fw_log.c
+++ b/sys/netpfil/ipfw/ip_fw_log.c
@@ -292,10 +292,8 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
altq->qid);
cmd += F_LEN(cmd);
}
- if (cmd->opcode == O_PROB)
- cmd += F_LEN(cmd);
-
- if (cmd->opcode == O_TAG)
+ if (cmd->opcode == O_PROB || cmd->opcode == O_TAG ||
+ cmd->opcode == O_SETDSCP)
cmd += F_LEN(cmd);
action = action2;
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 3363cf9..45da394 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -671,6 +671,10 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_IPID:
case O_IPTTL:
case O_IPLEN:
+ case O_DSCP:
+ if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
+ goto bad_size;
+ break;
case O_TCPDATALEN:
case O_TCPWIN:
case O_TAGGED:
@@ -738,6 +742,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_ACCEPT:
case O_DENY:
case O_REJECT:
+ case O_SETDSCP:
#ifdef INET6
case O_UNREACH6:
#endif
OpenPOWER on IntegriCloud