Commit 325ed823 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ddea7be0
...@@ -155,8 +155,6 @@ struct skb_shared_info { ...@@ -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 { ...@@ -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 * ...@@ -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 * ...@@ -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 @@ ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment