datapath: add skb mark matching and set action
[openvswitch] / datapath / datapath.c
index 9c253e1c8bff0f7c167248965f2bb0c4d5a486ee..f990b738a3b72f103f21b304c56352f0fdeed91f 100644 (file)
@@ -309,7 +309,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
        u64 *stats_counter;
        int error;
 
-       stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id());
+       stats = this_cpu_ptr(dp->stats_percpu);
 
        if (!OVS_CB(skb)->flow) {
                struct sw_flow_key key;
@@ -391,7 +391,7 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
        return 0;
 
 err:
-       stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id());
+       stats = this_cpu_ptr(dp->stats_percpu);
 
        u64_stats_update_begin(&stats->sync);
        stats->n_lost++;
@@ -588,12 +588,20 @@ static int validate_set(const struct nlattr *a,
        switch (key_type) {
        const struct ovs_key_ipv4 *ipv4_key;
        const struct ovs_key_ipv4_tunnel *tun_key;
+       const struct ovs_key_ipv6 *ipv6_key;
 
        case OVS_KEY_ATTR_PRIORITY:
        case OVS_KEY_ATTR_TUN_ID:
        case OVS_KEY_ATTR_ETHERNET:
                break;
 
+       case OVS_KEY_ATTR_SKB_MARK:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
+               if (nla_get_u32(ovs_key) != 0)
+                       return -EINVAL;
+#endif
+               break;
+
        case OVS_KEY_ATTR_IPV4_TUNNEL:
                tun_key = nla_data(ovs_key);
                if (!tun_key->ipv4_dst)
@@ -616,6 +624,25 @@ static int validate_set(const struct nlattr *a,
 
                break;
 
+       case OVS_KEY_ATTR_IPV6:
+               if (flow_key->eth.type != htons(ETH_P_IPV6))
+                       return -EINVAL;
+
+               if (!flow_key->ip.proto)
+                       return -EINVAL;
+
+               ipv6_key = nla_data(ovs_key);
+               if (ipv6_key->ipv6_proto != flow_key->ip.proto)
+                       return -EINVAL;
+
+               if (ipv6_key->ipv6_frag != flow_key->ip.frag)
+                       return -EINVAL;
+
+               if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000)
+                       return -EINVAL;
+
+               break;
+
        case OVS_KEY_ATTR_TCP:
                if (flow_key->ip.proto != IPPROTO_TCP)
                        return -EINVAL;
@@ -788,24 +815,25 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 
        err = ovs_flow_extract(packet, -1, &flow->key, &key_len);
        if (err)
-               goto err_flow_put;
+               goto err_flow_free;
 
        err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]);
        if (err)
-               goto err_flow_put;
+               goto err_flow_free;
 
        err = validate_actions(a[OVS_PACKET_ATTR_ACTIONS], &flow->key, 0);
        if (err)
-               goto err_flow_put;
+               goto err_flow_free;
 
        acts = ovs_flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]);
        err = PTR_ERR(acts);
        if (IS_ERR(acts))
-               goto err_flow_put;
+               goto err_flow_free;
        rcu_assign_pointer(flow->sf_acts, acts);
 
        OVS_CB(packet)->flow = flow;
        packet->priority = flow->key.phy.priority;
+       skb_set_mark(packet, flow->key.phy.skb_mark);
 
        rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
@@ -818,13 +846,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        local_bh_enable();
        rcu_read_unlock();
 
-       ovs_flow_put(flow);
+       ovs_flow_free(flow);
        return err;
 
 err_unlock:
        rcu_read_unlock();
-err_flow_put:
-       ovs_flow_put(flow);
+err_flow_free:
+       ovs_flow_free(flow);
 err_kfree_skb:
        kfree_skb(packet);
 err:
@@ -1139,7 +1167,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        return 0;
 
 error_free_flow:
-       ovs_flow_put(flow);
+       ovs_flow_free(flow);
 error:
        return error;
 }