From novel@FreeBSD.org  Thu Aug 24 07:23:53 2006
Return-Path: <novel@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 5C43816A4DA
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 24 Aug 2006 07:23:53 +0000 (UTC)
	(envelope-from novel@FreeBSD.org)
Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 0B81F43D49
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 24 Aug 2006 07:23:53 +0000 (GMT)
	(envelope-from novel@FreeBSD.org)
Received: from freefall.freebsd.org (novel@localhost [127.0.0.1])
	by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k7O7Nq3k027224
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 24 Aug 2006 07:23:52 GMT
	(envelope-from novel@freefall.freebsd.org)
Received: (from novel@localhost)
	by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k7O7NqsF027223;
	Thu, 24 Aug 2006 07:23:52 GMT
	(envelope-from novel)
Message-Id: <200608240723.k7O7NqsF027223@freefall.freebsd.org>
Date: Thu, 24 Aug 2006 07:23:52 GMT
From: Roman Bogorodskiy <novel@FreeBSD.org>
Reply-To: Roman Bogorodskiy <novel@FreeBSD.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [ipfw] [patch] add tos and dscp support
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         102471
>Category:       kern
>Synopsis:       [ipfw] [patch] add tos and dscp support
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    melifaro
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Aug 24 07:30:24 GMT 2006
>Closed-Date:    Fri Feb 14 14:15:05 UTC 2014
>Last-Modified:  Fri Feb 14 14:15:05 UTC 2014
>Originator:     Roman Bogorodskiy
>Release:        FreeBSD 6.0-STABLE i386
>Organization:
>Environment:
System: FreeBSD freefall.freebsd.org 6.0-STABLE FreeBSD 6.0-STABLE #0: Sat Dec 10 03:18:20 UTC 2005 kensmith@freefall.freebsd.org:/usr/obj/usr/src/sys/FREEFALL i386


	
>Description:
	This patch adds two features:
	
	1. Allow to change tos and dscp field of IPv4 packets. It can be
	used in a such way:

	ipfw add 100 iptos lowdelay all from <the rest of the rule>
	ipfw add 110 dscp AF33 all from -//-

	That will change tos/dscp field.

	2. Allow to match IPv4 packets by dscp field:

	ipfw add 80 count tcp from any to any dscp AF33

	The patch was originally written by Sergey Ryabin for FreeBSD 5.x
	and I have rewrote it in various places. I tested it on 6-STABLE.

	References:
		http://www.cisco.com/warp/public/105/dscpvalues.html
		http://www.iana.org/assignments/ipv4-tos-byte
		http://www.iana.org/assignments/dscp-registry
		
>How-To-Repeat:
>Fix:

--- ipfw_tos_dscp_20060824_1.diff begins here ---
diff -ru src/sbin/ipfw/ipfw.8 /usr/src/sbin/ipfw/ipfw.8
--- src/sbin/ipfw/ipfw.8	Sat Jul 29 12:24:12 2006
+++ /usr/src/sbin/ipfw/ipfw.8	Thu Aug 24 10:42:19 2006
@@ -823,6 +823,14 @@
 and
 .Cm ngtee
 actions.
+.It Cm iptos Ar code
+Changes
+.Cm tos
+field of an IPv4 packet.
+.It Cm dscp Ar code
+Changes
+.Cm dscp
+field of an IPv4 packet.
 .El
 .Ss RULE BODY
 The body of a rule contains zero or more patterns (such as
@@ -1273,6 +1281,55 @@
 The absence of a particular type may be denoted
 with a
 .Ql \&! .
+.It Cm dscp Ar code
+Matches IPv4 packets whose
+.Cm dscp
+field contains
+.Ar code .
+The supported values are:
+.Pp
+.Cm CS0
+.Pq Dv 000000 ,
+.Cm CS1
+.Pq Dv 001000 ,
+.Cm CS2
+.Pq Dv 010000 ,
+.Cm CS3
+.Pq Dv 011000 ,
+.Cm CS4
+.Pq Dv 100000 ,
+.Cm CS5
+.Pq Dv 101000 ,
+.Cm CS6
+.Pq Dv 110000 ,
+.Cm CS7
+.Pq Dv 111000 ,
+.Cm AF11
+.Pq Dv 001010 ,
+.Cm AF12
+.Pq Dv 001100 ,
+.Cm AF13
+.Pq Dv 001110 ,
+.Cm AF21
+.Pq Dv 010010 ,
+.Cm AF22
+.Pq Dv 010100 ,
+.Cm AF23
+.Pq Dv 010110 ,
+.Cm AF31
+.Pq Dv 011010 ,
+.Cm AF32
+.Pq Dv 011100 ,
+.Cm AF33
+.Pq Dv 011110 ,
+.Cm AF41
+.Pq Dv 100010 ,
+.Cm AF42
+.Pq Dv 100100 ,
+.Cm AF43
+.Pq Dv 100110 ,
+.Cm EF
+.Pq Dv 101110 .
 .It Cm ipttl Ar ttl-list
 Matches IPv4 packets whose time to live is included in
 .Ar ttl-list ,
diff -ru src/sbin/ipfw/ipfw2.c /usr/src/sbin/ipfw/ipfw2.c
--- src/sbin/ipfw/ipfw2.c	Mon Aug  7 23:32:57 2006
+++ /usr/src/sbin/ipfw/ipfw2.c	Thu Aug 24 10:14:10 2006
@@ -133,6 +133,33 @@
 	int x;
 };
 
