From: Jesse Gross Date: Sun, 29 Aug 2010 17:49:11 +0000 (-0700) Subject: datapath: Enable usage of cached flows. X-Git-Tag: v1.1.0~1099 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3976f6d57b1134c5c3ed054c9da4aa6786fbf5bf;hp=fb8c93473efacd67a50117d0f2a3084f2d96ceca;p=sliver-openvswitch.git datapath: Enable usage of cached flows. An upcoming commit will add support for supplying cached flows for packets entering the datapath. This adds the code in the datapath itself to recognize these cached flows and use them instead of extracting the flow fields and doing a lookup. Signed-off-by: Jesse Gross Reviewed-by: Ben Pfaff --- diff --git a/datapath/datapath.c b/datapath/datapath.c index 06e1006a8..390acc8a4 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -543,40 +543,44 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb) struct datapath *dp = p->dp; struct dp_stats_percpu *stats; int stats_counter_off; - struct odp_flow_key key; - struct tbl_node *flow_node; - struct sw_flow *flow; struct sw_flow_actions *acts; struct loop_counter *loop; int error; OVS_CB(skb)->dp_port = p; - /* Extract flow from 'skb' into 'key'. */ - error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key); - if (unlikely(error)) { - kfree_skb(skb); - return; - } + if (!OVS_CB(skb)->flow) { + struct odp_flow_key key; + struct tbl_node *flow_node; - if (OVS_CB(skb)->is_frag && dp->drop_frags) { - kfree_skb(skb); - stats_counter_off = offsetof(struct dp_stats_percpu, n_frags); - goto out; - } + /* Extract flow from 'skb' into 'key'. */ + error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key); + if (unlikely(error)) { + kfree_skb(skb); + return; + } - /* Look up flow. */ - flow_node = tbl_lookup(rcu_dereference(dp->table), &key, flow_hash(&key), flow_cmp); - if (unlikely(!flow_node)) { - dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id); - stats_counter_off = offsetof(struct dp_stats_percpu, n_missed); - goto out; + if (OVS_CB(skb)->is_frag && dp->drop_frags) { + kfree_skb(skb); + stats_counter_off = offsetof(struct dp_stats_percpu, n_frags); + goto out; + } + + /* Look up flow. */ + flow_node = tbl_lookup(rcu_dereference(dp->table), &key, + flow_hash(&key), flow_cmp); + if (unlikely(!flow_node)) { + dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id); + stats_counter_off = offsetof(struct dp_stats_percpu, n_missed); + goto out; + } + + OVS_CB(skb)->flow = flow_cast(flow_node); } - flow = flow_cast(flow_node); - flow_used(flow, skb); + flow_used(OVS_CB(skb)->flow, skb); - acts = rcu_dereference(flow->sf_acts); + acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); /* Check whether we've looped too much. */ loop = &get_cpu_var(dp_loop_counters).counters[!!in_interrupt()]; @@ -588,7 +592,8 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb) } /* Execute actions. */ - execute_actions(dp, skb, &key, acts->actions, acts->n_actions, GFP_ATOMIC); + execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions, + acts->n_actions, GFP_ATOMIC); stats_counter_off = offsetof(struct dp_stats_percpu, n_hit); /* Check whether sub-actions looped too much. */ diff --git a/datapath/datapath.h b/datapath/datapath.h index abc6aeab2..dacc3a42c 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -146,17 +146,19 @@ enum csum_type { /** * struct ovs_skb_cb - OVS data in skb CB * @dp_port: The datapath port on which the skb entered the switch. + * @flow: The flow associated with this packet. May be %NULL if no flow. + * @is_frag: %true if this packet is an IPv4 fragment, %false otherwise. * @ip_summed: Consistently stores L4 checksumming status across different * kernel versions. * @tun_id: ID (in network byte order) of the tunnel that encapsulated this * packet. It is 0 if the packet was not received on a tunnel. - * @is_frag: %true if this packet is an IPv4 fragment, %false otherwise. */ struct ovs_skb_cb { struct dp_port *dp_port; + struct sw_flow *flow; + bool is_frag; enum csum_type ip_summed; __be32 tun_id; - bool is_frag; }; #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c index 6cbfdf80d..514d00cb3 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -82,6 +82,7 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) skb_reset_mac_header(skb); compute_ip_summed(skb, true); + OVS_CB(skb)->flow = NULL; vport_receive(vport, skb); @@ -293,7 +294,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) struct vport_ops internal_vport_ops = { .type = "internal", - .flags = VPORT_F_REQUIRED | VPORT_F_GEN_STATS, + .flags = VPORT_F_REQUIRED | VPORT_F_GEN_STATS | VPORT_F_FLOW, .create = internal_dev_create, .destroy = internal_dev_destroy, .attach = internal_dev_attach, diff --git a/datapath/vport.c b/datapath/vport.c index 91b650e54..6c8eb0845 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -1217,6 +1217,9 @@ void vport_receive(struct vport *vport, struct sk_buff *skb) local_bh_enable(); } + if (!(vport->ops->flags & VPORT_F_FLOW)) + OVS_CB(skb)->flow = NULL; + if (!(vport->ops->flags & VPORT_F_TUN_ID)) OVS_CB(skb)->tun_id = 0; diff --git a/datapath/vport.h b/datapath/vport.h index fca5f1abe..30b0cc6b3 100644 --- a/datapath/vport.h +++ b/datapath/vport.h @@ -112,7 +112,8 @@ struct vport { #define VPORT_F_REQUIRED (1 << 0) /* If init fails, module loading fails. */ #define VPORT_F_GEN_STATS (1 << 1) /* Track stats at the generic layer. */ -#define VPORT_F_TUN_ID (1 << 2) /* Sets OVS_CB(skb)->tun_id. */ +#define VPORT_F_FLOW (1 << 2) /* Sets OVS_CB(skb)->flow. */ +#define VPORT_F_TUN_ID (1 << 3) /* Sets OVS_CB(skb)->tun_id. */ /** * struct vport_ops - definition of a type of virtual port