brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · e0f599e Raw
144 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * drivers/net/team/team_mode_activebackup.c - Active-backup mode for team4 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>5 */6 7#include <linux/kernel.h>8#include <linux/types.h>9#include <linux/module.h>10#include <linux/init.h>11#include <linux/errno.h>12#include <linux/netdevice.h>13#include <net/rtnetlink.h>14#include <linux/if_team.h>15 16struct ab_priv {17	struct team_port __rcu *active_port;18	struct team_option_inst_info *ap_opt_inst_info;19};20 21static struct ab_priv *ab_priv(struct team *team)22{23	return (struct ab_priv *) &team->mode_priv;24}25 26static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,27				      struct sk_buff *skb) {28	struct team_port *active_port;29 30	active_port = rcu_dereference(ab_priv(team)->active_port);31	if (active_port != port)32		return RX_HANDLER_EXACT;33	return RX_HANDLER_ANOTHER;34}35 36static bool ab_transmit(struct team *team, struct sk_buff *skb)37{38	struct team_port *active_port;39 40	active_port = rcu_dereference_bh(ab_priv(team)->active_port);41	if (unlikely(!active_port))42		goto drop;43	if (team_dev_queue_xmit(team, active_port, skb))44		return false;45	return true;46 47drop:48	dev_kfree_skb_any(skb);49	return false;50}51 52static void ab_port_leave(struct team *team, struct team_port *port)53{54	if (ab_priv(team)->active_port == port) {55		RCU_INIT_POINTER(ab_priv(team)->active_port, NULL);56		team_option_inst_set_change(ab_priv(team)->ap_opt_inst_info);57	}58}59 60static void ab_active_port_init(struct team *team,61				struct team_option_inst_info *info)62{63	ab_priv(team)->ap_opt_inst_info = info;64}65 66static void ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)67{68	struct team_port *active_port;69 70	active_port = rcu_dereference_protected(ab_priv(team)->active_port,71						lockdep_is_held(&team->lock));72	if (active_port)73		ctx->data.u32_val = active_port->dev->ifindex;74	else75		ctx->data.u32_val = 0;76}77 78static int ab_active_port_set(struct team *team, struct team_gsetter_ctx *ctx)79{80	struct team_port *port;81 82	list_for_each_entry(port, &team->port_list, list) {83		if (port->dev->ifindex == ctx->data.u32_val) {84			rcu_assign_pointer(ab_priv(team)->active_port, port);85			return 0;86		}87	}88	return -ENOENT;89}90 91static const struct team_option ab_options[] = {92	{93		.name = "activeport",94		.type = TEAM_OPTION_TYPE_U32,95		.init = ab_active_port_init,96		.getter = ab_active_port_get,97		.setter = ab_active_port_set,98	},99};100 101static int ab_init(struct team *team)102{103	return team_options_register(team, ab_options, ARRAY_SIZE(ab_options));104}105 106static void ab_exit(struct team *team)107{108	team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));109}110 111static const struct team_mode_ops ab_mode_ops = {112	.init			= ab_init,113	.exit			= ab_exit,114	.receive		= ab_receive,115	.transmit		= ab_transmit,116	.port_leave		= ab_port_leave,117};118 119static const struct team_mode ab_mode = {120	.kind		= "activebackup",121	.owner		= THIS_MODULE,122	.priv_size	= sizeof(struct ab_priv),123	.ops		= &ab_mode_ops,124	.lag_tx_type	= NETDEV_LAG_TX_TYPE_ACTIVEBACKUP,125};126 127static int __init ab_init_module(void)128{129	return team_mode_register(&ab_mode);130}131 132static void __exit ab_cleanup_module(void)133{134	team_mode_unregister(&ab_mode);135}136 137module_init(ab_init_module);138module_exit(ab_cleanup_module);139 140MODULE_LICENSE("GPL v2");141MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");142MODULE_DESCRIPTION("Active-backup mode for team");143MODULE_ALIAS_TEAM_MODE("activebackup");144