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 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 | |||
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 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 | ||
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 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 | } |