Skip to contentSkip to conversation

rtnetlink: Fix problem with buffer allocation

RFC PATCH Superseded Greg Rose 5 participants 13 messages Feb 12, 2012 – Feb 15, 2012

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Greg Rose

author
#0 lore raw

RFC PATCH v2 1/1 rtnetlink: Fix problem with buffer allocation

Implement a new nlattr type IFLA_EXT_MASK. The mask is a 32 bit value that can be used to indicate to the kernel that certain extended ifinfo values are requested by the user application. At this time the only mask value created is RTEXT_FILTER_VF to indicate that the user wants the ifinfo dump to send information about the VFs belonging to the interface.

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present. It does not act as the filter itself which has changed since the first submission of this RFC. Older versions of user applications won't set this flag which should fix the problem of some applications not allocating a large enough buffer for all the extended interface information.

---

 include/linux/if_link.h   |    1 +
 include/linux/netlink.h   |    2 +
 include/linux/rtnetlink.h |    9 ++++++
 include/net/rtnetlink.h   |    2 +
 net/core/rtnetlink.c      |   73 ++++++++++++++++++++++++++++++++-------------
 5 files changed, 65 insertions(+), 22 deletions(-)
include/linux/if_link.h +1 -0
index c52d4b5..4b24ff4 100644
@@ -137,6 +137,7 @@ enum {
 	IFLA_AF_SPEC,
 	IFLA_GROUP,		/* Group the device belongs to */
 	IFLA_NET_NS_FD,
+	IFLA_EXT_MASK,		/* Extended info mask, VFs, etc */
 	__IFLA_MAX
 };
 
include/linux/netlink.h +2 -0
index a390e9d..fe9e938 100644
@@ -59,6 +59,7 @@ struct nlmsghdr {
 #define NLM_F_MATCH	0x200	/* return all matching	*/
 #define NLM_F_ATOMIC	0x400	/* atomic GET		*/
 #define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+#define NLM_F_EXT	0x800	/* Get extended interface info such as VFs */
 
 /* Modifiers to NEW request */
 #define NLM_F_REPLACE	0x100	/* Override existing		*/
@@ -215,6 +216,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb);
 #else
 #define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
 #endif
+#define NLMSG_EXT_GOODSIZE SKB_WITH_OVERHEAD(32768UL)
 
 #define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
 
include/linux/rtnetlink.h +9 -0
index 8e872ea..89244b8 100644
@@ -602,6 +602,15 @@ struct tcamsg {
 #define TCA_ACT_TAB 1 /* attr type must be >=1 */	
 #define TCAA_MAX 1
 
+struct rtnl_req_extended {
+	struct nlmsghdr nlh;
+	struct rtgenmsg g;
+	char ext[RTA_SPACE(sizeof(__u32))];
+};
+
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF		(1 << 0)
+
 /* End of information exported to user level */
 
 #ifdef __KERNEL__
include/net/rtnetlink.h +1 -1
index 678f1ff..3702939 100644
@@ -6,7 +6,7 @@
 
 typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
 typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
-typedef u16 (*rtnl_calcit_func)(struct sk_buff *);
+typedef u16 (*rtnl_calcit_func)(struct sk_buff *, struct nlmsghdr *);
 
 extern int	__rtnl_register(int protocol, int msgtype,
 				rtnl_doit_func, rtnl_dumpit_func,
net/core/rtnetlink.c +52 -21

180 lines not on this page · raw message

#1 lore raw
Quoted 7 lines · On Sun, 12 Feb 2012 11:13:42 -0800 Greg Rose <[email protected]> wrote:

Implement a new nlattr type IFLA_EXT_MASK. The mask is a 32 bit value that can be used to indicate to the kernel that certain extended ifinfo values are requested by the user application. At this time the only mask value created is RTEXT_FILTER_VF to indicate that the user wants the ifinfo dump to send information about the VFs belonging to the interface.

Quoted 8 lines

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present. It does not act as the filter itself which has changed since the first submission of this RFC. Older versions of user applications won't set this flag which should fix the problem of some applications not allocating a large enough buffer for all the extended interface information.

Is u32 going to be enough in next 5 years?
Since it is TLV value it should work with bigger value; could you try sending a oversize attribute and code kernel to ignore bits it doesn't understand?

#2 lore raw
Quoted 25 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Stephen Hemminger
Sent: Monday, February 13, 2012 9:29 AM
To: Rose, Gregory V
Cc: [email protected]; [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

Quoted 14 lines · On Sun, 12 Feb 2012 11:13:42 -0800 Greg Rose <[email protected]> wrote:

Implement a new nlattr type IFLA_EXT_MASK. The mask is a 32 bit value that can be used to indicate to the kernel that certain extended ifinfo values are requested by the user application. At this time the only mask value created is RTEXT_FILTER_VF to indicate that the user wants the ifinfo dump to send information about the VFs belonging to the interface.

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present. It does not act as the filter itself which has changed since the first submission of this RFC. Older versions of user applications won't set this flag which should fix the problem of some applications not allocating a large enough buffer for all the extended interface information.

Quoted 3 lines
Quoted 1 line

Is u32 going to be enough in next 5 years?

I'm not very good at predicting the future.

;^)

Quoted 3 lines

Since it is TLV value it should work with bigger value; could you try sending a oversize attribute and code kernel to ignore bits it doesn't understand?

That sounds like a good idea. While I'm carving out some new space for the dump request message I might as well allocate some extra for future requirements. I'll increase the size of the ext space array to something like 16 or 32 u32 sized words and increase the attribute length accordingly. That should do for a long time I suppose.

First we'll see if the associated kernel patch is going to fly or not.

Thanks,

- Greg

#3 lore raw
In reply to Greg Rose

Thanks for persisting, Greg.

Quoted 13 lines · Greg Rose

Implement a new nlattr type IFLA_EXT_MASK. The mask is a 32 bit value that can be used to indicate to the kernel that certain extended ifinfo values are requested by the user application. At this time the only mask value created is RTEXT_FILTER_VF to indicate that the user wants the ifinfo dump to send information about the VFs belonging to the interface.

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present. It does not act as the filter itself which has changed since the first submission of this RFC. Older versions of user applications won't set this flag which should fix the problem of some applications not allocating a large enough buffer for all the extended interface information.

[...]

Quoted 11 lines
include/linux/netlink.h +1 -0
@@ -59,6 +59,7 @@ struct nlmsghdr {
 #define NLM_F_MATCH	0x200	/* return all matching	*/
 #define NLM_F_ATOMIC	0x400	/* atomic GET		*/
 #define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+#define NLM_F_EXT	0x800	/* Get extended interface info such as VFs */
 
 /* Modifiers to NEW request */
 #define NLM_F_REPLACE	0x100	/* Override existing		*/

include/linux/netlink.h int netlink_sendskb(struct sock *sk, struct sk_buff *skb); · line 219

Quoted 4 lines
include/linux/netlink.h +1 -0
@@ -215,6 +216,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb);
 #else
 #define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
 #endif
+#define NLMSG_EXT_GOODSIZE SKB_WITH_OVERHEAD(32768UL)

This will probably do for now, but it would be preferable to really calculate the maximum size.

I fear this is going to be too small in some cases while resulting in allocation failures in others (that's an order-4 page allocation!). Maybe reduce the message size slightly so that the skb data allocation is within 32K?

[...]

Quoted 2 lines
net/core/rtnetlink.c +0 -0

[...]

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1062

Quoted 5 lines
net/core/rtnetlink.c +1 -0
@@ -1055,6 +1059,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 	rcu_read_lock();
 	cb->seq = net->dev_base_seq;
 
+	if (cb->nlh->nlmsg_flags && NLM_F_EXT) {

& not &&

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1071

Quoted 9 lines
net/core/rtnetlink.c +9 -0
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)cb->nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

We cannot trust a flag to tell us what the length of the message is. We have to check the value of nlmsg_len (which netlink has already validated as being within the skb length and >= our declared request header length). I think that makes the flag redundant.

In fact, I think we should really use nlmsg_parse() here. That might be overkill when there's only a single valid attribute; I don't know.

[...]

Quoted 5 lines
net/core/rtnetlink.c +0 -1
@@ -1861,12 +1876,12 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 	if (dev == NULL)
 		return -ENODEV;
 
-	nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);

net/core/rtnetlink.c static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) · line 1887

Quoted 10 lines
net/core/rtnetlink.c +2 -1
+	nskb = nlmsg_new(if_nlmsg_size(dev, 0), GFP_KERNEL);
 	if (nskb == NULL)
 		return -ENOBUFS;
 
 	err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
-			       nlh->nlmsg_seq, 0, 0);
+			       nlh->nlmsg_seq, 0, 0, 0);
 	if (err < 0) {
 		/* -EMSGSIZE implies BUG in if_nlmsg_size */
 		WARN_ON(err == -EMSGSIZE);

It seems like this ought to support IFLA_EXT_MASK as well, though it's maybe less important ('ip link' doesn't need it).

