For SNAT, don't store the pre-fragment L2 header before actions are applied.
[sliver-openvswitch.git] / datapath / dp_act.c
index 3401c4a..4c27c85 100644 (file)
 #include <net/checksum.h>
 #include "forward.h"
 #include "dp_act.h"
-#include "nicira-ext.h"
+#include "openflow/nicira-ext.h"
 #include "nx_act.h"
 
-static int make_writable(struct sk_buff **);
-
 
 static uint16_t
 validate_output(struct datapath *dp, const struct sw_flow_key *key, 
@@ -28,7 +26,8 @@ validate_output(struct datapath *dp, const struct sw_flow_key *key,
 {
        struct ofp_action_output *oa = (struct ofp_action_output *)ah;
 
-       if (oa->port == htons(OFPP_NONE) || oa->port == key->in_port)
+       if (oa->port == htons(OFPP_NONE) || 
+                       (!(key->wildcards & OFPFW_IN_PORT) && oa->port == key->in_port)) 
                return OFPBAC_BAD_OUT_PORT;
 
        return ACT_VALIDATION_OK;
@@ -341,7 +340,7 @@ validate_vendor(struct datapath *dp, const struct sw_flow_key *key,
 
        switch(ntohl(avh->vendor)) {
        case NX_VENDOR_ID: 
-               ret = nx_validate_act(dp, key, avh, len);
+               ret = nx_validate_act(dp, key, (struct nx_action_header *)avh, len);
                break;
 
        default:
@@ -426,7 +425,7 @@ execute_vendor(struct sk_buff *skb, const struct sw_flow_key *key,
 
        switch(ntohl(avh->vendor)) {
        case NX_VENDOR_ID: 
-               skb = nx_execute_act(skb, key, avh);
+               skb = nx_execute_act(skb, key, (struct nx_action_header *)avh);
                break;
 
        default:
@@ -462,6 +461,7 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb,
                struct ofp_action_header *ah = (struct ofp_action_header *)p;
                size_t len = htons(ah->len);
 
+               WARN_ON_ONCE(skb_shared(skb));
                if (prev_port != -1) {
                        do_output(dp, skb_clone(skb, GFP_ATOMIC),
                                  max_len, prev_port, ignore_no_fwd);
@@ -501,29 +501,20 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb,
 /* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to
  * the copy.
  * Returns 1 if successful, 0 on failure. */
-static int
+int
 make_writable(struct sk_buff **pskb)
 {
-       /* Based on skb_make_writable() in net/netfilter/core.c. */
-       struct sk_buff *nskb;
-
-       /* Not exclusive use of packet?  Must copy. */
-       if (skb_shared(*pskb) || skb_cloned(*pskb))
-               goto copy_skb;
-
-       return pskb_may_pull(*pskb, 40); /* FIXME? */
-
-copy_skb:
-       nskb = skb_copy(*pskb, GFP_ATOMIC);
-       if (!nskb)
-               return 0;
-       BUG_ON(skb_is_nonlinear(nskb));
-
-       /* Rest of kernel will get very unhappy if we pass it a
-          suddenly-orphaned skbuff */
-       if ((*pskb)->sk)
-               skb_set_owner_w(nskb, (*pskb)->sk);
-       kfree_skb(*pskb);
-       *pskb = nskb;
-       return 1;
+       struct sk_buff *skb = *pskb;
+       if (skb_shared(skb) || skb_cloned(skb)) {
+               struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
+               if (!nskb)
+                       return 0;
+               kfree_skb(skb);
+               *pskb = nskb;
+               return 1;
+       } else {
+               unsigned int hdr_len = (skb_transport_offset(skb)
+                                       + sizeof(struct tcphdr));
+               return pskb_may_pull(skb, min(hdr_len, skb->len));
+       }
 }