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.c96
1 files changed, 89 insertions, 7 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index b409f5279601..16f4b46161d4 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,10 +61,16 @@ 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)) &&
69 flow->key.ip.proto == IPPROTO_TCP && 76 flow->key.ip.proto == IPPROTO_TCP &&
@@ -71,12 +78,87 @@ void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb)
71 tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); 78 tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb));
72 } 79 }
73 80
74 spin_lock(&flow->lock); 81 spin_lock(&stats->lock);
75 flow->used = jiffies; 82 stats->used = jiffies;
76 flow->packet_count++; 83 stats->packet_count++;
77 flow->byte_count += skb->len; 84 stats->byte_count += skb->len;
78 flow->tcp_flags |= tcp_flags; 85 stats->tcp_flags |= tcp_flags;
79 spin_unlock(&flow->lock); 86 spin_unlock(&stats->lock);
87}
88
89static void stats_read(struct flow_stats *stats,
90 struct ovs_flow_stats *ovs_stats,
91 unsigned long *used, __be16 *tcp_flags)
92{
93 spin_lock(&stats->lock);
94 if (time_after(stats->used, *used))
95 *used = stats->used;
96 *tcp_flags |= stats->tcp_flags;
97 ovs_stats->n_packets += stats->packet_count;
98 ovs_stats->n_bytes += stats->byte_count;
99 spin_unlock(&stats->lock);
100}
101
102void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
103 unsigned long *used, __be16 *tcp_flags)
104{
105 int cpu, cur_cpu;
106
107 *used = 0;
108 *tcp_flags = 0;
109 memset(ovs_stats, 0, sizeof(*ovs_stats));
110
111 if (!flow->stats.is_percpu) {
112 stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
113 } else {
114 cur_cpu = get_cpu();
115 for_each_possible_cpu(cpu) {
116 struct flow_stats *stats;
117
118 if (cpu == cur_cpu)
119 local_bh_disable();
120
121 stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
122 stats_read(stats, ovs_stats, used, tcp_flags);
123
124 if (cpu == cur_cpu)
125 local_bh_enable();
126 }
127 put_cpu();
128 }
129}
130
131static void stats_reset(struct flow_stats *stats)
132{
133 spin_lock(&stats->lock);
134 stats->used = 0;
135 stats->packet_count = 0;
136 stats->byte_count = 0;
137 stats->tcp_flags = 0;
138 spin_unlock(&stats->lock);
139}
140
141void ovs_flow_stats_clear(struct sw_flow *flow)
142{
143 int cpu, cur_cpu;
144
145 if (!flow->stats.is_percpu) {
146 stats_reset(flow->stats.stat);
147 } else {
148 cur_cpu = get_cpu();
149
150 for_each_possible_cpu(cpu) {
151
152 if (cpu == cur_cpu)
153 local_bh_disable();
154
155 stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
156
157 if (cpu == cur_cpu)
158 local_bh_enable();
159 }
160 put_cpu();
161 }
80} 162}
81 163
82static int check_header(struct sk_buff *skb, int len) 164static int check_header(struct sk_buff *skb, int len)