svn commit: r267467 - in projects/ipfw: sbin/ipfw sys/conf sys/netinet sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Sat Jun 14 10:58:41 UTC 2014
Author: melifaro
Date: Sat Jun 14 10:58:39 2014
New Revision: 267467
URL: http://svnweb.freebsd.org/changeset/base/267467
Log:
Add API to ease adding new algorithms/new tabletypes to ipfw.
Kernel-side changelog:
* Split general tables code and algorithm-specific table data.
Current algorithms (IPv4/IPv6 radix and interface tables radix) moved to
new ip_fw_table_algo.c file.
Tables code now supports any algorithm implementing the following callbacks:
+struct table_algo {
+ char name[64];
+ int idx;
+ ta_init *init;
+ ta_destroy *destroy;
+ table_lookup_t *lookup;
+ ta_prepare_add *prepare_add;
+ ta_prepare_del *prepare_del;
+ ta_add *add;
+ ta_del *del;
+ ta_flush_entry *flush_entry;
+ ta_foreach *foreach;
+ ta_dump_entry *dump_entry;
+ ta_dump_xentry *dump_xentry;
+};
* Change ->state, ->xstate, ->tabletype fields of ip_fw_chain to
->tablestate pointer (array of 32 bytes structures necessary for
runtime lookups (can be probably shrinked to 16 bytes later):
+struct table_info {
+ table_lookup_t *lookup; /* Lookup function */
+ void *state; /* Lookup radix/other structure */
+ void *xstate; /* eXtended state */
+ u_long data; /* Hints for given func */
+};
* Add count method for namedobj instance to ease size calculations
* Bump ip_fw3 buffer in ipfw_clt 128->256 bytes.
* Improve bitmask resizing on tables_max change.
* Remove table numbers checking from most places.
* Fix wrong nesting in ipfw_rewrite_table_uidx().
* Add IP_FW_OBJ_LIST opcode (list all objects of given type, currently
implemented for IPFW_OBJTYPE_TABLE).
* Add IP_FW_OBJ_LISTSIZE (get buffer size to hold IP_FW_OBJ_LIST data,
currenly implemented for IPFW_OBJTYPE_TABLE).
* Add IP_FW_OBJ_INFO (requests info for one object of given type).
Some name changes:
s/ipfw_xtable_tlv/ipfw_obj_tlv/ (no table specifics)
s/ipfw_xtable_ntlv/ipfw_obj_ntlv/ (no table specifics)
Userland changes:
* Add do_set3() cmd to ipfw2 to ease dealing with op3-embeded opcodes.
* Add/improve support for destroy/info cmds.
Added:
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified:
projects/ipfw/sbin/ipfw/ipfw2.c
projects/ipfw/sys/conf/files
projects/ipfw/sys/netinet/ip_fw.h
projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 14 10:58:39 2014 (r267467)
@@ -448,6 +448,33 @@ do_cmd(int optname, void *optval, uintpt
}
/*
+ * do_set3 - pass ipfw control cmd to kernel
+ * @optname: option name
+ * @optval: pointer to option data
+ * @optlen: option length
+ *
+ * Assumes op3 header is already embedded.
+ * Calls setsockopt() with IP_FW3 as kernel-visible opcode.
+ * Returns 0 on success or -1 otherwise.
+ */
+static int
+do_set3(int optname, ip_fw3_opheader *op3, socklen_t optlen)
+{
+
+ if (co.test_only)
+ return (0);
+
+ if (ipfw_socket == -1)
+ ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (ipfw_socket < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ op3->opcode = optname;
+
+ return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen));
+}
+
+/*
* do_setcmd3 - pass ipfw control cmd to kernel
* @optname: option name
* @optval: pointer to option data
@@ -4124,6 +4151,10 @@ ipfw_flush(int force)
static void table_list(uint16_t num, int need_header);
static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
+static int table_destroy(char *name, uint32_t set);
+static int table_get_info(char *name, uint32_t set, ipfw_xtable_info *i);
+static void table_show_info(ipfw_xtable_info *i);
+static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx);
/*
* Retrieve maximum number of tables supported by ipfw(4) module.
@@ -4167,12 +4198,17 @@ ipfw_table_handler(int ac, char *av[])
int is_all;
uint32_t a;
uint32_t tables_max;
+ uint32_t set;
+ int error;
+ char *tablename;
tables_max = ipfw_get_tables_max();
memset(&xent, 0, sizeof(xent));
ac--; av++;
+ tablename = *av;
+ set = 0;
if (ac && isdigit(**av)) {
xent.tbl = atoi(*av);
is_all = 0;
@@ -4244,22 +4280,13 @@ ipfw_table_handler(int ac, char *av[])
table_list(xent.tbl, is_all);
} while (++xent.tbl < a);
} else if (_substrcmp(*av, "destroy") == 0) {
- char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_ntlv)];
- ipfw_obj_header *oh;
- ipfw_xtable_ntlv *ntlv;
-
- memset(xbuf, 0, sizeof(xbuf));
- oh = (ipfw_obj_header *)xbuf;
- ntlv = (ipfw_xtable_ntlv *)(oh + 1);
-
- ntlv->head.type = IPFW_TLV_NAME;
- ntlv->head.length = sizeof(*ntlv);
- ntlv->idx = 1;
- snprintf(ntlv->name, sizeof(ntlv->name), "%d", xent.tbl);
- oh->idx = 1;
- oh->objtype = IPFW_OBJTYPE_TABLE;
- if (do_setcmd3(IP_FW_OBJ_DEL, xbuf, sizeof(xbuf)) != 0)
- err(EX_OSERR, "setsockopt(IP_FW_OBJ_DEL)");
+ if (table_destroy(tablename, set) != 0)
+ err(EX_OSERR, "failed to destroy table %s", tablename);
+ } else if (_substrcmp(*av, "info") == 0) {
+ ipfw_xtable_info i;
+ if ((error = table_get_info(tablename, set, &i)) != 0)
+ err(EX_OSERR, "failed to request table info");
+ table_show_info(&i);
} else
errx(EX_USAGE, "invalid table command %s", *av);
}
@@ -4363,6 +4390,93 @@ table_fill_xentry(char *arg, ipfw_table_
}
static void
+table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx)
+{
+
+ ntlv->head.type = IPFW_TLV_NAME;
+ ntlv->head.length = sizeof(ipfw_obj_ntlv);
+ ntlv->idx = uidx;
+ strlcpy(ntlv->name, name, sizeof(ntlv->name));
+}
+
+/*
+ * Destroys given table @name in given @set.
+ * Returns 0 on success.
+ */
+static int
+table_destroy(char *name, uint32_t set)
+{
+ ipfw_obj_header oh;
+
+ memset(&oh, 0, sizeof(oh));
+ oh.idx = 1;
+ oh.objtype = IPFW_OBJTYPE_TABLE;
+ table_fill_ntlv(&oh.ntlv, name, 1);
+ if (do_set3(IP_FW_OBJ_DEL, &oh.opheader, sizeof(oh)) != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Retrieves info for given table @name in given @set and stores
+ * it inside @i.
+ * Returns 0 on success.
+ */
+static int
+table_get_info(char *name, uint32_t set, ipfw_xtable_info *i)
+{
+ char tbuf[sizeof(ipfw_obj_header)+sizeof(ipfw_xtable_info)];
+ ipfw_obj_header *oh;
+ size_t sz;
+
+ sz = sizeof(tbuf);
+ memset(tbuf, 0, sizeof(tbuf));
+ oh = (ipfw_obj_header *)tbuf;
+
+ oh->opheader.opcode = IP_FW_OBJ_INFO;
+ oh->set = set;
+ oh->idx = 1;
+ oh->objtype = IPFW_OBJTYPE_TABLE;
+ table_fill_ntlv(&oh->ntlv, name, 1);
+
+ if (do_cmd(IP_FW3, oh, (uintptr_t)&sz) < 0)
+ return (-1);
+
+ if (sz < sizeof(tbuf))
+ return (-1);
+
+ *i = *(ipfw_xtable_info *)(oh + 1);
+
+ return (0);
+}
+
+/*
+ * Prints table info struct @i in human-readable form.
+ */
+static void
+table_show_info(ipfw_xtable_info *i)
+{
+ char *type;
+
+ printf("--- table %s, set %u ---\n", i->tablename, i->set);
+ switch (i->type) {
+ case IPFW_TABLE_CIDR:
+ type = "cidr";
+ break;
+ case IPFW_TABLE_INTERFACE:
+ type = "iface";
+ break;
+ default:
+ type = "unknown";
+ }
+ printf("type: %s, kindex: %d\n", type, i->kidx);
+ printf("ftype: %d, algorithm: %d\n", i->ftype, i->atype);
+ printf("references: %u\n", i->refcnt);
+ printf("items: %u, size: %u\n", i->count, i->size);
+}
+
+static void
table_list(uint16_t num, int need_header)
{
ipfw_xtable *tbl;
Modified: projects/ipfw/sys/conf/files
==============================================================================
--- projects/ipfw/sys/conf/files Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/conf/files Sat Jun 14 10:58:39 2014 (r267467)
@@ -3449,6 +3449,7 @@ netpfil/ipfw/ip_fw_log.c optional inet i
netpfil/ipfw/ip_fw_pfil.c optional inet ipfirewall
netpfil/ipfw/ip_fw_sockopt.c optional inet ipfirewall
netpfil/ipfw/ip_fw_table.c optional inet ipfirewall
+netpfil/ipfw/ip_fw_table_algo.c optional inet ipfirewall
netpfil/ipfw/ip_fw_nat.c optional inet ipfirewall_nat
netpfil/pf/if_pflog.c optional pflog pf inet
netpfil/pf/if_pfsync.c optional pfsync pf inet
Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/netinet/ip_fw.h Sat Jun 14 10:58:39 2014 (r267467)
@@ -80,6 +80,9 @@ typedef struct _ip_fw3_opheader {
#define IP_FW_TABLE_XGETSIZE 88 /* get table size */
#define IP_FW_TABLE_XLIST 89 /* list table contents */
#define IP_FW_OBJ_DEL 90 /* del table/pipe/etc */
+#define IP_FW_OBJ_LISTSIZE 91 /* get size for table/etc list */
+#define IP_FW_OBJ_LIST 92 /* list all objects of given type */
+#define IP_FW_OBJ_INFO 93 /* request info for one object */
/*
* The kernel representation of ipfw rules is made of a list of
@@ -646,26 +649,53 @@ typedef struct _ipfw_xtable {
ipfw_table_xentry xent[0]; /* entries */
} ipfw_xtable;
-typedef struct _ipfw_xtable_tlv {
+typedef struct _ipfw_obj_tlv {
uint16_t type; /* TLV type */
uint16_t length; /* Total length, aligned to u32 */
-} ipfw_xtable_tlv;
+} ipfw_obj_tlv;
#define IPFW_TLV_NAME 1
/* Object name TLV */
-typedef struct _ipfw_xtable_ntlv {
- ipfw_xtable_tlv head; /* TLV header */
+typedef struct _ipfw_obj_ntlv {
+ ipfw_obj_tlv head; /* TLV header */
uint16_t idx; /* Name index */
uint16_t spare; /* unused */
char name[64]; /* Null-terminated name */
-} ipfw_xtable_ntlv;
+} ipfw_obj_ntlv;
+typedef struct _ipfw_xtable_info {
+ uint8_t type; /* table type (cidr,iface,..) */
+ uint8_t ftype; /* format table type */
+ uint8_t atype; /* algorithm type */
+ uint8_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 */
+ char tablename[64]; /* table name */
+} ipfw_xtable_info;
+
+#define IPFW_OBJTYPE_TABLE 1
+/* IP_FW_OBJ_DEL, IP_FW_OBJ_INFO (followed by ipfw_xtable_info) */
typedef struct _ipfw_obj_header {
ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint32_t set; /* Set we're operating */
uint16_t idx; /* object name index */
- uint16_t objtype; /* object type */
+ uint8_t objtype; /* object type */
+ uint8_t objsubtype; /* object subtype */
+ ipfw_obj_ntlv ntlv; /* object name tlv */
} ipfw_obj_header;
-#define IPFW_OBJTYPE_TABLE 1
+
+/* IP_FW_OBJ_LISTSIZE, IP_FW_OBJ_LIST (followd by ipfw_xtable_info) */
+typedef struct _ipfw_obj_lheader {
+ ip_fw3_opheader opheader; /* IP_FW3 opcode */
+ uint8_t objtype; /* object type */
+ uint8_t spare0;
+ uint16_t spare1;
+ uint32_t count; /* Total objects count */
+ uint32_t size; /* Total objects size */
+ uint32_t objsize; /* Size of one object */
+} ipfw_obj_lheader;
#endif /* _IPFW2_H */
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sat Jun 14 10:58:39 2014 (r267467)
@@ -360,8 +360,8 @@ iface_match(struct ifnet *ifp, ipfw_insn
/* Check by name or by IP address */
if (cmd->name[0] != '\0') { /* match by name */
if (cmd->name[0] == '\1') /* use tablearg to match */
- return ipfw_lookup_table_extended(chain, cmd->p.glob,
- ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE);
+ return ipfw_lookup_table_extended(chain, cmd->p.glob, 0,
+ ifp->if_xname, tablearg);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -1506,8 +1506,9 @@ do { \
void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
&args->f_id.dst_ip6: &args->f_id.src_ip6;
match = ipfw_lookup_table_extended(chain,
- cmd->arg1, pkey, &v,
- IPFW_TABLE_CIDR);
+ cmd->arg1,
+ sizeof(struct in6_addr),
+ pkey, &v);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
if (match)
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Jun 14 10:58:39 2014 (r267467)
@@ -222,8 +222,7 @@ struct ip_fw_chain {
uint32_t id; /* ruleset id */
int n_rules; /* number of static rules */
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
- struct radix_node_head **tables; /* IPv4 tables */
- struct radix_node_head **xtables; /* extended tables */
+ void *tablestate; /* runtime table info */
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t rwmtx;
#else
@@ -304,7 +303,7 @@ struct tid_info {
uint32_t set; /* table set */
uint16_t uidx; /* table index */
uint8_t type; /* table type */
- uint8_t spare;
+ uint8_t atype;
void *tlvs; /* Pointer to first TLV */
int tlen; /* Total TLV size block */
};
@@ -363,7 +362,9 @@ typedef void (objhash_cb_t)(struct named
struct namedobj_instance *ipfw_objhash_create(uint32_t items);
void ipfw_objhash_destroy(struct namedobj_instance *);
void ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks);
-int ipfw_objhash_bitmap_merge(struct namedobj_instance *ni,
+void ipfw_objhash_bitmap_merge(struct namedobj_instance *ni,
+ void **idx, int *blocks);
+void ipfw_objhash_bitmap_swap(struct namedobj_instance *ni,
void **idx, int *blocks);
void ipfw_objhash_bitmap_free(void *idx, int blocks);
struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni,
@@ -372,6 +373,7 @@ struct named_object *ipfw_objhash_lookup
uint32_t set, uint16_t idx);
void ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no);
void ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no);
+uint32_t ipfw_objhash_count(struct namedobj_instance *ni);
void ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f,
void *arg);
int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint32_t set,
@@ -379,13 +381,60 @@ int ipfw_objhash_free_idx(struct namedob
int ipfw_objhash_alloc_idx(void *n, uint32_t set, uint16_t *pidx);
/* In ip_fw_table.c */
+struct table_info;
+
+typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen,
+ uint32_t *val);
+struct table_info {
+ table_lookup_t *lookup; /* Lookup function */
+ void *state; /* Lookup radix/other structure */
+ void *xstate; /* eXtended state */
+ u_long data; /* Hints for given func */
+};
+
+typedef int (ta_init)(void **ta_state, struct table_info *ti);
+typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
+typedef int (ta_prepare_add)(struct tentry_info *tei, void *ta_buf);
+typedef int (ta_prepare_del)(struct tentry_info *tei, void *ta_buf);
+typedef int (ta_add)(void *ta_state, struct table_info *ti,
+ struct tentry_info *tei, void *ta_buf);
+typedef int (ta_del)(void *ta_state, struct table_info *ti,
+ struct tentry_info *tei, void *ta_buf);
+typedef void (ta_flush_entry)(struct tentry_info *tei, void *ta_buf);
+
+typedef int ta_foreach_f(void *node, void *arg);
+typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ void *arg);
+typedef int ta_dump_entry(void *ta_state, struct table_info *ti, void *e,
+ ipfw_table_entry *ent);
+typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e,
+ ipfw_table_xentry *xent);
+
+struct table_algo {
+ char name[64];
+ int idx;
+ ta_init *init;
+ ta_destroy *destroy;
+ table_lookup_t *lookup;
+ ta_prepare_add *prepare_add;
+ ta_prepare_del *prepare_del;
+ ta_add *add;
+ ta_del *del;
+ ta_flush_entry *flush_entry;
+ ta_foreach *foreach;
+ ta_dump_entry *dump_entry;
+ ta_dump_xentry *dump_xentry;
+};
+void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
+extern struct table_algo radix_cidr, radix_iface;
+
struct radix_node;
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint32_t *val);
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
- uint32_t *val, int type);
+int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+ void *paddr, uint32_t *val);
int ipfw_init_tables(struct ip_fw_chain *ch);
-int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti, int force);
+int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
void ipfw_destroy_tables(struct ip_fw_chain *ch);
int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
int ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
@@ -394,13 +443,17 @@ int ipfw_del_table_entry(struct ip_fw_ch
struct tentry_info *tei);
int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti,
uint32_t *cnt);
-int ipfw_dump_table_entry(struct radix_node *rn, void *arg);
-int ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti,
- ipfw_table *tbl);
int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
uint32_t *cnt);
+int ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti,
+ ipfw_table *tbl);
int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
ipfw_xtable *tbl);
+int ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti,
+ ipfw_xtable_info *i);
+int ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh);
+int ipfw_list_tables(struct ip_fw_chain *ch, struct tid_info *ti,
+ ipfw_obj_lheader *olh);
int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
struct rule_check_info *ci);
@@ -408,6 +461,9 @@ int ipfw_rewrite_table_kidx(struct ip_fw
void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule);
void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
+void ipfw_table_algo_init(struct ip_fw_chain *chain);
+void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
+
/* In ip_fw_nat.c -- XXX to be moved to ip_var.h */
extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Jun 14 10:58:39 2014 (r267467)
@@ -77,6 +77,7 @@ struct namedobj_instance {
uint32_t nv_size; /* number hash size */
u_long *idx_mask; /* used items bitmask */
uint32_t max_blocks; /* number of "long" blocks in bitmask */
+ uint32_t count; /* number of items */
uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */
};
#define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */
@@ -1000,7 +1001,7 @@ ipfw_ctl(struct sockopt *sopt)
struct ip_fw_chain *chain;
u_int32_t rulenum[2];
uint32_t opt;
- char xbuf[128];
+ char xbuf[256];
ip_fw3_opheader *op3 = NULL;
struct rule_check_info ci;
@@ -1171,6 +1172,7 @@ ipfw_ctl(struct sockopt *sopt)
/*--- TABLE manipulations are protected by the IPFW_LOCK ---*/
case IP_FW_OBJ_DEL: /* IP_FW3 */
+ case IP_FW_OBJ_INFO: /* IP_FW3 */
{
struct _ipfw_obj_header *oh;
struct tid_info ti;
@@ -1180,16 +1182,31 @@ ipfw_ctl(struct sockopt *sopt)
break;
}
- oh = (struct _ipfw_obj_header *)(op3 + 1);
+ oh = (struct _ipfw_obj_header *)op3;
switch (oh->objtype) {
case IPFW_OBJTYPE_TABLE:
memset(&ti, 0, sizeof(ti));
ti.set = oh->set;
ti.uidx = oh->idx;
- ti.tlvs = (oh + 1);
- ti.tlen = sopt->sopt_valsize - sizeof(*oh);
- error = ipfw_destroy_table(chain, &ti, 0);
+ ti.tlvs = &oh->ntlv;
+ ti.tlen = oh->ntlv.head.length;
+ if (opt == IP_FW_OBJ_DEL)
+ error = ipfw_destroy_table(chain, &ti);
+ else {
+ /* IP_FW_OBJ_INFO */
+ if (sopt->sopt_valsize < sizeof(*oh) +
+ sizeof(ipfw_xtable_info)) {
+ error = EINVAL;
+ break;
+ }
+
+ error = ipfw_describe_table(chain, &ti,
+ (ipfw_xtable_info *)(oh + 1));
+ if (error == 0)
+ error = sooptcopyout(sopt, oh,
+ sopt->sopt_valsize);
+ }
break;
default:
error = ENOTSUP;
@@ -1563,6 +1580,10 @@ convert_rule_to_8(struct ip_fw *rule)
*
*/
+/*
+ * Allocate new bitmask which can be used to enlarge/shrink
+ * named instance index.
+ */
void
ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
{
@@ -1581,7 +1602,10 @@ ipfw_objhash_bitmap_alloc(uint32_t items
*pblocks = max_blocks;
}
-int
+/*
+ * Copy current bitmask index to new one.
+ */
+void
ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
{
int old_blocks, new_blocks;
@@ -1593,25 +1617,30 @@ ipfw_objhash_bitmap_merge(struct namedob
new_idx = *idx;
new_blocks = *blocks;
- /*
- * FIXME: Permit reducing total amount of tables
- */
- if (old_blocks > new_blocks)
- return (1);
-
for (i = 0; i < IPFW_MAX_SETS; i++) {
memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
old_blocks * sizeof(u_long));
}
+}
+
+/*
+ * Swaps current @ni index with new one.
+ */
+void
+ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
+{
+ int old_blocks;
+ u_long *old_idx;
- ni->idx_mask = new_idx;
- ni->max_blocks = new_blocks;
+ old_idx = ni->idx_mask;
+ old_blocks = ni->max_blocks;
+
+ ni->idx_mask = *idx;
+ ni->max_blocks = *blocks;
/* Save old values */
*idx = old_idx;
*blocks = old_blocks;
-
- return (0);
}
void
@@ -1727,6 +1756,8 @@ ipfw_objhash_add(struct namedobj_instanc
hash = objhash_hash_val(ni, no->set, no->kidx);
TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
+
+ ni->count++;
}
void
@@ -1739,6 +1770,15 @@ ipfw_objhash_del(struct namedobj_instanc
hash = objhash_hash_val(ni, no->set, no->kidx);
TAILQ_REMOVE(&ni->values[hash], no, nv_next);
+
+ ni->count--;
+}
+
+uint32_t
+ipfw_objhash_count(struct namedobj_instance *ni)
+{
+
+ return (ni->count);
}
/*
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Jun 14 06:54:03 2014 (r267466)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Jun 14 10:58:39 2014 (r267467)
@@ -65,252 +65,133 @@ __FBSDID("$FreeBSD$");
#include <netpfil/ipfw/ip_fw_private.h>
-#ifdef MAC
-#include <security/mac/mac_framework.h>
-#endif
-
-static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
-
-struct table_entry {
- struct radix_node rn[2];
- struct sockaddr_in addr, mask;
- u_int32_t value;
-};
-
-struct xaddr_iface {
- uint8_t if_len; /* length of this struct */
- uint8_t pad[7]; /* Align name */
- char ifname[IF_NAMESIZE]; /* Interface name */
-};
-
-struct table_xentry {
- struct radix_node rn[2];
- union {
-#ifdef INET6
- struct sockaddr_in6 addr6;
-#endif
- struct xaddr_iface iface;
- } a;
- union {
-#ifdef INET6
- struct sockaddr_in6 mask6;
-#endif
- struct xaddr_iface ifmask;
- } m;
- u_int32_t value;
-};
/*
* Table has the following `type` concepts:
*
- * `type` represents lookup key type (cidr, ifp, uid, etc..)
- * `ftype` is pure userland field helping to properly format table data
- * `atype` represents exact lookup algorithm for given tabletype.
+ * `no.type` represents lookup key type (cidr, ifp, uid, etc..)
+ * `ta->atype` represents exact lookup algorithm.
* For example, we can use more efficient search schemes if we plan
* to use some specific table for storing host-routes only.
+ * `ftype` is pure userland field helping to properly format table data
+ * e.g. "value is IPv4 nexthop" or "key is port number"
*
*/
struct table_config {
struct named_object no;
uint8_t ftype; /* format table type */
- uint8_t atype; /* algorith type */
uint8_t linked; /* 1 if already linked */
- uint8_t spare0;
+ uint16_t spare0;
uint32_t count; /* Number of records */
char tablename[64]; /* table name */
- void *state; /* Store some state if needed */
- void *xstate;
+ struct table_algo *ta; /* Callbacks for given algo */
+ void *astate; /* algorithm state */
+ struct table_info ti; /* data to put to table_info */
};
#define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0)
struct tables_config {
struct namedobj_instance *namehash;
+ int algo_count;
+ struct table_algo *algo[256];
};
static struct table_config *find_table(struct namedobj_instance *ni,
struct tid_info *ti);
static struct table_config *alloc_table_config(struct namedobj_instance *ni,
- struct tid_info *ti);
+ struct tid_info *ti, struct table_algo *ta);
static void free_table_config(struct namedobj_instance *ni,
struct table_config *tc);
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 int alloc_table_state(void **state, void **xstate, uint8_t type);
static void free_table_state(void **state, void **xstate, uint8_t type);
+static struct table_algo *find_table_algo(struct tables_config *tableconf,
+ struct tid_info *ti);
#define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg)
#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
+#define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k]))
-/*
- * The radix code expects addr and mask to be array of bytes,
- * with the first byte being the length of the array. rn_inithead
- * is called with the offset in bits of the lookup key within the
- * array. If we use a sockaddr_in as the underlying type,
- * sin_len is conveniently located at offset 0, sin_addr is at
- * offset 4 and normally aligned.
- * But for portability, let's avoid assumption and make the code explicit
- */
-#define KEY_LEN(v) *((uint8_t *)&(v))
-#define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr))
-/*
- * Do not require radix to compare more than actual IPv4/IPv6 address
- */
-#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
-#define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr))
-#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname))
-
-#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
-#define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr))
-#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
-
-
-#ifdef INET6
-static inline void
-ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
-{
- uint32_t *cp;
-
- for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
- *cp++ = 0xFFFFFFFF;
- *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
-}
-#endif
int
ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
struct tentry_info *tei)
{
- struct radix_node_head *rnh;
- struct table_entry *ent;
- struct table_xentry *xent;
- struct radix_node *rn;
- in_addr_t addr;
- int offset;
- void *ent_ptr;
- struct sockaddr *addr_ptr, *mask_ptr;
struct table_config *tc, *tc_new;
+ struct table_algo *ta;
struct namedobj_instance *ni;
- char c;
- uint8_t mlen;
uint16_t kidx;
+ int error;
+ char ta_buf[128];
+#if 0
if (ti->uidx >= V_fw_tables_max)
return (EINVAL);
+#endif
- mlen = tei->masklen;
+ IPFW_UH_WLOCK(ch);
+ ni = CHAIN_TO_NI(ch);
- switch (ti->type) {
- case IPFW_TABLE_CIDR:
- if (tei->plen == sizeof(in_addr_t)) {
-#ifdef INET
- /* IPv4 case */
- if (mlen > 32)
- return (EINVAL);
- ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
- ent->value = tei->value;
- /* Set 'total' structure length */
- KEY_LEN(ent->addr) = KEY_LEN_INET;
- KEY_LEN(ent->mask) = KEY_LEN_INET;
- /* Set offset of IPv4 address in bits */
- offset = OFF_LEN_INET;
- ent->mask.sin_addr.s_addr =
- htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
- addr = *((in_addr_t *)tei->paddr);
- ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
- /* Set pointers */
- ent_ptr = ent;
- addr_ptr = (struct sockaddr *)&ent->addr;
- mask_ptr = (struct sockaddr *)&ent->mask;
-#endif
-#ifdef INET6
- } else if (tei->plen == sizeof(struct in6_addr)) {
- /* IPv6 case */
- if (mlen > 128)
- return (EINVAL);
- xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
- xent->value = tei->value;
- /* Set 'total' structure length */
- KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
- KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
- /* Set offset of IPv6 address in bits */
- offset = OFF_LEN_INET6;
- ipv6_writemask(&xent->m.mask6.sin6_addr, mlen);
- memcpy(&xent->a.addr6.sin6_addr, tei->paddr,
- sizeof(struct in6_addr));
- APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr);
- /* Set pointers */
- ent_ptr = xent;
- addr_ptr = (struct sockaddr *)&xent->a.addr6;
- mask_ptr = (struct sockaddr *)&xent->m.mask6;
-#endif
- } else {
- /* Unknown CIDR type */
+ /*
+ * Find and reference existing table.
+ */
+ ta = NULL;
+ if ((tc = find_table(ni, ti)) != NULL) {
+ /* check table type */
+ if (tc->no.type != ti->type) {
+ IPFW_UH_WUNLOCK(ch);
return (EINVAL);
}
- break;
-
- case IPFW_TABLE_INTERFACE:
- /* Check if string is terminated */
- c = ((char *)tei->paddr)[IF_NAMESIZE - 1];
- ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0';
- mlen = strlen((char *)tei->paddr);
- if ((mlen == IF_NAMESIZE - 1) && (c != '\0'))
- return (EINVAL);
- /* Include last \0 into comparison */
- mlen++;
-
- xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
- xent->value = tei->value;
- /* Set 'total' structure length */
- KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen;
- KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen;
- /* Set offset of interface name in bits */
- offset = OFF_LEN_IFACE;
- memcpy(xent->a.iface.ifname, tei->paddr, mlen);
- /* Assume direct match */
- /* TODO: Add interface pattern matching */
-#if 0
- memset(xent->m.ifmask.ifname, 0xFF, IF_NAMESIZE);
- mask_ptr = (struct sockaddr *)&xent->m.ifmask;
-#endif
- /* Set pointers */
- ent_ptr = xent;
- addr_ptr = (struct sockaddr *)&xent->a.iface;
- mask_ptr = NULL;
- break;
-
- default:
- return (EINVAL);
+ /* Reference and unlock */
+ tc->no.refcnt++;
+ ta = tc->ta;
}
-
- IPFW_UH_WLOCK(ch);
-
- ni = CHAIN_TO_NI(ch);
+ IPFW_UH_WUNLOCK(ch);
tc_new = NULL;
- if ((tc = find_table(ni, ti)) == NULL) {
- /* Not found. We have to create new one */
- IPFW_UH_WUNLOCK(ch);
+ if (ta == NULL) {
+ /* Table not found. We have to create new one */
+ if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti)) == NULL)
+ return (ENOTSUP);
- tc_new = alloc_table_config(ni, ti);
+ tc_new = alloc_table_config(ni, ti, ta);
if (tc_new == NULL)
return (ENOMEM);
+ }
- IPFW_UH_WLOCK(ch);
+ /* Prepare record (allocate memory) */
+ memset(&ta_buf, 0, sizeof(ta_buf));
+ error = ta->prepare_add(tei, &ta_buf);
+ if (error != 0) {
+ if (tc_new != NULL)
+ free_table_config(ni, tc_new);
+ return (error);
+ }
+
+ IPFW_UH_WLOCK(ch);
- /* Check if table has already allocated by other thread */
+ ni = CHAIN_TO_NI(ch);
+
+ if (tc == NULL) {
+ /* Check if another table was allocated by other thread */
if ((tc = find_table(ni, ti)) != NULL) {
- if (tc->no.type != ti->type) {
+
+ /*
+ * Check if algoritm is the same since we've
+ * already allocated state using @ta algoritm
+ * callbacks.
+ */
+ if (tc->ta != ta) {
IPFW_UH_WUNLOCK(ch);
free_table_config(ni, tc);
return (EINVAL);
}
} else {
/*
- * New table.
+ * We're first to create this table.
* Set tc_new to zero not to free it afterwards.
*/
tc = tc_new;
@@ -331,212 +212,103 @@ ipfw_add_table_entry(struct ip_fw_chain
tc->no.kidx = kidx;
}
} else {
- /* We still have to check table type */
- if (tc->no.type != ti->type) {
- IPFW_UH_WUNLOCK(ch);
- return (EINVAL);
- }
+ /* Drop reference we've used in first search */
+ tc->no.refcnt--;
}
+
+ /* We've got valid table in @tc. Let's add data */
kidx = tc->no.kidx;
+ ta = tc->ta;
- /* We've got valid table in @tc. Let's add data */
IPFW_WLOCK(ch);
if (tc->linked == 0) {
link_table(ch, tc);
}
- /* XXX: Temporary until splitting add/del to per-type functions */
- rnh = NULL;
- switch (ti->type) {
- case IPFW_TABLE_CIDR:
- if (tei->plen == sizeof(in_addr_t))
- rnh = ch->tables[kidx];
- else
- rnh = ch->xtables[kidx];
- break;
- case IPFW_TABLE_INTERFACE:
- rnh = ch->xtables[kidx];
- break;
- }
+ error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf);
- rn = rnh->rnh_addaddr(addr_ptr, mask_ptr, rnh, ent_ptr);
IPFW_WUNLOCK(ch);
+
+ if (error == 0)
+ tc->count++;
+
IPFW_UH_WUNLOCK(ch);
if (tc_new != NULL)
free_table_config(ni, tc);
- if (rn == NULL) {
- free(ent_ptr, M_IPFW_TBL);
- return (EEXIST);
- }
+ if (error != 0)
+ ta->flush_entry(tei, &ta_buf);
- return (0);
+ return (error);
}
int
ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
struct tentry_info *tei)
{
- struct radix_node_head *rnh;
- struct table_entry *ent;
- in_addr_t addr;
- struct sockaddr_in sa, mask;
- struct sockaddr *sa_ptr, *mask_ptr;
struct table_config *tc;
+ struct table_algo *ta;
struct namedobj_instance *ni;
- char c;
- uint8_t mlen;
uint16_t kidx;
+ int error;
+ char ta_buf[128];
- if (ti->uidx >= V_fw_tables_max)
- return (EINVAL);
-
- mlen = tei->masklen;
-
- switch (ti->type) {
- case IPFW_TABLE_CIDR:
- if (tei->plen == sizeof(in_addr_t)) {
- /* Set 'total' structure length */
- KEY_LEN(sa) = KEY_LEN_INET;
- KEY_LEN(mask) = KEY_LEN_INET;
- mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
- addr = *((in_addr_t *)tei->paddr);
- sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
- sa_ptr = (struct sockaddr *)&sa;
- mask_ptr = (struct sockaddr *)&mask;
-#ifdef INET6
- } else if (tei->plen == sizeof(struct in6_addr)) {
- /* IPv6 case */
- if (mlen > 128)
- return (EINVAL);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list