svn commit: r269348 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Thu Jul 31 20:08:21 UTC 2014
Author: melifaro
Date: Thu Jul 31 20:08:19 2014
New Revision: 269348
URL: http://svnweb.freebsd.org/changeset/base/269348
Log:
* Add new "flow" table type to support N=1..5-tuple lookups
* Add "flow:hash" algorithm
Kernel changes:
* Add O_IP_FLOW_LOOKUP opcode to support "flow" lookups
* Add IPFW_TABLE_FLOW table type
* Add "struct tflow_entry" as strage for 6-tuple flows
* Add "flow:hash" algorithm. Basically it is auto-growing chained hash table.
Additionally, we store mask of fields we need to compare in each instance/
* Increase ipfw_obj_tentry size by adding struct tflow_entry
* Add per-algorithm stat (ifpw_ta_tinfo) to ipfw_xtable_info
* Increase algoname length: 32 -> 64 (algo options passed there as string)
* Assume every table type can be customized by flags, use u8 to store "tflags" field.
* Simplify ipfw_find_table_entry() by providing @tentry directly to algo callback.
* Fix bug in cidr:chash resize procedure.
Userland changes:
* add "flow table(NAME)" syntax to support n-tuple checking tables.
* make fill_flags() separate function to ease working with _s_x arrays
* change "table info" output to reflect longer "type" fields
Syntax:
ipfw table fl2 create type flow:[src-ip][,proto][,src-port][,dst-ip][dst-port] [algo flow:hash]
Examples:
0:02 [2] zfscurr0# ipfw table fl2 create type flow:src-ip,proto,dst-port algo flow:hash
0:02 [2] zfscurr0# ipfw table fl2 info
+++ table(fl2), set(0) +++
kindex: 0, type: flow:src-ip,proto,dst-port
valtype: number, references: 0
algorithm: flow:hash
items: 0, size: 280
0:02 [2] zfscurr0# ipfw table fl2 add 2a02:6b8::333,tcp,443 45000
0:02 [2] zfscurr0# ipfw table fl2 add 10.0.0.92,tcp,80 22000
0:02 [2] zfscurr0# ipfw table fl2 list
+++ table(fl2), set(0) +++
2a02:6b8::333,6,443 45000
10.0.0.92,6,80 22000
0:02 [2] zfscurr0# ipfw add 200 count tcp from me to 78.46.89.105 80 flow 'table(fl2)'
00200 count tcp from me to 78.46.89.105 dst-port 80 flow table(fl2)
0:03 [2] zfscurr0# ipfw show
00200 0 0 count tcp from me to 78.46.89.105 dst-port 80 flow table(fl2)
65535 617 59416 allow ip from any to any
0:03 [2] zfscurr0# telnet -s 10.0.0.92 78.46.89.105 80
Trying 78.46.89.105...
..
0:04 [2] zfscurr0# ipfw show
00200 5 272 count tcp from me to 78.46.89.105 dst-port 80 flow table(fl2)
65535 682 66733 allow ip from any to any
Modified:
projects/ipfw/sbin/ipfw/ipfw2.c
projects/ipfw/sbin/ipfw/ipfw2.h
projects/ipfw/sbin/ipfw/tables.c
projects/ipfw/sys/netinet/ip_fw.h
projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sbin/ipfw/ipfw2.c Thu Jul 31 20:08:19 2014 (r269348)
@@ -364,6 +364,7 @@ static struct _s_x rule_options[] = {
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
{ "lookup", TOK_LOOKUP},
+ { "flow", TOK_FLOW},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -707,6 +708,54 @@ concat_tokens(char *buf, size_t bufsize,
}
/*
+ * helper function to process a set of flags and set bits in the
+ * appropriate masks.
+ */
+void
+fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear)
+{
+ char *q; /* points to the separator */
+ int val;
+ uint8_t *which; /* mask we are working on */
+
+ while (p && *p) {
+ if (*p == '!') {
+ p++;
+ which = clear;
+ } else
+ which = set;
+ q = strchr(p, ',');
+ if (q)
+ *q++ = '\0';
+ val = match_token(flags, p);
+ if (val <= 0)
+ errx(EX_DATAERR, "invalid flag %s", p);
+ *which |= (uint8_t)val;
+ p = q;
+ }
+}
+
+void
+print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set)
+{
+ char const *comma = "";
+ int i, l;
+
+ for (i = 0; list[i].x != 0; i++) {
+ if ((set & list[i].x) == 0)
+ continue;
+
+ set &= ~list[i].x;
+ l = snprintf(buf, sz, "%s%s", comma, list[i].s);
+ if (l >= sz)
+ return;
+ comma = ",";
+ buf += l;
+ sz -=l;
+ }
+}
+
+/*
* _substrcmp takes two strings and returns 1 if they do not match,
* and 0 if they match exactly or the first string is a sub-string
* of the second. A warning is printed to stderr in the case that the
@@ -1087,6 +1136,7 @@ print_flags(char const *name, ipfw_insn
}
}
+
/*
* Print the ip address contained in a command.
*/
@@ -1795,6 +1845,18 @@ show_static_rule(struct cmdline_opts *co
break;
}
+ case O_IP_FLOW_LOOKUP:
+ {
+ char *t;
+
+ t = table_search_ctlv(fo->tstate, cmd->arg1);
+ printf(" flow table(%s", t);
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))
+ printf(",%u",
+ ((ipfw_insn_u32 *)cmd)->d[0]);
+ printf(")");
+ break;
+ }
case O_IPID:
if (F_LEN(cmd) == 1)
printf(" ipid %u", cmd->arg1 );
@@ -2660,6 +2722,33 @@ pack_table(struct tidx *tstate, char *na
return (ntlv->idx);
}
+static void
+fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate)
+{
+ uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
+ uint16_t uidx;
+ char *p;
+
+ if ((p = strchr(av + 6, ')')) == NULL)
+ errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
+ *p = '\0';
+ p = strchr(av + 6, ',');
+ if (p)
+ *p++ = '\0';
+
+ if ((uidx = pack_table(tstate, av + 6, 0)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", av + 6);
+
+ cmd->opcode = opcode;
+ cmd->arg1 = uidx;
+ if (p) {
+ cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
+ d[0] = strtoul(p, NULL, 0);
+ } else
+ cmd->len |= F_INSN_SIZE(ipfw_insn);
+}
+
+
/*
* fills the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
@@ -2676,8 +2765,6 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int
{
int len = 0;
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
- uint16_t uidx;
- char *p;
cmd->o.len &= ~F_LEN_MASK; /* zero len */
@@ -2690,23 +2777,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int
}
if (strncmp(av, "table(", 6) == 0) {
- if ((p = strchr(av + 6, ')')) == NULL)
- errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
- *p = '\0';
- p = strchr(av + 6, ',');
- if (p)
- *p++ = '\0';
-
- if ((uidx = pack_table(tstate, av + 6, 0)) == 0)
- errx(EX_DATAERR, "Invalid table name: %s", av + 6);
-
- cmd->o.opcode = O_IP_DST_LOOKUP;
- cmd->o.arg1 = uidx;
- if (p) {
- cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
- d[0] = strtoul(p, NULL, 0);
- } else
- cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate);
return;
}
@@ -2887,35 +2958,14 @@ n2mask(struct in6_addr *mask, int n)
return;
}
-/*
- * helper function to process a set of flags and set bits in the
- * appropriate masks.
- */
static void
-fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
+fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode,
struct _s_x *flags, char *p)
{
- uint8_t set=0, clear=0;
+ uint8_t set = 0, clear = 0;
- while (p && *p) {
- char *q; /* points to the separator */
- int val;
- uint8_t *which; /* mask we are working on */
+ fill_flags(flags, p, &set, &clear);
- if (*p == '!') {
- p++;
- which = &clear;
- } else
- which = &set;
- q = strchr(p, ',');
- if (q)
- *q++ = '\0';
- val = match_token(flags, p);
- if (val <= 0)
- errx(EX_DATAERR, "invalid flag %s", p);
- *which |= (uint8_t)val;
- p = q;
- }
cmd->opcode = opcode;
cmd->len = (cmd->len & (F_NOT | F_OR)) | 1;
cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);
@@ -4087,13 +4137,13 @@ read_options:
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
- fill_flags(cmd, O_IPOPT, f_ipopts, *av);
+ fill_flags_cmd(cmd, O_IPOPT, f_ipopts, *av);
av++;
break;
case TOK_IPTOS:
NEED1("missing argument for iptos");
- fill_flags(cmd, O_IPTOS, f_iptos, *av);
+ fill_flags_cmd(cmd, O_IPTOS, f_iptos, *av);
av++;
break;
@@ -4171,7 +4221,7 @@ read_options:
case TOK_TCPOPTS:
NEED1("missing argument for tcpoptions");
- fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
+ fill_flags_cmd(cmd, O_TCPOPTS, f_tcpopts, *av);
av++;
break;
@@ -4198,7 +4248,7 @@ read_options:
case TOK_TCPFLAGS:
NEED1("missing argument for tcpflags");
cmd->opcode = O_TCPFLAGS;
- fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
+ fill_flags_cmd(cmd, O_TCPFLAGS, f_tcpflags, *av);
av++;
break;
@@ -4407,6 +4457,14 @@ read_options:
av++;
}
break;
+ case TOK_FLOW:
+ NEED1("missing table name");
+ if (strncmp(*av, "table(", 6) != 0)
+ errx(EX_DATAERR,
+ "enclose table name into \"table()\"");
+ fill_table(cmd, *av, O_IP_FLOW_LOOKUP, tstate);
+ av++;
+ break;
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
Modified: projects/ipfw/sbin/ipfw/ipfw2.h
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.h Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sbin/ipfw/ipfw2.h Thu Jul 31 20:08:19 2014 (r269348)
@@ -217,6 +217,7 @@ enum tokens {
TOK_DEL,
TOK_VALTYPE,
TOK_ALGO,
+ TOK_FLOW,
};
/*
* the following macro returns an error message if we run out of
@@ -253,6 +254,10 @@ int match_token(struct _s_x *table, char
char const *match_value(struct _s_x *p, int value);
size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
char *delimiter);
+void fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear);
+void print_flags(char const *name, struct _s_x *list, uint8_t set,
+ uint8_t clear);
+void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set);
struct _ip_fw3_opheader;
int do_cmd(int optname, void *optval, uintptr_t optlen);
Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sbin/ipfw/tables.c Thu Jul 31 20:08:19 2014 (r269348)
@@ -83,6 +83,7 @@ static struct _s_x tabletypes[] = {
{ "cidr", IPFW_TABLE_CIDR },
{ "iface", IPFW_TABLE_INTERFACE },
{ "number", IPFW_TABLE_NUMBER },
+ { "flow", IPFW_TABLE_FLOW },
{ NULL, 0 }
};
@@ -256,6 +257,59 @@ static struct _s_x tablenewcmds[] = {
{ NULL, 0 }
};
+static struct _s_x flowtypecmds[] = {
+ { "src-ip", IPFW_TFFLAG_SRCIP },
+ { "proto", IPFW_TFFLAG_PROTO },
+ { "src-port", IPFW_TFFLAG_SRCPORT },
+ { "dst-ip", IPFW_TFFLAG_DSTIP },
+ { "dst-port", IPFW_TFFLAG_DSTPORT },
+ { NULL, 0 }
+};
+
+int
+table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
+{
+ uint8_t fset, fclear;
+
+ /* Parse type options */
+ switch(ttype) {
+ case IPFW_TABLE_FLOW:
+ fset = fclear = 0;
+ fill_flags(flowtypecmds, p, &fset,
+ &fclear);
+ *tflags = fset;
+ break;
+ default:
+ return (EX_USAGE);
+ }
+
+ return (0);
+}
+
+void
+table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
+{
+ const char *tname;
+ int l;
+
+ if ((tname = match_value(tabletypes, type)) == NULL)
+ tname = "unknown";
+
+ l = snprintf(tbuf, size, "%s", tname);
+ tbuf += l;
+ size -= l;
+
+ switch(type) {
+ case IPFW_TABLE_FLOW:
+ if (tflags != 0) {
+ *tbuf++ = ':';
+ l--;
+ print_flags_buffer(tbuf, size, flowtypecmds, tflags);
+ }
+ break;
+ }
+}
+
/*
* Creates new table
*
@@ -271,6 +325,7 @@ table_create(ipfw_obj_header *oh, int ac
ipfw_xtable_info xi;
int error, tcmd, val;
size_t sz;
+ char *p;
char tbuf[128];
sz = sizeof(tbuf);
@@ -288,15 +343,25 @@ table_create(ipfw_obj_header *oh, int ac
switch (tcmd) {
case TOK_TYPE:
NEED1("table type required");
+ /* Type may have suboptions after ':' */
+ if ((p = strchr(*av, ':')) != NULL)
+ *p++ = '\0';
val = match_token(tabletypes, *av);
- if (val != -1) {
- xi.type = val;
- ac--; av++;
- break;
+ if (val == -1) {
+ concat_tokens(tbuf, sizeof(tbuf), tabletypes,
+ ", ");
+ errx(EX_USAGE,
+ "Unknown tabletype: %s. Supported: %s",
+ *av, tbuf);
}
- concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", ");
- errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s",
- *av, tbuf);
+ xi.type = val;
+ if (p != NULL) {
+ error = table_parse_type(val, p, &xi.tflags);
+ if (error != 0)
+ errx(EX_USAGE,
+ "Unsupported suboptions: %s", p);
+ }
+ ac--; av++;
break;
case TOK_VALTYPE:
NEED1("table value type required");
@@ -408,15 +473,15 @@ table_get_info(ipfw_obj_header *oh, ipfw
static int
table_show_info(ipfw_xtable_info *i, void *arg)
{
- const char *ttype, *vtype;
+ const char *vtype;
+ char ttype[64];
- printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
- if ((ttype = match_value(tabletypes, i->type)) == NULL)
- ttype = "unknown";
+ table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
vtype = "unknown";
- printf(" type: %s, kindex: %d\n", ttype, i->kidx);
+ printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
+ printf(" kindex: %d, type: %s\n", i->kidx, ttype);
printf(" valtype: %s, references: %u\n", vtype, i->refcnt);
printf(" algorithm: %s\n", i->algoname);
printf(" items: %u, size: %u\n", i->count, i->size);
@@ -575,12 +640,15 @@ table_lookup(ipfw_obj_header *oh, int ac
{
ipfw_obj_tentry xtent;
ipfw_xtable_info xi;
+ char key[64];
int error;
if (ac == 0)
errx(EX_USAGE, "address required");
- error = table_do_lookup(oh, *av, &xi, &xtent);
+ strlcpy(key, *av, sizeof(key));
+
+ error = table_do_lookup(oh, key, &xi, &xtent);
switch (error) {
case 0:
@@ -600,12 +668,17 @@ table_lookup(ipfw_obj_header *oh, int ac
}
static void
-tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
+tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
+ uint8_t tflags)
{
- char *p;
+ char *p, *pp;
int mask, af;
- struct in6_addr *paddr;
+ struct in6_addr *paddr, tmp;
+ struct tflow_entry *tfe;
uint32_t key, *pkey;
+ uint16_t port;
+ struct protoent *pent;
+ struct servent *sent;
int masklen;
masklen = 0;
@@ -664,6 +737,117 @@ tentry_fill_key_type(char *arg, ipfw_obj
*pkey = key;
masklen = 32;
break;
+ case IPFW_TABLE_FLOW:
+ /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
+ tfe = &tentry->k.flow;
+ af = 0;
+
+ /* Handle <ipv4|ipv6>*/
+ if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+ /* Determine family using temporary storage */
+ if (inet_pton(AF_INET, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET)
+ errx(EX_DATAERR,
+ "Inconsistent address family\n");
+ af = AF_INET;
+ memcpy(&tfe->a.a4.sip, &tmp, 4);
+ } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET6)
+ errx(EX_DATAERR,
+ "Inconsistent address family\n");
+ af = AF_INET6;
+ memcpy(&tfe->a.a6.sip6, &tmp, 16);
+ }
+
+ arg = p;
+ }
+
+ /* Handle <proto-num|proto-name> */
+ if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ key = strtol(arg, &pp, 10);
+ if (*pp != '\0') {
+ if ((pent = getprotobyname(arg)) == NULL)
+ errx(EX_DATAERR, "Unknown proto: %s",
+ arg);
+ else
+ key = pent->p_proto;
+ }
+
+ if (key > 255)
+ errx(EX_DATAERR, "Bad protocol number: %u",key);
+
+ tfe->proto = key;
+
+ arg = p;
+ }
+
+ /* Handle <port-num|service-name> */
+ if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ if ((port = htons(strtol(arg, NULL, 10))) == 0) {
+ if ((sent = getservbyname(arg, NULL)) == NULL)
+ errx(EX_DATAERR, "Unknown service: %s",
+ arg);
+ else
+ key = sent->s_port;
+ }
+
+ tfe->sport = port;
+
+ arg = p;
+ }
+
+ /* Handle <ipv4|ipv6>*/
+ if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+ /* Determine family using temporary storage */
+ if (inet_pton(AF_INET, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET)
+ errx(EX_DATAERR,
+ "Inconsistent address family");
+ af = AF_INET;
+ memcpy(&tfe->a.a4.dip, &tmp, 4);
+ } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET6)
+ errx(EX_DATAERR,
+ "Inconsistent address family");
+ af = AF_INET6;
+ memcpy(&tfe->a.a6.dip6, &tmp, 16);
+ }
+
+ arg = p;
+ }
+
+ /* Handle <port-num|service-name> */
+ if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ if ((port = htons(strtol(arg, NULL, 10))) == 0) {
+ if ((sent = getservbyname(arg, NULL)) == NULL)
+ errx(EX_DATAERR, "Unknown service: %s",
+ arg);
+ else
+ key = sent->s_port;
+ }
+
+ tfe->dport = port;
+
+ arg = p;
+ }
+
+ tfe->af = af;
+
+ break;
+
default:
errx(EX_DATAERR, "Unsupported table type: %d", type);
}
@@ -676,11 +860,12 @@ static void
tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
{
- uint8_t type, vtype;
+ uint8_t type, tflags, vtype;
int error;
char *del;
type = 0;
+ tflags = 0;
vtype = 0;
error = table_get_info(oh, xi);
@@ -688,6 +873,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
if (error == 0) {
/* Table found. */
type = xi->type;
+ tflags = xi->tflags;
vtype = xi->vtype;
} else {
if (error != ESRCH)
@@ -718,7 +904,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
*del = '/';
}
- tentry_fill_key_type(key, tent, type);
+ tentry_fill_key_type(key, tent, type, tflags);
*ptype = type;
*pvtype = vtype;
@@ -874,41 +1060,75 @@ table_show_list(ipfw_obj_header *oh, int
static void
table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
{
- char tbuf[128];
+ char *comma, tbuf[128], pval[32];
+ void *paddr;
uint32_t tval;
+ struct tflow_entry *tfe;
tval = tent->value;
+ if (co.do_value_as_ip) {
+ tval = htonl(tval);
+ inet_ntop(AF_INET, &tval, pval, sizeof(pval));
+ } else
+ snprintf(pval, sizeof(pval), "%u", tval);
+
switch (i->type) {
case IPFW_TABLE_CIDR:
/* IPv4 or IPv6 prefixes */
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
-
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s/%u %s\n", tbuf, tent->masklen,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s/%u %u\n", tbuf, tent->masklen, tval);
+ printf("%s/%u %s\n", tbuf, tent->masklen, pval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s %s\n", tent->k.iface,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s %u\n", tent->k.iface, tval);
+ printf("%s %s\n", tent->k.iface, pval);
break;
case IPFW_TABLE_NUMBER:
/* numbers */
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%u %s\n", tent->k.key,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%u %u\n", tent->k.key, tval);
+ printf("%u %s\n", tent->k.key, pval);
break;
+ case IPFW_TABLE_FLOW:
+ /* flows */
+ tfe = &tent->k.flow;
+ comma = "";
+
+ if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
+ if (tfe->af == AF_INET)
+ paddr = &tfe->a.a4.sip;
+ else
+ paddr = &tfe->a.a6.sip6;
+
+ inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
+ printf("%s%s", comma, tbuf);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
+ printf("%s%d", comma, tfe->proto);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
+ printf("%s%d", comma, ntohs(tfe->sport));
+ comma = ",";
+ }
+ if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
+ if (tfe->af == AF_INET)
+ paddr = &tfe->a.a4.dip;
+ else
+ paddr = &tfe->a.a6.dip6;
+
+ inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
+ printf("%s%s", comma, tbuf);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
+ printf("%s%d", comma, ntohs(tfe->dport));
+ comma = ",";
+ }
+
+ printf(" %s\n", pval);
}
}
Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sys/netinet/ip_fw.h Thu Jul 31 20:08:19 2014 (r269348)
@@ -262,6 +262,7 @@ enum ipfw_opcodes { /* arguments (4 byt
O_DSCP, /* 2 u32 = DSCP mask */
O_SETDSCP, /* arg1=DSCP value */
+ O_IP_FLOW_LOOKUP, /* arg1=table number, u32=value */
O_LAST_OPCODE /* not an opcode! */
};
@@ -675,7 +676,8 @@ struct _ipfw_dyn_rule {
#define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
#define IPFW_TABLE_NUMBER 3 /* Table for holding ports/uid/gid/etc */
-#define IPFW_TABLE_MAXTYPE 3 /* Maximum valid number */
+#define IPFW_TABLE_FLOW 4 /* Table for holding flow data */
+#define IPFW_TABLE_MAXTYPE 4 /* Maximum valid number */
#define IPFW_VTYPE_U32 1 /* Skipto/tablearg integer */
#define IPFW_VTYPE_IP 2 /* Nexthop IP address */
@@ -743,6 +745,25 @@ typedef struct _ipfw_obj_ntlv {
char name[64]; /* Null-terminated name */
} ipfw_obj_ntlv;
+/* IPv4/IPv6 L4 flow description */
+struct tflow_entry {
+ uint8_t af;
+ uint8_t proto;
+ uint16_t spare;
+ uint16_t sport;
+ uint16_t dport;
+ union {
+ struct {
+ struct in_addr sip;
+ struct in_addr dip;
+ } a4;
+ struct {
+ struct in6_addr sip6;
+ struct in6_addr dip6;
+ } a6;
+ } a;
+};
+
/* Table entry TLV */
typedef struct _ipfw_obj_tentry {
ipfw_obj_tlv head; /* TLV header */
@@ -753,10 +774,11 @@ typedef struct _ipfw_obj_tentry {
uint64_t spare;
union {
/* Longest field needs to be aligned by 8-byte boundary */
- struct in_addr addr; /* IPv4 address */
- uint32_t key; /* uid/gid/port */
- struct in6_addr addr6; /* IPv6 address */
+ struct in_addr addr; /* IPv4 address */
+ uint32_t key; /* uid/gid/port */
+ struct in6_addr addr6; /* IPv6 address */
char iface[IF_NAMESIZE]; /* interface name */
+ struct tflow_entry flow;
} k;
} ipfw_obj_tentry;
#define IPFW_TF_UPDATE 0x01 /* Update record if exists */
@@ -776,19 +798,44 @@ typedef struct _ipfw_obj_ctlv {
uint8_t spare;
} ipfw_obj_ctlv;
+typedef struct _ifpw_ta_tinfo {
+ uint32_t flags; /* Format flags */
+ uint8_t taclass; /* algorithm class */
+ uint8_t spare0;
+ uint16_t spare1;
+ uint32_t rssize4; /* runtime structure size */
+ uint32_t rcount4; /* number of items in runtime */
+ uint32_t rsize4; /* item size in runtime */
+ uint32_t rssize6; /* runtime structure size */
+ uint32_t rcount6; /* number of items in runtime */
+ uint32_t rsize6; /* item size in runtime */
+} ifpw_ta_tinfo;
+#define IPFW_TACLASS_HASH 1 /* algo is based on hash */
+#define IPFW_TACLASS_ARRAY 2 /* algo is based on array */
+#define IPFW_TACLASS_RADIX 3 /* algo is based on radix tree */
+
+#define IPFW_TATFLAGS_DATA 0x0001 /* Has data filled in */
+#define IPFW_TATFLAGS_AF 0x0002 /* Separate data per AF */
+
typedef struct _ipfw_xtable_info {
uint8_t type; /* table type (cidr,iface,..) */
+ uint8_t tflags; /* type flags */
uint8_t ftype; /* table value format type */
uint8_t vtype; /* value type */
- uint16_t spare0;
uint32_t set; /* set table is in */
uint32_t kidx; /* kernel index */
uint32_t refcnt; /* number of references */
uint32_t count; /* Number of records */
- uint32_t size; /* Total size of records */
+ uint32_t size; /* Total size of records(export)*/
char tablename[64]; /* table name */
- char algoname[32]; /* algorithm name */
+ char algoname[64]; /* algorithm name */
+ ifpw_ta_tinfo ta_info; /* additional algo stats */
} ipfw_xtable_info;
+#define IPFW_TFFLAG_SRCIP 0x01
+#define IPFW_TFFLAG_DSTIP 0x02
+#define IPFW_TFFLAG_SRCPORT 0x04
+#define IPFW_TFFLAG_DSTPORT 0x08
+#define IPFW_TFFLAG_PROTO 0x10
typedef struct _ipfw_iface_info {
char ifname[64]; /* interface name */
@@ -801,7 +848,7 @@ typedef struct _ipfw_iface_info {
#define IPFW_IFFLAG_RESOLVED 0x01 /* Interface exists */
typedef struct _ipfw_ta_info {
- char algoname[32]; /* algorithm name */
+ char algoname[64]; /* algorithm name */
uint32_t type; /* lookup type */
uint32_t flags;
uint32_t refcnt;
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Thu Jul 31 20:08:19 2014 (r269348)
@@ -1522,6 +1522,17 @@ do { \
}
break;
+ case O_IP_FLOW_LOOKUP:
+ {
+ uint32_t v = 0;
+ match = ipfw_lookup_table_extended(chain,
+ cmd->arg1, 0, &args->f_id, &v);
+ if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
+ match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
+ if (match)
+ tablearg = v;
+ }
+ break;
case O_IP_SRC_MASK:
case O_IP_DST_MASK:
if (is_ipv4) {
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Thu Jul 31 20:08:19 2014 (r269348)
@@ -1011,6 +1011,17 @@ check_ipfw_rule_body(ipfw_insn *cmd, int
goto bad_size;
ci->table_opcodes++;
break;
+ case O_IP_FLOW_LOOKUP:
+ if (cmd->arg1 >= V_fw_tables_max) {
+ printf("ipfw: invalid table number %d\n",
+ cmd->arg1);
+ return (EINVAL);
+ }
+ if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
+ cmdlen != F_INSN_SIZE(ipfw_insn_u32))
+ goto bad_size;
+ ci->table_opcodes++;
+ break;
case O_MACADDR2:
if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
goto bad_size;
@@ -1726,7 +1737,7 @@ ipfw_ctl3(struct sockopt *sopt)
size_t bsize_max, size, valsize;
struct ip_fw_chain *chain;
uint32_t opt;
- char xbuf[128];
+ char xbuf[256];
struct sockopt_data sdata;
ip_fw3_opheader *op3 = NULL;
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Jul 31 19:24:44 2014 (r269347)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Jul 31 20:08:19 2014 (r269348)
@@ -77,7 +77,8 @@ struct table_config {
struct named_object no;
uint8_t vtype; /* format table type */
uint8_t linked; /* 1 if already linked */
- uint16_t spare;
+ uint8_t tflags; /* type flags */
+ uint8_t spare;
uint32_t count; /* Number of records */
uint64_t flags; /* state flags */
char tablename[64]; /* table name */
@@ -95,11 +96,12 @@ struct tables_config {
static struct table_config *find_table(struct namedobj_instance *ni,
struct tid_info *ti);
static struct table_config *alloc_table_config(struct ip_fw_chain *ch,
- struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t vtype);
+ struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags,
+ uint8_t vtype);
static void free_table_config(struct namedobj_instance *ni,
struct table_config *tc);
static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
- char *aname, uint8_t vtype);
+ char *aname, uint8_t tflags, uint8_t vtype);
static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc);
static void free_table_state(void **state, void **xstate, uint8_t type);
@@ -169,7 +171,7 @@ add_table_entry(struct ip_fw_chain *ch,
if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
return (ESRCH);
- error = create_table_internal(ch, ti, NULL, IPFW_VTYPE_U32);
+ error = create_table_internal(ch, ti, NULL, 0, IPFW_VTYPE_U32);
if (error != 0)
return (error);
@@ -533,8 +535,7 @@ ipfw_find_table_entry(struct ip_fw_chain
struct table_algo *ta;
struct table_info *kti;
struct namedobj_instance *ni;
- int error, plen;
- void *paddr;
+ int error;
size_t sz;
/* Check minimum header size */
@@ -571,41 +572,13 @@ ipfw_find_table_entry(struct ip_fw_chain
return (EINVAL);
}
- /* Check lookup key for validness */
- plen = 0;
- paddr = &tent->k;
- switch (ti.type)
- {
- case IPFW_TABLE_CIDR:
- if (tent->subtype == AF_INET)
- plen = sizeof(struct in_addr);
- else if (tent->subtype == AF_INET6)
- plen = sizeof(struct in6_addr);
- else {
- IPFW_UH_RUNLOCK(ch);
- return (EINVAL);
- }
- break;
- case IPFW_TABLE_INTERFACE:
- /* Check key first */
- plen = sizeof(tent->k.iface);
- if (strnlen(tent->k.iface, plen) == plen) {
- IPFW_UH_RUNLOCK(ch);
- return (EINVAL);
- }
- case IPFW_TABLE_NUMBER:
- plen = sizeof(uint32_t);
- break;
-
- break;
- default:
- IPFW_UH_RUNLOCK(ch);
- return (ENOTSUP);
- }
kti = KIDX_TO_TI(ch, tc->no.kidx);
ta = tc->ta;
- error = ta->find_tentry(tc->astate, kti, paddr, plen, tent);
+ if (ta->find_tentry == NULL)
+ return (ENOTSUP);
+
+ error = ta->find_tentry(tc->astate, kti, tent);
IPFW_UH_RUNLOCK(ch);
@@ -651,9 +624,10 @@ flush_table(struct ip_fw_chain *ch, stru
struct table_algo *ta;
struct table_info ti_old, ti_new, *tablestate;
void *astate_old, *astate_new;
- char algostate[32], *pstate;
+ char algostate[64], *pstate;
int error;
uint16_t kidx;
+ uint8_t tflags;
/*
* Stage 1: save table algoritm.
@@ -674,13 +648,14 @@ flush_table(struct ip_fw_chain *ch, stru
pstate = algostate;
} else
pstate = NULL;
+ tflags = tc->tflags;
IPFW_UH_WUNLOCK(ch);
/*
* Stage 2: allocate new table instance using same algo.
*/
memset(&ti_new, 0, sizeof(struct table_info));
- if ((error = ta->init(ch, &astate_new, &ti_new, pstate)) != 0) {
+ if ((error = ta->init(ch, &astate_new, &ti_new, pstate, tflags)) != 0) {
IPFW_UH_WLOCK(ch);
tc->no.refcnt--;
IPFW_UH_WUNLOCK(ch);
@@ -1211,7 +1186,7 @@ ipfw_create_table(struct ip_fw_chain *ch
}
IPFW_UH_RUNLOCK(ch);
- return (create_table_internal(ch, &ti, aname, i->vtype));
+ return (create_table_internal(ch, &ti, aname, i->tflags, i->vtype));
}
/*
@@ -1224,7 +1199,7 @@ ipfw_create_table(struct ip_fw_chain *ch
*/
static int
create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
- char *aname, uint8_t vtype)
+ char *aname, uint8_t tflags, uint8_t vtype)
{
struct namedobj_instance *ni;
struct table_config *tc;
@@ -1237,7 +1212,7 @@ create_table_internal(struct ip_fw_chain
if (ta == NULL)
return (ENOTSUP);
- if ((tc = alloc_table_config(ch, ti, ta, aname, vtype)) == NULL)
+ if ((tc = alloc_table_config(ch, ti, ta, aname, tflags, vtype)) == NULL)
return (ENOMEM);
IPFW_UH_WLOCK(ch);
@@ -1311,6 +1286,7 @@ export_table_info(struct ip_fw_chain *ch
struct table_info *ti;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list