From eb44f89919b3d7a9a9dd7be5e815ecf0acaaca2a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 8 Aug 2012 08:49:40 -0400 Subject: [PATCH] Update team driver from net-next from Jiri Pirko --- kernel.spec | 9 +- team-net-next-20120808.patch | 499 +++++++++++++++++++++++++++++++++++ 2 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 team-net-next-20120808.patch diff --git a/kernel.spec b/kernel.spec index abdac81b9..6d91dd307 100644 --- a/kernel.spec +++ b/kernel.spec @@ -62,7 +62,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 1 +%global baserelease 2 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -654,6 +654,8 @@ Patch100: taint-vbox.patch Patch110: vmbugon-warnon.patch +Patch150: team-net-next-20120808.patch + Patch390: linux-2.6-defaults-acpi-video.patch Patch391: linux-2.6-acpi-video-dos.patch Patch394: linux-2.6-acpi-debug-infinite-loop.patch @@ -1306,6 +1308,8 @@ ApplyPatch taint-vbox.patch ApplyPatch vmbugon-warnon.patch +ApplyPatch team-net-next-20120808.patch + # Architecture patches # x86(-64) @@ -2305,6 +2309,9 @@ fi # ||----w | # || || %changelog +* Wed Aug 08 2012 Josh Boyer - 3.6.0-0.rc1.git2.2 +- Update team driver from net-next from Jiri Pirko + * Tue Aug 07 2012 Josh Boyer - Add support for ppc64p7 subarch diff --git a/team-net-next-20120808.patch b/team-net-next-20120808.patch new file mode 100644 index 000000000..c738a4724 --- /dev/null +++ b/team-net-next-20120808.patch @@ -0,0 +1,499 @@ +Update team driver to latest net-next. + +Split patches available here: +http://people.redhat.com/jpirko/f18_team_update_2/ + +Jiri Pirko (4): + netlink: add signed types + team: add signed 32-bit team option type + team: add per port priority option + team: add support for queue override by setting queue_id for port + + drivers/net/team/team.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++- + include/linux/if_team.h | 7 ++ + include/net/netlink.h | 98 +++++++++++++++++++++++ + 3 files changed, 303 insertions(+), 2 deletions(-) + +Signed-off-by: Jiri Pirko + +diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c +index 87707ab..ba10c46 100644 +--- a/drivers/net/team/team.c ++++ b/drivers/net/team/team.c +@@ -658,6 +658,122 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) + } + + ++/************************************* ++ * Multiqueue Tx port select override ++ *************************************/ ++ ++static int team_queue_override_init(struct team *team) ++{ ++ struct list_head *listarr; ++ unsigned int queue_cnt = team->dev->num_tx_queues - 1; ++ unsigned int i; ++ ++ if (!queue_cnt) ++ return 0; ++ listarr = kmalloc(sizeof(struct list_head) * queue_cnt, GFP_KERNEL); ++ if (!listarr) ++ return -ENOMEM; ++ team->qom_lists = listarr; ++ for (i = 0; i < queue_cnt; i++) ++ INIT_LIST_HEAD(listarr++); ++ return 0; ++} ++ ++static void team_queue_override_fini(struct team *team) ++{ ++ kfree(team->qom_lists); ++} ++ ++static struct list_head *__team_get_qom_list(struct team *team, u16 queue_id) ++{ ++ return &team->qom_lists[queue_id - 1]; ++} ++ ++/* ++ * note: already called with rcu_read_lock ++ */ ++static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb) ++{ ++ struct list_head *qom_list; ++ struct team_port *port; ++ ++ if (!team->queue_override_enabled || !skb->queue_mapping) ++ return false; ++ qom_list = __team_get_qom_list(team, skb->queue_mapping); ++ list_for_each_entry_rcu(port, qom_list, qom_list) { ++ if (!team_dev_queue_xmit(team, port, skb)) ++ return true; ++ } ++ return false; ++} ++ ++static void __team_queue_override_port_del(struct team *team, ++ struct team_port *port) ++{ ++ list_del_rcu(&port->qom_list); ++ synchronize_rcu(); ++ INIT_LIST_HEAD(&port->qom_list); ++} ++ ++static bool team_queue_override_port_has_gt_prio_than(struct team_port *port, ++ struct team_port *cur) ++{ ++ if (port->priority < cur->priority) ++ return true; ++ if (port->priority > cur->priority) ++ return false; ++ if (port->index < cur->index) ++ return true; ++ return false; ++} ++ ++static void __team_queue_override_port_add(struct team *team, ++ struct team_port *port) ++{ ++ struct team_port *cur; ++ struct list_head *qom_list; ++ struct list_head *node; ++ ++ if (!port->queue_id || !team_port_enabled(port)) ++ return; ++ ++ qom_list = __team_get_qom_list(team, port->queue_id); ++ node = qom_list; ++ list_for_each_entry(cur, qom_list, qom_list) { ++ if (team_queue_override_port_has_gt_prio_than(port, cur)) ++ break; ++ node = &cur->qom_list; ++ } ++ list_add_tail_rcu(&port->qom_list, node); ++} ++ ++static void __team_queue_override_enabled_check(struct team *team) ++{ ++ struct team_port *port; ++ bool enabled = false; ++ ++ list_for_each_entry(port, &team->port_list, list) { ++ if (!list_empty(&port->qom_list)) { ++ enabled = true; ++ break; ++ } ++ } ++ if (enabled == team->queue_override_enabled) ++ return; ++ netdev_dbg(team->dev, "%s queue override\n", ++ enabled ? "Enabling" : "Disabling"); ++ team->queue_override_enabled = enabled; ++} ++ ++static void team_queue_override_port_refresh(struct team *team, ++ struct team_port *port) ++{ ++ __team_queue_override_port_del(team, port); ++ __team_queue_override_port_add(team, port); ++ __team_queue_override_enabled_check(team); ++} ++ ++ + /**************** + * Port handling + ****************/ +@@ -688,6 +804,7 @@ static void team_port_enable(struct team *team, + hlist_add_head_rcu(&port->hlist, + team_port_index_hash(team, port->index)); + team_adjust_ops(team); ++ team_queue_override_port_refresh(team, port); + if (team->ops.port_enabled) + team->ops.port_enabled(team, port); + } +@@ -716,6 +833,7 @@ static void team_port_disable(struct team *team, + hlist_del_rcu(&port->hlist); + __reconstruct_port_hlist(team, port->index); + port->index = -1; ++ team_queue_override_port_refresh(team, port); + __team_adjust_ops(team, team->en_port_count - 1); + /* + * Wait until readers see adjusted ops. This ensures that +@@ -881,6 +999,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev) + + port->dev = port_dev; + port->team = team; ++ INIT_LIST_HEAD(&port->qom_list); + + port->orig.mtu = port_dev->mtu; + err = dev_set_mtu(port_dev, dev->mtu); +@@ -1092,6 +1211,49 @@ static int team_user_linkup_en_option_set(struct team *team, + return 0; + } + ++static int team_priority_option_get(struct team *team, ++ struct team_gsetter_ctx *ctx) ++{ ++ struct team_port *port = ctx->info->port; ++ ++ ctx->data.s32_val = port->priority; ++ return 0; ++} ++ ++static int team_priority_option_set(struct team *team, ++ struct team_gsetter_ctx *ctx) ++{ ++ struct team_port *port = ctx->info->port; ++ ++ port->priority = ctx->data.s32_val; ++ team_queue_override_port_refresh(team, port); ++ return 0; ++} ++ ++static int team_queue_id_option_get(struct team *team, ++ struct team_gsetter_ctx *ctx) ++{ ++ struct team_port *port = ctx->info->port; ++ ++ ctx->data.u32_val = port->queue_id; ++ return 0; ++} ++ ++static int team_queue_id_option_set(struct team *team, ++ struct team_gsetter_ctx *ctx) ++{ ++ struct team_port *port = ctx->info->port; ++ ++ if (port->queue_id == ctx->data.u32_val) ++ return 0; ++ if (ctx->data.u32_val >= team->dev->real_num_tx_queues) ++ return -EINVAL; ++ port->queue_id = ctx->data.u32_val; ++ team_queue_override_port_refresh(team, port); ++ return 0; ++} ++ ++ + static const struct team_option team_options[] = { + { + .name = "mode", +@@ -1120,6 +1282,20 @@ static const struct team_option team_options[] = { + .getter = team_user_linkup_en_option_get, + .setter = team_user_linkup_en_option_set, + }, ++ { ++ .name = "priority", ++ .type = TEAM_OPTION_TYPE_S32, ++ .per_port = true, ++ .getter = team_priority_option_get, ++ .setter = team_priority_option_set, ++ }, ++ { ++ .name = "queue_id", ++ .type = TEAM_OPTION_TYPE_U32, ++ .per_port = true, ++ .getter = team_queue_id_option_get, ++ .setter = team_queue_id_option_set, ++ }, + }; + + static struct lock_class_key team_netdev_xmit_lock_key; +@@ -1155,6 +1331,9 @@ static int team_init(struct net_device *dev) + for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) + INIT_HLIST_HEAD(&team->en_port_hlist[i]); + INIT_LIST_HEAD(&team->port_list); ++ err = team_queue_override_init(team); ++ if (err) ++ goto err_team_queue_override_init; + + team_adjust_ops(team); + +@@ -1170,6 +1349,8 @@ static int team_init(struct net_device *dev) + return 0; + + err_options_register: ++ team_queue_override_fini(team); ++err_team_queue_override_init: + free_percpu(team->pcpu_stats); + + return err; +@@ -1187,6 +1368,7 @@ static void team_uninit(struct net_device *dev) + + __team_change_mode(team, NULL); /* cleanup */ + __team_options_unregister(team, team_options, ARRAY_SIZE(team_options)); ++ team_queue_override_fini(team); + mutex_unlock(&team->lock); + } + +@@ -1216,10 +1398,12 @@ static int team_close(struct net_device *dev) + static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct team *team = netdev_priv(dev); +- bool tx_success = false; ++ bool tx_success; + unsigned int len = skb->len; + +- tx_success = team->ops.transmit(team, skb); ++ tx_success = team_queue_override_transmit(team, skb); ++ if (!tx_success) ++ tx_success = team->ops.transmit(team, skb); + if (tx_success) { + struct team_pcpu_stats *pcpu_stats; + +@@ -1787,6 +1971,12 @@ static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team, + nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) + goto nest_cancel; + break; ++ case TEAM_OPTION_TYPE_S32: ++ if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_S32)) ++ goto nest_cancel; ++ if (nla_put_s32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.s32_val)) ++ goto nest_cancel; ++ break; + default: + BUG(); + } +@@ -1975,6 +2165,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) + case NLA_FLAG: + opt_type = TEAM_OPTION_TYPE_BOOL; + break; ++ case NLA_S32: ++ opt_type = TEAM_OPTION_TYPE_S32; ++ break; + default: + goto team_put; + } +@@ -2031,6 +2224,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) + case TEAM_OPTION_TYPE_BOOL: + ctx.data.bool_val = attr_data ? true : false; + break; ++ case TEAM_OPTION_TYPE_S32: ++ ctx.data.s32_val = nla_get_s32(attr_data); ++ break; + default: + BUG(); + } +diff --git a/include/linux/if_team.h b/include/linux/if_team.h +index 6960fc1..33fcc20 100644 +--- a/include/linux/if_team.h ++++ b/include/linux/if_team.h +@@ -67,6 +67,9 @@ struct team_port { + struct netpoll *np; + #endif + ++ s32 priority; /* lower number ~ higher priority */ ++ u16 queue_id; ++ struct list_head qom_list; /* node in queue override mapping list */ + long mode_priv[0]; + }; + +@@ -130,6 +133,7 @@ enum team_option_type { + TEAM_OPTION_TYPE_STRING, + TEAM_OPTION_TYPE_BINARY, + TEAM_OPTION_TYPE_BOOL, ++ TEAM_OPTION_TYPE_S32, + }; + + struct team_option_inst_info { +@@ -146,6 +150,7 @@ struct team_gsetter_ctx { + u32 len; + } bin_val; + bool bool_val; ++ s32 s32_val; + } data; + struct team_option_inst_info *info; + }; +@@ -197,6 +202,8 @@ struct team { + + const struct team_mode *mode; + struct team_mode_ops ops; ++ bool queue_override_enabled; ++ struct list_head *qom_lists; /* array of queue override mapping lists */ + long mode_priv[TEAM_MODE_PRIV_LONGS]; + }; + +diff --git a/include/net/netlink.h b/include/net/netlink.h +index 785f37a..09175d5 100644 +--- a/include/net/netlink.h ++++ b/include/net/netlink.h +@@ -98,6 +98,10 @@ + * nla_put_u16(skb, type, value) add u16 attribute to skb + * nla_put_u32(skb, type, value) add u32 attribute to skb + * nla_put_u64(skb, type, value) add u64 attribute to skb ++ * nla_put_s8(skb, type, value) add s8 attribute to skb ++ * nla_put_s16(skb, type, value) add s16 attribute to skb ++ * nla_put_s32(skb, type, value) add s32 attribute to skb ++ * nla_put_s64(skb, type, value) add s64 attribute to skb + * nla_put_string(skb, type, str) add string attribute to skb + * nla_put_flag(skb, type) add flag attribute to skb + * nla_put_msecs(skb, type, jiffies) add msecs attribute to skb +@@ -121,6 +125,10 @@ + * nla_get_u16(nla) get payload for a u16 attribute + * nla_get_u32(nla) get payload for a u32 attribute + * nla_get_u64(nla) get payload for a u64 attribute ++ * nla_get_s8(nla) get payload for a s8 attribute ++ * nla_get_s16(nla) get payload for a s16 attribute ++ * nla_get_s32(nla) get payload for a s32 attribute ++ * nla_get_s64(nla) get payload for a s64 attribute + * nla_get_flag(nla) return 1 if flag is true + * nla_get_msecs(nla) get payload for a msecs attribute + * +@@ -160,6 +168,10 @@ enum { + NLA_NESTED_COMPAT, + NLA_NUL_STRING, + NLA_BINARY, ++ NLA_S8, ++ NLA_S16, ++ NLA_S32, ++ NLA_S64, + __NLA_TYPE_MAX, + }; + +@@ -183,6 +195,8 @@ enum { + * NLA_NESTED_COMPAT Minimum length of structure payload + * NLA_U8, NLA_U16, + * NLA_U32, NLA_U64, ++ * NLA_S8, NLA_S16, ++ * NLA_S32, NLA_S64, + * NLA_MSECS Leaving the length field zero will verify the + * given type fits, using it verifies minimum length + * just like "All other" +@@ -879,6 +893,50 @@ static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value) + } + + /** ++ * nla_put_s8 - Add a s8 netlink attribute to a socket buffer ++ * @skb: socket buffer to add attribute to ++ * @attrtype: attribute type ++ * @value: numeric value ++ */ ++static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value) ++{ ++ return nla_put(skb, attrtype, sizeof(s8), &value); ++} ++ ++/** ++ * nla_put_s16 - Add a s16 netlink attribute to a socket buffer ++ * @skb: socket buffer to add attribute to ++ * @attrtype: attribute type ++ * @value: numeric value ++ */ ++static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value) ++{ ++ return nla_put(skb, attrtype, sizeof(s16), &value); ++} ++ ++/** ++ * nla_put_s32 - Add a s32 netlink attribute to a socket buffer ++ * @skb: socket buffer to add attribute to ++ * @attrtype: attribute type ++ * @value: numeric value ++ */ ++static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value) ++{ ++ return nla_put(skb, attrtype, sizeof(s32), &value); ++} ++ ++/** ++ * nla_put_s64 - Add a s64 netlink attribute to a socket buffer ++ * @skb: socket buffer to add attribute to ++ * @attrtype: attribute type ++ * @value: numeric value ++ */ ++static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value) ++{ ++ return nla_put(skb, attrtype, sizeof(s64), &value); ++} ++ ++/** + * nla_put_string - Add a string netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type +@@ -994,6 +1052,46 @@ static inline __be64 nla_get_be64(const struct nlattr *nla) + } + + /** ++ * nla_get_s32 - return payload of s32 attribute ++ * @nla: s32 netlink attribute ++ */ ++static inline s32 nla_get_s32(const struct nlattr *nla) ++{ ++ return *(s32 *) nla_data(nla); ++} ++ ++/** ++ * nla_get_s16 - return payload of s16 attribute ++ * @nla: s16 netlink attribute ++ */ ++static inline s16 nla_get_s16(const struct nlattr *nla) ++{ ++ return *(s16 *) nla_data(nla); ++} ++ ++/** ++ * nla_get_s8 - return payload of s8 attribute ++ * @nla: s8 netlink attribute ++ */ ++static inline s8 nla_get_s8(const struct nlattr *nla) ++{ ++ return *(s8 *) nla_data(nla); ++} ++ ++/** ++ * nla_get_s64 - return payload of s64 attribute ++ * @nla: s64 netlink attribute ++ */ ++static inline s64 nla_get_s64(const struct nlattr *nla) ++{ ++ s64 tmp; ++ ++ nla_memcpy(&tmp, nla, sizeof(tmp)); ++ ++ return tmp; ++} ++ ++/** + * nla_get_flag - return payload of flag attribute + * @nla: flag netlink attribute + */ +