aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team/team_mode_activebackup.c
diff options
context:
space:
mode:
authorJiri Pirko <jpirko@redhat.com>2011-11-11 17:16:48 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-13 16:10:10 -0500
commit3d249d4ca7d0ed6629a135ea1ea21c72286c0d80 (patch)
treee89c8b6bbf4f8d0e4a3428304c26305eca76e4b8 /drivers/net/team/team_mode_activebackup.c
parent5d70b88cd41ef0f2ac0caaab4fd492dd686feee6 (diff)
net: introduce ethernet teaming device
This patch introduces new network device called team. It supposes to be very fast, simple, userspace-driven alternative to existing bonding driver. Userspace library called libteam with couple of demo apps is available here: https://github.com/jpirko/libteam Note it's still in its dipers atm. team<->libteam use generic netlink for communication. That and rtnl suppose to be the only way to configure team device, no sysfs etc. Python binding of libteam was recently introduced. Daemon providing arpmon/miimon active-backup functionality will be introduced shortly. All what's necessary is already implemented in kernel team driver. v7->v8: - check ndo_ndo_vlan_rx_[add/kill]_vid functions before calling them. - use dev_kfree_skb_any() instead of dev_kfree_skb() v6->v7: - transmit and receive functions are not checked in hot paths. That also resolves memory leak on transmit when no port is present v5->v6: - changed couple of _rcu calls to non _rcu ones in non-readers v4->v5: - team_change_mtu() uses team->lock while travesing though port list - mac address changes are moved completely to jurisdiction of userspace daemon. This way the daemon can do FOM1, FOM2 and possibly other weird things with mac addresses. Only round-robin mode sets up all ports to bond's address then enslaved. - Extended Kconfig text v3->v4: - remove redundant synchronize_rcu from __team_change_mode() - revert "set and clear of mode_ops happens per pointer, not per byte" - extend comment of function __team_change_mode() v2->v3: - team_change_mtu() uses rcu version of list traversal to unwind - set and clear of mode_ops happens per pointer, not per byte - port hashlist changed to be embedded into team structure - error branch in team_port_enter() does cleanup now - fixed rtln->rtnl v1->v2: - modes are made as modules. Makes team more modular and extendable. - several commenters' nitpicks found on v1 were fixed - several other bugs were fixed. - note I ignored Eric's comment about roundrobin port selector as Eric's way may be easily implemented as another mode (mode "random") in future. Signed-off-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/team/team_mode_activebackup.c')
-rw-r--r--drivers/net/team/team_mode_activebackup.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
new file mode 100644
index 000000000000..6fe920c440b3
--- /dev/null
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -0,0 +1,137 @@
1/*
2 * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
3 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/errno.h>
16#include <linux/netdevice.h>
17#include <net/rtnetlink.h>
18#include <linux/if_team.h>
19
20struct ab_priv {
21 struct team_port __rcu *active_port;
22};
23
24static struct ab_priv *ab_priv(struct team *team)
25{
26 return (struct ab_priv *) &team->mode_priv;
27}
28
29static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,
30 struct sk_buff *skb) {
31 struct team_port *active_port;
32
33 active_port = rcu_dereference(ab_priv(team)->active_port);
34 if (active_port != port)
35 return RX_HANDLER_EXACT;
36 return RX_HANDLER_ANOTHER;
37}
38
39static bool ab_transmit(struct team *team, struct sk_buff *skb)
40{
41 struct team_port *active_port;
42
43 active_port = rcu_dereference(ab_priv(team)->active_port);
44 if (unlikely(!active_port))
45 goto drop;
46 skb->dev = active_port->dev;
47 if (dev_queue_xmit(skb))
48 return false;
49 return true;
50
51drop:
52 dev_kfree_skb_any(skb);
53 return false;
54}
55
56static void ab_port_leave(struct team *team, struct team_port *port)
57{
58 if (ab_priv(team)->active_port == port)
59 rcu_assign_pointer(ab_priv(team)->active_port, NULL);
60}
61
62static int ab_active_port_get(struct team *team, void *arg)
63{
64 u32 *ifindex = arg;
65
66 *ifindex = 0;
67 if (ab_priv(team)->active_port)
68 *ifindex = ab_priv(team)->active_port->dev->ifindex;
69 return 0;
70}
71
72static int ab_active_port_set(struct team *team, void *arg)
73{
74 u32 *ifindex = arg;
75 struct team_port *port;
76
77 list_for_each_entry_rcu(port, &team->port_list, list) {
78 if (port->dev->ifindex == *ifindex) {
79 rcu_assign_pointer(ab_priv(team)->active_port, port);
80 return 0;
81 }
82 }
83 return -ENOENT;
84}
85
86static struct team_option ab_options[] = {
87 {
88 .name = "activeport",
89 .type = TEAM_OPTION_TYPE_U32,
90 .getter = ab_active_port_get,
91 .setter = ab_active_port_set,
92 },
93};
94
95int ab_init(struct team *team)
96{
97 team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
98 return 0;
99}
100
101void ab_exit(struct team *team)
102{
103 team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
104}
105
106static const struct team_mode_ops ab_mode_ops = {
107 .init = ab_init,
108 .exit = ab_exit,
109 .receive = ab_receive,
110 .transmit = ab_transmit,
111 .port_leave = ab_port_leave,
112};
113
114static struct team_mode ab_mode = {
115 .kind = "activebackup",
116 .owner = THIS_MODULE,
117 .priv_size = sizeof(struct ab_priv),
118 .ops = &ab_mode_ops,
119};
120
121static int __init ab_init_module(void)
122{
123 return team_mode_register(&ab_mode);
124}
125
126static void __exit ab_cleanup_module(void)
127{
128 team_mode_unregister(&ab_mode);
129}
130
131module_init(ab_init_module);
132module_exit(ab_cleanup_module);
133
134MODULE_LICENSE("GPL v2");
135MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
136MODULE_DESCRIPTION("Active-backup mode for team");
137MODULE_ALIAS("team-mode-activebackup");