Skip to contentSkip to conversation

NETLINK: Use SKB_MAXORDER to calculate NLMSG_GOODSIZE

PATCH Applied Thomas Graf 4 participants 16 messages Jan 28, 2005 – Feb 9, 2005

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 NETLINK: Use SKB_MAXORDER to calculate NLMSG_GOODSIZE

NLMSG_GOODSIZE specifies a good default size for the skb tailroom used in netlink messages when the size is unknown at the time of the allocation.

The current value doesn't make much sense anymore because skb_shared_info isn't taken into account which means that depending on the architecture NLMSG_GOOSIZE can exceed PAGE_SIZE resulting in a waste of almost a complete page.

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

include/linux/netlink.h +2 -3
@@ -133,10 +133,9 @@
 
 /*
  *	skb should fit one page. This choice is good for headerless malloc.
- *
- *      FIXME: What is the best size for SLAB???? --ANK
  */
-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+#define NLMSG_GOODORDER 0
+#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
 
 
 struct netlink_callback
#1 lore raw
Quoted 5 lines · Thomas Graf

The current value doesn't make much sense anymore because skb_shared_info isn't taken into account which means that depending on the architecture NLMSG_GOOSIZE can exceed PAGE_SIZE resulting in a waste of almost a complete page.

You're quite right.

Quoted 2 lines

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

At first glance it's not clear which of sk_buff or skb_shared_info is bigger. So it might even end up being bigger :)

include/linux/netlink.h line 138

Quoted 3 lines
include/linux/netlink.h +2 -1
-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+#define NLMSG_GOODORDER 0
+#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))

Are we ever going use NLMSG_GOODORDER for anything? If not why don't we go straight to NLMSG_GOODSIZE?

Cheers,

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#2 lore raw

* Herbert Xu <[email protected]> 2005-01-29 10:22

Quoted 7 lines
Quoted 5 lines · Thomas Graf

The current value doesn't make much sense anymore because skb_shared_info isn't taken into account which means that depending on the architecture NLMSG_GOOSIZE can exceed PAGE_SIZE resulting in a waste of almost a complete page.

Quoted 7 lines

You're quite right.

Quoted 2 lines

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

At first glance it's not clear which of sk_buff or skb_shared_info is bigger. So it might even end up being bigger :)

skb_shared_info is 160 bytes and sk_buff is 196 bytes on my box (x86) but that's not the point. We need to take SMP_CACHE_BYTES alignment into account which tends to be quite big. The original NLMSG_GOODSIZE results in 3908 on my box and gets pumped up to 4128 by skb_alloc (ALIGN(...,SMP_CACHE_BYTES) + sizeof(struct skb_shared_info)) having SMP_CACHE_BYTES at 128.

Quoted 6 lines

include/linux/netlink.h line 138

Quoted 3 lines
include/linux/netlink.h +2 -1
-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+#define NLMSG_GOODORDER 0
+#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))

Are we ever going use NLMSG_GOODORDER for anything? If not why don't we go straight to NLMSG_GOODSIZE?

My thought behind it is that it clearly documents that we use order-0 allocation and we can easly bump it up if we need more space but it's basically just cosmetic.

maintainer
#3 lore raw
Quoted 6 lines · On Sat, 29 Jan 2005 00:40:22 +0100 Thomas Graf <[email protected]> wrote:
Quoted 5 lines
Quoted 2 lines

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

At first glance it's not clear which of sk_buff or skb_shared_info is bigger. So it might even end up being bigger :)

Quoted 6 lines

skb_shared_info is 160 bytes and sk_buff is 196 bytes on my box (x86) but that's not the point. We need to take SMP_CACHE_BYTES alignment into account which tends to be quite big. The original NLMSG_GOODSIZE results in 3908 on my box and gets pumped up to 4128 by skb_alloc (ALIGN(...,SMP_CACHE_BYTES) + sizeof(struct skb_shared_info)) having SMP_CACHE_BYTES at 128.

Furthermore, it's not sk_buff that's ever the issue. The SKB data area size is where the skb_shared_info gets tacked onto, sk_buff's size is never added to this calculation.

#4 lore raw
In reply to Herbert Xu

Hello!

Quoted 1 line
Quoted 1 line

-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))

... which reminded me about an old stale patchlet:

Comment: improper size calculation for collapsed skb size.
Noticed by Denis V. Lunev <[email protected]>

===== net/ipv4/tcp_input.c 1.89 vs edited =====

net/ipv4/tcp_input.c +2 -2
@@ -3760,8 +3760,8 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = (PAGE_SIZE - sizeof(struct skb_shared_info)
+			    - header - 31)&~15;
 
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)
#5 lore raw

* Alexey Kuznetsov <[email protected]> 2005-01-29 02:48

Quoted 13 lines
Quoted 1 line
Quoted 1 line

-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))

... which reminded me about an old stale patchlet:

Comment: improper size calculation for collapsed skb size.
Noticed by Denis V. Lunev <[email protected]>

===== net/ipv4/tcp_input.c 1.89 vs edited =====

net/ipv4/tcp_input.c line 3764

Quoted 7 lines
net/ipv4/tcp_input.c +2 -2
@@ -3760,8 +3760,8 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = (PAGE_SIZE - sizeof(struct skb_shared_info)
+			    - header - 31)&~15;

Indeed, it can still exceed PAGE_SIZE in alloc_skb because of the SMP_CACHE_BYTES alignment though. Can someone enlighten me about the magic 31 in there? I don't get it from the context. The patch below should do a little bit better

net/ipv4/tcp_input.c +1 -2
@@ -3760,8 +3760,7 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = SKB_MAX_ORDER(header + 31, 0);
 
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)
#6 lore raw

* Thomas Graf <[email protected]> 2005-01-29 01:21

net/ipv4/tcp_input.c line 3766

Quoted 12 lines
net/ipv4/tcp_input.c +1 -2
@@ -3760,8 +3760,7 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = SKB_MAX_ORDER(header + 31, 0);
 
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)

Sorry, this is incomplete, we should refetch copy via (skb->end - skb->head) after allocating it. I have to think some more about this first. ;-)

maintainer
#7 lore raw
Quoted 11 lines · On Sat, 29 Jan 2005 01:27:01 +0100 Thomas Graf <[email protected]> wrote:

* Thomas Graf <[email protected]> 2005-01-29 01:21

Quoted 10 lines
net/ipv4/tcp_input.c +1 -2
@@ -3760,8 +3760,7 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = SKB_MAX_ORDER(header + 31, 0);
 
Quoted 5 lines

net/ipv4/tcp_input.c line 3766

Quoted 2 lines
net/ipv4/tcp_input.c +0 -0
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)

Sorry, this is incomplete, we should refetch copy via (skb->end - skb->head) after allocating it. I have to think some more about this first. ;-)

I don't understand, if we alloc_skb(copy) we are guarenteed to have "copy" bytes available in the SKB data area.

This transformation to SKB_MAX_ORDER() (with the "+ 31" removed as per Alexey's reply), seems perfectly fine to me.

Isn't it?

#8 lore raw
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
net/ipv4/tcp_input.c +1 -2
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = SKB_MAX_ORDER(header + 31, 0);
Quoted 8 lines
Quoted 5 lines

net/ipv4/tcp_input.c line 3766

Quoted 2 lines
net/ipv4/tcp_input.c +0 -0
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)

Sorry, this is incomplete, we should refetch copy via (skb->end - skb->head) after allocating it. I have to think some more about this first. ;-)

I don't understand, if we alloc_skb(copy) we are guarenteed to have "copy" bytes available in the SKB data area.

Yes but don't we waste space in the headroom of the new skb iff the headroom of the original skb is no aligned to SKB_DATA_ALIGN?

I'll post a new patch without the anyway though.

#9 lore raw

PATCH 1/1 NET: Fix calculation for collapsed skb size

In reply to David S. Miller

patch also applies to 2.4 with some fuzz.

Noticed by Denis V. Lunev <[email protected]>

net/ipv4/tcp_input.c +1 -2
@@ -3760,8 +3760,7 @@
 	while (before(start, end)) {
 		struct sk_buff *nskb;
 		int header = skb_headroom(skb);
-		int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
-			    sizeof(struct skb_shared_info) - header - 31)&~15;
+		int copy = SKB_MAX_ORDER(header, 0);
 
 		/* Too big header? This can happen with IPv6. */
 		if (copy < 0)
#11 lore raw
In reply to Thomas Graf

Hello!

Quoted 1 line

alignment though. Can someone enlighten me about the magic 31 in there?

It was me who wrote both NLMSG_GOODSIZE and this crap. Does the explanation sound enough? :-)

Apparently it was a brainless attempt of formal merge of (broken) NLMSG_GOODSIZE and inversed calculation in alloc_skb. Delete this 31.

Alexey

#13 lore raw
In reply to Thomas Graf
Quoted 9 lines

NLMSG_GOODSIZE specifies a good default size for the skb tailroom used in netlink messages when the size is unknown at the time of the allocation.

The current value doesn't make much sense anymore because skb_shared_info isn't taken into account which means that depending on the architecture NLMSG_GOOSIZE can exceed PAGE_SIZE resulting in a waste of almost a complete page.

Quoted 4 lines

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

Dave, did you get this one?

maintainer
#14 lore raw
Quoted 1 line · On Sun, 6 Feb 2005 19:54:17 +0100 Thomas Graf <[email protected]> wrote:

Dave, did you get this one?

Yes I did. I'm just busy with all the memory barrier stuff this past few days, sorry.

maintainer Applied
#15 lore raw
In reply to Thomas Graf
Quoted 11 lines · On Sat, 29 Jan 2005 00:03:27 +0100 Thomas Graf <[email protected]> wrote:

NLMSG_GOODSIZE specifies a good default size for the skb tailroom used in netlink messages when the size is unknown at the time of the allocation.

The current value doesn't make much sense anymore because skb_shared_info isn't taken into account which means that depending on the architecture NLMSG_GOOSIZE can exceed PAGE_SIZE resulting in a waste of almost a complete page.

Using SKB_MAXORDER solves this potential leak at the cost of slightly smaller but safer sizes for some architectures.

Applied, to 2.4.x and 2.6.x, thanks Thomas.

This issue comes up again and again. In the most recent discussion I remember partaking in, I was trying to get it so that all the code paths would calculate the size they actually needed. Most, if not all, are able to do so.