Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Mar 2012 20:37:59 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r233478 - in head: sbin/ipfw sys/netinet sys/netinet/ipfw
Message-ID:  <201203252037.q2PKbxhw098617@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sun Mar 25 20:37:59 2012
New Revision: 233478
URL: http://svn.freebsd.org/changeset/base/233478

Log:
  - Permit number of ipfw tables to be changed in runtime.
  
  net.inet.ip.fw.tables_max is now read-write.
  
  - Bump IPFW_TABLES_MAX to 65535
  Default number of tables is still 128
  
  - Remove IPFW_TABLES_MAX from ipfw(8) code.
  
  Sponsored by Yandex LLC
  
  Approved by:    kib(mentor)
  
  MFC after:      2 weeks

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipfw2.c
  head/sys/netinet/ip_fw.h
  head/sys/netinet/ipfw/ip_fw2.c
  head/sys/netinet/ipfw/ip_fw_private.h
  head/sys/netinet/ipfw/ip_fw_table.c

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sbin/ipfw/ipfw.8	Sun Mar 25 20:37:59 2012	(r233478)
@@ -2845,7 +2845,7 @@ node is not passed though the firewall a
 Otherwise, after an action, the packet is
 reinjected into the firewall at the next rule.
 .It Va net.inet.ip.fw.tables_max : No 128
-Maximum number of tables (read-only).
+Maximum number of tables.
 .It Va net.inet.ip.fw.verbose : No 1
 Enables verbose messages.
 .It Va net.inet.ip.fw.verbose_limit : No 0

Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sbin/ipfw/ipfw2.c	Sun Mar 25 20:37:59 2012	(r233478)
@@ -3932,15 +3932,9 @@ ipfw_table_handler(int ac, char *av[])
 
 	len = sizeof(tables_max);
 	if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
-		NULL, 0) == -1) {
-#ifdef IPFW_TABLES_MAX
-		warn("Warn: Failed to get the max tables number via sysctl. "
-		     "Using the compiled in defaults. \nThe reason was");
-		tables_max = IPFW_TABLES_MAX;
-#else
-		errx(1, "Failed sysctlbyname(\"net.inet.ip.fw.tables_max\")");
-#endif
-	}
+		NULL, 0) == -1)
+		errx(1, "Can't determine maximum number of ipfw tables. "
+		    "Perhaps you forgot to load ipfw module?");
 
 	memset(&xent, 0, sizeof(xent));
 

Modified: head/sys/netinet/ip_fw.h
==============================================================================
--- head/sys/netinet/ip_fw.h	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sys/netinet/ip_fw.h	Sun Mar 25 20:37:59 2012	(r233478)
@@ -39,7 +39,8 @@
 /*
  * Default number of ipfw tables.
  */
-#define	IPFW_TABLES_MAX		128
+#define	IPFW_TABLES_MAX		65535
+#define	IPFW_TABLES_DEFAULT	128
 
 /*
  * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit

Modified: head/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw2.c	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sys/netinet/ipfw/ip_fw2.c	Sun Mar 25 20:37:59 2012	(r233478)
@@ -116,8 +116,9 @@ static int default_to_accept;
 VNET_DEFINE(int, autoinc_step);
 VNET_DEFINE(int, fw_one_pass) = 1;
 
+VNET_DEFINE(unsigned int, fw_tables_max);
 /* Use 128 tables by default */
-int fw_tables_max = IPFW_TABLES_MAX;
+static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT;
 
 /*
  * Each rule belongs to one of 32 different sets (0..31).
@@ -148,6 +149,7 @@ ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
 
 #ifdef SYSCTL_NODE
 uint32_t dummy_def = IPFW_DEFAULT_RULE;
+static int sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS);
 
 SYSBEGIN(f3)
 
@@ -167,14 +169,14 @@ SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUT
 SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
     &dummy_def, 0,
     "The default/max possible rule number.");
-SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
-    &V_fw_tables_max, 0,
-    "The maximum number of tables.");
+SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, tables_max,
+    CTLTYPE_UINT|CTLFLAG_RW, 0, 0, sysctl_ipfw_table_num, "IU",
+    "Maximum number of tables");
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
     &default_to_accept, 0,
     "Make the default rule accept all packets.");
 TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
-TUNABLE_INT("net.inet.ip.fw.tables_max", &V_fw_tables_max);
+TUNABLE_INT("net.inet.ip.fw.tables_max", &default_fw_tables);
 SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
     CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
     "Number of static rules");
@@ -2488,6 +2490,26 @@ pullup_failed:
 }
 
 /*
+ * Set maximum number of tables that can be used in given VNET ipfw instance.
+ */
+#ifdef SYSCTL_NODE
+static int
+sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS)
+{
+	int error;
+	unsigned int ntables;
+
+	ntables = V_fw_tables_max;
+
+	error = sysctl_handle_int(oidp, &ntables, 0, req);
+	/* Read operation or some error */
+	if ((error != 0) || (req->newptr == NULL))
+		return (error);
+
+	return (ipfw_resize_tables(&V_layer3_chain, ntables));
+}
+#endif
+/*
  * Module and VNET glue
  */
 
@@ -2543,6 +2565,10 @@ ipfw_init(void)
 		printf("limited to %d packets/entry by default\n",
 		    V_verbose_limit);
 
+	/* Check user-supplied table count for validness */
+	if (default_fw_tables > IPFW_TABLES_MAX)
+	  default_fw_tables = IPFW_TABLES_MAX;
+
 	ipfw_log_bpf(1); /* init */
 	return (error);
 }
@@ -2585,18 +2611,15 @@ vnet_ipfw_init(const void *unused)
 	LIST_INIT(&chain->nat);
 #endif
 
-	/* Check user-supplied number for validness */
-	if (V_fw_tables_max < 0)
-	  V_fw_tables_max = IPFW_TABLES_MAX;
-	if (V_fw_tables_max > 65534)
-	  V_fw_tables_max = 65534;
-
 	/* insert the default rule and create the initial map */
 	chain->n_rules = 1;
 	chain->static_len = sizeof(struct ip_fw);
 	chain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_WAITOK | M_ZERO);
 	if (chain->map)
 		rule = malloc(chain->static_len, M_IPFW, M_WAITOK | M_ZERO);
+
+	/* Set initial number of tables */
+	V_fw_tables_max = default_fw_tables;
 	error = ipfw_init_tables(chain);
 	if (error) {
 		printf("ipfw2: setting up tables failed\n");

Modified: head/sys/netinet/ipfw/ip_fw_private.h
==============================================================================
--- head/sys/netinet/ipfw/ip_fw_private.h	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sys/netinet/ipfw/ip_fw_private.h	Sun Mar 25 20:37:59 2012	(r233478)
@@ -209,8 +209,8 @@ VNET_DECLARE(u_int32_t, set_disable);
 VNET_DECLARE(int, autoinc_step);
 #define V_autoinc_step		VNET(autoinc_step)
 
-extern int fw_tables_max;
-#define V_fw_tables_max		fw_tables_max
+VNET_DECLARE(unsigned int, fw_tables_max);
+#define V_fw_tables_max		VNET(fw_tables_max)
 
 struct ip_fw_chain {
 	struct ip_fw	*rules;		/* list of rules */
@@ -292,6 +292,7 @@ int ipfw_dump_table_entry(struct radix_n
 int ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
 int ipfw_count_xtable(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
 int ipfw_dump_xtable(struct ip_fw_chain *ch, ipfw_xtable *tbl);
+int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
 
 /* In ip_fw_nat.c -- XXX to be moved to ip_var.h */
 

Modified: head/sys/netinet/ipfw/ip_fw_table.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw_table.c	Sun Mar 25 20:09:02 2012	(r233477)
+++ head/sys/netinet/ipfw/ip_fw_table.c	Sun Mar 25 20:37:59 2012	(r233478)
@@ -460,6 +460,68 @@ ipfw_init_tables(struct ip_fw_chain *ch)
 }
 
 int
+ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
+{
+	struct radix_node_head **tables, **xtables, *rnh;
+	struct radix_node_head **tables_old, **xtables_old;
+	uint8_t *tabletype, *tabletype_old;
+	unsigned int ntables_old, tbl;
+
+	/* Check new value for validity */
+	if (ntables > IPFW_TABLES_MAX)
+		ntables = IPFW_TABLES_MAX;
+
+	/* Allocate new pointers */
+	tables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
+	xtables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
+	tabletype = malloc(ntables * sizeof(uint8_t), M_IPFW, M_WAITOK | M_ZERO);
+
+	IPFW_WLOCK(ch);
+
+	tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
+
+	/* Copy old table pointers */
+	memcpy(tables, ch->tables, sizeof(void *) * tbl);
+	memcpy(xtables, ch->xtables, sizeof(void *) * tbl);
+	memcpy(tabletype, ch->tabletype, sizeof(uint8_t) * tbl);
+
+	/* Change pointers and number of tables */
+	tables_old = ch->tables;
+	xtables_old = ch->xtables;
+	tabletype_old = ch->tabletype;
+	ch->tables = tables;
+	ch->xtables = xtables;
+	ch->tabletype = tabletype;
+
+	ntables_old = V_fw_tables_max;
+	V_fw_tables_max = ntables;
+
+	IPFW_WUNLOCK(ch);
+
+	/* Check if we need to destroy radix trees */
+	if (ntables < ntables_old) {
+		for (tbl = ntables; tbl < ntables_old; tbl++) {
+			if ((rnh = tables_old[tbl]) != NULL) {
+				rnh->rnh_walktree(rnh, flush_table_entry, rnh);
+				rn_detachhead((void **)&rnh);
+			}
+
+			if ((rnh = xtables_old[tbl]) != NULL) {
+				rnh->rnh_walktree(rnh, flush_table_entry, rnh);
+				rn_detachhead((void **)&rnh);
+			}
+		}
+	}
+
+	/* Free old pointers */
+	free(tables_old, M_IPFW);
+	free(xtables_old, M_IPFW);
+	free(tabletype_old, M_IPFW);
+
+	return (0);
+}
+
+int
 ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
     uint32_t *val)
 {



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