packet: tx timestamping on tpacket ring
When transmit timestamping is enabled at the socket level, record a timestamp on packets written to a PACKET_TX_RING. Tx timestamps are always looped to the application over the socket error queue. Software timestamps are also written back into the packet frame header in the packet ring. Reported-by: Paul Chavent <paul.chavent@onera.fr> Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									92dea7c066
								
							
						
					
					
						commit
						2e31396fa1
					
				| @ -3327,12 +3327,8 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, | ||||
| 	if (!sk) | ||||
| 		return; | ||||
| 
 | ||||
| 	skb = skb_clone(orig_skb, GFP_ATOMIC); | ||||
| 	if (!skb) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (hwtstamps) { | ||||
| 		*skb_hwtstamps(skb) = | ||||
| 		*skb_hwtstamps(orig_skb) = | ||||
| 			*hwtstamps; | ||||
| 	} else { | ||||
| 		/*
 | ||||
| @ -3340,9 +3336,13 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, | ||||
| 		 * so keep the shared tx_flags and only | ||||
| 		 * store software time stamp | ||||
| 		 */ | ||||
| 		skb->tstamp = ktime_get_real(); | ||||
| 		orig_skb->tstamp = ktime_get_real(); | ||||
| 	} | ||||
| 
 | ||||
| 	skb = skb_clone(orig_skb, GFP_ATOMIC); | ||||
| 	if (!skb) | ||||
| 		return; | ||||
| 
 | ||||
| 	serr = SKB_EXT_ERR(skb); | ||||
| 	memset(serr, 0, sizeof(*serr)); | ||||
| 	serr->ee.ee_errno = ENOMSG; | ||||
|  | ||||
| @ -339,6 +339,37 @@ static int __packet_get_status(struct packet_sock *po, void *frame) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void __packet_set_timestamp(struct packet_sock *po, void *frame, | ||||
| 				   ktime_t tstamp) | ||||
| { | ||||
| 	union tpacket_uhdr h; | ||||
| 	struct timespec ts; | ||||
| 
 | ||||
| 	if (!ktime_to_timespec_cond(tstamp, &ts) || | ||||
| 	    !sock_flag(&po->sk, SOCK_TIMESTAMPING_SOFTWARE)) | ||||
| 		return; | ||||
| 
 | ||||
| 	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(); | ||||
| } | ||||
| 
 | ||||
| static void *packet_lookup_frame(struct packet_sock *po, | ||||
| 		struct packet_ring_buffer *rb, | ||||
| 		unsigned int position, | ||||
| @ -1877,6 +1908,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb) | ||||
| 		ph = skb_shinfo(skb)->destructor_arg; | ||||
| 		BUG_ON(atomic_read(&po->tx_ring.pending) == 0); | ||||
| 		atomic_dec(&po->tx_ring.pending); | ||||
| 		__packet_set_timestamp(po, ph, skb->tstamp); | ||||
| 		__packet_set_status(po, ph, TP_STATUS_AVAILABLE); | ||||
| 	} | ||||
| 
 | ||||
| @ -1900,6 +1932,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) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user