Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Scott McMillan and committed by
David S. Miller
614f60fa 7dad171c

+62 -2
+26
Documentation/networking/packet_mmap.txt
··· 493 493 pfd.events = POLLOUT; 494 494 retval = poll(&pfd, 1, timeout); 495 495 496 + ------------------------------------------------------------------------------- 497 + + PACKET_TIMESTAMP 498 + ------------------------------------------------------------------------------- 499 + 500 + The PACKET_TIMESTAMP setting determines the source of the timestamp in 501 + the packet meta information. If your NIC is capable of timestamping 502 + packets in hardware, you can request those hardware timestamps to used. 503 + Note: you may need to enable the generation of hardware timestamps with 504 + SIOCSHWTSTAMP. 505 + 506 + PACKET_TIMESTAMP accepts the same integer bit field as 507 + SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE 508 + and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by 509 + PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over 510 + SOF_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 + 516 + If PACKET_TIMESTAMP is not set, a software timestamp generated inside 517 + the networking stack is used (the behavior before this setting was added). 518 + 519 + See include/linux/net_tstamp.h and Documentation/networking/timestamping 520 + for more information on hardware timestamps. 521 + 496 522 -------------------------------------------------------------------------------- 497 523 + THANKS 498 524 --------------------------------------------------------------------------------
+1
include/linux/if_packet.h
··· 48 48 #define PACKET_LOSS 14 49 49 #define PACKET_VNET_HDR 15 50 50 #define PACKET_TX_TIMESTAMP 16 51 + #define PACKET_TIMESTAMP 17 51 52 52 53 struct tpacket_stats { 53 54 unsigned int tp_packets;
+35 -2
net/packet/af_packet.c
··· 83 83 #include <linux/if_vlan.h> 84 84 #include <linux/virtio_net.h> 85 85 #include <linux/errqueue.h> 86 + #include <linux/net_tstamp.h> 86 87 87 88 #ifdef CONFIG_INET 88 89 #include <net/inet_common.h> ··· 203 202 unsigned int tp_hdrlen; 204 203 unsigned int tp_reserve; 205 204 unsigned int tp_loss:1; 205 + unsigned int tp_tstamp; 206 206 struct packet_type prot_hook ____cacheline_aligned_in_smp; 207 207 }; 208 208 ··· 658 656 struct sk_buff *copy_skb = NULL; 659 657 struct timeval tv; 660 658 struct timespec ts; 659 + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); 661 660 662 661 if (skb->pkt_type == PACKET_LOOPBACK) 663 662 goto drop; ··· 740 737 h.h1->tp_snaplen = snaplen; 741 738 h.h1->tp_mac = macoff; 742 739 h.h1->tp_net = netoff; 743 - if (skb->tstamp.tv64) 740 + if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE) 741 + && shhwtstamps->syststamp.tv64) 742 + tv = ktime_to_timeval(shhwtstamps->syststamp); 743 + else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE) 744 + && shhwtstamps->hwtstamp.tv64) 745 + tv = ktime_to_timeval(shhwtstamps->hwtstamp); 746 + else if (skb->tstamp.tv64) 744 747 tv = ktime_to_timeval(skb->tstamp); 745 748 else 746 749 do_gettimeofday(&tv); ··· 759 750 h.h2->tp_snaplen = snaplen; 760 751 h.h2->tp_mac = macoff; 761 752 h.h2->tp_net = netoff; 762 - if (skb->tstamp.tv64) 753 + if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE) 754 + && shhwtstamps->syststamp.tv64) 755 + ts = ktime_to_timespec(shhwtstamps->syststamp); 756 + else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE) 757 + && shhwtstamps->hwtstamp.tv64) 758 + ts = ktime_to_timespec(shhwtstamps->hwtstamp); 759 + else if (skb->tstamp.tv64) 763 760 ts = ktime_to_timespec(skb->tstamp); 764 761 else 765 762 getnstimeofday(&ts); ··· 2042 2027 po->has_vnet_hdr = !!val; 2043 2028 return 0; 2044 2029 } 2030 + case PACKET_TIMESTAMP: 2031 + { 2032 + int val; 2033 + 2034 + if (optlen != sizeof(val)) 2035 + return -EINVAL; 2036 + if (copy_from_user(&val, optval, sizeof(val))) 2037 + return -EFAULT; 2038 + 2039 + po->tp_tstamp = val; 2040 + return 0; 2041 + } 2045 2042 default: 2046 2043 return -ENOPROTOOPT; 2047 2044 } ··· 2144 2117 if (len > sizeof(unsigned int)) 2145 2118 len = sizeof(unsigned int); 2146 2119 val = po->tp_loss; 2120 + data = &val; 2121 + break; 2122 + case PACKET_TIMESTAMP: 2123 + if (len > sizeof(int)) 2124 + len = sizeof(int); 2125 + val = po->tp_tstamp; 2147 2126 data = &val; 2148 2127 break; 2149 2128 default: