diff options
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/actions.c | 55 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 77 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 2 | ||||
-rw-r--r-- | net/openvswitch/vport-internal_dev.c | 24 | ||||
-rw-r--r-- | net/openvswitch/vport-internal_dev.h | 2 | ||||
-rw-r--r-- | net/openvswitch/vport-vxlan.c | 5 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 103 | ||||
-rw-r--r-- | net/openvswitch/vport.h | 27 |
8 files changed, 244 insertions, 51 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 | } |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9db4bf6740d1..64dc864a417f 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -47,8 +47,6 @@ | |||
47 | #include <linux/openvswitch.h> | 47 | #include <linux/openvswitch.h> |
48 | #include <linux/rculist.h> | 48 | #include <linux/rculist.h> |
49 | #include <linux/dmi.h> | 49 | #include <linux/dmi.h> |
50 | #include <linux/genetlink.h> | ||
51 | #include <net/genetlink.h> | ||
52 | #include <net/genetlink.h> | 50 | #include <net/genetlink.h> |
53 | #include <net/net_namespace.h> | 51 | #include <net/net_namespace.h> |
54 | #include <net/netns/generic.h> | 52 | #include <net/netns/generic.h> |
@@ -66,25 +64,26 @@ static struct genl_family dp_packet_genl_family; | |||
66 | static struct genl_family dp_flow_genl_family; | 64 | static struct genl_family dp_flow_genl_family; |
67 | static struct genl_family dp_datapath_genl_family; | 65 | static struct genl_family dp_datapath_genl_family; |
68 | 66 | ||
69 | static struct genl_multicast_group ovs_dp_flow_multicast_group = { | 67 | static const struct genl_multicast_group ovs_dp_flow_multicast_group = { |
70 | .name = OVS_FLOW_MCGROUP | 68 | .name = OVS_FLOW_MCGROUP, |
71 | }; | 69 | }; |
72 | 70 | ||
73 | static struct genl_multicast_group ovs_dp_datapath_multicast_group = { | 71 | static const struct genl_multicast_group ovs_dp_datapath_multicast_group = { |
74 | .name = OVS_DATAPATH_MCGROUP | 72 | .name = OVS_DATAPATH_MCGROUP, |
75 | }; | 73 | }; |
76 | 74 | ||
77 | struct genl_multicast_group ovs_dp_vport_multicast_group = { | 75 | static const struct genl_multicast_group ovs_dp_vport_multicast_group = { |
78 | .name = OVS_VPORT_MCGROUP | 76 | .name = OVS_VPORT_MCGROUP, |
79 | }; | 77 | }; |
80 | 78 | ||
81 | /* Check if need to build a reply message. | 79 | /* Check if need to build a reply message. |
82 | * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */ | 80 | * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */ |
83 | static bool ovs_must_notify(struct genl_info *info, | 81 | static bool ovs_must_notify(struct genl_family *family, struct genl_info *info, |
84 | const struct genl_multicast_group *grp) | 82 | unsigned int group) |
85 | { | 83 | { |
86 | return info->nlhdr->nlmsg_flags & NLM_F_ECHO || | 84 | return info->nlhdr->nlmsg_flags & NLM_F_ECHO || |
87 | netlink_has_listeners(genl_info_net(info)->genl_sock, 0); | 85 | genl_has_listeners(family, genl_info_net(info)->genl_sock, |
86 | group); | ||
88 | } | 87 | } |
89 | 88 | ||
90 | static void ovs_notify(struct genl_family *family, | 89 | static void ovs_notify(struct genl_family *family, |
@@ -266,9 +265,12 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
266 | upcall.cmd = OVS_PACKET_CMD_MISS; | 265 | upcall.cmd = OVS_PACKET_CMD_MISS; |
267 | upcall.key = &key; | 266 | upcall.key = &key; |
268 | upcall.userdata = NULL; | 267 | upcall.userdata = NULL; |
269 | upcall.portid = p->upcall_portid; | 268 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); |
270 | ovs_dp_upcall(dp, skb, &upcall); | 269 | error = ovs_dp_upcall(dp, skb, &upcall); |
271 | consume_skb(skb); | 270 | if (unlikely(error)) |
271 | kfree_skb(skb); | ||
272 | else | ||
273 | consume_skb(skb); | ||
272 | stats_counter = &stats->n_missed; | 274 | stats_counter = &stats->n_missed; |
273 | goto out; | 275 | goto out; |
274 | } | 276 | } |
@@ -406,7 +408,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
406 | { | 408 | { |
407 | struct ovs_header *upcall; | 409 | struct ovs_header *upcall; |
408 | struct sk_buff *nskb = NULL; | 410 | struct sk_buff *nskb = NULL; |
409 | struct sk_buff *user_skb; /* to be queued to userspace */ | 411 | struct sk_buff *user_skb = NULL; /* to be queued to userspace */ |
410 | struct nlattr *nla; | 412 | struct nlattr *nla; |
411 | struct genl_info info = { | 413 | struct genl_info info = { |
412 | .dst_sk = ovs_dp_get_net(dp)->genl_sock, | 414 | .dst_sk = ovs_dp_get_net(dp)->genl_sock, |
@@ -464,7 +466,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
464 | upcall->dp_ifindex = dp_ifindex; | 466 | upcall->dp_ifindex = dp_ifindex; |
465 | 467 | ||
466 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 468 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); |
467 | ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); | 469 | err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); |
470 | BUG_ON(err); | ||
468 | nla_nest_end(user_skb, nla); | 471 | nla_nest_end(user_skb, nla); |
469 | 472 | ||
470 | if (upcall_info->userdata) | 473 | if (upcall_info->userdata) |
@@ -495,9 +498,11 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
495 | ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; | 498 | ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; |
496 | 499 | ||
497 | err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); | 500 | err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid); |
501 | user_skb = NULL; | ||
498 | out: | 502 | out: |
499 | if (err) | 503 | if (err) |
500 | skb_tx_error(skb); | 504 | skb_tx_error(skb); |
505 | kfree_skb(user_skb); | ||
501 | kfree_skb(nskb); | 506 | kfree_skb(nskb); |
502 | return err; | 507 | return err; |
503 | } | 508 | } |
@@ -759,7 +764,7 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *act | |||
759 | { | 764 | { |
760 | struct sk_buff *skb; | 765 | struct sk_buff *skb; |
761 | 766 | ||
762 | if (!always && !ovs_must_notify(info, &ovs_dp_flow_multicast_group)) | 767 | if (!always && !ovs_must_notify(&dp_flow_genl_family, info, 0)) |
763 | return NULL; | 768 | return NULL; |
764 | 769 | ||
765 | skb = genlmsg_new_unicast(ovs_flow_cmd_msg_size(acts), info, GFP_KERNEL); | 770 | skb = genlmsg_new_unicast(ovs_flow_cmd_msg_size(acts), info, GFP_KERNEL); |
@@ -780,7 +785,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, | |||
780 | 785 | ||
781 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, | 786 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, |
782 | always); | 787 | always); |
783 | if (!skb || IS_ERR(skb)) | 788 | if (IS_ERR_OR_NULL(skb)) |
784 | return skb; | 789 | return skb; |
785 | 790 | ||
786 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, | 791 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, |
@@ -1189,7 +1194,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { | |||
1189 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, | 1194 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, |
1190 | }; | 1195 | }; |
1191 | 1196 | ||
1192 | static struct genl_ops dp_flow_genl_ops[] = { | 1197 | static const struct genl_ops dp_flow_genl_ops[] = { |
1193 | { .cmd = OVS_FLOW_CMD_NEW, | 1198 | { .cmd = OVS_FLOW_CMD_NEW, |
1194 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1199 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1195 | .policy = flow_policy, | 1200 | .policy = flow_policy, |
@@ -1373,7 +1378,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
1373 | parms.options = NULL; | 1378 | parms.options = NULL; |
1374 | parms.dp = dp; | 1379 | parms.dp = dp; |
1375 | parms.port_no = OVSP_LOCAL; | 1380 | parms.port_no = OVSP_LOCAL; |
1376 | parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); | 1381 | parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID]; |
1377 | 1382 | ||
1378 | ovs_dp_change(dp, a); | 1383 | ovs_dp_change(dp, a); |
1379 | 1384 | ||
@@ -1577,7 +1582,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { | |||
1577 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, | 1582 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, |
1578 | }; | 1583 | }; |
1579 | 1584 | ||
1580 | static struct genl_ops dp_datapath_genl_ops[] = { | 1585 | static const struct genl_ops dp_datapath_genl_ops[] = { |
1581 | { .cmd = OVS_DP_CMD_NEW, | 1586 | { .cmd = OVS_DP_CMD_NEW, |
1582 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1587 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1583 | .policy = datapath_policy, | 1588 | .policy = datapath_policy, |
@@ -1632,8 +1637,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
1632 | 1637 | ||
1633 | if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || | 1638 | if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || |
1634 | nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || | 1639 | nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || |
1635 | nla_put_string(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport)) || | 1640 | nla_put_string(skb, OVS_VPORT_ATTR_NAME, |
1636 | nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_portid)) | 1641 | vport->ops->get_name(vport))) |
1637 | goto nla_put_failure; | 1642 | goto nla_put_failure; |
1638 | 1643 | ||
1639 | ovs_vport_get_stats(vport, &vport_stats); | 1644 | ovs_vport_get_stats(vport, &vport_stats); |
@@ -1641,6 +1646,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
1641 | &vport_stats)) | 1646 | &vport_stats)) |
1642 | goto nla_put_failure; | 1647 | goto nla_put_failure; |
1643 | 1648 | ||
1649 | if (ovs_vport_get_upcall_portids(vport, skb)) | ||
1650 | goto nla_put_failure; | ||
1651 | |||
1644 | err = ovs_vport_get_options(vport, skb); | 1652 | err = ovs_vport_get_options(vport, skb); |
1645 | if (err == -EMSGSIZE) | 1653 | if (err == -EMSGSIZE) |
1646 | goto error; | 1654 | goto error; |
@@ -1762,7 +1770,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
1762 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; | 1770 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; |
1763 | parms.dp = dp; | 1771 | parms.dp = dp; |
1764 | parms.port_no = port_no; | 1772 | parms.port_no = port_no; |
1765 | parms.upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1773 | parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID]; |
1766 | 1774 | ||
1767 | vport = new_vport(&parms); | 1775 | vport = new_vport(&parms); |
1768 | err = PTR_ERR(vport); | 1776 | err = PTR_ERR(vport); |
@@ -1812,8 +1820,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1812 | goto exit_unlock_free; | 1820 | goto exit_unlock_free; |
1813 | } | 1821 | } |
1814 | 1822 | ||
1815 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) | 1823 | |
1816 | vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1824 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) { |
1825 | struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID]; | ||
1826 | |||
1827 | err = ovs_vport_set_upcall_portids(vport, ids); | ||
1828 | if (err) | ||
1829 | goto exit_unlock_free; | ||
1830 | } | ||
1817 | 1831 | ||
1818 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, | 1832 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, |
1819 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); | 1833 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); |
@@ -1944,7 +1958,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { | |||
1944 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, | 1958 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, |
1945 | }; | 1959 | }; |
1946 | 1960 | ||
1947 | static struct genl_ops dp_vport_genl_ops[] = { | 1961 | static const struct genl_ops dp_vport_genl_ops[] = { |
1948 | { .cmd = OVS_VPORT_CMD_NEW, | 1962 | { .cmd = OVS_VPORT_CMD_NEW, |
1949 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1963 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1950 | .policy = vport_policy, | 1964 | .policy = vport_policy, |
@@ -2053,10 +2067,14 @@ static int __init dp_init(void) | |||
2053 | 2067 | ||
2054 | pr_info("Open vSwitch switching datapath\n"); | 2068 | pr_info("Open vSwitch switching datapath\n"); |
2055 | 2069 | ||
2056 | err = ovs_flow_init(); | 2070 | err = ovs_internal_dev_rtnl_link_register(); |
2057 | if (err) | 2071 | if (err) |
2058 | goto error; | 2072 | goto error; |
2059 | 2073 | ||
2074 | err = ovs_flow_init(); | ||
2075 | if (err) | ||
2076 | goto error_unreg_rtnl_link; | ||
2077 | |||
2060 | err = ovs_vport_init(); | 2078 | err = ovs_vport_init(); |
2061 | if (err) | 2079 | if (err) |
2062 | goto error_flow_exit; | 2080 | goto error_flow_exit; |
@@ -2083,6 +2101,8 @@ error_vport_exit: | |||
2083 | ovs_vport_exit(); | 2101 | ovs_vport_exit(); |
2084 | error_flow_exit: | 2102 | error_flow_exit: |
2085 | ovs_flow_exit(); | 2103 | ovs_flow_exit(); |
2104 | error_unreg_rtnl_link: | ||
2105 | ovs_internal_dev_rtnl_link_unregister(); | ||
2086 | error: | 2106 | error: |
2087 | return err; | 2107 | return err; |
2088 | } | 2108 | } |
@@ -2095,6 +2115,7 @@ static void dp_cleanup(void) | |||
2095 | rcu_barrier(); | 2115 | rcu_barrier(); |
2096 | ovs_vport_exit(); | 2116 | ovs_vport_exit(); |
2097 | ovs_flow_exit(); | 2117 | ovs_flow_exit(); |
2118 | ovs_internal_dev_rtnl_link_unregister(); | ||
2098 | } | 2119 | } |
2099 | 2120 | ||
2100 | module_init(dp_init); | 2121 | module_init(dp_init); |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 7ede507500d7..701b5738c38a 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -144,7 +144,7 @@ int lockdep_ovsl_is_held(void); | |||
144 | #define lockdep_ovsl_is_held() 1 | 144 | #define lockdep_ovsl_is_held() 1 |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | #define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held())) | 147 | #define ASSERT_OVSL() WARN_ON(!lockdep_ovsl_is_held()) |
148 | #define ovsl_dereference(p) \ | 148 | #define ovsl_dereference(p) \ |
149 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) | 149 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) |
150 | #define rcu_dereference_ovsl(p) \ | 150 | #define rcu_dereference_ovsl(p) \ |
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 789af9280e77..84516126e5f3 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <net/dst.h> | 27 | #include <net/dst.h> |
28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
29 | #include <net/rtnetlink.h> | ||
29 | 30 | ||
30 | #include "datapath.h" | 31 | #include "datapath.h" |
31 | #include "vport-internal_dev.h" | 32 | #include "vport-internal_dev.h" |
@@ -121,6 +122,10 @@ static const struct net_device_ops internal_dev_netdev_ops = { | |||
121 | .ndo_get_stats64 = internal_dev_get_stats, | 122 | .ndo_get_stats64 = internal_dev_get_stats, |
122 | }; | 123 | }; |
123 | 124 | ||
125 | static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { | ||
126 | .kind = "openvswitch", | ||
127 | }; | ||
128 | |||
124 | static void do_setup(struct net_device *netdev) | 129 | static void do_setup(struct net_device *netdev) |
125 | { | 130 | { |
126 | ether_setup(netdev); | 131 | ether_setup(netdev); |
@@ -131,14 +136,18 @@ static void do_setup(struct net_device *netdev) | |||
131 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; | 136 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
132 | netdev->destructor = internal_dev_destructor; | 137 | netdev->destructor = internal_dev_destructor; |
133 | netdev->ethtool_ops = &internal_dev_ethtool_ops; | 138 | netdev->ethtool_ops = &internal_dev_ethtool_ops; |
139 | netdev->rtnl_link_ops = &internal_dev_link_ops; | ||
134 | netdev->tx_queue_len = 0; | 140 | netdev->tx_queue_len = 0; |
135 | 141 | ||
136 | netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | | 142 | netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | |
137 | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE; | 143 | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | |
144 | NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL; | ||
138 | 145 | ||
139 | netdev->vlan_features = netdev->features; | 146 | netdev->vlan_features = netdev->features; |
147 | netdev->hw_enc_features = netdev->features; | ||
140 | netdev->features |= NETIF_F_HW_VLAN_CTAG_TX; | 148 | netdev->features |= NETIF_F_HW_VLAN_CTAG_TX; |
141 | netdev->hw_features = netdev->features & ~NETIF_F_LLTX; | 149 | netdev->hw_features = netdev->features & ~NETIF_F_LLTX; |
150 | |||
142 | eth_hw_addr_random(netdev); | 151 | eth_hw_addr_random(netdev); |
143 | } | 152 | } |
144 | 153 | ||
@@ -159,7 +168,8 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
159 | netdev_vport = netdev_vport_priv(vport); | 168 | netdev_vport = netdev_vport_priv(vport); |
160 | 169 | ||
161 | netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), | 170 | netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), |
162 | parms->name, do_setup); | 171 | parms->name, NET_NAME_UNKNOWN, |
172 | do_setup); | ||
163 | if (!netdev_vport->dev) { | 173 | if (!netdev_vport->dev) { |
164 | err = -ENOMEM; | 174 | err = -ENOMEM; |
165 | goto error_free_vport; | 175 | goto error_free_vport; |
@@ -248,3 +258,13 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev) | |||
248 | 258 | ||
249 | return internal_dev_priv(netdev)->vport; | 259 | return internal_dev_priv(netdev)->vport; |
250 | } | 260 | } |
261 | |||
262 | int ovs_internal_dev_rtnl_link_register(void) | ||
263 | { | ||
264 | return rtnl_link_register(&internal_dev_link_ops); | ||
265 | } | ||
266 | |||
267 | void ovs_internal_dev_rtnl_link_unregister(void) | ||
268 | { | ||
269 | rtnl_link_unregister(&internal_dev_link_ops); | ||
270 | } | ||
diff --git a/net/openvswitch/vport-internal_dev.h b/net/openvswitch/vport-internal_dev.h index 9a7d30ecc6a2..1b179a190cff 100644 --- a/net/openvswitch/vport-internal_dev.h +++ b/net/openvswitch/vport-internal_dev.h | |||
@@ -24,5 +24,7 @@ | |||
24 | 24 | ||
25 | int ovs_is_internal_dev(const struct net_device *); | 25 | int ovs_is_internal_dev(const struct net_device *); |
26 | struct vport *ovs_internal_dev_get_vport(struct net_device *); | 26 | struct vport *ovs_internal_dev_get_vport(struct net_device *); |
27 | int ovs_internal_dev_rtnl_link_register(void); | ||
28 | void ovs_internal_dev_rtnl_link_unregister(void); | ||
27 | 29 | ||
28 | #endif /* vport-internal_dev.h */ | 30 | #endif /* vport-internal_dev.h */ |
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 0edbd95c60e7..d8b7e247bebf 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c | |||
@@ -143,8 +143,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
143 | struct rtable *rt; | 143 | struct rtable *rt; |
144 | struct flowi4 fl; | 144 | struct flowi4 fl; |
145 | __be16 src_port; | 145 | __be16 src_port; |
146 | int port_min; | ||
147 | int port_max; | ||
148 | __be16 df; | 146 | __be16 df; |
149 | int err; | 147 | int err; |
150 | 148 | ||
@@ -172,8 +170,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
172 | 170 | ||
173 | skb->ignore_df = 1; | 171 | skb->ignore_df = 1; |
174 | 172 | ||
175 | inet_get_local_port_range(net, &port_min, &port_max); | 173 | src_port = udp_flow_src_port(net, skb, 0, 0, true); |
176 | src_port = vxlan_src_port(port_min, port_max, skb); | ||
177 | 174 | ||
178 | err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, | 175 | err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, |
179 | fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, | 176 | fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 42c0f4a0b78c..6d8f2ec481d9 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -134,10 +134,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
134 | 134 | ||
135 | vport->dp = parms->dp; | 135 | vport->dp = parms->dp; |
136 | vport->port_no = parms->port_no; | 136 | vport->port_no = parms->port_no; |
137 | vport->upcall_portid = parms->upcall_portid; | ||
138 | vport->ops = ops; | 137 | vport->ops = ops; |
139 | INIT_HLIST_NODE(&vport->dp_hash_node); | 138 | INIT_HLIST_NODE(&vport->dp_hash_node); |
140 | 139 | ||
140 | if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) { | ||
141 | kfree(vport); | ||
142 | return ERR_PTR(-EINVAL); | ||
143 | } | ||
144 | |||
141 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); | 145 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); |
142 | if (!vport->percpu_stats) { | 146 | if (!vport->percpu_stats) { |
143 | kfree(vport); | 147 | kfree(vport); |
@@ -161,6 +165,10 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
161 | */ | 165 | */ |
162 | void ovs_vport_free(struct vport *vport) | 166 | void ovs_vport_free(struct vport *vport) |
163 | { | 167 | { |
168 | /* vport is freed from RCU callback or error path, Therefore | ||
169 | * it is safe to use raw dereference. | ||
170 | */ | ||
171 | kfree(rcu_dereference_raw(vport->upcall_portids)); | ||
164 | free_percpu(vport->percpu_stats); | 172 | free_percpu(vport->percpu_stats); |
165 | kfree(vport); | 173 | kfree(vport); |
166 | } | 174 | } |
@@ -327,6 +335,99 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) | |||
327 | } | 335 | } |
328 | 336 | ||
329 | /** | 337 | /** |
338 | * ovs_vport_set_upcall_portids - set upcall portids of @vport. | ||
339 | * | ||
340 | * @vport: vport to modify. | ||
341 | * @ids: new configuration, an array of port ids. | ||
342 | * | ||
343 | * Sets the vport's upcall_portids to @ids. | ||
344 | * | ||
345 | * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed | ||
346 | * as an array of U32. | ||
347 | * | ||
348 | * Must be called with ovs_mutex. | ||
349 | */ | ||
350 | int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids) | ||
351 | { | ||
352 | struct vport_portids *old, *vport_portids; | ||
353 | |||
354 | if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) | ||
355 | return -EINVAL; | ||
356 | |||
357 | old = ovsl_dereference(vport->upcall_portids); | ||
358 | |||
359 | vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), | ||
360 | GFP_KERNEL); | ||
361 | if (!vport_portids) | ||
362 | return -ENOMEM; | ||
363 | |||
364 | vport_portids->n_ids = nla_len(ids) / sizeof(u32); | ||
365 | vport_portids->rn_ids = reciprocal_value(vport_portids->n_ids); | ||
366 | nla_memcpy(vport_portids->ids, ids, nla_len(ids)); | ||
367 | |||
368 | rcu_assign_pointer(vport->upcall_portids, vport_portids); | ||
369 | |||
370 | if (old) | ||
371 | kfree_rcu(old, rcu); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | /** | ||
376 | * ovs_vport_get_upcall_portids - get the upcall_portids of @vport. | ||
377 | * | ||
378 | * @vport: vport from which to retrieve the portids. | ||
379 | * @skb: sk_buff where portids should be appended. | ||
380 | * | ||
381 | * Retrieves the configuration of the given vport, appending the | ||
382 | * %OVS_VPORT_ATTR_UPCALL_PID attribute which is the array of upcall | ||
383 | * portids to @skb. | ||
384 | * | ||
385 | * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room. | ||
386 | * If an error occurs, @skb is left unmodified. Must be called with | ||
387 | * ovs_mutex or rcu_read_lock. | ||
388 | */ | ||
389 | int ovs_vport_get_upcall_portids(const struct vport *vport, | ||
390 | struct sk_buff *skb) | ||
391 | { | ||
392 | struct vport_portids *ids; | ||
393 | |||
394 | ids = rcu_dereference_ovsl(vport->upcall_portids); | ||
395 | |||
396 | if (vport->dp->user_features & OVS_DP_F_VPORT_PIDS) | ||
397 | return nla_put(skb, OVS_VPORT_ATTR_UPCALL_PID, | ||
398 | ids->n_ids * sizeof(u32), (void *)ids->ids); | ||
399 | else | ||
400 | return nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, ids->ids[0]); | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * ovs_vport_find_upcall_portid - find the upcall portid to send upcall. | ||
405 | * | ||
406 | * @vport: vport from which the missed packet is received. | ||
407 | * @skb: skb that the missed packet was received. | ||
408 | * | ||
409 | * Uses the skb_get_hash() to select the upcall portid to send the | ||
410 | * upcall. | ||
411 | * | ||
412 | * Returns the portid of the target socket. Must be called with rcu_read_lock. | ||
413 | */ | ||
414 | u32 ovs_vport_find_upcall_portid(const struct vport *p, struct sk_buff *skb) | ||
415 | { | ||
416 | struct vport_portids *ids; | ||
417 | u32 ids_index; | ||
418 | u32 hash; | ||
419 | |||
420 | ids = rcu_dereference(p->upcall_portids); | ||
421 | |||
422 | if (ids->n_ids == 1 && ids->ids[0] == 0) | ||
423 | return 0; | ||
424 | |||
425 | hash = skb_get_hash(skb); | ||
426 | ids_index = hash - ids->n_ids * reciprocal_divide(hash, ids->rn_ids); | ||
427 | return ids->ids[ids_index]; | ||
428 | } | ||
429 | |||
430 | /** | ||
330 | * ovs_vport_receive - pass up received packet to the datapath for processing | 431 | * ovs_vport_receive - pass up received packet to the datapath for processing |
331 | * | 432 | * |
332 | * @vport: vport that received the packet | 433 | * @vport: vport that received the packet |
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 8d721e62f388..35f89d84b45e 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/netlink.h> | 24 | #include <linux/netlink.h> |
25 | #include <linux/openvswitch.h> | 25 | #include <linux/openvswitch.h> |
26 | #include <linux/reciprocal_div.h> | ||
26 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
28 | #include <linux/u64_stats_sync.h> | 29 | #include <linux/u64_stats_sync.h> |
@@ -52,6 +53,10 @@ void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); | |||
52 | int ovs_vport_set_options(struct vport *, struct nlattr *options); | 53 | int ovs_vport_set_options(struct vport *, struct nlattr *options); |
53 | int ovs_vport_get_options(const struct vport *, struct sk_buff *); | 54 | int ovs_vport_get_options(const struct vport *, struct sk_buff *); |
54 | 55 | ||
56 | int ovs_vport_set_upcall_portids(struct vport *, struct nlattr *pids); | ||
57 | int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); | ||
58 | u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); | ||
59 | |||
55 | int ovs_vport_send(struct vport *, struct sk_buff *); | 60 | int ovs_vport_send(struct vport *, struct sk_buff *); |
56 | 61 | ||
57 | /* The following definitions are for implementers of vport devices: */ | 62 | /* The following definitions are for implementers of vport devices: */ |
@@ -62,13 +67,27 @@ struct vport_err_stats { | |||
62 | u64 tx_dropped; | 67 | u64 tx_dropped; |
63 | u64 tx_errors; | 68 | u64 tx_errors; |
64 | }; | 69 | }; |
70 | /** | ||
71 | * struct vport_portids - array of netlink portids of a vport. | ||
72 | * must be protected by rcu. | ||
73 | * @rn_ids: The reciprocal value of @n_ids. | ||
74 | * @rcu: RCU callback head for deferred destruction. | ||
75 | * @n_ids: Size of @ids array. | ||
76 | * @ids: Array storing the Netlink socket pids to be used for packets received | ||
77 | * on this port that miss the flow table. | ||
78 | */ | ||
79 | struct vport_portids { | ||
80 | struct reciprocal_value rn_ids; | ||
81 | struct rcu_head rcu; | ||
82 | u32 n_ids; | ||
83 | u32 ids[]; | ||
84 | }; | ||
65 | 85 | ||
66 | /** | 86 | /** |
67 | * struct vport - one port within a datapath | 87 | * struct vport - one port within a datapath |
68 | * @rcu: RCU callback head for deferred destruction. | 88 | * @rcu: RCU callback head for deferred destruction. |
69 | * @dp: Datapath to which this port belongs. | 89 | * @dp: Datapath to which this port belongs. |
70 | * @upcall_portid: The Netlink port to use for packets received on this port that | 90 | * @upcall_portids: RCU protected 'struct vport_portids'. |
71 | * miss the flow table. | ||
72 | * @port_no: Index into @dp's @ports array. | 91 | * @port_no: Index into @dp's @ports array. |
73 | * @hash_node: Element in @dev_table hash table in vport.c. | 92 | * @hash_node: Element in @dev_table hash table in vport.c. |
74 | * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. | 93 | * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. |
@@ -80,7 +99,7 @@ struct vport_err_stats { | |||
80 | struct vport { | 99 | struct vport { |
81 | struct rcu_head rcu; | 100 | struct rcu_head rcu; |
82 | struct datapath *dp; | 101 | struct datapath *dp; |
83 | u32 upcall_portid; | 102 | struct vport_portids __rcu *upcall_portids; |
84 | u16 port_no; | 103 | u16 port_no; |
85 | 104 | ||
86 | struct hlist_node hash_node; | 105 | struct hlist_node hash_node; |
@@ -111,7 +130,7 @@ struct vport_parms { | |||
111 | /* For ovs_vport_alloc(). */ | 130 | /* For ovs_vport_alloc(). */ |
112 | struct datapath *dp; | 131 | struct datapath *dp; |
113 | u16 port_no; | 132 | u16 port_no; |
114 | u32 upcall_portid; | 133 | struct nlattr *upcall_portids; |
115 | }; | 134 | }; |
116 | 135 | ||
117 | /** | 136 | /** |