X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Factions.c;h=5871d823161d7da5374f3bb22df1beb0180924fd;hb=28c5588e8e1a8d091c5d2275232c35f2968a97fa;hp=0b66e7c6eff37ac833fb786d25b1aa6368abe5a4;hpb=982a47eceac1be710f354b2083aff488e224cbb8;p=sliver-openvswitch.git diff --git a/datapath/actions.c b/datapath/actions.c index 0b66e7c6e..5871d8231 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2013 Nicira, Inc. + * Copyright (c) 2007-2014 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -460,6 +460,21 @@ static int sample(struct datapath *dp, struct sk_buff *skb, nla_len(acts_list), true); } +static void execute_hash(struct sk_buff *skb, const struct nlattr *attr) +{ + struct sw_flow_key *key = OVS_CB(skb)->pkt_key; + struct ovs_action_hash *hash_act = nla_data(attr); + u32 hash = 0; + + /* OVS_HASH_ALG_L4 is the only possible hash algorithm. */ + hash = skb_get_rxhash(skb); + hash = jhash_1word(hash, hash_act->hash_basis); + if (!hash) + hash = 0x1; + + key->ovs_flow_hash = hash; +} + static int execute_set_action(struct sk_buff *skb, const struct nlattr *nested_attr) { @@ -506,6 +521,26 @@ static int execute_set_action(struct sk_buff *skb, return err; } +static int execute_recirc(struct datapath *dp, struct sk_buff *skb, + const struct nlattr *a) +{ + struct sw_flow_key recirc_key; + const struct vport *p = OVS_CB(skb)->input_vport; + uint32_t hash = OVS_CB(skb)->pkt_key->ovs_flow_hash; + int err; + + err = ovs_flow_extract(skb, p->port_no, &recirc_key); + if (err) + return err; + + recirc_key.ovs_flow_hash = hash; + recirc_key.recirc_id = nla_get_u32(a); + + ovs_dp_process_packet_with_key(skb, &recirc_key); + + return 0; +} + /* Execute a list of actions against 'skb'. */ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, const struct nlattr *attr, int len, bool keep_skb) @@ -536,6 +571,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, output_userspace(dp, skb, a); break; + case OVS_ACTION_ATTR_HASH: + execute_hash(skb, a); + break; + case OVS_ACTION_ATTR_PUSH_VLAN: err = push_vlan(skb, nla_data(a)); if (unlikely(err)) /* skb already freed. */ @@ -546,12 +585,31 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, err = pop_vlan(skb); break; + case OVS_ACTION_ATTR_RECIRC: { + struct sk_buff *recirc_skb; + const bool last_action = (a->nla_len == rem); + + if (!last_action || keep_skb) + recirc_skb = skb_clone(skb, GFP_ATOMIC); + else + recirc_skb = skb; + + err = execute_recirc(dp, recirc_skb, a); + + if (last_action || err) + return err; + + break; + } + case OVS_ACTION_ATTR_SET: err = execute_set_action(skb, nla_data(a)); break; case OVS_ACTION_ATTR_SAMPLE: err = sample(dp, skb, a); + if (unlikely(err)) /* skb already freed. */ + return err; break; }