Add a new feature for optimizining ipfw rulesets - substitution of the

action argument with the value obtained from table lookup. The feature
is now applicable only to "pipe", "queue", "divert", "tee", "netgraph"
and "ngtee" rules.

An example usage:

  ipfw pipe 1000 config bw 1000Kbyte/s
  ipfw pipe 4000 config bw 4000Kbyte/s
  ipfw table 1 add x.x.x.x 1000
  ipfw table 1 add x.x.x.y 4000
  ipfw pipe tablearg ip from table(1) to any

In the example above the rule will throw different packets to different pipes.

TODO:
  - Support "skipto" action, but without searching all rules.
  - Improve parser, so that it warns about bad rules. These are:
    - "tablearg" argument to action, but no "table" in the rule. All
      traffic will be blocked.
    - "tablearg" argument to action, but "table" searches for entry with
      a specific value. All traffic will be blocked.
    - "tablearg" argument to action, and two "table" looks - for src and
      for dst. The last lookup will match.
This commit is contained in:
Gleb Smirnoff 2005-12-13 12:16:03 +00:00
parent 2778b70e71
commit 40b1ae9e00
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=153374
3 changed files with 63 additions and 52 deletions

View File

@ -420,6 +420,8 @@ struct _s_x rule_options[] = {
{ NULL, 0 } /* terminator */ { NULL, 0 } /* terminator */
}; };
#define TABLEARG "tablearg"
static __inline uint64_t static __inline uint64_t
align_uint64(uint64_t *pll) { align_uint64(uint64_t *pll) {
uint64_t ret; uint64_t ret;
@ -1457,33 +1459,28 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
print_unreach6_code(cmd->arg1); print_unreach6_code(cmd->arg1);
break; break;
#define PRINT_WITH_ARG(o) \
if (cmd->arg1 == IP_FW_TABLEARG) \
printf("%s tablearg", (o)); \
else \
printf("%s %u", (o), cmd->arg1); \
break;
case O_SKIPTO: case O_SKIPTO:
printf("skipto %u", cmd->arg1); PRINT_WITH_ARG("skipto");
break;
case O_PIPE: case O_PIPE:
printf("pipe %u", cmd->arg1); PRINT_WITH_ARG("pipe");
break;
case O_QUEUE: case O_QUEUE:
printf("queue %u", cmd->arg1); PRINT_WITH_ARG("queue");
break;
case O_DIVERT: case O_DIVERT:
printf("divert %u", cmd->arg1); PRINT_WITH_ARG("divert");
break;
case O_TEE: case O_TEE:
printf("tee %u", cmd->arg1); PRINT_WITH_ARG("tee");
break;
case O_NETGRAPH: case O_NETGRAPH:
printf("netgraph %u", cmd->arg1); PRINT_WITH_ARG("netgraph");
break;
case O_NGTEE: case O_NGTEE:
printf("ngtee %u", cmd->arg1); PRINT_WITH_ARG("ngtee");
break; #undef PRINT_WITH_ARG
case O_FORWARD_IP: case O_FORWARD_IP:
{ {
@ -3863,26 +3860,36 @@ add(int ac, char *av[])
break; break;
case TOK_QUEUE: case TOK_QUEUE:
action->opcode = O_QUEUE;
goto chkarg;
case TOK_PIPE: case TOK_PIPE:
action->len = F_INSN_SIZE(ipfw_insn); action->opcode = O_PIPE;
goto chkarg;
case TOK_SKIPTO: case TOK_SKIPTO:
if (i == TOK_QUEUE) action->opcode = O_SKIPTO;
action->opcode = O_QUEUE; goto chkarg;
else if (i == TOK_PIPE) case TOK_NETGRAPH:
action->opcode = O_PIPE; action->opcode = O_NETGRAPH;
else if (i == TOK_SKIPTO) goto chkarg;
action->opcode = O_SKIPTO; case TOK_NGTEE:
NEED1("missing skipto/pipe/queue number"); action->opcode = O_NGTEE;
action->arg1 = strtoul(*av, NULL, 10); goto chkarg;
av++; ac--;
break;
case TOK_DIVERT: case TOK_DIVERT:
action->opcode = O_DIVERT;
goto chkarg;
case TOK_TEE: case TOK_TEE:
action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; action->opcode = O_TEE;
NEED1("missing divert/tee port"); chkarg:
action->arg1 = strtoul(*av, NULL, 0); if (!ac)
if (action->arg1 == 0) { errx(EX_USAGE, "missing argument for %s", *(av - 1));
if (isdigit(**av)) {
action->arg1 = strtoul(*av, NULL, 10);
if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG)
errx(EX_DATAERR, "illegal argument for %s",
*(av - 1));
} else if (_substrcmp(*av, TABLEARG) == 0) {
action->arg1 = IP_FW_TABLEARG;
} else if (i == TOK_DIVERT || i == TOK_TEE) {
struct servent *s; struct servent *s;
setservent(1); setservent(1);
s = getservbyname(av[0], "divert"); s = getservbyname(av[0], "divert");
@ -3890,17 +3897,8 @@ add(int ac, char *av[])
action->arg1 = ntohs(s->s_port); action->arg1 = ntohs(s->s_port);
else else
errx(EX_DATAERR, "illegal divert/tee port"); errx(EX_DATAERR, "illegal divert/tee port");
} } else
ac--; av++; errx(EX_DATAERR, "illegal argument for %s", *(av - 1));
break;
case TOK_NETGRAPH:
case TOK_NGTEE:
action->opcode = (i == TOK_NETGRAPH ) ? O_NETGRAPH : O_NGTEE;
NEED1("missing netgraph cookie");
action->arg1 = strtoul(*av, NULL, 0);
if (action->arg1 == 0)
errx(EX_DATAERR, "illegal netgraph cookie");
ac--; av++; ac--; av++;
break; break;

View File

@ -461,6 +461,8 @@ typedef struct _ipfw_table {
ipfw_table_entry ent[0]; /* entries */ ipfw_table_entry ent[0]; /* entries */
} ipfw_table; } ipfw_table;
#define IP_FW_TABLEARG 65535
/* /*
* Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions.
*/ */

View File

@ -2383,9 +2383,9 @@ do { \
* Now scan the rules, and parse microinstructions for each rule. * Now scan the rules, and parse microinstructions for each rule.
*/ */
for (; f; f = f->next) { for (; f; f = f->next) {
int l, cmdlen;
ipfw_insn *cmd; ipfw_insn *cmd;
int skip_or; /* skip rest of OR block */ uint32_t tablearg = 0;
int l, cmdlen, skip_or; /* skip rest of OR block */
again: again:
if (set_disable & (1 << f->set) ) if (set_disable & (1 << f->set) )
@ -2548,6 +2548,8 @@ do { \
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = match =
((ipfw_insn_u32 *)cmd)->d[0] == v; ((ipfw_insn_u32 *)cmd)->d[0] == v;
else
tablearg = v;
} }
break; break;
@ -2999,7 +3001,10 @@ do { \
case O_PIPE: case O_PIPE:
case O_QUEUE: case O_QUEUE:
args->rule = f; /* report matching rule */ args->rule = f; /* report matching rule */
args->cookie = cmd->arg1; if (cmd->arg1 == IP_FW_TABLEARG)
args->cookie = tablearg;
else
args->cookie = cmd->arg1;
retval = IP_FW_DUMMYNET; retval = IP_FW_DUMMYNET;
goto done; goto done;
@ -3020,7 +3025,10 @@ do { \
} }
dt = (struct divert_tag *)(mtag+1); dt = (struct divert_tag *)(mtag+1);
dt->cookie = f->rulenum; dt->cookie = f->rulenum;
dt->info = cmd->arg1; if (cmd->arg1 == IP_FW_TABLEARG)
dt->info = tablearg;
else
dt->info = cmd->arg1;
m_tag_prepend(m, mtag); m_tag_prepend(m, mtag);
retval = (cmd->opcode == O_DIVERT) ? retval = (cmd->opcode == O_DIVERT) ?
IP_FW_DIVERT : IP_FW_TEE; IP_FW_DIVERT : IP_FW_TEE;
@ -3085,7 +3093,10 @@ do { \
case O_NETGRAPH: case O_NETGRAPH:
case O_NGTEE: case O_NGTEE:
args->rule = f; /* report matching rule */ args->rule = f; /* report matching rule */
args->cookie = cmd->arg1; if (cmd->arg1 == IP_FW_TABLEARG)
args->cookie = tablearg;
else
args->cookie = cmd->arg1;
retval = (cmd->opcode == O_NETGRAPH) ? retval = (cmd->opcode == O_NETGRAPH) ?
IP_FW_NETGRAPH : IP_FW_NGTEE; IP_FW_NETGRAPH : IP_FW_NGTEE;
goto done; goto done;