aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2010-08-12 15:12:28 -0700
committerBen Pfaff <blp@nicira.com>2010-08-26 09:15:42 -0700
commit769f8ccd5fe0cbfbf85fb41c42e6c164e21352be (patch)
tree54068fb883deb7f390526738f70b3e212e97b83a
parenta31e0e31c6f319b50e0d285117c5d187804a7b2e (diff)
datapath: Free up flow_extract() return value for reporting errors.
flow_extract() can fail due to memory allocation errors in pskb_may_pull(). Currently it doesn't return those properly, instead just reporting a bogus flow to the caller. But its return value is currently in use for reporting whether the packet was an IPv4 fragment. This commit switches to reporting that in the skb itself so that the return value can be reused to report errors. Signed-off-by: Ben Pfaff <blp@nicira.com>
-rw-r--r--datapath/datapath.c11
-rw-r--r--datapath/datapath.h2
-rw-r--r--datapath/flow.c9
3 files changed, 12 insertions, 10 deletions
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 32572c6f..e8b2976e 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -551,12 +551,11 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
OVS_CB(skb)->dp_port = p;
/* Extract flow from 'skb' into 'key'. */
- if (flow_extract(skb, p ? p->port_no : ODPP_NONE, &key)) {
- if (dp->drop_frags) {
- kfree_skb(skb);
- stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
- goto out;
- }
+ flow_extract(skb, p ? p->port_no : ODPP_NONE, &key);
+ 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. */
diff --git a/datapath/datapath.h b/datapath/datapath.h
index fd81dfba..abc6aeab 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -150,11 +150,13 @@ enum csum_type {
* 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;
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/flow.c b/datapath/flow.c
index 7b1f23bd..5e362e30 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -228,17 +228,18 @@ static __be16 parse_ethertype(struct sk_buff *skb)
*
* The caller must ensure that skb->len >= ETH_HLEN.
*
- * Returns 1 if @skb contains an IPv4 fragment, 0 otherwise.
+ * Sets OVS_CB(skb)->is_frag to %true if @skb is an IPv4 fragment, otherwise to
+ * %false.
*/
int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
{
struct ethhdr *eth;
- int retval = 0;
memset(key, 0, sizeof *key);
key->tun_id = OVS_CB(skb)->tun_id;
key->in_port = in_port;
key->dl_vlan = htons(ODP_VLAN_NONE);
+ OVS_CB(skb)->is_frag = false;
if (!pskb_may_pull(skb, min(skb->len, 64u)))
return 0;
@@ -308,7 +309,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
}
}
} else {
- retval = 1;
+ OVS_CB(skb)->is_frag = true;
}
} else if (key->dl_type == htons(ETH_P_ARP) && arphdr_ok(skb)) {
struct arp_eth_header *arp;
@@ -334,7 +335,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
} else {
skb_reset_transport_header(skb);
}
- return retval;
+ return 0;
}
u32 flow_hash(const struct odp_flow_key *key)