diff options
author | David S. Miller <davem@davemloft.net> | 2013-04-25 01:22:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-25 01:22:53 -0400 |
commit | 660f7d22298ceb82facd2088c197f2de5cbfb7d6 (patch) | |
tree | 2413117b5a07e3632a392e4f03a76ebb37e9c157 /net/packet | |
parent | 92dea7c06656f709a3957aacef20574ce3dbe6fc (diff) | |
parent | 2940b26bec9fe5bf183c994678e62b55d35717e6 (diff) |
Merge branch 'af_packet-timestamp'
Daniel Borkmann says:
====================
This is a joint effort with Willem to bring optional i) tx hw/sw
timestamping into PF_PACKET, that was reported by Paul Chavent,
and ii) to expose the type of timestamp to the user, which is in
the current situation not possible to distinguish with the RX_RING
and TX_RING API (but distinguishable through the normal timestamping
API), reported by Richard Cochran. This set is based on top of
``packet: account statistics only in tpacket_stats_u''. Related
discussion can be found in: http://patchwork.ozlabs.org/patch/238125/
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 87 |
1 files changed, 65 insertions, 22 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7e387ff64465..ba8309a3e01b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -339,6 +339,59 @@ static int __packet_get_status(struct packet_sock *po, void *frame) | |||
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts, | ||
343 | unsigned int flags) | ||
344 | { | ||
345 | struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); | ||
346 | |||
347 | if (shhwtstamps) { | ||
348 | if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) && | ||
349 | ktime_to_timespec_cond(shhwtstamps->syststamp, ts)) | ||
350 | return TP_STATUS_TS_SYS_HARDWARE; | ||
351 | if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) && | ||
352 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) | ||
353 | return TP_STATUS_TS_RAW_HARDWARE; | ||
354 | } | ||
355 | |||
356 | if (ktime_to_timespec_cond(skb->tstamp, ts)) | ||
357 | return TP_STATUS_TS_SOFTWARE; | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame, | ||
363 | struct sk_buff *skb) | ||
364 | { | ||
365 | union tpacket_uhdr h; | ||
366 | struct timespec ts; | ||
367 | __u32 ts_status; | ||
368 | |||
369 | if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp))) | ||
370 | return 0; | ||
371 | |||
372 | h.raw = frame; | ||
373 | switch (po->tp_version) { | ||
374 | case TPACKET_V1: | ||
375 | h.h1->tp_sec = ts.tv_sec; | ||
376 | h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
377 | break; | ||
378 | case TPACKET_V2: | ||
379 | h.h2->tp_sec = ts.tv_sec; | ||
380 | h.h2->tp_nsec = ts.tv_nsec; | ||
381 | break; | ||
382 | case TPACKET_V3: | ||
383 | default: | ||
384 | WARN(1, "TPACKET version not supported.\n"); | ||
385 | BUG(); | ||
386 | } | ||
387 | |||
388 | /* one flush is safe, as both fields always lie on the same cacheline */ | ||
389 | flush_dcache_page(pgv_to_page(&h.h1->tp_sec)); | ||
390 | smp_wmb(); | ||
391 | |||
392 | return ts_status; | ||
393 | } | ||
394 | |||
342 | static void *packet_lookup_frame(struct packet_sock *po, | 395 | static void *packet_lookup_frame(struct packet_sock *po, |
343 | struct packet_ring_buffer *rb, | 396 | struct packet_ring_buffer *rb, |
344 | unsigned int position, | 397 | unsigned int position, |
@@ -1657,26 +1710,6 @@ drop: | |||
1657 | return 0; | 1710 | return 0; |
1658 | } | 1711 | } |
1659 | 1712 | ||
1660 | static void tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts, | ||
1661 | unsigned int flags) | ||
1662 | { | ||
1663 | struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); | ||
1664 | |||
1665 | if (shhwtstamps) { | ||
1666 | if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) && | ||
1667 | ktime_to_timespec_cond(shhwtstamps->syststamp, ts)) | ||
1668 | return; | ||
1669 | if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) && | ||
1670 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) | ||
1671 | return; | ||
1672 | } | ||
1673 | |||
1674 | if (ktime_to_timespec_cond(skb->tstamp, ts)) | ||
1675 | return; | ||
1676 | |||
1677 | getnstimeofday(ts); | ||
1678 | } | ||
1679 | |||
1680 | static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | 1713 | static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, |
1681 | struct packet_type *pt, struct net_device *orig_dev) | 1714 | struct packet_type *pt, struct net_device *orig_dev) |
1682 | { | 1715 | { |
@@ -1691,6 +1724,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1691 | unsigned short macoff, netoff, hdrlen; | 1724 | unsigned short macoff, netoff, hdrlen; |
1692 | struct sk_buff *copy_skb = NULL; | 1725 | struct sk_buff *copy_skb = NULL; |
1693 | struct timespec ts; | 1726 | struct timespec ts; |
1727 | __u32 ts_status; | ||
1694 | 1728 | ||
1695 | if (skb->pkt_type == PACKET_LOOPBACK) | 1729 | if (skb->pkt_type == PACKET_LOOPBACK) |
1696 | goto drop; | 1730 | goto drop; |
@@ -1773,7 +1807,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1773 | spin_unlock(&sk->sk_receive_queue.lock); | 1807 | spin_unlock(&sk->sk_receive_queue.lock); |
1774 | 1808 | ||
1775 | skb_copy_bits(skb, 0, h.raw + macoff, snaplen); | 1809 | skb_copy_bits(skb, 0, h.raw + macoff, snaplen); |
1776 | tpacket_get_timestamp(skb, &ts, po->tp_tstamp); | 1810 | |
1811 | if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp))) | ||
1812 | getnstimeofday(&ts); | ||
1813 | |||
1814 | status |= ts_status; | ||
1777 | 1815 | ||
1778 | switch (po->tp_version) { | 1816 | switch (po->tp_version) { |
1779 | case TPACKET_V1: | 1817 | case TPACKET_V1: |
@@ -1874,10 +1912,14 @@ static void tpacket_destruct_skb(struct sk_buff *skb) | |||
1874 | void *ph; | 1912 | void *ph; |
1875 | 1913 | ||
1876 | if (likely(po->tx_ring.pg_vec)) { | 1914 | if (likely(po->tx_ring.pg_vec)) { |
1915 | __u32 ts; | ||
1916 | |||
1877 | ph = skb_shinfo(skb)->destructor_arg; | 1917 | ph = skb_shinfo(skb)->destructor_arg; |
1878 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); | 1918 | BUG_ON(atomic_read(&po->tx_ring.pending) == 0); |
1879 | atomic_dec(&po->tx_ring.pending); | 1919 | atomic_dec(&po->tx_ring.pending); |
1880 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE); | 1920 | |
1921 | ts = __packet_set_timestamp(po, ph, skb); | ||
1922 | __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts); | ||
1881 | } | 1923 | } |
1882 | 1924 | ||
1883 | sock_wfree(skb); | 1925 | sock_wfree(skb); |
@@ -1900,6 +1942,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
1900 | skb->dev = dev; | 1942 | skb->dev = dev; |
1901 | skb->priority = po->sk.sk_priority; | 1943 | skb->priority = po->sk.sk_priority; |
1902 | skb->mark = po->sk.sk_mark; | 1944 | skb->mark = po->sk.sk_mark; |
1945 | sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags); | ||
1903 | skb_shinfo(skb)->destructor_arg = ph.raw; | 1946 | skb_shinfo(skb)->destructor_arg = ph.raw; |
1904 | 1947 | ||
1905 | switch (po->tp_version) { | 1948 | switch (po->tp_version) { |