11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/module.h>
15 #include <linux/errno.h>
16 #include <linux/netdevice.h>
17 #include <linux/filter.h>
18 #include <linux/if_team.h>
27 #define LB_TX_HASHTABLE_SIZE 256
82 #define LB_HTPM_PORT_BY_HASH(lp_priv, hash) \
83 (lb_priv)->ex->tx_hash_to_port_mapping[hash].port
85 #define LB_HTPM_OPT_INST_INFO_BY_HASH(lp_priv, hash) \
86 (lb_priv)->ex->tx_hash_to_port_mapping[hash].opt_inst_info
88 static void lb_tx_hash_to_port_mapping_null_port(
struct team *
team,
98 pm = &lb_priv->
ex->tx_hash_to_port_mapping[
i];
118 return team_get_port_by_index_rcu(team, port_index);
138 .func = lb_hash_select_tx_port,
141 .name =
"hash_to_port_mapping",
142 .func = lb_htpm_select_tx_port,
145 #define LB_SELECT_TX_PORT_LIST_COUNT ARRAY_SIZE(lb_select_tx_port_list)
154 item = &lb_select_tx_port_list[
i];
155 if (item->
func == func)
168 item = &lb_select_tx_port_list[
i];
175 static unsigned int lb_get_skb_hash(
struct lb_priv *lb_priv,
187 return c[0] ^ c[1] ^ c[2] ^ c[3];
190 static void lb_update_tx_stats(
unsigned int tx_bytes,
struct lb_priv *lb_priv,
201 u64_stats_update_begin(&pcpu_stats->
syncp);
204 u64_stats_update_end(&pcpu_stats->
syncp);
207 static bool lb_transmit(
struct team *team,
struct sk_buff *skb)
209 struct lb_priv *lb_priv = get_lb_priv(team);
215 hash = lb_get_skb_hash(lb_priv, skb);
217 port = select_tx_port_func(team, lb_priv, skb, hash);
220 if (team_dev_queue_xmit(team, port, skb))
222 lb_update_tx_stats(tx_bytes, lb_priv, get_lb_port_priv(port), hash);
232 struct lb_priv *lb_priv = get_lb_priv(team);
234 if (!lb_priv->
ex->orig_fprog) {
266 static void __fprog_destroy(
struct sock_fprog *fprog)
274 struct lb_priv *lb_priv = get_lb_priv(team);
281 err = __fprog_create(&fprog, ctx->
data.
bin_val.len,
287 __fprog_destroy(fprog);
292 if (lb_priv->
ex->orig_fprog) {
294 __fprog_destroy(lb_priv->
ex->orig_fprog);
296 lockdep_is_held(&team->
lock));
301 lb_priv->
ex->orig_fprog = fprog;
305 static int lb_tx_method_get(
struct team *team,
struct team_gsetter_ctx *ctx)
307 struct lb_priv *lb_priv = get_lb_priv(team);
312 lockdep_is_held(&team->
lock));
313 name = lb_select_tx_port_get_name(func);
319 static int lb_tx_method_set(
struct team *team,
struct team_gsetter_ctx *ctx)
321 struct lb_priv *lb_priv = get_lb_priv(team);
324 func = lb_select_tx_port_get_func(ctx->
data.
str_val);
331 static int lb_tx_hash_to_port_mapping_init(
struct team *team,
334 struct lb_priv *lb_priv = get_lb_priv(team);
341 static int lb_tx_hash_to_port_mapping_get(
struct team *team,
344 struct lb_priv *lb_priv = get_lb_priv(team);
346 unsigned char hash = ctx->
info->array_index;
353 static int lb_tx_hash_to_port_mapping_set(
struct team *team,
356 struct lb_priv *lb_priv = get_lb_priv(team);
358 unsigned char hash = ctx->
info->array_index;
362 team_port_enabled(port)) {
371 static int lb_hash_stats_init(
struct team *team,
374 struct lb_priv *lb_priv = get_lb_priv(team);
377 lb_priv->
ex->stats.info[
hash].opt_inst_info =
info;
381 static int lb_hash_stats_get(
struct team *team,
struct team_gsetter_ctx *ctx)
383 struct lb_priv *lb_priv = get_lb_priv(team);
384 unsigned char hash = ctx->
info->array_index;
391 static int lb_port_stats_init(
struct team *team,
401 static int lb_port_stats_get(
struct team *team,
struct team_gsetter_ctx *ctx)
411 static void __lb_stats_info_refresh_prepare(
struct lb_stats_info *s_info)
417 static bool __lb_stats_info_refresh_check(
struct lb_stats_info *s_info,
428 static void __lb_one_cpu_stats_add(
struct lb_stats *acc_stats,
436 start = u64_stats_fetch_begin_bh(syncp);
438 }
while (u64_stats_fetch_retry_bh(syncp, start));
445 struct lb_priv *lb_priv;
456 stats.refresh_dw.work);
458 team = lb_priv_ex->
team;
459 lb_priv = get_lb_priv(team);
467 s_info = &lb_priv->
ex->stats.info[
j];
468 __lb_stats_info_refresh_prepare(s_info);
472 __lb_one_cpu_stats_add(&s_info->
stats, stats,
475 changed |= __lb_stats_info_refresh_check(s_info, team);
482 __lb_stats_info_refresh_prepare(s_info);
486 __lb_one_cpu_stats_add(&s_info->
stats, stats,
489 changed |= __lb_stats_info_refresh_check(s_info, team);
496 (lb_priv_ex->
stats.refresh_interval *
HZ) / 10);
501 static int lb_stats_refresh_interval_get(
struct team *team,
504 struct lb_priv *lb_priv = get_lb_priv(team);
510 static int lb_stats_refresh_interval_set(
struct team *team,
513 struct lb_priv *lb_priv = get_lb_priv(team);
517 if (lb_priv->
ex->stats.refresh_interval == interval)
519 lb_priv->
ex->stats.refresh_interval =
interval;
529 .name =
"bpf_hash_func",
531 .getter = lb_bpf_func_get,
532 .setter = lb_bpf_func_set,
535 .name =
"lb_tx_method",
537 .getter = lb_tx_method_get,
538 .setter = lb_tx_method_set,
541 .name =
"lb_tx_hash_to_port_mapping",
544 .init = lb_tx_hash_to_port_mapping_init,
545 .getter = lb_tx_hash_to_port_mapping_get,
546 .setter = lb_tx_hash_to_port_mapping_set,
549 .name =
"lb_hash_stats",
552 .init = lb_hash_stats_init,
553 .getter = lb_hash_stats_get,
556 .name =
"lb_port_stats",
559 .init = lb_port_stats_init,
560 .getter = lb_port_stats_get,
563 .name =
"lb_stats_refresh_interval",
565 .getter = lb_stats_refresh_interval_get,
566 .setter = lb_stats_refresh_interval_set,
570 static int lb_init(
struct team *team)
572 struct lb_priv *lb_priv = get_lb_priv(team);
577 func = lb_select_tx_port_get_func(
"hash");
584 lb_priv->
ex->team = team;
589 goto err_alloc_pcpu_stats;
596 goto err_options_register;
599 err_options_register:
601 err_alloc_pcpu_stats:
606 static void lb_exit(
struct team *team)
608 struct lb_priv *lb_priv = get_lb_priv(team);
617 static int lb_port_enter(
struct team *team,
struct team_port *port)
627 static void lb_port_leave(
struct team *team,
struct team_port *port)
629 struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
634 static void lb_port_disabled(
struct team *team,
struct team_port *port)
636 lb_tx_hash_to_port_mapping_null_port(team, port);
642 .port_enter = lb_port_enter,
643 .port_leave = lb_port_leave,
644 .port_disabled = lb_port_disabled,
645 .transmit = lb_transmit,
648 static const struct team_mode lb_mode = {
649 .kind =
"loadbalance",
651 .priv_size =
sizeof(
struct lb_priv),
652 .port_priv_size =
sizeof(
struct lb_port_priv),
656 static int __init lb_init_module(
void)
661 static void __exit lb_cleanup_module(
void)