diff options
author | Willem de Bruijn <willemb@google.com> | 2013-04-22 20:39:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-25 01:22:22 -0400 |
commit | 2e31396fa14be50a98c5d2b00416ebd74d381c1f (patch) | |
tree | e01cf0a24659116265e189a68331bd74ebb48d42 /net/packet | |
parent | 92dea7c06656f709a3957aacef20574ce3dbe6fc (diff) |
packet: tx timestamping on tpacket ring
When transmit timestamping is enabled at the socket level, record a
timestamp on packets written to a PACKET_TX_RING. Tx timestamps are
always looped to the application over the socket error queue. Software
timestamps are also written back into the packet frame header in the
packet ring.
Reported-by: Paul Chavent <paul.chavent@onera.fr>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7e387ff64465..ec8ea27733ac 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -339,6 +339,37 @@ static int __packet_get_status(struct packet_sock *po, void *frame) | |||
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | static void __packet_set_timestamp(struct packet_sock *po, void *frame, | ||
343 | ktime_t tstamp) | ||
344 | { | ||
345 | union tpacket_uhdr h; | ||
346 | struct timespec ts; | ||
347 | |||
348 | if (!ktime_to_timespec_cond(tstamp, &ts) || | ||
349 | !sock_flag(&po->sk, SOCK_TIMESTAMPING_SOFTWARE)) | ||
350 | return; | ||
351 | |||
352 | h.raw = frame; | ||
353 | switch (po->tp_version) { | ||
354 | case TPACKET_V1: | ||
355 | h.h1->tp_sec = ts.tv_sec; | ||
356 | h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
357 | break; | ||
358 | case TPACKET_V2: | ||
359 | h.h2->tp_sec = ts.tv_sec; | ||
360 | h.h2->tp_nsec = ts.tv_nsec; | ||
361 | break; | ||
362 | case TPACKET_V3: | ||
363 | default: | ||
364 | WARN(1, "TPACKET version not supported.\n"); | ||
365 | BUG(); | ||
366 | } | ||
367 | |||
368 | /* one flush is safe, as both fields always lie on the same cacheline */ | ||
369 | flush_dcache_page(pgv_to_page(&h.h1->tp_sec)); | ||
370 | smp_wmb(); | ||
371 | } | ||
372 | |||
342 | static void *packet_lookup_frame(struct packet_sock *po, | 373 | static void *packet_lookup_frame(struct packet_sock *po, |
343 | struct packet_ring_buffer *rb, | 374 | struct packet_ring_buffer *rb, |
344 | unsigned int position, | 375 | unsigned int position, |
@@ -1877,6 +1908,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb) | |||
1877 | ph = skb_shinfo(skb)->destructor_arg; | 1908 | ph = skb_shinfo(skb)->destructor_arg; |
1878 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); | 1909 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); |
1879 | atomic_dec(&po->tx_ring.pending); | 1910 | atomic_dec(&po->tx_ring.pending); |
1911 | __packet_set_timestamp(po, ph, skb->tstamp); | ||
1880 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE); | 1912 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE); |
1881 | } | 1913 | } |
1882 | 1914 | ||
@@ -1900,6 +1932,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
1900 | skb->dev = dev; | 1932 | skb->dev = dev; |
1901 | skb->priority = po->sk.sk_priority; | 1933 | skb->priority = po->sk.sk_priority; |
1902 | skb->mark = po->sk.sk_mark; | 1934 | skb->mark = po->sk.sk_mark; |
1935 | sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags); | ||
1903 | skb_shinfo(skb)->destructor_arg = ph.raw; | 1936 | skb_shinfo(skb)->destructor_arg = ph.raw; |
1904 | 1937 | ||
1905 | switch (po->tp_version) { | 1938 | switch (po->tp_version) { |