summaryrefslogtreecommitdiffstats
path: root/team-net-next-20120808.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2012-08-08 08:49:40 -0400
committerJosh Boyer <jwboyer@redhat.com>2012-08-08 08:49:40 -0400
commiteb44f89919b3d7a9a9dd7be5e815ecf0acaaca2a (patch)
treea63748e1d5c280f8e94acee2bd81ba13b85f077a /team-net-next-20120808.patch
parent3b7690310ec8a6055cb754b69d8a08c6b4fe65ed (diff)
downloadkernel-eb44f89919b3d7a9a9dd7be5e815ecf0acaaca2a.tar.gz
kernel-eb44f89919b3d7a9a9dd7be5e815ecf0acaaca2a.tar.xz
kernel-eb44f89919b3d7a9a9dd7be5e815ecf0acaaca2a.zip
Update team driver from net-next from Jiri Pirko
Diffstat (limited to 'team-net-next-20120808.patch')
-rw-r--r--team-net-next-20120808.patch499
1 files changed, 499 insertions, 0 deletions
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 <jpirko@redhat.com>
+
+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
+ */
+