diff options
author | melifaro <melifaro@FreeBSD.org> | 2013-03-20 10:35:33 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2013-03-20 10:35:33 +0000 |
commit | 31a6358fffd6950960c98280182bba118f5ac9f9 (patch) | |
tree | 44e82abbb64d1051fdaf7d30eff801b105e36c64 /sys/netpfil | |
parent | fde3650fd88d5b6ebbf80e8fdc864164130256ac (diff) | |
download | FreeBSD-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.c | 52 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_log.c | 6 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_sockopt.c | 5 |
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 |