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 | } |
