diff options
Diffstat (limited to 'net/openvswitch/flow.c')
-rw-r--r-- | net/openvswitch/flow.c | 97 |
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 | ||
63 | void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) | 64 | void 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 | |||
90 | static 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 | |||
103 | void 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 | |||
132 | static 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 | |||
142 | void 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 | ||
82 | static int check_header(struct sk_buff *skb, int len) | 165 | static int check_header(struct sk_buff *skb, int len) |