Commit b9c32fb2717094231b31a7d7dcf5fd7f3638ac2f

Authored by Daniel Borkmann
Committed by David S. Miller
1 parent 7276d5d743

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>

Showing 2 changed files with 28 additions and 13 deletions Side-by-side Diff

include/uapi/linux/if_packet.h
... ... @@ -100,6 +100,11 @@
100 100 #define TP_STATUS_SENDING (1 << 1)
101 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 108 /* Rx ring - feature request bits */
104 109 #define TP_FT_REQ_FILL_RXHASH 0x1
105 110  
net/packet/af_packet.c
... ... @@ -339,34 +339,35 @@
339 339 }
340 340 }
341 341  
342   -static bool tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
343   - unsigned int flags)
  342 +static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
  343 + unsigned int flags)
344 344 {
345 345 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
346 346  
347 347 if (shhwtstamps) {
348 348 if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
349 349 ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
350   - return true;
  350 + return TP_STATUS_TS_SYS_HARDWARE;
351 351 if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
352 352 ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
353   - return true;
  353 + return TP_STATUS_TS_RAW_HARDWARE;
354 354 }
355 355  
356 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  
362   -static void __packet_set_timestamp(struct packet_sock *po, void *frame,
363   - struct sk_buff *skb)
  362 +static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
  363 + struct sk_buff *skb)
364 364 {
365 365 union tpacket_uhdr h;
366 366 struct timespec ts;
  367 + __u32 ts_status;
367 368  
368   - if (!tpacket_get_timestamp(skb, &ts, po->tp_tstamp))
369   - return;
  369 + if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
  370 + return 0;
370 371  
371 372 h.raw = frame;
372 373 switch (po->tp_version) {
... ... @@ -387,6 +388,8 @@
387 388 /* one flush is safe, as both fields always lie on the same cacheline */
388 389 flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
389 390 smp_wmb();
  391 +
  392 + return ts_status;
390 393 }
391 394  
392 395 static void *packet_lookup_frame(struct packet_sock *po,
... ... @@ -1721,6 +1724,7 @@
1721 1724 unsigned short macoff, netoff, hdrlen;
1722 1725 struct sk_buff *copy_skb = NULL;
1723 1726 struct timespec ts;
  1727 + __u32 ts_status;
1724 1728  
1725 1729 if (skb->pkt_type == PACKET_LOOPBACK)
1726 1730 goto drop;
1727 1731  
... ... @@ -1803,9 +1807,12 @@
1803 1807 spin_unlock(&sk->sk_receive_queue.lock);
1804 1808  
1805 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 1812 getnstimeofday(&ts);
1808 1813  
  1814 + status |= ts_status;
  1815 +
1809 1816 switch (po->tp_version) {
1810 1817 case TPACKET_V1:
1811 1818 h.h1->tp_len = skb->len;
1812 1819  
... ... @@ -1905,11 +1912,14 @@
1905 1912 void *ph;
1906 1913  
1907 1914 if (likely(po->tx_ring.pg_vec)) {
  1915 + __u32 ts;
  1916 +
1908 1917 ph = skb_shinfo(skb)->destructor_arg;
1909 1918 BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
1910 1919 atomic_dec(&po->tx_ring.pending);
1911   - __packet_set_timestamp(po, ph, skb);
1912   - __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);
1913 1923 }
1914 1924  
1915 1925 sock_wfree(skb);