diff mbox

[net] netpoll: fix rx_hook() interface by passing the skb

Message ID 1382431715-3128-1-git-send-email-antonio@meshcoding.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Antonio Quartulli Oct. 22, 2013, 8:48 a.m. UTC
Right now skb->data is passed to rx_hook() even if the skb
has not been linearised and without giving rx_hook() a way
to linearise it.

Change the rx_hook() interface and make it accept the skb
as argument. In this way users implementing rx_hook() can
perform all the needed operations to properly (and safely)
access the skb data.

Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
---
 include/linux/netpoll.h |  2 +-
 net/core/netpoll.c      | 10 ++++------
 2 files changed, 5 insertions(+), 7 deletions(-)

Comments

David Laight Oct. 22, 2013, 9:09 a.m. UTC | #1
> Subject: [PATCH net] netpoll: fix rx_hook() interface by passing the skb
> 
> Right now skb->data is passed to rx_hook() even if the skb
> has not been linearised and without giving rx_hook() a way
> to linearise it.
> 
> Change the rx_hook() interface and make it accept the skb
> as argument. In this way users implementing rx_hook() can
> perform all the needed operations to properly (and safely)
> access the skb data.
...
> -	void (*rx_hook)(struct netpoll *, int, char *, int);
> +	void (*rx_hook)(struct netpoll *np, struct sk_buff *skb, int offset);

You can't do that change without changing the way that hooks are registered
so that any existing modules will fail to register their hooks.

	David



--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Antonio Quartulli Oct. 22, 2013, 10:11 a.m. UTC | #2
On Tue, Oct 22, 2013 at 10:09:00AM +0100, David Laight wrote:
> > Subject: [PATCH net] netpoll: fix rx_hook() interface by passing the skb
> > 
> > Right now skb->data is passed to rx_hook() even if the skb
> > has not been linearised and without giving rx_hook() a way
> > to linearise it.
> > 
> > Change the rx_hook() interface and make it accept the skb
> > as argument. In this way users implementing rx_hook() can
> > perform all the needed operations to properly (and safely)
> > access the skb data.
> ...
> > -	void (*rx_hook)(struct netpoll *, int, char *, int);
> > +	void (*rx_hook)(struct netpoll *np, struct sk_buff *skb, int offset);
> 
> You can't do that change without changing the way that hooks are registered
> so that any existing modules will fail to register their hooks.

There is no hook registration in the kernel tree. All the users are outside.
David Laight Oct. 22, 2013, 12:46 p.m. UTC | #3
> Subject: Re: [PATCH net] netpoll: fix rx_hook() interface by passing the skb

> 

> On Tue, Oct 22, 2013 at 10:09:00AM +0100, David Laight wrote:

> > > Subject: [PATCH net] netpoll: fix rx_hook() interface by passing the skb

> > >

> > > Right now skb->data is passed to rx_hook() even if the skb

> > > has not been linearised and without giving rx_hook() a way

> > > to linearise it.

> > >

> > > Change the rx_hook() interface and make it accept the skb

> > > as argument. In this way users implementing rx_hook() can

> > > perform all the needed operations to properly (and safely)

> > > access the skb data.

> > ...

> > > -	void (*rx_hook)(struct netpoll *, int, char *, int);

> > > +	void (*rx_hook)(struct netpoll *np, struct sk_buff *skb, int offset);

> >

> > You can't do that change without changing the way that hooks are registered

> > so that any existing modules will fail to register their hooks.

> 

> There is no hook registration in the kernel tree. All the users are outside.


Looking at __netpoll_rx() I notice that there isn't an skb_pull for the
udp header.

Actually, I think the alignment rules effectively imply that iph->ihl
(the second byte) will always be in the first skb fragment so the
code could sensible do a single skb_pull() that includes the udp header.

I can't remember which value you passed as 'offset' (and my mailer makes
it hard to find), but to ease the code changes the offset of the udp data
would make sense.
In that case you still need to pass the source port.
If you do rx_hook(np, source_port, skb, offset) then if anyone manages to
load an old module (or code that casts the assignement to rx_poll)
at least it won't go 'bang'.
Renaming the structure member will guarantee to generate compile errors.

	David
Antonio Quartulli Oct. 22, 2013, 5:13 p.m. UTC | #4
On Tue, Oct 22, 2013 at 01:46:22PM +0100, David Laight wrote:
> > Subject: Re: [PATCH net] netpoll: fix rx_hook() interface by passing the skb
> > 
> > On Tue, Oct 22, 2013 at 10:09:00AM +0100, David Laight wrote:
> > > > Subject: [PATCH net] netpoll: fix rx_hook() interface by passing the skb
> > > >
> > > > Right now skb->data is passed to rx_hook() even if the skb
> > > > has not been linearised and without giving rx_hook() a way
> > > > to linearise it.
> > > >
> > > > Change the rx_hook() interface and make it accept the skb
> > > > as argument. In this way users implementing rx_hook() can
> > > > perform all the needed operations to properly (and safely)
> > > > access the skb data.
> > > ...
> > > > -	void (*rx_hook)(struct netpoll *, int, char *, int);
> > > > +	void (*rx_hook)(struct netpoll *np, struct sk_buff *skb, int offset);
> > >
> > > You can't do that change without changing the way that hooks are registered
> > > so that any existing modules will fail to register their hooks.
> > 
> > There is no hook registration in the kernel tree. All the users are outside.
> 
> Looking at __netpoll_rx() I notice that there isn't an skb_pull for the
> udp header.
> 
> Actually, I think the alignment rules effectively imply that iph->ihl
> (the second byte) will always be in the first skb fragment so the
> code could sensible do a single skb_pull() that includes the udp header.
> 
> I can't remember which value you passed as 'offset' (and my mailer makes
> it hard to find), but to ease the code changes the offset of the udp data
> would make sense.
> In that case you still need to pass the source port.

