aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott McMillan <scott.a.mcmillan@intel.com>2010-06-02 08:53:56 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-02 08:53:56 -0400
commit614f60fa9d73a9e8fdff3df83381907fea7c5649 (patch)
treea1b7704393b7042242470db09d59944bca67ec51
parent7dad171c39dc83bd267c4f98d8b02d38e0d65596 (diff)
packet_mmap: expose hw packet timestamps to network packet capture utilities
This patch adds a setting, PACKET_TIMESTAMP, to specify the packet timestamp source that is exported to capture utilities like tcpdump by packet_mmap. PACKET_TIMESTAMP accepts the same integer bit field as SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE and SOF_TIMESTAMPING_RAW_HARDWARE values are currently recognized by PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set. If PACKET_TIMESTAMP is not set, a software timestamp generated inside the networking stack is used (the behavior before this setting was added). Signed-off-by: Scott McMillan <scott.a.mcmillan@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/packet_mmap.txt26
-rw-r--r--include/linux/if_packet.h1
-rw-r--r--net/packet/af_packet.c37
3 files changed, 62 insertions, 2 deletions
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 98f71a5cef0..2546aa4dc23 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -493,6 +493,32 @@ The user can also use poll() to check if a buffer is available:
493 pfd.events = POLLOUT; 493 pfd.events = POLLOUT;
494 retval = poll(&pfd, 1, timeout); 494 retval = poll(&pfd, 1, timeout);
495 495
496-------------------------------------------------------------------------------
497+ PACKET_TIMESTAMP
498-------------------------------------------------------------------------------
499
500The PACKET_TIMESTAMP setting determines the source of the timestamp in
501the packet meta information. If your NIC is capable of timestamping
502packets in hardware, you can request those hardware timestamps to used.
503Note: you may need to enable the generation of hardware timestamps with
504SIOCSHWTSTAMP.
505
506PACKET_TIMESTAMP accepts the same integer bit field as
507SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE
508and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by
509PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over
510SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
511
512 int req = 0;
513 req |= SOF_TIMESTAMPING_SYS_HARDWARE;
514 setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
515
516If PACKET_TIMESTAMP is not set, a software timestamp generated inside
517the networking stack is used (the behavior before this setting was added).
518
519See include/linux/net_tstamp.h and Documentation/networking/timestamping
520for more information on hardware timestamps.
521
496-------------------------------------------------------------------------------- 522--------------------------------------------------------------------------------
497+ THANKS 523+ THANKS
498-------------------------------------------------------------------------------- 524--------------------------------------------------------------------------------
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 6ac23ef1801..72bfa5a034d 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -48,6 +48,7 @@ struct sockaddr_ll {
48#define PACKET_LOSS 14 48#define PACKET_LOSS 14
49#define PACKET_VNET_HDR 15 49#define PACKET_VNET_HDR 15
50#define PACKET_TX_TIMESTAMP 16 50#define PACKET_TX_TIMESTAMP 16
51#define PACKET_TIMESTAMP 17
51 52
52struct tpacket_stats { 53struct tpacket_stats {
53 unsigned int tp_packets; 54 unsigned int tp_packets;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2078a277e06..9a17f28b125 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -83,6 +83,7 @@
83#include <linux/if_vlan.h> 83#include <linux/if_vlan.h>
84#include <linux/virtio_net.h> 84#include <linux/virtio_net.h>
85#include <linux/errqueue.h> 85#include <linux/errqueue.h>
86#include <linux/net_tstamp.h>
86 87
87#ifdef CONFIG_INET 88#ifdef CONFIG_INET
88#include <net/inet_common.h> 89#include <net/inet_common.h>
@@ -202,6 +203,7 @@ struct packet_sock {
202 unsigned int tp_hdrlen; 203 unsigned int tp_hdrlen;
203 unsigned int tp_reserve; 204 unsigned int tp_reserve;
204 unsigned int tp_loss:1; 205 unsigned int tp_loss:1;
206 unsigned int tp_tstamp;
205 struct packet_type prot_hook ____cacheline_aligned_in_smp; 207 struct packet_type prot_hook ____cacheline_aligned_in_smp;
206}; 208};
207 209
@@ -656,6 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
656 struct sk_buff *copy_skb = NULL; 658 struct sk_buff *copy_skb = NULL;
657 struct timeval tv; 659 struct timeval tv;
658 struct timespec ts; 660 struct timespec ts;
661 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
659 662
660 if (skb->pkt_type == PACKET_LOOPBACK) 663 if (skb->pkt_type == PACKET_LOOPBACK)
661 goto drop; 664 goto drop;
@@ -737,7 +740,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
737 h.h1->tp_snaplen = snaplen; 740 h.h1->tp_snaplen = snaplen;
738 h.h1->tp_mac = macoff; 741 h.h1->tp_mac = macoff;
739 h.h1->tp_net = netoff; 742 h.h1->tp_net = netoff;
740 if (skb->tstamp.tv64) 743 if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
744 && shhwtstamps->syststamp.tv64)
745 tv = ktime_to_timeval(shhwtstamps->syststamp);
746 else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
747 && shhwtstamps->hwtstamp.tv64)
748 tv = ktime_to_timeval(shhwtstamps->hwtstamp);
749 else if (skb->tstamp.tv64)
741 tv = ktime_to_timeval(skb->tstamp); 750 tv = ktime_to_timeval(skb->tstamp);
742 else 751 else
743 do_gettimeofday(&tv); 752 do_gettimeofday(&tv);
@@ -750,7 +759,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
750 h.h2->tp_snaplen = snaplen; 759 h.h2->tp_snaplen = snaplen;
751 h.h2->tp_mac = macoff; 760 h.h2->tp_mac = macoff;
752 h.h2->tp_net = netoff; 761 h.h2->tp_net = netoff;
753 if (skb->tstamp.tv64) 762 if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
763 && shhwtstamps->syststamp.tv64)
764 ts = ktime_to_timespec(shhwtstamps->syststamp);
765 else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
766 && shhwtstamps->hwtstamp.tv64)
767 ts = ktime_to_timespec(shhwtstamps->hwtstamp);
768 else if (skb->tstamp.tv64)
754 ts = ktime_to_timespec(skb->tstamp); 769 ts = ktime_to_timespec(skb->tstamp);
755 else 770 else
756 getnstimeofday(&ts); 771 getnstimeofday(&ts);
@@ -2027,6 +2042,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
2027 po->has_vnet_hdr = !!val; 2042 po->has_vnet_hdr = !!val;
2028 return 0; 2043 return 0;
2029 } 2044 }
2045 case PACKET_TIMESTAMP:
2046 {
2047 int val;
2048
2049 if (optlen != sizeof(val))
2050 return -EINVAL;
2051 if (copy_from_user(&val, optval, sizeof(val)))
2052 return -EFAULT;
2053
2054 po->tp_tstamp = val;
2055 return 0;
2056 }
2030 default: 2057 default:
2031 return -ENOPROTOOPT; 2058 return -ENOPROTOOPT;
2032 } 2059 }
@@ -2119,6 +2146,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
2119 val = po->tp_loss; 2146 val = po->tp_loss;
2120 data = &val; 2147 data = &val;
2121 break; 2148 break;
2149 case PACKET_TIMESTAMP:
2150 if (len > sizeof(int))
2151 len = sizeof(int);
2152 val = po->tp_tstamp;
2153 data = &val;
2154 break;
2122 default: 2155 default:
2123 return -ENOPROTOOPT; 2156 return -ENOPROTOOPT;
2124 } 2157 }