net: packet: option to only pass skb protocol
Subsystems (3)
PATCH 1/1 net: packet: option to only pass skb protocol
When sending packets with a packet socket it is often necessary to set protocol in msg_name: otherwise the protocol field in the skb will not be set correctly. However, currently doing this also requires supplying the interface index.
The following patch makes it possible to avoid supplying the interface index by interpreting index 0 as "use device this socket is bound to".
--- net/packet/af_packet.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
net/packet/af_packet.c +2 -2
@@ -958,7 +958,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) + offsetof(struct sockaddr_ll, sll_addr))) goto out; - ifindex = saddr->sll_ifindex; + ifindex = saddr->sll_ifindex ? : po->ifindex; proto = saddr->sll_protocol; addr = saddr->sll_addr; }
@@ -1074,7 +1074,7 @@ static int packet_snd(struct socket *sock, goto out;if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; - ifindex = saddr->sll_ifindex; + ifindex = saddr->sll_ifindex ? : po->ifindex; proto = saddr->sll_protocol; addr = saddr->sll_addr; }
Signature · 1 line
1.6.6.rc1.43.gf55cc
Quoted 8 lines · Michael S. Tsirkin
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly. However, currently doing this also requires supplying the interface index.The following patch makes it possible to avoid supplying the interface index by interpreting index 0 as "use device this socket is bound to".
Patch is correct, but I dont understand why zero initialization by caller is any better then supplying ifindex (known when socket was bound to device ?)
To avoid one syscall at socket setup (to get ifindex from dev name), you prefer to add a test/branch at each send() syscall...
Am I missing something ?
Quoted 10 lines · Eric Dumazet
Quoted 8 lines · Michael S. Tsirkin
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly. However, currently doing this also requires supplying the interface index.The following patch makes it possible to avoid supplying the interface index by interpreting index 0 as "use device this socket is bound to".
Quoted 7 lines
Patch is correct, but I dont understand why zero initialization by caller is any better then supplying ifindex (known when socket was bound to device ?)
To avoid one syscall at socket setup (to get ifindex from dev name), you prefer to add a test/branch at each
send()syscall...Am I missing something ?
binding socket to device might be done by a separate process from the one doing sendmsg, and IMO the device socket is bound to might change at any time.
So the sending process would need to get socket name before each sendmsg.
Makes sense?
Signature · 1 line
MST
Quoted 3 lines · Michael S. Tsirkin
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.
What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
Chris
David Miller
maintainerFrom: "Michael S. Tsirkin" <[email protected]>
Date: Tue, 5 Jan 2010 22:50:40 +0200
Quoted 8 lines
binding socket to device might be done by a separate process from the one doing sendmsg, and IMO the device socket is bound to might change at any time.
So the sending process would need to get socket name before each sendmsg.
Makes sense?
Not really, when it's at the expense of everyone else.
If you can pass the FD around, you can pass around auxiliary information as well.
Make sense? :-)
David Miller
maintainerFrom: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 15:28:22 -0600
Quoted 7 lines · Michael S. Tsirkin
Quoted 3 lines
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
This limits packet socket usage to only protocols the kernel is aware of, defeating part of the usefulness of the packet socket facility.
Quoted 8 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 15:28:22 -0600Quoted 5 lines · Michael S. Tsirkin
Quoted 3 lines
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.
Quoted 5 lines
Quoted 2 lines
What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
This limits packet socket usage to only protocols the kernel is aware of, defeating part of the usefulness of the packet socket facility.
We could do this if the protocol is ETH_P_ALL - skbs end up with this protocol currently when sendmsg does not have msgname and when socket is set up to listen for all packets. It's not a valid protocol value, is it?
Signature · 1 line
MST
Quoted 10 lines · David Miller
From: "Michael S. Tsirkin" <[email protected]>
Date: Tue, 5 Jan 2010 22:50:40 +0200Quoted 7 lines
binding socket to device might be done by a separate process from the one doing sendmsg, and IMO the device socket is bound to might change at any time.
So the sending process would need to get socket name before each sendmsg.
Quoted 8 lines
Quoted 1 line
Makes sense?
Not really, when it's at the expense of everyone else.
If you can pass the FD around, you can pass around auxiliary information as well.
Make sense? :-)
At some level, of course I can. But I would have to do this communication each time socket is bound to another device, as opposed to passing the fd once. At least for me, option to autodetect protocol would work even better though - it's what I do in the application anyway.
Signature · 1 line
MST
Quoted 12 lines · Michael S. Tsirkin
Quoted 11 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 15:28:22 -0600Quoted 7 lines · Michael S. Tsirkin
Quoted 3 lines
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
Quoted 7 lines
Quoted 2 lines
This limits packet socket usage to only protocols the kernel is aware of, defeating part of the usefulness of the packet socket facility.
We could do this if the protocol is
ETH_P_ALL- skbs end up with this protocol currently when sendmsg does not have msgname and when socket is set up to listen for all packets. It's not a valid protocol value, is it?
Something like this (if we want to support this for all device types, we would probably need to add get_proto callback to net_device_ops), and call it instead of eth_hdr(skb)->h_proto.
net/packet/af_packet.c +9 -2
@@ -845,7 +845,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ph.raw = frame; - skb->protocol = proto; skb->dev = dev; skb->priority = po->sk.sk_priority; skb->mark = po->sk.sk_mark;
@@ -924,6 +923,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, len = ((to_write > len_max) ? len_max : to_write); } +if (proto ==htons (ETH_P_ALL ) && dev->type ==ARPHRD_ETHER ) + skb->protocol =eth_hdr (skb)->h_proto; +else + skb->protocol = proto; +return tp_len; }
@@ -1113,7 +1117,10 @@ static int packet_snd(struct socket *sock,if (err) goto out_free; - skb->protocol = proto; +if (proto ==htons (ETH_P_ALL ) && dev->type ==ARPHRD_ETHER ) + skb->protocol =eth_hdr (skb)->h_proto; +else + skb->protocol = proto; skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark;
Quoted 8 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 15:28:22 -0600Quoted 5 lines · Michael S. Tsirkin
Quoted 3 lines
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.
Quoted 5 lines
Quoted 2 lines
What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
This limits packet socket usage to only protocols the kernel is aware of, defeating part of the usefulness of the packet socket facility.
I don't follow.
If SOCK_RAW packets are being sent, the protocol number is embedded in the packet data and the kernel should be able to extract it regardless of whether the kernel actually supports it or not. I see that Michael just posted a patch for this.
If SOCK_DGRAM packets are being sent, then I agree that the app needs to pass it down at send time or at bind() time to support protocols of which the kernel is not aware.
While looking at the code I noticed that while the protocol number is validated at socket creation time it does not appear to be validated for calls to bind() for packet sockets. Is this intentional?
As a further question, does it actually make sense to check the protocol number at packet socket creation? It seems like we should be able to allow a packet socket to specify arbitrary protocol numbers since the kernel doesn't really need to do anything with them.
Chris
Quoted 30 lines · Chris Friesen
Quoted 8 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 15:28:22 -0600Quoted 5 lines · Michael S. Tsirkin
Quoted 3 lines
When sending packets with a packet socket it is often necessary to set protocol in
msg_name: otherwise the protocol field in the skb will not be set correctly.Quoted 5 lines
Quoted 2 lines
What about automatically detecting the protocol from the data being sent to avoid the necessity of specifying it in the first place?
This limits packet socket usage to only protocols the kernel is aware of, defeating part of the usefulness of the packet socket facility.
I don't follow.
If
SOCK_RAWpackets are being sent, the protocol number is embedded in the packet data and the kernel should be able to extract it regardless of whether the kernel actually supports it or not. I see that Michael just posted a patch for this.If
SOCK_DGRAMpackets are being sent, then I agree that the app needs to pass it down at send time or atbind()time to support protocols of which the kernel is not aware.While looking at the code I noticed that while the protocol number is validated at socket creation time it does not appear to be validated for calls to
bind()for packet sockets. Is this intentional?
Quoted 6 lines
As a further question, does it actually make sense to check the protocol number at packet socket creation? It seems like we should be able to allow a packet socket to specify arbitrary protocol numbers since the kernel doesn't really need to do anything with them.
Chris
I wouldn't say kernel doesn't really need to do anything with them.
In fact I think currently protocol number affects whether other packet sockets see the packet in question. There may be other cases, e.g. if the device in question is a bridge, the packet gets reinjected in host stack, so using a silly value for protocol field might interfere with GRO etc.
Signature · 1 line
MST
David Miller
maintainerFrom: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 16:13:29 -0600
Quoted 2 lines
If
SOCK_RAWpackets are being sent, the protocol number is embedded in the packet data
Where exactly is that protocol value? Not every link level protocol is ethernet.
We support FDDI, HIPPI, wireless, VLAN, PPP, and a host of others.
So you can't know for sure unless you assume ethernet, which you can't do.
Quoted 6 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 16:13:29 -0600Quoted 2 lines
If
SOCK_RAWpackets are being sent, the protocol number is embedded in the packet data
Quoted 7 lines
Where exactly is that protocol value? Not every link level protocol is ethernet.
We support FDDI, HIPPI, wireless, VLAN, PPP, and a host of others.
So you can't know for sure unless you assume ethernet, which you can't do.
You are right. This is TX though so the socket is bound to a specific device, and devices know which link protocol they use. So we could add a get_protocol operation to each device type, and call it if the protocol passed is ETH_P_ALL to get the real one.
Like this: except I only added this for ethernet, and I would have to add this for the rest of device types. But I would like to hear what others think about this before I do the rest of the work for the rest of device types.
Does the below look sane?
include/linux/netdevice.h +1 -0
@@ -319,6 +319,7 @@ struct header_ops {void (*cache_update)(struct hh_cache *hh,const struct net_device *dev,const unsigned char *haddr); + __be16 (*get_protocol)(struct sk_buff *skb, struct net_device *dev) };/* These flag bits are private to the generic network queueing
net/ethernet/eth.c +12 -0
@@ -231,6 +231,17 @@ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)EXPORT_SYMBOL (eth_header_parse);/** +* eth_get_protocol - extract protocol value from packet +* @skb: packet to extract protocol from +* @dev: source device +*/ +__be16 eth_get_protocol (const struct sk_buff *skb,struct net_device *dev) +{ +const struct ethhdr *eth =eth_hdr (skb); + return eth->h_proto +} + +/** * eth_header_cache - fill cache entry from neighbour * @neigh: source neighbour * @hh: destination cache entry
@@ -324,6 +335,7 @@ EXPORT_SYMBOL(eth_validate_addr);const struct header_ops eth_header_ops____cacheline_aligned = { .create = eth_header, .parse = eth_header_parse, + .get_protocol = eth_get_protocol, .rebuild = eth_rebuild_header, .cache = eth_header_cache, .cache_update = eth_header_cache_update,
net/packet/af_packet.c +15 -2
@@ -845,7 +845,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ph.raw = frame; - skb->protocol = proto; skb->dev = dev; skb->priority = po->sk.sk_priority; skb->mark = po->sk.sk_mark;
@@ -924,6 +923,14 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, len = ((to_write > len_max) ? len_max : to_write); } +if (proto ==htons (ETH_P_ALL ) && dev->header_ops->get_protocol) { + skb->protocol = dev->header_ops->get_protocol (dev, skb); +if (unlikely (skb->protocol ==htons (ETH_P_ALL ))) +return -EINVAL ; + }else { + skb->protocol = proto; + } +return tp_len; }
@@ -1113,7 +1120,13 @@ static int packet_snd(struct socket *sock,if (err) goto out_free; - skb->protocol = proto; +if (proto ==htons (ETH_P_ALL ) && dev->header_ops->get_protocol) { + skb->protocol = dev->header_ops->get_protocol (dev, skb); +if (unlikely (skb->protocol ==htons (ETH_P_ALL ))) +return -EINVAL ; + }else { + skb->protocol = proto; + } skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark;
Signature · 1 line
MST
Quoted 20 lines · Michael S. Tsirkin
Quoted 6 lines · David Miller
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 16:13:29 -0600Quoted 2 lines
If
SOCK_RAWpackets are being sent, the protocol number is embedded in the packet dataQuoted 7 lines
Where exactly is that protocol value? Not every link level protocol is ethernet.
We support FDDI, HIPPI, wireless, VLAN, PPP, and a host of others.
So you can't know for sure unless you assume ethernet, which you can't do.
You are right. This is TX though so the socket is bound to a specific device, and devices know which link protocol they use. So we could add a
get_protocoloperation to each device type, and call it if the protocol passed isETH_P_ALLto get the real one.
Quoted 6 lines
Like this: except I only added this for ethernet, and I would have to add this for the rest of device types. But I would like to hear what others think about this before I do the rest of the work for the rest of device types.
Does the below look sane?
I mean, besides the missing semicolons etc :)
Also, maybe it's a good idea to add a socket option that would trigger this behaviour, just to make sure existing behavior stays unchanged even if it's broken?
Quoted 87 lines
include/linux/netdevice.h +1
-0@@ -319,6 +319,7 @@ struct header_ops {void (*cache_update)(struct hh_cache *hh,const struct net_device *dev,const unsigned char *haddr); + __be16 (*get_protocol)(struct sk_buff *skb, struct net_device *dev) };/* These flag bits are private to the generic network queueing net/ethernet/eth.c +12
-0@@ -231,6 +231,17 @@ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)EXPORT_SYMBOL (eth_header_parse);/** +* eth_get_protocol - extract protocol value from packet +* @skb: packet to extract protocol from +* @dev: source device +*/ +__be16 eth_get_protocol (const struct sk_buff *skb,struct net_device *dev) +{ +const struct ethhdr *eth =eth_hdr (skb); + return eth->h_proto +} + +/** * eth_header_cache - fill cache entry from neighbour * @neigh: source neighbour * @hh: destination cache entry @@ -324,6 +335,7 @@ EXPORT_SYMBOL(eth_validate_addr);const struct header_ops eth_header_ops____cacheline_aligned = { .create = eth_header, .parse = eth_header_parse, + .get_protocol = eth_get_protocol, .rebuild = eth_rebuild_header, .cache = eth_header_cache, .cache_update = eth_header_cache_update,net/packet/af_packet.c +15
-2@@ -845,7 +845,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ph.raw = frame; - skb->protocol = proto; skb->dev = dev; skb->priority = po->sk.sk_priority; skb->mark = po->sk.sk_mark;@@ -924,6 +923,14 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, len = ((to_write > len_max) ? len_max : to_write); } +if (proto ==htons (ETH_P_ALL ) && dev->header_ops->get_protocol) { + skb->protocol = dev->header_ops->get_protocol (dev, skb); +if (unlikely (skb->protocol ==htons (ETH_P_ALL ))) +return -EINVAL ; + }else { + skb->protocol = proto; + } +return tp_len; }@@ -1113,7 +1120,13 @@ static int packet_snd(struct socket *sock,if (err) goto out_free; - skb->protocol = proto; +if (proto ==htons (ETH_P_ALL ) && dev->header_ops->get_protocol) { + skb->protocol = dev->header_ops->get_protocol (dev, skb); +if (unlikely (skb->protocol ==htons (ETH_P_ALL ))) +return -EINVAL ; + }else { + skb->protocol = proto; + } skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark;Signature · 2 lines
-- MST
2010/1/6 Michael S. Tsirkin <[email protected]>:
Quoted 22 lines · David Miller
Quoted 9 lines
From: "Chris Friesen" <[email protected]>
Date: Tue, 05 Jan 2010 16:13:29 -0600Quoted 2 lines
If
SOCK_RAWpackets are being sent, the protocol number is embedded in the packet dataWhere exactly is that protocol value? Not every link level protocol is ethernet.
We support FDDI, HIPPI, wireless, VLAN, PPP, and a host of others. So you can't know for sure unless you assume ethernet, which you can't do.You are right. This is TX though so the socket is bound to a specific device, and devices know which link protocol they use. So we could add a
get_protocoloperation to each device type, and call it if the protocol passed isETH_P_ALLto get the real one.Like this: except I only added this for ethernet, and I would have to add this for the rest of device types. But I would like to hear what others think about this before I do the rest of the work for the rest of device types.
Does the below look sane?
[...]
Quoted 7 lines
net/ethernet/eth.c +0
-0@@ -231,6 +231,17 @@ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) EXPORT_SYMBOL(eth_header_parse);
net/ethernet/eth.c int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) · line 242
Quoted 10 lines
net/ethernet/eth.c +9
-0/** +* eth_get_protocol - extract protocol value from packet +* @skb: packet to extract protocol from +* @dev: source device +*/ +__be16 eth_get_protocol (const struct sk_buff *skb,struct net_device *dev) +{ + const struct ethhdr *eth = eth_hdr(skb); + return eth->h_proto +}
[...]
You might want taking fragment of eth_type_trans() for this function so that 802.2/IPX would be detected too.
Best Regards,
Michał Mirosław