+static struct _s_x f_ipdscp[] = {
+	/* DSCP */
+	{ "AF11", 40 },
+	{ "AF12", 48 },
+	{ "AF13", 56 },
+        { "AF21", 72 },
+        { "AF22", 80 },
+	{ "AF23", 88 },
+	{ "AF31", 104 },
+	{ "AF32", 112 },
+	{ "AF33", 120 },
+	{ "AF41", 136 },
+	{ "AF42", 144 }, 
+	{ "AF43", 152 },
+	{ "EF",   184 },
+	/* COS flags */
+        { "CS0", 0 },
+	{ "CS1", 32 },  
+	{ "CS2", 64 },
+	{ "CS3", 96 },
+	{ "CS4", 128 },
+	{ "CS5", 160 },
+	{ "CS6", 192 },
+	{ "CS7", 224 },
+	{ NULL, 0 }
+};
+
 static struct _s_x f_tcpflags[] = {
 	{ "syn", TH_SYN },
 	{ "fin", TH_FIN },
@@ -274,6 +301,7 @@
 	TOK_IPID,
 	TOK_IPPRECEDENCE,
 	TOK_IPTOS,
+	TOK_IPDSCP,
 	TOK_IPTTL,
 	TOK_IPVER,
 	TOK_ESTAB,
@@ -309,6 +337,8 @@
 	TOK_DROPTAIL,
 	TOK_PROTO,
 	TOK_WEIGHT,
+	TOK_SETIPTOS,
+	TOK_SETDSCP,
 
 	TOK_IPV6,
 	TOK_FLOWID,
@@ -374,6 +404,8 @@
 	{ "unreach6",		TOK_UNREACH6 },
 	{ "unreach",		TOK_UNREACH },
 	{ "check-state",	TOK_CHECKSTATE },
+	{ "iptos",		TOK_SETIPTOS },
+	{ "dscp",               TOK_SETDSCP },
 	{ "//",			TOK_COMMENT },
 	{ NULL, 0 }	/* terminator */
 };
@@ -411,6 +443,7 @@
 	{ "ipid",		TOK_IPID },
 	{ "ipprecedence",	TOK_IPPRECEDENCE },
 	{ "iptos",		TOK_IPTOS },
+	{ "dscp",		TOK_IPDSCP },
 	{ "ipttl",		TOK_IPTTL },
 	{ "ipversion",		TOK_IPVER },
 	{ "ipver",		TOK_IPVER },
@@ -1550,6 +1583,12 @@
 				printf(",%d", s->sa.sin_port);
 		    }
 			break;
+		case O_SET_IPTOS:
+			printf("iptos %s", match_value(f_iptos, cmd->arg1));
+			break;
+	        case O_SET_DSCP:
+			printf("dscp %s", match_value(f_ipdscp, cmd->arg1));
+			break;
 
 		case O_LOG: /* O_LOG is printed last */
 			logptr = (ipfw_insn_log *)cmd;
@@ -1855,6 +1894,10 @@
 				print_flags("iptos", cmd, f_iptos);
 				break;
 
+			case O_IPDSCP:
+				printf(" dscp %s", match_value(f_ipdscp, cmd->arg1));
+				break;
+
 			case O_ICMPTYPE:
 				print_icmptypes((ipfw_insn_u32 *)cmd);
 				break;
@@ -2631,7 +2674,7 @@
 "RULE-BODY:	check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
 "ACTION:	check-state | allow | count | deny | unreach{,6} CODE |\n"
 "               skipto N | {divert|tee} PORT | forward ADDR |\n"
-"               pipe N | queue N\n"
+"               pipe N | queue N | iptos CODE | dscp CODE\n"
 "PARAMS: 	[log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
 "ADDR:		[ MAC dst src ether_type ] \n"
 "		[ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
@@ -2642,8 +2685,8 @@
 "IPLIST:	{ ip | ip/bits | ip:mask }[,IPLIST]\n"
 "OPTION_LIST:	OPTION [OPTION_LIST]\n"
 "OPTION:	bridged | diverted | diverted-loopback | diverted-output |\n"
-"	{dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
-"	{dst-port|src-port} LIST |\n"
+"	dscp CODE | {dst-ip|src-ip} IPADDR |\n"
+"	{dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR | {dst-port|src-port} LIST |\n"
 "	estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
 "	iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
 "	ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
@@ -3960,6 +4003,18 @@
 	case TOK_COUNT:
 		action->opcode = O_COUNT;
 		break;
+		
+	case TOK_SETIPTOS:
+		NEED1("need iptos arg\n");
+		fill_flags(action, O_SET_IPTOS, f_iptos, *av);
+		ac--; av++;
+		break;
+	
+	case TOK_SETDSCP:
+		NEED1("need dscp arg\n");
+		fill_flags(action, O_SET_DSCP, f_ipdscp, *av);
+		ac--; av++;
+		break;
 
 	case TOK_QUEUE:
 		action->len = F_INSN_SIZE(ipfw_insn_pipe);
@@ -4446,6 +4501,12 @@
 		case TOK_IPTOS:
 			NEED1("missing argument for iptos");
 			fill_flags(cmd, O_IPTOS, f_iptos, *av);
+			ac--; av++;
+			break;
+
+		case TOK_IPDSCP:
+			NEED1("missing argument for dscp");
+			fill_flags(cmd, O_IPDSCP, f_ipdscp, *av);
 			ac--; av++;
 			break;
 
diff -ru src/sys/netinet/ip_fw.h /usr/src/sys/netinet/ip_fw.h
--- src/sys/netinet/ip_fw.h	Sat Jul 29 12:24:12 2006
+++ /usr/src/sys/netinet/ip_fw.h	Wed Aug 23 17:22:43 2006
@@ -160,6 +160,10 @@
 	O_TAG,   		/* arg1=tag number */
 	O_TAGGED,		/* arg1=tag number */
 
+        O_SET_IPTOS,            /* arg1 = iptos               	*/
+        O_SET_DSCP,             /* arg1 = dscp            	*/
+        O_IPDSCP,               /* arg1 = DSCP                  */
+
 	O_LAST_OPCODE		/* not an opcode!		*/
 };
 
@@ -563,6 +567,21 @@
 typedef	int ip_fw_chk_t(struct ip_fw_args *args);
 extern	ip_fw_chk_t	*ip_fw_chk_ptr;
 #define	IPFW_LOADED	(ip_fw_chk_ptr != NULL)
+
+#define ADJUST_CHECKSUM(acc, cksum) \
+        do { \
+                acc += cksum; \
+                if (acc < 0) { \
+                        acc = -acc; \
+                        acc = (acc >> 16) + (acc & 0xffff); \
+                        acc += acc >> 16; \
+                        cksum = (u_short) ~acc; \
+                } else { \
+                        acc = (acc >> 16) + (acc & 0xffff); \
+                        acc += acc >> 16; \
+                        cksum = (u_short) acc; \
+                } \
+        } while (0)
 
 #endif /* _KERNEL */
 #endif /* _IPFW2_H */
diff -ru src/sys/netinet/ip_fw2.c /usr/src/sys/netinet/ip_fw2.c
--- src/sys/netinet/ip_fw2.c	Sat Jul 29 12:24:12 2006
+++ /usr/src/sys/netinet/ip_fw2.c	Thu Aug 24 10:43:17 2006
@@ -145,6 +145,21 @@
 	NET_ASSERT_GIANT();						\
 } while (0)
 
+static __inline int
+twowords(void *p)
+{
+        uint8_t *c = p;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+        uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
+        uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
+#else   
+        uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
+        uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
+#endif  
+        return (s1 + s2);
+}
+
 static __inline void
 IPFW_RLOCK(struct ip_fw_chain *chain)
 {
@@ -2427,6 +2442,7 @@
 	for (; f; f = f->next) {
 		ipfw_insn *cmd;
 		uint32_t tablearg = 0;
+		int accumulate;
 		int l, cmdlen, skip_or; /* skip rest of OR block */
 
 again:
@@ -2734,6 +2750,11 @@
 				    flags_match(cmd, mtod(m, struct ip *)->ip_tos));
 				break;
 
+			case O_IPDSCP:
+				match = (is_ipv4 &&
+				    (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xfc)) );
+				break;
+			
 			case O_TCPDATALEN:
 				if (proto == IPPROTO_TCP && offset == 0) {
 				    struct tcphdr *tcp;
@@ -3052,6 +3073,28 @@
 				}
 				match = 1;
 				break;
+			
+			case O_SET_IPTOS:
+                                accumulate = twowords(&ip->ip_tos);
+				/* for tos, we have to change whole byte,
+				   and for dscp bits 0-5 only */
+                                ip->ip_tos = cmd->arg1;
+                                accumulate -= twowords(&ip->ip_tos);
+                                ADJUST_CHECKSUM(accumulate, ip->ip_sum);
+                                f->pcnt++;      /* update stats */
+                                f->bcnt += pktlen;
+                                f->timestamp = time_second;
+                                goto next_rule;
+
+			case O_SET_DSCP:
+				accumulate = twowords(&ip->ip_tos);
+				ip->ip_tos = ip->ip_tos | cmd->arg1;
+				accumulate -= twowords(&ip->ip_tos);
+				ADJUST_CHECKSUM(accumulate, ip->ip_sum);
+				f->pcnt++;      /* update stats */
+				f->bcnt += pktlen;
+				f->timestamp = time_second;
+				goto next_rule;
 
 			case O_PROBE_STATE:
 			case O_CHECK_STATE:
@@ -3655,6 +3698,7 @@
 		case O_DIVERTED:
 		case O_IPOPT:
 		case O_IPTOS:
+		case O_IPDSCP:
 		case O_IPPRECEDENCE:
 		case O_IPVER:
 		case O_TCPWIN:
@@ -3675,6 +3719,11 @@
 		case O_TAG:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
 				goto bad_size;
+			break;
+
+		case O_SET_DSCP:
+		case O_SET_IPTOS:
+			have_action = 1;
 			break;
 
 		case O_UID:
--- ipfw_tos_dscp_20060824_1.diff ends here ---


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw 
Responsible-Changed-By: novel 
Responsible-Changed-When: Thu Aug 24 07:39:28 UTC 2006 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=102471 
Responsible-Changed-From-To: freebsd-ipfw->melifaro 
Responsible-Changed-By: melifaro 
Responsible-Changed-When: Tue Mar 12 13:27:21 UTC 2013 
Responsible-Changed-Why:  
Take 