Quoted 11 lines
net/core/rtnetlink.c +4 -2
@@ -1877,9 +1892,26 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 	return err;
 }
 
-static u16 rtnl_calcit(struct sk_buff *skb)
+static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	return min_ifinfo_dump_size;
+	struct rtnl_req_extended *req;
+	u32 ext_filter_mask = 0;
+

net/core/rtnetlink.c static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) · line 1909

Quoted 10 lines
net/core/rtnetlink.c +10 -0
+	if (nlh->nlmsg_flags && NLM_F_EXT) {
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)&nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

[...]

This has the same parsing problem as rtnl_dump_ifinfo().

Ben.

Signature · 3 lines
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
#4 lore raw
Quoted 8 lines

-----Original Message-----
From: Ben Hutchings [mailto:[email protected]]
Sent: Tuesday, February 14, 2012 1:13 PM
To: Rose, Gregory V
Cc: [email protected]; [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

Thanks for persisting, Greg.

We'll slay this dragon for good someday.

Quoted 29 lines · Greg Rose
Quoted 13 lines

Implement a new nlattr type IFLA_EXT_MASK. The mask is a 32 bit value that can be used to indicate to the kernel that certain extended ifinfo values are requested by the user application. At this time the only mask value created is RTEXT_FILTER_VF to indicate that the user wants the ifinfo dump to send information about the VFs belonging to the interface.

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present. It does not act as the filter itself which has changed since the first submission of this RFC. Older versions of user applications won't set this flag which should fix the problem of some applications not allocating a large enough buffer for all the extended interface information.

[...]

include/linux/netlink.h struct nlmsghdr { · line 62

Quoted 7 lines
include/linux/netlink.h +1 -0
@@ -59,6 +59,7 @@ struct nlmsghdr {
 #define NLM_F_MATCH	0x200	/* return all matching	*/
 #define NLM_F_ATOMIC	0x400	/* atomic GET		*/
 #define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+#define NLM_F_EXT	0x800	/* Get extended interface info such as VFs

*/

include/linux/netlink.h int netlink_sendskb(struct sock *sk, struct sk_buff

Quoted 4 lines
include/linux/netlink.h +0 -0
 /* Modifiers to NEW request */
 #define NLM_F_REPLACE	0x100	/* Override existing		*/
@@ -215,6 +216,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff

*skb);

Quoted 7 lines

include/linux/netlink.h int netlink_sendskb(struct sock *sk, struct sk_buff *skb); · line 219

Quoted 4 lines
include/linux/netlink.h +1 -0
 #else
 #define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
 #endif
+#define NLMSG_EXT_GOODSIZE SKB_WITH_OVERHEAD(32768UL)

This will probably do for now, but it would be preferable to really calculate the maximum size.

That's a real sticky problem. When the dump request comes in we don't know how big the required buffer might actually get. That's why we used to have the min_ifinfo_dump_size. However there were problems with that also so Dave asked me to get rid of it. The only thing I could come up with just allocating a really big buffer. If someone could point out to me how to get a maximum ifinfo dump size before rtnl_dump_ifinfo starts filtering through the matching interfaces then that would really help. But at the point the dump request comes in we don't know beforehand how to calculate the info dump size because if_nlmsg_size() requires a pointer to a netdevice.

Quoted 5 lines

I fear this is going to be too small in some cases while resulting in allocation failures in others (that's an order-4 page allocation!). Maybe reduce the message size slightly so that the skb data allocation is within 32K?

Yeah, I could certainly do that.

Quoted 5 lines

[...]

Quoted 2 lines
net/core/rtnetlink.c +0 -0

[...]

Quoted 8 lines

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb,

Quoted 1 line
net/core/rtnetlink.c +0 -0
@@ -1055,6 +1059,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb,

struct netlink_callback *cb)

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1062

Quoted 4 lines
net/core/rtnetlink.c +1 -0
 	rcu_read_lock();
 	cb->seq = net->dev_base_seq;
 
+	if (cb->nlh->nlmsg_flags && NLM_F_EXT) {

& not &&

Oops. OK.

Quoted 16 lines

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1071

Quoted 10 lines
net/core/rtnetlink.c +9 -0
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)cb->nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

We cannot trust a flag to tell us what the length of the message is. We have to check the value of nlmsg_len (which netlink has already validated as being within the skb length and >= our declared request header length). I think that makes the flag redundant.

Quoted 2 lines

In fact, I think we should really use nlmsg_parse() here. That might be overkill when there's only a single valid attribute; I don't know.

Hmm, but we do want to plan for future expansion and more attributes. I think that is probably a good idea.

Quoted 12 lines

[...]

net/core/rtnetlink.c static int rtnl_getlink(struct sk_buff *skb,

Quoted 1 line
net/core/rtnetlink.c +0 -0
@@ -1861,12 +1876,12 @@ static int rtnl_getlink(struct sk_buff *skb,

struct nlmsghdr* nlh, void *arg)

Quoted 8 lines
net/core/rtnetlink.c +1 -1
 	if (dev == NULL)
 		return -ENODEV;
 
-	nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
+	nskb = nlmsg_new(if_nlmsg_size(dev, 0), GFP_KERNEL);
 	if (nskb == NULL)
 		return -ENOBUFS;
 
Quoted 9 lines

net/core/rtnetlink.c static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) · line 1887

Quoted 6 lines
net/core/rtnetlink.c +1 -1
 	err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
-			       nlh->nlmsg_seq, 0, 0);
+			       nlh->nlmsg_seq, 0, 0, 0);
 	if (err < 0) {
 		/* -EMSGSIZE implies BUG in if_nlmsg_size */
 		WARN_ON(err == -EMSGSIZE);

It seems like this ought to support IFLA_EXT_MASK as well, though it's maybe less important ('ip link' doesn't need it).

That's all I've been testing with but if there are other callers I'm unaware of then I can add the parsing here too.

Quoted 25 lines

net/core/rtnetlink.c static int rtnl_getlink(struct sk_buff *skb,

Quoted 2 lines
net/core/rtnetlink.c +0 -0
@@ -1877,9 +1892,26 @@ static int rtnl_getlink(struct sk_buff *skb,

struct nlmsghdr* nlh, void *arg)

Quoted 20 lines
net/core/rtnetlink.c +14 -2
 	return err;
 }
 
-static u16 rtnl_calcit(struct sk_buff *skb)
+static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	return min_ifinfo_dump_size;
+	struct rtnl_req_extended *req;
+	u32 ext_filter_mask = 0;
+
+	if (nlh->nlmsg_flags && NLM_F_EXT) {
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)&nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

[...]

Quoted 1 line

This has the same parsing problem as rtnl_dump_ifinfo().

OK.

Thanks for the review. I'll work in your suggested changes and resubmit the RFC.

- Greg

maintainer
#5 lore raw

From: "Rose, Gregory V" <[email protected]>
Date: Tue, 14 Feb 2012 21:27:59 +0000

Quoted 10 lines

That's a real sticky problem. When the dump request comes in we don't know how big the required buffer might actually get. That's why we used to have the min_ifinfo_dump_size. However there were problems with that also so Dave asked me to get rid of it. The only thing I could come up with just allocating a really big buffer. If someone could point out to me how to get a maximum ifinfo dump size before rtnl_dump_ifinfo starts filtering through the matching interfaces then that would really help. But at the point the dump request comes in we don't know beforehand how to calculate the info dump size because if_nlmsg_size() requires a pointer to a netdevice.

Two quick ideas:

1) Have a first pass which iterates over the devices and calculates the maximum of all if_nlmsg_size() calculations over those devices then uses that for the dump buffer allocation size.

