net: infrastructure for hardware time stamping
The additional per-packet information (16 bytes for time stamps, 1 byte for flags) is stored for all packets in the skb_shared_info struct. This implementation detail is hidden from users of that information via skb_* accessor functions. A separate struct resp. union is used for the additional information so that it can be stored/copied easily outside of skb_shared_info. Compared to previous implementations (reusing the tstamp field depending on the context, optional additional structures) this is the simplest solution. It does not extend sk_buff itself. TX time stamping is implemented in software if the device driver doesn't support hardware time stamping. The new semantic for hardware/software time stamping around ndo_start_xmit() is based on two assumptions about existing network device drivers which don't support hardware time stamping and know nothing about it: - they leave the new skb_shared_tx unmodified - the keep the connection to the originating socket in skb->sk alive, i.e., don't call skb_orphan() Given that skb_shared_tx is new, the first assumption is safe. The second is only true for some drivers. As a result, software TX time stamping currently works with the bnx2 driver, but not with the unmodified igb driver (the two drivers this patch series was tested with). Signed-off-by: Patrick Ohly <patrick.ohly@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
cb9eff0978
commit
ac45f602ee
@ -132,6 +132,57 @@ struct skb_frag_struct {
|
||||
__u32 size;
|
||||
};
|
||||
|
||||
#define HAVE_HW_TIME_STAMP
|
||||
|
||||
/**
|
||||
* skb_shared_hwtstamps - hardware time stamps
|
||||
*
|
||||
* @hwtstamp: hardware time stamp transformed into duration
|
||||
* since arbitrary point in time
|
||||
* @syststamp: hwtstamp transformed to system time base
|
||||
*
|
||||
* Software time stamps generated by ktime_get_real() are stored in
|
||||
* skb->tstamp. The relation between the different kinds of time
|
||||
* stamps is as follows:
|
||||
*
|
||||
* syststamp and tstamp can be compared against each other in
|
||||
* arbitrary combinations. The accuracy of a
|
||||
* syststamp/tstamp/"syststamp from other device" comparison is
|
||||
* limited by the accuracy of the transformation into system time
|
||||
* base. This depends on the device driver and its underlying
|
||||
* hardware.
|
||||
*
|
||||
* hwtstamps can only be compared against other hwtstamps from
|
||||
* the same device.
|
||||
*
|
||||
* This structure is attached to packets as part of the
|
||||
* &skb_shared_info. Use skb_hwtstamps() to get a pointer.
|
||||
*/
|
||||
struct skb_shared_hwtstamps {
|
||||
ktime_t hwtstamp;
|
||||
ktime_t syststamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* skb_shared_tx - instructions for time stamping of outgoing packets
|
||||
*
|
||||
* @hardware: generate hardware time stamp
|
||||
* @software: generate software time stamp
|
||||
* @in_progress: device driver is going to provide
|
||||
* hardware time stamp
|
||||
*
|
||||
* These flags are attached to packets as part of the
|
||||
* &skb_shared_info. Use skb_tx() to get a pointer.
|
||||
*/
|
||||
union skb_shared_tx {
|
||||
struct {
|
||||
__u8 hardware:1,
|
||||
software:1,
|
||||
in_progress:1;
|
||||
};
|
||||
__u8 flags;
|
||||
};
|
||||
|
||||
/* This data is invariant across clones and lives at
|
||||
* the end of the header data, ie. at skb->end.
|
||||
*/
|
||||
@ -143,10 +194,12 @@ struct skb_shared_info {
|
||||
unsigned short gso_segs;
|
||||
unsigned short gso_type;
|
||||
__be32 ip6_frag_id;
|
||||
union skb_shared_tx tx_flags;
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
unsigned int num_dma_maps;
|
||||
#endif
|
||||
struct sk_buff *frag_list;
|
||||
struct skb_shared_hwtstamps hwtstamps;
|
||||
skb_frag_t frags[MAX_SKB_FRAGS];
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
dma_addr_t dma_maps[MAX_SKB_FRAGS + 1];
|
||||
@ -465,6 +518,16 @@ static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
|
||||
/* Internal */
|
||||
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
|
||||
|
||||
static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
|
||||
{
|
||||
return &skb_shinfo(skb)->hwtstamps;
|
||||
}
|
||||
|
||||
static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
|
||||
{
|
||||
return &skb_shinfo(skb)->tx_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_queue_empty - check if a queue is empty
|
||||
* @list: queue head
|
||||
@ -1730,6 +1793,11 @@ static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
|
||||
|
||||
extern void skb_init(void);
|
||||
|
||||
static inline ktime_t skb_get_ktime(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->tstamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_get_timestamp - get timestamp from a skb
|
||||
* @skb: skb to get stamp from
|
||||
@ -1739,11 +1807,18 @@ extern void skb_init(void);
|
||||
* This function converts the offset back to a struct timeval and stores
|
||||
* it in stamp.
|
||||
*/
|
||||
static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
|
||||
static inline void skb_get_timestamp(const struct sk_buff *skb,
|
||||
struct timeval *stamp)
|
||||
{
|
||||
*stamp = ktime_to_timeval(skb->tstamp);
|
||||
}
|
||||
|
||||
static inline void skb_get_timestampns(const struct sk_buff *skb,
|
||||
struct timespec *stamp)
|
||||
{
|
||||
*stamp = ktime_to_timespec(skb->tstamp);
|
||||
}
|
||||
|
||||
static inline void __net_timestamp(struct sk_buff *skb)
|
||||
{
|
||||
skb->tstamp = ktime_get_real();
|
||||
@ -1759,6 +1834,20 @@ static inline ktime_t net_invalid_timestamp(void)
|
||||
return ktime_set(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_tstamp_tx - queue clone of skb with send time stamps
|
||||
* @orig_skb: the original outgoing packet
|
||||
* @hwtstamps: hardware time stamps, may be NULL if not available
|
||||
*
|
||||
* If the skb has a socket associated, then this function clones the
|
||||
* skb (thus sharing the actual data and optional structures), stores
|
||||
* the optional hardware time stamping information (if non NULL) or
|
||||
* generates a software time stamp (otherwise), then queues the clone
|
||||
* to the error queue of the socket. Errors are silently ignored.
|
||||
*/
|
||||
extern void skb_tstamp_tx(struct sk_buff *orig_skb,
|
||||
struct skb_shared_hwtstamps *hwtstamps);
|
||||
|
||||
extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
|
||||
extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
|
||||
|
||||
|
Reference in New Issue
Block a user