* MARK target extension
@ 2004-05-26 22:09 Grzegorz Nosek
2004-05-27 9:53 ` Patrick McHardy
0 siblings, 1 reply; 10+ messages in thread
From: Grzegorz Nosek @ 2004-05-26 22:09 UTC (permalink / raw)
To: netfilter-devel
[-- Attachment #1: Type: text/plain, Size: 990 bytes --]
Hello all!
I've extended the MARK target (ipv4 only currently) to allow partial
modification of nfmark values instead of replacing. As in:
... -j MARK --set-mark 0x80
... -j MARK --set-mark 0x8000 --mask 0xff00
sets the resulting mark value to 0x8080. Note that it isn't a logical OR:
... -j MARK --set-mark 0xffff
... -j MARK --set-mark 0 --mask 0xff
would change the mark to 0xff00.
This way you can use the nfmark as a bit field (testing individual
bits can be done already). Patches included are based on
iptables-1.2.9 (from debian sarge source) and kernel 2.4.26, somewhat
patched (nothing related to nfmark, though, so it should apply cleanly
to a vanilla kernel too). What do you think? IMNSHO it would be useful
to include in standard kernel/iptables especially as it breaks no
existing applications (default mask is 0xffffffff), is no code bloat
and might actually be useful to somebody besides me. Note that it's my
first public kernel patch so be gentle.
Regards,
Greg
[-- Attachment #2: iptables-mark-1.2.9.diff --]
[-- Type: text/plain, Size: 2503 bytes --]
diff -Naur iptables-1.2.9/extensions/libipt_MARK.c iptables-1.2.9-mark/extensions/libipt_MARK.c
--- iptables-1.2.9/extensions/libipt_MARK.c 2003-03-02 17:16:45.000000000 +0100
+++ iptables-1.2.9-mark/extensions/libipt_MARK.c 2004-05-26 17:37:17.000000000 +0200
@@ -20,12 +20,14 @@
printf(
"MARK target v%s options:\n"
" --set-mark value Set nfmark value\n"
+" --mask value Set modification mask\n"
"\n",
IPTABLES_VERSION);
}
static struct option opts[] = {
{ "set-mark", 1, 0, '1' },
+ { "mask", 1, 0, '2' },
{ 0 }
};
@@ -33,6 +35,9 @@
static void
init(struct ipt_entry_target *t, unsigned int *nfcache)
{
+ struct ipt_mark_target_info *markinfo =
+ (struct ipt_mark_target_info *)t->data;
+ markinfo->mask = 0xffffffff;
}
/* Function which parses command options; returns true if it
@@ -50,10 +55,20 @@
if (string_to_number(optarg, 0, 0xffffffff,
(unsigned int *)&markinfo->mark))
exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
- if (*flags)
+ if (*flags & 1)
exit_error(PARAMETER_PROBLEM,
"MARK target: Can't specify --set-mark twice");
- *flags = 1;
+ *flags |= 1;
+ break;
+
+ case '2':
+ if (string_to_number(optarg, 0, 0xffffffff,
+ (unsigned int *)&markinfo->mask))
+ exit_error(PARAMETER_PROBLEM, "Bad mask value `%s'", optarg);
+ if (*flags & 2)
+ exit_error(PARAMETER_PROBLEM,
+ "MARK target: Can't specify --mask twice");
+ *flags |= 2;
break;
default:
@@ -66,15 +81,17 @@
static void
final_check(unsigned int flags)
{
- if (!flags)
+ if ((flags & 1) == 0)
exit_error(PARAMETER_PROBLEM,
"MARK target: Parameter --set-mark is required");
}
static void
-print_mark(unsigned long mark, int numeric)
+print_mark(unsigned long mark, unsigned long mask, int numeric)
{
printf("0x%lx ", mark);
+ if (mask != 0xffffffff)
+ printf(" mask 0x%lx ", mask);
}
/* Prints out the targinfo. */
@@ -86,7 +103,7 @@
const struct ipt_mark_target_info *markinfo =
(const struct ipt_mark_target_info *)target->data;
printf("MARK set ");
- print_mark(markinfo->mark, numeric);
+ print_mark(markinfo->mark, markinfo->mask, numeric);
}
/* Saves the union ipt_targinfo in parsable form to stdout. */
@@ -97,6 +114,8 @@
(const struct ipt_mark_target_info *)target->data;
printf("--set-mark 0x%lx ", markinfo->mark);
+ if (markinfo->mask != 0xffffffff)
+ printf("--mask 0x%lx ", markinfo->mask);
}
static
[-- Attachment #3: kernel-mark-2.4.26.diff --]
[-- Type: text/plain, Size: 1202 bytes --]
diff -Naur linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h linux-2.4.26-ow1+route+mark/include/linux/netfilter_ipv4/ipt_MARK.h
--- linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h 2000-03-17 19:56:20.000000000 +0100
+++ linux-2.4.26-ow1+route+mark/include/linux/netfilter_ipv4/ipt_MARK.h 2004-05-26 17:10:26.000000000 +0200
@@ -3,6 +3,7 @@
struct ipt_mark_target_info {
unsigned long mark;
+ unsigned long mask;
};
#endif /*_IPT_MARK_H_target*/
diff -Naur linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c linux-2.4.26-ow1+route+mark/net/ipv4/netfilter/ipt_MARK.c
--- linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c 2001-09-30 21:26:08.000000000 +0200
+++ linux-2.4.26-ow1+route+mark/net/ipv4/netfilter/ipt_MARK.c 2004-05-26 17:18:49.000000000 +0200
@@ -16,9 +16,10 @@
void *userinfo)
{
const struct ipt_mark_target_info *markinfo = targinfo;
+ long new_mark = ((*pskb)->nfmark & ~markinfo->mask) | (markinfo->mark & markinfo->mask);
- if((*pskb)->nfmark != markinfo->mark) {
- (*pskb)->nfmark = markinfo->mark;
+ if((*pskb)->nfmark != new_mark) {
+ (*pskb)->nfmark = new_mark;
(*pskb)->nfcache |= NFC_ALTERED;
}
return IPT_CONTINUE;
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: MARK target extension 2004-05-26 22:09 MARK target extension Grzegorz Nosek @ 2004-05-27 9:53 ` Patrick McHardy 2004-06-05 22:06 ` Grzegorz Nosek 0 siblings, 1 reply; 10+ messages in thread From: Patrick McHardy @ 2004-05-27 9:53 UTC (permalink / raw) To: Grzegorz Nosek; +Cc: netfilter-devel Grzegorz Nosek wrote: > Hello all! > > I've extended the MARK target (ipv4 only currently) to allow partial > modification of nfmark values instead of replacing. As in: > > ... -j MARK --set-mark 0x80 > ... -j MARK --set-mark 0x8000 --mask 0xff00 > > sets the resulting mark value to 0x8080. Note that it isn't a logical OR: > > ... -j MARK --set-mark 0xffff > ... -j MARK --set-mark 0 --mask 0xff > > would change the mark to 0xff00. > > This way you can use the nfmark as a bit field (testing individual > bits can be done already). Patches included are based on > iptables-1.2.9 (from debian sarge source) and kernel 2.4.26, somewhat > patched (nothing related to nfmark, though, so it should apply cleanly > to a vanilla kernel too). What do you think? IMNSHO it would be useful > to include in standard kernel/iptables especially as it breaks no > existing applications (default mask is 0xffffffff), is no code bloat > and might actually be useful to somebody besides me. Note that it's my > first public kernel patch so be gentle. We already have a similar patch, MARK-operations, in pom-ng. Unfortunately it can't be included in the stable series because it breaks userspace compatibility. Regards Patrick > > Regards, > Greg ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-05-27 9:53 ` Patrick McHardy @ 2004-06-05 22:06 ` Grzegorz Nosek 2004-06-06 14:25 ` Patrick McHardy 0 siblings, 1 reply; 10+ messages in thread From: Grzegorz Nosek @ 2004-06-05 22:06 UTC (permalink / raw) To: netfilter-devel On Thu, 27 May 2004 11:53:08 +0200, Patrick McHardy wrote > We already have a similar patch, MARK-operations, in pom-ng. > Unfortunately it can't be included in the stable series because > it breaks userspace compatibility. > > Regards > Patrick > I had a look at the patch and it's indeed similar but supports only single AND and OR operations and I think that it should allow more flexibility. If you don't like the idea of adding another parameter, maybe something like this would do: --set-mark overrides all, without further questions --and-mark and --or-mark are performed in sequence (thus more than one allowed), so that (in my proposed syntax) --set-mark 0x1234 --mask 0xffff (leaving top 16 bits untouched) could be expressed as --and-mark 0xffff0000 --or-mark 0x1234 It shouldn't break any existing applications either (they're using only one of the parameters now). It certainly is possible to get the same result using two consecutive rules but it seems inefficient. Regards, Greg ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-06-05 22:06 ` Grzegorz Nosek @ 2004-06-06 14:25 ` Patrick McHardy [not found] ` <20040608073821.M38174@metal.art.pl> 0 siblings, 1 reply; 10+ messages in thread From: Patrick McHardy @ 2004-06-06 14:25 UTC (permalink / raw) To: Grzegorz Nosek; +Cc: netfilter-devel Grzegorz Nosek wrote: > I had a look at the patch and it's indeed similar but supports only > single AND and OR operations and I think that it should allow more > flexibility. If you don't like the idea of adding another parameter, > maybe something like this would do: > --set-mark overrides all, without further questions > --and-mark and --or-mark are performed in sequence (thus more than one > allowed), so that (in my proposed syntax) > --set-mark 0x1234 --mask 0xffff > (leaving top 16 bits untouched) could be expressed as > --and-mark 0xffff0000 --or-mark 0x1234 > It shouldn't break any existing applications either (they're using > only one of the parameters now). > > It certainly is possible to get the same result using two consecutive > rules but it seems inefficient. I agree with you. CONNMARK seems to have the most flexible solution: newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; Note that unlike with your patch, mark isn't ANDed with mask, so you can also do a simple OR by setting mask to zero. If you change your patch this way, and also make the userspace-part look like CONNMARK (mark/mask instead of --mask), I'll happily replace the MARK-operations patch. Regards Patrick ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <20040608073821.M38174@metal.art.pl>]
* Re: MARK target extension [not found] ` <20040608073821.M38174@metal.art.pl> @ 2004-06-09 8:51 ` Patrick McHardy 2004-06-09 13:43 ` Henrik Nordstrom 0 siblings, 1 reply; 10+ messages in thread From: Patrick McHardy @ 2004-06-09 8:51 UTC (permalink / raw) To: Grzegorz Nosek; +Cc: netfilter-devel, Henrik Nordstrom Grzegorz Nosek wrote: > On Sun, 06 Jun 2004 16:25:12 +0200, Patrick McHardy wrote > >>I agree with you. CONNMARK seems to have the most flexible solution: >>newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; > > Hmm I think I made it even more flexible by replacing the OR with XOR. > > --set-mark 0x80 - nfmark = 0x80 > --set-mark 0x80/0x80 - nfmark |= 0x80 > --set-mark 0x80/0 - nfmark ^= 0x80 > --set-mark 0x80/0xff - replace lowest 8 bits with 0x80 > --set-mark 0/0xff - clear lowest 8 bits > --set-mark 0/0 - silly NOP > etc. > > With R and S being corresponding bits in mark and mask, you can set > (RS=11), clear (RS=01), invert (RS=10) and leave intact (RS=00) any > set of bits in the nfmark. What do you think? Nice, although the xor operation (0x80/0) is a bit non-intuitive. > >>Note that unlike with your patch, mark isn't ANDed with mask, >> so you can also do a simple OR by setting mask to zero. >> >>If you change your patch this way, and also make the >>userspace-part look like CONNMARK (mark/mask instead of - >>-mask), I'll happily replace the MARK-operations patch. > > > Done and attached. One of my concerns was that MARK and CONNMARK should look and behave the same way. We should either change CONNMARK to also use xor, or change your patch to using or. Henrik, what do you think ? Regards Patrick > ------------------------------------------------------------------------ > > diff -Naur linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h linux-2.4.26-ow1+route+mark/include/linux/netfilter_ipv4/ipt_MARK.h > --- linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h 2000-03-17 19:56:20.000000000 +0100 > +++ linux-2.4.26-ow1+route+mark/include/linux/netfilter_ipv4/ipt_MARK.h 2004-05-26 17:10:26.000000000 +0200 > @@ -3,6 +3,7 @@ > > struct ipt_mark_target_info { > unsigned long mark; > + unsigned long mask; > }; > > #endif /*_IPT_MARK_H_target*/ > diff -Naur linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c linux-2.4.26-ow1+route+mark/net/ipv4/netfilter/ipt_MARK.c > --- linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c 2001-09-30 21:26:08.000000000 +0200 > +++ linux-2.4.26-ow1+route+mark/net/ipv4/netfilter/ipt_MARK.c 2004-05-26 17:18:49.000000000 +0200 > @@ -16,9 +16,10 @@ > void *userinfo) > { > const struct ipt_mark_target_info *markinfo = targinfo; > + long new_mark = ((*pskb)->nfmark & ~markinfo->mask) ^ markinfo->mark; > > - if((*pskb)->nfmark != markinfo->mark) { > - (*pskb)->nfmark = markinfo->mark; > + if((*pskb)->nfmark != new_mark) { > + (*pskb)->nfmark = new_mark; > (*pskb)->nfcache |= NFC_ALTERED; > } > return IPT_CONTINUE; > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-06-09 8:51 ` Patrick McHardy @ 2004-06-09 13:43 ` Henrik Nordstrom 2004-06-13 20:23 ` Patrick McHardy 0 siblings, 1 reply; 10+ messages in thread From: Henrik Nordstrom @ 2004-06-09 13:43 UTC (permalink / raw) To: Patrick McHardy; +Cc: Grzegorz Nosek, netfilter-devel On Wed, 9 Jun 2004, Patrick McHardy wrote: > Nice, although the xor operation (0x80/0) is a bit non-intuitive. And therefore also quite easy to get wrong.. for me the intuitive meaning of 0x80/0 is to set bit 0x80 or nothing, not xor. I do agree that it is nice to have the functionality of xor. May I propose that to solve this a userspace option is added "--xor-mark value", and that mask 0 is probited in --set-mark if this representation is used. > One of my concerns was that MARK and CONNMARK should look and behave > the same way. We should either change CONNMARK to also use xor, or > change your patch to using or. Henrik, what do you think ? I have no problem adjusting CONNMARK if a acceptable notation is found. It has not yet been submitted to the kernel even if this has been favorly discussed many times already. Regards Henrik ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-06-09 13:43 ` Henrik Nordstrom @ 2004-06-13 20:23 ` Patrick McHardy 2004-06-14 17:26 ` Grzegorz Nosek 0 siblings, 1 reply; 10+ messages in thread From: Patrick McHardy @ 2004-06-13 20:23 UTC (permalink / raw) To: Henrik Nordstrom; +Cc: Grzegorz Nosek, netfilter-devel On Wed, 2004-06-09 at 15:43, Henrik Nordstrom wrote: > On Wed, 9 Jun 2004, Patrick McHardy wrote: > > I do agree that it is nice to have the functionality of xor. > > May I propose that to solve this a userspace option is added "--xor-mark > value", and that mask 0 is probited in --set-mark if this representation > is used. Seems like a good way. I'm also going to add --and-mark and --or-mark as alternative representations. I'll post the patch before applying it to see if everyone is happy. > > One of my concerns was that MARK and CONNMARK should look and behave > > the same way. We should either change CONNMARK to also use xor, or > > change your patch to using or. Henrik, what do you think ? > > I have no problem adjusting CONNMARK if a acceptable notation is found. It > has not yet been submitted to the kernel even if this has been favorly > discussed many times already. Yes, I know. I hope it will go in soon .. Regards Patrick ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-06-13 20:23 ` Patrick McHardy @ 2004-06-14 17:26 ` Grzegorz Nosek 2004-06-14 20:59 ` Henrik Nordstrom 0 siblings, 1 reply; 10+ messages in thread From: Grzegorz Nosek @ 2004-06-14 17:26 UTC (permalink / raw) To: Patrick McHardy, Henrik Nordstrom; +Cc: netfilter-devel [-- Attachment #1: Type: text/plain, Size: 9310 bytes --] On Sun, 13 Jun 2004 22:23:08 +0200, Patrick McHardy wrote > On Wed, 2004-06-09 at 15:43, Henrik Nordstrom wrote: > > On Wed, 9 Jun 2004, Patrick McHardy wrote: > > > > I do agree that it is nice to have the functionality of xor. > > > > May I propose that to solve this a userspace option is added "--xor-mark > > value", and that mask 0 is probited in --set-mark if this representation > > is used. > > Seems like a good way. I'm also going to add --and-mark and - > -or-mark as alternative representations. I'll post the patch > before applying it to see if everyone is happy. > > > > One of my concerns was that MARK and CONNMARK should look and behave > > > the same way. We should either change CONNMARK to also use xor, or > > > change your patch to using or. Henrik, what do you think ? > > > > I have no problem adjusting CONNMARK if a acceptable notation is found. It > > has not yet been submitted to the kernel even if this has been favorly > > discussed many times already. > > Yes, I know. I hope it will go in soon .. > > Regards > Patrick Hello I'm sorry I haven't replied earlier, I had connectivity problems (my ISP sucks really bad...). Here's the reply I prepared earlier, I've rewritten the code from scratch and I like it. I'd love to know your input. Regards, Greg Several-days-old reply follows: ---------------------------------------------------------------- On Thu, 10 Jun 2004 11:59:35 +0200 (CEST), Henrik Nordstrom wrote > On Thu, 10 Jun 2004, Grzegorz Nosek wrote: > > > Taking this a little bit further, why not get rid of the /mask > > entirely as it's not exactly obvious what it means and replace them > > with more verbose --set-mark, --or-mark, --and-mark, --xor-mark? > > Because the mask is far more powerful in the --set-mark. Please check your opinion against my new code. :) > > --or-mark makes sense to add as an alternative human > representation as 0x80/0x80 is not very intuitive unless one > is used to work with masked values, and even more so if > value/0 is reserved for xor (mask 0 in CONNMARK is today or, > regardless of the value) value/0 isn't exactly reserved for XOR, every bit of value and mask is treated separately, so you can mix all bit operations in a single statement. As I've written several mails before (the bits have changed with my latest patch!): S - a bit of the mask R - a bit of the mark value SR | | operation ---+---+----------- 00 | C | clear 01 | S | set 10 | N | no-op 11 | I | invert I think that it gives the ultimate flexibility (four operations in two bits) at the expense of some readability, which could be accomodated in userspace. > > --and-mark also makes sense to add as an alternative > representation of 0/value > > but both --or-mark and --and-mark can be represented in - > -set-mark by the logics of --set-mark. It is only --xor-mark > which can not. > With the OR in kernel code, you're right, with the XOR, anything goes. > > One side effect would be that upon iptables-save, all ORs would change > > to XORs "mysteriously" but there might be a way to detect ORs and > > treat them as such (xor_mask & and_mask == 0 or thereabouts). > > Eh? That was my sleeping brain trying to say that iptables-save would work like this: if (mask==~0) print "--set-mark " value else if (mask == value) print "--or-mark " value else print "--and-mark " mask " --xor-mark " value It's still smarter (and tested at least) in my current patch, though (of course, any comments and improvements are welcome). This version wouldn't probably do anything remotely correct now. > > xor is a special case and will always be xor. xor can not be > combined with anything else without extending the > representation, and if the representation is extended xor is > still cleraly separate from the other operation. OR can be expressed easily with AND and XOR so I'm not really sure it's needed as a separate value. A | B = (A & (~B)) ^ B Anything besides AND and XOR, while useful, is only syntactic sugar. > > With the following binary representation and kernel function > any combination of set/and/or/xor can be represented: > > unsigned long value, mask, xor; > > newvalue = ((oldvalue & mask) | value) ^ xor; > > or alternatively > > newvalue = ((oldvalue ^ xor ) & mask ) | value) > But still, I don't see how it allows for anything more than a simple newvalue = (oldvalue & mask) ^ value; BTW, I changed the `~mask' into `mask' in my kernel code, I can't seem to remember the purpose of the negation. > Userspace operations: > > --set-mark > > value |= specified_value; > if (mask specified) > mask |= specified_mask; > else > mask = ~0; > > --or-mark > > value |= specified_value; > mask |= specified_value; > > --and-mark becomes > > if (mask = 0) > mask = ~0; > mask &= specified_value; > > --xor-mark becomes > > if (mask = 0) > mask = ~0; > xor |= specified_value; > > If you like there can be appropriate asserts to alert the > user if he is specifying conflicting operations on the same > bit, but I am not sure if this is needed other than for xor. > After I scratched my head for a while on this issue (esp. overlapping masks), I came up with a solution which: + is (IMHO) very user-friendly (I'd say DWIM) + is extremely flexible (unlimited number and unrestricted order of expressions) - almost doubled the size of libipt_MARK.c - may not be developer-friendly (obvious operation traded for a bit of non-obvious implementation) - may be overkill but I like it I'll hopefully explain the basis of this idea below. (this might go into some README if the MARK target ever gets one) Theory of operation ------------------- The new MARK-ops algorithm is based on the fact that any bit can be transformed in one of 4 ways: clear (00), set (01), no-op (10), invert (11). Now, the elementary operations are defined as follows (by examples, lowest 4 bits only): --set-mark 1/3 NNCS (leave top 2 bits alone, clear bit 1 and set bit 0) It can be expressed as a value + mask pair: m=1100 (~specified_mask) v=0001 (specified_value) Read vertically, the (mv) values are the same as the numbers in parentheses above. --and-mark 3 CCNN (clear top 2 bits) m=0011 (specified_value) v=0000 (always zero) --xor-mark 3 NNII (invert lowest 2 bits) m=1111 (always ones) v=0011 (specified_value) --or-mark 3 NNSS (set lowest 2 bits) m=1100 (~specified_value) v=0011 (specified_value) Now, this isn't in any way new or innovative and by itself it only enables us to specify a single command per rule - definitely not enough. However, now we define a state diagram which tells us what the result of superimposing two states is: |CSIN -+---- C|CSSC S|CSCS I|CSNI N|CSIN So, if you want to see what should happen to a bit which is set first and then inverted, you consult the "S" row and "I" column and you know that it should be cleared (no surprise). So now we have a state machine whose state is represented by nth bit of mask and value (32 independent state machines, actually). For example: --set-mark 1/3 --xor-mark 6 This statement is parsed starting with the --set-mark. We get NNCS encoded in mask and value and now we get to the xor. It gives NIIN and now we check the state diagram to check what happens to each of the bits: (bit 3) NN -> N (bit 2) NI -> I (bit 1) CI -> S (bit 0) SN -> S So now we have the state NISS, which means "don't touch bit 3, invert bit 2 and set the lowest 2 ones". It's stored as: m=1100 v=0111 which is the form directly used inside the kernel. (old_mark & 0b1100) ^ 0b0111 (kernel code) is completely equivalent to what you might expect: ((old_mark & 0b1100) | 0b0001) ^ 0b0110 but does the calculation using only 2 logical operations. Implementation details ---------------------- Replacing symbols (C,S,I,N) with their numerical values (00,01,11,10) we get the following table: MV|00 01 11 10 --+----------- 00|00 01 01 00 01|00 01 00 01 11|00 01 10 11 10|00 01 11 10 It contains two-bit values which can be written in separate Karnaugh tables: M |00 01 11 10 V |00 01 11 10 --+----------- --+----------- 00| 0 0 0 0 00| 0 1 1 0 01| 0 0 0 0 01| 0 1 0 1 11| 0 0 1 1 11| 0 1 0 1 10| 0 0 1 1 10| 0 1 1 0 Given that the two bits designating row are m0,v0 and m1,v1 designate the column, we can express the tables as the following functions: M = m0 & m1 V = v1 ^ (v0 & m1) And this is what function transfer_value() does. It probably is possible to find these equations somehow simpler, without several pages of explanations, however this documents how I came up with these. Comments welcome, of course. So in the end it turns out (for me at least) that although you may specify the operation using the set-mark mask, it is unneccessary as now you can give the parameters in a mostly natural language (OR this, then XOR that and SET another...). And if you write some complex expression, you also get its simple{r,st} version for free. I think that given this power in --xxx-mark the internal representation (visible in VALUE/MASK) is mostly irrelevant as the user won't see it anyway. > Regards > Henrik Regards, Greg [-- Attachment #2: linux-2.4.26-mark.diff --] [-- Type: application/octet-stream, Size: 1182 bytes --] diff -Naur linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h linux-2.4.26-ow1+route-mark/include/linux/netfilter_ipv4/ipt_MARK.h --- linux-2.4.26-ow1+route/include/linux/netfilter_ipv4/ipt_MARK.h 2000-03-17 19:56:20.000000000 +0100 +++ linux-2.4.26-ow1+route-mark/include/linux/netfilter_ipv4/ipt_MARK.h 2004-05-26 17:10:26.000000000 +0200 @@ -3,6 +3,7 @@ struct ipt_mark_target_info { unsigned long mark; + unsigned long mask; }; #endif /*_IPT_MARK_H_target*/ diff -Naur linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c linux-2.4.26-ow1+route-mark/net/ipv4/netfilter/ipt_MARK.c --- linux-2.4.26-ow1+route/net/ipv4/netfilter/ipt_MARK.c 2001-09-30 21:26:08.000000000 +0200 +++ linux-2.4.26-ow1+route-mark/net/ipv4/netfilter/ipt_MARK.c 2004-06-12 01:06:06.000000000 +0200 @@ -16,9 +16,10 @@ void *userinfo) { const struct ipt_mark_target_info *markinfo = targinfo; + long new_mark = ((*pskb)->nfmark & markinfo->mask) | markinfo->mark; - if((*pskb)->nfmark != markinfo->mark) { - (*pskb)->nfmark = markinfo->mark; + if((*pskb)->nfmark != new_mark) { + (*pskb)->nfmark = new_mark; (*pskb)->nfcache |= NFC_ALTERED; } return IPT_CONTINUE; [-- Attachment #3: iptables-1.2.9-mark.diff --] [-- Type: application/octet-stream, Size: 4839 bytes --] diff -Naur iptables-1.2.9/extensions/libipt_MARK.c iptables-1.2.9-mark/extensions/libipt_MARK.c --- iptables-1.2.9/extensions/libipt_MARK.c 2003-03-02 17:16:45.000000000 +0100 +++ iptables-1.2.9-mark/extensions/libipt_MARK.c 2004-06-12 03:26:23.000000000 +0200 @@ -3,6 +3,7 @@ #include <string.h> #include <stdlib.h> #include <getopt.h> +#include <errno.h> #include <iptables.h> #include <linux/netfilter_ipv4/ip_tables.h> @@ -19,13 +20,21 @@ { printf( "MARK target v%s options:\n" -" --set-mark value Set nfmark value\n" +" --set-mark value[/mask] Set nfmark value\n" +" --and-mark value Perform logical AND on nfmark and value\n" +" --xor-mark value Perform logical XOR on nfmark and value\n" +" --or-mark value Perform logical OR on nfmark and value\n" +"\n" +"Options can be specified multiple times, in any order.\n" "\n", IPTABLES_VERSION); } static struct option opts[] = { { "set-mark", 1, 0, '1' }, + { "and-mark", 1, 0, '2' }, + { "xor-mark", 1, 0, '3' }, + { "or-mark", 1, 0, '4' }, { 0 } }; @@ -33,6 +42,38 @@ static void init(struct ipt_entry_target *t, unsigned int *nfcache) { + struct ipt_mark_target_info *markinfo + = (struct ipt_mark_target_info *)t->data; + + markinfo->mask = ~0UL; +} + +/* Extract value/mask from a string */ +static void +parse_arg(char* optarg, struct ipt_mark_target_info* markinfo, int mask_valid) +{ + char *tail, *tail2; + errno = 0; + markinfo->mark = strtoul(optarg, &tail, 0); + if (errno || (optarg == tail)) + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + if (*tail) { + if (!mask_valid || *tail != '/') + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + errno = 0; + markinfo->mask = strtoul(tail+1, &tail2, 0); + if (errno || (tail2 == tail+1)) + exit_error(PARAMETER_PROBLEM, "Bad mask value `%s'", tail+1); + } +} + +/* State transfer function for subsequent operations on + the same bit in nfmark */ +static void +transfer_value(struct ipt_mark_target_info *markinfo, struct ipt_mark_target_info op) +{ + markinfo->mark = op.mark ^ (markinfo->mark & op.mask); + markinfo->mask &= op.mask; } /* Function which parses command options; returns true if it @@ -44,22 +85,39 @@ { struct ipt_mark_target_info *markinfo = (struct ipt_mark_target_info *)(*target)->data; + struct ipt_mark_target_info op; switch (c) { case '1': - if (string_to_number(optarg, 0, 0xffffffff, - (unsigned int *)&markinfo->mark)) - exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); - if (*flags) - exit_error(PARAMETER_PROBLEM, - "MARK target: Can't specify --set-mark twice"); - *flags = 1; + parse_arg(optarg, &op, 1); + if (!op.mask) + op.mask = 0; + else + op.mask ^= ~0UL; + break; + + case '2': + parse_arg(optarg, &op, 0); + op.mask = op.mark; + op.mark = 0; + break; + + case '3': + parse_arg(optarg, &op, 0); + op.mask = ~0UL; + break; + + case '4': + parse_arg(optarg, &op, 1); + op.mask = ~op.mark; break; default: return 0; } + transfer_value(markinfo, op); + *flags = 1; return 1; } @@ -68,13 +126,24 @@ { if (!flags) exit_error(PARAMETER_PROBLEM, - "MARK target: Parameter --set-mark is required"); + "MARK target: A parameter is required (see -j MARK --help)"); } static void -print_mark(unsigned long mark, int numeric) +print_mark(unsigned long mark, unsigned long mask, int numeric) { - printf("0x%lx ", mark); + if (mask == 0) + printf("set 0x%lx ", mark); + else if (mark == ~mask) + printf("or 0x%lx ", mark); + else if ((mark & mask) == 0) + printf("set 0x%lx/0x%lx ", mark, ~mask); + else { + if (mask != ~0UL) + printf("and 0x%lx ", mask); + if (mark) + printf("xor 0x%lx ", mark); + } } /* Prints out the targinfo. */ @@ -85,8 +154,8 @@ { const struct ipt_mark_target_info *markinfo = (const struct ipt_mark_target_info *)target->data; - printf("MARK set "); - print_mark(markinfo->mark, numeric); + printf("MARK "); + print_mark(markinfo->mark, markinfo->mask, numeric); } /* Saves the union ipt_targinfo in parsable form to stdout. */ @@ -96,7 +165,18 @@ const struct ipt_mark_target_info *markinfo = (const struct ipt_mark_target_info *)target->data; - printf("--set-mark 0x%lx ", markinfo->mark); + if (markinfo->mask == 0) + printf("--set-mark 0x%lx ", markinfo->mark); + else if (markinfo->mark == ~markinfo->mask) + printf("--or-mark 0x%lx ", markinfo->mark); + else if ((markinfo->mark & markinfo->mask) == 0) + printf("--set-mark 0x%lx/0x%lx ", markinfo->mark, ~markinfo->mask); + else { + if (markinfo->mask != ~0UL) + printf("--and-mark 0x%lx ", markinfo->mask); + if (markinfo->mark) + printf("--xor-mark 0x%lx ", markinfo->mark); + } } static ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: MARK target extension 2004-06-14 17:26 ` Grzegorz Nosek @ 2004-06-14 20:59 ` Henrik Nordstrom 0 siblings, 0 replies; 10+ messages in thread From: Henrik Nordstrom @ 2004-06-14 20:59 UTC (permalink / raw) To: Grzegorz Nosek; +Cc: Patrick McHardy, Netfilter Developers List On Mon, 14 Jun 2004, Grzegorz Nosek wrote: > S - a bit of the mask > R - a bit of the mark value > > SR | | operation > ---+---+----------- > 00 | C | clear > 01 | S | set > 10 | N | no-op > 11 | I | invert Interesting encoding with a very nice kernel side algorithm. > But still, I don't see how it allows for anything more than a simple > > newvalue = (oldvalue & mask) ^ value; It doesn't. AND+XOR is logically complete and can represent all the bitwise logic operations in a very efficient manner in both space and time. Note: The ~mask in CONNMARK was from the mask representing the bits to modify, not the bits to save. Regards Henrik ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <20040609222646.M64@metal.art.pl>]
* Re: MARK target extension [not found] <20040609222646.M64@metal.art.pl> @ 2004-06-10 9:59 ` Henrik Nordstrom 0 siblings, 0 replies; 10+ messages in thread From: Henrik Nordstrom @ 2004-06-10 9:59 UTC (permalink / raw) To: Grzegorz Nosek; +Cc: Patrick McHardy, netfilter-devel On Thu, 10 Jun 2004, Grzegorz Nosek wrote: > Taking this a little bit further, why not get rid of the /mask > entirely as it's not exactly obvious what it means and replace them > with more verbose --set-mark, --or-mark, --and-mark, --xor-mark? Because the mask is far more powerful in the --set-mark. --or-mark makes sense to add as an alternative human representation as 0x80/0x80 is not very intuitive unless one is used to work with masked values, and even more so if value/0 is reserved for xor (mask 0 in CONNMARK is today or, regardless of the value) --and-mark also makes sense to add as an alternative representation of 0/value but both --or-mark and --and-mark can be represented in --set-mark by the logics of --set-mark. It is only --xor-mark which can not. > It would look like the mark-operations patch but should allow for > multiple operations per line. --set-mark would prohibit any other > options, --and-mark would be performed before --xor-mark. --or-mark > would end up as a xor and a change to the and mask, as in: xor_mark = > or_mark; and_mark = and_mark & ~or_mark; /* or something, I'm asleep > right now */ If you like the userspace can allow for multiple and/or/set operations (in any order). xor is exclusive with the other operations however unless the representation is extended with one more bitfield for xor. > One side effect would be that upon iptables-save, all ORs would change > to XORs "mysteriously" but there might be a way to detect ORs and > treat them as such (xor_mask & and_mask == 0 or thereabouts). Eh? xor is a special case and will always be xor. xor can not be combined with anything else without extending the representation, and if the representation is extended xor is still cleraly separate from the other operation. With the following binary representation and kernel function any combination of set/and/or/xor can be represented: unsigned long value, mask, xor; newvalue = ((oldvalue & mask) | value) ^ xor; or alternatively newvalue = ((oldvalue ^ xor ) & mask ) | value) Userspace operations: --set-mark value |= specified_value; if (mask specified) mask |= specified_mask; else mask = ~0; --or-mark value |= specified_value; mask |= specified_value; --and-mark becomes if (mask = 0) mask = ~0; mask &= specified_value; --xor-mark becomes if (mask = 0) mask = ~0; xor |= specified_value; If you like there can be appropriate asserts to alert the user if he is specifying conflicting operations on the same bit, but I am not sure if this is needed other than for xor. Regards Henrik ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2004-06-14 20:59 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-26 22:09 MARK target extension Grzegorz Nosek
2004-05-27 9:53 ` Patrick McHardy
2004-06-05 22:06 ` Grzegorz Nosek
2004-06-06 14:25 ` Patrick McHardy
[not found] ` <20040608073821.M38174@metal.art.pl>
2004-06-09 8:51 ` Patrick McHardy
2004-06-09 13:43 ` Henrik Nordstrom
2004-06-13 20:23 ` Patrick McHardy
2004-06-14 17:26 ` Grzegorz Nosek
2004-06-14 20:59 ` Henrik Nordstrom
[not found] <20040609222646.M64@metal.art.pl>
2004-06-10 9:59 ` Henrik Nordstrom
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.