diff options
author | Soheil Hassas Yeganeh <soheil@google.com> | 2016-04-02 23:08:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-04 15:50:30 -0400 |
commit | c14ac9451c34832554db33386a4393be8bba3a7b (patch) | |
tree | 99f4d7c46d01732fcbfdf8de89e1d9846d56c3b3 /net/packet | |
parent | ad1e46a837163a3e7160a1250825bcfafd2e714b (diff) |
sock: enable timestamping using control messages
Currently, SOL_TIMESTAMPING can only be enabled using setsockopt.
This is very costly when users want to sample writes to gather
tx timestamps.
Add support for enabling SO_TIMESTAMPING via control messages by
using tsflags added in `struct sockcm_cookie` (added in the previous
patches in this series) to set the tx_flags of the last skb created in
a sendmsg. With this patch, the timestamp recording bits in tx_flags
of the skbuff is overridden if SO_TIMESTAMPING is passed in a cmsg.
Please note that this is only effective for overriding the recording
timestamps flags. Users should enable timestamp reporting (e.g.,
SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_OPT_ID) using
socket options and then should ask for SOF_TIMESTAMPING_TX_*
using control messages per sendmsg to sample timestamps for each
write.
Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 1ecfa710ca98..0007e23202e4 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1837,6 +1837,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, | |||
1837 | DECLARE_SOCKADDR(struct sockaddr_pkt *, saddr, msg->msg_name); | 1837 | DECLARE_SOCKADDR(struct sockaddr_pkt *, saddr, msg->msg_name); |
1838 | struct sk_buff *skb = NULL; | 1838 | struct sk_buff *skb = NULL; |
1839 | struct net_device *dev; | 1839 | struct net_device *dev; |
1840 | struct sockcm_cookie sockc; | ||
1840 | __be16 proto = 0; | 1841 | __be16 proto = 0; |
1841 | int err; | 1842 | int err; |
1842 | int extra_len = 0; | 1843 | int extra_len = 0; |
@@ -1925,12 +1926,21 @@ retry: | |||
1925 | goto out_unlock; | 1926 | goto out_unlock; |
1926 | } | 1927 | } |
1927 | 1928 | ||
1929 | sockc.tsflags = 0; | ||
1930 | if (msg->msg_controllen) { | ||
1931 | err = sock_cmsg_send(sk, msg, &sockc); | ||
1932 | if (unlikely(err)) { | ||
1933 | err = -EINVAL; | ||
1934 | goto out_unlock; | ||
1935 | } | ||
1936 | } | ||
1937 | |||
1928 | skb->protocol = proto; | 1938 | skb->protocol = proto; |
1929 | skb->dev = dev; | 1939 | skb->dev = dev; |
1930 | skb->priority = sk->sk_priority; | 1940 | skb->priority = sk->sk_priority; |
1931 | skb->mark = sk->sk_mark; | 1941 | skb->mark = sk->sk_mark; |
1932 | 1942 | ||
1933 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); | 1943 | sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags); |
1934 | 1944 | ||
1935 | if (unlikely(extra_len == 4)) | 1945 | if (unlikely(extra_len == 4)) |
1936 | skb->no_fcs = 1; | 1946 | skb->no_fcs = 1; |
@@ -2486,7 +2496,8 @@ static int packet_snd_vnet_gso(struct sk_buff *skb, | |||
2486 | 2496 | ||
2487 | static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | 2497 | static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, |
2488 | void *frame, struct net_device *dev, void *data, int tp_len, | 2498 | void *frame, struct net_device *dev, void *data, int tp_len, |
2489 | __be16 proto, unsigned char *addr, int hlen, int copylen) | 2499 | __be16 proto, unsigned char *addr, int hlen, int copylen, |
2500 | const struct sockcm_cookie *sockc) | ||
2490 | { | 2501 | { |
2491 | union tpacket_uhdr ph; | 2502 | union tpacket_uhdr ph; |
2492 | int to_write, offset, len, nr_frags, len_max; | 2503 | int to_write, offset, len, nr_frags, len_max; |
@@ -2500,7 +2511,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
2500 | skb->dev = dev; | 2511 | skb->dev = dev; |
2501 | skb->priority = po->sk.sk_priority; | 2512 | skb->priority = po->sk.sk_priority; |
2502 | skb->mark = po->sk.sk_mark; | 2513 | skb->mark = po->sk.sk_mark; |
2503 | sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags); | 2514 | sock_tx_timestamp(&po->sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags); |
2504 | skb_shinfo(skb)->destructor_arg = ph.raw; | 2515 | skb_shinfo(skb)->destructor_arg = ph.raw; |
2505 | 2516 | ||
2506 | skb_reserve(skb, hlen); | 2517 | skb_reserve(skb, hlen); |
@@ -2624,6 +2635,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2624 | struct sk_buff *skb; | 2635 | struct sk_buff *skb; |
2625 | struct net_device *dev; | 2636 | struct net_device *dev; |
2626 | struct virtio_net_hdr *vnet_hdr = NULL; | 2637 | struct virtio_net_hdr *vnet_hdr = NULL; |
2638 | struct sockcm_cookie sockc; | ||
2627 | __be16 proto; | 2639 | __be16 proto; |
2628 | int err, reserve = 0; | 2640 | int err, reserve = 0; |
2629 | void *ph; | 2641 | void *ph; |
@@ -2655,6 +2667,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2655 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); | 2667 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); |
2656 | } | 2668 | } |
2657 | 2669 | ||
2670 | sockc.tsflags = 0; | ||
2671 | if (msg->msg_controllen) { | ||
2672 | err = sock_cmsg_send(&po->sk, msg, &sockc); | ||
2673 | if (unlikely(err)) | ||
2674 | goto out; | ||
2675 | } | ||
2676 | |||
2658 | err = -ENXIO; | 2677 | err = -ENXIO; |
2659 | if (unlikely(dev == NULL)) | 2678 | if (unlikely(dev == NULL)) |
2660 | goto out; | 2679 | goto out; |
@@ -2712,7 +2731,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2712 | goto out_status; | 2731 | goto out_status; |
2713 | } | 2732 | } |
2714 | tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto, | 2733 | tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto, |
2715 | addr, hlen, copylen); | 2734 | addr, hlen, copylen, &sockc); |
2716 | if (likely(tp_len >= 0) && | 2735 | if (likely(tp_len >= 0) && |
2717 | tp_len > dev->mtu + reserve && | 2736 | tp_len > dev->mtu + reserve && |
2718 | !po->has_vnet_hdr && | 2737 | !po->has_vnet_hdr && |
@@ -2851,6 +2870,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
2851 | if (unlikely(!(dev->flags & IFF_UP))) | 2870 | if (unlikely(!(dev->flags & IFF_UP))) |
2852 | goto out_unlock; | 2871 | goto out_unlock; |
2853 | 2872 | ||
2873 | sockc.tsflags = 0; | ||
2854 | sockc.mark = sk->sk_mark; | 2874 | sockc.mark = sk->sk_mark; |
2855 | if (msg->msg_controllen) { | 2875 | if (msg->msg_controllen) { |
2856 | err = sock_cmsg_send(sk, msg, &sockc); | 2876 | err = sock_cmsg_send(sk, msg, &sockc); |
@@ -2908,7 +2928,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
2908 | goto out_free; | 2928 | goto out_free; |
2909 | } | 2929 | } |
2910 | 2930 | ||
2911 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); | 2931 | sock_tx_timestamp(sk, sockc.tsflags, &skb_shinfo(skb)->tx_flags); |
2912 | 2932 | ||
2913 | if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) && | 2933 | if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) && |
2914 | !packet_extra_vlan_len_allowed(dev, skb)) { | 2934 | !packet_extra_vlan_len_allowed(dev, skb)) { |