diff options
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/actions.c | 50 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 55 | ||||
-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 | 101 | ||||
-rw-r--r-- | net/openvswitch/vport.h | 27 |
8 files changed, 224 insertions, 42 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index e70d8b18e962..fe5cda0deb39 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -38,7 +38,7 @@ | |||
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 | { |
@@ -434,11 +434,17 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
434 | return ovs_dp_upcall(dp, skb, &upcall); | 434 | return ovs_dp_upcall(dp, skb, &upcall); |
435 | } | 435 | } |
436 | 436 | ||
437 | static bool last_action(const struct nlattr *a, int rem) | ||
438 | { | ||
439 | return a->nla_len == rem; | ||
440 | } | ||
441 | |||
437 | static int sample(struct datapath *dp, struct sk_buff *skb, | 442 | static int sample(struct datapath *dp, struct sk_buff *skb, |
438 | const struct nlattr *attr) | 443 | const struct nlattr *attr) |
439 | { | 444 | { |
440 | const struct nlattr *acts_list = NULL; | 445 | const struct nlattr *acts_list = NULL; |
441 | const struct nlattr *a; | 446 | const struct nlattr *a; |
447 | struct sk_buff *sample_skb; | ||
442 | int rem; | 448 | int rem; |
443 | 449 | ||
444 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; | 450 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; |
@@ -455,8 +461,34 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
455 | } | 461 | } |
456 | } | 462 | } |
457 | 463 | ||
458 | return do_execute_actions(dp, skb, nla_data(acts_list), | 464 | rem = nla_len(acts_list); |
459 | nla_len(acts_list), true); | 465 | a = nla_data(acts_list); |
466 | |||
467 | /* Actions list is either empty or only contains a single user-space | ||
468 | * action, the latter being a special case as it is the only known | ||
469 | * usage of the sample action. | ||
470 | * In these special cases don't clone the skb as there are no | ||
471 | * side-effects in the nested actions. | ||
472 | * Otherwise, clone in case the nested actions have side effects. | ||
473 | */ | ||
474 | if (likely(rem == 0 || (nla_type(a) == OVS_ACTION_ATTR_USERSPACE && | ||
475 | last_action(a, rem)))) { | ||
476 | sample_skb = skb; | ||
477 | skb_get(skb); | ||
478 | } else { | ||
479 | sample_skb = skb_clone(skb, GFP_ATOMIC); | ||
480 | if (!sample_skb) /* Skip sample action when out of memory. */ | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | /* Note that do_execute_actions() never consumes skb. | ||
485 | * In the case where skb has been cloned above it is the clone that | ||
486 | * is consumed. Otherwise the skb_get(skb) call prevents | ||
487 | * consumption by do_execute_actions(). Thus, it is safe to simply | ||
488 | * return the error code and let the caller (also | ||
489 | * do_execute_actions()) free skb on error. | ||
490 | */ | ||
491 | return do_execute_actions(dp, sample_skb, a, rem); | ||
460 | } | 492 | } |
461 | 493 | ||
462 | static int execute_set_action(struct sk_buff *skb, | 494 | static int execute_set_action(struct sk_buff *skb, |
@@ -507,7 +539,7 @@ static int execute_set_action(struct sk_buff *skb, | |||
507 | 539 | ||
508 | /* Execute a list of actions against 'skb'. */ | 540 | /* Execute a list of actions against 'skb'. */ |
509 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | 541 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
510 | const struct nlattr *attr, int len, bool keep_skb) | 542 | const struct nlattr *attr, int len) |
511 | { | 543 | { |
512 | /* Every output action needs a separate clone of 'skb', but the common | 544 | /* 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 | 545 | * case is just a single output action, so that doing a clone and |
@@ -562,12 +594,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
562 | } | 594 | } |
563 | } | 595 | } |
564 | 596 | ||
565 | if (prev_port != -1) { | 597 | if (prev_port != -1) |
566 | if (keep_skb) | ||
567 | skb = skb_clone(skb, GFP_ATOMIC); | ||
568 | |||
569 | do_output(dp, skb, prev_port); | 598 | do_output(dp, skb, prev_port); |
570 | } else if (!keep_skb) | 599 | else |
571 | consume_skb(skb); | 600 | consume_skb(skb); |
572 | 601 | ||
573 | return 0; | 602 | return 0; |
@@ -579,6 +608,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); | 608 | struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); |
580 | 609 | ||
581 | OVS_CB(skb)->tun_key = NULL; | 610 | OVS_CB(skb)->tun_key = NULL; |
582 | return do_execute_actions(dp, skb, acts->actions, | 611 | return do_execute_actions(dp, skb, acts->actions, acts->actions_len); |
583 | acts->actions_len, false); | ||
584 | } | 612 | } |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9db4bf6740d1..7ad3f029baae 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -66,16 +66,16 @@ static struct genl_family dp_packet_genl_family; | |||
66 | static struct genl_family dp_flow_genl_family; | 66 | static struct genl_family dp_flow_genl_family; |
67 | static struct genl_family dp_datapath_genl_family; | 67 | static struct genl_family dp_datapath_genl_family; |
68 | 68 | ||
69 | static struct genl_multicast_group ovs_dp_flow_multicast_group = { | 69 | static const struct genl_multicast_group ovs_dp_flow_multicast_group = { |
70 | .name = OVS_FLOW_MCGROUP | 70 | .name = OVS_FLOW_MCGROUP, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static struct genl_multicast_group ovs_dp_datapath_multicast_group = { | 73 | static const struct genl_multicast_group ovs_dp_datapath_multicast_group = { |
74 | .name = OVS_DATAPATH_MCGROUP | 74 | .name = OVS_DATAPATH_MCGROUP, |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct genl_multicast_group ovs_dp_vport_multicast_group = { | 77 | static const struct genl_multicast_group ovs_dp_vport_multicast_group = { |
78 | .name = OVS_VPORT_MCGROUP | 78 | .name = OVS_VPORT_MCGROUP, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /* Check if need to build a reply message. | 81 | /* Check if need to build a reply message. |
@@ -266,7 +266,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
266 | upcall.cmd = OVS_PACKET_CMD_MISS; | 266 | upcall.cmd = OVS_PACKET_CMD_MISS; |
267 | upcall.key = &key; | 267 | upcall.key = &key; |
268 | upcall.userdata = NULL; | 268 | upcall.userdata = NULL; |
269 | upcall.portid = p->upcall_portid; | 269 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); |
270 | ovs_dp_upcall(dp, skb, &upcall); | 270 | ovs_dp_upcall(dp, skb, &upcall); |
271 | consume_skb(skb); | 271 | consume_skb(skb); |
272 | stats_counter = &stats->n_missed; | 272 | stats_counter = &stats->n_missed; |
@@ -464,7 +464,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
464 | upcall->dp_ifindex = dp_ifindex; | 464 | upcall->dp_ifindex = dp_ifindex; |
465 | 465 | ||
466 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 466 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); |
467 | ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); | 467 | err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); |
468 | BUG_ON(err); | ||
468 | nla_nest_end(user_skb, nla); | 469 | nla_nest_end(user_skb, nla); |
469 | 470 | ||
470 | if (upcall_info->userdata) | 471 | if (upcall_info->userdata) |
@@ -780,7 +781,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, | |||
780 | 781 | ||
781 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, | 782 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, |
782 | always); | 783 | always); |
783 | if (!skb || IS_ERR(skb)) | 784 | if (IS_ERR_OR_NULL(skb)) |
784 | return skb; | 785 | return skb; |
785 | 786 | ||
786 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, | 787 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, |
@@ -1189,7 +1190,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { | |||
1189 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, | 1190 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, |
1190 | }; | 1191 | }; |
1191 | 1192 | ||
1192 | static struct genl_ops dp_flow_genl_ops[] = { | 1193 | static const struct genl_ops dp_flow_genl_ops[] = { |
1193 | { .cmd = OVS_FLOW_CMD_NEW, | 1194 | { .cmd = OVS_FLOW_CMD_NEW, |
1194 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1195 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1195 | .policy = flow_policy, | 1196 | .policy = flow_policy, |
@@ -1373,7 +1374,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
1373 | parms.options = NULL; | 1374 | parms.options = NULL; |
1374 | parms.dp = dp; | 1375 | parms.dp = dp; |
1375 | parms.port_no = OVSP_LOCAL; | 1376 | parms.port_no = OVSP_LOCAL; |
1376 | parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); | 1377 | parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID]; |
1377 | 1378 | ||
1378 | ovs_dp_change(dp, a); | 1379 | ovs_dp_change(dp, a); |
1379 | 1380 | ||
@@ -1577,7 +1578,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { | |||
1577 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, | 1578 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, |
1578 | }; | 1579 | }; |
1579 | 1580 | ||
1580 | static struct genl_ops dp_datapath_genl_ops[] = { | 1581 | static const struct genl_ops dp_datapath_genl_ops[] = { |
1581 | { .cmd = OVS_DP_CMD_NEW, | 1582 | { .cmd = OVS_DP_CMD_NEW, |
1582 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1583 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1583 | .policy = datapath_policy, | 1584 | .policy = datapath_policy, |
@@ -1632,8 +1633,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
1632 | 1633 | ||
1633 | if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || | 1634 | 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) || | 1635 | 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)) || | 1636 | nla_put_string(skb, OVS_VPORT_ATTR_NAME, |
1636 | nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_portid)) | 1637 | vport->ops->get_name(vport))) |
1637 | goto nla_put_failure; | 1638 | goto nla_put_failure; |
1638 | 1639 | ||
1639 | ovs_vport_get_stats(vport, &vport_stats); | 1640 | ovs_vport_get_stats(vport, &vport_stats); |
@@ -1641,6 +1642,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
1641 | &vport_stats)) | 1642 | &vport_stats)) |
1642 | goto nla_put_failure; | 1643 | goto nla_put_failure; |
1643 | 1644 | ||
1645 | if (ovs_vport_get_upcall_portids(vport, skb)) | ||
1646 | goto nla_put_failure; | ||
1647 | |||
1644 | err = ovs_vport_get_options(vport, skb); | 1648 | err = ovs_vport_get_options(vport, skb); |
1645 | if (err == -EMSGSIZE) | 1649 | if (err == -EMSGSIZE) |
1646 | goto error; | 1650 | goto error; |
@@ -1762,7 +1766,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
1762 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; | 1766 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; |
1763 | parms.dp = dp; | 1767 | parms.dp = dp; |
1764 | parms.port_no = port_no; | 1768 | parms.port_no = port_no; |
1765 | parms.upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1769 | parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID]; |
1766 | 1770 | ||
1767 | vport = new_vport(&parms); | 1771 | vport = new_vport(&parms); |
1768 | err = PTR_ERR(vport); | 1772 | err = PTR_ERR(vport); |
@@ -1812,8 +1816,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
1812 | goto exit_unlock_free; | 1816 | goto exit_unlock_free; |
1813 | } | 1817 | } |
1814 | 1818 | ||
1815 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) | 1819 | |
1816 | vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1820 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) { |
1821 | struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID]; | ||
1822 | |||
1823 | err = ovs_vport_set_upcall_portids(vport, ids); | ||
1824 | if (err) | ||
1825 | goto exit_unlock_free; | ||
1826 | } | ||
1817 | 1827 | ||
1818 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, | 1828 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, |
1819 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); | 1829 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); |
@@ -1944,7 +1954,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { | |||
1944 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, | 1954 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, |
1945 | }; | 1955 | }; |
1946 | 1956 | ||
1947 | static struct genl_ops dp_vport_genl_ops[] = { | 1957 | static const struct genl_ops dp_vport_genl_ops[] = { |
1948 | { .cmd = OVS_VPORT_CMD_NEW, | 1958 | { .cmd = OVS_VPORT_CMD_NEW, |
1949 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1959 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
1950 | .policy = vport_policy, | 1960 | .policy = vport_policy, |
@@ -2053,10 +2063,14 @@ static int __init dp_init(void) | |||
2053 | 2063 | ||
2054 | pr_info("Open vSwitch switching datapath\n"); | 2064 | pr_info("Open vSwitch switching datapath\n"); |
2055 | 2065 | ||
2056 | err = ovs_flow_init(); | 2066 | err = ovs_internal_dev_rtnl_link_register(); |
2057 | if (err) | 2067 | if (err) |
2058 | goto error; | 2068 | goto error; |
2059 | 2069 | ||
2070 | err = ovs_flow_init(); | ||
2071 | if (err) | ||
2072 | goto error_unreg_rtnl_link; | ||
2073 | |||
2060 | err = ovs_vport_init(); | 2074 | err = ovs_vport_init(); |
2061 | if (err) | 2075 | if (err) |
2062 | goto error_flow_exit; | 2076 | goto error_flow_exit; |
@@ -2083,6 +2097,8 @@ error_vport_exit: | |||
2083 | ovs_vport_exit(); | 2097 | ovs_vport_exit(); |
2084 | error_flow_exit: | 2098 | error_flow_exit: |
2085 | ovs_flow_exit(); | 2099 | ovs_flow_exit(); |
2100 | error_unreg_rtnl_link: | ||
2101 | ovs_internal_dev_rtnl_link_unregister(); | ||
2086 | error: | 2102 | error: |
2087 | return err; | 2103 | return err; |
2088 | } | 2104 | } |
@@ -2095,6 +2111,7 @@ static void dp_cleanup(void) | |||
2095 | rcu_barrier(); | 2111 | rcu_barrier(); |
2096 | ovs_vport_exit(); | 2112 | ovs_vport_exit(); |
2097 | ovs_flow_exit(); | 2113 | ovs_flow_exit(); |
2114 | ovs_internal_dev_rtnl_link_unregister(); | ||
2098 | } | 2115 | } |
2099 | 2116 | ||
2100 | module_init(dp_init); | 2117 | 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..702fb21bfe15 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -134,10 +134,12 @@ 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 | return ERR_PTR(-EINVAL); | ||
142 | |||
141 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); | 143 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); |
142 | if (!vport->percpu_stats) { | 144 | if (!vport->percpu_stats) { |
143 | kfree(vport); | 145 | kfree(vport); |
@@ -161,6 +163,10 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
161 | */ | 163 | */ |
162 | void ovs_vport_free(struct vport *vport) | 164 | void ovs_vport_free(struct vport *vport) |
163 | { | 165 | { |
166 | /* vport is freed from RCU callback or error path, Therefore | ||
167 | * it is safe to use raw dereference. | ||
168 | */ | ||
169 | kfree(rcu_dereference_raw(vport->upcall_portids)); | ||
164 | free_percpu(vport->percpu_stats); | 170 | free_percpu(vport->percpu_stats); |
165 | kfree(vport); | 171 | kfree(vport); |
166 | } | 172 | } |
@@ -327,6 +333,99 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) | |||
327 | } | 333 | } |
328 | 334 | ||
329 | /** | 335 | /** |
336 | * ovs_vport_set_upcall_portids - set upcall portids of @vport. | ||
337 | * | ||
338 | * @vport: vport to modify. | ||
339 | * @ids: new configuration, an array of port ids. | ||
340 | * | ||
341 | * Sets the vport's upcall_portids to @ids. | ||
342 | * | ||
343 | * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed | ||
344 | * as an array of U32. | ||
345 | * | ||
346 | * Must be called with ovs_mutex. | ||
347 | */ | ||
348 | int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids) | ||
349 | { | ||
350 | struct vport_portids *old, *vport_portids; | ||
351 | |||
352 | if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) | ||
353 | return -EINVAL; | ||
354 | |||
355 | old = ovsl_dereference(vport->upcall_portids); | ||
356 | |||
357 | vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), | ||
358 | GFP_KERNEL); | ||
359 | if (!vport_portids) | ||
360 | return -ENOMEM; | ||
361 | |||
362 | vport_portids->n_ids = nla_len(ids) / sizeof(u32); | ||
363 | vport_portids->rn_ids = reciprocal_value(vport_portids->n_ids); | ||
364 | nla_memcpy(vport_portids->ids, ids, nla_len(ids)); | ||
365 | |||
366 | rcu_assign_pointer(vport->upcall_portids, vport_portids); | ||
367 | |||
368 | if (old) | ||
369 | kfree_rcu(old, rcu); | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * ovs_vport_get_upcall_portids - get the upcall_portids of @vport. | ||
375 | * | ||
376 | * @vport: vport from which to retrieve the portids. | ||
377 | * @skb: sk_buff where portids should be appended. | ||
378 | * | ||
379 | * Retrieves the configuration of the given vport, appending the | ||
380 | * %OVS_VPORT_ATTR_UPCALL_PID attribute which is the array of upcall | ||
381 | * portids to @skb. | ||
382 | * | ||
383 | * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room. | ||
384 | * If an error occurs, @skb is left unmodified. Must be called with | ||
385 | * ovs_mutex or rcu_read_lock. | ||
386 | */ | ||
387 | int ovs_vport_get_upcall_portids(const struct vport *vport, | ||
388 | struct sk_buff *skb) | ||
389 | { | ||
390 | struct vport_portids *ids; | ||
391 | |||
392 | ids = rcu_dereference_ovsl(vport->upcall_portids); | ||
393 | |||
394 | if (vport->dp->user_features & OVS_DP_F_VPORT_PIDS) | ||
395 | return nla_put(skb, OVS_VPORT_ATTR_UPCALL_PID, | ||
396 | ids->n_ids * sizeof(u32), (void *)ids->ids); | ||
397 | else | ||
398 | return nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, ids->ids[0]); | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * ovs_vport_find_upcall_portid - find the upcall portid to send upcall. | ||
403 | * | ||
404 | * @vport: vport from which the missed packet is received. | ||
405 | * @skb: skb that the missed packet was received. | ||
406 | * | ||
407 | * Uses the skb_get_hash() to select the upcall portid to send the | ||
408 | * upcall. | ||
409 | * | ||
410 | * Returns the portid of the target socket. Must be called with rcu_read_lock. | ||
411 | */ | ||
412 | u32 ovs_vport_find_upcall_portid(const struct vport *p, struct sk_buff *skb) | ||
413 | { | ||
414 | struct vport_portids *ids; | ||
415 | u32 ids_index; | ||
416 | u32 hash; | ||
417 | |||
418 | ids = rcu_dereference(p->upcall_portids); | ||
419 | |||
420 | if (ids->n_ids == 1 && ids->ids[0] == 0) | ||
421 | return 0; | ||
422 | |||
423 | hash = skb_get_hash(skb); | ||
424 | ids_index = hash - ids->n_ids * reciprocal_divide(hash, ids->rn_ids); | ||
425 | return ids->ids[ids_index]; | ||
426 | } | ||
427 | |||
428 | /** | ||
330 | * ovs_vport_receive - pass up received packet to the datapath for processing | 429 | * ovs_vport_receive - pass up received packet to the datapath for processing |
331 | * | 430 | * |
332 | * @vport: vport that received the packet | 431 | * @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 | /** |