aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2014-09-15 22:37:25 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-09-16 02:28:14 -0400
commit971427f353f3c42c8dcef62e7124440df68eb809 (patch)
tree7eed9ed50fe70cfc82ce33e12a13147ad0de580c /net/openvswitch
parent32ae87ff795781b7ceffc44b7c694c1bb206a266 (diff)
openvswitch: Add recirc and hash action.
Recirc action allows a packet to reenter openvswitch processing. currently openvswitch lookup flow for packet received and execute set of actions on that packet, with help of recirc action we can process/modify the packet and recirculate it back in openvswitch for another pass. OVS hash action calculates 5-tupple hash and set hash in flow-key hash. This can be used along with recirculation for distributing packets among different ports for bond devices. For example: OVS bonding can use following actions: Match on: bond flow; Action: hash, recirc(id) Match on: recirc-id == id and hash lower bits == a; Action: output port_bond_a Signed-off-by: Andy Zhou <azhou@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/actions.c203
-rw-r--r--net/openvswitch/datapath.c11
-rw-r--r--net/openvswitch/datapath.h7
-rw-r--r--net/openvswitch/flow.c7
-rw-r--r--net/openvswitch/flow.h3
-rw-r--r--net/openvswitch/flow_netlink.c43
6 files changed, 262 insertions, 12 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index c31bb80c984f..6932a42e41a2 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007-2013 Nicira, Inc. 2 * Copyright (c) 2007-2014 Nicira, Inc.
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -35,12 +35,78 @@
35#include <net/sctp/checksum.h> 35#include <net/sctp/checksum.h>
36 36
37#include "datapath.h" 37#include "datapath.h"
38#include "flow.h"
38#include "vport.h" 39#include "vport.h"
39 40
40static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, 41static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
41 struct sw_flow_key *key, 42 struct sw_flow_key *key,
42 const struct nlattr *attr, int len); 43 const struct nlattr *attr, int len);
43 44
45struct deferred_action {
46 struct sk_buff *skb;
47 const struct nlattr *actions;
48
49 /* Store pkt_key clone when creating deferred action. */
50 struct sw_flow_key pkt_key;
51};
52
53#define DEFERRED_ACTION_FIFO_SIZE 10
54struct action_fifo {
55 int head;
56 int tail;
57 /* Deferred action fifo queue storage. */
58 struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE];
59};
60
61static struct action_fifo __percpu *action_fifos;
62static DEFINE_PER_CPU(int, exec_actions_level);
63
64static void action_fifo_init(struct action_fifo *fifo)
65{
66 fifo->head = 0;
67 fifo->tail = 0;
68}
69
70static bool action_fifo_is_empty(struct action_fifo *fifo)
71{
72 return (fifo->head == fifo->tail);
73}
74
75static struct deferred_action *action_fifo_get(struct action_fifo *fifo)
76{
77 if (action_fifo_is_empty(fifo))
78 return NULL;
79
80 return &fifo->fifo[fifo->tail++];
81}
82
83static struct deferred_action *action_fifo_put(struct action_fifo *fifo)
84{
85 if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1)
86 return NULL;
87
88 return &fifo->fifo[fifo->head++];
89}
90
91/* Return true if fifo is not full */
92static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
93 struct sw_flow_key *key,
94 const struct nlattr *attr)
95{
96 struct action_fifo *fifo;
97 struct deferred_action *da;
98
99 fifo = this_cpu_ptr(action_fifos);
100 da = action_fifo_put(fifo);
101 if (da) {
102 da->skb = skb;
103 da->actions = attr;
104 da->pkt_key = *key;
105 }
106
107 return da;
108}
109
44static int make_writable(struct sk_buff *skb, int write_len) 110static int make_writable(struct sk_buff *skb, int write_len)
45{ 111{
46 if (!pskb_may_pull(skb, write_len)) 112 if (!pskb_may_pull(skb, write_len))
@@ -485,8 +551,29 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
485 /* Skip the sample action when out of memory. */ 551 /* Skip the sample action when out of memory. */
486 return 0; 552 return 0;
487 553
488 /* do_execute_actions() will consume the cloned skb. */ 554 if (!add_deferred_actions(skb, key, a)) {
489 return do_execute_actions(dp, skb, key, a, rem); 555 if (net_ratelimit())
556 pr_warn("%s: deferred actions limit reached, dropping sample action\n",
557 ovs_dp_name(dp));
558
559 kfree_skb(skb);
560 }
561 return 0;
562}
563
564static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key,
565 const struct nlattr *attr)
566{
567 struct ovs_action_hash *hash_act = nla_data(attr);
568 u32 hash = 0;
569
570 /* OVS_HASH_ALG_L4 is the only possible hash algorithm. */
571 hash = skb_get_hash(skb);
572 hash = jhash_1word(hash, hash_act->hash_basis);
573 if (!hash)
574 hash = 0x1;
575
576 key->ovs_flow_hash = hash;
490} 577}
491 578
492static int execute_set_action(struct sk_buff *skb, 579static int execute_set_action(struct sk_buff *skb,
@@ -535,6 +622,44 @@ static int execute_set_action(struct sk_buff *skb,
535 return err; 622 return err;
536} 623}
537 624
625static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
626 struct sw_flow_key *key,
627 const struct nlattr *a, int rem)
628{
629 struct deferred_action *da;
630 int err;
631
632 err = ovs_flow_key_update(skb, key);
633 if (err)
634 return err;
635
636 if (!last_action(a, rem)) {
637 /* Recirc action is the not the last action
638 * of the action list, need to clone the skb.
639 */
640 skb = skb_clone(skb, GFP_ATOMIC);
641
642 /* Skip the recirc action when out of memory, but
643 * continue on with the rest of the action list.
644 */
645 if (!skb)
646 return 0;
647 }
648
649 da = add_deferred_actions(skb, key, NULL);
650 if (da) {
651 da->pkt_key.recirc_id = nla_get_u32(a);
652 } else {
653 kfree_skb(skb);
654
655 if (net_ratelimit())
656 pr_warn("%s: deferred action limit reached, drop recirc action\n",
657 ovs_dp_name(dp));
658 }
659
660 return 0;
661}
662
538/* Execute a list of actions against 'skb'. */ 663/* Execute a list of actions against 'skb'. */
539static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, 664static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
540 struct sw_flow_key *key, 665 struct sw_flow_key *key,
@@ -566,6 +691,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
566 output_userspace(dp, skb, key, a); 691 output_userspace(dp, skb, key, a);
567 break; 692 break;
568 693
694 case OVS_ACTION_ATTR_HASH:
695 execute_hash(skb, key, a);
696 break;
697
569 case OVS_ACTION_ATTR_PUSH_VLAN: 698 case OVS_ACTION_ATTR_PUSH_VLAN:
570 err = push_vlan(skb, nla_data(a)); 699 err = push_vlan(skb, nla_data(a));
571 if (unlikely(err)) /* skb already freed. */ 700 if (unlikely(err)) /* skb already freed. */
@@ -576,6 +705,17 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
576 err = pop_vlan(skb); 705 err = pop_vlan(skb);
577 break; 706 break;
578 707
708 case OVS_ACTION_ATTR_RECIRC:
709 err = execute_recirc(dp, skb, key, a, rem);
710 if (last_action(a, rem)) {
711 /* If this is the last action, the skb has
712 * been consumed or freed.
713 * Return immediately.
714 */
715 return err;
716 }
717 break;
718
579 case OVS_ACTION_ATTR_SET: 719 case OVS_ACTION_ATTR_SET:
580 err = execute_set_action(skb, nla_data(a)); 720 err = execute_set_action(skb, nla_data(a));
581 break; 721 break;
@@ -601,12 +741,63 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
601 return 0; 741 return 0;
602} 742}
603 743
744static void process_deferred_actions(struct datapath *dp)
745{
746 struct action_fifo *fifo = this_cpu_ptr(action_fifos);
747
748 /* Do not touch the FIFO in case there is no deferred actions. */
749 if (action_fifo_is_empty(fifo))
750 return;
751
752 /* Finishing executing all deferred actions. */
753 do {
754 struct deferred_action *da = action_fifo_get(fifo);
755 struct sk_buff *skb = da->skb;
756 struct sw_flow_key *key = &da->pkt_key;
757 const struct nlattr *actions = da->actions;
758
759 if (actions)
760 do_execute_actions(dp, skb, key, actions,
761 nla_len(actions));
762 else
763 ovs_dp_process_packet(skb, key);
764 } while (!action_fifo_is_empty(fifo));
765
766 /* Reset FIFO for the next packet. */
767 action_fifo_init(fifo);
768}
769
604/* Execute a list of actions against 'skb'. */ 770/* Execute a list of actions against 'skb'. */
605int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, 771int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
606 struct sw_flow_key *key) 772 struct sw_flow_key *key)
607{ 773{
608 struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); 774 int level = this_cpu_read(exec_actions_level);
775 struct sw_flow_actions *acts;
776 int err;
777
778 acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
779
780 this_cpu_inc(exec_actions_level);
781 err = do_execute_actions(dp, skb, key,
782 acts->actions, acts->actions_len);
783
784 if (!level)
785 process_deferred_actions(dp);
786
787 this_cpu_dec(exec_actions_level);
788 return err;
789}
790
791int action_fifos_init(void)
792{
793 action_fifos = alloc_percpu(struct action_fifo);
794 if (!action_fifos)
795 return -ENOMEM;
609 796
610 return do_execute_actions(dp, skb, key, 797 return 0;
611 acts->actions, acts->actions_len); 798}
799
800void action_fifos_exit(void)
801{
802 free_percpu(action_fifos);
612} 803}
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 7e0819919b8a..16cad14fa81e 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -156,7 +156,7 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex)
156} 156}
157 157
158/* Must be called with rcu_read_lock or ovs_mutex. */ 158/* Must be called with rcu_read_lock or ovs_mutex. */
159static const char *ovs_dp_name(const struct datapath *dp) 159const char *ovs_dp_name(const struct datapath *dp)
160{ 160{
161 struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL); 161 struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
162 return vport->ops->get_name(vport); 162 return vport->ops->get_name(vport);
@@ -2065,10 +2065,14 @@ static int __init dp_init(void)
2065 2065
2066 pr_info("Open vSwitch switching datapath\n"); 2066 pr_info("Open vSwitch switching datapath\n");
2067 2067
2068 err = ovs_internal_dev_rtnl_link_register(); 2068 err = action_fifos_init();
2069 if (err) 2069 if (err)
2070 goto error; 2070 goto error;
2071 2071
2072 err = ovs_internal_dev_rtnl_link_register();
2073 if (err)
2074 goto error_action_fifos_exit;
2075
2072 err = ovs_flow_init(); 2076 err = ovs_flow_init();
2073 if (err) 2077 if (err)
2074 goto error_unreg_rtnl_link; 2078 goto error_unreg_rtnl_link;
@@ -2101,6 +2105,8 @@ error_flow_exit:
2101 ovs_flow_exit(); 2105 ovs_flow_exit();
2102error_unreg_rtnl_link: 2106error_unreg_rtnl_link:
2103 ovs_internal_dev_rtnl_link_unregister(); 2107 ovs_internal_dev_rtnl_link_unregister();
2108error_action_fifos_exit:
2109 action_fifos_exit();
2104error: 2110error:
2105 return err; 2111 return err;
2106} 2112}
@@ -2114,6 +2120,7 @@ static void dp_cleanup(void)
2114 ovs_vport_exit(); 2120 ovs_vport_exit();
2115 ovs_flow_exit(); 2121 ovs_flow_exit();
2116 ovs_internal_dev_rtnl_link_unregister(); 2122 ovs_internal_dev_rtnl_link_unregister();
2123 action_fifos_exit();
2117} 2124}
2118 2125
2119module_init(dp_init); 2126module_init(dp_init);
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 25b0e888cb27..ac3f3df96961 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007-2012 Nicira, Inc. 2 * Copyright (c) 2007-2014 Nicira, Inc.
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -189,13 +189,18 @@ void ovs_dp_detach_port(struct vport *);
189int ovs_dp_upcall(struct datapath *, struct sk_buff *, 189int ovs_dp_upcall(struct datapath *, struct sk_buff *,
190 const struct dp_upcall_info *); 190 const struct dp_upcall_info *);
191 191
192const char *ovs_dp_name(const struct datapath *dp);
192struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, 193struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
193 u8 cmd); 194 u8 cmd);
194 195
195int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, 196int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
196 struct sw_flow_key *); 197 struct sw_flow_key *);
198
197void ovs_dp_notify_wq(struct work_struct *work); 199void ovs_dp_notify_wq(struct work_struct *work);
198 200
201int action_fifos_init(void);
202void action_fifos_exit(void);
203
199#define OVS_NLERR(fmt, ...) \ 204#define OVS_NLERR(fmt, ...) \
200do { \ 205do { \
201 if (net_ratelimit()) \ 206 if (net_ratelimit()) \
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index bf8442071d75..4010423f2831 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007-2013 Nicira, Inc. 2 * Copyright (c) 2007-2014 Nicira, Inc.
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -606,6 +606,11 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
606 return 0; 606 return 0;
607} 607}
608 608
609int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
610{
611 return key_extract(skb, key);
612}
613
609int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key, 614int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key,
610 struct sk_buff *skb, struct sw_flow_key *key) 615 struct sk_buff *skb, struct sw_flow_key *key)
611{ 616{
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 3869a540365c..0f5db4ec565d 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -72,6 +72,8 @@ struct sw_flow_key {
72 u32 skb_mark; /* SKB mark. */ 72 u32 skb_mark; /* SKB mark. */
73 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ 73 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
74 } __packed phy; /* Safe when right after 'tun_key'. */ 74 } __packed phy; /* Safe when right after 'tun_key'. */
75 u32 ovs_flow_hash; /* Datapath computed hash value. */
76 u32 recirc_id; /* Recirculation ID. */
75 struct { 77 struct {
76 u8 src[ETH_ALEN]; /* Ethernet source address. */ 78 u8 src[ETH_ALEN]; /* Ethernet source address. */
77 u8 dst[ETH_ALEN]; /* Ethernet destination address. */ 79 u8 dst[ETH_ALEN]; /* Ethernet destination address. */
@@ -187,6 +189,7 @@ void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
187void ovs_flow_stats_clear(struct sw_flow *); 189void ovs_flow_stats_clear(struct sw_flow *);
188u64 ovs_flow_used_time(unsigned long flow_jiffies); 190u64 ovs_flow_used_time(unsigned long flow_jiffies);
189 191
192int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key);
190int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key, 193int ovs_flow_key_extract(struct ovs_key_ipv4_tunnel *tun_key,
191 struct sk_buff *skb, struct sw_flow_key *key); 194 struct sk_buff *skb, struct sw_flow_key *key);
192/* Extract key from packet coming from userspace. */ 195/* Extract key from packet coming from userspace. */
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 630b320fbf3e..f4c8daa73965 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007-2013 Nicira, Inc. 2 * Copyright (c) 2007-2014 Nicira, Inc.
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -251,6 +251,8 @@ static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
251 [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), 251 [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),
252 [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), 252 [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
253 [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd), 253 [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
254 [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32),
255 [OVS_KEY_ATTR_DP_HASH] = sizeof(u32),
254 [OVS_KEY_ATTR_TUNNEL] = -1, 256 [OVS_KEY_ATTR_TUNNEL] = -1,
255}; 257};
256 258
@@ -454,6 +456,20 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
454static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, 456static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
455 const struct nlattr **a, bool is_mask) 457 const struct nlattr **a, bool is_mask)
456{ 458{
459 if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
460 u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
461
462 SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
463 *attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH);
464 }
465
466 if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) {
467 u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
468
469 SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
470 *attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID);
471 }
472
457 if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) { 473 if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {
458 SW_FLOW_KEY_PUT(match, phy.priority, 474 SW_FLOW_KEY_PUT(match, phy.priority,
459 nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask); 475 nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
@@ -873,6 +889,12 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey,
873 struct nlattr *nla, *encap; 889 struct nlattr *nla, *encap;
874 bool is_mask = (swkey != output); 890 bool is_mask = (swkey != output);
875 891
892 if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id))
893 goto nla_put_failure;
894
895 if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
896 goto nla_put_failure;
897
876 if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) 898 if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
877 goto nla_put_failure; 899 goto nla_put_failure;
878 900
@@ -1401,11 +1423,13 @@ int ovs_nla_copy_actions(const struct nlattr *attr,
1401 /* Expected argument lengths, (u32)-1 for variable length. */ 1423 /* Expected argument lengths, (u32)-1 for variable length. */
1402 static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { 1424 static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
1403 [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32), 1425 [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
1426 [OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
1404 [OVS_ACTION_ATTR_USERSPACE] = (u32)-1, 1427 [OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
1405 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), 1428 [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
1406 [OVS_ACTION_ATTR_POP_VLAN] = 0, 1429 [OVS_ACTION_ATTR_POP_VLAN] = 0,
1407 [OVS_ACTION_ATTR_SET] = (u32)-1, 1430 [OVS_ACTION_ATTR_SET] = (u32)-1,
1408 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1 1431 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
1432 [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
1409 }; 1433 };
1410 const struct ovs_action_push_vlan *vlan; 1434 const struct ovs_action_push_vlan *vlan;
1411 int type = nla_type(a); 1435 int type = nla_type(a);
@@ -1432,6 +1456,18 @@ int ovs_nla_copy_actions(const struct nlattr *attr,
1432 return -EINVAL; 1456 return -EINVAL;
1433 break; 1457 break;
1434 1458
1459 case OVS_ACTION_ATTR_HASH: {
1460 const struct ovs_action_hash *act_hash = nla_data(a);
1461
1462 switch (act_hash->hash_alg) {
1463 case OVS_HASH_ALG_L4:
1464 break;
1465 default:
1466 return -EINVAL;
1467 }
1468
1469 break;
1470 }
1435 1471
1436 case OVS_ACTION_ATTR_POP_VLAN: 1472 case OVS_ACTION_ATTR_POP_VLAN:
1437 break; 1473 break;
@@ -1444,6 +1480,9 @@ int ovs_nla_copy_actions(const struct nlattr *attr,
1444 return -EINVAL; 1480 return -EINVAL;
1445 break; 1481 break;
1446 1482
1483 case OVS_ACTION_ATTR_RECIRC:
1484 break;
1485
1447 case OVS_ACTION_ATTR_SET: 1486 case OVS_ACTION_ATTR_SET:
1448 err = validate_set(a, key, sfa, &skip_copy); 1487 err = validate_set(a, key, sfa, &skip_copy);
1449 if (err) 1488 if (err)