aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2013-04-22 20:39:31 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-25 01:22:22 -0400
commitb9c32fb2717094231b31a7d7dcf5fd7f3638ac2f (patch)
tree3a50419c26357a99c8af55000ebd1b7fd2bf83f0
parent7276d5d743d775388bf382cd7bdea1a14e486d32 (diff)
packet: if hw/sw ts enabled in rx/tx ring, report which ts we got
Currently, there is no way to find out which timestamp is reported in tpacket{,2,3}_hdr's tp_sec, tp_{n,u}sec members. It can be one of SOF_TIMESTAMPING_SYS_HARDWARE, SOF_TIMESTAMPING_RAW_HARDWARE, SOF_TIMESTAMPING_SOFTWARE, or a fallback variant late call from the PF_PACKET code in software. Therefore, report in the tp_status member of the ring buffer which timestamp has been reported for RX and TX path. This should not break anything for the following reasons: i) in RX ring path, the user needs to test for tp_status & TP_STATUS_USER, and later for other flags as well such as TP_STATUS_VLAN_VALID et al, so adding other flags will do no harm; ii) in TX ring path, time stamps with PACKET_TIMESTAMP socketoption are not available resp. had no effect except that the application setting this is buggy. Next to TP_STATUS_AVAILABLE, the user also should check for other flags such as TP_STATUS_WRONG_FORMAT to reclaim frames to the application. Thus, in case TX ts are turned off (default case), nothing happens to the application logic, and in case we want to use this new feature, we now can also check which of the ts source is reported in the status field as provided in the docs. Reported-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_packet.h5
-rw-r--r--net/packet/af_packet.c36
2 files changed, 28 insertions, 13 deletions
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
index 4dfc234d80e5..b950c02030c0 100644
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -100,6 +100,11 @@ struct tpacket_auxdata {
100#define TP_STATUS_SENDING (1 << 1) 100#define TP_STATUS_SENDING (1 << 1)
101#define TP_STATUS_WRONG_FORMAT (1 << 2) 101#define TP_STATUS_WRONG_FORMAT (1 << 2)
102 102
103/* Rx and Tx ring - header status */
104#define TP_STATUS_TS_SOFTWARE (1 << 29)
105#define TP_STATUS_TS_SYS_HARDWARE (1 << 30)
106#define TP_STATUS_TS_RAW_HARDWARE (1 << 31)
107
103/* Rx ring - feature request bits */ 108/* Rx ring - feature request bits */
104#define TP_FT_REQ_FILL_RXHASH 0x1 109#define TP_FT_REQ_FILL_RXHASH 0x1
105 110
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9d46a07a15c0..ba8309a3e01b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -339,34 +339,35 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
339 } 339 }
340} 340}
341 341
342static bool tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts, 342static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
343 unsigned int flags) 343 unsigned int flags)
344{ 344{
345 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); 345 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
346 346
347 if (shhwtstamps) { 347 if (shhwtstamps) {
348 if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) && 348 if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
349 ktime_to_timespec_cond(shhwtstamps->syststamp, ts)) 349 ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
350 return true; 350 return TP_STATUS_TS_SYS_HARDWARE;
351 if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) && 351 if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
352 ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) 352 ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
353 return true; 353 return TP_STATUS_TS_RAW_HARDWARE;
354 } 354 }
355 355
356 if (ktime_to_timespec_cond(skb->tstamp, ts)) 356 if (ktime_to_timespec_cond(skb->tstamp, ts))
357 return true; 357 return TP_STATUS_TS_SOFTWARE;
358 358
359 return false; 359 return 0;
360} 360}
361 361
362static void __packet_set_timestamp(struct packet_sock *po, void *frame, 362static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
363 struct sk_buff *skb) 363 struct sk_buff *skb)
364{ 364{
365 union tpacket_uhdr h; 365 union tpacket_uhdr h;
366 struct timespec ts; 366 struct timespec ts;
367 __u32 ts_status;
367 368
368 if (!tpacket_get_timestamp(skb, &ts, po->tp_tstamp)) 369 if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
369 return; 370 return 0;
370 371
371 h.raw = frame; 372 h.raw = frame;
372 switch (po->tp_version) { 373 switch (po->tp_version) {
@@ -387,6 +388,8 @@ static void __packet_set_timestamp(struct packet_sock *po, void *frame,
387 /* one flush is safe, as both fields always lie on the same cacheline */ 388 /* one flush is safe, as both fields always lie on the same cacheline */
388 flush_dcache_page(pgv_to_page(&h.h1->tp_sec)); 389 flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
389 smp_wmb(); 390 smp_wmb();
391
392 return ts_status;
390} 393}
391 394
392static void *packet_lookup_frame(struct packet_sock *po, 395static void *packet_lookup_frame(struct packet_sock *po,
@@ -1721,6 +1724,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
1721 unsigned short macoff, netoff, hdrlen; 1724 unsigned short macoff, netoff, hdrlen;
1722 struct sk_buff *copy_skb = NULL; 1725 struct sk_buff *copy_skb = NULL;
1723 struct timespec ts; 1726 struct timespec ts;
1727 __u32 ts_status;
1724 1728
1725 if (skb->pkt_type == PACKET_LOOPBACK) 1729 if (skb->pkt_type == PACKET_LOOPBACK)
1726 goto drop; 1730 goto drop;
@@ -1803,9 +1807,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
1803 spin_unlock(&sk->sk_receive_queue.lock); 1807 spin_unlock(&sk->sk_receive_queue.lock);
1804 1808
1805 skb_copy_bits(skb, 0, h.raw + macoff, snaplen); 1809 skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
1806 if (!tpacket_get_timestamp(skb, &ts, po->tp_tstamp)) 1810
1811 if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
1807 getnstimeofday(&ts); 1812 getnstimeofday(&ts);
1808 1813
1814 status |= ts_status;
1815
1809 switch (po->tp_version) { 1816 switch (po->tp_version) {
1810 case TPACKET_V1: 1817 case TPACKET_V1:
1811 h.h1->tp_len = skb->len; 1818 h.h1->tp_len = skb->len;
@@ -1905,11 +1912,14 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
1905 void *ph; 1912 void *ph;
1906 1913
1907 if (likely(po->tx_ring.pg_vec)) { 1914 if (likely(po->tx_ring.pg_vec)) {
1915 __u32 ts;
1916
1908 ph = skb_shinfo(skb)->destructor_arg; 1917 ph = skb_shinfo(skb)->destructor_arg;
1909 BUG_ON(atomic_read(&po->tx_ring.pending) == 0); 1918 BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
1910 atomic_dec(&po->tx_ring.pending); 1919 atomic_dec(&po->tx_ring.pending);
1911 __packet_set_timestamp(po, ph, skb); 1920
1912 __packet_set_status(po, ph, TP_STATUS_AVAILABLE); 1921 ts = __packet_set_timestamp(po, ph, skb);
1922 __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts);
1913 } 1923 }
1914 1924
1915 sock_wfree(skb); 1925 sock_wfree(skb);