summaryrefslogtreecommitdiff
path: root/net/packet
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-04-25 01:22:53 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-25 01:22:53 -0400
commit660f7d22298ceb82facd2088c197f2de5cbfb7d6 (patch)
tree2413117b5a07e3632a392e4f03a76ebb37e9c157 /net/packet
parent92dea7c06656f709a3957aacef20574ce3dbe6fc (diff)
parent2940b26bec9fe5bf183c994678e62b55d35717e6 (diff)
downloadlinux-next-660f7d22298ceb82facd2088c197f2de5cbfb7d6.tar.gz
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.c87
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)
}
}
+static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
+ unsigned int flags)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+
+ if (shhwtstamps) {
+ if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
+ ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
+ return TP_STATUS_TS_SYS_HARDWARE;
+ if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
+ ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+ return TP_STATUS_TS_RAW_HARDWARE;
+ }
+
+ if (ktime_to_timespec_cond(skb->tstamp, ts))
+ return TP_STATUS_TS_SOFTWARE;
+
+ return 0;
+}
+
+static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
+ struct sk_buff *skb)
+{
+ union tpacket_uhdr h;
+ struct timespec ts;
+ __u32 ts_status;
+
+ if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
+ return 0;
+
+ h.raw = frame;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ h.h1->tp_sec = ts.tv_sec;
+ h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC;
+ break;
+ case TPACKET_V2:
+ h.h2->tp_sec = ts.tv_sec;
+ h.h2->tp_nsec = ts.tv_nsec;
+ break;
+ case TPACKET_V3:
+ default:
+ WARN(1, "TPACKET version not supported.\n");
+ BUG();
+ }
+
+ /* one flush is safe, as both fields always lie on the same cacheline */
+ flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
+ smp_wmb();
+
+ return ts_status;
+}
+
static void *packet_lookup_frame(struct packet_sock *po,
struct packet_ring_buffer *rb,
unsigned int position,
@@ -1657,26 +1710,6 @@ drop:
return 0;
}
-static void tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
- unsigned int flags)
-{
- struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
-
- if (shhwtstamps) {
- if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
- ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
- return;
- if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
- ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
- return;
- }
-
- if (ktime_to_timespec_cond(skb->tstamp, ts))
- return;
-
- getnstimeofday(ts);
-}
-
static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
@@ -1691,6 +1724,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
unsigned short macoff, netoff, hdrlen;
struct sk_buff *copy_skb = NULL;
struct timespec ts;
+ __u32 ts_status;
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
@@ -1773,7 +1807,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
spin_unlock(&sk->sk_receive_queue.lock);
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
- tpacket_get_timestamp(skb, &ts, po->tp_tstamp);
+
+ if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
+ getnstimeofday(&ts);
+
+ status |= ts_status;
switch (po->tp_version) {
case TPACKET_V1:
@@ -1874,10 +1912,14 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
void *ph;
if (likely(po->tx_ring.pg_vec)) {
+ __u32 ts;
+
ph = skb_shinfo(skb)->destructor_arg;
BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
atomic_dec(&po->tx_ring.pending);
- __packet_set_status(po, ph, TP_STATUS_AVAILABLE);
+
+ ts = __packet_set_timestamp(po, ph, skb);
+ __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts);
}
sock_wfree(skb);
@@ -1900,6 +1942,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->dev = dev;
skb->priority = po->sk.sk_priority;
skb->mark = po->sk.sk_mark;
+ sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags);
skb_shinfo(skb)->destructor_arg = ph.raw;
switch (po->tp_version) {