From 32cd3ee5901ea33d41ff550e5f40ce743c8d4165 Mon Sep 17 00:00:00 2001 From: Boris Lytochkin Date: Sun, 1 Mar 2026 21:54:24 +0300 Subject: ipfw: add support for masked ip-address lookups Current radix-based implementation of lookup tables in ipfw does not support non-contiguous prefixes while this type of lookup is needed to write CPU-effective firewall configurations. For some of the cases we can reach the goal using a masked table lookup by adding masked (e.g. zero non-significant bits) records into a table and then zero non-significant bits in lookup key prior to making a table lookup. Obtained from: Yandex LLC MFC after: 3 weeks Relnotes: yes Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D53694 --- sys/netinet/ip_fw.h | 81 ++++++++++---- sys/netpfil/ipfw/ip_fw2.c | 231 +++++++++++++++++++++++---------------- sys/netpfil/ipfw/ip_fw_sockopt.c | 32 ++++++ sys/netpfil/ipfw/ip_fw_table.c | 26 ++++- 4 files changed, 251 insertions(+), 119 deletions(-) (limited to 'sys') diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index f3b2dc051c7d..f7372f41a48a 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -216,8 +216,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_VERREVPATH = 36, /* none */ O_VERSRCREACH = 37, /* none */ - O_PROBE_STATE = 38, /* v0:arg1=kidx, v1:kidx=kidx */ - O_KEEP_STATE = 39, /* v0:arg1=kidx, v1:kidx=kidx */ + O_PROBE_STATE = 38, /* kidx=kidx */ + O_KEEP_STATE = 39, /* kidx=kidx */ O_LIMIT = 40, /* ipfw_insn_limit */ O_LIMIT_PARENT = 41, /* dyn_type, not an opcode. */ @@ -228,13 +228,12 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_LOG = 42, /* ipfw_insn_log */ O_PROB = 43, /* u32 = match probability */ - O_CHECK_STATE = 44, /* v0:arg1=kidx, v1:kidx=kidx */ + O_CHECK_STATE = 44, /* kidx=kidx */ O_ACCEPT = 45, /* none */ O_DENY = 46, /* none */ O_REJECT = 47, /* arg1=icmp arg (same as deny) */ O_COUNT = 48, /* none */ - O_SKIPTO = 49, /* v0:arg1=next rule number */ - /* v1:kidx= next rule number */ + O_SKIPTO = 49, /* u32= next rule number */ O_PIPE = 50, /* arg1=pipe number */ O_QUEUE = 51, /* arg1=queue number */ O_DIVERT = 52, /* arg1=port number */ @@ -248,10 +247,12 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ * More opcodes. */ O_IPSEC = 58, /* has ipsec history */ - O_IP_SRC_LOOKUP = 59, /* v0:arg1=table number, u32=value */ - /* v1:kidx=name, u32=value, arg1=key */ - O_IP_DST_LOOKUP = 60, /* arg1=table number, u32=value */ - /* v1:kidx=name, u32=value, arg1=key */ + O_IP_SRC_LOOKUP = 59, /* kidx=name */ + /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ + O_IP_DST_LOOKUP = 60, /* kidx=name */ + /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ O_ANTISPOOF = 61, /* none */ O_JAIL = 62, /* u32 = id */ O_ALTQ = 63, /* u32 = altq classif. qid */ @@ -286,31 +287,36 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_SOCKARG = 84, /* socket argument */ - O_CALLRETURN = 85, /* v0:arg1=called rule number */ - /* v1:kidx=called rule number */ + O_CALLRETURN = 85, /* u32=called rule number */ O_FORWARD_IP6 = 86, /* fwd sockaddr_in6 */ O_DSCP = 87, /* 2 u32 = DSCP mask */ O_SETDSCP = 88, /* arg1=DSCP value */ - O_IP_FLOW_LOOKUP = 89, /* v0:arg1=table number, u32=value */ - /* v1:kidx=name, u32=value */ + O_IP_FLOW_LOOKUP = 89, /* kidx=name */ + /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ - O_EXTERNAL_ACTION = 90, /* v0:arg1=id of external action handler */ - /* v1:kidx=id of external action handler */ - O_EXTERNAL_INSTANCE = 91, /* v0:arg1=id of eaction handler instance */ - /* v1:kidx=id of eaction handler instance */ + O_EXTERNAL_ACTION = 90, /* kidx=id of external action handler */ + O_EXTERNAL_INSTANCE = 91, /* kidx=id of eaction handler instance */ O_EXTERNAL_DATA = 92, /* variable length data */ O_SKIP_ACTION = 93, /* none */ O_TCPMSS = 94, /* arg1=MSS value */ - O_MAC_SRC_LOOKUP = 95, /* kidx=name, u32=value, arg1=key */ - O_MAC_DST_LOOKUP = 96, /* kidx=name, u32=value, arg1=key */ + O_MAC_SRC_LOOKUP = 95, /* kidx=name */ + /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ + O_MAC_DST_LOOKUP = 96, /* kidx=name */ + /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ O_SETMARK = 97, /* u32 = value */ O_MARK = 98, /* 2 u32 = value, bitmask */ + O_TABLE_LOOKUP = 99, /* lookup: kidx=name, arg1=key */ + /* and flags, bitmask */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -408,12 +414,32 @@ typedef struct _ipfw_insn_table { uint32_t value; /* table value */ } ipfw_insn_table; -#define IPFW_LOOKUP_TYPE_MASK 0x00FF +typedef struct _ipfw_insn_lookup { + ipfw_insn o; /* arg1 is flags and lookup key */ + uint32_t kidx; /* table name index */ + union { /* lookup mask */ + uint64_t __mask64[2]; + struct in6_addr ip6; + struct in_addr ip4; + char mac[6]; + uint32_t u32; + }; +} ipfw_insn_lookup; + +#define IPFW_LOOKUP_TYPE_MASK 0x007F #define IPFW_LOOKUP_TYPE(insn) ((insn)->arg1 & IPFW_LOOKUP_TYPE_MASK) #define IPFW_SET_LOOKUP_TYPE(insn, type) do { \ (insn)->arg1 &= ~IPFW_LOOKUP_TYPE_MASK; \ (insn)->arg1 |= (type) & IPFW_LOOKUP_TYPE_MASK; \ } while (0) +#define IPFW_LOOKUP_F_MASKING 0x0080 +#define IPFW_LOOKUP_MASKING(insn) ((insn)->arg1 & IPFW_LOOKUP_F_MASKING) +#define IPFW_SET_LOOKUP_MASKING(insn, value) do { \ + if (value) \ + (insn)->arg1 |= IPFW_LOOKUP_F_MASKING; \ + else \ + (insn)->arg1 &= ~IPFW_LOOKUP_F_MASKING; \ +} while (0) /* * Defines key types used by lookup instruction @@ -431,6 +457,10 @@ enum ipfw_table_lookup_type { LOOKUP_SRC_MAC, LOOKUP_MARK, LOOKUP_RULENUM, + LOOKUP_DST_IP4, + LOOKUP_SRC_IP4, + LOOKUP_DST_IP6, + LOOKUP_SRC_IP6, }; enum ipfw_return_type { @@ -940,12 +970,20 @@ struct tflow_entry { } a; }; -#define IPFW_TVALUE_TYPE_MASK 0xFF00 +#define IPFW_TVALUE_TYPE_MASK 0x7F00 #define IPFW_TVALUE_TYPE(insn) (((insn)->arg1 & IPFW_TVALUE_TYPE_MASK) >> 8) #define IPFW_SET_TVALUE_TYPE(insn, type) do { \ (insn)->arg1 &= ~IPFW_TVALUE_TYPE_MASK; \ (insn)->arg1 |= ((type) << 8) & IPFW_TVALUE_TYPE_MASK; \ } while (0) +#define IPFW_LOOKUP_F_MATCH_TVALUE 0x8000 +#define IPFW_LOOKUP_MATCH_TVALUE(insn) ((insn)->arg1 & IPFW_LOOKUP_F_MATCH_TVALUE) +#define IPFW_SET_LOOKUP_MATCH_TVALUE(insn, value) do { \ + if (value) \ + (insn)->arg1 |= IPFW_LOOKUP_F_MATCH_TVALUE; \ + else \ + (insn)->arg1 &= ~IPFW_LOOKUP_F_MATCH_TVALUE; \ +} while (0) enum ipfw_table_value_type { TVALUE_TAG = 0, @@ -959,6 +997,7 @@ enum ipfw_table_value_type { TVALUE_DSCP, TVALUE_LIMIT, TVALUE_MARK, + TVALUE_NH6, }; /* 64-byte structure representing multi-field table value */ diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index fe707abc7682..10690920e6fd 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -1309,7 +1309,7 @@ jump(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, #define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f) static inline int -tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, +tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_lookup *cmd, uint32_t tablearg) { uint32_t tvalue; @@ -1336,6 +1336,11 @@ tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, case TVALUE_NH4: tvalue = TARG_VAL(ch, tablearg, nh4); break; + case TVALUE_NH6: + if (F_LEN(&cmd->o) != F_INSN_SIZE(ipfw_insn_lookup)) + return (0); + return (0 == memcmp(&TARG_VAL(ch, tablearg, nh6), + &cmd->ip6, sizeof(struct in6_addr))); case TVALUE_DSCP: tvalue = TARG_VAL(ch, tablearg, dscp); break; @@ -1350,7 +1355,13 @@ tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, tvalue = TARG_VAL(ch, tablearg, tag); break; } - return (tvalue == cmd->value); + /* + * XXX: compatibility layer, to be removed. + * Match u32 values specified as ipfw_insn_table structure. + */ + if (F_LEN(&cmd->o) == F_INSN_SIZE(ipfw_insn_table)) + return (tvalue == insntoc(cmd, table)->value); + return (tvalue == cmd->u32); } /* @@ -2097,45 +2108,101 @@ do { \ break; case O_IP_DST_LOOKUP: - if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) { - void *pkey = NULL; - uint32_t key, vidx; - uint16_t keylen = 0; /* zero if can't match the packet */ - uint8_t lookup_type; + case O_IP_SRC_LOOKUP: + /* + * XXX: compatibility layer, to be removed. + * The following if and subsequent fallthrough + * are here for backward opcode compatibility + * used for lookup opcode until O_TABLE_LOOKUP + * appeared. + */ + if (IPFW_LOOKUP_TYPE(cmd) == LOOKUP_NONE) { + void *pkey; + uint32_t vidx; + uint16_t keylen; + + if (is_ipv4) { + keylen = sizeof(in_addr_t); + if (cmd->opcode == O_IP_DST_LOOKUP) + pkey = &dst_ip; + else + pkey = &src_ip; + } else if (is_ipv6) { + keylen = sizeof(struct in6_addr); + if (cmd->opcode == O_IP_DST_LOOKUP) + pkey = &args->f_id.dst_ip6; + else + pkey = &args->f_id.src_ip6; + } else + break; + match = ipfw_lookup_table(chain, + insntod(cmd, kidx)->kidx, + keylen, pkey, &vidx); + if (!match) + break; + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) { + match = tvalue_match(chain, + insntod(cmd, lookup), vidx); + if (!match) + break; + } + tablearg = vidx; + break; + } + /* FALLTHROUGH */ + case O_TABLE_LOOKUP: + { + ipfw_insn_lookup key; + uint32_t vidx; + uint16_t keylen = 0; /* zero if can't match the packet */ + uint8_t lookup_type; lookup_type = IPFW_LOOKUP_TYPE(cmd); switch (lookup_type) { case LOOKUP_DST_IP: + case LOOKUP_DST_IP4: + if (is_ipv4) { + keylen = sizeof(in_addr_t); + key.ip4 = dst_ip; + break; + } + if (lookup_type == LOOKUP_DST_IP4) + break; + /* FALLTHOUGH */ + case LOOKUP_DST_IP6: + if (is_ipv6 == 0) + break; + keylen = sizeof(struct in6_addr); + key.ip6 = args->f_id.dst_ip6; + break; case LOOKUP_SRC_IP: + case LOOKUP_SRC_IP4: if (is_ipv4) { keylen = sizeof(in_addr_t); - if (lookup_type == LOOKUP_DST_IP) - pkey = &dst_ip; - else - pkey = &src_ip; - } else if (is_ipv6) { - keylen = sizeof(struct in6_addr); - if (lookup_type == LOOKUP_DST_IP) - pkey = &args->f_id.dst_ip6; - else - pkey = &args->f_id.src_ip6; + key.ip4 = src_ip; + break; } + if (lookup_type == LOOKUP_SRC_IP4) + break; + /* FALLTHOUGH */ + case LOOKUP_SRC_IP6: + if (is_ipv6 == 0) + break; + keylen = sizeof(struct in6_addr); + key.ip6 = args->f_id.src_ip6; break; case LOOKUP_DSCP: if (is_ipv4) - key = ip->ip_tos >> 2; + key.u32 = ip->ip_tos >> 2; else if (is_ipv6) - key = IPV6_DSCP( + key.u32 = IPV6_DSCP( (struct ip6_hdr *)ip) >> 2; else break; /* only for L3 */ - key &= 0x3f; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + keylen = sizeof(key.u32); + key.u32 &= 0x3f; break; case LOOKUP_DST_PORT: case LOOKUP_SRC_PORT: @@ -2154,23 +2221,26 @@ do { \ proto != IPPROTO_SCTP) break; if (lookup_type == LOOKUP_DST_PORT) - key = dst_port; + key.u32 = dst_port; else - key = src_port; - pkey = &key; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - keylen = sizeof(key); + key.u32 = src_port; + keylen = sizeof(key.u32); break; case LOOKUP_DST_MAC: + /* only for L2 */ + if ((args->flags & IPFW_ARGS_ETHER) == 0) + break; + keylen = ETHER_ADDR_LEN; + memcpy(key.mac, eh->ether_dhost, + sizeof(key.mac)); + break; case LOOKUP_SRC_MAC: /* only for L2 */ if ((args->flags & IPFW_ARGS_ETHER) == 0) break; - - pkey = lookup_type == LOOKUP_DST_MAC ? - eh->ether_dhost : eh->ether_shost; keylen = ETHER_ADDR_LEN; + memcpy(key.mac, eh->ether_shost, + sizeof(key.mac)); break; #ifndef USERSPACE case LOOKUP_UID: @@ -2180,84 +2250,61 @@ do { \ #ifdef __FreeBSD__ &ucred_cache); if (lookup_type == LOOKUP_UID) - key = ucred_cache->cr_uid; + key.u32 = ucred_cache->cr_uid; else if (lookup_type == LOOKUP_JAIL) - key = ucred_cache->cr_prison->pr_id; + key.u32 = ucred_cache->cr_prison->pr_id; #else /* !__FreeBSD__ */ (void *)&ucred_cache); if (lookup_type == LOOKUP_UID) - key = ucred_cache.uid; + key.u32 = ucred_cache.uid; else if (lookup_type == LOOKUP_JAIL) - key = ucred_cache.xid; + key.u32 = ucred_cache.xid; #endif /* !__FreeBSD__ */ - pkey = &key; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - keylen = sizeof(key); + keylen = sizeof(key.u32); break; #endif /* !USERSPACE */ case LOOKUP_MARK: - key = args->rule.pkt_mark; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + key.u32 = args->rule.pkt_mark; + keylen = sizeof(key.u32); break; case LOOKUP_RULENUM: - key = f->rulenum; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + key.u32 = f->rulenum; + keylen = sizeof(key.u32); break; } /* unknown key type */ if (keylen == 0) break; - match = ipfw_lookup_table(chain, - insntod(cmd, kidx)->kidx, keylen, - pkey, &vidx); - if (match) - tablearg = vidx; - break; - } - /* LOOKUP_NONE */ - /* FALLTHROUGH */ - case O_IP_SRC_LOOKUP: - { - void *pkey; - uint32_t vidx; - uint16_t keylen; + if (IPFW_LOOKUP_MASKING(cmd) == 0) { + /* no masking needed */ + } else if (cmdlen == + F_INSN_SIZE(ipfw_insn_table)) { + /* + * XXX: compatibility layer, + * to be removed. + */ + key.u32 &= insntod(cmd, table)->value; + } else { + key.__mask64[0] &= + insntod(cmd, lookup)->__mask64[0]; + key.__mask64[1] &= + insntod(cmd, lookup)->__mask64[1]; + } - if (is_ipv4) { - keylen = sizeof(in_addr_t); - if (cmd->opcode == O_IP_DST_LOOKUP) - pkey = &dst_ip; - else - pkey = &src_ip; - } else if (is_ipv6) { - keylen = sizeof(struct in6_addr); - if (cmd->opcode == O_IP_DST_LOOKUP) - pkey = &args->f_id.dst_ip6; - else - pkey = &args->f_id.src_ip6; - } else - break; match = ipfw_lookup_table(chain, - insntod(cmd, kidx)->kidx, - keylen, pkey, &vidx); + insntod(cmd, kidx)->kidx, keylen, + key.__mask64, &vidx); + if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { - match = tvalue_match(chain, - insntod(cmd, table), vidx); - if (!match) - break; - } + /* + * XXX should we support check for value + * simultaneously with masked lookup? + */ tablearg = vidx; break; - } + } /* O_TABLE_LOOKUP */ case O_MAC_SRC_LOOKUP: case O_MAC_DST_LOOKUP: @@ -2280,9 +2327,9 @@ do { \ keylen, pkey, &vidx); if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) { match = tvalue_match(chain, - insntod(cmd, table), vidx); + insntod(cmd, lookup), vidx); if (!match) break; } @@ -2299,9 +2346,9 @@ do { \ &args->f_id, &vidx); if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) match = tvalue_match(chain, - insntod(cmd, table), vidx); + insntod(cmd, lookup), vidx); if (match) tablearg = vidx; break; diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 2941444a7bd3..a5892bb387e5 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1418,6 +1418,7 @@ ipfw_check_opcode(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) case O_MAC_SRC_LOOKUP: case O_MAC_DST_LOOKUP: if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) && + cmdlen != F_INSN_SIZE(ipfw_insn_lookup) && cmdlen != F_INSN_SIZE(ipfw_insn_table)) return (BAD_SIZE); if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) { @@ -1426,6 +1427,37 @@ ipfw_check_opcode(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) return (FAILED); } ci->object_opcodes++; + /* + * XXX: compatibility layer, to be removed. + + * ipfw_insn_table was used to match table value for u32 + * values and cmdlen was used to detect such intention. + * A special flag is now used for that in module so + * adopt legacy sbin/ipfw behavior and set it for all + * lookup instructions with ipfw_insn_table opcode. + * + * Lookup type different from LOOKUP_NONE was used for + * 32-bit bitmasking prior to lookup. + * Table value matching was expected otherwise. + */ + if (cmdlen != F_INSN_SIZE(ipfw_insn_table)) + break; + + if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) + IPFW_SET_LOOKUP_MASKING(cmd, 1); + else + IPFW_SET_LOOKUP_MATCH_TVALUE(cmd, 1); + break; + case O_TABLE_LOOKUP: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) && + cmdlen != F_INSN_SIZE(ipfw_insn_lookup)) + return (BAD_SIZE); + if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) { + printf("ipfw: invalid table index %u\n", + insntod(cmd, kidx)->kidx); + return (FAILED); + } + ci->object_opcodes++; break; case O_MACADDR2: if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index dde18d41ab15..29fbab1676b9 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -2169,14 +2169,18 @@ list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, static int classify_srcdst(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - ipfw_insn_table *cmd; + ipfw_insn_lookup *cmd; /* Basic IPv4/IPv6 or u32 lookups */ - cmd = insntod(cmd0, table); + cmd = insntod(cmd0, lookup); *puidx = cmd->kidx; - switch(cmd0->arg1) { + switch(IPFW_LOOKUP_TYPE(cmd0)) { case LOOKUP_DST_IP: case LOOKUP_SRC_IP: + case LOOKUP_DST_IP4: + case LOOKUP_SRC_IP4: + case LOOKUP_DST_IP6: + case LOOKUP_SRC_IP6: default: /* IPv4 src/dst */ *ptype = IPFW_TABLE_ADDR; @@ -2216,7 +2220,7 @@ classify_via(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static int classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - *puidx = insntod(cmd0, table)->kidx; + *puidx = insntod(cmd0, kidx)->kidx; *ptype = IPFW_TABLE_FLOW; return (0); } @@ -2224,7 +2228,7 @@ classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static int classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - *puidx = insntod(cmd0, table)->kidx; + *puidx = insntod(cmd0, kidx)->kidx; *ptype = IPFW_TABLE_MAC; return (0); } @@ -2232,7 +2236,7 @@ classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static void update_kidx(ipfw_insn *cmd0, uint32_t idx) { - insntod(cmd0, table)->kidx = idx; + insntod(cmd0, kidx)->kidx = idx; } static void @@ -2365,6 +2369,16 @@ static struct opcode_obj_rewrite opcodes[] = { .create_object = create_table_compat, .manage_sets = table_manage_sets, }, + { + .opcode = O_TABLE_LOOKUP, + .etlv = IPFW_TLV_TBL_NAME, + .classifier = classify_srcdst, + .update = update_kidx, + .find_byname = table_findbyname, + .find_bykidx = table_findbykidx, + .create_object = create_table_compat, + .manage_sets = table_manage_sets, + }, { .opcode = O_IP_FLOW_LOOKUP, .etlv = IPFW_TLV_TBL_NAME, -- cgit v1.3