[NET]: Fix packet timestamping.
I've found the problem in general. It affects any 64-bit architecture. The problem occurs when you change the system time. Suppose that when you boot your system clock is forward by a day. This gets recorded down in skb_tv_base. You then wind the clock back by a day. From that point onwards the offset will be negative which essentially overflows the 32-bit variables they're stored in. In fact, why don't we just store the real time stamp in those 32-bit variables? After all, we're not going to overflow for quite a while yet. When we do overflow, we'll need a better solution of course. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ddea7be0ec
commit
325ed82393
8 changed files with 15 additions and 26 deletions
|
@ -155,8 +155,6 @@ struct skb_shared_info {
|
||||||
#define SKB_DATAREF_SHIFT 16
|
#define SKB_DATAREF_SHIFT 16
|
||||||
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
|
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
|
||||||
|
|
||||||
extern struct timeval skb_tv_base;
|
|
||||||
|
|
||||||
struct skb_timeval {
|
struct skb_timeval {
|
||||||
u32 off_sec;
|
u32 off_sec;
|
||||||
u32 off_usec;
|
u32 off_usec;
|
||||||
|
@ -175,7 +173,7 @@ enum {
|
||||||
* @prev: Previous buffer in list
|
* @prev: Previous buffer in list
|
||||||
* @list: List we are on
|
* @list: List we are on
|
||||||
* @sk: Socket we are owned by
|
* @sk: Socket we are owned by
|
||||||
* @tstamp: Time we arrived stored as offset to skb_tv_base
|
* @tstamp: Time we arrived
|
||||||
* @dev: Device we arrived on/are leaving by
|
* @dev: Device we arrived on/are leaving by
|
||||||
* @input_dev: Device we arrived on
|
* @input_dev: Device we arrived on
|
||||||
* @h: Transport layer header
|
* @h: Transport layer header
|
||||||
|
@ -1255,10 +1253,6 @@ static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *
|
||||||
{
|
{
|
||||||
stamp->tv_sec = skb->tstamp.off_sec;
|
stamp->tv_sec = skb->tstamp.off_sec;
|
||||||
stamp->tv_usec = skb->tstamp.off_usec;
|
stamp->tv_usec = skb->tstamp.off_usec;
|
||||||
if (skb->tstamp.off_sec) {
|
|
||||||
stamp->tv_sec += skb_tv_base.tv_sec;
|
|
||||||
stamp->tv_usec += skb_tv_base.tv_usec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1272,8 +1266,8 @@ static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *
|
||||||
*/
|
*/
|
||||||
static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
|
static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
|
||||||
{
|
{
|
||||||
skb->tstamp.off_sec = stamp->tv_sec - skb_tv_base.tv_sec;
|
skb->tstamp.off_sec = stamp->tv_sec;
|
||||||
skb->tstamp.off_usec = stamp->tv_usec - skb_tv_base.tv_usec;
|
skb->tstamp.off_usec = stamp->tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void __net_timestamp(struct sk_buff *skb);
|
extern void __net_timestamp(struct sk_buff *skb);
|
||||||
|
|
|
@ -71,8 +71,6 @@
|
||||||
static kmem_cache_t *skbuff_head_cache __read_mostly;
|
static kmem_cache_t *skbuff_head_cache __read_mostly;
|
||||||
static kmem_cache_t *skbuff_fclone_cache __read_mostly;
|
static kmem_cache_t *skbuff_fclone_cache __read_mostly;
|
||||||
|
|
||||||
struct timeval __read_mostly skb_tv_base;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep out-of-line to prevent kernel bloat.
|
* Keep out-of-line to prevent kernel bloat.
|
||||||
* __builtin_return_address is not used because it is not always
|
* __builtin_return_address is not used because it is not always
|
||||||
|
@ -1708,8 +1706,6 @@ void __init skb_init(void)
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
if (!skbuff_fclone_cache)
|
if (!skbuff_fclone_cache)
|
||||||
panic("cannot create skbuff cache");
|
panic("cannot create skbuff cache");
|
||||||
|
|
||||||
do_gettimeofday(&skb_tv_base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(___pskb_trim);
|
EXPORT_SYMBOL(___pskb_trim);
|
||||||
|
@ -1743,4 +1739,3 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
|
||||||
EXPORT_SYMBOL(skb_seq_read);
|
EXPORT_SYMBOL(skb_seq_read);
|
||||||
EXPORT_SYMBOL(skb_abort_seq_read);
|
EXPORT_SYMBOL(skb_abort_seq_read);
|
||||||
EXPORT_SYMBOL(skb_find_text);
|
EXPORT_SYMBOL(skb_find_text);
|
||||||
EXPORT_SYMBOL(skb_tv_base);
|
|
||||||
|
|
|
@ -240,8 +240,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
|
||||||
|
|
||||||
pmsg->packet_id = (unsigned long )entry;
|
pmsg->packet_id = (unsigned long )entry;
|
||||||
pmsg->data_len = data_len;
|
pmsg->data_len = data_len;
|
||||||
pmsg->timestamp_sec = skb_tv_base.tv_sec + entry->skb->tstamp.off_sec;
|
pmsg->timestamp_sec = entry->skb->tstamp.off_sec;
|
||||||
pmsg->timestamp_usec = skb_tv_base.tv_usec + entry->skb->tstamp.off_usec;
|
pmsg->timestamp_usec = entry->skb->tstamp.off_usec;
|
||||||
pmsg->mark = entry->skb->nfmark;
|
pmsg->mark = entry->skb->nfmark;
|
||||||
pmsg->hook = entry->info->hook;
|
pmsg->hook = entry->info->hook;
|
||||||
pmsg->hw_protocol = entry->skb->protocol;
|
pmsg->hw_protocol = entry->skb->protocol;
|
||||||
|
|
|
@ -225,8 +225,8 @@ static void ipt_ulog_packet(unsigned int hooknum,
|
||||||
|
|
||||||
/* copy hook, prefix, timestamp, payload, etc. */
|
/* copy hook, prefix, timestamp, payload, etc. */
|
||||||
pm->data_len = copy_len;
|
pm->data_len = copy_len;
|
||||||
pm->timestamp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
|
pm->timestamp_sec = skb->tstamp.off_sec;
|
||||||
pm->timestamp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
|
pm->timestamp_usec = skb->tstamp.off_usec;
|
||||||
pm->mark = skb->nfmark;
|
pm->mark = skb->nfmark;
|
||||||
pm->hook = hooknum;
|
pm->hook = hooknum;
|
||||||
if (prefix != NULL)
|
if (prefix != NULL)
|
||||||
|
|
|
@ -238,8 +238,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
|
||||||
|
|
||||||
pmsg->packet_id = (unsigned long )entry;
|
pmsg->packet_id = (unsigned long )entry;
|
||||||
pmsg->data_len = data_len;
|
pmsg->data_len = data_len;
|
||||||
pmsg->timestamp_sec = skb_tv_base.tv_sec + entry->skb->tstamp.off_sec;
|
pmsg->timestamp_sec = entry->skb->tstamp.off_sec;
|
||||||
pmsg->timestamp_usec = skb_tv_base.tv_usec + entry->skb->tstamp.off_usec;
|
pmsg->timestamp_usec = entry->skb->tstamp.off_usec;
|
||||||
pmsg->mark = entry->skb->nfmark;
|
pmsg->mark = entry->skb->nfmark;
|
||||||
pmsg->hook = entry->info->hook;
|
pmsg->hook = entry->info->hook;
|
||||||
pmsg->hw_protocol = entry->skb->protocol;
|
pmsg->hw_protocol = entry->skb->protocol;
|
||||||
|
|
|
@ -494,8 +494,8 @@ __build_packet_message(struct nfulnl_instance *inst,
|
||||||
if (skb->tstamp.off_sec) {
|
if (skb->tstamp.off_sec) {
|
||||||
struct nfulnl_msg_packet_timestamp ts;
|
struct nfulnl_msg_packet_timestamp ts;
|
||||||
|
|
||||||
ts.sec = cpu_to_be64(skb_tv_base.tv_sec + skb->tstamp.off_sec);
|
ts.sec = cpu_to_be64(skb->tstamp.off_sec);
|
||||||
ts.usec = cpu_to_be64(skb_tv_base.tv_usec + skb->tstamp.off_usec);
|
ts.usec = cpu_to_be64(skb->tstamp.off_usec);
|
||||||
|
|
||||||
NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
|
NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,8 +492,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
|
||||||
if (entry->skb->tstamp.off_sec) {
|
if (entry->skb->tstamp.off_sec) {
|
||||||
struct nfqnl_msg_packet_timestamp ts;
|
struct nfqnl_msg_packet_timestamp ts;
|
||||||
|
|
||||||
ts.sec = cpu_to_be64(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec);
|
ts.sec = cpu_to_be64(entry->skb->tstamp.off_sec);
|
||||||
ts.usec = cpu_to_be64(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec);
|
ts.usec = cpu_to_be64(entry->skb->tstamp.off_usec);
|
||||||
|
|
||||||
NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
|
NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -654,8 +654,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
|
||||||
__net_timestamp(skb);
|
__net_timestamp(skb);
|
||||||
sock_enable_timestamp(sk);
|
sock_enable_timestamp(sk);
|
||||||
}
|
}
|
||||||
h->tp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
|
h->tp_sec = skb->tstamp.off_sec;
|
||||||
h->tp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
|
h->tp_usec = skb->tstamp.off_usec;
|
||||||
|
|
||||||
sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
|
sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
|
||||||
sll->sll_halen = 0;
|
sll->sll_halen = 0;
|
||||||
|
|
Loading…
Reference in a new issue