Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/ip_fw_table.c
| /*- | /*- | ||||
| * SPDX-License-Identifier: BSD-2-Clause | * SPDX-License-Identifier: BSD-2-Clause | ||||
| * | * | ||||
| * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. | * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. | ||||
| * Copyright (c) 2014 Yandex LLC | * Copyright (c) 2014-2024 Yandex LLC | ||||
| * Copyright (c) 2014 Alexander V. Chernikov | * Copyright (c) 2014 Alexander V. Chernikov | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
| * are met: | * are met: | ||||
| * 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
| * notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
| * 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
| ▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | static int find_table_err(struct namedobj_instance *ni, struct tid_info *ti, | ||||
| struct table_config **tc); | struct table_config **tc); | ||||
| static struct table_config *find_table(struct namedobj_instance *ni, | static struct table_config *find_table(struct namedobj_instance *ni, | ||||
| struct tid_info *ti); | struct tid_info *ti); | ||||
| static struct table_config *alloc_table_config(struct ip_fw_chain *ch, | static struct table_config *alloc_table_config(struct ip_fw_chain *ch, | ||||
| struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags); | struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags); | ||||
| static void free_table_config(struct namedobj_instance *ni, | static void free_table_config(struct namedobj_instance *ni, | ||||
| struct table_config *tc); | struct table_config *tc); | ||||
| static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, | static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int ref); | char *aname, ipfw_xtable_info *i, uint32_t *pkidx, int ref); | ||||
| static void link_table(struct ip_fw_chain *ch, struct table_config *tc); | static void link_table(struct ip_fw_chain *ch, struct table_config *tc); | ||||
| static void unlink_table(struct ip_fw_chain *ch, struct table_config *tc); | static void unlink_table(struct ip_fw_chain *ch, struct table_config *tc); | ||||
| static int find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, | static int find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| struct tentry_info *tei, uint32_t count, int op, struct table_config **ptc); | struct tentry_info *tei, uint32_t count, int op, struct table_config **ptc); | ||||
| #define OP_ADD 1 | #define OP_ADD 1 | ||||
| #define OP_DEL 0 | #define OP_DEL 0 | ||||
| static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, | static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, | ||||
| struct sockopt_data *sd); | struct sockopt_data *sd); | ||||
| static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, | static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, | ||||
| ipfw_xtable_info *i); | ipfw_xtable_info *i); | ||||
| static int dump_table_tentry(void *e, void *arg); | static int dump_table_tentry(void *e, void *arg); | ||||
| static int dump_table_xentry(void *e, void *arg); | |||||
| static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a, | static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a, | ||||
| struct tid_info *b); | struct tid_info *b); | ||||
| static int check_table_name(const char *name); | static int check_table_name(const char *name); | ||||
| static int check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts, | static int check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts, | ||||
| struct table_config *tc, struct table_info *ti, uint32_t count); | struct table_config *tc, struct table_info *ti, uint32_t count); | ||||
| static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); | static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); | ||||
| ▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
| * Saves table config, algo and allocated kidx info @ptc, @pta and | * Saves table config, algo and allocated kidx info @ptc, @pta and | ||||
| * @pkidx if non-zero. | * @pkidx if non-zero. | ||||
| * Used for table auto-creation to support old binaries. | * Used for table auto-creation to support old binaries. | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns 0 on success. | ||||
| */ | */ | ||||
| static int | static int | ||||
| create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti, | create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| uint16_t *pkidx) | uint32_t *pkidx) | ||||
| { | { | ||||
| ipfw_xtable_info xi; | ipfw_xtable_info xi; | ||||
| int error; | int error; | ||||
| memset(&xi, 0, sizeof(xi)); | memset(&xi, 0, sizeof(xi)); | ||||
| /* Set default value mask for legacy clients */ | /* Set default value mask for legacy clients */ | ||||
| xi.vmask = IPFW_VTYPE_LEGACY; | xi.vmask = IPFW_VTYPE_LEGACY; | ||||
| Show All 15 Lines | |||||
| */ | */ | ||||
| static int | static int | ||||
| find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, | find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| struct tentry_info *tei, uint32_t count, int op, | struct tentry_info *tei, uint32_t count, int op, | ||||
| struct table_config **ptc) | struct table_config **ptc) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| uint16_t kidx; | uint32_t kidx; | ||||
| int error; | int error; | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| tc = NULL; | tc = NULL; | ||||
| if ((tc = find_table(ni, ti)) != NULL) { | if ((tc = find_table(ni, ti)) != NULL) { | ||||
| /* check table type */ | /* check table type */ | ||||
| Show All 24 Lines | find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| error = create_table_compat(ch, ti, &kidx); | error = create_table_compat(ch, ti, &kidx); | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| if (error != 0) | if (error != 0) | ||||
| return (error); | return (error); | ||||
| tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx); | tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx); | ||||
| KASSERT(tc != NULL, ("create_table_compat returned bad idx %d", kidx)); | KASSERT(tc != NULL, ("create_table_compat returned bad idx %u", kidx)); | ||||
| /* OK, now we've got referenced table. */ | /* OK, now we've got referenced table. */ | ||||
| *ptc = tc; | *ptc = tc; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Rolls back already @added to @tc entries using state array @ta_buf_m. | * Rolls back already @added to @tc entries using state array @ta_buf_m. | ||||
| ▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | |||||
| * Returns 0 on success. | * Returns 0 on success. | ||||
| */ | */ | ||||
| int | int | ||||
| add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, | add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| struct tentry_info *tei, uint8_t flags, uint32_t count) | struct tentry_info *tei, uint8_t flags, uint32_t count) | ||||
| { | { | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| uint16_t kidx; | |||||
| int error, first_error, i, rollback; | |||||
| uint32_t num, numadd; | |||||
| struct tentry_info *ptei; | struct tentry_info *ptei; | ||||
| struct tableop_state ts; | struct tableop_state ts; | ||||
| char ta_buf[TA_BUF_SZ]; | char ta_buf[TA_BUF_SZ]; | ||||
| caddr_t ta_buf_m, v; | caddr_t ta_buf_m, v; | ||||
| uint32_t kidx, num, numadd; | |||||
| int error, first_error, i, rollback; | |||||
| memset(&ts, 0, sizeof(ts)); | memset(&ts, 0, sizeof(ts)); | ||||
| ta = NULL; | ta = NULL; | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| /* | /* | ||||
| * Find and reference existing table. | * Find and reference existing table. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| int | int | ||||
| del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, | del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| struct tentry_info *tei, uint8_t flags, uint32_t count) | struct tentry_info *tei, uint8_t flags, uint32_t count) | ||||
| { | { | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| struct tentry_info *ptei; | struct tentry_info *ptei; | ||||
| uint16_t kidx; | |||||
| int error, first_error, i; | |||||
| uint32_t num, numdel; | |||||
| char ta_buf[TA_BUF_SZ]; | char ta_buf[TA_BUF_SZ]; | ||||
| caddr_t ta_buf_m, v; | caddr_t ta_buf_m, v; | ||||
| uint32_t kidx, num, numdel; | |||||
| int error, first_error, i; | |||||
| /* | /* | ||||
| * Find and reference existing table. | * Find and reference existing table. | ||||
| */ | */ | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| error = find_ref_table(ch, ti, tei, count, OP_DEL, &tc); | error = find_ref_table(ch, ti, tei, count, OP_DEL, &tc); | ||||
| if (error != 0) { | if (error != 0) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| ▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts, | ||||
| } | } | ||||
| tc->no.refcnt--; | tc->no.refcnt--; | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| /* | /* | ||||
| * Adds or deletes record in table. | * Adds or deletes record in table. | ||||
| * Data layout (v0): | |||||
| * Request: [ ip_fw3_opheader ipfw_table_xentry ] | |||||
| * | |||||
| * Returns 0 on success | |||||
| */ | |||||
| static int | |||||
| manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | |||||
| struct sockopt_data *sd) | |||||
| { | |||||
| ipfw_table_xentry *xent; | |||||
| struct tentry_info tei; | |||||
| struct tid_info ti; | |||||
| struct table_value v; | |||||
| int error, hdrlen, read; | |||||
| hdrlen = offsetof(ipfw_table_xentry, k); | |||||
| /* Check minimum header size */ | |||||
| if (sd->valsize < (sizeof(*op3) + hdrlen)) | |||||
| return (EINVAL); | |||||
| read = sizeof(ip_fw3_opheader); | |||||
| /* Check if xentry len field is valid */ | |||||
| xent = (ipfw_table_xentry *)(op3 + 1); | |||||
| if (xent->len < hdrlen || xent->len + read > sd->valsize) | |||||
| return (EINVAL); | |||||
| memset(&tei, 0, sizeof(tei)); | |||||
| tei.paddr = &xent->k; | |||||
| tei.masklen = xent->masklen; | |||||
| ipfw_import_table_value_legacy(xent->value, &v); | |||||
| tei.pvalue = &v; | |||||
| /* Old requests compatibility */ | |||||
| tei.flags = TEI_FLAGS_COMPAT; | |||||
| if (xent->type == IPFW_TABLE_ADDR) { | |||||
| if (xent->len - hdrlen == sizeof(in_addr_t)) | |||||
| tei.subtype = AF_INET; | |||||
| else | |||||
| tei.subtype = AF_INET6; | |||||
| } | |||||
| memset(&ti, 0, sizeof(ti)); | |||||
| ti.uidx = xent->tbl; | |||||
| ti.type = xent->type; | |||||
| error = (op3->opcode == IP_FW_TABLE_XADD) ? | |||||
| add_table_entry(ch, &ti, &tei, 0, 1) : | |||||
| del_table_entry(ch, &ti, &tei, 0, 1); | |||||
| return (error); | |||||
| } | |||||
| /* | |||||
| * Adds or deletes record in table. | |||||
| * Data layout (v1)(current): | * Data layout (v1)(current): | ||||
| * Request: [ ipfw_obj_header | * Request: [ ipfw_obj_header | ||||
| * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ] | * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ] | ||||
| * ] | * ] | ||||
| * | * | ||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| ipfw_obj_tentry *tent, *ptent; | ipfw_obj_tentry *tent, *ptent; | ||||
| ipfw_obj_ctlv *ctlv; | ipfw_obj_ctlv *ctlv; | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| struct tentry_info *ptei, tei, *tei_buf; | struct tentry_info *ptei, tei, *tei_buf; | ||||
| struct tid_info ti; | struct tid_info ti; | ||||
| int error, i, kidx, read; | uint32_t kidx; | ||||
| int error, i, read; | |||||
| /* Check minimum header size */ | /* Check minimum header size */ | ||||
| if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) | if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| /* Check if passed data is too long */ | /* Check if passed data is too long */ | ||||
| if (sd->valsize != sd->kavail) | if (sd->valsize != sd->kavail) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| ▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | flush_table(struct ip_fw_chain *ch, struct tid_info *ti) | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| struct table_info ti_old, ti_new, *tablestate; | struct table_info ti_old, ti_new, *tablestate; | ||||
| void *astate_old, *astate_new; | void *astate_old, *astate_new; | ||||
| char algostate[64], *pstate; | char algostate[64], *pstate; | ||||
| struct tableop_state ts; | struct tableop_state ts; | ||||
| int error, need_gc; | int error, need_gc; | ||||
| uint16_t kidx; | uint32_t kidx; | ||||
| uint8_t tflags; | uint8_t tflags; | ||||
| /* | /* | ||||
| * Stage 1: save table algorithm. | * Stage 1: save table algorithm. | ||||
| * Reference found table to ensure it won't disappear. | * Reference found table to ensure it won't disappear. | ||||
| */ | */ | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| ▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) | ||||
| } | } | ||||
| IPFW_WLOCK(ch); | IPFW_WLOCK(ch); | ||||
| unlink_table(ch, tc); | unlink_table(ch, tc); | ||||
| IPFW_WUNLOCK(ch); | IPFW_WUNLOCK(ch); | ||||
| /* Free obj index */ | /* Free obj index */ | ||||
| if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) | if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) | ||||
| printf("Error unlinking kidx %d from table %s\n", | printf("Error unlinking kidx %u from table %s\n", | ||||
| tc->no.kidx, tc->tablename); | tc->no.kidx, tc->tablename); | ||||
| /* Unref values used in tables while holding UH lock */ | /* Unref values used in tables while holding UH lock */ | ||||
| ipfw_unref_table_values(ch, tc, tc->ta, tc->astate, &tc->ti_copy); | ipfw_unref_table_values(ch, tc, tc->ta, tc->astate, &tc->ti_copy); | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| free_table_config(ni, tc); | free_table_config(ni, tc); | ||||
| Show All 16 Lines | ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) | ||||
| int i, new_blocks; | int i, new_blocks; | ||||
| /* Check new value for validity */ | /* Check new value for validity */ | ||||
| if (ntables == 0) | if (ntables == 0) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| if (ntables > IPFW_TABLES_MAX) | if (ntables > IPFW_TABLES_MAX) | ||||
| ntables = IPFW_TABLES_MAX; | ntables = IPFW_TABLES_MAX; | ||||
| /* Alight to nearest power of 2 */ | /* Alight to nearest power of 2 */ | ||||
| ntables = roundup_pow_of_two(ntables); | ntables = roundup_pow_of_two(ntables); | ||||
| /* Allocate new pointers */ | /* Allocate new pointers */ | ||||
| tablestate = malloc(ntables * sizeof(struct table_info), | tablestate = malloc(ntables * sizeof(struct table_info), | ||||
| M_IPFW, M_WAITOK | M_ZERO); | M_IPFW, M_WAITOK | M_ZERO); | ||||
| ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); | ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Lookup table's named object by its @kidx. | * Lookup table's named object by its @kidx. | ||||
| */ | */ | ||||
| struct named_object * | struct named_object * | ||||
| ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint16_t kidx) | ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint32_t kidx) | ||||
| { | { | ||||
| return (ipfw_objhash_lookup_kidx(CHAIN_TO_NI(ch), kidx)); | return (ipfw_objhash_lookup_kidx(CHAIN_TO_NI(ch), kidx)); | ||||
| } | } | ||||
| /* | /* | ||||
| * Take reference to table specified in @ntlv. | * Take reference to table specified in @ntlv. | ||||
| * On success return its @kidx. | * On success return its @kidx. | ||||
| */ | */ | ||||
| int | int | ||||
| ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx) | ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint32_t *kidx) | ||||
| { | { | ||||
| struct tid_info ti; | struct tid_info ti; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| int error; | int error; | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| ntlv_to_ti(ntlv, &ti); | ntlv_to_ti(ntlv, &ti); | ||||
| error = find_table_err(CHAIN_TO_NI(ch), &ti, &tc); | error = find_table_err(CHAIN_TO_NI(ch), &ti, &tc); | ||||
| if (error != 0) | if (error != 0) | ||||
| return (error); | return (error); | ||||
| if (tc == NULL) | if (tc == NULL) | ||||
| return (ESRCH); | return (ESRCH); | ||||
| tc_ref(tc); | tc_ref(tc); | ||||
| *kidx = tc->no.kidx; | *kidx = tc->no.kidx; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| void | void | ||||
| ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx) | ipfw_unref_table(struct ip_fw_chain *ch, uint32_t kidx) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct named_object *no; | struct named_object *no; | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| no = ipfw_objhash_lookup_kidx(ni, kidx); | no = ipfw_objhash_lookup_kidx(ni, kidx); | ||||
| KASSERT(no != NULL, ("Table with index %d not found", kidx)); | KASSERT(no != NULL, ("Table with index %u not found", kidx)); | ||||
| no->refcnt--; | no->refcnt--; | ||||
| } | } | ||||
| /* | /* | ||||
| * Lookup an arbitrary key @paddr of length @plen in table @tbl. | * Lookup an arbitrary key @paddr of length @plen in table @tbl. | ||||
| * Stores found value in @val. | * Stores found value in @val. | ||||
| * | * | ||||
| * Returns 1 if key was found. | * Returns 1 if key was found. | ||||
| */ | */ | ||||
| int | int | ||||
| ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, | ipfw_lookup_table(struct ip_fw_chain *ch, uint32_t tbl, uint16_t plen, | ||||
| void *paddr, uint32_t *val) | void *paddr, uint32_t *val) | ||||
| { | { | ||||
| struct table_info *ti; | struct table_info *ti; | ||||
| ti = KIDX_TO_TI(ch, tbl); | ti = KIDX_TO_TI(ch, tbl); | ||||
| return (ti->lookup(ti, paddr, plen, val)); | return (ti->lookup(ti, paddr, plen, val)); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 187 Lines • ▼ Show 20 Lines | |||||
| * Assume @aname to be checked and valid. | * Assume @aname to be checked and valid. | ||||
| * Stores allocated table kidx inside @pkidx (if non-NULL). | * Stores allocated table kidx inside @pkidx (if non-NULL). | ||||
| * Reference created table if @compat is non-zero. | * Reference created table if @compat is non-zero. | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns 0 on success. | ||||
| */ | */ | ||||
| static int | static int | ||||
| create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, | create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int compat) | char *aname, ipfw_xtable_info *i, uint32_t *pkidx, int compat) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct table_config *tc, *tc_new, *tmp; | struct table_config *tc, *tc_new, *tmp; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| uint16_t kidx; | uint32_t kidx; | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname); | ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname); | ||||
| if (ta == NULL) | if (ta == NULL) | ||||
| return (ENOTSUP); | return (ENOTSUP); | ||||
| tc = alloc_table_config(ch, ti, ta, aname, i->tflags); | tc = alloc_table_config(ch, ti, ta, aname, i->tflags); | ||||
| ▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
| /* | /* | ||||
| * Exports basic table info as name TLV. | * Exports basic table info as name TLV. | ||||
| * Used inside dump_static_rules() to provide info | * Used inside dump_static_rules() to provide info | ||||
| * about all tables referenced by current ruleset. | * about all tables referenced by current ruleset. | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns 0 on success. | ||||
| */ | */ | ||||
| int | int | ||||
| ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, | ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint32_t kidx, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct named_object *no; | struct named_object *no; | ||||
| ipfw_obj_ntlv *ntlv; | ipfw_obj_ntlv *ntlv; | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| Show All 16 Lines | struct dump_args { | ||||
| struct ip_fw_chain *ch; | struct ip_fw_chain *ch; | ||||
| struct table_info *ti; | struct table_info *ti; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct sockopt_data *sd; | struct sockopt_data *sd; | ||||
| uint32_t cnt; | uint32_t cnt; | ||||
| uint16_t uidx; | uint16_t uidx; | ||||
| int error; | int error; | ||||
| uint32_t size; | uint32_t size; | ||||
| ipfw_table_entry *ent; | |||||
| ta_foreach_f *f; | ta_foreach_f *f; | ||||
| void *farg; | void *farg; | ||||
| ipfw_obj_tentry tent; | ipfw_obj_tentry tent; | ||||
| }; | }; | ||||
| static int | static int | ||||
| count_ext_entries(void *e, void *arg) | count_ext_entries(void *e, void *arg) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); | ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (da.error); | return (da.error); | ||||
| } | } | ||||
| /* | /* | ||||
| * Dumps all table data | |||||
| * Data layout (version 0)(legacy): | |||||
| * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() | |||||
| * Reply: [ ipfw_xtable ipfw_table_xentry x N ] | |||||
| * | |||||
| * Returns 0 on success | |||||
| */ | |||||
| static int | |||||
| dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | |||||
| struct sockopt_data *sd) | |||||
| { | |||||
| ipfw_xtable *xtbl; | |||||
| struct tid_info ti; | |||||
| struct table_config *tc; | |||||
| struct table_algo *ta; | |||||
| struct dump_args da; | |||||
| size_t sz, count; | |||||
| xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); | |||||
| if (xtbl == NULL) | |||||
| return (EINVAL); | |||||
| memset(&ti, 0, sizeof(ti)); | |||||
| ti.uidx = xtbl->tbl; | |||||
| IPFW_UH_RLOCK(ch); | |||||
| if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { | |||||
| IPFW_UH_RUNLOCK(ch); | |||||
| return (0); | |||||
| } | |||||
| count = table_get_count(ch, tc); | |||||
| sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); | |||||
| xtbl->cnt = count; | |||||
| xtbl->size = sz; | |||||
| xtbl->type = tc->no.subtype; | |||||
| xtbl->tbl = ti.uidx; | |||||
| if (sd->valsize < sz) { | |||||
| /* | |||||
| * Submitted buffer size is not enough. | |||||
| * WE've already filled in @i structure with | |||||
| * relevant table info including size, so we | |||||
| * can return. Buffer will be flushed automatically. | |||||
| */ | |||||
| IPFW_UH_RUNLOCK(ch); | |||||
| return (ENOMEM); | |||||
| } | |||||
| /* Do the actual dump in eXtended format */ | |||||
| memset(&da, 0, sizeof(da)); | |||||
| da.ch = ch; | |||||
| da.ti = KIDX_TO_TI(ch, tc->no.kidx); | |||||
| da.tc = tc; | |||||
| da.sd = sd; | |||||
| ta = tc->ta; | |||||
| ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); | |||||
| IPFW_UH_RUNLOCK(ch); | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Legacy function to retrieve number of items in table. | |||||
| */ | |||||
| static int | |||||
| get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | |||||
| struct sockopt_data *sd) | |||||
| { | |||||
| uint32_t *tbl; | |||||
| struct tid_info ti; | |||||
| size_t sz; | |||||
| int error; | |||||
| sz = sizeof(*op3) + sizeof(uint32_t); | |||||
| op3 = (ip_fw3_opheader *)ipfw_get_sopt_header(sd, sz); | |||||
| if (op3 == NULL) | |||||
| return (EINVAL); | |||||
| tbl = (uint32_t *)(op3 + 1); | |||||
| memset(&ti, 0, sizeof(ti)); | |||||
| ti.uidx = *tbl; | |||||
| IPFW_UH_RLOCK(ch); | |||||
| error = ipfw_count_xtable(ch, &ti, tbl); | |||||
| IPFW_UH_RUNLOCK(ch); | |||||
| return (error); | |||||
| } | |||||
| /* | |||||
| * Legacy IP_FW_TABLE_GETSIZE handler | |||||
| */ | |||||
| int | |||||
| ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) | |||||
| { | |||||
| struct table_config *tc; | |||||
| if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) | |||||
| return (ESRCH); | |||||
| *cnt = table_get_count(ch, tc); | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Legacy IP_FW_TABLE_XGETSIZE handler | |||||
| */ | |||||
| int | |||||
| ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) | |||||
| { | |||||
| struct table_config *tc; | |||||
| uint32_t count; | |||||
| if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { | |||||
| *cnt = 0; | |||||
| return (0); /* 'table all list' requires success */ | |||||
| } | |||||
| count = table_get_count(ch, tc); | |||||
| *cnt = count * sizeof(ipfw_table_xentry); | |||||
| if (count > 0) | |||||
| *cnt += sizeof(ipfw_xtable); | |||||
| return (0); | |||||
| } | |||||
| static int | |||||
| dump_table_entry(void *e, void *arg) | |||||
| { | |||||
| struct dump_args *da; | |||||
| struct table_config *tc; | |||||
| struct table_algo *ta; | |||||
| ipfw_table_entry *ent; | |||||
| struct table_value *pval; | |||||
| int error; | |||||
| da = (struct dump_args *)arg; | |||||
| tc = da->tc; | |||||
| ta = tc->ta; | |||||
| /* Out of memory, returning */ | |||||
| if (da->cnt == da->size) | |||||
| return (1); | |||||
| ent = da->ent++; | |||||
| ent->tbl = da->uidx; | |||||
| da->cnt++; | |||||
| error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); | |||||
| if (error != 0) | |||||
| return (error); | |||||
| ent->addr = da->tent.k.addr.s_addr; | |||||
| ent->masklen = da->tent.masklen; | |||||
| pval = get_table_value(da->ch, da->tc, da->tent.v.kidx); | |||||
| ent->value = ipfw_export_table_value_legacy(pval); | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Dumps table in pre-8.1 legacy format. | |||||
| */ | |||||
| int | |||||
| ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, | |||||
| ipfw_table *tbl) | |||||
| { | |||||
| struct table_config *tc; | |||||
| struct table_algo *ta; | |||||
| struct dump_args da; | |||||
| tbl->cnt = 0; | |||||
| if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) | |||||
| return (0); /* XXX: We should return ESRCH */ | |||||
| ta = tc->ta; | |||||
| /* This dump format supports IPv4 only */ | |||||
| if (tc->no.subtype != IPFW_TABLE_ADDR) | |||||
| return (0); | |||||
| memset(&da, 0, sizeof(da)); | |||||
| da.ch = ch; | |||||
| da.ti = KIDX_TO_TI(ch, tc->no.kidx); | |||||
| da.tc = tc; | |||||
| da.ent = &tbl->ent[0]; | |||||
| da.size = tbl->size; | |||||
| tbl->cnt = 0; | |||||
| ta->foreach(tc->astate, da.ti, dump_table_entry, &da); | |||||
| tbl->cnt = da.cnt; | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Dumps table entry in eXtended format (v1)(current). | * Dumps table entry in eXtended format (v1)(current). | ||||
| */ | */ | ||||
| static int | static int | ||||
| dump_table_tentry(void *e, void *arg) | dump_table_tentry(void *e, void *arg) | ||||
| { | { | ||||
| struct dump_args *da; | struct dump_args *da; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| Show All 21 Lines | dump_table_tentry(void *e, void *arg) | ||||
| pval = get_table_value(da->ch, da->tc, tent->v.kidx); | pval = get_table_value(da->ch, da->tc, tent->v.kidx); | ||||
| ipfw_export_table_value_v1(pval, &tent->v.value); | ipfw_export_table_value_v1(pval, &tent->v.value); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Dumps table entry in eXtended format (v0). | |||||
| */ | |||||
| static int | |||||
| dump_table_xentry(void *e, void *arg) | |||||
| { | |||||
| struct dump_args *da; | |||||
| struct table_config *tc; | |||||
| struct table_algo *ta; | |||||
| ipfw_table_xentry *xent; | |||||
| ipfw_obj_tentry *tent; | |||||
| struct table_value *pval; | |||||
| int error; | |||||
| da = (struct dump_args *)arg; | |||||
| tc = da->tc; | |||||
| ta = tc->ta; | |||||
| xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); | |||||
| /* Out of memory, returning */ | |||||
| if (xent == NULL) | |||||
| return (1); | |||||
| xent->len = sizeof(ipfw_table_xentry); | |||||
| xent->tbl = da->uidx; | |||||
| memset(&da->tent, 0, sizeof(da->tent)); | |||||
| tent = &da->tent; | |||||
| error = ta->dump_tentry(tc->astate, da->ti, e, tent); | |||||
| if (error != 0) | |||||
| return (error); | |||||
| /* Convert current format to previous one */ | |||||
| xent->masklen = tent->masklen; | |||||
| pval = get_table_value(da->ch, da->tc, da->tent.v.kidx); | |||||
| xent->value = ipfw_export_table_value_legacy(pval); | |||||
| /* Apply some hacks */ | |||||
| if (tc->no.subtype == IPFW_TABLE_ADDR && tent->subtype == AF_INET) { | |||||
| xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; | |||||
| xent->flags = IPFW_TCF_INET; | |||||
| } else | |||||
| memcpy(&xent->k, &tent->k, sizeof(xent->k)); | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Helper function to export table algo data | * Helper function to export table algo data | ||||
| * to tentry format before calling user function. | * to tentry format before calling user function. | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns 0 on success. | ||||
| */ | */ | ||||
| static int | static int | ||||
| prepare_table_tentry(void *e, void *arg) | prepare_table_tentry(void *e, void *arg) | ||||
| { | { | ||||
| Show All 15 Lines | prepare_table_tentry(void *e, void *arg) | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Allow external consumers to read table entries in standard format. | * Allow external consumers to read table entries in standard format. | ||||
| */ | */ | ||||
| int | int | ||||
| ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx, | ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint32_t kidx, | ||||
| ta_foreach_f *f, void *arg) | ta_foreach_f *f, void *arg) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| struct table_algo *ta; | struct table_algo *ta; | ||||
| struct dump_args da; | struct dump_args da; | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| Show All 13 Lines | ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint32_t kidx, | ||||
| ta->foreach(tc->astate, da.ti, prepare_table_tentry, &da); | ta->foreach(tc->astate, da.ti, prepare_table_tentry, &da); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Table algorithms | * Table algorithms | ||||
| */ | */ | ||||
| /* | /* | ||||
| * Finds algorithm by index, table type or supplied name. | * Finds algorithm by index, table type or supplied name. | ||||
| * | * | ||||
| * Returns pointer to algo or NULL. | * Returns pointer to algo or NULL. | ||||
| */ | */ | ||||
| static struct table_algo * | static struct table_algo * | ||||
| find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) | find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) | ||||
| ▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| } | } | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| classify_srcdst(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | classify_srcdst(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) | ||||
| { | { | ||||
| /* Basic IPv4/IPv6 or u32 lookups */ | ipfw_insn_table *cmd; | ||||
| *puidx = cmd->arg1; | |||||
| /* Assume ADDR by default */ | |||||
| *ptype = IPFW_TABLE_ADDR; | |||||
| int v; | |||||
| if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { | /* Basic IPv4/IPv6 or u32 lookups */ | ||||
| /* | cmd = insntod(cmd0, table); | ||||
| * generic lookup. The key must be | *puidx = cmd->kidx; | ||||
| * in 32bit big-endian format. | switch(cmd0->arg1) { | ||||
| */ | |||||
| v = ((ipfw_insn_u32 *)cmd)->d[1]; | |||||
| switch (v) { | |||||
| case LOOKUP_DST_IP: | case LOOKUP_DST_IP: | ||||
| case LOOKUP_SRC_IP: | case LOOKUP_SRC_IP: | ||||
| default: | |||||
| /* IPv4 src/dst */ | |||||
| *ptype = IPFW_TABLE_ADDR; | |||||
| break; | break; | ||||
| case LOOKUP_DST_PORT: | case LOOKUP_DST_PORT: | ||||
| case LOOKUP_SRC_PORT: | case LOOKUP_SRC_PORT: | ||||
| case LOOKUP_UID: | case LOOKUP_UID: | ||||
| case LOOKUP_JAIL: | case LOOKUP_JAIL: | ||||
| case LOOKUP_DSCP: | case LOOKUP_DSCP: | ||||
| case LOOKUP_MARK: | case LOOKUP_MARK: | ||||
| case LOOKUP_RULENUM: | |||||
| *ptype = IPFW_TABLE_NUMBER; | *ptype = IPFW_TABLE_NUMBER; | ||||
| break; | break; | ||||
| case LOOKUP_DST_MAC: | case LOOKUP_DST_MAC: | ||||
| case LOOKUP_SRC_MAC: | case LOOKUP_SRC_MAC: | ||||
| *ptype = IPFW_TABLE_MAC; | *ptype = IPFW_TABLE_MAC; | ||||
| break; | break; | ||||
| } | } | ||||
| } | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| classify_via(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | classify_via(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) | ||||
| { | { | ||||
| ipfw_insn_if *cmdif; | ipfw_insn_if *cmdif; | ||||
| /* Interface table, possibly */ | /* Interface table, possibly */ | ||||
| cmdif = (ipfw_insn_if *)cmd; | cmdif = insntod(cmd0, if); | ||||
| if (cmdif->name[0] != '\1') | if (cmdif->name[0] != '\1') | ||||
| return (1); | return (1); | ||||
| *ptype = IPFW_TABLE_INTERFACE; | *ptype = IPFW_TABLE_INTERFACE; | ||||
| *puidx = cmdif->p.kidx; | *puidx = cmdif->p.kidx; /* XXXAE */ | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| classify_flow(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) | ||||
| { | { | ||||
| *puidx = insntod(cmd0, table)->kidx; | |||||
| *puidx = cmd->arg1; | |||||
| *ptype = IPFW_TABLE_FLOW; | *ptype = IPFW_TABLE_FLOW; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| classify_mac_lookup(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) | ||||
| { | { | ||||
| *puidx = cmd->arg1; | *puidx = insntod(cmd0, table)->kidx; | ||||
| *ptype = IPFW_TABLE_MAC; | *ptype = IPFW_TABLE_MAC; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | static void | ||||
| update_arg1(ipfw_insn *cmd, uint16_t idx) | update_kidx(ipfw_insn *cmd0, uint32_t idx) | ||||
| { | { | ||||
| insntod(cmd0, table)->kidx = idx; | |||||
| cmd->arg1 = idx; | |||||
| } | } | ||||
| static void | static void | ||||
| update_via(ipfw_insn *cmd, uint16_t idx) | update_via(ipfw_insn *cmd0, uint32_t idx) | ||||
| { | { | ||||
| ipfw_insn_if *cmdif; | insntod(cmd0, if)->p.kidx = idx; | ||||
| cmdif = (ipfw_insn_if *)cmd; | |||||
| cmdif->p.kidx = idx; | |||||
| } | } | ||||
| static int | static int | ||||
| table_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, | table_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, | ||||
| struct named_object **pno) | struct named_object **pno) | ||||
| { | { | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| int error; | int error; | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| error = find_table_err(CHAIN_TO_NI(ch), ti, &tc); | error = find_table_err(CHAIN_TO_NI(ch), ti, &tc); | ||||
| if (error != 0) | if (error != 0) | ||||
| return (error); | return (error); | ||||
| *pno = &tc->no; | *pno = &tc->no; | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* XXX: sets-sets! */ | /* XXX: sets-sets! */ | ||||
| static struct named_object * | static struct named_object * | ||||
| table_findbykidx(struct ip_fw_chain *ch, uint16_t idx) | table_findbykidx(struct ip_fw_chain *ch, uint32_t idx) | ||||
| { | { | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct table_config *tc; | struct table_config *tc; | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| ni = CHAIN_TO_NI(ch); | ni = CHAIN_TO_NI(ch); | ||||
| tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, idx); | tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, idx); | ||||
| KASSERT(tc != NULL, ("Table with index %d not found", idx)); | KASSERT(tc != NULL, ("Table with index %u not found", idx)); | ||||
| return (&tc->no); | return (&tc->no); | ||||
| } | } | ||||
| static int | static int | ||||
| table_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, | table_manage_sets(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, | ||||
| enum ipfw_sets_cmd cmd) | enum ipfw_sets_cmd cmd) | ||||
| { | { | ||||
| switch (cmd) { | switch (cmd) { | ||||
| case SWAP_ALL: | case SWAP_ALL: | ||||
| case TEST_ALL: | case TEST_ALL: | ||||
| case MOVE_ALL: | case MOVE_ALL: | ||||
| /* | /* | ||||
| Show All 28 Lines | |||||
| /* | /* | ||||
| * We register several opcode rewriters for lookup tables. | * We register several opcode rewriters for lookup tables. | ||||
| * All tables opcodes have the same ETLV type, but different subtype. | * All tables opcodes have the same ETLV type, but different subtype. | ||||
| * To avoid invoking sets handler several times for XXX_ALL commands, | * To avoid invoking sets handler several times for XXX_ALL commands, | ||||
| * we use separate manage_sets handler. O_RECV has the lowest value, | * we use separate manage_sets handler. O_RECV has the lowest value, | ||||
| * so it should be called first. | * so it should be called first. | ||||
| */ | */ | ||||
| static int | static int | ||||
| table_manage_sets_all(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, | table_manage_sets_all(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, | ||||
| enum ipfw_sets_cmd cmd) | enum ipfw_sets_cmd cmd) | ||||
| { | { | ||||
| switch (cmd) { | switch (cmd) { | ||||
| case SWAP_ALL: | case SWAP_ALL: | ||||
| case TEST_ALL: | case TEST_ALL: | ||||
| /* | /* | ||||
| * Return success for TEST_ALL, since nothing prevents | * Return success for TEST_ALL, since nothing prevents | ||||
| Show All 13 Lines | return (ipfw_obj_manage_sets(CHAIN_TO_NI(ch), IPFW_TLV_TBL_NAME, | ||||
| set, new_set, cmd)); | set, new_set, cmd)); | ||||
| } | } | ||||
| static struct opcode_obj_rewrite opcodes[] = { | static struct opcode_obj_rewrite opcodes[] = { | ||||
| { | { | ||||
| .opcode = O_IP_SRC_LOOKUP, | .opcode = O_IP_SRC_LOOKUP, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| .classifier = classify_srcdst, | .classifier = classify_srcdst, | ||||
| .update = update_arg1, | .update = update_kidx, | ||||
| .find_byname = table_findbyname, | .find_byname = table_findbyname, | ||||
| .find_bykidx = table_findbykidx, | .find_bykidx = table_findbykidx, | ||||
| .create_object = create_table_compat, | .create_object = create_table_compat, | ||||
| .manage_sets = table_manage_sets, | .manage_sets = table_manage_sets, | ||||
| }, | }, | ||||
| { | { | ||||
| .opcode = O_IP_DST_LOOKUP, | .opcode = O_IP_DST_LOOKUP, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| .classifier = classify_srcdst, | .classifier = classify_srcdst, | ||||
| .update = update_arg1, | .update = update_kidx, | ||||
| .find_byname = table_findbyname, | .find_byname = table_findbyname, | ||||
| .find_bykidx = table_findbykidx, | .find_bykidx = table_findbykidx, | ||||
| .create_object = create_table_compat, | .create_object = create_table_compat, | ||||
| .manage_sets = table_manage_sets, | .manage_sets = table_manage_sets, | ||||
| }, | }, | ||||
| { | { | ||||
| .opcode = O_IP_FLOW_LOOKUP, | .opcode = O_IP_FLOW_LOOKUP, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| .classifier = classify_flow, | .classifier = classify_flow, | ||||
| .update = update_arg1, | .update = update_kidx, | ||||
| .find_byname = table_findbyname, | .find_byname = table_findbyname, | ||||
| .find_bykidx = table_findbykidx, | .find_bykidx = table_findbykidx, | ||||
| .create_object = create_table_compat, | .create_object = create_table_compat, | ||||
| .manage_sets = table_manage_sets, | .manage_sets = table_manage_sets, | ||||
| }, | }, | ||||
| { | { | ||||
| .opcode = O_MAC_SRC_LOOKUP, | .opcode = O_MAC_SRC_LOOKUP, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| .classifier = classify_mac_lookup, | .classifier = classify_mac_lookup, | ||||
| .update = update_arg1, | .update = update_kidx, | ||||
| .find_byname = table_findbyname, | .find_byname = table_findbyname, | ||||
| .find_bykidx = table_findbykidx, | .find_bykidx = table_findbykidx, | ||||
| .create_object = create_table_compat, | .create_object = create_table_compat, | ||||
| .manage_sets = table_manage_sets, | .manage_sets = table_manage_sets, | ||||
| }, | }, | ||||
| { | { | ||||
| .opcode = O_MAC_DST_LOOKUP, | .opcode = O_MAC_DST_LOOKUP, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| .classifier = classify_mac_lookup, | .classifier = classify_mac_lookup, | ||||
| .update = update_arg1, | .update = update_kidx, | ||||
| .find_byname = table_findbyname, | .find_byname = table_findbyname, | ||||
| .find_bykidx = table_findbykidx, | .find_bykidx = table_findbykidx, | ||||
| .create_object = create_table_compat, | .create_object = create_table_compat, | ||||
| .manage_sets = table_manage_sets, | .manage_sets = table_manage_sets, | ||||
| }, | }, | ||||
| { | { | ||||
| .opcode = O_XMIT, | .opcode = O_XMIT, | ||||
| .etlv = IPFW_TLV_TBL_NAME, | .etlv = IPFW_TLV_TBL_NAME, | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets) | ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets) | ||||
| { | { | ||||
| struct opcode_obj_rewrite *rw; | struct opcode_obj_rewrite *rw; | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| struct named_object *no; | struct named_object *no; | ||||
| struct ip_fw *rule; | struct ip_fw *rule; | ||||
| ipfw_insn *cmd; | ipfw_insn *cmd; | ||||
| int cmdlen, i, l; | int cmdlen, i, l; | ||||
| uint16_t kidx; | uint32_t kidx; | ||||
| uint8_t subtype; | uint8_t subtype; | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| if (V_fw_tables_sets == sets) { | if (V_fw_tables_sets == sets) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | unlink_table(struct ip_fw_chain *ch, struct table_config *tc) | ||||
| tc->ta->refcnt--; | tc->ta->refcnt--; | ||||
| /* Notify algo on real @ti address */ | /* Notify algo on real @ti address */ | ||||
| if (tc->ta->change_ti != NULL) | if (tc->ta->change_ti != NULL) | ||||
| tc->ta->change_ti(tc->astate, NULL); | tc->ta->change_ti(tc->astate, NULL); | ||||
| } | } | ||||
| static struct ipfw_sopt_handler scodes[] = { | static struct ipfw_sopt_handler scodes[] = { | ||||
| { IP_FW_TABLE_XCREATE, 0, HDIR_SET, create_table }, | { IP_FW_TABLE_XCREATE, IP_FW3_OPVER, HDIR_SET, create_table }, | ||||
| { IP_FW_TABLE_XDESTROY, 0, HDIR_SET, flush_table_v0 }, | { IP_FW_TABLE_XDESTROY, IP_FW3_OPVER, HDIR_SET, flush_table_v0 }, | ||||
| { IP_FW_TABLE_XFLUSH, 0, HDIR_SET, flush_table_v0 }, | { IP_FW_TABLE_XFLUSH, IP_FW3_OPVER, HDIR_SET, flush_table_v0 }, | ||||
| { IP_FW_TABLE_XMODIFY, 0, HDIR_BOTH, modify_table }, | { IP_FW_TABLE_XMODIFY, IP_FW3_OPVER, HDIR_BOTH, modify_table }, | ||||
| { IP_FW_TABLE_XINFO, 0, HDIR_GET, describe_table }, | { IP_FW_TABLE_XINFO, IP_FW3_OPVER, HDIR_GET, describe_table }, | ||||
| { IP_FW_TABLES_XLIST, 0, HDIR_GET, list_tables }, | { IP_FW_TABLES_XLIST, IP_FW3_OPVER, HDIR_GET, list_tables }, | ||||
| { IP_FW_TABLE_XLIST, 0, HDIR_GET, dump_table_v0 }, | { IP_FW_TABLE_XLIST, IP_FW3_OPVER, HDIR_GET, dump_table_v1 }, | ||||
| { IP_FW_TABLE_XLIST, 1, HDIR_GET, dump_table_v1 }, | { IP_FW_TABLE_XADD, IP_FW3_OPVER, HDIR_BOTH, manage_table_ent_v1 }, | ||||
| { IP_FW_TABLE_XADD, 0, HDIR_BOTH, manage_table_ent_v0 }, | { IP_FW_TABLE_XDEL, IP_FW3_OPVER, HDIR_BOTH, manage_table_ent_v1 }, | ||||
| { IP_FW_TABLE_XADD, 1, HDIR_BOTH, manage_table_ent_v1 }, | { IP_FW_TABLE_XFIND, IP_FW3_OPVER, HDIR_GET, find_table_entry }, | ||||
| { IP_FW_TABLE_XDEL, 0, HDIR_BOTH, manage_table_ent_v0 }, | { IP_FW_TABLE_XSWAP, IP_FW3_OPVER, HDIR_SET, swap_table }, | ||||
| { IP_FW_TABLE_XDEL, 1, HDIR_BOTH, manage_table_ent_v1 }, | { IP_FW_TABLES_ALIST, IP_FW3_OPVER, HDIR_GET, list_table_algo }, | ||||
| { IP_FW_TABLE_XFIND, 0, HDIR_GET, find_table_entry }, | |||||
| { IP_FW_TABLE_XSWAP, 0, HDIR_SET, swap_table }, | |||||
| { IP_FW_TABLES_ALIST, 0, HDIR_GET, list_table_algo }, | |||||
| { IP_FW_TABLE_XGETSIZE, 0, HDIR_GET, get_table_size }, | |||||
| }; | }; | ||||
| static int | static int | ||||
| destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, | destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, | ||||
| void *arg) | void *arg) | ||||
| { | { | ||||
| unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); | unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); | ||||
| Show All 39 Lines | |||||
| { | { | ||||
| struct tables_config *tcfg; | struct tables_config *tcfg; | ||||
| /* Allocate pointers */ | /* Allocate pointers */ | ||||
| ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), | ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), | ||||
| M_IPFW, M_WAITOK | M_ZERO); | M_IPFW, M_WAITOK | M_ZERO); | ||||
| tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); | tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); | ||||
| tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); | tcfg->namehash = ipfw_objhash_create(V_fw_tables_max, | ||||
| DEFAULT_OBJHASH_SIZE); | |||||
| ch->tblcfg = tcfg; | ch->tblcfg = tcfg; | ||||
| ipfw_table_value_init(ch, first); | ipfw_table_value_init(ch, first); | ||||
| ipfw_table_algo_init(ch); | ipfw_table_algo_init(ch); | ||||
| IPFW_ADD_OBJ_REWRITER(first, opcodes); | IPFW_ADD_OBJ_REWRITER(first, opcodes); | ||||
| IPFW_ADD_SOPT_HANDLER(first, scodes); | IPFW_ADD_SOPT_HANDLER(first, scodes); | ||||
| return (0); | return (0); | ||||
| } | } | ||||