I decided not to pass the source port because if the user is really interested
in it, it is still possible to get the udp_hdr from the skb and read its value.

> If you do rx_hook(np, source_port, skb, offset) then if anyone manages to
> load an old module (or code that casts the assignement to rx_poll)
> at least it won't go 'bang'.
> Renaming the structure member will guarantee to generate compile errors.
> 

so you suggest to rename rx_hook to something else to warn people about the
change?

If we go for the "no udp port" approach they will get an error any way because
of the mismatching arguments.

Regards,
David Miller Oct. 22, 2013, 7:40 p.m. UTC | #5
From: Antonio Quartulli <antonio@meshcoding.com>
Date: Tue, 22 Oct 2013 19:13:14 +0200

> If we go for the "no udp port" approach they will get an error any
> way because of the mismatching arguments.

Antonio, I think it is fair enough to keep passing the port argument
as well as the length.

These precomputed values might as well be provided the to receiver.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Antonio Quartulli Oct. 23, 2013, 10:28 a.m. UTC | #6
On Wed, Oct 23, 2013 at 09:33:49AM +0100, David Laight wrote:
> ...
> > > I can't remember which value you passed as 'offset' (and my mailer makes
> > > it hard to find), but to ease the code changes the offset of the udp data
> > > would make sense.
> > > In that case you still need to pass the source port.
> > 
> > I decided not to pass the source port because if the user is really interested
> > in it, it is still possible to get the udp_hdr from the skb and read its value.
> 
> It just seemed that there was no need to require that the hook re-parse
> the ip header just to find the source port.
> (ok it could assume that the udp header is just before the data)

Also David (M.) pointed out the same. I will keep the port as argument for
rx_hook.

>  
> > > If you do rx_hook(np, source_port, skb, offset) then if anyone manages to
> > > load an old module (or code that casts the assignement to rx_poll)
> > > at least it won't go 'bang'.
> > > Renaming the structure member will guarantee to generate compile errors.
> > 
> > so you suggest to rename rx_hook to something else to warn people about the
> > change?
> 
> Yes.
> 

mh..what about rx_skb_hook ? this way we also make it easy to notice the
difference (both in arguments and behaviour).

> > If we go for the "no udp port" approach they will get an error any way because
> > of the mismatching arguments.
> 
> No - you only get a warning when you assign a function pointer of the wrong type.
> And that is true even if you just change the type of the pointer.
> However code might already have a cast on the function pointer (eg because the
> hook has 'unsigned char *') - so you won't even get a warning.
> You then get an OOPS when the hook tries to read the buffer.
> 
> It is a really bad interface...
> There isn't even a flags/options (etc) word that can be used
> to detect enhancements.
> 


agreed. But I am not sure about what I could do to fix that.

My idea is to use the following API:

rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int len);


Any suggestion or objection?


Regards,
David Laight Oct. 23, 2013, 11:18 a.m. UTC | #7
> My idea is to use the following API:

> 

> rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int len);

> 

> Any suggestion or objection?


Don't you need to pass the offset of the udp data?

	David
Antonio Quartulli Oct. 23, 2013, 12:44 p.m. UTC | #8
On Wed, Oct 23, 2013 at 12:18:32PM +0100, David Laight wrote:
> > My idea is to use the following API:
> > 
> > rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int len);
> > 
> > Any suggestion or objection?
> 
> Don't you need to pass the offset of the udp data?

Yes, you are right. I just forgot it. Therefore we have:

rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int offset,
	    int len);

where offset is going to be = (udp_hdr + 1) - skb->data
and len = skb->len - offset

Regards,
David Miller Oct. 23, 2013, 8:16 p.m. UTC | #9
From: Antonio Quartulli <antonio@meshcoding.com>
Date: Wed, 23 Oct 2013 14:44:01 +0200

> On Wed, Oct 23, 2013 at 12:18:32PM +0100, David Laight wrote:
>> > My idea is to use the following API:
>> > 
>> > rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int len);
>> > 
>> > Any suggestion or objection?
>> 
>> Don't you need to pass the offset of the udp data?
> 
> Yes, you are right. I just forgot it. Therefore we have:
> 
> rx_skb_hook(struct netpoll *np, int source, struct sk_buff *skb, int offset,
> 	    int len);
> 
> where offset is going to be = (udp_hdr + 1) - skb->data
> and len = skb->len - offset

This looks good to me.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index f3c7c24..5352160 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -24,7 +24,7 @@  struct netpoll {
 	struct net_device *dev;
 	char dev_name[IFNAMSIZ];
 	const char *name;
-	void (*rx_hook)(struct netpoll *, int, char *, int);
+	void (*rx_hook)(struct netpoll *np, struct sk_buff *skb, int offset);
 
 	union inet_addr local_ip, remote_ip;
 	bool ipv6;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index fc75c9e..b415437 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -834,9 +834,8 @@  int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 			if (np->local_port && np->local_port != ntohs(uh->dest))
 				continue;
 
-			np->rx_hook(np, ntohs(uh->source),
-				       (char *)(uh+1),
-				       ulen - sizeof(struct udphdr));
+			np->rx_hook(np, skb,
+				    (unsigned char *)(uh + 1) - skb->data);
 			hits++;
 		}
 	} else {
@@ -872,9 +871,8 @@  int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 			if (np->local_port && np->local_port != ntohs(uh->dest))
 				continue;
 
-			np->rx_hook(np, ntohs(uh->source),
-				       (char *)(uh+1),
-				       ulen - sizeof(struct udphdr));
+			np->rx_hook(np, skb,
+				    (unsigned char *)(uh + 1) - skb->data);
 			hits++;
 		}
 #endif