|
@@ -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) {
|