Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Aug 2014 15:51:49 +0000 (UTC)
From:      Alexander V. Chernikov <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r269880 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <53ea3815.6a8f.771861e@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Tue Aug 12 15:51:48 2014
New Revision: 269880
URL: http://svnweb.freebsd.org/changeset/base/269880

Log:
  Change tablearg value to be 0 (try #2).
  Most of the tablearg-supported opcodes does not accept 0 as valid value:
   O_TAG, O_TAGGED, O_PIPE, O_QUEUE, O_DIVERT, O_TEE, O_SKIPTO, O_CALLRET,
   O_NETGRAPH, O_NGTEE, O_NAT treats 0 as invalid input.
  
  The rest are O_SETDSCP and O_SETFIB.
  'Fix' them by adding high-order bit (0x8000) set for non-tablearg values.
  Do translation in kernel for old clients (import_rule0 / export_rule0),
  teach current ipfw(8) binary to add/remove given bit.
  
  This change does not affect handling SETDSCP values, but limit
  O_SETFIB values to 32767 instead of 65k. Since currently we have either
  old (16) or new (2^32) max fibs, this should not be a big deal:
  we're definitely OK for former and have to add another opcode to deal
  with latter, regardless of tablearg value.

Modified:
  projects/ipfw/sbin/ipfw/ipfw2.c
  projects/ipfw/sbin/ipfw/ipfw2.h
  projects/ipfw/sys/netinet/ip_fw.h
  projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
  projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.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	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sbin/ipfw/ipfw2.c	Tue Aug 12 15:51:48 2014	(r269880)
@@ -93,7 +93,7 @@ int ipfw_socket = -1;
 	if (!av[0])							\
 		errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
 	if (_substrcmp(*av, "tablearg") == 0) {				\
-		arg = IP_FW_TABLEARG;					\
+		arg = IP_FW_TARG;					\
 		break;							\
 	}								\
 									\
@@ -111,7 +111,7 @@ int ipfw_socket = -1;
 		errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \
 		    match_value(s_x, tok), min, max, *av);		\
 									\
-	if (_xval == IP_FW_TABLEARG)					\
+	if (_xval == IP_FW_TARG)					\
 		errx(EX_DATAERR, "%s: illegal argument value: %s",	\
 		    match_value(s_x, tok), *av);			\
 	arg = _xval;							\
