netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Multiple DSCP match by "-m dscp --dscp-multi value,value,..."
@ 2015-08-03  4:08 Kyeong Yoo
  0 siblings, 0 replies; only message in thread
From: Kyeong Yoo @ 2015-08-03  4:08 UTC (permalink / raw)
  To: netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 859 bytes --]

I found this is useful for me to match multiple DSCP values in a rule.

For example, if you want to handle traffic with a list of DSCP same way, 
instead of using this:

  -A FORWARD ...condition 1... -m dscp --dscp-class AF11 -j TARGET
  -A FORWARD ...condition 1... -m dscp --dscp-class AF21 -j TARGET
  -A FORWARD ...condition 1... -m dscp --dscp-class AF31 -j TARGET
  -A FORWARD ...condition 2... -m dscp --dscp 10 -j TARGET
  -A FORWARD ...condition 2... -m dscp --dscp 10 -j TARGET

you can use:

  -A FORWARD ... -m dscp --dscp-class AF11,AF21,AF31 -j TARGET

This is mainly convenient if you want to 1-to-1 mapping from your app to 
iptables rule.
Also you don't need to add up packet counts (for example) from multiple 
rules.


Does anyone have an idea whether this will be useful for others and 
worth to push?

Thanks.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: linux-dscp-multi.patch --]
[-- Type: text/x-patch; name="linux-dscp-multi.patch", Size: 2191 bytes --]

commit 97958cdb209a6babc88fdeb10893597dcb8856d5
Author: Kyeong Yoo <kyeong.yoo@alliedtelesis.co.nz>
Date:   Mon Jul 27 23:46:05 2015 +1200

    [NETFILTER]: support multiple DSCP value match by "-m dscp --dscp-multi"
    
    Current "dscp" match supports one DSCP value in a rule.
    
    This patch enhances "dscp" match with multiple values:
    
      -m dscp --dscp-multi value,value,...
    
    As there are 64 values possible in DSCP field (6 bits), list of values
    are stored in a 64-bit bitmap.
    
    Reviewed-by: Luuk Paulussen <luuk.paulussen@alliedtelesis.co.nz>
    Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>

diff --git a/include/uapi/linux/netfilter/xt_dscp.h b/include/uapi/linux/netfilter/xt_dscp.h
index 15f8932..bea99fa 100644
--- a/include/uapi/linux/netfilter/xt_dscp.h
+++ b/include/uapi/linux/netfilter/xt_dscp.h
@@ -16,10 +16,17 @@
 #define XT_DSCP_SHIFT	2
 #define XT_DSCP_MAX	0x3f	/* 00111111 */
 
+#define dscp_set_bit(bmap, idx) \
+	(bmap[(idx) >> 5] |= 1U << (idx & 31))
+#define dscp_test_bit(bmap, idx) \
+	(((1U << (idx & 31)) & bmap[(idx) >> 5]) != 0)
+
 /* match info */
 struct xt_dscp_info {
 	__u8 dscp;
 	__u8 invert;
+	__u8 multi;
+	__u32 dscp_bitmap[(XT_DSCP_MAX >> 5) + 1];
 };
 
 struct xt_tos_match_info {
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
index 64670fc..f127f04 100644
--- a/net/netfilter/xt_dscp.c
+++ b/net/netfilter/xt_dscp.c
@@ -30,6 +30,8 @@ dscp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 	const struct xt_dscp_info *info = par->matchinfo;
 	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
 
+	if (info->multi)
+		return (dscp_test_bit(info->dscp_bitmap, dscp) != 0) ^ !!info->invert;
 	return (dscp == info->dscp) ^ !!info->invert;
 }
 
@@ -39,6 +41,8 @@ dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 	const struct xt_dscp_info *info = par->matchinfo;
 	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
 
+	if (info->multi)
+		return (dscp_test_bit(info->dscp_bitmap, dscp) != 0) ^ !!info->invert;
 	return (dscp == info->dscp) ^ !!info->invert;
 }
 

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: iptables-dscp-multi.patch --]
[-- Type: text/x-patch; name="iptables-dscp-multi.patch", Size: 5893 bytes --]

