diff options
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 77 |
1 files changed, 49 insertions, 28 deletions
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); |