X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fflow.c;h=57eb6b565834fa60e8ef0da4d3961cc1a83e897e;hb=6c75562d49e87237cfaafc82d786c8c4f0823326;hp=faa4e158fb4163830d4d4a0da8b3fc87e16bb9af;hpb=a097c0b230333cbc038be4ec67bf34b5b26c5112;p=sliver-openvswitch.git diff --git a/datapath/flow.c b/datapath/flow.c index faa4e158f..57eb6b565 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -59,27 +60,78 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies) return cur_ms - idle_ms; } -#define TCP_FLAGS_OFFSET 13 -#define TCP_FLAG_MASK 0x3f +#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) -void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) +void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb) { - u8 tcp_flags = 0; + struct sw_flow_stats *stats = &flow->stats[smp_processor_id()]; + __be16 tcp_flags = 0; 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))) { - u8 *tcp = (u8 *)tcp_hdr(skb); - tcp_flags = *(tcp + TCP_FLAGS_OFFSET) & TCP_FLAG_MASK; + tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); } - spin_lock(&flow->lock); - flow->used = jiffies; - flow->packet_count++; - flow->byte_count += skb->len; - flow->tcp_flags |= tcp_flags; - spin_unlock(&flow->lock); + spin_lock(&stats->lock); + stats->used = jiffies; + stats->packet_count++; + stats->byte_count += skb->len; + stats->tcp_flags |= tcp_flags; + spin_unlock(&stats->lock); +} + +void ovs_flow_stats_get(struct sw_flow *flow, struct sw_flow_stats *res) +{ + int cpu, cur_cpu; + + memset(res, 0, sizeof(*res)); + + cur_cpu = get_cpu(); + for_each_possible_cpu(cpu) { + struct sw_flow_stats *stats = &flow->stats[cpu]; + + if (cpu == cur_cpu) + local_bh_disable(); + + spin_lock(&stats->lock); + if (time_after(stats->used, res->used)) + res->used = stats->used; + res->packet_count += stats->packet_count; + res->byte_count += stats->byte_count; + res->tcp_flags |= stats->tcp_flags; + spin_unlock(&stats->lock); + + if (cpu == cur_cpu) + local_bh_enable(); + + } + put_cpu(); +} + +void ovs_flow_stats_clear(struct sw_flow *flow) +{ + int cpu, cur_cpu; + + cur_cpu = get_cpu(); + for_each_possible_cpu(cpu) { + struct sw_flow_stats *stats = &flow->stats[cpu]; + + if (cpu == cur_cpu) + local_bh_disable(); + + spin_lock(&stats->lock); + stats->used = 0; + stats->packet_count = 0; + stats->byte_count = 0; + stats->tcp_flags = 0; + spin_unlock(&stats->lock); + + if (cpu == cur_cpu) + local_bh_enable(); + } + put_cpu(); } static int check_header(struct sk_buff *skb, int len) @@ -430,6 +482,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) struct tcphdr *tcp = tcp_hdr(skb); key->ipv4.tp.src = tcp->source; key->ipv4.tp.dst = tcp->dest; + key->ipv4.tp.flags = TCP_FLAGS_BE16(tcp); } } else if (key->ip.proto == IPPROTO_UDP) { if (udphdr_ok(skb)) { @@ -498,6 +551,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) struct tcphdr *tcp = tcp_hdr(skb); key->ipv6.tp.src = tcp->source; key->ipv6.tp.dst = tcp->dest; + key->ipv6.tp.flags = TCP_FLAGS_BE16(tcp); } } else if (key->ip.proto == NEXTHDR_UDP) { if (udphdr_ok(skb)) {