aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch/flow.c')
-rw-r--r--net/openvswitch/flow.c97
1 files changed, 90 insertions, 7 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index b409f5279601..dda451f4429c 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -35,6 +35,7 @@
35#include <linux/ip.h> 35#include <linux/ip.h>
36#include <linux/ipv6.h> 36#include <linux/ipv6.h>
37#include <linux/sctp.h> 37#include <linux/sctp.h>
38#include <linux/smp.h>
38#include <linux/tcp.h> 39#include <linux/tcp.h>
39#include <linux/udp.h> 40#include <linux/udp.h>
40#include <linux/icmp.h> 41#include <linux/icmp.h>
@@ -60,23 +61,105 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
60 61
61#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) 62#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF))
62 63
63void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) 64void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
64{ 65{
66 struct flow_stats *stats;
65 __be16 tcp_flags = 0; 67 __be16 tcp_flags = 0;
66 68
69 if (!flow->stats.is_percpu)
70 stats = flow->stats.stat;
71 else
72 stats = this_cpu_ptr(flow->stats.cpu_stats);
73
67 if ((flow->key.eth.type == htons(ETH_P_IP) || 74 if ((flow->key.eth.type == htons(ETH_P_IP) ||
68 flow->key.eth.type == htons(ETH_P_IPV6)) && 75 flow->key.eth.type == htons(ETH_P_IPV6)) &&
76 flow->key.ip.frag != OVS_FRAG_TYPE_LATER &&
69 flow->key.ip.proto == IPPROTO_TCP && 77 flow->key.ip.proto == IPPROTO_TCP &&
70 likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) { 78 likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) {
71 tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); 79 tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb));
72 } 80 }
73 81
74 spin_lock(&flow->lock); 82 spin_lock(&stats->lock);
75 flow->used = jiffies; 83 stats->used = jiffies;
76 flow->packet_count++; 84 stats->packet_count++;
77 flow->byte_count += skb->len; 85 stats->byte_count += skb->len;
78 flow->tcp_flags |= tcp_flags; 86 stats->tcp_flags |= tcp_flags;
79 spin_unlock(&flow->lock); 87 spin_unlock(&stats->lock);
88}
89
90static void stats_read(struct flow_stats *stats,
91 struct ovs_flow_stats *ovs_stats,
92 unsigned long *used, __be16 *tcp_flags)
93{
94 spin_lock(&stats->lock);
95 if (!*used || time_after(stats->used, *used))
96 *used = stats->used;
97 *tcp_flags |= stats->tcp_flags;
98 ovs_stats->n_packets += stats->packet_count;
99 ovs_stats->n_bytes += stats->byte_count;
100 spin_unlock(&stats->lock);
101}
102
103void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
104 unsigned long *used, __be16 *tcp_flags)
105{
106 int cpu, cur_cpu;
107
108 *used = 0;
109 *tcp_flags = 0;
110 memset(ovs_stats, 0, sizeof(*ovs_stats));
111
112 if (!flow->stats.is_percpu) {
113 stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
114 } else {
115 cur_cpu = get_cpu();
116 for_each_possible_cpu(cpu) {
117 struct flow_stats *stats;
118
119 if (cpu == cur_cpu)
120 local_bh_disable();
121
122 stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
123 stats_read(stats, ovs_stats, used, tcp_flags);
124
125 if (cpu == cur_cpu)
126 local_bh_enable();
127 }
128 put_cpu();
129 }
130}
131
132static void stats_reset(struct flow_stats *stats)
133{
134 spin_lock(&stats->lock);
135 stats->used = 0;
136 stats->packet_count = 0;
137 stats->byte_count = 0;
138 stats->tcp_flags = 0;
139 spin_unlock(&stats->lock);
140}
141
142void ovs_flow_stats_clear(struct sw_flow *flow)
143{
144 int cpu, cur_cpu;
145
146 if (!flow->stats.is_percpu) {
147 stats_reset(flow->stats.stat);
148 } else {
149 cur_cpu = get_cpu();
150
151 for_each_possible_cpu(cpu) {
152
153 if (cpu == cur_cpu)
154 local_bh_disable();
155
156 stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
157
158 if (cpu == cur_cpu)
159 local_bh_enable();
160 }
161 put_cpu();
162 }
80} 163}
81 164
82static int check_header(struct sk_buff *skb, int len) 165static int check_header(struct sk_buff *skb, int len)