From nobody@FreeBSD.org  Mon May 12 15:39:24 2014
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTPS id 03E70236
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 12 May 2014 15:39:24 +0000 (UTC)
Received: from cgiserv.freebsd.org (cgiserv.freebsd.org [IPv6:2001:1900:2254:206a::50:4])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client did not present a certificate)
	by mx1.freebsd.org (Postfix) with ESMTPS id D97012207
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 12 May 2014 15:39:23 +0000 (UTC)
Received: from cgiserv.freebsd.org ([127.0.1.6])
	by cgiserv.freebsd.org (8.14.8/8.14.8) with ESMTP id s4CFdNL5011902
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 12 May 2014 15:39:23 GMT
	(envelope-from nobody@cgiserv.freebsd.org)
Received: (from nobody@localhost)
	by cgiserv.freebsd.org (8.14.8/8.14.8/Submit) id s4CFdNNT011901;
	Mon, 12 May 2014 15:39:23 GMT
	(envelope-from nobody)
Message-Id: <201405121539.s4CFdNNT011901@cgiserv.freebsd.org>
Date: Mon, 12 May 2014 15:39:23 GMT
From: Bill Yuan <bycn82@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: pps action for ipfw
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         189720
>Category:       kern
>Synopsis:       [ipfw] [patch] pps action for ipfw
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ipfw
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 12 15:40:00 UTC 2014
>Closed-Date:    
>Last-Modified:  Fri May 30 17:20:04 UTC 2014
>Originator:     Bill Yuan
>Release:        FB10Stable
>Organization:
cozilyworks
>Environment:
FreeBSD FB10Stable 10.0-STABLE FreeBSD 10.0-STABLE #0 r265900: Mon May 12 13:41:15 UTC 2014     root@FB10Stable:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
pps action for ipfw
pps: packet for second (millisecond)

usage:
    ipfw add pps 1 50 tcp from any to any


man page

 pps limit duration
             Rule with the pps keyword will allow the first limit packets in
             each duration milliseconds
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: sbin/ipfw/ipfw.8
===================================================================
--- sbin/ipfw/ipfw.8	(revision 265916)
+++ sbin/ipfw/ipfw.8	(working copy)
@@ -603,6 +603,14 @@
 Note: logging is done after all other packet matching conditions
 have been successfully verified, and before performing the final
 action (accept, deny, etc.) on the packet.
+.It Cm pps Ar limit duration
+Rule with the 
+.Cm pps
+keyword will allow the first
+.Ar limit
+packets in each 
+.Ar duration 
+milliseconds
 .It Cm tag Ar number
 When a packet matches a rule with the
 .Cm tag
Index: sbin/ipfw/ipfw2.c
===================================================================
--- sbin/ipfw/ipfw2.c	(revision 265916)
+++ sbin/ipfw/ipfw2.c	(working copy)
@@ -244,6 +244,7 @@
 	{ "allow",		TOK_ACCEPT },
 	{ "permit",		TOK_ACCEPT },
 	{ "count",		TOK_COUNT },
+	{ "pps",		TOK_PPS },
 	{ "pipe",		TOK_PIPE },
 	{ "queue",		TOK_QUEUE },
 	{ "divert",		TOK_DIVERT },
@@ -1231,7 +1232,12 @@
 		case O_SKIPTO:
 			PRINT_UINT_ARG("skipto ", cmd->arg1);
 			break;
-
+		case O_PPS:
+			{
+			ipfw_insn_pps *pps=(ipfw_insn_pps *)cmd;
+			printf("pps %d %d",cmd->arg1,pps->duration);
+			break;
+			}
 		case O_PIPE:
 			PRINT_UINT_ARG("pipe ", cmd->arg1);
 			break;
@@ -2985,7 +2991,23 @@
 	case TOK_COUNT:
 		action->opcode = O_COUNT;
 		break;
-
+	
+	case TOK_PPS:
+		action->opcode = O_PPS;
+		ipfw_insn_pps *p = (ipfw_insn_pps *)action;
+		action->len = F_INSN_SIZE(ipfw_insn_pps);
+		if (isdigit(**av)) {
+			action->arg1 = strtoul(*av, NULL, 10);
+			av++;
+		}else
+			errx(EX_USAGE, "illegal argument pps `limit` %s", *av);
+		if (isdigit(**av)) {
+			p->duration = strtoul(*av, NULL, 10);
+			av++;
+		}else
+			errx(EX_USAGE,"illegal arugment pps `duration` %s", *av);
+		break;
+	
 	case TOK_NAT:
 		action->opcode = O_NAT;
 		action->len = F_INSN_SIZE(ipfw_insn_nat);