2) Replace min_ifinfo_dump_size() with an array of sizes, one for each combination of extended features. The only concern with this one is that whilst it's practical to do this now with only 1 or a few feature bits, in the future it may be a lot less practical.

#6 lore raw
Quoted 23 lines

-----Original Message-----
From: David Miller [mailto:[email protected]]
Sent: Tuesday, February 14, 2012 1:32 PM
To: Rose, Gregory V
Cc: [email protected]; [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

From: "Rose, Gregory V" <[email protected]>
Date: Tue, 14 Feb 2012 21:27:59 +0000

Quoted 10 lines

That's a real sticky problem. When the dump request comes in we don't know how big the required buffer might actually get. That's why we used to have the min_ifinfo_dump_size. However there were problems with that also so Dave asked me to get rid of it. The only thing I could come up with just allocating a really big buffer. If someone could point out to me how to get a maximum ifinfo dump size before rtnl_dump_ifinfo starts filtering through the matching interfaces then that would really help. But at the point the dump request comes in we don't know beforehand how to calculate the info dump size because if_nlmsg_size() requires a pointer to a netdevice.

Two quick ideas:

Quoted 8 lines

1) Have a first pass which iterates over the devices and calculates the maximum of all if_nlmsg_size() calculations over those devices then uses that for the dump buffer allocation size.

