datapath: Free up flow_extract() return value for reporting errors.
authorBen Pfaff <blp@nicira.com>
Thu, 12 Aug 2010 22:12:28 +0000 (15:12 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 26 Aug 2010 16:15:42 +0000 (09:15 -0700)
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>
datapath/datapath.c
datapath/datapath.h
datapath/flow.c

index 32572c6f9d5a2bced7cdc005a3e4d0ec45cc1540..e8b2976e0a07e334966bc6bfeab0f4b6278f3e36 100644 (file)
@@ -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. */
index fd81dfbad0866427401e345e1ff39ffbe4d6dece..abc6aeab2af415a77811eef5f39df955711d915f 100644 (file)
@@ -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)
 
index 7b1f23bdbc7fac92ecee7c8b1b5fa871a37e3717..5e362e300290ac161a33e143f8d8b358b7cb740f 100644 (file)
@@ -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)