Index: sbin/ipfw/ipfw2.h
===================================================================
--- sbin/ipfw/ipfw2.h	(revision 265916)
+++ sbin/ipfw/ipfw2.h	(working copy)
@@ -92,6 +92,7 @@
 	TOK_NGTEE,
 	TOK_FORWARD,
 	TOK_SKIPTO,
+	TOK_PPS,
 	TOK_DENY,
 	TOK_REJECT,
 	TOK_RESET,
Index: sys/netinet/ip_fw.h
===================================================================
--- sys/netinet/ip_fw.h	(revision 265916)
+++ sys/netinet/ip_fw.h	(working copy)
@@ -165,6 +165,7 @@
 	O_REJECT,		/* arg1=icmp arg (same as deny)	*/
 	O_COUNT,		/* none				*/
 	O_SKIPTO,		/* arg1=next rule number	*/
+	O_PPS,			/* arg1=limit, pps->duration */
 	O_PIPE,			/* arg1=pipe number		*/
 	O_QUEUE,		/* arg1=queue number		*/
 	O_DIVERT,		/* arg1=port number		*/
@@ -378,6 +379,15 @@
 } ipfw_insn_log;
 
 /*
+ * This is used for PPS
+ */
+typedef struct _ipfw_insn_pps{
+	ipfw_insn o;
+	uint32_t start_time;
+	uint16_t count;
+	uint16_t duration;
+} ipfw_insn_pps;
+/*
  * Data structures required by both ipfw(8) and ipfw(4) but not part of the
  * management API are protected by IPFW_INTERNAL.
  */
Index: sys/netpfil/ipfw/ip_fw2.c
===================================================================
--- sys/netpfil/ipfw/ip_fw2.c	(revision 265916)
+++ sys/netpfil/ipfw/ip_fw2.c	(working copy)
@@ -2179,7 +2179,24 @@
 			    skip_or = 0;
 			    continue;
 			    break;	/* not reached */
-
+			case O_PPS:{
+				ipfw_insn_pps *pps = (ipfw_insn_pps *)cmd;
+				if(pps->start_time+pps->duration >= ticks){
+					if(pps->count < cmd->arg1){
+						retval = IP_FW_PASS;
+					}else{
+						retval = IP_FW_DENY;
+					}
+					pps->count++;
+				}else{
+					pps->start_time=ticks;
+					pps->count=1;
+					retval = IP_FW_PASS;
+				}
+				l = 0;		
+				done = 1;
+				break;	
+				}
 			case O_CALLRETURN: {
 				/*
 				 * Implementation of `subroutine' call/return,
Index: sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_sockopt.c	(revision 265916)
+++ sys/netpfil/ipfw/ip_fw_sockopt.c	(working copy)
@@ -702,6 +702,12 @@
 			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
 				goto bad_size;
 			break;
+		
+		case O_PPS:
+			have_action=1;
+			if (cmdlen != F_INSN_SIZE(ipfw_insn_pps))
+				goto bad_size;
+			break;
 
 		case O_PIPE:
 		case O_QUEUE:
@@ -769,6 +775,7 @@
 				return EINVAL;
 			}
 			break;
+
 #ifdef INET6
 		case O_IP6_SRC:
 		case O_IP6_DST:
@@ -776,7 +783,6 @@
 			    F_INSN_SIZE(ipfw_insn))
 				goto bad_size;
 			break;
-
 		case O_FLOW6ID:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
 			    ((ipfw_insn_u32 *)cmd)->o.arg1)


>Release-Note:
>Audit-Trail:

From: bycn82 <bycn82@gmail.com>
To: bug-followup@FreeBSD.org, bycn82@gmail.com
Cc:  
Subject: Re: kern/189720: pps action for ipfw
Date: Tue, 13 May 2014 10:54:47 +0800

 This is a multi-part message in MIME format.
 --------------060500040406000407020409
 Content-Type: multipart/alternative;
  boundary="------------070308050506000908020500"
 
 
 --------------070308050506000908020500
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 1.Clean some gratuitous white-space.
 2.Increase `count` and `duration` to uint32.
 
 --------------070308050506000908020500--
 
 --------------060500040406000407020409
 Content-Type: text/plain;
  name="pps.patch2.txt"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="pps.patch2.txt"
 
 Index: sbin/ipfw/ipfw.8
 ===================================================================
 --- sbin/ipfw/ipfw.8	(revision 265941)
 +++ sbin/ipfw/ipfw.8	(working copy)
 @@ -603,6 +603,14 @@
  Note: logging is done after all other packet matching conditions
  have been successfully verified, and before performing the final
  action (accept, deny, etc.) on the packet.
 +.It Cm pps Ar limit duration
 +Rule with the 
 +.Cm pps
 +keyword will allow the first
 +.Ar limit
 +packets in recent 
 +.Ar duration 
 +milliseconds
  .It Cm tag Ar number
  When a packet matches a rule with the
  .Cm tag
 Index: sbin/ipfw/ipfw2.c
 ===================================================================
 --- sbin/ipfw/ipfw2.c	(revision 265941)
 +++ sbin/ipfw/ipfw2.c	(working copy)
 @@ -244,6 +244,7 @@
  	{ "allow",		TOK_ACCEPT },
  	{ "permit",		TOK_ACCEPT },
  	{ "count",		TOK_COUNT },
 +	{ "pps",		TOK_PPS },
  	{ "pipe",		TOK_PIPE },
  	{ "queue",		TOK_QUEUE },
  	{ "divert",		TOK_DIVERT },
 @@ -1232,6 +1233,13 @@
  			PRINT_UINT_ARG("skipto ", cmd->arg1);
  			break;
  
 +		case O_PPS:
 +			{
 +			ipfw_insn_pps *pps=(ipfw_insn_pps *)cmd;
 +			printf("pps %d %d",cmd->arg1,pps->duration);
 +			break;			
 +			}
 +
  		case O_PIPE:
  			PRINT_UINT_ARG("pipe ", cmd->arg1);
  			break;
 @@ -2986,6 +2994,24 @@
  		action->opcode = O_COUNT;
  		break;
  
 +	case TOK_PPS:
 +		action->opcode = O_PPS;
 +		ipfw_insn_pps *p = (ipfw_insn_pps *)action;
 +		action->len = F_INSN_SIZE(ipfw_insn_pps);
 +		if (isdigit(**av)) {
 +			action->arg1 = strtoul(*av, NULL, 10);
 +			av++;
 +		}else{
 +			errx(EX_USAGE, "illegal argument pps `limit` %s", *av);
 +		}
 +		if (isdigit(**av)) {
 +			p->duration = strtoul(*av, NULL, 10);
 +			av++;
 +		}else{
 +			errx(EX_USAGE,"illegal arugment pps `duration` %s", *av);
 +		}
 +		break;	
 +
  	case TOK_NAT:
  		action->opcode = O_NAT;
  		action->len = F_INSN_SIZE(ipfw_insn_nat);
 Index: sbin/ipfw/ipfw2.h
 ===================================================================
 --- sbin/ipfw/ipfw2.h	(revision 265941)
 +++ sbin/ipfw/ipfw2.h	(working copy)
 @@ -92,6 +92,7 @@
  	TOK_NGTEE,
  	TOK_FORWARD,
  	TOK_SKIPTO,
 +	TOK_PPS,
  	TOK_DENY,
  	TOK_REJECT,
  	TOK_RESET,
 Index: sys/netinet/ip_fw.h
 ===================================================================
 --- sys/netinet/ip_fw.h	(revision 265941)
 +++ sys/netinet/ip_fw.h	(working copy)
 @@ -165,6 +165,7 @@
  	O_REJECT,		/* arg1=icmp arg (same as deny)	*/
  	O_COUNT,		/* none				*/
  	O_SKIPTO,		/* arg1=next rule number	*/
 +	O_PPS,			/* arg1=limit, pps->duration */
  	O_PIPE,			/* arg1=pipe number		*/
  	O_QUEUE,		/* arg1=queue number		*/
  	O_DIVERT,		/* arg1=port number		*/
 @@ -378,6 +379,16 @@
  } ipfw_insn_log;
  
  /*
 + *	This is used for PPS
 + */
 +typedef struct _ipfw_insn_pps{
 +	ipfw_insn o;
 +	uint32_t start_time;
 +	uint32_t count;
 +	uint32_t duration;
 +} ipfw_insn_pps;
 +
 +/*
   * Data structures required by both ipfw(8) and ipfw(4) but not part of the
   * management API are protected by IPFW_INTERNAL.
   */
 Index: sys/netpfil/ipfw/ip_fw2.c
 ===================================================================
 --- sys/netpfil/ipfw/ip_fw2.c	(revision 265941)
 +++ sys/netpfil/ipfw/ip_fw2.c	(working copy)
 @@ -2180,6 +2180,24 @@
  			    continue;
  			    break;	/* not reached */
  
 +			case O_PPS:{
 +				ipfw_insn_pps *pps = (ipfw_insn_pps *)cmd;
 +				if(pps->start_time+pps->duration >= ticks){
 +					if(pps->count < cmd->arg1){
 +						retval = IP_FW_PASS;
 +					}else{
 +						retval = IP_FW_DENY;
 +					}
 +					pps->count++;
 +				}else{
 +					pps->start_time=ticks;
 +					pps->count=1;
 +					retval = IP_FW_PASS;
 +				}
 +				l = 0;		
 +				done = 1;
 +				break;	
 +			}
  			case O_CALLRETURN: {
  				/*
  				 * Implementation of `subroutine' call/return,
 Index: sys/netpfil/ipfw/ip_fw_sockopt.c
 ===================================================================
 --- sys/netpfil/ipfw/ip_fw_sockopt.c	(revision 265941)
 +++ sys/netpfil/ipfw/ip_fw_sockopt.c	(working copy)
 @@ -703,6 +703,12 @@
  				goto bad_size;
  			break;
  
 +		case O_PPS:
 +			have_action=1;
 +			if (cmdlen != F_INSN_SIZE(ipfw_insn_pps))
 +				goto bad_size;
 +			break;
 +
  		case O_PIPE:
  		case O_QUEUE:
  			if (cmdlen != F_INSN_SIZE(ipfw_insn))
 
 --------------060500040406000407020409--
Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Tue May 13 04:51:40 UTC 2014 
Responsible-Changed-Why:  
Over to maintainer(s). 

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

From: Luigi Rizzo <rizzo@iet.unipi.it>
To: bug-followup@FreeBSD.org, bycn82@gmail.com
Cc:  
Subject: kern/189720: [ipfw] [patch] pps action for ipfw
Date: Thu, 29 May 2014 16:12:16 +0200

 Hi,
 I have looked at the update from May 13th but it is not ready yet,
 the code assumes HZ=1000 so 1 tick=1ms.
 
 The translation can be done in userspace or in the kernel.
 I would prefer the latter.
 
 Please note that the count might need to be adjusted accordingly
 if 1/HZ > duration. I covered most of these things in the email
 exchange before the patch was submitted.
 
 cheers
 luigi

From: "bycn82" <bycn82@gmail.com>
To: "'Luigi Rizzo'" <rizzo@iet.unipi.it>,
	<bug-followup@FreeBSD.org>
Cc:  
Subject: RE: kern/189720: [ipfw] [patch] pps action for ipfw
Date: Thu, 29 May 2014 23:06:27 +0800

 -----Original Message-----
 From: Luigi Rizzo [mailto:rizzo@iet.unipi.it]=20
 Sent: 29 May, 2014 22:12
 To: bug-followup@FreeBSD.org; bycn82@gmail.com
 Subject: kern/189720: [ipfw] [patch] pps action for ipfw
 
 Hi,
 I have looked at the update from May 13th but it is not ready yet, the =
 code assumes HZ=3D1000 so 1 tick=3D1ms.
 
 The translation can be done in userspace or in the kernel.
 I would prefer the latter.
 I see,=20
 If the HZ=3D3, that means every tick=3D333ms
 And if the user wants to =E2=80=9C 1 packet per 500ms=E2=80=9D, then in =
 the backend will not do the exactly the same as what user expect.
 
 Actually the implementation should be =E2=80=9Cpackets per =
 ticks=E2=80=9D, so how about this? Instead of translate it in codes. Why =
 not update the document, and explain it to the user in the document ?
 
 Please note that the count might need to be adjusted accordingly if 1/HZ =
 > duration. I covered most of these things in the email exchange before =
 the patch was submitted.
 
 cheers
 luigi
 

From: 'Luigi Rizzo' <rizzo@iet.unipi.it>
To: bycn82 <bycn82@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/189720: [ipfw] [patch] pps action for ipfw
Date: Thu, 29 May 2014 17:17:59 +0200

 On Thu, May 29, 2014 at 11:06:27PM +0800, bycn82 wrote:
 > 
 > 
 > -----Original Message-----
 > From: Luigi Rizzo [mailto:rizzo@iet.unipi.it] 
 > Sent: 29 May, 2014 22:12
 > To: bug-followup@FreeBSD.org; bycn82@gmail.com
 > Subject: kern/189720: [ipfw] [patch] pps action for ipfw
 > 
 > Hi,
 > I have looked at the update from May 13th but it is not ready yet, the code assumes HZ=1000 so 1 tick=1ms.
 > 
 > The translation can be done in userspace or in the kernel.
 > I would prefer the latter.
 > I see, 
 > If the HZ=3, that means every tick=333ms
 > And if the user wants to ??? 1 packet per 500ms???, then in the backend will not do the exactly the same as what user expect.
 > 
 > Actually the implementation should be ???packets per ticks???, so how about this? Instead of translate it in codes. Why not update the document, and explain it to the user in the document ?
 
 'Packets per tick' this is not a useful specification
 since the tick's duration is unknown to the user.
 Depending on the platform you can have HZ ranging from 15-20 (on windows)
 to 10000 or even more. Normal values are 100, 250, 1000 but
 you just cannot know what you are going to get.
 
 Yes there are rounding issues, and yes it is boring to write
 code to handle them.
 
 luigi

From: "bycn82" <bycn82@gmail.com>
To: <bug-followup@FreeBSD.org>,
	<bycn82@gmail.com>
Cc: "Luigi Rizzo" <rizzo@iet.unipi.it>
Subject: Re: kern/189720: [ipfw] [patch] pps action for ipfw
Date: Sat, 31 May 2014 00:53:56 +0800

 This is a multipart message in MIME format.
 
 ------=_NextPart_000_0002_01CF7C6A.CF4B9B50
 Content-Type: multipart/alternative;
 	boundary="----=_NextPart_001_0003_01CF7C6A.CF4B9B50"
 
 
 ------=_NextPart_001_0003_01CF7C6A.CF4B9B50
 Content-Type: text/plain;
 	charset="utf-8"
 Content-Transfer-Encoding: 7bit
 
 1.       Add static int to store the value of kern.hz
 
 2.       Convert the duration into number of ticks based on  kern.hz
 
  
 
 regards,
 
 bycn82
 
 
 ------=_NextPart_001_0003_01CF7C6A.CF4B9B50
 Content-Type: text/html;
 	charset="utf-8"
 Content-Transfer-Encoding: quoted-printable
 
 <html xmlns:v=3D"urn:schemas-microsoft-com:vml" =
 xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
 xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
 xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" =
 xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta =
 http-equiv=3DContent-Type content=3D"text/html; charset=3Dutf-8"><meta =
 name=3DGenerator content=3D"Microsoft Word 14 (filtered =
 medium)"><style><!--
 /* Font Definitions */
 @font-face
 	{font-family:=E5=AE=8B=E4=BD=93;
 	panose-1:2 1 6 0 3 1 1 1 1 1;}
 @font-face
 	{font-family:=E5=AE=8B=E4=BD=93;
 	panose-1:2 1 6 0 3 1 1 1 1 1;}
 @font-face
 	{font-family:Calibri;
 	panose-1:2 15 5 2 2 2 4 3 2 4;}
 @font-face
 	{font-family:"\@=E5=AE=8B=E4=BD=93";
 	panose-1:2 1 6 0 3 1 1 1 1 1;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
 	{margin:0in;
 	margin-bottom:.0001pt;
 	font-size:11.0pt;
 	font-family:"Calibri","sans-serif";}
 a:link, span.MsoHyperlink
 	{mso-style-priority:99;
 	color:blue;
 	text-decoration:underline;}
 a:visited, span.MsoHyperlinkFollowed
 	{mso-style-priority:99;
 	color:purple;
 	text-decoration:underline;}
 p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
 	{mso-style-priority:34;
 	margin-top:0in;
 	margin-right:0in;
 	margin-bottom:0in;
 	margin-left:.5in;
 	margin-bottom:.0001pt;
 	font-size:11.0pt;
 	font-family:"Calibri","sans-serif";}
 span.EmailStyle17
 	{mso-style-type:personal-compose;
 	font-family:"Calibri","sans-serif";
 	color:windowtext;}
 .MsoChpDefault
 	{mso-style-type:export-only;
 	font-family:"Calibri","sans-serif";}
 @page WordSection1
 	{size:8.5in 11.0in;
 	margin:1.0in 1.25in 1.0in 1.25in;}
 div.WordSection1
 	{page:WordSection1;}
 /* List Definitions */
 @list l0
 	{mso-list-id:633340690;
 	mso-list-type:hybrid;
 	mso-list-template-ids:1182030700 67698703 67698713 67698715 67698703 =
 67698713 67698715 67698703 67698713 67698715;}
 @list l0:level1
 	{mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level2
 	{mso-level-number-format:alpha-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level3
 	{mso-level-number-format:roman-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:right;
 	text-indent:-9.0pt;}
 @list l0:level4
 	{mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level5
 	{mso-level-number-format:alpha-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level6
 	{mso-level-number-format:roman-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:right;
 	text-indent:-9.0pt;}
 @list l0:level7
 	{mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level8
 	{mso-level-number-format:alpha-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:left;
 	text-indent:-.25in;}
 @list l0:level9
 	{mso-level-number-format:roman-lower;
 	mso-level-tab-stop:none;
 	mso-level-number-position:right;
 	text-indent:-9.0pt;}
 ol
 	{margin-bottom:0in;}
 ul
 	{margin-bottom:0in;}
 --></style><!--[if gte mso 9]><xml>
 <o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
 </xml><![endif]--><!--[if gte mso 9]><xml>
 <o:shapelayout v:ext=3D"edit">
 <o:idmap v:ext=3D"edit" data=3D"1" />
 </o:shapelayout></xml><![endif]--></head><body lang=3DEN-US link=3Dblue =
 vlink=3Dpurple><div class=3DWordSection1><p class=3DMsoListParagraph =
 style=3D'text-indent:-.25in;mso-list:l0 level1 lfo1'><![if =
 !supportLists]><span style=3D'mso-list:Ignore'>1.<span =
 style=3D'font:7.0pt "Times New =
 Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><![endif]>Add =
 static int to store the value of kern.hz<o:p></o:p></p><p =
 class=3DMsoListParagraph style=3D'text-indent:-.25in;mso-list:l0 level1 =
 lfo1'><![if !supportLists]><span style=3D'mso-list:Ignore'>2.<span =
 style=3D'font:7.0pt "Times New =
 Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
 </span></span><![endif]>Convert the duration into number of ticks based =
 on =C2=A0kern.hz<o:p></o:p></p><p =
 class=3DMsoNormal><o:p>&nbsp;</o:p></p><p =
 class=3DMsoNormal>regards,<o:p></o:p></p><p =
 class=3DMsoNormal>bycn82<o:p></o:p></p></div></body></html>
 ------=_NextPart_001_0003_01CF7C6A.CF4B9B50--
 
 ------=_NextPart_000_0002_01CF7C6A.CF4B9B50
 Content-Type: application/octet-stream;
 	name="pps.patch"
 Content-Transfer-Encoding: quoted-printable
 Content-Disposition: attachment;
 	filename="pps.patch"
 
 Index: sbin/ipfw/ipfw.8=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sbin/ipfw/ipfw.8	(revision 266886)=0A=
 +++ sbin/ipfw/ipfw.8	(working copy)=0A=
 @@ -602,6 +602,14 @@=0A=
  Note: logging is done after all other packet matching conditions=0A=
  have been successfully verified, and before performing the final=0A=
  action (accept, deny, etc.) on the packet.=0A=
 +.It Cm pps Ar limit duration=0A=
 +Rule with the =0A=
 +.Cm pps=0A=
 +keyword will allow the first=0A=
 +.Ar limit=0A=
 +packets in recent =0A=
 +.Ar duration =0A=
 +milliseconds=0A=
  .It Cm tag Ar number=0A=
  When a packet matches a rule with the=0A=
  .Cm tag=0A=
 Index: sbin/ipfw/ipfw2.c=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sbin/ipfw/ipfw2.c	(revision 266886)=0A=
 +++ sbin/ipfw/ipfw2.c	(working copy)=0A=
 @@ -244,6 +244,7 @@=0A=
  	{ "allow",		TOK_ACCEPT },=0A=
  	{ "permit",		TOK_ACCEPT },=0A=
  	{ "count",		TOK_COUNT },=0A=
 +	{ "pps",		TOK_PPS },=0A=
  	{ "pipe",		TOK_PIPE },=0A=
  	{ "queue",		TOK_QUEUE },=0A=
  	{ "divert",		TOK_DIVERT },=0A=
 @@ -1232,6 +1233,13 @@=0A=
  			PRINT_UINT_ARG("skipto ", cmd->arg1);=0A=
  			break;=0A=
  =0A=
 +		case O_PPS:=0A=
 +			{=0A=
 +			ipfw_insn_pps *pps=3D(ipfw_insn_pps *)cmd;=0A=
 +			printf("pps %d %d",cmd->arg1,pps->duration);=0A=
 +			break;			=0A=
 +			}=0A=
 +=0A=
  		case O_PIPE:=0A=
  			PRINT_UINT_ARG("pipe ", cmd->arg1);=0A=
  			break;=0A=
 @@ -2985,6 +2993,24 @@=0A=
  	case TOK_COUNT:=0A=
  		action->opcode =3D O_COUNT;=0A=
  		break;=0A=
 +		=0A=
 +	case TOK_PPS:=0A=
 +		action->opcode =3D O_PPS;=0A=
 +		ipfw_insn_pps *p =3D (ipfw_insn_pps *)action;=0A=
 +		action->len =3D F_INSN_SIZE(ipfw_insn_pps);=0A=
 +		if (isdigit(**av)) {=0A=
 +			action->arg1 =3D strtoul(*av, NULL, 10);=0A=
 +			av++;=0A=
 +		}else{=0A=
 +			errx(EX_USAGE, "illegal argument pps `limit` %s", *av);=0A=
 +		}=0A=
 +		if (isdigit(**av)) {=0A=
 +			p->duration =3D strtoul(*av, NULL, 10);=0A=
 +			av++;=0A=
 +		}else{=0A=
 +			errx(EX_USAGE,"illegal arugment pps `duration` %s", *av);=0A=
 +		}=0A=
 +		break;	=0A=
  =0A=
  	case TOK_NAT:=0A=
  		action->opcode =3D O_NAT;=0A=
 Index: sbin/ipfw/ipfw2.h=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sbin/ipfw/ipfw2.h	(revision 266886)=0A=
 +++ sbin/ipfw/ipfw2.h	(working copy)=0A=
 @@ -92,6 +92,7 @@=0A=
  	TOK_NGTEE,=0A=
  	TOK_FORWARD,=0A=
  	TOK_SKIPTO,=0A=
 +	TOK_PPS,=0A=
  	TOK_DENY,=0A=
  	TOK_REJECT,=0A=
  	TOK_RESET,=0A=
 Index: sys/netinet/ip_fw.h=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sys/netinet/ip_fw.h	(revision 266886)=0A=
 +++ sys/netinet/ip_fw.h	(working copy)=0A=
 @@ -165,6 +165,7 @@=0A=
  	O_REJECT,		/* arg1=3Dicmp arg (same as deny)	*/=0A=
  	O_COUNT,		/* none				*/=0A=
  	O_SKIPTO,		/* arg1=3Dnext rule number	*/=0A=
 +	O_PPS,			/* arg1=3Dlimit, pps->duration */=0A=
  	O_PIPE,			/* arg1=3Dpipe number		*/=0A=
  	O_QUEUE,		/* arg1=3Dqueue number		*/=0A=
  	O_DIVERT,		/* arg1=3Dport number		*/=0A=
 @@ -378,6 +379,16 @@=0A=
  } ipfw_insn_log;=0A=
  =0A=
  /*=0A=
 + *	This is used for PPS=0A=
 + */=0A=
 +typedef struct _ipfw_insn_pps{=0A=
 +	ipfw_insn o;=0A=
 +	uint32_t start_time;=0A=
 +	uint32_t count;=0A=
 +	uint32_t duration;=0A=
 +} ipfw_insn_pps;=0A=
 +=0A=
 +/*=0A=
   * Data structures required by both ipfw(8) and ipfw(4) but not part of =
 the=0A=
   * management API are protected by IPFW_INTERNAL.=0A=
   */=0A=
 Index: sys/netpfil/ipfw/ip_fw2.c=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sys/netpfil/ipfw/ip_fw2.c	(revision 266886)=0A=
 +++ sys/netpfil/ipfw/ip_fw2.c	(working copy)=0A=
 @@ -124,6 +124,7 @@=0A=
  /* Use 128 tables by default */=0A=
  static unsigned int default_fw_tables =3D IPFW_TABLES_DEFAULT;=0A=
  =0A=
 +static unsigned int kern_hz=3D1000;=0A=
  /*=0A=
   * Each rule belongs to one of 32 different sets (0..31).=0A=
   * The variable set_disable contains one bit per set.=0A=
 @@ -186,6 +187,7 @@=0A=
  SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,=0A=
      CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,=0A=
      "Number of static rules");=0A=
 +TUNABLE_INT("kern.hz", (int *)&kern_hz);=0A=
  =0A=
  #ifdef INET6=0A=
  SYSCTL_DECL(_net_inet6_ip6);=0A=
 @@ -2189,6 +2191,31 @@=0A=
  			    continue;=0A=
  			    break;	/* not reached */=0A=
  =0A=
 +			case O_PPS:{=0A=
 +				int duration_in_ticks;=0A=
 +				ipfw_insn_pps *pps =3D (ipfw_insn_pps *)cmd;=0A=
 +				if(1000/kern_hz >=3D pps->duration){=0A=
 +					duration_in_ticks=3D1;=0A=
 +				}else{=0A=
 +					duration_in_ticks=3Dpps->duration*kern_hz/1000+1;=0A=
 +				}=0A=
 +				if(pps->start_time+duration_in_ticks>=3D ticks){=0A=
 +					if(pps->count < cmd->arg1){=0A=
 +						retval =3D IP_FW_PASS;=0A=
 +					}else{=0A=
 +						retval =3D IP_FW_DENY;=0A=
 +					}=0A=
 +					pps->count++;=0A=
 +				}else{=0A=
 +					pps->start_time=3Dticks;=0A=
 +					pps->count=3D1;=0A=
 +					retval =3D IP_FW_PASS;=0A=
 +				}=0A=
 +				l =3D 0;		=0A=
 +				done =3D 1;=0A=
 +				break;	=0A=
 +			}=0A=
 +=0A=
  			case O_CALLRETURN: {=0A=
  				/*=0A=
  				 * Implementation of `subroutine' call/return,=0A=
 Index: sys/netpfil/ipfw/ip_fw_sockopt.c=0A=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
 --- sys/netpfil/ipfw/ip_fw_sockopt.c	(revision 266886)=0A=
 +++ sys/netpfil/ipfw/ip_fw_sockopt.c	(working copy)=0A=
 @@ -703,6 +703,12 @@=0A=
  				goto bad_size;=0A=
  			break;=0A=
  =0A=
 +		case O_PPS:=0A=
 +			have_action=3D1;=0A=
 +			if (cmdlen !=3D F_INSN_SIZE(ipfw_insn_pps))=0A=
 +				goto bad_size;=0A=
 +			break;=0A=
 +=0A=
  		case O_PIPE:=0A=
  		case O_QUEUE:=0A=
  			if (cmdlen !=3D F_INSN_SIZE(ipfw_insn))=0A=
 
 ------=_NextPart_000_0002_01CF7C6A.CF4B9B50--
 

From: Luigi Rizzo <rizzo@iet.unipi.it>
To: bycn82 <bycn82@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/189720: [ipfw] [patch] pps action for ipfw
Date: Fri, 30 May 2014 19:16:10 +0200

 On Sat, May 31, 2014 at 12:53:56AM +0800, bycn82 wrote:
 > 1.       Add static int to store the value of kern.hz
 
 this is unnecessary. There is already a global variable
 called "hz" which contains the correct information
 
 > 2.       Convert the duration into number of ticks based on  kern.hz
 
 this is done incorrectly.
 
 First, hz does not change at runtime so it is unnecessary to recompute
 the duration on every instace, even more since this is costing you
 one division.  You should adjust the value when the rule is injected
 in the kernel, perhaps adding a couple of fields in the rule
 so you can store the adjusted duration and threshold (see below).
 
 Second, you are still not doing the rounding correctly.
 When the requested interval is shorter than a tick, you adjust the
 interval but leave the limit unchanged, which means you are reducing
 the limit below what the user wants.
 Instead you should correct the limit so that it approximates
 the desired rate; one above or one below is not a problem,
 but your code might be off by a very large factor.
 
 BTW even in the other case you are always adding 1 tick unconditionally.
 A correct way to do the rounding is (pps->duration * hz + 999)/1000
 (and then again adjust the count according to the actual duration)
 
 cheers
 luigi
>Unformatted:
