diff options
Diffstat (limited to 'net/openvswitch/actions.c')
-rw-r--r-- | net/openvswitch/actions.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index e70d8b18e962..5231652a95d9 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -38,10 +38,13 @@ | |||
38 | #include "vport.h" | 38 | #include "vport.h" |
39 | 39 | ||
40 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | 40 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
41 | const struct nlattr *attr, int len, bool keep_skb); | 41 | const struct nlattr *attr, int len); |
42 | 42 | ||
43 | static int make_writable(struct sk_buff *skb, int write_len) | 43 | static int make_writable(struct sk_buff *skb, int write_len) |
44 | { | 44 | { |
45 | if (!pskb_may_pull(skb, write_len)) | ||
46 | return -ENOMEM; | ||
47 | |||
45 | if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) | 48 | if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) |
46 | return 0; | 49 | return 0; |
47 | 50 | ||
@@ -70,6 +73,8 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) | |||
70 | 73 | ||
71 | vlan_set_encap_proto(skb, vhdr); | 74 | vlan_set_encap_proto(skb, vhdr); |
72 | skb->mac_header += VLAN_HLEN; | 75 | skb->mac_header += VLAN_HLEN; |
76 | if (skb_network_offset(skb) < ETH_HLEN) | ||
77 | skb_set_network_header(skb, ETH_HLEN); | ||
73 | skb_reset_mac_len(skb); | 78 | skb_reset_mac_len(skb); |
74 | 79 | ||
75 | return 0; | 80 | return 0; |
@@ -434,11 +439,17 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
434 | return ovs_dp_upcall(dp, skb, &upcall); | 439 | return ovs_dp_upcall(dp, skb, &upcall); |
435 | } | 440 | } |
436 | 441 | ||
442 | static bool last_action(const struct nlattr *a, int rem) | ||
443 | { | ||
444 | return a->nla_len == rem; | ||
445 | } | ||
446 | |||
437 | static int sample(struct datapath *dp, struct sk_buff *skb, | 447 | static int sample(struct datapath *dp, struct sk_buff *skb, |
438 | const struct nlattr *attr) | 448 | const struct nlattr *attr) |
439 | { | 449 | { |
440 | const struct nlattr *acts_list = NULL; | 450 | const struct nlattr *acts_list = NULL; |
441 | const struct nlattr *a; | 451 | const struct nlattr *a; |
452 | struct sk_buff *sample_skb; | ||
442 | int rem; | 453 | int rem; |
443 | 454 | ||
444 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; | 455 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; |
@@ -455,8 +466,34 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
455 | } | 466 | } |
456 | } | 467 | } |
457 | 468 | ||
458 | return do_execute_actions(dp, skb, nla_data(acts_list), | 469 | rem = nla_len(acts_list); |
459 | nla_len(acts_list), true); | 470 | a = nla_data(acts_list); |
471 | |||
472 | /* Actions list is either empty or only contains a single user-space | ||
473 | * action, the latter being a special case as it is the only known | ||
474 | * usage of the sample action. | ||
475 | * In these special cases don't clone the skb as there are no | ||
476 | * side-effects in the nested actions. | ||
477 | * Otherwise, clone in case the nested actions have side effects. | ||
478 | */ | ||
479 | if (likely(rem == 0 || (nla_type(a) == OVS_ACTION_ATTR_USERSPACE && | ||
480 | last_action(a, rem)))) { | ||
481 | sample_skb = skb; | ||
482 | skb_get(skb); | ||
483 | } else { | ||
484 | sample_skb = skb_clone(skb, GFP_ATOMIC); | ||
485 | if (!sample_skb) /* Skip sample action when out of memory. */ | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | /* Note that do_execute_actions() never consumes skb. | ||
490 | * In the case where skb has been cloned above it is the clone that | ||
491 | * is consumed. Otherwise the skb_get(skb) call prevents | ||
492 | * consumption by do_execute_actions(). Thus, it is safe to simply | ||
493 | * return the error code and let the caller (also | ||
494 | * do_execute_actions()) free skb on error. | ||
495 | */ | ||
496 | return do_execute_actions(dp, sample_skb, a, rem); | ||
460 | } | 497 | } |
461 | 498 | ||
462 | static int execute_set_action(struct sk_buff *skb, | 499 | static int execute_set_action(struct sk_buff *skb, |
@@ -507,7 +544,7 @@ static int execute_set_action(struct sk_buff *skb, | |||
507 | 544 | ||
508 | /* Execute a list of actions against 'skb'. */ | 545 | /* Execute a list of actions against 'skb'. */ |
509 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | 546 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
510 | const struct nlattr *attr, int len, bool keep_skb) | 547 | const struct nlattr *attr, int len) |
511 | { | 548 | { |
512 | /* Every output action needs a separate clone of 'skb', but the common | 549 | /* Every output action needs a separate clone of 'skb', but the common |
513 | * case is just a single output action, so that doing a clone and | 550 | * case is just a single output action, so that doing a clone and |
@@ -562,12 +599,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
562 | } | 599 | } |
563 | } | 600 | } |
564 | 601 | ||
565 | if (prev_port != -1) { | 602 | if (prev_port != -1) |
566 | if (keep_skb) | ||
567 | skb = skb_clone(skb, GFP_ATOMIC); | ||
568 | |||
569 | do_output(dp, skb, prev_port); | 603 | do_output(dp, skb, prev_port); |
570 | } else if (!keep_skb) | 604 | else |
571 | consume_skb(skb); | 605 | consume_skb(skb); |
572 | 606 | ||
573 | return 0; | 607 | return 0; |
@@ -579,6 +613,5 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) | |||
579 | struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); | 613 | struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); |
580 | 614 | ||
581 | OVS_CB(skb)->tun_key = NULL; | 615 | OVS_CB(skb)->tun_key = NULL; |
582 | return do_execute_actions(dp, skb, acts->actions, | 616 | return do_execute_actions(dp, skb, acts->actions, acts->actions_len); |
583 | acts->actions_len, false); | ||
584 | } | 617 | } |