Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Jun 2014 10:58:39 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r267467 - in projects/ipfw: sbin/ipfw sys/conf sys/netinet sys/netpfil/ipfw
Message-ID:  <201406141058.s5EAwdkp008536@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406141058.s5EAwdkp008536>