commit a6370996fd612a538474209195c3fbdd7dfeef76
Author: Kyeong Yoo <kyeong.yoo@alliedtelesis.co.nz>
Date:   Wed Jul 29 09:38:51 2015 +1200

    extensions: libxt_dscp: allow multiple DSCP value match (--dscp-multi)
    
    Current "dscp" match supports one DSCP value in a rule.
    
    This patch enhances "dscp" match with multiple values ("--dscp-multi" option):
    
      -m dscp --dscp-multi value,value,...
    
    DSCP value should be between 0 and 63 or valid DSCP name like AF11, etc.
    
    Reviewed-by: Luuk Paulussen <luuk.paulussen@alliedtelesis.co.nz>
    Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>

diff --git a/extensions/libxt_dscp.c b/extensions/libxt_dscp.c
index 02b22a4..ebf8723 100644
--- a/extensions/libxt_dscp.c
+++ b/extensions/libxt_dscp.c
@@ -14,6 +14,7 @@
  */
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <xtables.h>
 #include <linux/netfilter/xt_dscp.h>
 
@@ -23,8 +24,10 @@
 enum {
 	O_DSCP = 0,
 	O_DSCP_CLASS,
+	O_DSCP_MULTI,
 	F_DSCP       = 1 << O_DSCP,
 	F_DSCP_CLASS = 1 << O_DSCP_CLASS,
+	F_DSCP_MULTI = 1 << O_DSCP_MULTI,
 };
 
 static void dscp_help(void)
@@ -36,20 +39,78 @@ static void dscp_help(void)
 "               		or in hex (ex: 0x20)\n"
 "[!] --dscp-class name		Match the DiffServ class. This value may\n"
 "				be any of the BE,EF, AFxx or CSx classes\n"
+"[!] --dscp-multi value[,value]	Match DSCP value(s) in decimal or in hex\n"
 "\n"
