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>
This commit is contained in:
parent
7dad171c39
commit
614f60fa9d
|
@ -493,6 +493,32 @@ The user can also use poll() to check if a buffer is available:
|
||||||
pfd.events = POLLOUT;
|
pfd.events = POLLOUT;
|
||||||
retval = poll(&pfd, 1, timeout);
|
retval = poll(&pfd, 1, timeout);
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
+ PACKET_TIMESTAMP
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The PACKET_TIMESTAMP setting determines the source of the timestamp in
|
||||||
|
the packet meta information. If your NIC is capable of timestamping
|
||||||
|
packets in hardware, you can request those hardware timestamps to used.
|
||||||
|
Note: you may need to enable the generation of hardware timestamps with
|
||||||
|
SIOCSHWTSTAMP.
|
||||||
|
|
||||||
|
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 recognized by
|
||||||
|
PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over
|
||||||
|
SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
|
||||||
|
|
||||||
|
int req = 0;
|
||||||
|
req |= SOF_TIMESTAMPING_SYS_HARDWARE;
|
||||||
|
setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
|
||||||
|
|
||||||
|
If PACKET_TIMESTAMP is not set, a software timestamp generated inside
|
||||||
|
the networking stack is used (the behavior before this setting was added).
|
||||||
|
|
||||||
|
See include/linux/net_tstamp.h and Documentation/networking/timestamping
|
||||||
|
for more information on hardware timestamps.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
+ THANKS
|
+ THANKS
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct sockaddr_ll {
|
||||||
#define PACKET_LOSS 14
|
#define PACKET_LOSS 14
|
||||||
#define PACKET_VNET_HDR 15
|
#define PACKET_VNET_HDR 15
|
||||||
#define PACKET_TX_TIMESTAMP 16
|
#define PACKET_TX_TIMESTAMP 16
|
||||||
|
#define PACKET_TIMESTAMP 17
|
||||||
|
|
||||||
struct tpacket_stats {
|
struct tpacket_stats {
|
||||||
unsigned int tp_packets;
|
unsigned int tp_packets;
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/virtio_net.h>
|
#include <linux/virtio_net.h>
|
||||||
#include <linux/errqueue.h>
|
#include <linux/errqueue.h>
|
||||||
|
#include <linux/net_tstamp.h>
|
||||||
|
|
||||||
#ifdef CONFIG_INET
|
#ifdef CONFIG_INET
|
||||||
#include <net/inet_common.h>
|
#include <net/inet_common.h>
|
||||||
|
@ -202,6 +203,7 @@ struct packet_sock {
|
||||||
unsigned int tp_hdrlen;
|
unsigned int tp_hdrlen;
|
||||||
unsigned int tp_reserve;
|
unsigned int tp_reserve;
|
||||||
unsigned int tp_loss:1;
|
unsigned int tp_loss:1;
|
||||||
|
unsigned int tp_tstamp;
|
||||||
struct packet_type prot_hook ____cacheline_aligned_in_smp;
|
struct packet_type prot_hook ____cacheline_aligned_in_smp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -656,6 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
struct sk_buff *copy_skb = NULL;
|
struct sk_buff *copy_skb = NULL;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
|
||||||
|
|
||||||
if (skb->pkt_type == PACKET_LOOPBACK)
|
if (skb->pkt_type == PACKET_LOOPBACK)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
@ -737,7 +740,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
h.h1->tp_snaplen = snaplen;
|
h.h1->tp_snaplen = snaplen;
|
||||||
h.h1->tp_mac = macoff;
|
h.h1->tp_mac = macoff;
|
||||||
h.h1->tp_net = netoff;
|
h.h1->tp_net = netoff;
|
||||||
if (skb->tstamp.tv64)
|
if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
|
||||||
|
&& shhwtstamps->syststamp.tv64)
|
||||||
|
tv = ktime_to_timeval(shhwtstamps->syststamp);
|
||||||
|
else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
|
||||||
|
&& shhwtstamps->hwtstamp.tv64)
|
||||||
|
tv = ktime_to_timeval(shhwtstamps->hwtstamp);
|
||||||
|
else if (skb->tstamp.tv64)
|
||||||
tv = ktime_to_timeval(skb->tstamp);
|
tv = ktime_to_timeval(skb->tstamp);
|
||||||
else
|
else
|
||||||
do_gettimeofday(&tv);
|
do_gettimeofday(&tv);
|
||||||
|
@ -750,7 +759,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
h.h2->tp_snaplen = snaplen;
|
h.h2->tp_snaplen = snaplen;
|
||||||
h.h2->tp_mac = macoff;
|
h.h2->tp_mac = macoff;
|
||||||
h.h2->tp_net = netoff;
|
h.h2->tp_net = netoff;
|
||||||
if (skb->tstamp.tv64)
|
if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
|
||||||
|
&& shhwtstamps->syststamp.tv64)
|
||||||
|
ts = ktime_to_timespec(shhwtstamps->syststamp);
|
||||||
|
else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
|
||||||
|
&& shhwtstamps->hwtstamp.tv64)
|
||||||
|
ts = ktime_to_timespec(shhwtstamps->hwtstamp);
|
||||||
|
else if (skb->tstamp.tv64)
|
||||||
ts = ktime_to_timespec(skb->tstamp);
|
ts = ktime_to_timespec(skb->tstamp);
|
||||||
else
|
else
|
||||||
getnstimeofday(&ts);
|
getnstimeofday(&ts);
|
||||||
|
@ -2027,6 +2042,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
||||||
po->has_vnet_hdr = !!val;
|
po->has_vnet_hdr = !!val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case PACKET_TIMESTAMP:
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (optlen != sizeof(val))
|
||||||
|
return -EINVAL;
|
||||||
|
if (copy_from_user(&val, optval, sizeof(val)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
po->tp_tstamp = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
@ -2119,6 +2146,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
||||||
val = po->tp_loss;
|
val = po->tp_loss;
|
||||||
data = &val;
|
data = &val;
|
||||||
break;
|
break;
|
||||||
|
case PACKET_TIMESTAMP:
|
||||||
|
if (len > sizeof(int))
|
||||||
|
len = sizeof(int);
|
||||||
|
val = po->tp_tstamp;
|
||||||
|
data = &val;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue