aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/team/team.c')
-rw-r--r--drivers/net/team/team.c200
1 files changed, 198 insertions, 2 deletions
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 87707ab39430..ba10c469b02b 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)
658} 658}
659 659
660 660
661/*************************************
662 * Multiqueue Tx port select override
663 *************************************/
664
665static int team_queue_override_init(struct team *team)
666{
667 struct list_head *listarr;
668 unsigned int queue_cnt = team->dev->num_tx_queues - 1;
669 unsigned int i;
670
671 if (!queue_cnt)
672 return 0;
673 listarr = kmalloc(sizeof(struct list_head) * queue_cnt, GFP_KERNEL);
674 if (!listarr)
675 return -ENOMEM;
676 team->qom_lists = listarr;
677 for (i = 0; i < queue_cnt; i++)
678 INIT_LIST_HEAD(listarr++);
679 return 0;
680}
681
682static void team_queue_override_fini(struct team *team)
683{
684 kfree(team->qom_lists);
685}
686
687static struct list_head *__team_get_qom_list(struct team *team, u16 queue_id)
688{
689 return &team->qom_lists[queue_id - 1];
690}
691
692/*
693 * note: already called with rcu_read_lock
694 */
695static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
696{
697 struct list_head *qom_list;
698 struct team_port *port;
699
700 if (!team->queue_override_enabled || !skb->queue_mapping)
701 return false;
702 qom_list = __team_get_qom_list(team, skb->queue_mapping);
703 list_for_each_entry_rcu(port, qom_list, qom_list) {
704 if (!team_dev_queue_xmit(team, port, skb))
705 return true;
706 }
707 return false;
708}
709
710static void __team_queue_override_port_del(struct team *team,
711 struct team_port *port)
712{
713 list_del_rcu(&port->qom_list);
714 synchronize_rcu();
715 INIT_LIST_HEAD(&port->qom_list);
716}
717
718static bool team_queue_override_port_has_gt_prio_than(struct team_port *port,
719 struct team_port *cur)
720{
721 if (port->priority < cur->priority)
722 return true;
723 if (port->priority > cur->priority)
724 return false;
725 if (port->index < cur->index)
726 return true;
727 return false;
728}
729
730static void __team_queue_override_port_add(struct team *team,
731 struct team_port *port)
732{
733 struct team_port *cur;
734 struct list_head *qom_list;
735 struct list_head *node;
736
737 if (!port->queue_id || !team_port_enabled(port))
738 return;
739
740 qom_list = __team_get_qom_list(team, port->queue_id);
741 node = qom_list;
742 list_for_each_entry(cur, qom_list, qom_list) {
743 if (team_queue_override_port_has_gt_prio_than(port, cur))
744 break;
745 node = &cur->qom_list;
746 }
747 list_add_tail_rcu(&port->qom_list, node);
748}
749
750static void __team_queue_override_enabled_check(struct team *team)
751{
752 struct team_port *port;
753 bool enabled = false;
754
755 list_for_each_entry(port, &team->port_list, list) {
756 if (!list_empty(&port->qom_list)) {
757 enabled = true;
758 break;
759 }
760 }
761 if (enabled == team->queue_override_enabled)
762 return;
763 netdev_dbg(team->dev, "%s queue override\n",
764 enabled ? "Enabling" : "Disabling");
765 team->queue_override_enabled = enabled;
766}
767
768static void team_queue_override_port_refresh(struct team *team,
769 struct team_port *port)
770{
771 __team_queue_override_port_del(team, port);
772 __team_queue_override_port_add(team, port);
773 __team_queue_override_enabled_check(team);
774}
775
776
661/**************** 777/****************
662 * Port handling 778 * Port handling
663 ****************/ 779 ****************/
@@ -688,6 +804,7 @@ static void team_port_enable(struct team *team,
688 hlist_add_head_rcu(&port->hlist, 804 hlist_add_head_rcu(&port->hlist,
689 team_port_index_hash(team, port->index)); 805 team_port_index_hash(team, port->index));
690 team_adjust_ops(team); 806 team_adjust_ops(team);
807 team_queue_override_port_refresh(team, port);
691 if (team->ops.port_enabled) 808 if (team->ops.port_enabled)
692 team->ops.port_enabled(team, port); 809 team->ops.port_enabled(team, port);
693} 810}
@@ -716,6 +833,7 @@ static void team_port_disable(struct team *team,
716 hlist_del_rcu(&port->hlist); 833 hlist_del_rcu(&port->hlist);
717 __reconstruct_port_hlist(team, port->index); 834 __reconstruct_port_hlist(team, port->index);
718 port->index = -1; 835 port->index = -1;
836 team_queue_override_port_refresh(team, port);
719 __team_adjust_ops(team, team->en_port_count - 1); 837 __team_adjust_ops(team, team->en_port_count - 1);
720 /* 838 /*
721 * Wait until readers see adjusted ops. This ensures that 839 * 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)
881 999
882 port->dev = port_dev; 1000 port->dev = port_dev;
883 port->team = team; 1001 port->team = team;
1002 INIT_LIST_HEAD(&port->qom_list);
884 1003
885 port->orig.mtu = port_dev->mtu; 1004 port->orig.mtu = port_dev->mtu;
886 err = dev_set_mtu(port_dev, dev->mtu); 1005 err = dev_set_mtu(port_dev, dev->mtu);
@@ -1092,6 +1211,49 @@ static int team_user_linkup_en_option_set(struct team *team,
1092 return 0; 1211 return 0;
1093} 1212}
1094 1213
1214static int team_priority_option_get(struct team *team,
1215 struct team_gsetter_ctx *ctx)
1216{
1217 struct team_port *port = ctx->info->port;
1218
1219 ctx->data.s32_val = port->priority;
1220 return 0;
1221}
1222
1223static int team_priority_option_set(struct team *team,
1224 struct team_gsetter_ctx *ctx)
1225{
1226 struct team_port *port = ctx->info->port;
1227
1228 port->priority = ctx->data.s32_val;
1229 team_queue_override_port_refresh(team, port);
1230 return 0;
1231}
1232
1233static int team_queue_id_option_get(struct team *team,
1234 struct team_gsetter_ctx *ctx)
1235{
1236 struct team_port *port = ctx->info->port;
1237
1238 ctx->data.u32_val = port->queue_id;
1239 return 0;
1240}
1241
1242static int team_queue_id_option_set(struct team *team,
1243 struct team_gsetter_ctx *ctx)
1244{
1245 struct team_port *port = ctx->info->port;
1246
1247 if (port->queue_id == ctx->data.u32_val)
1248 return 0;
1249 if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
1250 return -EINVAL;
1251 port->queue_id = ctx->data.u32_val;
1252 team_queue_override_port_refresh(team, port);
1253 return 0;
1254}
1255
1256
1095static const struct team_option team_options[] = { 1257static const struct team_option team_options[] = {
1096 { 1258 {
1097 .name = "mode", 1259 .name = "mode",
@@ -1120,6 +1282,20 @@ static const struct team_option team_options[] = {
1120 .getter = team_user_linkup_en_option_get, 1282 .getter = team_user_linkup_en_option_get,
1121 .setter = team_user_linkup_en_option_set, 1283 .setter = team_user_linkup_en_option_set,
1122 }, 1284 },
1285 {
1286 .name = "priority",
1287 .type = TEAM_OPTION_TYPE_S32,
1288 .per_port = true,
1289 .getter = team_priority_option_get,
1290 .setter = team_priority_option_set,
1291 },
1292 {
1293 .name = "queue_id",
1294 .type = TEAM_OPTION_TYPE_U32,
1295 .per_port = true,
1296 .getter = team_queue_id_option_get,
1297 .setter = team_queue_id_option_set,
1298 },
1123}; 1299};
1124 1300
1125static struct lock_class_key team_netdev_xmit_lock_key; 1301static struct lock_class_key team_netdev_xmit_lock_key;
@@ -1155,6 +1331,9 @@ static int team_init(struct net_device *dev)
1155 for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) 1331 for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
1156 INIT_HLIST_HEAD(&team->en_port_hlist[i]); 1332 INIT_HLIST_HEAD(&team->en_port_hlist[i]);
1157 INIT_LIST_HEAD(&team->port_list); 1333 INIT_LIST_HEAD(&team->port_list);
1334 err = team_queue_override_init(team);
1335 if (err)
1336 goto err_team_queue_override_init;
1158 1337
1159 team_adjust_ops(team); 1338 team_adjust_ops(team);
1160 1339
@@ -1170,6 +1349,8 @@ static int team_init(struct net_device *dev)
1170 return 0; 1349 return 0;
1171 1350
1172err_options_register: 1351err_options_register:
1352 team_queue_override_fini(team);
1353err_team_queue_override_init:
1173 free_percpu(team->pcpu_stats); 1354 free_percpu(team->pcpu_stats);
1174 1355
1175 return err; 1356 return err;
@@ -1187,6 +1368,7 @@ static void team_uninit(struct net_device *dev)
1187 1368
1188 __team_change_mode(team, NULL); /* cleanup */ 1369 __team_change_mode(team, NULL); /* cleanup */
1189 __team_options_unregister(team, team_options, ARRAY_SIZE(team_options)); 1370 __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
1371 team_queue_override_fini(team);
1190 mutex_unlock(&team->lock); 1372 mutex_unlock(&team->lock);
1191} 1373}
1192 1374
@@ -1216,10 +1398,12 @@ static int team_close(struct net_device *dev)
1216static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) 1398static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
1217{ 1399{
1218 struct team *team = netdev_priv(dev); 1400 struct team *team = netdev_priv(dev);
1219 bool tx_success = false; 1401 bool tx_success;
1220 unsigned int len = skb->len; 1402 unsigned int len = skb->len;
1221 1403
1222 tx_success = team->ops.transmit(team, skb); 1404 tx_success = team_queue_override_transmit(team, skb);
1405 if (!tx_success)
1406 tx_success = team->ops.transmit(team, skb);
1223 if (tx_success) { 1407 if (tx_success) {
1224 struct team_pcpu_stats *pcpu_stats; 1408 struct team_pcpu_stats *pcpu_stats;
1225 1409
@@ -1787,6 +1971,12 @@ static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
1787 nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) 1971 nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
1788 goto nest_cancel; 1972 goto nest_cancel;
1789 break; 1973 break;
1974 case TEAM_OPTION_TYPE_S32:
1975 if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_S32))
1976 goto nest_cancel;
1977 if (nla_put_s32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.s32_val))
1978 goto nest_cancel;
1979 break;
1790 default: 1980 default:
1791 BUG(); 1981 BUG();
1792 } 1982 }
@@ -1975,6 +2165,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
1975 case NLA_FLAG: 2165 case NLA_FLAG:
1976 opt_type = TEAM_OPTION_TYPE_BOOL; 2166 opt_type = TEAM_OPTION_TYPE_BOOL;
1977 break; 2167 break;
2168 case NLA_S32:
2169 opt_type = TEAM_OPTION_TYPE_S32;
2170 break;
1978 default: 2171 default:
1979 goto team_put; 2172 goto team_put;
1980 } 2173 }
@@ -2031,6 +2224,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
2031 case TEAM_OPTION_TYPE_BOOL: 2224 case TEAM_OPTION_TYPE_BOOL:
2032 ctx.data.bool_val = attr_data ? true : false; 2225 ctx.data.bool_val = attr_data ? true : false;
2033 break; 2226 break;
2227 case TEAM_OPTION_TYPE_S32:
2228 ctx.data.s32_val = nla_get_s32(attr_data);
2229 break;
2034 default: 2230 default:
2035 BUG(); 2231 BUG();
2036 } 2232 }