-"				These two options are mutually exclusive !\n");
+"				These three options are mutually exclusive !\n");
 }
 
 static const struct xt_option_entry dscp_opts[] = {
-	{.name = "dscp", .id = O_DSCP, .excl = F_DSCP_CLASS,
+	{.name = "dscp", .id = O_DSCP, .excl = F_DSCP_CLASS | F_DSCP_MULTI,
 	 .type = XTTYPE_UINT8, .min = 0, .max = XT_DSCP_MAX,
 	 .flags = XTOPT_INVERT | XTOPT_PUT,
 	 XTOPT_POINTER(struct xt_dscp_info, dscp)},
-	{.name = "dscp-class", .id = O_DSCP_CLASS, .excl = F_DSCP,
+	{.name = "dscp-class", .id = O_DSCP_CLASS, .excl = F_DSCP | F_DSCP_MULTI,
+	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
+	{.name = "dscp-multi", .id = O_DSCP_MULTI, .excl = F_DSCP | F_DSCP_CLASS,
 	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
 	XTOPT_TABLEEND,
 };
 
+static void dscp_multi_parse(struct xt_dscp_info *dinfo, const char *arg)
+{
+	char *buffer, *str, *next;
+	unsigned int dscp;
+
+	buffer = strdup(arg);
+	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+
+	for (str = buffer; str; str = next)
+	{
+		if ((next = strchr(str, ',')) != NULL)
+			*next++ = '\0';
+		/* Try to convert as a number first and then as a DSCP name.
+		 * Note class_to_dscp() calls exit() on error after printing error message. */
+		if (!xtables_strtoui(str, NULL, &dscp, 0, XT_DSCP_MAX))
+			dscp = class_to_dscp(str);
+		dscp_set_bit(dinfo->dscp_bitmap, dscp);
+	}
+	free(buffer);
+}
+
+static void dscp_multi_print(const struct xt_dscp_info *dinfo)
+{
+	unsigned char dscp;
+	int count = 0;
+
+	for (dscp = 0; dscp <= XT_DSCP_MAX; dscp++)
+	{
+		if (dscp_test_bit(dinfo->dscp_bitmap, dscp)) {
+			if (count == 0)
+				printf(" DSCP multi-match %s0x%02x", dinfo->invert ? "!" : "", dscp);
+			else
+				printf(",0x%02x", dscp);
+			count++;
+		}
+	}
+}
+
+static void dscp_multi_save(const struct xt_dscp_info *dinfo)
+{
+	unsigned char dscp;
+	int count = 0;
+
+	for (dscp = 0; dscp <= XT_DSCP_MAX; dscp++)
+	{
+		if (dscp_test_bit(dinfo->dscp_bitmap, dscp)) {
+			if (count == 0)
+				printf("%s --dscp-multi 0x%02x", dinfo->invert ? " !" : "", dscp);
+			else
+				printf(",0x%02x", dscp);
+			count++;
+		}
+	}
+}
+
 static void dscp_parse(struct xt_option_call *cb)
 {
 	struct xt_dscp_info *dinfo = cb->data;
@@ -65,6 +126,12 @@ static void dscp_parse(struct xt_option_call *cb)
 		if (cb->invert)
 			dinfo->invert = 1;
 		break;
+	case O_DSCP_MULTI:
+		dinfo->multi = 1;
+		dscp_multi_parse(dinfo, cb->arg);
+		if (cb->invert)
+			dinfo->invert = 1;
+		break;
 	}
 }
 
@@ -72,7 +139,7 @@ static void dscp_check(struct xt_fcheck_call *cb)
 {
 	if (cb->xflags == 0)
 		xtables_error(PARAMETER_PROBLEM,
-		           "DSCP match: Parameter --dscp is required");
+		           "DSCP match: Parameter --dscp or --dscp-multi is required");
 }
 
 static void
@@ -80,7 +147,10 @@ dscp_print(const void *ip, const struct xt_entry_match *match, int numeric)
 {
 	const struct xt_dscp_info *dinfo =
 		(const struct xt_dscp_info *)match->data;
-	printf(" DSCP match %s0x%02x", dinfo->invert ? "!" : "", dinfo->dscp);
+	if (dinfo->multi)
+		dscp_multi_print(dinfo);
+	else
+		printf(" DSCP match %s0x%02x", dinfo->invert ? "!" : "", dinfo->dscp);
 }
 
 static void dscp_save(const void *ip, const struct xt_entry_match *match)
@@ -88,7 +158,10 @@ static void dscp_save(const void *ip, const struct xt_entry_match *match)
 	const struct xt_dscp_info *dinfo =
 		(const struct xt_dscp_info *)match->data;
 
-	printf("%s --dscp 0x%02x", dinfo->invert ? " !" : "", dinfo->dscp);
+	if (dinfo->multi)
+		dscp_multi_save(dinfo);
+	else
+		printf("%s --dscp 0x%02x", dinfo->invert ? " !" : "", dinfo->dscp);
 }
 
 static struct xtables_match dscp_match = {
diff --git a/include/linux/netfilter/xt_dscp.h b/include/linux/netfilter/xt_dscp.h
index 15f8932..bea99fa 100644
--- a/include/linux/netfilter/xt_dscp.h
+++ b/include/linux/netfilter/xt_dscp.h
@@ -16,10 +16,17 @@
 #define XT_DSCP_SHIFT	2
 #define XT_DSCP_MAX	0x3f	/* 00111111 */
 
+#define dscp_set_bit(bmap, idx) \
+	(bmap[(idx) >> 5] |= 1U << (idx & 31))
+#define dscp_test_bit(bmap, idx) \
+	(((1U << (idx & 31)) & bmap[(idx) >> 5]) != 0)
+
 /* match info */
 struct xt_dscp_info {
 	__u8 dscp;
 	__u8 invert;
+	__u8 multi;
+	__u32 dscp_bitmap[(XT_DSCP_MAX >> 5) + 1];
 };
 
 struct xt_tos_match_info {

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2015-08-03  4:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-03  4:08 Multiple DSCP match by "-m dscp --dscp-multi value,value,..." Kyeong Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).