diff options
| -rw-r--r-- | Documentation/networking/packet_mmap.txt | 26 | ||||
| -rw-r--r-- | include/linux/if_packet.h | 1 | ||||
| -rw-r--r-- | net/packet/af_packet.c | 37 |
3 files changed, 62 insertions, 2 deletions
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 98f71a5cef00..2546aa4dc232 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 | |||
| 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 | + THANKS | 523 | + THANKS |
| 498 | -------------------------------------------------------------------------------- | 524 | -------------------------------------------------------------------------------- |
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index 6ac23ef1801a..72bfa5a034dd 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 | ||
| 52 | struct tpacket_stats { | 53 | struct 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 2078a277e06b..9a17f28b1253 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 | } |
