diff options
Diffstat (limited to 'net/openvswitch/flow.c')
| -rw-r--r-- | net/openvswitch/flow.c | 96 |
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 | ||
| 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)) && |
| 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 | |||
| 89 | static 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 | |||
| 102 | void 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 | |||
| 131 | static 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 | |||
| 141 | void 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 | ||
| 82 | static int check_header(struct sk_buff *skb, int len) | 164 | static int check_header(struct sk_buff *skb, int len) |
