Implements ip_defrag action in Linux kenrel using ip_defrag kernel APIs.

Signed-off-by: Andy Zhou <az...@nicira.com>
---
 datapath/actions.c      | 39 ++++++++++++++++++++++++++++++++++++++-
 datapath/flow_netlink.c |  6 +++++-
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 5a1dbe2..668d44f 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -826,6 +826,38 @@ static int execute_recirc(struct datapath *dp, struct 
sk_buff *skb,
        return 0;
 }
 
+static int ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
+{
+       int err;
+
+       local_bh_disable();
+       err = ip_defrag(skb, user);
+       local_bh_enable();
+
+       if (!err) {
+               ip_send_check(ip_hdr(skb));
+               skb->ignore_df = 1;
+       }
+
+       return err;
+}
+
+static int execute_ip_defrag(struct sk_buff *skb, struct sw_flow_key *key,
+                            const struct ovs_action_ip_defrag *act_ip_defrag)
+{
+       if (key->eth.type == htons(ETH_P_IP)) {
+               if (ip_is_fragment(ip_hdr(skb))) {
+                       enum ip_defrag_users user;
+
+                       user = IP_DEFRAG_CONNTRACK_IN + act_ip_defrag->zone;
+                       if (ipv4_gather_frags(skb, user))
+                               return -EINPROGRESS;
+               }
+       }
+
+       return 0;
+}
+
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                              struct sw_flow_key *key,
@@ -902,10 +934,15 @@ static int do_execute_actions(struct datapath *dp, struct 
sk_buff *skb,
                case OVS_ACTION_ATTR_SAMPLE:
                        err = sample(dp, skb, key, a);
                        break;
+
+               case OVS_ACTION_ATTR_IP_DEFRAG:
+                       err = execute_ip_defrag(skb, key, nla_data(a));
+                       break;
                }
 
                if (unlikely(err)) {
-                       kfree_skb(skb);
+                       if (err != -EINPROGRESS)
+                               kfree_skb(skb);
                        return err;
                }
        }
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 503cf63..d96ad65 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -1782,7 +1782,8 @@ static int __ovs_nla_copy_actions(const struct nlattr 
*attr,
                        [OVS_ACTION_ATTR_POP_VLAN] = 0,
                        [OVS_ACTION_ATTR_SET] = (u32)-1,
                        [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
-                       [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
+                       [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
+                       [OVS_ACTION_ATTR_IP_DEFRAG] = sizeof(struct 
ovs_action_ip_defrag)
                };
                const struct ovs_action_push_vlan *vlan;
                int type = nla_type(a);
@@ -1899,6 +1900,9 @@ static int __ovs_nla_copy_actions(const struct nlattr 
*attr,
                        skip_copy = true;
                        break;
 
+               case OVS_ACTION_ATTR_IP_DEFRAG:
+                       break;
+
                default:
                        OVS_NLERR(log, "Unknown Action type %d", type);
                        return -EINVAL;
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to