The stats are taken before execution, but flow stats are updated only after execution in hope that stats prefetch is complete by then.
Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- datapath/datapath.c | 34 +++++++++++++++++++++++++++++++++- datapath/flow.c | 20 +++++--------------- datapath/flow.h | 4 +++- datapath/flow_table.c | 12 ------------ 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index c80abe0..296e7b1 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -214,6 +214,36 @@ void ovs_dp_detach_port(struct vport *p) ovs_vport_del(p); } +static void ovs_flow_stats_prefetch(const struct sw_flow *flow) +{ + struct flow_stats *stats; + + if (!flow->stats.per_numa_mem) + stats = flow->stats.stat; + else + stats = &flow->stats.numa_stats[numa_node_id()]; + spin_lock_prefetch(&stats->lock); +} + +static void get_skb_stats(struct flow_stats *stat, const struct sw_flow *flow, + const struct sk_buff *skb) +{ + ovs_flow_stats_prefetch(flow); /* Prepare for writing later. */ + + stat->used = jiffies; + stat->packet_count = 1; + stat->byte_count = skb->len; + + if ((flow->key.eth.type == htons(ETH_P_IP) || + flow->key.eth.type == htons(ETH_P_IPV6)) && + flow->key.ip.proto == IPPROTO_TCP && + likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) { + stat->tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); + } else { + stat->tcp_flags = 0; + } +} + /* Must be called with rcu_read_lock. */ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) { @@ -221,6 +251,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) struct sw_flow *flow; struct dp_stats_percpu *stats; struct sw_flow_key key; + struct flow_stats stat; u64 *stats_counter; u32 n_mask_hit; int error; @@ -252,8 +283,9 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) OVS_CB(skb)->flow = flow; OVS_CB(skb)->pkt_key = &key; - ovs_flow_stats_update(OVS_CB(skb)->flow, skb); + get_skb_stats(&stat, flow, skb); ovs_execute_actions(dp, skb); + ovs_flow_stats_update(flow, &stat); stats_counter = &stats->n_hit; out: diff --git a/datapath/flow.c b/datapath/flow.c index 0002759..afc7cd9 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -60,30 +60,20 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies) return cur_ms - idle_ms; } -#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) - -void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb) +void ovs_flow_stats_update(struct sw_flow *flow, const struct flow_stats *stat) { struct flow_stats *stats; - __be16 tcp_flags = 0; if (!flow->stats.per_numa_mem) stats = flow->stats.stat; else stats = &flow->stats.numa_stats[numa_node_id()]; - if ((flow->key.eth.type == htons(ETH_P_IP) || - flow->key.eth.type == htons(ETH_P_IPV6)) && - flow->key.ip.proto == IPPROTO_TCP && - likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) { - tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); - } - spin_lock_bh(&stats->lock); - stats->used = jiffies; - stats->packet_count++; - stats->byte_count += skb->len; - stats->tcp_flags |= tcp_flags; + stats->used = stat->used; + stats->packet_count += stat->packet_count; + stats->byte_count += stat->byte_count; + stats->tcp_flags |= stat->tcp_flags; spin_unlock_bh(&stats->lock); } diff --git a/datapath/flow.h b/datapath/flow.h index 14ea93f..008c92c 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -67,6 +67,8 @@ static inline void ovs_flow_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key, sizeof(*tun_key) - OVS_TUNNEL_KEY_SIZE); } +#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) + struct sw_flow_key { struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ struct { @@ -191,7 +193,7 @@ struct arp_eth_header { unsigned char ar_tip[4]; /* target IP address */ } __packed; -void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb); +void ovs_flow_stats_update(struct sw_flow *flow, const struct flow_stats *stat); void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats, unsigned long *used, __be16 *tcp_flags); void ovs_flow_stats_clear(struct sw_flow *flow); diff --git a/datapath/flow_table.c b/datapath/flow_table.c index aec96cb..417c57b 100644 --- a/datapath/flow_table.c +++ b/datapath/flow_table.c @@ -435,17 +435,6 @@ bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, return cmp_key(&flow->unmasked_key, key, key_start, key_end); } -static void ovs_flow_stats_prefetch(struct sw_flow *flow) -{ - struct flow_stats *stats; - - if (!flow->stats.per_numa_mem) - stats = flow->stats.stat; - else - stats = &flow->stats.numa_stats[numa_node_id()]; - spin_lock_prefetch(&stats->lock); -} - static struct sw_flow *masked_flow_lookup(struct table_instance *ti, const struct sw_flow_key *unmasked, struct sw_flow_mask *mask) @@ -464,7 +453,6 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, if (flow->mask == mask && flow->hash == hash && flow_cmp_masked_key(flow, &masked_key, key_start, key_end)) { - ovs_flow_stats_prefetch(flow); return flow; } } -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev