Index: src/sbin/ipfw/ipfw.8 =================================================================== RCS file: /ncvs/src/sbin/ipfw/ipfw.8,v retrieving revision 1.211 diff -u -b -p -r1.211 ipfw.8 --- src/sbin/ipfw/ipfw.8 27 Feb 2008 13:52:33 -0000 1.211 +++ src/sbin/ipfw/ipfw.8 17 Mar 2008 20:48:13 -0000 @@ -1104,6 +1104,14 @@ action followed by the comment. .It Cm bridged Alias for .Cm layer2 . +.It Bro Cm counterlimit-bytes | counterlimit-packets Brc Ar number +Matches packets until rule counter (byte or packet) is lower than +specified +.Ar number . +Also it can be specified with suffix +.Sm off +.Op Cm K | M | G . +.Sm on .It Cm diverted Matches only packets generated by a divert socket. .It Cm diverted-loopback Index: src/sbin/ipfw/ipfw2.c =================================================================== RCS file: /ncvs/src/sbin/ipfw/ipfw2.c,v retrieving revision 1.118 diff -u -b -p -r1.118 ipfw2.c --- src/sbin/ipfw/ipfw2.c 27 Feb 2008 13:52:33 -0000 1.118 +++ src/sbin/ipfw/ipfw2.c 17 Mar 2008 20:48:13 -0000 @@ -341,6 +341,9 @@ enum tokens { TOK_IPV4, TOK_UNREACH6, TOK_RESET6, + + TOK_COUNTERLIMIT_BYTES, + TOK_COUNTERLIMIT_PACKETS, }; struct _s_x dummynet_params[] = { @@ -489,6 +492,8 @@ struct _s_x rule_options[] = { { "dst-ip6", TOK_DSTIP6}, { "src-ipv6", TOK_SRCIP6}, { "src-ip6", TOK_SRCIP6}, + { "counterlimit-bytes", TOK_COUNTERLIMIT_BYTES }, + { "counterlimit-packets", TOK_COUNTERLIMIT_PACKETS }, { "//", TOK_COMMENT }, { "not", TOK_NOT }, /* pseudo option */ @@ -2029,6 +2034,13 @@ show_ipfw(struct ip_fw *rule, int pcwidt O_TAGGED); break; + case O_COUNTERLIMIT: + printf(" counterlimit-%s %llu", + (cmd->arg1 == COUNTERLIMIT_BYTES) ? + "bytes":"packets", + ((ipfw_insn_u64 *)cmd)->d[0]); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -2732,6 +2744,7 @@ help(void) " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" +" counterlimit-bytes VALUE | counterlimit-packets VALUE\n" ); exit(0); } @@ -5625,7 +5638,27 @@ read_options: } ac--; av++; break; + case TOK_COUNTERLIMIT_BYTES: + case TOK_COUNTERLIMIT_PACKETS: { + NEED1("counterlimit requires numeric value"); + char *end = NULL; + uint64_t limit = strtoull(*av, &end, 0); + + if (limit) + switch(*end) { + case 'G': limit *= 1024; + case 'M': limit *= 1024; + case 'K': limit *= 1024; + }; + cmd->opcode = O_COUNTERLIMIT; + cmd->len = F_INSN_SIZE(ipfw_insn_u64); + cmd->arg1 = (i == TOK_COUNTERLIMIT_BYTES) ? + COUNTERLIMIT_BYTES: COUNTERLIMIT_PACKETS; + ((ipfw_insn_u64 *)cmd)->d[0] = limit; + ac--; av++; + break; + } default: errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } Index: src/sys/netinet/ip_fw.h =================================================================== RCS file: /ncvs/src/sys/netinet/ip_fw.h,v retrieving revision 1.112 diff -u -b -p -r1.112 ip_fw.h --- src/sys/netinet/ip_fw.h 29 Feb 2008 22:27:19 -0000 1.112 +++ src/sys/netinet/ip_fw.h 17 Mar 2008 20:48:16 -0000 @@ -161,6 +161,8 @@ enum ipfw_opcodes { /* arguments (4 byt O_TAG, /* arg1=tag number */ O_TAGGED, /* arg1=tag number */ + O_COUNTERLIMIT, /* u64 = counter limit */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -241,6 +243,19 @@ typedef struct _ipfw_insn_u32 { } ipfw_insn_u32; /* + * This is used to store an array of 64-bit entries + * (counter limits) + */ +typedef struct _ipfw_insn_u64 { + ipfw_insn o; + u_int64_t d[1]; /* one or more */ +} ipfw_insn_u64; + +/* Counter limits modes */ +#define COUNTERLIMIT_BYTES 0x0 +#define COUNTERLIMIT_PACKETS 0x1 + +/* * This is used to store IP addr-mask pairs. */ typedef struct _ipfw_insn_ip { Index: src/sys/netinet/ip_fw2.c =================================================================== RCS file: /ncvs/src/sys/netinet/ip_fw2.c,v retrieving revision 1.182 diff -u -b -p -r1.182 ip_fw2.c --- src/sys/netinet/ip_fw2.c 29 Feb 2008 22:27:19 -0000 1.182 +++ src/sys/netinet/ip_fw2.c 17 Mar 2008 20:48:16 -0000 @@ -3072,6 +3072,13 @@ check_body: } break; } + case O_COUNTERLIMIT: { + if (cmd->arg1 == COUNTERLIMIT_BYTES) + match = (f->bcnt < ((ipfw_insn_u64 *)cmd)->d[0]); + else + match = (f->pcnt < ((ipfw_insn_u64 *)cmd)->d[0]); + break; + } /* * The second set of opcodes represents 'actions', @@ -3884,6 +3891,17 @@ check_ipfw_struct(struct ip_fw *rule, in goto bad_size; break; + case O_COUNTERLIMIT: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u64)) + goto bad_size; + if (cmd->arg1 != COUNTERLIMIT_BYTES && + cmd->arg1 != COUNTERLIMIT_PACKETS) { + printf("ipfw: invalid counterlimit mode %d\n", + cmd->arg1); + return (EINVAL); + } + break; + case O_PIPE: case O_QUEUE: if (cmdlen != F_INSN_SIZE(ipfw_insn))