2) Replace min_ifinfo_dump_size() with an array of sizes, one for each combination of extended features. The only concern with this one is that whilst it's practical to do this now with only 1 or a few feature bits, in the future it may be a lot less practical.

The second item sort of matches what I said in the last reply. Base the buffer allocation size on the maximum possible for the given extension which as I said, is up to 255 VFs for the case under immediate consideration.

The first one seems like a good idea but I wonder what the effect would be on a system with a large number of interfaces.

- Greg

maintainer
#7 lore raw

From: "Rose, Gregory V" <[email protected]>
Date: Tue, 14 Feb 2012 21:41:57 +0000

Quoted 4 lines

The second item sort of matches what I said in the last reply. Base the buffer allocation size on the maximum possible for the given extension which as I said, is up to 255 VFs for the case under immediate consideration.

That's what we're trying to avoid, because that will result in multi-order allocations (which are failure prone) when most of the time such a large buffer is entirely unnecessary.

Quoted 2 lines

The first one seems like a good idea but I wonder what the effect would be on a system with a large number of interfaces.

It's already expensive to dump a large number of devices, and in effect you'll be optimizing the buffer allocation which could in fact end up helping performance.

#8 lore raw
Quoted 19 lines

-----Original Message-----
From: David Miller [mailto:[email protected]]
Sent: Tuesday, February 14, 2012 1:48 PM
To: Rose, Gregory V
Cc: [email protected]; [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

From: "Rose, Gregory V" <[email protected]>
Date: Tue, 14 Feb 2012 21:41:57 +0000

Quoted 4 lines

The second item sort of matches what I said in the last reply. Base the buffer allocation size on the maximum possible for the given extension which as I said, is up to 255 VFs for the case under immediate consideration.

That's what we're trying to avoid, because that will result in multi-order allocations (which are failure prone) when most of the time such a large buffer is entirely unnecessary.

Quoted 6 lines
Quoted 2 lines

The first one seems like a good idea but I wonder what the effect would be on a system with a large number of interfaces.

It's already expensive to dump a large number of devices, and in effect you'll be optimizing the buffer allocation which could in fact end up helping performance.

OK, I'll see what I can do.

- Greg

#9 lore raw
In reply to Ben Hutchings
Quoted 15 lines · Ben Hutchings

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1071

Quoted 9 lines
net/core/rtnetlink.c +9 -0
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)cb->nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

We cannot trust a flag to tell us what the length of the message is. We have to check the value of nlmsg_len (which netlink has already validated as being within the skb length and >= our declared request header length). I think that makes the flag redundant.

Quoted 2 lines

In fact, I think we should really use nlmsg_parse() here. That might be overkill when there's only a single valid attribute; I don't know.

I think it's worth the effort. You get all the validation for free. And please use the netlink interface in <net/netlink.h>, the rtattr based interface has been deprecated a while ago.

#10 lore raw
Quoted 23 lines

-----Original Message-----
From: Thomas Graf [mailto:[email protected]] On Behalf Of Thomas Graf
Sent: Wednesday, February 15, 2012 6:08 AM
To: Ben Hutchings
Cc: Rose, Gregory V; [email protected]; [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

Quoted 15 lines · Ben Hutchings

net/core/rtnetlink.c static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) · line 1071

Quoted 9 lines
net/core/rtnetlink.c +9 -0
+		struct rtattr *ext_req;
+		u32 *ext_req_data;
+		req = (struct rtnl_req_extended *)cb->nlh;
+		ext_req = (struct rtattr *)&req->ext;
+		if (ext_req->rta_type == IFLA_EXT_MASK) {
+			ext_req_data = RTA_DATA(ext_req);
+			ext_filter_mask = *ext_req_data;
+		}
+	}

We cannot trust a flag to tell us what the length of the message is. We have to check the value of nlmsg_len (which netlink has already validated as being within the skb length and >= our declared request header length). I think that makes the flag redundant.

Quoted 6 lines
Quoted 2 lines

In fact, I think we should really use nlmsg_parse() here. That might be overkill when there's only a single valid attribute; I don't know.

I think it's worth the effort. You get all the validation for free. And please use the netlink interface in <net/netlink.h>, the rtattr based interface has been deprecated a while ago.

Yes, I'm changing it to use nlmsg_parse. Didn't know about the deprecation of rtattr though, thanks for the tip.

- Greg

maintainer
#11 lore raw
In reply to Greg Rose

From: Greg Rose <[email protected]>
Date: Sun, 12 Feb 2012 11:13:42 -0800

Quoted 2 lines

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present.

No extra indications other than presence of the attribute itself is necessary. Please remove this flag.

include/linux/netlink.h int netlink_sendskb(struct sock *sk, struct sk_buff *skb); · line 219

Quoted 5 lines
include/linux/netlink.h +1 -0
@@ -215,6 +216,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb);
 #else
 #define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
 #endif
+#define NLMSG_EXT_GOODSIZE SKB_WITH_OVERHEAD(32768UL)

I indicated in my suggestions that you'll need to calculate this at run-time based upon the extensions enabled and the size of the resulting message plus attributes.

You absolutely cannot just pick some large number and run with this, it's highly wasteful and will be potentially causing allocation failures.

The goodsize value is specifically choosen such that we don't exceed an order-1 allocation with page sizes of 4096 and larger.

include/linux/rtnetlink.h struct tcamsg { · line 613

Quoted 9 lines
include/linux/rtnetlink.h +9 -0
+struct rtnl_req_extended {
+	struct nlmsghdr nlh;
+	struct rtgenmsg g;
+	char ext[RTA_SPACE(sizeof(__u32))];
+};
+
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF		(1 << 0)
+

This seems completely unnecessary.

Just define IFLA_EXT_MASK as a variable length array of u32's, but to be honest, for now, you can just make it a normal u32 attribute.

If we extend it in the future, we can make the kernel handle any length, u32 or otherwise. The size field already present in all netlink attributes will allow us to do this transparently.

#12 lore raw
Quoted 27 lines

-----Original Message-----
From: David Miller [mailto:[email protected]]
Sent: Tuesday, February 14, 2012 1:23 PM
To: Rose, Gregory V
Cc: [email protected]
Subject: Re: [RFC V2 PATCH] rtnetlink: Fix problem with buffer allocation

From: Greg Rose <[email protected]>
Date: Sun, 12 Feb 2012 11:13:42 -0800

Quoted 2 lines

I have kept the NLM_F_EXT nlmsg_flags bit to indicate to the kernel that the extended ifinfo dump filter mask is present.

No extra indications other than presence of the attribute itself is necessary. Please remove this flag.

Review int netlink_sendskb(struct sock *sk, struct sk_buff

Quoted 1 line
(quoted diff) +0 -0
@@ -215,6 +216,7 @@ int netlink_sendskb(struct sock *sk, struct sk_buff

*skb);

include/linux/netlink.h int netlink_sendskb(struct sock *sk, struct sk_buff *skb); · line 219

Quoted 4 lines
include/linux/netlink.h +1 -0
 #else
 #define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
 #endif
+#define NLMSG_EXT_GOODSIZE SKB_WITH_OVERHEAD(32768UL)

I indicated in my suggestions that you'll need to calculate this at run-time based upon the extensions enabled and the size of the resulting message plus attributes.

Quoted 6 lines

You absolutely cannot just pick some large number and run with this, it's highly wasteful and will be potentially causing allocation failures.

The goodsize value is specifically choosen such that we don't exceed an order-1 allocation with page sizes of 4096 and larger.

If I do the buffer size calculation based upon the extensions enabled then I'll have to assume the maximum possible size because at the time the buffer size is calculated we don't' have a handle to the net devices yet.

So if the VF flag is set then I'll assume that up to 255 VFs might be present and calculate based upon that.

Quoted 13 lines

include/linux/rtnetlink.h struct tcamsg { · line 613

Quoted 10 lines
include/linux/rtnetlink.h +9 -0
+struct rtnl_req_extended {
+	struct nlmsghdr nlh;
+	struct rtgenmsg g;
+	char ext[RTA_SPACE(sizeof(__u32))];
+};
+
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF		(1 << 0)
+

This seems completely unnecessary.

Quoted 6 lines

Just define IFLA_EXT_MASK as a variable length array of u32's, but to be honest, for now, you can just make it a normal u32 attribute.

If we extend it in the future, we can make the kernel handle any length, u32 or otherwise. The size field already present in all netlink attributes will allow us to do this transparently.

OK, I think I see where you and Ben are coming from on this.

Thanks,

- Greg