@@ -123,7 +123,7 @@ PRINT_UINT_ARG(const char *str, uint32_t
 {
 	if (str != NULL)
 		printf("%s",str);
-	if (arg == IP_FW_TABLEARG)
+	if (arg == IP_FW_TARG)
 		printf("tablearg");
 	else
 		printf("%u", arg);
@@ -469,7 +469,7 @@ bprint_uint_arg(struct buf_pr *bp, const
 
 	if (str != NULL)
 		bprintf(bp, "%s", str);
-	if (arg == IP_FW_TABLEARG)
+	if (arg == IP_FW_TARG)
 		bprintf(bp, "tablearg");
 	else
 		bprintf(bp, "%u", arg);
@@ -1386,6 +1386,7 @@ show_static_rule(struct cmdline_opts *co
 	ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
 	ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
 	int or_block = 0;	/* we are in an or block */
+	uint32_t uval;
 
 	if ((fo->set_mask & (1 << rule->set)) == 0) {
 		/* disabled mask */
@@ -1556,17 +1557,22 @@ show_static_rule(struct cmdline_opts *co
 			break;
 
 		case O_SETFIB:
-			bprint_uint_arg(bp, "setfib ", cmd->arg1);
+			bprint_uint_arg(bp, "setfib ", cmd->arg1 & 0x7FFF);
  			break;
 
 		case O_SETDSCP:
 		    {
 			const char *code;
 
-			if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
+			if (cmd->arg1 == IP_FW_TARG) {
+				bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+				break;
+			}
+			uval = cmd->arg1 & 0x3F;
+			if ((code = match_value(f_ipdscp, uval)) != NULL)
 				bprintf(bp, "setdscp %s", code);
 			else
-				bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+				bprint_uint_arg(bp, "setdscp ", uval);
 		    }
  			break;
 
@@ -3597,11 +3603,11 @@ chkarg:
 			errx(EX_USAGE, "missing argument for %s", *(av - 1));
 		if (isdigit(**av)) {
 			action->arg1 = strtoul(*av, NULL, 10);
-			if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG)
+			if (action->arg1 <= 0 || action->arg1 >= IP_FW_TARG)
 				errx(EX_DATAERR, "illegal argument for %s",
 				    *(av - 1));
 		} else if (_substrcmp(*av, "tablearg") == 0) {
-			action->arg1 = IP_FW_TABLEARG;
+			action->arg1 = IP_FW_TARG;
 		} else if (i == TOK_DIVERT || i == TOK_TEE) {
 			struct servent *s;
 			setservent(1);
@@ -3725,7 +3731,7 @@ chkarg:
 		action->opcode = O_SETFIB;
 		NEED1("missing fib number");
 		if (_substrcmp(*av, "tablearg") == 0) {
-			action->arg1 = IP_FW_TABLEARG;
+			action->arg1 = IP_FW_TARG;
 		} else {
 		        action->arg1 = strtoul(*av, NULL, 10);
 			if (sysctlbyname("net.fibs", &numfibs, &intsize,
@@ -3733,6 +3739,8 @@ chkarg:
 				errx(EX_DATAERR, "fibs not suported.\n");
 			if (action->arg1 >= numfibs)  /* Temporary */
 				errx(EX_DATAERR, "fib too large.\n");
+			/* Add high-order bit to fib to make room for tablearg*/
+			action->arg1 |= 0x8000;
 		}
 		av++;
 		break;
@@ -3745,13 +3753,16 @@ chkarg:
 		action->opcode = O_SETDSCP;
 		NEED1("missing DSCP code");
 		if (_substrcmp(*av, "tablearg") == 0) {
-			action->arg1 = IP_FW_TABLEARG;
+			action->arg1 = IP_FW_TARG;
 		} else if (isalpha(*av[0])) {
 			if ((code = match_token(f_ipdscp, *av)) == -1)
 				errx(EX_DATAERR, "Unknown DSCP code");
 			action->arg1 = code;
 		} else
 		        action->arg1 = strtoul(*av, NULL, 10);
+		/* Add high-order bit to DSCP to make room for tablearg */
+		if (action->arg1 != IP_FW_TARG)
+			action->arg1 |= 0x8000;
 		av++;
 		break;
 	    }

Modified: projects/ipfw/sbin/ipfw/ipfw2.h
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.h	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sbin/ipfw/ipfw2.h	Tue Aug 12 15:51:48 2014	(r269880)
@@ -228,6 +228,7 @@ enum tokens {
 	TOK_LOCK,
 	TOK_UNLOCK,
 };
+
 /*
  * the following macro returns an error message if we run out of
  * arguments.

Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netinet/ip_fw.h	Tue Aug 12 15:51:48 2014	(r269880)
@@ -47,18 +47,17 @@
 
 /*
  * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit
- * argument between 1 and 65534. The value 0 is unused, the value
- * 65535 (IP_FW_TABLEARG) is used to represent 'tablearg', i.e. the
- * can be 1..65534, or 65535 to indicate the use of a 'tablearg'
+ * argument between 1 and 65534. The value 0 (IP_FW_TARG) is used
+ * to represent 'tablearg' value, e.g.  indicate the use of a 'tablearg'
  * result of the most recent table() lookup.
  * Note that 16bit is only a historical limit, resulting from
  * the use of a 16-bit fields for that value. In reality, we can have
- * 2^32 pipes, queues, tag values and so on, and use 0 as a tablearg.
- * Note there are some opcodes where value 0 is perfectly valid (fib, dscp).
+ * 2^32 pipes, queues, tag values and so on.
  */
 #define	IPFW_ARG_MIN		1
 #define	IPFW_ARG_MAX		65534
-#define IP_FW_TABLEARG		65535
+#define IP_FW_TABLEARG		65535	/* Compat value for old clients */
+#define	IP_FW_TARG		0	/* Current tablearg value */
 
 /*
  * Number of entries in the call stack of the call/return commands.

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c	Tue Aug 12 15:51:48 2014	(r269880)
@@ -810,7 +810,7 @@ jump_fast(struct ip_fw_chain *chain, str
 	 * whose version is written in f->next_rule
 	 * (horrible hacks to avoid changing the ABI).
 	 */
-	if (num != IP_FW_TABLEARG && f->cached_id == chain->id)
+	if (num != IP_FW_TARG && f->cached_id == chain->id)
 		f_pos = f->cached_pos;
 	else {
 		int i = IP_FW_ARG_TABLEARG(num);
@@ -822,7 +822,7 @@ jump_fast(struct ip_fw_chain *chain, str
 		else
 			f_pos = ipfw_find_rule(chain, i, 0);
 		/* update the cache */
-		if (num != IP_FW_TABLEARG) {
+		if (num != IP_FW_TARG) {
 			f->cached_id = chain->id;
 			f->cached_pos = f_pos;
 		}
@@ -2400,7 +2400,7 @@ do {								\
 				uint32_t fib;
 
 				IPFW_INC_RULE_COUNTER(f, pktlen);
-				fib = IP_FW_ARG_TABLEARG(cmd->arg1);
+				fib = IP_FW_ARG_TABLEARG(cmd->arg1) & 0x7FFFF;
 				if (fib >= rt_numfibs)
 					fib = 0;
 				M_SETFIB(m, fib);
@@ -2461,7 +2461,7 @@ do {								\
 					    retval = IP_FW_DENY;
 					    break;
 					}
-					if (cmd->arg1 != IP_FW_TABLEARG)
+					if (cmd->arg1 != IP_FW_TARG)
 					    ((ipfw_insn_nat *)cmd)->nat = t;
 				}
 				retval = ipfw_nat_ptr(args, t, m);

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c	Tue Aug 12 15:51:48 2014	(r269880)
@@ -719,7 +719,7 @@ ipfw_install_state(struct ip_fw *rule, i
 		conn_limit = IP_FW_ARG_TABLEARG(cmd->conn_limit);
 		  
 		DEB(
-		if (cmd->conn_limit == IP_FW_TABLEARG)
+		if (cmd->conn_limit == IP_FW_TARG)
 			printf("ipfw: %s: O_LIMIT rule, conn_limit: %u "
 			    "(tablearg)\n", __func__, conn_limit);
 		else

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h	Tue Aug 12 15:51:48 2014	(r269880)
@@ -384,7 +384,7 @@ struct ipfw_ifc {
 #endif
 
 
-#define	IP_FW_ARG_TABLEARG(a)	(((a) == IP_FW_TABLEARG) ? tablearg : (a))
+#define	IP_FW_ARG_TABLEARG(a)	(((a) == IP_FW_TARG) ? tablearg : (a))
 /*
  * The lock is heavily used by ip_fw2.c (the main file) and ip_fw_nat.c
  * so the variable and the macros must be here.

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c	Tue Aug 12 15:51:48 2014	(r269880)
@@ -375,7 +375,7 @@ export_cntr0_base(struct ip_fw *krule, s
 }
 
 /*
- * Copies rule @urule from v1 userland format
+ * Copies rule @urule from v1 userland format (current).
  * to kernel @krule.
  * Assume @krule is zeroed.
  */
@@ -456,6 +456,7 @@ import_rule0(struct rule_check_info *ci)
 	struct ip_fw *krule;
 	int cmdlen, l;
 	ipfw_insn *cmd;
+	ipfw_insn_limit *lcmd;
 	ipfw_insn_if *cmdif;
 
 	urule = (struct ip_fw_rule0 *)ci->urule;
@@ -477,36 +478,69 @@ import_rule0(struct rule_check_info *ci)
 
 	/*
 	 * Alter opcodes:
-	 * 1) convert table number in iface opcodes to u16
+	 * 1) convert tablearg value from 65335 to 0
+	 * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room for targ).
+	 * 3) convert table number in iface opcodes to u16
 	 */
-	l = urule->cmd_len;
-	cmd = urule->cmd;
+	l = krule->cmd_len;
+	cmd = krule->cmd;
 	cmdlen = 0;
 
-	for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
-	        cmdlen = F_LEN(cmd);
+	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
+		cmdlen = F_LEN(cmd);
+
+		switch (cmd->opcode) {
+		/* Opcodes supporting tablearg */
+		case O_TAG:
+		case O_TAGGED:
+		case O_PIPE:
+		case O_QUEUE:
+		case O_DIVERT:
+		case O_TEE:
+		case O_SKIPTO:
+		case O_CALLRETURN:
+		case O_NETGRAPH:
+		case O_NGTEE:
+		case O_NAT:
+			if (cmd->arg1 == 65535)
+				cmd->arg1 = IP_FW_TARG;
+			break;
+		case O_SETFIB:
+		case O_SETDSCP:
+			if (cmd->arg1 == 65535)
+				cmd->arg1 = IP_FW_TARG;
+			else
+				cmd->arg1 |= 0x8000;
+			break;
+		case O_LIMIT:
+			lcmd = (ipfw_insn_limit *)cmd;
+			if (lcmd->conn_limit == 65535)
+				lcmd->conn_limit = IP_FW_TARG;
+			break;
+		/* Interface tables */
+		case O_XMIT:
+		case O_RECV:
+		case O_VIA:
+			/* Interface table, possibly */
+			cmdif = (ipfw_insn_if *)cmd;
+			if (cmdif->name[0] != '\1')
+				break;
 
-	        switch (cmd->opcode) {
-	        /* Interface tables */
-	        case O_XMIT:
-	        case O_RECV:
-	        case O_VIA:
-	                /* Interface table, possibly */
-	                cmdif = (ipfw_insn_if *)cmd;
-	                if (cmdif->name[0] != '\1')
-	                        break;
-
-	                cmdif->p.kidx = cmdif->p.glob;
-	                break;
-	        }
+			cmdif->p.kidx = (uint16_t)cmdif->p.glob;
+			break;
+		}
 	}
 }
 
+/*
+ * Copies rule @krule from kernel to FreeBSD8 userland format (v0)
+ */
 static void
 export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
 {
 	int cmdlen, l;
 	ipfw_insn *cmd;
+	ipfw_insn_limit *lcmd;
 	ipfw_insn_if *cmdif;
 
 	/* copy header */
@@ -526,28 +560,57 @@ export_rule0(struct ip_fw *krule, struct
 
 	/*
 	 * Alter opcodes:
-	 * 1) convert table number in iface opcodes to int
+	 * 1) convert tablearg value from 0 to 65335
+	 * 2) Remove highest bit from O_SETFIB/O_SETDSCP values.
+	 * 3) convert table number in iface opcodes to int
 	 */
 	l = urule->cmd_len;
 	cmd = urule->cmd;
 	cmdlen = 0;
 
-	for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
-	        cmdlen = F_LEN(cmd);
+	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
+		cmdlen = F_LEN(cmd);
 
-	        switch (cmd->opcode) {
-	        /* Interface tables */
-	        case O_XMIT:
-	        case O_RECV:
-	        case O_VIA:
-	                /* Interface table, possibly */
-	                cmdif = (ipfw_insn_if *)cmd;
-	                if (cmdif->name[0] != '\1')
-	                        break;
-
-	                cmdif->p.glob = cmdif->p.kidx;
-	                break;
-	        }
+		switch (cmd->opcode) {
+		/* Opcodes supporting tablearg */
+		case O_TAG:
+		case O_TAGGED:
+		case O_PIPE:
+		case O_QUEUE:
+		case O_DIVERT:
+		case O_TEE:
+		case O_SKIPTO:
+		case O_CALLRETURN:
+		case O_NETGRAPH:
+		case O_NGTEE:
+		case O_NAT:
+			if (cmd->arg1 == IP_FW_TARG)
+				cmd->arg1 = 65535;
+			break;
+		case O_SETFIB:
+		case O_SETDSCP:
+			if (cmd->arg1 == IP_FW_TARG)
+				cmd->arg1 = 65535;
+			else
+				cmd->arg1 &= ~0x8000;
+			break;
+		case O_LIMIT:
+			lcmd = (ipfw_insn_limit *)cmd;
+			if (lcmd->conn_limit == IP_FW_TARG)
+				lcmd->conn_limit = 65535;
+			break;
+		/* Interface tables */
+		case O_XMIT:
+		case O_RECV:
+		case O_VIA:
+			/* Interface table, possibly */
+			cmdif = (ipfw_insn_if *)cmd;
+			if (cmdif->name[0] != '\1')
+				break;
+
+			cmdif->p.glob = cmdif->p.kidx;
+			break;
+		}
 	}
 }
 
@@ -1391,10 +1454,10 @@ check_ipfw_rule_body(ipfw_insn *cmd, int
 		case O_SETFIB:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
 				goto bad_size;
-			if ((cmd->arg1 != IP_FW_TABLEARG) &&
-			    (cmd->arg1 >= rt_numfibs)) {
+			if ((cmd->arg1 != IP_FW_TARG) &&
+			    ((cmd->arg1 & 0x7FFFF) >= rt_numfibs)) {
 				printf("ipfw: invalid fib number %d\n",
-					cmd->arg1);
+					cmd->arg1 & 0x7FFFF);
 				return EINVAL;
 			}
 			goto check_action;

Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Tue Aug 12 14:53:02 2014	(r269879)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c	Tue Aug 12 15:51:48 2014	(r269880)
@@ -2482,7 +2482,7 @@ classify_table_opcode(ipfw_insn *cmd, ui
 			break;
 
 		*ptype = IPFW_TABLE_INTERFACE;
-		*puidx = cmdif->p.glob;
+		*puidx = cmdif->p.kidx;
 		skip = 0;
 		break;
 	case O_IP_FLOW_LOOKUP:
@@ -2515,7 +2515,7 @@ update_table_opcode(ipfw_insn *cmd, uint
 	case O_VIA:
 		/* Interface table, possibly */
 		cmdif = (ipfw_insn_if *)cmd;
-		cmdif->p.glob = idx;
+		cmdif->p.kidx = idx;
 		break;
 	case O_IP_FLOW_LOOKUP:
 		cmd->arg1 = idx;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53ea3815.6a8f.771861e>