http://www.freebsd.org/cgi/query-pr.cgi?pr=102471 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/102471: commit references a PR
Date: Wed, 20 Mar 2013 10:35:42 +0000 (UTC)

 Author: melifaro
 Date: Wed Mar 20 10:35:33 2013
 New Revision: 248552
 URL: http://svnweb.freebsd.org/changeset/base/248552
 
 Log:
   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
 
 Modified:
   head/sbin/ipfw/ipfw.8
   head/sbin/ipfw/ipfw2.c
   head/sbin/ipfw/ipfw2.h
   head/sys/netinet/ip_fw.h
   head/sys/netpfil/ipfw/ip_fw2.c
   head/sys/netpfil/ipfw/ip_fw_log.c
   head/sys/netpfil/ipfw/ip_fw_sockopt.c
 
 Modified: head/sbin/ipfw/ipfw.8
 ==============================================================================
 --- head/sbin/ipfw/ipfw.8	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sbin/ipfw/ipfw.8	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -960,6 +960,61 @@ It is possible to use the
  keyword with setfib.
  If the tablearg value is not within the compiled range of fibs,
  the packet's fib is set to 0.
 +.It Cm setdscp Ar DSCP | number | tablearg
 +Set specified DiffServ codepoint for an IPv4/IPv6 packet.
 +Processing continues at the next rule.
 +Supported values are:
 +.Pp
 +.Cm CS0
 +.Pq Dv 000000 ,
 +.Cm CS1
 +.Pq Dv 001000 ,
 +.Cm CS2
 +.Pq Dv 010000 ,
 +.Cm CS3
 +.Pq Dv 011000 ,
 +.Cm CS4
 +.Pq Dv 100000 ,
 +.Cm CS5
 +.Pq Dv 101000 ,
 +.Cm CS6
 +.Pq Dv 110000 ,
 +.Cm CS7
 +.Pq Dv 111000 ,
 +.Cm AF11
 +.Pq Dv 001010 ,
 +.Cm AF12
 +.Pq Dv 001100 ,
 +.Cm AF13
 +.Pq Dv 001110 ,
 +.Cm AF21
 +.Pq Dv 010010 ,
 +.Cm AF22
 +.Pq Dv 010100 ,
 +.Cm AF23
 +.Pq Dv 010110 ,
 +.Cm AF31
 +.Pq Dv 011010 ,
 +.Cm AF32
 +.Pq Dv 011100 ,
 +.Cm AF33
 +.Pq Dv 011110 ,
 +.Cm AF41
 +.Pq Dv 100010 ,
 +.Cm AF42
 +.Pq Dv 100100 ,
 +.Cm AF43
 +.Pq Dv 100110 ,
 +.Cm EF
 +.Pq Dv 101110 ,
 +.Cm BE
 +.Pq Dv 000000 .
 +Additionally, DSCP value can be specified by number (0..64).
 +It is also possible to use the
 +.Cm tablearg
 +keyword with setdscp.
 +If the tablearg value is not within the 0..64 range, lower 6 bits of supplied
 +value are used.
  .It Cm reass
  Queue and reassemble IP fragments.
  If the packet is not fragmented, counters are updated and
 @@ -1454,6 +1509,17 @@ The supported IP types of service are:
  The absence of a particular type may be denoted
  with a
  .Ql \&! .
 +.It Cm dscp spec Ns Op , Ns Ar spec
 +Matches IPv4/IPv6 packets whose
 +.Cm DS
 +field value is contained in
 +.Ar spec
 +mask.
 +Multiple values can be specified via 
 +the comma separated list.
 +Value can be one of keywords used in
 +.Cm setdscp
 +action or exact number.
  .It Cm ipttl Ar ttl-list
  Matches IPv4 packets whose time to live is included in
  .Ar ttl-list ,
 @@ -2976,6 +3042,23 @@ configured on
  but coming in on
  .Li fxp1
  would be dropped.
 +.Pp
 +The
 +.Cm setdscp
 +option could be used to (re)mark user traffic,
 +by adding the following to the appropriate place in ruleset:
 +.Pp
 +.Dl "ipfw add setdscp be ip from any to any dscp af11,af21"
 +.Pp
 +This rule drops all incoming packets that appear to be coming from another
 +directly connected system but on the wrong interface.
 +For example, a packet with a source address of
 +.Li 192.168.0.0/24 ,
 +configured on
 +.Li fxp0 ,
 +but coming in on
 +.Li fxp1
 +would be dropped.
  .Ss DYNAMIC RULES
  In order to protect a site from flood attacks involving fake
  TCP packets, it is safer to use dynamic rules:
 
 Modified: head/sbin/ipfw/ipfw2.c
 ==============================================================================
 --- head/sbin/ipfw/ipfw2.c	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sbin/ipfw/ipfw2.c	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -167,6 +167,32 @@ static struct _s_x f_iptos[] = {
  	{ NULL,	0 }
  };
  
 +static struct _s_x f_ipdscp[] = {
 +	{ "af11", IPTOS_DSCP_AF11 >> 2 },	/* 001010 */
 +	{ "af12", IPTOS_DSCP_AF12 >> 2 },	/* 001100 */
 +	{ "af13", IPTOS_DSCP_AF13 >> 2 },	/* 001110 */
 +	{ "af21", IPTOS_DSCP_AF21 >> 2 },	/* 010010 */
 +	{ "af22", IPTOS_DSCP_AF22 >> 2 },	/* 010100 */
 +	{ "af23", IPTOS_DSCP_AF23 >> 2 },	/* 010110 */
 +	{ "af31", IPTOS_DSCP_AF31 >> 2 },	/* 011010 */
 +	{ "af32", IPTOS_DSCP_AF32 >> 2 },	/* 011100 */
 +	{ "af33", IPTOS_DSCP_AF33 >> 2 },	/* 011110 */
 +	{ "af41", IPTOS_DSCP_AF41 >> 2 },	/* 100010 */
 +	{ "af42", IPTOS_DSCP_AF42 >> 2 },	/* 100100 */
 +	{ "af43", IPTOS_DSCP_AF43 >> 2 },	/* 100110 */
 +	{ "be", IPTOS_DSCP_CS0 >> 2 }, 	/* 000000 */
 +	{ "ef", IPTOS_DSCP_EF >> 2 },	/* 101110 */
 +	{ "cs0", IPTOS_DSCP_CS0 >> 2 },	/* 000000 */
 +	{ "cs1", IPTOS_DSCP_CS1 >> 2 },	/* 001000 */
 +	{ "cs2", IPTOS_DSCP_CS2 >> 2 },	/* 010000 */
 +	{ "cs3", IPTOS_DSCP_CS3 >> 2 },	/* 011000 */
 +	{ "cs4", IPTOS_DSCP_CS4 >> 2 },	/* 100000 */
 +	{ "cs5", IPTOS_DSCP_CS5 >> 2 },	/* 101000 */
 +	{ "cs6", IPTOS_DSCP_CS6 >> 2 },	/* 110000 */
 +	{ "cs7", IPTOS_DSCP_CS7 >> 2 },	/* 100000 */
 +	{ NULL, 0 }
 +};
 +
  static struct _s_x limit_masks[] = {
  	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
  	{"src-addr",	DYN_SRC_ADDR},
 @@ -237,6 +263,7 @@ static struct _s_x rule_actions[] = {
  	{ "nat",		TOK_NAT },
  	{ "reass",		TOK_REASS },
  	{ "setfib",		TOK_SETFIB },
 +	{ "setdscp",		TOK_SETDSCP },
  	{ "call",		TOK_CALL },
  	{ "return",		TOK_RETURN },
  	{ NULL, 0 }	/* terminator */
 @@ -714,6 +741,51 @@ fill_newports(ipfw_insn_u16 *cmd, char *
  	return (i);
  }
  
 +/*
 + * Fill the body of the command with the list of DiffServ codepoints.
 + */
 +static void
 +fill_dscp(ipfw_insn *cmd, char *av, int cblen)
 +{
 +	uint32_t *low, *high;
 +	char *s = av, *a;
 +	int code;
 +
 +	cmd->opcode = O_DSCP;
 +	cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1;
 +
 +	CHECK_CMDLEN;
 +
 +	low = (uint32_t *)(cmd + 1);
 +	high = low + 1;
 +
 +	*low = 0;
 +	*high = 0;
 +
 +	while (s != NULL) {
 +		a = strchr(s, ',');
 +
 +		if (a != NULL)
 +			*a++ = '\0';
 +
 +		if (isalpha(*s)) {
 +			if ((code = match_token(f_ipdscp, s)) == -1)
 +				errx(EX_DATAERR, "Unknown DSCP code");
 +		} else {
 +			code = strtoul(s, NULL, 10);
 +			if (code < 0 || code > 63)
 +				errx(EX_DATAERR, "Invalid DSCP value");
 +		}
 +
 +		if (code > 32)
 +			*high |= 1 << (code - 32);
 +		else
 +			*low |= 1 << code;
 +
 +		s = a;
 +	}
 +}
 +
  static struct _s_x icmpcodes[] = {
        { "net",			ICMP_UNREACH_NET },
        { "host",			ICMP_UNREACH_HOST },
 @@ -972,6 +1044,32 @@ print_icmptypes(ipfw_insn_u32 *cmd)
  	}
  }
  
 +static void
 +print_dscp(ipfw_insn_u32 *cmd)
 +{
 +	int i, c;
 +	uint32_t *v;
 +	char sep= ' ';
 +	const char *code;
 +
 +	printf(" dscp");
 +	i = 0;
 +	c = 0;
 +	v = cmd->d;
 +	while (i < 64) {
 +		if (*v & (1 << i)) {
 +			if ((code = match_value(f_ipdscp, i)) != NULL)
 +				printf("%c%s", sep, code);
 +			else
 +				printf("%c%d", sep, i);
 +			sep = ',';
 +		}
 +
 +		if ((++i % 32) == 0)
 +			v++;
 +	}
 +}
 +
  /*
   * show_ipfw() prints the body of an ipfw rule.
   * Because the standard rule has at least proto src_ip dst_ip, we use
 @@ -1205,6 +1303,17 @@ show_ipfw(struct ip_fw *rule, int pcwidt
  			PRINT_UINT_ARG("setfib ", cmd->arg1);
   			break;
  
 +		case O_SETDSCP:
 +		    {
 +			const char *code;
 +
 +			if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
 +				printf("setdscp %s", code);
 +			else
 +				PRINT_UINT_ARG("setdscp ", cmd->arg1);
 +		    }
 + 			break;
 +
  		case O_REASS:
  			printf("reass");
  			break;
 @@ -1500,6 +1609,10 @@ show_ipfw(struct ip_fw *rule, int pcwidt
  				printf(" ipprecedence %u", (cmd->arg1) >> 5 );
  				break;
  
 +			case O_DSCP:
 +				print_dscp((ipfw_insn_u32 *)cmd);
 +	 			break;
 +
  			case O_IPLEN:
  				if (F_LEN(cmd) == 1)
  				    printf(" iplen %u", cmd->arg1 );
 @@ -3036,6 +3149,24 @@ chkarg:
  		break;
  	    }
  
 +	case TOK_SETDSCP:
 +	    {
 +		int code;
 +
 +		action->opcode = O_SETDSCP;
 +		NEED1("missing DSCP code");
 +		if (_substrcmp(*av, "tablearg") == 0) {
 +			action->arg1 = IP_FW_TABLEARG;
 +		} else if (isalpha(*av[0])) {
 +			if ((code = match_token(f_ipdscp, *av)) == -1)
 +				errx(EX_DATAERR, "Unknown DSCP code");
 +			action->arg1 = code;
 +		} else
 +		        action->arg1 = strtoul(*av, NULL, 10);
 +		av++;
 +		break;
 +	    }
 +
  	case TOK_REASS:
  		action->opcode = O_REASS;
  		break;
 @@ -3448,6 +3579,12 @@ read_options:
  			av++;
  			break;
  
 +		case TOK_DSCP:
 +			NEED1("missing DSCP code");
 +			fill_dscp(cmd, *av, cblen);
 +			av++;
 +			break;
 +
  		case TOK_IPOPTS:
  			NEED1("missing argument for ipoptions");
  			fill_flags(cmd, O_IPOPT, f_ipopts, *av);
 
 Modified: head/sbin/ipfw/ipfw2.h
 ==============================================================================
 --- head/sbin/ipfw/ipfw2.h	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sbin/ipfw/ipfw2.h	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -203,6 +203,7 @@ enum tokens {
  	TOK_SETFIB,
  	TOK_LOOKUP,
  	TOK_SOCKARG,
 +	TOK_SETDSCP,
  };
  /*
   * the following macro returns an error message if we run out of
 
 Modified: head/sys/netinet/ip_fw.h
 ==============================================================================
 --- head/sys/netinet/ip_fw.h	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sys/netinet/ip_fw.h	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -218,6 +218,9 @@ enum ipfw_opcodes {		/* arguments (4 byt
  
  	O_FORWARD_IP6,		/* fwd sockaddr_in6             */
  
 +	O_DSCP,			/* 2 u32 = DSCP mask */
 +	O_SETDSCP,		/* arg1=DSCP value */
 +
  	O_LAST_OPCODE		/* not an opcode!		*/
  };
  
 
 Modified: head/sys/netpfil/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netpfil/ipfw/ip_fw2.c	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sys/netpfil/ipfw/ip_fw2.c	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -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;
 
 Modified: head/sys/netpfil/ipfw/ip_fw_log.c
 ==============================================================================
 --- head/sys/netpfil/ipfw/ip_fw_log.c	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sys/netpfil/ipfw/ip_fw_log.c	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -292,10 +292,8 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  				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;
 
 Modified: head/sys/netpfil/ipfw/ip_fw_sockopt.c
 ==============================================================================
 --- head/sys/netpfil/ipfw/ip_fw_sockopt.c	Wed Mar 20 09:56:20 2013	(r248551)
 +++ head/sys/netpfil/ipfw/ip_fw_sockopt.c	Wed Mar 20 10:35:33 2013	(r248552)
 @@ -671,6 +671,10 @@ check_ipfw_struct(struct ip_fw *rule, in
  		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, in
  		case O_ACCEPT:
  		case O_DENY:
  		case O_REJECT:
 +		case O_SETDSCP:
  #ifdef INET6
  		case O_UNREACH6:
  #endif
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: melifaro 
State-Changed-When: Thu Mar 21 15:55:05 UTC 2013 
State-Changed-Why:  
ipfw dscp set/match options were committed to -head. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=102471 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/102471: commit references a PR
Date: Sat, 18 May 2013 05:48:55 +0000 (UTC)

 Author: melifaro
 Date: Sat May 18 05:48:46 2013
 New Revision: 250762
 URL: http://svnweb.freebsd.org/changeset/base/250762
 
 Log:
   MFC r248552, r248971
   
   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
   
   Fix ipfw rule validation partially broken by r248552.
 
 Modified:
   stable/9/sbin/ipfw/ipfw.8
   stable/9/sbin/ipfw/ipfw2.c
   stable/9/sbin/ipfw/ipfw2.h
   stable/9/sys/netinet/ip_fw.h
   stable/9/sys/netpfil/ipfw/ip_fw2.c
   stable/9/sys/netpfil/ipfw/ip_fw_log.c
   stable/9/sys/netpfil/ipfw/ip_fw_sockopt.c
 Directory Properties:
   stable/9/sbin/   (props changed)
   stable/9/sbin/ipfw/   (props changed)
   stable/9/sys/   (props changed)
 
 Modified: stable/9/sbin/ipfw/ipfw.8
 ==============================================================================
 --- stable/9/sbin/ipfw/ipfw.8	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sbin/ipfw/ipfw.8	Sat May 18 05:48:46 2013	(r250762)
 @@ -948,6 +948,61 @@ Processing continues at the next rule.
  It is possible to use the
  .Cm tablearg
  keyword with a setfib. If tablearg value is not within compiled FIB range packet fib is set to 0.
 +.It Cm setdscp Ar DSCP | number | tablearg
 +Set specified DiffServ codepoint for an IPv4/IPv6 packet.
 +Processing continues at the next rule.
 +Supported values are:
 +.Pp
 +.Cm CS0
 +.Pq Dv 000000 ,
 +.Cm CS1
 +.Pq Dv 001000 ,
 +.Cm CS2
 +.Pq Dv 010000 ,
 +.Cm CS3
 +.Pq Dv 011000 ,
 +.Cm CS4
 +.Pq Dv 100000 ,
 +.Cm CS5
 +.Pq Dv 101000 ,
 +.Cm CS6
 +.Pq Dv 110000 ,
 +.Cm CS7
 +.Pq Dv 111000 ,
 +.Cm AF11
 +.Pq Dv 001010 ,
 +.Cm AF12
 +.Pq Dv 001100 ,
 +.Cm AF13
 +.Pq Dv 001110 ,
 +.Cm AF21
 +.Pq Dv 010010 ,
 +.Cm AF22
 +.Pq Dv 010100 ,
 +.Cm AF23
 +.Pq Dv 010110 ,
 +.Cm AF31
 +.Pq Dv 011010 ,
 +.Cm AF32
 +.Pq Dv 011100 ,
 +.Cm AF33
 +.Pq Dv 011110 ,
 +.Cm AF41
 +.Pq Dv 100010 ,
 +.Cm AF42
 +.Pq Dv 100100 ,
 +.Cm AF43
 +.Pq Dv 100110 ,
 +.Cm EF
 +.Pq Dv 101110 ,
 +.Cm BE
 +.Pq Dv 000000 .
 +Additionally, DSCP value can be specified by number (0..64).
 +It is also possible to use the
 +.Cm tablearg
 +keyword with setdscp.
 +If the tablearg value is not within the 0..64 range, lower 6 bits of supplied
 +value are used.
  .It Cm reass
  Queue and reassemble ip fragments.
  If the packet is not fragmented, counters are updated and processing continues with the next rule.
 @@ -1436,6 +1491,17 @@ The supported IP types of service are:
  The absence of a particular type may be denoted
  with a
  .Ql \&! .
 +.It Cm dscp spec Ns Op , Ns Ar spec
 +Matches IPv4/IPv6 packets whose
 +.Cm DS
 +field value is contained in
 +.Ar spec
 +mask.
 +Multiple values can be specified via 
 +the comma separated list.
 +Value can be one of keywords used in
 +.Cm setdscp
 +action or exact number.
  .It Cm ipttl Ar ttl-list
  Matches IPv4 packets whose time to live is included in
  .Ar ttl-list ,
 @@ -2944,6 +3010,23 @@ configured on
  but coming in on
  .Li fxp1
  would be dropped.
 +.Pp
 +The
 +.Cm setdscp
 +option could be used to (re)mark user traffic,
 +by adding the following to the appropriate place in ruleset:
 +.Pp
 +.Dl "ipfw add setdscp be ip from any to any dscp af11,af21"
 +.Pp
 +This rule drops all incoming packets that appear to be coming from another
 +directly connected system but on the wrong interface.
 +For example, a packet with a source address of
 +.Li 192.168.0.0/24 ,
 +configured on
 +.Li fxp0 ,
 +but coming in on
 +.Li fxp1
 +would be dropped.
  .Ss DYNAMIC RULES
  In order to protect a site from flood attacks involving fake
  TCP packets, it is safer to use dynamic rules:
 
 Modified: stable/9/sbin/ipfw/ipfw2.c
 ==============================================================================
 --- stable/9/sbin/ipfw/ipfw2.c	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sbin/ipfw/ipfw2.c	Sat May 18 05:48:46 2013	(r250762)
 @@ -167,6 +167,32 @@ static struct _s_x f_iptos[] = {
  	{ NULL,	0 }
  };
  
 +static struct _s_x f_ipdscp[] = {
 +	{ "af11", IPTOS_DSCP_AF11 >> 2 },	/* 001010 */
 +	{ "af12", IPTOS_DSCP_AF12 >> 2 },	/* 001100 */
 +	{ "af13", IPTOS_DSCP_AF13 >> 2 },	/* 001110 */
 +	{ "af21", IPTOS_DSCP_AF21 >> 2 },	/* 010010 */
 +	{ "af22", IPTOS_DSCP_AF22 >> 2 },	/* 010100 */
 +	{ "af23", IPTOS_DSCP_AF23 >> 2 },	/* 010110 */
 +	{ "af31", IPTOS_DSCP_AF31 >> 2 },	/* 011010 */
 +	{ "af32", IPTOS_DSCP_AF32 >> 2 },	/* 011100 */
 +	{ "af33", IPTOS_DSCP_AF33 >> 2 },	/* 011110 */
 +	{ "af41", IPTOS_DSCP_AF41 >> 2 },	/* 100010 */
 +	{ "af42", IPTOS_DSCP_AF42 >> 2 },	/* 100100 */
 +	{ "af43", IPTOS_DSCP_AF43 >> 2 },	/* 100110 */
 +	{ "be", IPTOS_DSCP_CS0 >> 2 }, 	/* 000000 */
 +	{ "ef", IPTOS_DSCP_EF >> 2 },	/* 101110 */
 +	{ "cs0", IPTOS_DSCP_CS0 >> 2 },	/* 000000 */
 +	{ "cs1", IPTOS_DSCP_CS1 >> 2 },	/* 001000 */
 +	{ "cs2", IPTOS_DSCP_CS2 >> 2 },	/* 010000 */
 +	{ "cs3", IPTOS_DSCP_CS3 >> 2 },	/* 011000 */
 +	{ "cs4", IPTOS_DSCP_CS4 >> 2 },	/* 100000 */
 +	{ "cs5", IPTOS_DSCP_CS5 >> 2 },	/* 101000 */
 +	{ "cs6", IPTOS_DSCP_CS6 >> 2 },	/* 110000 */
 +	{ "cs7", IPTOS_DSCP_CS7 >> 2 },	/* 100000 */
 +	{ NULL, 0 }
 +};
 +
  static struct _s_x limit_masks[] = {
  	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
  	{"src-addr",	DYN_SRC_ADDR},
 @@ -237,6 +263,7 @@ static struct _s_x rule_actions[] = {
  	{ "nat",		TOK_NAT },
  	{ "reass",		TOK_REASS },
  	{ "setfib",		TOK_SETFIB },
 +	{ "setdscp",		TOK_SETDSCP },
  	{ "call",		TOK_CALL },
  	{ "return",		TOK_RETURN },
  	{ NULL, 0 }	/* terminator */
 @@ -714,6 +741,51 @@ fill_newports(ipfw_insn_u16 *cmd, char *
  	return (i);
  }
  
 +/*
 + * Fill the body of the command with the list of DiffServ codepoints.
 + */
 +static void
 +fill_dscp(ipfw_insn *cmd, char *av, int cblen)
 +{
 +	uint32_t *low, *high;
 +	char *s = av, *a;
 +	int code;
 +
 +	cmd->opcode = O_DSCP;
 +	cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1;
 +
 +	CHECK_CMDLEN;
 +
 +	low = (uint32_t *)(cmd + 1);
 +	high = low + 1;
 +
 +	*low = 0;
 +	*high = 0;
 +
 +	while (s != NULL) {
 +		a = strchr(s, ',');
 +
 +		if (a != NULL)
 +			*a++ = '\0';
 +
 +		if (isalpha(*s)) {
 +			if ((code = match_token(f_ipdscp, s)) == -1)
 +				errx(EX_DATAERR, "Unknown DSCP code");
 +		} else {
 +			code = strtoul(s, NULL, 10);
 +			if (code < 0 || code > 63)
 +				errx(EX_DATAERR, "Invalid DSCP value");
 +		}
 +
 +		if (code > 32)
 +			*high |= 1 << (code - 32);
 +		else
 +			*low |= 1 << code;
 +
 +		s = a;
 +	}
 +}
 +
  static struct _s_x icmpcodes[] = {
        { "net",			ICMP_UNREACH_NET },
        { "host",			ICMP_UNREACH_HOST },
 @@ -972,6 +1044,32 @@ print_icmptypes(ipfw_insn_u32 *cmd)
  	}
  }
  
 +static void
 +print_dscp(ipfw_insn_u32 *cmd)
 +{
 +	int i, c;
 +	uint32_t *v;
 +	char sep= ' ';
 +	const char *code;
 +
 +	printf(" dscp");
 +	i = 0;
 +	c = 0;
 +	v = cmd->d;
 +	while (i < 64) {
 +		if (*v & (1 << i)) {
 +			if ((code = match_value(f_ipdscp, i)) != NULL)
 +				printf("%c%s", sep, code);
 +			else
 +				printf("%c%d", sep, i);
 +			sep = ',';
 +		}
 +
 +		if ((++i % 32) == 0)
 +			v++;
 +	}
 +}
 +
  /*
   * show_ipfw() prints the body of an ipfw rule.
   * Because the standard rule has at least proto src_ip dst_ip, we use
 @@ -1204,6 +1302,17 @@ show_ipfw(struct ip_fw *rule, int pcwidt
  			PRINT_UINT_ARG("setfib ", cmd->arg1);
   			break;
  
 +		case O_SETDSCP:
 +		    {
 +			const char *code;
 +
 +			if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
 +				printf("setdscp %s", code);
 +			else
 +				PRINT_UINT_ARG("setdscp ", cmd->arg1);
 +		    }
 + 			break;
 +
  		case O_REASS:
  			printf("reass");
  			break;
 @@ -1499,6 +1608,10 @@ show_ipfw(struct ip_fw *rule, int pcwidt
  				printf(" ipprecedence %u", (cmd->arg1) >> 5 );
  				break;
  
 +			case O_DSCP:
 +				print_dscp((ipfw_insn_u32 *)cmd);
 +	 			break;
 +
  			case O_IPLEN:
  				if (F_LEN(cmd) == 1)
  				    printf(" iplen %u", cmd->arg1 );
 @@ -3035,6 +3148,24 @@ chkarg:
  		break;
  	    }
  
 +	case TOK_SETDSCP:
 +	    {
 +		int code;
 +
 +		action->opcode = O_SETDSCP;
 +		NEED1("missing DSCP code");
 +		if (_substrcmp(*av, "tablearg") == 0) {
 +			action->arg1 = IP_FW_TABLEARG;
 +		} else if (isalpha(*av[0])) {
 +			if ((code = match_token(f_ipdscp, *av)) == -1)
 +				errx(EX_DATAERR, "Unknown DSCP code");
 +			action->arg1 = code;
 +		} else
 +		        action->arg1 = strtoul(*av, NULL, 10);
 +		av++;
 +		break;
 +	    }
 +
  	case TOK_REASS:
  		action->opcode = O_REASS;
  		break;
 @@ -3447,6 +3578,12 @@ read_options:
  			av++;
  			break;
  
 +		case TOK_DSCP:
 +			NEED1("missing DSCP code");
 +			fill_dscp(cmd, *av, cblen);
 +			av++;
 +			break;
 +
  		case TOK_IPOPTS:
  			NEED1("missing argument for ipoptions");
  			fill_flags(cmd, O_IPOPT, f_ipopts, *av);
 
 Modified: stable/9/sbin/ipfw/ipfw2.h
 ==============================================================================
 --- stable/9/sbin/ipfw/ipfw2.h	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sbin/ipfw/ipfw2.h	Sat May 18 05:48:46 2013	(r250762)
 @@ -203,6 +203,7 @@ enum tokens {
  	TOK_SETFIB,
  	TOK_LOOKUP,
  	TOK_SOCKARG,
 +	TOK_SETDSCP,
  };
  /*
   * the following macro returns an error message if we run out of
 
 Modified: stable/9/sys/netinet/ip_fw.h
 ==============================================================================
 --- stable/9/sys/netinet/ip_fw.h	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sys/netinet/ip_fw.h	Sat May 18 05:48:46 2013	(r250762)
 @@ -218,6 +218,9 @@ enum ipfw_opcodes {		/* arguments (4 byt
  
  	O_FORWARD_IP6,		/* fwd sockaddr_in6             */
  
 +	O_DSCP,			/* 2 u32 = DSCP mask */
 +	O_SETDSCP,		/* arg1=DSCP value */
 +
  	O_LAST_OPCODE		/* not an opcode!		*/
  };
  
 
 Modified: stable/9/sys/netpfil/ipfw/ip_fw2.c
 ==============================================================================
 --- stable/9/sys/netpfil/ipfw/ip_fw2.c	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sys/netpfil/ipfw/ip_fw2.c	Sat May 18 05:48:46 2013	(r250762)
 @@ -1658,6 +1658,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;
 @@ -2340,6 +2366,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;
 
 Modified: stable/9/sys/netpfil/ipfw/ip_fw_log.c
 ==============================================================================
 --- stable/9/sys/netpfil/ipfw/ip_fw_log.c	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sys/netpfil/ipfw/ip_fw_log.c	Sat May 18 05:48:46 2013	(r250762)
 @@ -209,10 +209,8 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  				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;
 
 Modified: stable/9/sys/netpfil/ipfw/ip_fw_sockopt.c
 ==============================================================================
 --- stable/9/sys/netpfil/ipfw/ip_fw_sockopt.c	Sat May 18 05:40:59 2013	(r250761)
 +++ stable/9/sys/netpfil/ipfw/ip_fw_sockopt.c	Sat May 18 05:48:46 2013	(r250762)
 @@ -681,6 +681,11 @@ check_ipfw_struct(struct ip_fw *rule, in
  				goto bad_size;
  			break;
  
 +		case O_DSCP:
 +			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
 +				goto bad_size;
 +			break;
 +
  		case O_MAC_TYPE:
  		case O_IP_SRCPORT:
  		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
 @@ -741,6 +746,7 @@ check_ipfw_struct(struct ip_fw *rule, in
  		case O_ACCEPT:
  		case O_DENY:
  		case O_REJECT:
 +		case O_SETDSCP:
  #ifdef INET6
  		case O_UNREACH6:
  #endif
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: melifaro 
State-Changed-When: Fri Feb 14 14:14:17 UTC 2014 
State-Changed-Why:  
Committed and merged. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=102471 
>Unformatted:
